155102Storek /*
2*63318Sbostic * Copyright (c) 1991, 1992, 1993
3*63318Sbostic * The Regents of the University of California. 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
1259182Storek * California, Lawrence Berkeley Laboratory.
1355499Sbostic *
1455102Storek * %sccs.include.redist.c%
1555102Storek *
16*63318Sbostic * @(#)bsd_audio.c 8.1 (Berkeley) 06/11/93
1755102Storek *
1859328Storek * from: $Header: bsd_audio.c,v 1.18 93/04/24 16:20:35 leres 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
5859182Storek #include <sbusdev/bsd_audioreg.h>
5959182Storek #include <sbusdev/bsd_audiovar.h>
6059182Storek #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;
7959182Storek 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
audioselect(dev,rw)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
selrecord(p,si)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
audioidentify(cp)19155102Storek audioidentify(cp)
19255102Storek char *cp;
19355102Storek {
19455102Storek return (strcmp(cp, "audio") == 0);
19555102Storek }
19655102Storek
19755102Storek static int
audioattach(dev)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
audioattach(parent,self,args)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
init_amd(amd)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));
31359182Storek 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
32359328Storek /* ARGSUSED */
32455102Storek int
AUDIOOPEN(dev,flags,ifmt,p)32555102Storek AUDIOOPEN(dev, flags, ifmt, p)
32655102Storek {
32755102Storek register struct audio_softc *sc;
32855102Storek register volatile struct amd7930 *amd;
32959328Storek int unit = minor(dev);
33055102Storek
33155102Storek #ifdef SUNOS
33255102Storek if (unit > 0)
33355102Storek return (ENXIO);
33455102Storek sc = &audio_softc;
33555102Storek #else
33655102Storek if (unit >= audiocd.cd_ndevs || (sc = audiocd.cd_devs[unit]) == NULL)
33755102Storek return (ENXIO);
33855102Storek #endif
33955102Storek if (sc->sc_open)
34055102Storek return (EBUSY);
34155102Storek sc->sc_open = 1;
34255102Storek
34355102Storek sc->sc_au.au_lowat = audio_blocksize;
34455102Storek sc->sc_au.au_hiwat = AUCB_SIZE - sc->sc_au.au_lowat;
34555102Storek sc->sc_au.au_blksize = audio_blocksize;
34659182Storek sc->sc_au.au_backlog = audio_backlog;
34755102Storek
34855102Storek /* set up read and write blocks and `dead sound' zero value. */
34955102Storek AUCB_INIT(&sc->sc_au.au_rb);
35055102Storek sc->sc_au.au_rb.cb_thresh = AUCB_SIZE;
35155102Storek AUCB_INIT(&sc->sc_au.au_wb);
35255102Storek sc->sc_au.au_wb.cb_thresh = -1;
35355102Storek
35455102Storek /* nothing read or written yet */
35555102Storek sc->sc_rseek = 0;
35655102Storek sc->sc_wseek = 0;
35755102Storek
35855102Storek bzero((char *)&sc->sc_map, sizeof sc->sc_map);
35955102Storek /* default to speaker */
36055102Storek sc->sc_map.mr_mmr2 = AMD_MMR2_AINB | AMD_MMR2_LS;
36155102Storek
36255102Storek /* enable interrupts and set parameters established above */
36355102Storek amd = sc->sc_au.au_amd;
36455102Storek audio_setmmr2(amd, sc->sc_map.mr_mmr2);
36555102Storek ausetrgain(sc, audio_default_level);
36655102Storek ausetpgain(sc, audio_default_level);
36759182Storek ausetmgain(sc, 0);
36855102Storek amd->cr = AMDR_INIT;
36955102Storek amd->dr = AMD_INIT_PMS_ACTIVE;
37055102Storek
37155102Storek return (0);
37255102Storek }
37355102Storek
37455102Storek static int
audio_drain(sc)37555102Storek audio_drain(sc)
37655102Storek register struct audio_softc *sc;
37755102Storek {
37855102Storek register int error;
37955102Storek
38055102Storek while (!AUCB_EMPTY(&sc->sc_au.au_wb))
38155102Storek if ((error = audio_sleep(&sc->sc_au.au_wb, 0)) != 0)
38255102Storek return (error);
38355102Storek return (0);
38455102Storek }
38555102Storek
38655102Storek /*
38755102Storek * Close an audio chip.
38855102Storek */
38955102Storek /* ARGSUSED */
39055102Storek int
AUDIOCLOSE(dev,flags,ifmt,p)39155102Storek AUDIOCLOSE(dev, flags, ifmt, p)
39255102Storek {
39355102Storek register struct audio_softc *sc = SOFTC(dev);
39455102Storek register volatile struct amd7930 *amd;
39555102Storek register struct aucb *cb;
39655102Storek register int s;
39755102Storek
39855102Storek /*
39955102Storek * Block until output drains, but allow ^C interrupt.
40055102Storek */
40155102Storek sc->sc_au.au_lowat = 0; /* avoid excessive wakeups */
40255102Storek s = splaudio();
40355102Storek /*
40455102Storek * If there is pending output, let it drain (unless
40555102Storek * the output is paused).
40655102Storek */
40755102Storek cb = &sc->sc_au.au_wb;
40855102Storek if (!AUCB_EMPTY(cb) && !cb->cb_pause)
40955102Storek (void)audio_drain(sc);
41055102Storek /*
41155102Storek * Disable interrupts, clear open flag, and done.
41255102Storek */
41355102Storek amd = sc->sc_au.au_amd;
41455102Storek amd->cr = AMDR_INIT;
41555102Storek amd->dr = AMD_INIT_PMS_ACTIVE | AMD_INIT_INT_DISABLE;
41655102Storek splx(s);
41755102Storek sc->sc_open = 0;
41855102Storek return (0);
41955102Storek }
42055102Storek
42155102Storek int
audio_sleep(cb,thresh)42255102Storek audio_sleep(cb, thresh)
42355102Storek register struct aucb *cb;
42455102Storek register int thresh;
42555102Storek {
42655102Storek register int error;
42759182Storek register int s = splaudio();
42855102Storek
42955102Storek cb->cb_thresh = thresh;
43055102Storek error = tsleep((caddr_t)cb, (PZERO + 1) | PCATCH, "audio", 0);
43159182Storek splx(s);
43255102Storek return (error);
43355102Storek }
43455102Storek
43559328Storek /* ARGSUSED */
43655102Storek int
AUDIOREAD(dev,uio,ioflag)43755102Storek AUDIOREAD(dev, uio, ioflag)
43855102Storek {
43955102Storek register struct audio_softc *sc = SOFTC(dev);
44055102Storek register struct aucb *cb;
44159182Storek register int n, head, taildata, error;
44255102Storek register int blocksize = sc->sc_au.au_blksize;
44355102Storek
44455102Storek if (uio->uio_resid == 0)
44555102Storek return (0);
44655102Storek cb = &sc->sc_au.au_rb;
44755102Storek error = 0;
44855102Storek cb->cb_drops = 0;
44955102Storek sc->sc_rseek = sc->sc_au.au_stamp - AUCB_LEN(cb);
45055102Storek do {
45155102Storek while (AUCB_LEN(cb) < blocksize) {
45255102Storek #ifndef SUNOS
45355102Storek if (ioflag & IO_NDELAY) {
45455102Storek error = EWOULDBLOCK;
45559182Storek return (error);
45655102Storek }
45755102Storek #endif
45855102Storek if ((error = audio_sleep(cb, blocksize)) != 0)
45959182Storek return (error);
46055102Storek }
46155102Storek /*
46255102Storek * The space calculation can only err on the short
46355102Storek * side if an interrupt occurs during processing:
46455102Storek * only cb_tail is altered in the interrupt code.
46555102Storek */
46655102Storek head = cb->cb_head;
46755102Storek if ((n = AUCB_LEN(cb)) > uio->uio_resid)
46855102Storek n = uio->uio_resid;
46955102Storek taildata = AUCB_SIZE - head;
47055102Storek if (n > taildata) {
47155102Storek error = UIOMOVE((caddr_t)cb->cb_data + head,
47255102Storek taildata, UIO_READ, uio);
47355102Storek if (error == 0)
47455102Storek error = UIOMOVE((caddr_t)cb->cb_data,
47555102Storek n - taildata, UIO_READ, uio);
47655102Storek } else
47755102Storek error = UIOMOVE((caddr_t)cb->cb_data + head, n,
47855102Storek UIO_READ, uio);
47955102Storek if (error)
48059182Storek break;
48155102Storek head = AUCB_MOD(head + n);
48255102Storek cb->cb_head = head;
48355102Storek } while (uio->uio_resid >= blocksize);
48459182Storek
48555102Storek return (error);
48655102Storek }
48755102Storek
48859328Storek /* ARGSUSED */
48955102Storek int
AUDIOWRITE(dev,uio,ioflag)49055102Storek AUDIOWRITE(dev, uio, ioflag)
49155102Storek {
49255102Storek register struct audio_softc *sc = SOFTC(dev);
49355102Storek register struct aucb *cb = &sc->sc_au.au_wb;
49459328Storek register int n, tail, tailspace, error, first, watermark;
49555102Storek
49655102Storek error = 0;
49755102Storek first = 1;
49855102Storek while (uio->uio_resid > 0) {
49955102Storek watermark = sc->sc_au.au_hiwat;
50055102Storek while (AUCB_LEN(cb) > watermark) {
50155102Storek #ifndef SUNOS
50255102Storek if (ioflag & IO_NDELAY) {
50355102Storek error = EWOULDBLOCK;
50459182Storek return (error);
50555102Storek }
50655102Storek #endif
50755102Storek if ((error = audio_sleep(cb, watermark)) != 0)
50859182Storek return (error);
50955102Storek watermark = sc->sc_au.au_lowat;
51055102Storek }
51155102Storek /*
51255102Storek * The only value that can change on an interrupt is
51355102Storek * cb->cb_head. We only pull that out once to decide
51455102Storek * how much to write into cb_data; if we lose a race
51555102Storek * and cb_head changes, we will merely be overly
51655102Storek * conservative. For a legitimate time stamp,
51755102Storek * however, we need to synchronize the accesses to
51855102Storek * au_stamp and cb_head at a high ipl below.
51955102Storek */
52059182Storek tail = cb->cb_tail;
52159182Storek if ((n = (AUCB_SIZE - 1) - AUCB_LEN(cb)) > uio->uio_resid) {
52255102Storek n = uio->uio_resid;
52359182Storek if (cb->cb_head == tail &&
52459182Storek n <= sc->sc_au.au_blksize &&
52559182Storek sc->sc_au.au_stamp - sc->sc_wseek > 400) {
52659182Storek /*
52759182Storek * the write is 'small', the buffer is empty
52859182Storek * and we have been silent for at least 50ms
52959182Storek * so we might be dealing with an application
53059182Storek * that writes frames synchronously with
53159182Storek * reading them. If so, we need an output
53259182Storek * backlog to cover scheduling delays or
53359182Storek * there will be gaps in the sound output.
53459182Storek * Also take this opportunity to reset the
53559182Storek * buffer pointers in case we ended up on
53659182Storek * a bad boundary (odd byte, blksize bytes
53759182Storek * from end, etc.).
53859182Storek */
53959182Storek register u_int* ip;
54059182Storek register int muzero = 0x7f7f7f7f;
54159182Storek register int i = splaudio();
54259182Storek cb->cb_head = cb->cb_tail = 0;
54359182Storek splx(i);
54459182Storek tail = sc->sc_au.au_backlog;
54559182Storek ip = (u_int*)cb->cb_data;
54659182Storek for (i = tail >> 2; --i >= 0; )
54759182Storek *ip++ = muzero;
54859182Storek }
54959182Storek }
55055102Storek tailspace = AUCB_SIZE - tail;
55155102Storek if (n > tailspace) {
55255102Storek /* write first part at tail and rest at head */
55355102Storek error = UIOMOVE((caddr_t)cb->cb_data + tail,
55455102Storek tailspace, UIO_WRITE, uio);
55555102Storek if (error == 0)
55655102Storek error = UIOMOVE((caddr_t)cb->cb_data,
55755102Storek n - tailspace, UIO_WRITE, uio);
55855102Storek } else
55955102Storek error = UIOMOVE((caddr_t)cb->cb_data + tail, n,
56055102Storek UIO_WRITE, uio);
56155102Storek if (error)
56259182Storek break;
56359182Storek
56455102Storek tail = AUCB_MOD(tail + n);
56555102Storek if (first) {
56659182Storek register int s = splaudio();
56759182Storek sc->sc_wseek = AUCB_LEN(cb) + sc->sc_au.au_stamp + 1;
56855102Storek /*
56955102Storek * To guarantee that a write is contiguous in the
57055102Storek * sample space, we clear the drop count the first
57155102Storek * time through. If we later get drops, we will
57255102Storek * break out of the loop below, before writing
57355102Storek * a new frame.
57455102Storek */
57555102Storek cb->cb_drops = 0;
57659182Storek cb->cb_tail = tail;
57759182Storek splx(s);
57859182Storek first = 0;
57959182Storek } else {
58059182Storek if (cb->cb_drops != 0)
58159182Storek break;
58259182Storek cb->cb_tail = tail;
58355102Storek }
58455102Storek }
58555102Storek return (error);
58655102Storek }
58755102Storek
58855102Storek /* Sun audio compatibility */
58955102Storek struct sun_audio_prinfo {
59055102Storek u_int sample_rate;
59155102Storek u_int channels;
59255102Storek u_int precision;
59355102Storek u_int encoding;
59455102Storek u_int gain;
59555102Storek u_int port;
59655102Storek u_int reserved0[4];
59755102Storek u_int samples;
59855102Storek u_int eof;
59955102Storek u_char pause;
60055102Storek u_char error;
60155102Storek u_char waiting;
60255102Storek u_char reserved1[3];
60355102Storek u_char open;
60455102Storek u_char active;
60555102Storek };
60655102Storek struct sun_audio_info {
60755102Storek struct sun_audio_prinfo play;
60855102Storek struct sun_audio_prinfo record;
60955102Storek u_int monitor_gain;
61055102Storek u_int reserved[4];
61155102Storek };
61255102Storek
61355102Storek #ifndef SUNOS
61455102Storek #define SUNAUDIO_GETINFO _IOR('A', 1, struct sun_audio_info)
61555102Storek #define SUNAUDIO_SETINFO _IOWR('A', 2, struct sun_audio_info)
61655102Storek #else
61755102Storek #define SUNAUDIO_GETINFO _IOR(A, 1, struct sun_audio_info)
61855102Storek #define SUNAUDIO_SETINFO _IOWR(A, 2, struct sun_audio_info)
61955102Storek #endif
62055102Storek
62159328Storek /* ARGSUSED */
62255102Storek int
AUDIOIOCTL(dev,cmd,addr,flag,p)62355102Storek AUDIOIOCTL(dev, cmd, addr, flag, p)
62455102Storek {
62555102Storek register struct audio_softc *sc = SOFTC(dev);
62659328Storek int error = 0, s;
62755102Storek
62855102Storek switch (cmd) {
62955102Storek
63055102Storek case AUDIO_GETMAP:
63155102Storek bcopy((caddr_t)&sc->sc_map, addr, sizeof(sc->sc_map));
63255102Storek break;
63355102Storek
63455102Storek case AUDIO_SETMAP:
63555102Storek bcopy(addr, (caddr_t)&sc->sc_map, sizeof(sc->sc_map));
63655102Storek sc->sc_map.mr_mmr2 &= 0x7f;
63755102Storek audio_setmap(sc->sc_au.au_amd, &sc->sc_map);
63855102Storek break;
63955102Storek
64055102Storek case AUDIO_FLUSH:
64155102Storek s = splaudio();
64255102Storek AUCB_INIT(&sc->sc_au.au_rb);
64355102Storek AUCB_INIT(&sc->sc_au.au_wb);
64459182Storek sc->sc_au.au_stamp = 0;
64555102Storek splx(s);
64655102Storek sc->sc_wseek = 0;
64755102Storek sc->sc_rseek = 0;
64855102Storek break;
64955102Storek
65055102Storek /*
65155102Storek * Number of read samples dropped. We don't know where or
65255102Storek * when they were dropped.
65355102Storek */
65455102Storek case AUDIO_RERROR:
65555102Storek *(int *)addr = sc->sc_au.au_rb.cb_drops != 0;
65655102Storek break;
65755102Storek
65855102Storek /*
65959182Storek * How many samples will elapse until mike hears the first
66059182Storek * sample of what we last wrote?
66155102Storek */
66255102Storek case AUDIO_WSEEK:
66359182Storek s = splaudio();
66459182Storek *(u_long *)addr = sc->sc_wseek - sc->sc_au.au_stamp
66559182Storek + AUCB_LEN(&sc->sc_au.au_rb);
66659182Storek splx(s);
66755102Storek break;
66855102Storek
66955102Storek case AUDIO_SETINFO:
67055102Storek error = audiosetinfo(sc, (struct audio_info *)addr);
67155102Storek break;
67255102Storek
67355102Storek case AUDIO_GETINFO:
67455102Storek error = audiogetinfo(sc, (struct audio_info *)addr);
67555102Storek break;
67655102Storek
67755102Storek case SUNAUDIO_GETINFO:
67855102Storek error = sunaudiogetinfo(sc, (struct sun_audio_info *)addr);
67955102Storek break;
68055102Storek
68155102Storek case SUNAUDIO_SETINFO:
68255102Storek error = sunaudiosetinfo(sc, (struct sun_audio_info *)addr);
68355102Storek break;
68455102Storek
68555102Storek case AUDIO_DRAIN:
68655102Storek error = audio_drain(sc);
68755102Storek break;
68855102Storek
68955102Storek default:
69055102Storek error = EINVAL;
69155102Storek break;
69255102Storek }
69355102Storek return (error);
69455102Storek }
69555102Storek
69659328Storek /* ARGSUSED */
69755102Storek int
AUDIOSELECT(dev,rw,p)69855102Storek AUDIOSELECT(dev, rw, p)
69955102Storek {
70055102Storek register struct audio_softc *sc = SOFTC(dev);
70155102Storek register struct aucb *cb;
70255102Storek register int s = splaudio();
70355102Storek
70455102Storek switch (rw) {
70555102Storek
70655102Storek case FREAD:
70755102Storek cb = &sc->sc_au.au_rb;
70855102Storek if (AUCB_LEN(cb) >= sc->sc_au.au_blksize) {
70955102Storek splx(s);
71055102Storek return (1);
71155102Storek }
71255102Storek selrecord(p, &sc->sc_rsel);
71355102Storek cb->cb_thresh = sc->sc_au.au_blksize;
71455102Storek break;
71555102Storek
71655102Storek case FWRITE:
71755102Storek cb = &sc->sc_au.au_wb;
71855102Storek if (AUCB_LEN(cb) <= sc->sc_au.au_lowat) {
71955102Storek splx(s);
72055102Storek return (1);
72155102Storek }
72255102Storek selrecord(p, &sc->sc_wsel);
72355102Storek cb->cb_thresh = sc->sc_au.au_lowat;
72455102Storek break;
72555102Storek }
72655102Storek splx(s);
72755102Storek return (0);
72855102Storek }
72955102Storek
73055102Storek #ifdef AUDIO_C_HANDLER
73155102Storek int
audiohwintr(au0)73255102Storek audiohwintr(au0)
73355102Storek void *au0;
73455102Storek {
73555102Storek #ifdef SUNOS
73655102Storek register struct auio *au = audio_au;
73755102Storek #else
73855102Storek register struct auio *au = au0;
73955102Storek #endif
74055102Storek register volatile struct amd7930 *amd = au->au_amd;
74155102Storek register struct aucb *cb;
74255102Storek register int h, t, k;
74355102Storek
74455102Storek k = amd->ir; /* clear interrupt */
74555102Storek ++au->au_stamp;
74655102Storek
74755102Storek /* receive incoming data */
74855102Storek cb = &au->au_rb;
74955102Storek h = cb->cb_head;
75055102Storek t = cb->cb_tail;
75155102Storek k = AUCB_MOD(t + 1);
75255102Storek if (h == k)
75355102Storek cb->cb_drops++;
75455102Storek else if (cb->cb_pause != 0)
75555102Storek cb->cb_pdrops++;
75655102Storek else {
75755102Storek cb->cb_data[t] = amd->bbrb;
75855102Storek cb->cb_tail = t = k;
75955102Storek }
76055102Storek if (AUCB_MOD(t - h) >= cb->cb_thresh) {
76155102Storek cb->cb_thresh = AUCB_SIZE;
76255102Storek cb->cb_waking = 1;
76355102Storek AUDIO_SET_SWINTR;
76455102Storek }
76555102Storek /* send outgoing data */
76655102Storek cb = &au->au_wb;
76755102Storek h = cb->cb_head;
76855102Storek t = cb->cb_tail;
76955102Storek if (h == t)
77055102Storek cb->cb_drops++;
77155102Storek else if (cb->cb_pause != 0)
77255102Storek cb->cb_pdrops++;
77355102Storek else {
77455102Storek cb->cb_head = h = AUCB_MOD(h + 1);
77555102Storek amd->bbtb = cb->cb_data[h];
77655102Storek }
77755102Storek if (AUCB_MOD(t - h) <= cb->cb_thresh) {
77855102Storek cb->cb_thresh = -1;
77955102Storek cb->cb_waking = 1;
78055102Storek AUDIO_SET_SWINTR;
78155102Storek }
78255102Storek return (1);
78355102Storek }
78455102Storek #endif
78555102Storek
78659328Storek /* ARGSUSED */
78755102Storek int
audioswintr(sc0)78855102Storek audioswintr(sc0)
78955102Storek void *sc0;
79055102Storek {
79155102Storek register struct audio_softc *sc;
79255102Storek register int s, ret = 0;
79355102Storek #ifdef SUNOS
79455102Storek sc = &audio_softc;
79555102Storek #else
79655102Storek sc = sc0;
79755102Storek #endif
79855102Storek s = splaudio();
79955102Storek if (sc->sc_au.au_rb.cb_waking != 0) {
80055102Storek sc->sc_au.au_rb.cb_waking = 0;
80155102Storek splx(s);
80255102Storek ret = 1;
80355102Storek wakeup((caddr_t)&sc->sc_au.au_rb);
80455102Storek SELWAKEUP(&sc->sc_rsel);
80555102Storek }
80655102Storek if (sc->sc_au.au_wb.cb_waking != 0) {
80755102Storek sc->sc_au.au_wb.cb_waking = 0;
80855102Storek splx(s);
80955102Storek ret = 1;
81055102Storek wakeup((caddr_t)&sc->sc_au.au_wb);
81155102Storek SELWAKEUP(&sc->sc_wsel);
81255102Storek } else
81355102Storek splx(s);
81455102Storek return (ret);
81555102Storek }
81655102Storek
81755102Storek /* Write 16 bits of data from variable v to the data port of the audio chip */
81855102Storek
81959182Storek #define WAMD16(amd, v) ((amd)->dr = (v), (amd)->dr = (v) >> 8)
82055102Storek
82155102Storek void
audio_setmap(amd,map)82255102Storek audio_setmap(amd, map)
82355102Storek register volatile struct amd7930 *amd;
82455102Storek register struct mapreg *map;
82555102Storek {
82655102Storek register int i, s, v;
82755102Storek
82855102Storek s = splaudio();
82955102Storek amd->cr = AMDR_MAP_1_10;
83055102Storek for (i = 0; i < 8; i++) {
83155102Storek v = map->mr_x[i];
83255102Storek WAMD16(amd, v);
83355102Storek }
83455102Storek for (i = 0; i < 8; ++i) {
83555102Storek v = map->mr_r[i];
83655102Storek WAMD16(amd, v);
83755102Storek }
83855102Storek v = map->mr_gx; WAMD16(amd, v);
83955102Storek v = map->mr_gr; WAMD16(amd, v);
84055102Storek v = map->mr_ger; WAMD16(amd, v);
84155102Storek v = map->mr_stgr; WAMD16(amd, v);
84255102Storek v = map->mr_ftgr; WAMD16(amd, v);
84355102Storek v = map->mr_atgr; WAMD16(amd, v);
84455102Storek amd->dr = map->mr_mmr1;
84555102Storek amd->dr = map->mr_mmr2;
84655102Storek splx(s);
84755102Storek }
84855102Storek
84955102Storek /*
85055102Storek * Set the mmr1 register and one other 16 bit register in the audio chip.
85155102Storek * The other register is indicated by op and val.
85255102Storek */
85355102Storek void
audio_setmmr1(amd,mmr1,op,val)85455102Storek audio_setmmr1(amd, mmr1, op, val)
85555102Storek register volatile struct amd7930 *amd;
85655102Storek register int mmr1;
85755102Storek register int op;
85855102Storek register int val;
85955102Storek {
86055102Storek register int s = splaudio();
86155102Storek
86255102Storek amd->cr = AMDR_MAP_MMR1;
86355102Storek amd->dr = mmr1;
86455102Storek amd->cr = op;
86555102Storek WAMD16(amd, val);
86655102Storek splx(s);
86755102Storek }
86855102Storek
86955102Storek /*
87059182Storek * Set the mmr2 register.
87155102Storek */
87255102Storek static void
audio_setmmr2(amd,mmr2)87355102Storek audio_setmmr2(amd, mmr2)
87455102Storek register volatile struct amd7930 *amd;
87555102Storek register int mmr2;
87655102Storek {
87755102Storek register int s = splaudio();
87855102Storek
87955102Storek amd->cr = AMDR_MAP_MMR2;
88055102Storek amd->dr = mmr2;
88155102Storek splx(s);
88255102Storek }
88355102Storek
88459182Storek /*
88559182Storek * gx, gr & stg gains. this table must contain 256 elements with
88659182Storek * the 0th being "infinity" (the magic value 9008). The remaining
88759182Storek * elements match sun's gain curve (but with higher resolution):
88859182Storek * -18 to 0dB in .16dB steps then 0 to 12dB in .08dB steps.
88959182Storek */
89059182Storek static const u_short gx_coeff[256] = {
89159182Storek 0x9008, 0x8b7c, 0x8b51, 0x8b45, 0x8b42, 0x8b3b, 0x8b36, 0x8b33,
89259182Storek 0x8b32, 0x8b2a, 0x8b2b, 0x8b2c, 0x8b25, 0x8b23, 0x8b22, 0x8b22,
89359182Storek 0x9122, 0x8b1a, 0x8aa3, 0x8aa3, 0x8b1c, 0x8aa6, 0x912d, 0x912b,
89459182Storek 0x8aab, 0x8b12, 0x8aaa, 0x8ab2, 0x9132, 0x8ab4, 0x913c, 0x8abb,
89559182Storek 0x9142, 0x9144, 0x9151, 0x8ad5, 0x8aeb, 0x8a79, 0x8a5a, 0x8a4a,
89659182Storek 0x8b03, 0x91c2, 0x91bb, 0x8a3f, 0x8a33, 0x91b2, 0x9212, 0x9213,
89759182Storek 0x8a2c, 0x921d, 0x8a23, 0x921a, 0x9222, 0x9223, 0x922d, 0x9231,
89859182Storek 0x9234, 0x9242, 0x925b, 0x92dd, 0x92c1, 0x92b3, 0x92ab, 0x92a4,
89959182Storek 0x92a2, 0x932b, 0x9341, 0x93d3, 0x93b2, 0x93a2, 0x943c, 0x94b2,
90059182Storek 0x953a, 0x9653, 0x9782, 0x9e21, 0x9d23, 0x9cd2, 0x9c23, 0x9baa,
90159182Storek 0x9bde, 0x9b33, 0x9b22, 0x9b1d, 0x9ab2, 0xa142, 0xa1e5, 0x9a3b,
90259182Storek 0xa213, 0xa1a2, 0xa231, 0xa2eb, 0xa313, 0xa334, 0xa421, 0xa54b,
90359182Storek 0xada4, 0xac23, 0xab3b, 0xaaab, 0xaa5c, 0xb1a3, 0xb2ca, 0xb3bd,
90459182Storek 0xbe24, 0xbb2b, 0xba33, 0xc32b, 0xcb5a, 0xd2a2, 0xe31d, 0x0808,
90559182Storek 0x72ba, 0x62c2, 0x5c32, 0x52db, 0x513e, 0x4cce, 0x43b2, 0x4243,
90659182Storek 0x41b4, 0x3b12, 0x3bc3, 0x3df2, 0x34bd, 0x3334, 0x32c2, 0x3224,
90759182Storek 0x31aa, 0x2a7b, 0x2aaa, 0x2b23, 0x2bba, 0x2c42, 0x2e23, 0x25bb,
90859182Storek 0x242b, 0x240f, 0x231a, 0x22bb, 0x2241, 0x2223, 0x221f, 0x1a33,
90959182Storek 0x1a4a, 0x1acd, 0x2132, 0x1b1b, 0x1b2c, 0x1b62, 0x1c12, 0x1c32,
91059182Storek 0x1d1b, 0x1e71, 0x16b1, 0x1522, 0x1434, 0x1412, 0x1352, 0x1323,
91159182Storek 0x1315, 0x12bc, 0x127a, 0x1235, 0x1226, 0x11a2, 0x1216, 0x0a2a,
91259182Storek 0x11bc, 0x11d1, 0x1163, 0x0ac2, 0x0ab2, 0x0aab, 0x0b1b, 0x0b23,
91359182Storek 0x0b33, 0x0c0f, 0x0bb3, 0x0c1b, 0x0c3e, 0x0cb1, 0x0d4c, 0x0ec1,
91459182Storek 0x079a, 0x0614, 0x0521, 0x047c, 0x0422, 0x03b1, 0x03e3, 0x0333,
91559182Storek 0x0322, 0x031c, 0x02aa, 0x02ba, 0x02f2, 0x0242, 0x0232, 0x0227,
91659182Storek 0x0222, 0x021b, 0x01ad, 0x0212, 0x01b2, 0x01bb, 0x01cb, 0x01f6,
91759182Storek 0x0152, 0x013a, 0x0133, 0x0131, 0x012c, 0x0123, 0x0122, 0x00a2,
91859182Storek 0x011b, 0x011e, 0x0114, 0x00b1, 0x00aa, 0x00b3, 0x00bd, 0x00ba,
91959182Storek 0x00c5, 0x00d3, 0x00f3, 0x0062, 0x0051, 0x0042, 0x003b, 0x0033,
92059182Storek 0x0032, 0x002a, 0x002c, 0x0025, 0x0023, 0x0022, 0x001a, 0x0021,
92159182Storek 0x001b, 0x001b, 0x001d, 0x0015, 0x0013, 0x0013, 0x0012, 0x0012,
92259182Storek 0x000a, 0x000a, 0x0011, 0x0011, 0x000b, 0x000b, 0x000c, 0x000e,
92355102Storek };
92455102Storek
92559182Storek /*
92659182Storek * second stage play gain.
92759182Storek */
92859182Storek static const u_short ger_coeff[] = {
92959182Storek 0x431f, /* 5. dB */
93059182Storek 0x331f, /* 5.5 dB */
93159182Storek 0x40dd, /* 6. dB */
93259182Storek 0x11dd, /* 6.5 dB */
93359182Storek 0x440f, /* 7. dB */
93459182Storek 0x411f, /* 7.5 dB */
93559182Storek 0x311f, /* 8. dB */
93659182Storek 0x5520, /* 8.5 dB */
93759182Storek 0x10dd, /* 9. dB */
93859182Storek 0x4211, /* 9.5 dB */
93959182Storek 0x410f, /* 10. dB */
94059182Storek 0x111f, /* 10.5 dB */
94159182Storek 0x600b, /* 11. dB */
94259182Storek 0x00dd, /* 11.5 dB */
94359182Storek 0x4210, /* 12. dB */
94459182Storek 0x110f, /* 13. dB */
94559182Storek 0x7200, /* 14. dB */
94659182Storek 0x2110, /* 15. dB */
94759182Storek 0x2200, /* 15.9 dB */
94859182Storek 0x000b, /* 16.9 dB */
94959182Storek 0x000f /* 18. dB */
95059182Storek #define NGER (sizeof(ger_coeff) / sizeof(ger_coeff[0]))
95155102Storek };
95255102Storek
95355102Storek static void
ausetrgain(sc,level)95455102Storek ausetrgain(sc, level)
95555102Storek register struct audio_softc *sc;
95655102Storek register int level;
95755102Storek {
95855102Storek level &= 0xff;
95955102Storek sc->sc_rlevel = level;
96059182Storek sc->sc_map.mr_mmr1 |= AMD_MMR1_GX;
96159182Storek sc->sc_map.mr_gx = gx_coeff[level];
96255102Storek audio_setmmr1(sc->sc_au.au_amd, sc->sc_map.mr_mmr1,
96355102Storek AMDR_MAP_GX, sc->sc_map.mr_gx);
96455102Storek }
96555102Storek
96655102Storek static void
ausetpgain(sc,level)96755102Storek ausetpgain(sc, level)
96855102Storek register struct audio_softc *sc;
96955102Storek register int level;
97055102Storek {
97159182Storek register int gi, s;
97259182Storek register volatile struct amd7930 *amd;
97359182Storek
97455102Storek level &= 0xff;
97555102Storek sc->sc_plevel = level;
97659182Storek sc->sc_map.mr_mmr1 |= AMD_MMR1_GER|AMD_MMR1_GR;
97759182Storek level *= 256 + NGER;
97859182Storek level >>= 8;
97959182Storek if (level >= 256) {
98059182Storek gi = level - 256;
98159182Storek level = 255;
98259182Storek } else
98359182Storek gi = 0;
98459182Storek sc->sc_map.mr_ger = ger_coeff[gi];
98559182Storek sc->sc_map.mr_gr = gx_coeff[level];
98659182Storek
98759182Storek amd = sc->sc_au.au_amd;
98859182Storek s = splaudio();
98959182Storek amd->cr = AMDR_MAP_MMR1;
99059182Storek amd->dr = sc->sc_map.mr_mmr1;
99159182Storek amd->cr = AMDR_MAP_GR;
99259182Storek gi = sc->sc_map.mr_gr;
99359182Storek WAMD16(amd, gi);
99459182Storek amd->cr = AMDR_MAP_GER;
99559182Storek gi = sc->sc_map.mr_ger;
99659182Storek WAMD16(amd, gi);
99759182Storek splx(s);
99855102Storek }
99955102Storek
100055102Storek static void
ausetmgain(sc,level)100155102Storek ausetmgain(sc, level)
100255102Storek register struct audio_softc *sc;
100355102Storek register int level;
100455102Storek {
100555102Storek level &= 0xff;
100655102Storek sc->sc_mlevel = level;
100759182Storek sc->sc_map.mr_mmr1 |= AMD_MMR1_STG;
100859182Storek sc->sc_map.mr_stgr = gx_coeff[level];
100955102Storek audio_setmmr1(sc->sc_au.au_amd, sc->sc_map.mr_mmr1,
101055102Storek AMDR_MAP_STG, sc->sc_map.mr_stgr);
101155102Storek }
101255102Storek
101355102Storek static int
audiosetinfo(sc,ai)101455102Storek audiosetinfo(sc, ai)
101555102Storek struct audio_softc *sc;
101655102Storek struct audio_info *ai;
101755102Storek {
101855102Storek struct audio_prinfo *r = &ai->record, *p = &ai->play;
101955102Storek register int s, bsize;
102055102Storek
102155102Storek if (p->gain != ~0)
102255102Storek ausetpgain(sc, p->gain);
102355102Storek if (r->gain != ~0)
102455102Storek ausetrgain(sc, r->gain);
102555102Storek if (ai->monitor_gain != ~0)
102659182Storek ausetmgain(sc, ai->monitor_gain);
102755102Storek if (p->port == AUDIO_SPEAKER) {
102855102Storek sc->sc_map.mr_mmr2 |= AMD_MMR2_LS;
102955102Storek audio_setmmr2(sc->sc_au.au_amd, sc->sc_map.mr_mmr2);
103055102Storek } else if (p->port == AUDIO_HEADPHONE) {
103155102Storek sc->sc_map.mr_mmr2 &=~ AMD_MMR2_LS;
103255102Storek audio_setmmr2(sc->sc_au.au_amd, sc->sc_map.mr_mmr2);
103355102Storek }
103455102Storek if (p->pause != (u_char)~0)
103555102Storek sc->sc_au.au_wb.cb_pause = p->pause;
103655102Storek if (r->pause != (u_char)~0)
103755102Storek sc->sc_au.au_rb.cb_pause = r->pause;
103855102Storek
103955102Storek if (ai->blocksize != ~0) {
104055102Storek if (ai->blocksize == 0)
104155102Storek bsize = ai->blocksize = DEFBLKSIZE;
104255102Storek else if (ai->blocksize > MAXBLKSIZE)
104355102Storek bsize = ai->blocksize = MAXBLKSIZE;
104455102Storek else
104555102Storek bsize = ai->blocksize;
104655102Storek
104755102Storek s = splaudio();
104855102Storek sc->sc_au.au_blksize = bsize;
104955102Storek /* AUDIO_FLUSH */
105055102Storek AUCB_INIT(&sc->sc_au.au_rb);
105155102Storek AUCB_INIT(&sc->sc_au.au_wb);
105255102Storek splx(s);
105355102Storek
105455102Storek }
105555102Storek if (ai->hiwat != ~0 && (unsigned)ai->hiwat < AUCB_SIZE)
105655102Storek sc->sc_au.au_hiwat = ai->hiwat;
105755102Storek if (ai->lowat != ~0 && ai->lowat < AUCB_SIZE)
105855102Storek sc->sc_au.au_lowat = ai->lowat;
105959182Storek if (ai->backlog != ~0 && ai->backlog < (AUCB_SIZE/2))
106059182Storek sc->sc_au.au_backlog = ai->backlog;
106155102Storek
106255102Storek return (0);
106355102Storek }
106455102Storek
106555102Storek static int
sunaudiosetinfo(sc,ai)106655102Storek sunaudiosetinfo(sc, ai)
106755102Storek struct audio_softc *sc;
106855102Storek struct sun_audio_info *ai;
106955102Storek {
107055102Storek struct sun_audio_prinfo *r = &ai->record, *p = &ai->play;
107155102Storek
107255102Storek if (p->gain != ~0)
107355102Storek ausetpgain(sc, p->gain);
107455102Storek if (r->gain != ~0)
107555102Storek ausetrgain(sc, r->gain);
107655102Storek if (ai->monitor_gain != ~0)
107759182Storek ausetmgain(sc, ai->monitor_gain);
107855102Storek if (p->port == AUDIO_SPEAKER) {
107955102Storek sc->sc_map.mr_mmr2 |= AMD_MMR2_LS;
108055102Storek audio_setmmr2(sc->sc_au.au_amd, sc->sc_map.mr_mmr2);
108155102Storek } else if (p->port == AUDIO_HEADPHONE) {
108255102Storek sc->sc_map.mr_mmr2 &=~ AMD_MMR2_LS;
108355102Storek audio_setmmr2(sc->sc_au.au_amd, sc->sc_map.mr_mmr2);
108455102Storek }
108555102Storek /*
108655102Storek * The bsd driver does not distinguish between paused and active.
108755102Storek * (In the sun driver, not active means samples are not ouput
108855102Storek * at all, but paused means the last streams buffer is drained
108955102Storek * and then output stops.) If either are 0, then when stop output.
109055102Storek * Otherwise, if either are non-zero, we resume.
109155102Storek */
109255102Storek if (p->pause == 0 || p->active == 0)
109355102Storek sc->sc_au.au_wb.cb_pause = 0;
109455102Storek else if (p->pause != (u_char)~0 || p->active != (u_char)~0)
109555102Storek sc->sc_au.au_wb.cb_pause = 1;
109655102Storek if (r->pause == 0 || r->active == 0)
109755102Storek sc->sc_au.au_rb.cb_pause = 0;
109855102Storek else if (r->pause != (u_char)~0 || r->active != (u_char)~0)
109955102Storek sc->sc_au.au_rb.cb_pause = 1;
110055102Storek
110155102Storek return (0);
110255102Storek }
110355102Storek
110455102Storek static int
audiogetinfo(sc,ai)110555102Storek audiogetinfo(sc, ai)
110655102Storek struct audio_softc *sc;
110755102Storek struct audio_info *ai;
110855102Storek {
110955102Storek struct audio_prinfo *r = &ai->record, *p = &ai->play;
111055102Storek
111155102Storek p->sample_rate = r->sample_rate = 8000;
111255102Storek p->channels = r->channels = 1;
111355102Storek p->precision = r->precision = 8;
111455102Storek p->encoding = r->encoding = AUDIO_ENCODING_ULAW;
111555102Storek
111655102Storek ai->monitor_gain = sc->sc_mlevel;
111755102Storek r->gain = sc->sc_rlevel;
111855102Storek p->gain = sc->sc_plevel;
111955102Storek r->port = 1; p->port = (sc->sc_map.mr_mmr2 & AMD_MMR2_LS) ?
112055102Storek AUDIO_SPEAKER : AUDIO_HEADPHONE;
112155102Storek
112255102Storek p->pause = sc->sc_au.au_wb.cb_pause;
112355102Storek r->pause = sc->sc_au.au_rb.cb_pause;
112455102Storek p->error = sc->sc_au.au_wb.cb_drops != 0;
112555102Storek r->error = sc->sc_au.au_rb.cb_drops != 0;
112655102Storek
112755102Storek p->open = sc->sc_open;
112855102Storek r->open = sc->sc_open;
112955102Storek
113055102Storek p->samples = sc->sc_au.au_stamp - sc->sc_au.au_wb.cb_pdrops;
113155102Storek r->samples = sc->sc_au.au_stamp - sc->sc_au.au_rb.cb_pdrops;
113255102Storek
113355102Storek p->seek = sc->sc_wseek;
113455102Storek r->seek = sc->sc_rseek;
113555102Storek
113655102Storek ai->blocksize = sc->sc_au.au_blksize;
113755102Storek ai->hiwat = sc->sc_au.au_hiwat;
113855102Storek ai->lowat = sc->sc_au.au_lowat;
113959182Storek ai->backlog = sc->sc_au.au_backlog;
114055102Storek
114155102Storek return (0);
114255102Storek }
114355102Storek
114455102Storek static int
sunaudiogetinfo(sc,ai)114555102Storek sunaudiogetinfo(sc, ai)
114655102Storek struct audio_softc *sc;
114755102Storek struct sun_audio_info *ai;
114855102Storek {
114955102Storek struct sun_audio_prinfo *r = &ai->record, *p = &ai->play;
115055102Storek
115155102Storek p->sample_rate = r->sample_rate = 8000;
115255102Storek p->channels = r->channels = 1;
115355102Storek p->precision = r->precision = 8;
115455102Storek p->encoding = r->encoding = AUDIO_ENCODING_ULAW;
115555102Storek
115655102Storek ai->monitor_gain = sc->sc_mlevel;
115755102Storek r->gain = sc->sc_rlevel;
115855102Storek p->gain = sc->sc_plevel;
115955102Storek r->port = 1; p->port = (sc->sc_map.mr_mmr2 & AMD_MMR2_LS) ?
116055102Storek AUDIO_SPEAKER : AUDIO_HEADPHONE;
116155102Storek
116255102Storek p->active = p->pause = sc->sc_au.au_wb.cb_pause;
116355102Storek r->active = r->pause = sc->sc_au.au_rb.cb_pause;
116455102Storek p->error = sc->sc_au.au_wb.cb_drops != 0;
116555102Storek r->error = sc->sc_au.au_rb.cb_drops != 0;
116655102Storek
116755102Storek p->waiting = 0;
116855102Storek r->waiting = 0;
116955102Storek p->eof = 0;
117055102Storek r->eof = 0;
117155102Storek
117255102Storek p->open = sc->sc_open;
117355102Storek r->open = sc->sc_open;
117455102Storek
117555102Storek p->samples = sc->sc_au.au_stamp - sc->sc_au.au_wb.cb_pdrops;
117655102Storek r->samples = sc->sc_au.au_stamp - sc->sc_au.au_rb.cb_pdrops;
117755102Storek
117855102Storek return (0);
117955102Storek }
118055102Storek #endif
1181