1*55102Storek /* 2*55102Storek * Copyright (c) 1991, 1992 The Regents of the University of California. 3*55102Storek * All rights reserved. 4*55102Storek * 5*55102Storek * This software was developed by the Computer Systems Engineering group 6*55102Storek * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 7*55102Storek * contributed to Berkeley. 8*55102Storek * 9*55102Storek * %sccs.include.redist.c% 10*55102Storek * 11*55102Storek * @(#)bsd_audio.c 7.1 (Berkeley) 07/13/92 12*55102Storek * 13*55102Storek * from: $Header: bsd_audio.c,v 1.14 92/07/03 23:21:23 mccanne Exp $ (LBL) 14*55102Storek */ 15*55102Storek #include "bsdaudio.h" 16*55102Storek #if NBSDAUDIO > 0 17*55102Storek 18*55102Storek #include "sys/param.h" 19*55102Storek #include "sys/systm.h" 20*55102Storek 21*55102Storek #if BSD < 199103 22*55102Storek #ifndef SUNOS 23*55102Storek #define SUNOS 24*55102Storek #endif 25*55102Storek #endif 26*55102Storek 27*55102Storek #include "sys/errno.h" 28*55102Storek #include "sys/file.h" 29*55102Storek #include "sys/proc.h" 30*55102Storek #include "sys/user.h" 31*55102Storek #include "sys/vnode.h" 32*55102Storek #include "sys/ioctl.h" 33*55102Storek #include "sys/time.h" 34*55102Storek #ifndef SUNOS 35*55102Storek #include "sys/tty.h" 36*55102Storek #endif 37*55102Storek #include "sys/uio.h" 38*55102Storek 39*55102Storek #ifdef SUNOS 40*55102Storek #include <sundev/mbvar.h> 41*55102Storek #include <sun4c/intreg.h> 42*55102Storek #else 43*55102Storek #include "sys/device.h" 44*55102Storek #include "machine/autoconf.h" 45*55102Storek #endif 46*55102Storek #include "machine/cpu.h" 47*55102Storek 48*55102Storek /* 49*55102Storek * Avoid name clashes with SunOS so we can config either the bsd or sun 50*55102Storek * streams driver in a SunOS kernel. 51*55102Storek */ 52*55102Storek #ifdef SUNOS 53*55102Storek #include "sbusdev/bsd_audioreg.h" 54*55102Storek #include "sbusdev/bsd_audiovar.h" 55*55102Storek #include "sbusdev/bsd_audioio.h" 56*55102Storek struct selinfo { 57*55102Storek struct proc *si_proc; 58*55102Storek int si_coll; 59*55102Storek }; 60*55102Storek #else 61*55102Storek #include "../dev/bsd_audioreg.h" 62*55102Storek #include "../dev/bsd_audiovar.h" 63*55102Storek #include "machine/bsd_audioio.h" 64*55102Storek #endif 65*55102Storek 66*55102Storek #ifdef SUNOS 67*55102Storek #include "bsd_audiocompat.h" 68*55102Storek #endif 69*55102Storek 70*55102Storek /* 71*55102Storek * Initial/default block size is patchable. 72*55102Storek */ 73*55102Storek int audio_blocksize = DEFBLKSIZE; 74*55102Storek 75*55102Storek /* 76*55102Storek * Software state, per AMD79C30 audio chip. 77*55102Storek */ 78*55102Storek struct audio_softc { 79*55102Storek #ifndef SUNOS 80*55102Storek struct device sc_dev; /* base device */ 81*55102Storek struct intrhand sc_hwih; /* hardware interrupt vector */ 82*55102Storek struct intrhand sc_swih; /* software interrupt vector */ 83*55102Storek #endif 84*55102Storek int sc_interrupts; /* number of interrupts taken */ 85*55102Storek 86*55102Storek int sc_open; /* single use device */ 87*55102Storek u_long sc_wseek; /* timestamp of last frame written */ 88*55102Storek u_long sc_rseek; /* timestamp of last frame read */ 89*55102Storek struct mapreg sc_map; /* current contents of map registers */ 90*55102Storek struct selinfo sc_wsel; /* write selector */ 91*55102Storek struct selinfo sc_rsel; /* read selector */ 92*55102Storek /* 93*55102Storek * keep track of levels so we don't have to convert back from 94*55102Storek * MAP gain constants 95*55102Storek */ 96*55102Storek int sc_rlevel; /* record level */ 97*55102Storek int sc_plevel; /* play level */ 98*55102Storek int sc_mlevel; /* monitor level */ 99*55102Storek 100*55102Storek /* sc_au is special in that the hardware interrupt handler uses it */ 101*55102Storek struct auio sc_au; /* recv and xmit buffers, etc */ 102*55102Storek 103*55102Storek }; 104*55102Storek 105*55102Storek /* interrupt interfaces */ 106*55102Storek #ifndef AUDIO_C_HANDLER 107*55102Storek int audiohwintr __P((void *)); 108*55102Storek #endif 109*55102Storek int audioswintr __P((void *)); 110*55102Storek 111*55102Storek /* forward declarations */ 112*55102Storek int audio_sleep __P((struct aucb *, int)); 113*55102Storek void audio_setmap __P((volatile struct amd7930 *, struct mapreg *)); 114*55102Storek 115*55102Storek static void init_amd(); 116*55102Storek 117*55102Storek #if !defined(AUDIO_C_HANDLER) || defined(SUNOS) 118*55102Storek struct auio *audio_au; 119*55102Storek extern void audio_trap(); 120*55102Storek #endif 121*55102Storek 122*55102Storek #ifdef SUNOS 123*55102Storek struct audio_softc audio_softc; 124*55102Storek #define SOFTC(dev) &audio_softc 125*55102Storek #define UIOMOVE(cp, len, code, uio) uiomove(cp, len, code, uio) 126*55102Storek 127*55102Storek #define AUDIOOPEN(d, f, i, p)\ 128*55102Storek audioopen(d, f, i)\ 129*55102Storek dev_t d; int f, i; 130*55102Storek #define AUDIOCLOSE(d, f, i, p)\ 131*55102Storek audioclose(d, f, i)\ 132*55102Storek dev_t d; int f, i; 133*55102Storek #define AUDIOREAD(d, u, f) \ 134*55102Storek audioread(d, u) dev_t d; struct uio *u; 135*55102Storek #define AUDIOWRITE(d, u, f) \ 136*55102Storek audiowrite(d, u) dev_t d; struct uio *u; 137*55102Storek #define AUDIOIOCTL(d, c, a, f, o)\ 138*55102Storek audioioctl(d, c, a, f)\ 139*55102Storek dev_t d; int c; caddr_t a; int f; 140*55102Storek #define AUDIOSELECT(d, r, p)\ 141*55102Storek audio_select(d, r, p)\ 142*55102Storek dev_t d; int r; struct proc *p; 143*55102Storek 144*55102Storek 145*55102Storek #define AUDIO_SET_SWINTR set_intreg(IR_SOFT_INT4, 1) 146*55102Storek 147*55102Storek int 148*55102Storek audioselect(dev, rw) 149*55102Storek register dev_t dev; 150*55102Storek int rw; 151*55102Storek { 152*55102Storek return (audio_select(dev, rw, u.u_procp)); 153*55102Storek } 154*55102Storek 155*55102Storek static void 156*55102Storek selrecord(p, si) 157*55102Storek struct proc *p; 158*55102Storek struct selinfo *si; 159*55102Storek { 160*55102Storek if (si->si_proc != 0) 161*55102Storek si->si_coll = 1; 162*55102Storek else 163*55102Storek si->si_proc = p; 164*55102Storek } 165*55102Storek #define SELWAKEUP(si) \ 166*55102Storek {\ 167*55102Storek if ((si)->si_proc != 0) {\ 168*55102Storek selwakeup((si)->si_proc, (si)->si_coll); \ 169*55102Storek (si)->si_proc = 0;\ 170*55102Storek (si)->si_coll = 0;\ 171*55102Storek }\ 172*55102Storek } 173*55102Storek 174*55102Storek 175*55102Storek static int audioattach(); 176*55102Storek static int audioidentify(); 177*55102Storek 178*55102Storek struct dev_ops bsdaudio_ops = { 179*55102Storek 0, 180*55102Storek audioidentify, 181*55102Storek audioattach, 182*55102Storek }; 183*55102Storek 184*55102Storek static int 185*55102Storek audioidentify(cp) 186*55102Storek char *cp; 187*55102Storek { 188*55102Storek return (strcmp(cp, "audio") == 0); 189*55102Storek } 190*55102Storek 191*55102Storek static int 192*55102Storek audioattach(dev) 193*55102Storek struct dev_info *dev; 194*55102Storek { 195*55102Storek register struct audio_softc *sc; 196*55102Storek register volatile struct amd7930 *amd; 197*55102Storek struct dev_reg *reg; 198*55102Storek 199*55102Storek sc = &audio_softc; 200*55102Storek if (dev->devi_nreg != 1 || dev->devi_nintr != 1) { 201*55102Storek printf("audio: bad config\n"); 202*55102Storek return (-1); 203*55102Storek } 204*55102Storek reg = dev->devi_reg; 205*55102Storek amd = (struct amd7930 *)map_regs(reg->reg_addr, reg->reg_size, 206*55102Storek reg->reg_bustype); 207*55102Storek sc->sc_au.au_amd = amd; 208*55102Storek init_amd(amd); 209*55102Storek 210*55102Storek audio_au = &sc->sc_au; 211*55102Storek #ifndef AUDIO_C_HANDLER 212*55102Storek settrap(dev->devi_intr->int_pri, audio_trap); 213*55102Storek #else 214*55102Storek /* XXX */ 215*55102Storek addintr(dev->devi_intr->int_pri, audiohwintr, dev->devi_name, 216*55102Storek dev->devi_unit); 217*55102Storek #endif 218*55102Storek addintr(4, audioswintr, dev->devi_name, dev->devi_unit); 219*55102Storek report_dev(dev); 220*55102Storek 221*55102Storek return (0); 222*55102Storek } 223*55102Storek #else 224*55102Storek #define AUDIOOPEN(d, f, i, p) audioopen(dev_t d, int f, int i, struct proc *p) 225*55102Storek #define AUDIOCLOSE(d, f, i, p) audioclose(dev_t d, int f, int i, \ 226*55102Storek struct proc *p) 227*55102Storek #define AUDIOREAD(d, u, f) audioread(dev_t d, struct uio *u, int f) 228*55102Storek #define AUDIOWRITE(d, u, f) audiowrite(dev_t d, struct uio *u, int f) 229*55102Storek #define AUDIOIOCTL(d, c, a, f, o)\ 230*55102Storek audioioctl(dev_t dev, int c, caddr_t a, int f, struct proc *p) 231*55102Storek #define AUDIOSELECT(d, r, p) audioselect(dev_t dev, int rw, struct proc *p) 232*55102Storek #define SELWAKEUP selwakeup 233*55102Storek 234*55102Storek #define AUDIO_SET_SWINTR ienab_bis(IE_L6) 235*55102Storek 236*55102Storek /* autoconfiguration driver */ 237*55102Storek void audioattach(struct device *, struct device *, void *); 238*55102Storek struct cfdriver audiocd = 239*55102Storek { NULL, "audio", matchbyname, audioattach, 240*55102Storek DV_DULL, sizeof(struct audio_softc) }; 241*55102Storek #define SOFTC(dev) audiocd.cd_devs[minor(dev)] 242*55102Storek #define UIOMOVE(cp, len, code, uio) uiomove(cp, len, uio) 243*55102Storek 244*55102Storek /* 245*55102Storek * Audio chip found. 246*55102Storek */ 247*55102Storek void 248*55102Storek audioattach(parent, self, args) 249*55102Storek struct device *parent, *self; 250*55102Storek void *args; 251*55102Storek { 252*55102Storek register struct audio_softc *sc = (struct audio_softc *)self; 253*55102Storek register struct romaux *ra = args; 254*55102Storek register volatile struct amd7930 *amd; 255*55102Storek register int pri; 256*55102Storek 257*55102Storek if (ra->ra_nintr != 1) { 258*55102Storek printf(": expected 1 interrupt, got %d\n", ra->ra_nintr); 259*55102Storek return; 260*55102Storek } 261*55102Storek pri = ra->ra_intr[0].int_pri; 262*55102Storek printf(" pri %d, softpri %d\n", pri, PIL_AUSOFT); 263*55102Storek amd = (volatile struct amd7930 *)(ra->ra_vaddr ? 264*55102Storek ra->ra_vaddr : mapiodev(ra->ra_paddr, sizeof *amd)); 265*55102Storek sc->sc_au.au_amd = amd; 266*55102Storek 267*55102Storek init_amd(amd); 268*55102Storek 269*55102Storek #ifndef AUDIO_C_HANDLER 270*55102Storek audio_au = &sc->sc_au; 271*55102Storek intr_fasttrap(pri, audio_trap); 272*55102Storek #else 273*55102Storek sc->sc_hwih.ih_fun = audiohwintr; 274*55102Storek sc->sc_hwih.ih_arg = &sc->sc_au; 275*55102Storek intr_establish(pri, &sc->sc_hwih); 276*55102Storek #endif 277*55102Storek sc->sc_swih.ih_fun = audioswintr; 278*55102Storek sc->sc_swih.ih_arg = sc; 279*55102Storek intr_establish(PIL_AUSOFT, &sc->sc_swih); 280*55102Storek } 281*55102Storek #endif 282*55102Storek 283*55102Storek static void 284*55102Storek init_amd(amd) 285*55102Storek register volatile struct amd7930 *amd; 286*55102Storek { 287*55102Storek /* disable interrupts */ 288*55102Storek amd->cr = AMDR_INIT; 289*55102Storek amd->dr = AMD_INIT_PMS_ACTIVE | AMD_INIT_INT_DISABLE; 290*55102Storek 291*55102Storek /* 292*55102Storek * Initialize the mux unit. We use MCR3 to route audio (MAP) 293*55102Storek * through channel Bb. MCR1 and MCR2 are unused. 294*55102Storek * Setting the INT enable bit in MCR4 will generate an interrupt 295*55102Storek * on each converted audio sample. 296*55102Storek */ 297*55102Storek amd->cr = AMDR_MUX_1_4; 298*55102Storek amd->dr = 0; 299*55102Storek amd->dr = 0; 300*55102Storek amd->dr = (AMD_MCRCHAN_BB << 4) | AMD_MCRCHAN_BA; 301*55102Storek amd->dr = AMD_MCR4_INT_ENABLE; 302*55102Storek } 303*55102Storek 304*55102Storek static int audio_default_level = 150; 305*55102Storek static void ausetrgain __P((struct audio_softc *, int)); 306*55102Storek static void ausetpgain __P((struct audio_softc *, int)); 307*55102Storek static int audiosetinfo __P((struct audio_softc *, struct audio_info *)); 308*55102Storek static int audiogetinfo __P((struct audio_softc *, struct audio_info *)); 309*55102Storek struct sun_audio_info; 310*55102Storek static int sunaudiosetinfo __P((struct audio_softc *, 311*55102Storek struct sun_audio_info *)); 312*55102Storek static int sunaudiogetinfo __P((struct audio_softc *, 313*55102Storek struct sun_audio_info *)); 314*55102Storek static void audio_setmmr2 __P((volatile struct amd7930 *, int)); 315*55102Storek 316*55102Storek int 317*55102Storek AUDIOOPEN(dev, flags, ifmt, p) 318*55102Storek { 319*55102Storek register struct audio_softc *sc; 320*55102Storek register volatile struct amd7930 *amd; 321*55102Storek int unit = minor(dev), error, s; 322*55102Storek 323*55102Storek #ifdef SUNOS 324*55102Storek if (unit > 0) 325*55102Storek return (ENXIO); 326*55102Storek sc = &audio_softc; 327*55102Storek #else 328*55102Storek if (unit >= audiocd.cd_ndevs || (sc = audiocd.cd_devs[unit]) == NULL) 329*55102Storek return (ENXIO); 330*55102Storek #endif 331*55102Storek if (sc->sc_open) 332*55102Storek return (EBUSY); 333*55102Storek sc->sc_open = 1; 334*55102Storek 335*55102Storek sc->sc_au.au_lowat = audio_blocksize; 336*55102Storek sc->sc_au.au_hiwat = AUCB_SIZE - sc->sc_au.au_lowat; 337*55102Storek sc->sc_au.au_blksize = audio_blocksize; 338*55102Storek 339*55102Storek /* set up read and write blocks and `dead sound' zero value. */ 340*55102Storek AUCB_INIT(&sc->sc_au.au_rb); 341*55102Storek sc->sc_au.au_rb.cb_thresh = AUCB_SIZE; 342*55102Storek AUCB_INIT(&sc->sc_au.au_wb); 343*55102Storek sc->sc_au.au_wb.cb_thresh = -1; 344*55102Storek 345*55102Storek /* nothing read or written yet */ 346*55102Storek sc->sc_rseek = 0; 347*55102Storek sc->sc_wseek = 0; 348*55102Storek 349*55102Storek bzero((char *)&sc->sc_map, sizeof sc->sc_map); 350*55102Storek /* default to speaker */ 351*55102Storek sc->sc_map.mr_mmr2 = AMD_MMR2_AINB | AMD_MMR2_LS; 352*55102Storek 353*55102Storek /* enable interrupts and set parameters established above */ 354*55102Storek amd = sc->sc_au.au_amd; 355*55102Storek audio_setmmr2(amd, sc->sc_map.mr_mmr2); 356*55102Storek ausetrgain(sc, audio_default_level); 357*55102Storek ausetpgain(sc, audio_default_level); 358*55102Storek amd->cr = AMDR_INIT; 359*55102Storek amd->dr = AMD_INIT_PMS_ACTIVE; 360*55102Storek 361*55102Storek return (0); 362*55102Storek } 363*55102Storek 364*55102Storek static int 365*55102Storek audio_drain(sc) 366*55102Storek register struct audio_softc *sc; 367*55102Storek { 368*55102Storek register int error; 369*55102Storek 370*55102Storek while (!AUCB_EMPTY(&sc->sc_au.au_wb)) 371*55102Storek if ((error = audio_sleep(&sc->sc_au.au_wb, 0)) != 0) 372*55102Storek return (error); 373*55102Storek return (0); 374*55102Storek } 375*55102Storek 376*55102Storek /* 377*55102Storek * Close an audio chip. 378*55102Storek */ 379*55102Storek /* ARGSUSED */ 380*55102Storek int 381*55102Storek AUDIOCLOSE(dev, flags, ifmt, p) 382*55102Storek { 383*55102Storek register struct audio_softc *sc = SOFTC(dev); 384*55102Storek register volatile struct amd7930 *amd; 385*55102Storek register struct aucb *cb; 386*55102Storek register int s; 387*55102Storek 388*55102Storek /* 389*55102Storek * Block until output drains, but allow ^C interrupt. 390*55102Storek */ 391*55102Storek sc->sc_au.au_lowat = 0; /* avoid excessive wakeups */ 392*55102Storek s = splaudio(); 393*55102Storek /* 394*55102Storek * If there is pending output, let it drain (unless 395*55102Storek * the output is paused). 396*55102Storek */ 397*55102Storek cb = &sc->sc_au.au_wb; 398*55102Storek if (!AUCB_EMPTY(cb) && !cb->cb_pause) 399*55102Storek (void)audio_drain(sc); 400*55102Storek /* 401*55102Storek * Disable interrupts, clear open flag, and done. 402*55102Storek */ 403*55102Storek amd = sc->sc_au.au_amd; 404*55102Storek amd->cr = AMDR_INIT; 405*55102Storek amd->dr = AMD_INIT_PMS_ACTIVE | AMD_INIT_INT_DISABLE; 406*55102Storek splx(s); 407*55102Storek sc->sc_open = 0; 408*55102Storek return (0); 409*55102Storek } 410*55102Storek 411*55102Storek int 412*55102Storek audio_sleep(cb, thresh) 413*55102Storek register struct aucb *cb; 414*55102Storek register int thresh; 415*55102Storek { 416*55102Storek register int error; 417*55102Storek 418*55102Storek cb->cb_thresh = thresh; 419*55102Storek error = tsleep((caddr_t)cb, (PZERO + 1) | PCATCH, "audio", 0); 420*55102Storek return (error); 421*55102Storek } 422*55102Storek 423*55102Storek int 424*55102Storek AUDIOREAD(dev, uio, ioflag) 425*55102Storek { 426*55102Storek register struct audio_softc *sc = SOFTC(dev); 427*55102Storek register struct aucb *cb; 428*55102Storek register int s, n, head, taildata, error; 429*55102Storek register int blocksize = sc->sc_au.au_blksize; 430*55102Storek 431*55102Storek if (uio->uio_resid == 0) 432*55102Storek return (0); 433*55102Storek cb = &sc->sc_au.au_rb; 434*55102Storek error = 0; 435*55102Storek s = splaudio(); 436*55102Storek cb->cb_drops = 0; 437*55102Storek sc->sc_rseek = sc->sc_au.au_stamp - AUCB_LEN(cb); 438*55102Storek do { 439*55102Storek while (AUCB_LEN(cb) < blocksize) { 440*55102Storek #ifndef SUNOS 441*55102Storek if (ioflag & IO_NDELAY) { 442*55102Storek error = EWOULDBLOCK; 443*55102Storek goto out; 444*55102Storek } 445*55102Storek #endif 446*55102Storek if ((error = audio_sleep(cb, blocksize)) != 0) 447*55102Storek goto out; 448*55102Storek } 449*55102Storek splx(s); 450*55102Storek /* 451*55102Storek * The space calculation can only err on the short 452*55102Storek * side if an interrupt occurs during processing: 453*55102Storek * only cb_tail is altered in the interrupt code. 454*55102Storek */ 455*55102Storek head = cb->cb_head; 456*55102Storek if ((n = AUCB_LEN(cb)) > uio->uio_resid) 457*55102Storek n = uio->uio_resid; 458*55102Storek taildata = AUCB_SIZE - head; 459*55102Storek if (n > taildata) { 460*55102Storek error = UIOMOVE((caddr_t)cb->cb_data + head, 461*55102Storek taildata, UIO_READ, uio); 462*55102Storek if (error == 0) 463*55102Storek error = UIOMOVE((caddr_t)cb->cb_data, 464*55102Storek n - taildata, UIO_READ, uio); 465*55102Storek } else 466*55102Storek error = UIOMOVE((caddr_t)cb->cb_data + head, n, 467*55102Storek UIO_READ, uio); 468*55102Storek if (error) 469*55102Storek return (error); 470*55102Storek head = AUCB_MOD(head + n); 471*55102Storek (void) splaudio(); 472*55102Storek cb->cb_head = head; 473*55102Storek } while (uio->uio_resid >= blocksize); 474*55102Storek out: 475*55102Storek splx(s); 476*55102Storek return (error); 477*55102Storek } 478*55102Storek 479*55102Storek int 480*55102Storek AUDIOWRITE(dev, uio, ioflag) 481*55102Storek { 482*55102Storek register struct audio_softc *sc = SOFTC(dev); 483*55102Storek register struct aucb *cb = &sc->sc_au.au_wb; 484*55102Storek register int s, n, tail, tailspace, error, first, watermark, drops; 485*55102Storek 486*55102Storek error = 0; 487*55102Storek first = 1; 488*55102Storek s = splaudio(); 489*55102Storek while (uio->uio_resid > 0) { 490*55102Storek watermark = sc->sc_au.au_hiwat; 491*55102Storek while (AUCB_LEN(cb) > watermark) { 492*55102Storek #ifndef SUNOS 493*55102Storek if (ioflag & IO_NDELAY) { 494*55102Storek error = EWOULDBLOCK; 495*55102Storek goto out; 496*55102Storek } 497*55102Storek #endif 498*55102Storek if ((error = audio_sleep(cb, watermark)) != 0) 499*55102Storek goto out; 500*55102Storek watermark = sc->sc_au.au_lowat; 501*55102Storek } 502*55102Storek splx(s); 503*55102Storek /* 504*55102Storek * The only value that can change on an interrupt is 505*55102Storek * cb->cb_head. We only pull that out once to decide 506*55102Storek * how much to write into cb_data; if we lose a race 507*55102Storek * and cb_head changes, we will merely be overly 508*55102Storek * conservative. For a legitimate time stamp, 509*55102Storek * however, we need to synchronize the accesses to 510*55102Storek * au_stamp and cb_head at a high ipl below. 511*55102Storek */ 512*55102Storek if ((n = AUCB_SIZE - AUCB_LEN(cb) - 1) > uio->uio_resid) 513*55102Storek n = uio->uio_resid; 514*55102Storek tail = cb->cb_tail; 515*55102Storek tailspace = AUCB_SIZE - tail; 516*55102Storek if (n > tailspace) { 517*55102Storek /* write first part at tail and rest at head */ 518*55102Storek error = UIOMOVE((caddr_t)cb->cb_data + tail, 519*55102Storek tailspace, UIO_WRITE, uio); 520*55102Storek if (error == 0) 521*55102Storek error = UIOMOVE((caddr_t)cb->cb_data, 522*55102Storek n - tailspace, UIO_WRITE, uio); 523*55102Storek } else 524*55102Storek error = UIOMOVE((caddr_t)cb->cb_data + tail, n, 525*55102Storek UIO_WRITE, uio); 526*55102Storek if (error) 527*55102Storek return (error); 528*55102Storek /* 529*55102Storek * We cannot do this outside the loop because if the 530*55102Storek * buffer is empty, an indeterminate amount of time 531*55102Storek * will pass before the output starts to drain. 532*55102Storek */ 533*55102Storek (void)splaudio(); 534*55102Storek tail = AUCB_MOD(tail + n); 535*55102Storek if (first) { 536*55102Storek first = 0; 537*55102Storek sc->sc_wseek = sc->sc_au.au_stamp + AUCB_LEN(cb) + 1; 538*55102Storek /* 539*55102Storek * To guarantee that a write is contiguous in the 540*55102Storek * sample space, we clear the drop count the first 541*55102Storek * time through. If we later get drops, we will 542*55102Storek * break out of the loop below, before writing 543*55102Storek * a new frame. 544*55102Storek * XXX I think we're one iteration too late! 545*55102Storek */ 546*55102Storek cb->cb_drops = 0; 547*55102Storek } 548*55102Storek cb->cb_tail = tail; 549*55102Storek if (cb->cb_drops != 0) 550*55102Storek break; 551*55102Storek } 552*55102Storek out: 553*55102Storek splx(s); 554*55102Storek return (error); 555*55102Storek } 556*55102Storek 557*55102Storek /* Sun audio compatibility */ 558*55102Storek struct sun_audio_prinfo { 559*55102Storek u_int sample_rate; 560*55102Storek u_int channels; 561*55102Storek u_int precision; 562*55102Storek u_int encoding; 563*55102Storek u_int gain; 564*55102Storek u_int port; 565*55102Storek u_int reserved0[4]; 566*55102Storek u_int samples; 567*55102Storek u_int eof; 568*55102Storek u_char pause; 569*55102Storek u_char error; 570*55102Storek u_char waiting; 571*55102Storek u_char reserved1[3]; 572*55102Storek u_char open; 573*55102Storek u_char active; 574*55102Storek }; 575*55102Storek struct sun_audio_info { 576*55102Storek struct sun_audio_prinfo play; 577*55102Storek struct sun_audio_prinfo record; 578*55102Storek u_int monitor_gain; 579*55102Storek u_int reserved[4]; 580*55102Storek }; 581*55102Storek 582*55102Storek #ifndef SUNOS 583*55102Storek #define SUNAUDIO_GETINFO _IOR('A', 1, struct sun_audio_info) 584*55102Storek #define SUNAUDIO_SETINFO _IOWR('A', 2, struct sun_audio_info) 585*55102Storek #else 586*55102Storek #define SUNAUDIO_GETINFO _IOR(A, 1, struct sun_audio_info) 587*55102Storek #define SUNAUDIO_SETINFO _IOWR(A, 2, struct sun_audio_info) 588*55102Storek #endif 589*55102Storek 590*55102Storek int 591*55102Storek AUDIOIOCTL(dev, cmd, addr, flag, p) 592*55102Storek { 593*55102Storek register struct audio_softc *sc = SOFTC(dev); 594*55102Storek int error = 0, i, s; 595*55102Storek 596*55102Storek switch (cmd) { 597*55102Storek 598*55102Storek case AUDIO_GETMAP: 599*55102Storek bcopy((caddr_t)&sc->sc_map, addr, sizeof(sc->sc_map)); 600*55102Storek break; 601*55102Storek 602*55102Storek case AUDIO_SETMAP: 603*55102Storek bcopy(addr, (caddr_t)&sc->sc_map, sizeof(sc->sc_map)); 604*55102Storek sc->sc_map.mr_mmr2 &= 0x7f; 605*55102Storek audio_setmap(sc->sc_au.au_amd, &sc->sc_map); 606*55102Storek break; 607*55102Storek 608*55102Storek case AUDIO_FLUSH: 609*55102Storek s = splaudio(); 610*55102Storek AUCB_INIT(&sc->sc_au.au_rb); 611*55102Storek AUCB_INIT(&sc->sc_au.au_wb); 612*55102Storek splx(s); 613*55102Storek sc->sc_wseek = 0; 614*55102Storek sc->sc_rseek = 0; 615*55102Storek break; 616*55102Storek 617*55102Storek /* 618*55102Storek * Number of read samples dropped. We don't know where or 619*55102Storek * when they were dropped. 620*55102Storek */ 621*55102Storek case AUDIO_RERROR: 622*55102Storek *(int *)addr = sc->sc_au.au_rb.cb_drops != 0; 623*55102Storek break; 624*55102Storek 625*55102Storek /* 626*55102Storek * Timestamp of last frame written. 627*55102Storek */ 628*55102Storek case AUDIO_WSEEK: 629*55102Storek *(u_long *)addr = sc->sc_wseek; 630*55102Storek break; 631*55102Storek 632*55102Storek case AUDIO_SETINFO: 633*55102Storek error = audiosetinfo(sc, (struct audio_info *)addr); 634*55102Storek break; 635*55102Storek 636*55102Storek case AUDIO_GETINFO: 637*55102Storek error = audiogetinfo(sc, (struct audio_info *)addr); 638*55102Storek break; 639*55102Storek 640*55102Storek case SUNAUDIO_GETINFO: 641*55102Storek error = sunaudiogetinfo(sc, (struct sun_audio_info *)addr); 642*55102Storek break; 643*55102Storek 644*55102Storek case SUNAUDIO_SETINFO: 645*55102Storek error = sunaudiosetinfo(sc, (struct sun_audio_info *)addr); 646*55102Storek break; 647*55102Storek 648*55102Storek case AUDIO_DRAIN: 649*55102Storek s = splaudio(); 650*55102Storek error = audio_drain(sc); 651*55102Storek splx(s); 652*55102Storek break; 653*55102Storek 654*55102Storek default: 655*55102Storek error = EINVAL; 656*55102Storek break; 657*55102Storek } 658*55102Storek return (error); 659*55102Storek } 660*55102Storek 661*55102Storek int 662*55102Storek AUDIOSELECT(dev, rw, p) 663*55102Storek { 664*55102Storek register struct audio_softc *sc = SOFTC(dev); 665*55102Storek register struct aucb *cb; 666*55102Storek register int s = splaudio(); 667*55102Storek 668*55102Storek switch (rw) { 669*55102Storek 670*55102Storek case FREAD: 671*55102Storek cb = &sc->sc_au.au_rb; 672*55102Storek if (AUCB_LEN(cb) >= sc->sc_au.au_blksize) { 673*55102Storek splx(s); 674*55102Storek return (1); 675*55102Storek } 676*55102Storek selrecord(p, &sc->sc_rsel); 677*55102Storek cb->cb_thresh = sc->sc_au.au_blksize; 678*55102Storek break; 679*55102Storek 680*55102Storek case FWRITE: 681*55102Storek cb = &sc->sc_au.au_wb; 682*55102Storek if (AUCB_LEN(cb) <= sc->sc_au.au_lowat) { 683*55102Storek splx(s); 684*55102Storek return (1); 685*55102Storek } 686*55102Storek selrecord(p, &sc->sc_wsel); 687*55102Storek cb->cb_thresh = sc->sc_au.au_lowat; 688*55102Storek break; 689*55102Storek } 690*55102Storek splx(s); 691*55102Storek return (0); 692*55102Storek } 693*55102Storek 694*55102Storek #ifdef AUDIO_C_HANDLER 695*55102Storek int 696*55102Storek audiohwintr(au0) 697*55102Storek void *au0; 698*55102Storek { 699*55102Storek #ifdef SUNOS 700*55102Storek register struct auio *au = audio_au; 701*55102Storek #else 702*55102Storek register struct auio *au = au0; 703*55102Storek #endif 704*55102Storek register volatile struct amd7930 *amd = au->au_amd; 705*55102Storek register struct aucb *cb; 706*55102Storek register int h, t, k; 707*55102Storek 708*55102Storek k = amd->ir; /* clear interrupt */ 709*55102Storek ++au->au_stamp; 710*55102Storek 711*55102Storek /* receive incoming data */ 712*55102Storek cb = &au->au_rb; 713*55102Storek h = cb->cb_head; 714*55102Storek t = cb->cb_tail; 715*55102Storek k = AUCB_MOD(t + 1); 716*55102Storek if (h == k) 717*55102Storek cb->cb_drops++; 718*55102Storek else if (cb->cb_pause != 0) 719*55102Storek cb->cb_pdrops++; 720*55102Storek else { 721*55102Storek cb->cb_data[t] = amd->bbrb; 722*55102Storek cb->cb_tail = t = k; 723*55102Storek } 724*55102Storek if (AUCB_MOD(t - h) >= cb->cb_thresh) { 725*55102Storek cb->cb_thresh = AUCB_SIZE; 726*55102Storek cb->cb_waking = 1; 727*55102Storek AUDIO_SET_SWINTR; 728*55102Storek } 729*55102Storek /* send outgoing data */ 730*55102Storek cb = &au->au_wb; 731*55102Storek h = cb->cb_head; 732*55102Storek t = cb->cb_tail; 733*55102Storek if (h == t) 734*55102Storek cb->cb_drops++; 735*55102Storek else if (cb->cb_pause != 0) 736*55102Storek cb->cb_pdrops++; 737*55102Storek else { 738*55102Storek cb->cb_head = h = AUCB_MOD(h + 1); 739*55102Storek amd->bbtb = cb->cb_data[h]; 740*55102Storek } 741*55102Storek if (AUCB_MOD(t - h) <= cb->cb_thresh) { 742*55102Storek cb->cb_thresh = -1; 743*55102Storek cb->cb_waking = 1; 744*55102Storek AUDIO_SET_SWINTR; 745*55102Storek } 746*55102Storek return (1); 747*55102Storek } 748*55102Storek #endif 749*55102Storek 750*55102Storek int 751*55102Storek audioswintr(sc0) 752*55102Storek void *sc0; 753*55102Storek { 754*55102Storek register struct audio_softc *sc; 755*55102Storek register int s, ret = 0; 756*55102Storek #ifdef SUNOS 757*55102Storek sc = &audio_softc; 758*55102Storek #else 759*55102Storek sc = sc0; 760*55102Storek #endif 761*55102Storek s = splaudio(); 762*55102Storek if (sc->sc_au.au_rb.cb_waking != 0) { 763*55102Storek sc->sc_au.au_rb.cb_waking = 0; 764*55102Storek splx(s); 765*55102Storek ret = 1; 766*55102Storek wakeup((caddr_t)&sc->sc_au.au_rb); 767*55102Storek SELWAKEUP(&sc->sc_rsel); 768*55102Storek (void) splaudio(); 769*55102Storek } 770*55102Storek if (sc->sc_au.au_wb.cb_waking != 0) { 771*55102Storek sc->sc_au.au_wb.cb_waking = 0; 772*55102Storek splx(s); 773*55102Storek ret = 1; 774*55102Storek wakeup((caddr_t)&sc->sc_au.au_wb); 775*55102Storek SELWAKEUP(&sc->sc_wsel); 776*55102Storek } else 777*55102Storek splx(s); 778*55102Storek return (ret); 779*55102Storek } 780*55102Storek 781*55102Storek /* Write 16 bits of data from variable v to the data port of the audio chip */ 782*55102Storek 783*55102Storek #define WAMD16(amd, v) ((amd)->dr = v, (amd)->dr = v >> 8) 784*55102Storek 785*55102Storek void 786*55102Storek audio_setmap(amd, map) 787*55102Storek register volatile struct amd7930 *amd; 788*55102Storek register struct mapreg *map; 789*55102Storek { 790*55102Storek register int i, s, v; 791*55102Storek 792*55102Storek s = splaudio(); 793*55102Storek amd->cr = AMDR_MAP_1_10; 794*55102Storek for (i = 0; i < 8; i++) { 795*55102Storek v = map->mr_x[i]; 796*55102Storek WAMD16(amd, v); 797*55102Storek } 798*55102Storek for (i = 0; i < 8; ++i) { 799*55102Storek v = map->mr_r[i]; 800*55102Storek WAMD16(amd, v); 801*55102Storek } 802*55102Storek v = map->mr_gx; WAMD16(amd, v); 803*55102Storek v = map->mr_gr; WAMD16(amd, v); 804*55102Storek v = map->mr_ger; WAMD16(amd, v); 805*55102Storek v = map->mr_stgr; WAMD16(amd, v); 806*55102Storek v = map->mr_ftgr; WAMD16(amd, v); 807*55102Storek v = map->mr_atgr; WAMD16(amd, v); 808*55102Storek amd->dr = map->mr_mmr1; 809*55102Storek amd->dr = map->mr_mmr2; 810*55102Storek splx(s); 811*55102Storek } 812*55102Storek 813*55102Storek /* 814*55102Storek * Set the mmr1 register and one other 16 bit register in the audio chip. 815*55102Storek * The other register is indicated by op and val. 816*55102Storek */ 817*55102Storek void 818*55102Storek audio_setmmr1(amd, mmr1, op, val) 819*55102Storek register volatile struct amd7930 *amd; 820*55102Storek register int mmr1; 821*55102Storek register int op; 822*55102Storek register int val; 823*55102Storek { 824*55102Storek register int s = splaudio(); 825*55102Storek 826*55102Storek amd->cr = AMDR_MAP_MMR1; 827*55102Storek amd->dr = mmr1; 828*55102Storek amd->cr = op; 829*55102Storek WAMD16(amd, val); 830*55102Storek splx(s); 831*55102Storek } 832*55102Storek 833*55102Storek /* 834*55102Storek * Set only the mmr1 regsiter, and one other. 835*55102Storek */ 836*55102Storek static void 837*55102Storek audio_setmmr2(amd, mmr2) 838*55102Storek register volatile struct amd7930 *amd; 839*55102Storek register int mmr2; 840*55102Storek { 841*55102Storek register int s = splaudio(); 842*55102Storek 843*55102Storek amd->cr = AMDR_MAP_MMR2; 844*55102Storek amd->dr = mmr2; 845*55102Storek splx(s); 846*55102Storek } 847*55102Storek 848*55102Storek static u_short ger_coeff[] = { 849*55102Storek 0xaaaa, 0x9bbb, 0x79ac, 0x099a, 0x4199, 0x3199, 0x9cde, 0x9def, 850*55102Storek 0x749c, 0x549d, 0x6aae, 0xabcd, 0xabdf, 0x7429, 0x64ab, 0x6aff, 851*55102Storek 0x2abd, 0xbeef, 0x5cce, 0x75cd, 0x0099, 0x554c, 0x43dd, 0x33dd, 852*55102Storek 0x52ef, 0x771b, 0x5542, 0x41dd, 0x31dd, 0x441f, 0x431f, 0x331f, 853*55102Storek 0x40dd, 0x11dd, 0x440f, 0x411f, 0x311f, 0x5520, 0x10dd, 0x4211, 854*55102Storek 0x410f, 0x111f, 0x600b, 0x00dd, 0x4210, 0x400f, 0x110f, 0x2210, 855*55102Storek 0x7200, 0x4200, 0x2110, 0x100f, 0x2200, 0x1110, 0x000b, 0x2100, 856*55102Storek 0x000f, 857*55102Storek #define NGER (sizeof(ger_coeff) / sizeof(ger_coeff[0])) 858*55102Storek }; 859*55102Storek 860*55102Storek static u_short gx_coeff[] = { 861*55102Storek 0x0808, 0x4cb2, 0x3dac, 0x2ae5, 0x2533, 0x2222, 0x2122, 0x1fd3, 862*55102Storek 0x12a2, 0x121b, 0x113b, 0x0bc3, 0x10f2, 0x03ba, 0x02ca, 0x021d, 863*55102Storek 0x015a, 0x0122, 0x0112, 0x00ec, 0x0032, 0x0021, 0x0013, 0x0011, 864*55102Storek 0x000e, 865*55102Storek #define NGX (sizeof(gx_coeff) / sizeof(gx_coeff[0])) 866*55102Storek }; 867*55102Storek 868*55102Storek static u_short stg_coeff[] = { 869*55102Storek 0x8b7c, 0x8b44, 0x8b35, 0x8b2a, 0x8b24, 0x8b22, 0x9123, 0x912e, 870*55102Storek 0x912a, 0x9132, 0x913b, 0x914b, 0x91f9, 0x91c5, 0x91b6, 0x9212, 871*55102Storek 0x91a4, 0x9222, 0x9232, 0x92fb, 0x92aa, 0x9327, 0x93b3, 0x94b3, 872*55102Storek 0x9f91, 0x9cea, 0x9bf9, 0x9aac, 0x9a4a, 0xa222, 0xa2a2, 0xa68d, 873*55102Storek 0xaaa3, 0xb242, 0xbb52, 0xcbb2, 0x0808, 874*55102Storek #define NSTG (sizeof(stg_coeff) / sizeof(stg_coeff[0])) 875*55102Storek }; 876*55102Storek 877*55102Storek static void 878*55102Storek ausetrgain(sc, level) 879*55102Storek register struct audio_softc *sc; 880*55102Storek register int level; 881*55102Storek { 882*55102Storek level &= 0xff; 883*55102Storek sc->sc_rlevel = level; 884*55102Storek if (level != 0) 885*55102Storek sc->sc_map.mr_mmr1 |= AMD_MMR1_GX; 886*55102Storek else 887*55102Storek sc->sc_map.mr_mmr1 &=~ AMD_MMR1_GX; 888*55102Storek 889*55102Storek sc->sc_map.mr_gx = gx_coeff[(level * NGX) / 256]; 890*55102Storek audio_setmmr1(sc->sc_au.au_amd, sc->sc_map.mr_mmr1, 891*55102Storek AMDR_MAP_GX, sc->sc_map.mr_gx); 892*55102Storek } 893*55102Storek 894*55102Storek static void 895*55102Storek ausetpgain(sc, level) 896*55102Storek register struct audio_softc *sc; 897*55102Storek register int level; 898*55102Storek { 899*55102Storek level &= 0xff; 900*55102Storek sc->sc_plevel = level; 901*55102Storek if (level != 0) 902*55102Storek sc->sc_map.mr_mmr1 |= AMD_MMR1_GER; 903*55102Storek else 904*55102Storek sc->sc_map.mr_mmr1 &=~ AMD_MMR1_GER; 905*55102Storek 906*55102Storek sc->sc_map.mr_ger = ger_coeff[(level * NGER) / 256]; 907*55102Storek audio_setmmr1(sc->sc_au.au_amd, sc->sc_map.mr_mmr1, 908*55102Storek AMDR_MAP_GER, sc->sc_map.mr_ger); 909*55102Storek } 910*55102Storek 911*55102Storek static void 912*55102Storek ausetmgain(sc, level) 913*55102Storek register struct audio_softc *sc; 914*55102Storek register int level; 915*55102Storek { 916*55102Storek level &= 0xff; 917*55102Storek sc->sc_mlevel = level; 918*55102Storek if (level != 0) 919*55102Storek sc->sc_map.mr_mmr1 |= AMD_MMR1_STG; 920*55102Storek else 921*55102Storek sc->sc_map.mr_mmr1 &=~ AMD_MMR1_STG; 922*55102Storek 923*55102Storek sc->sc_map.mr_stgr = stg_coeff[(level * NSTG) / 256]; 924*55102Storek audio_setmmr1(sc->sc_au.au_amd, sc->sc_map.mr_mmr1, 925*55102Storek AMDR_MAP_STG, sc->sc_map.mr_stgr); 926*55102Storek } 927*55102Storek 928*55102Storek static int 929*55102Storek audiosetinfo(sc, ai) 930*55102Storek struct audio_softc *sc; 931*55102Storek struct audio_info *ai; 932*55102Storek { 933*55102Storek struct audio_prinfo *r = &ai->record, *p = &ai->play; 934*55102Storek register int s, bsize; 935*55102Storek 936*55102Storek if (p->gain != ~0) 937*55102Storek ausetpgain(sc, p->gain); 938*55102Storek if (r->gain != ~0) 939*55102Storek ausetrgain(sc, r->gain); 940*55102Storek if (ai->monitor_gain != ~0) 941*55102Storek ausetmgain(sc, p->gain); 942*55102Storek if (p->port == AUDIO_SPEAKER) { 943*55102Storek sc->sc_map.mr_mmr2 |= AMD_MMR2_LS; 944*55102Storek audio_setmmr2(sc->sc_au.au_amd, sc->sc_map.mr_mmr2); 945*55102Storek } else if (p->port == AUDIO_HEADPHONE) { 946*55102Storek sc->sc_map.mr_mmr2 &=~ AMD_MMR2_LS; 947*55102Storek audio_setmmr2(sc->sc_au.au_amd, sc->sc_map.mr_mmr2); 948*55102Storek } 949*55102Storek if (p->pause != (u_char)~0) 950*55102Storek sc->sc_au.au_wb.cb_pause = p->pause; 951*55102Storek if (r->pause != (u_char)~0) 952*55102Storek sc->sc_au.au_rb.cb_pause = r->pause; 953*55102Storek 954*55102Storek if (ai->blocksize != ~0) { 955*55102Storek if (ai->blocksize == 0) 956*55102Storek bsize = ai->blocksize = DEFBLKSIZE; 957*55102Storek else if (ai->blocksize > MAXBLKSIZE) 958*55102Storek bsize = ai->blocksize = MAXBLKSIZE; 959*55102Storek else 960*55102Storek bsize = ai->blocksize; 961*55102Storek 962*55102Storek s = splaudio(); 963*55102Storek sc->sc_au.au_blksize = bsize; 964*55102Storek /* AUDIO_FLUSH */ 965*55102Storek AUCB_INIT(&sc->sc_au.au_rb); 966*55102Storek AUCB_INIT(&sc->sc_au.au_wb); 967*55102Storek splx(s); 968*55102Storek 969*55102Storek } 970*55102Storek if (ai->hiwat != ~0 && (unsigned)ai->hiwat < AUCB_SIZE) 971*55102Storek sc->sc_au.au_hiwat = ai->hiwat; 972*55102Storek if (ai->lowat != ~0 && ai->lowat < AUCB_SIZE) 973*55102Storek sc->sc_au.au_lowat = ai->lowat; 974*55102Storek 975*55102Storek return (0); 976*55102Storek } 977*55102Storek 978*55102Storek static int 979*55102Storek sunaudiosetinfo(sc, ai) 980*55102Storek struct audio_softc *sc; 981*55102Storek struct sun_audio_info *ai; 982*55102Storek { 983*55102Storek struct sun_audio_prinfo *r = &ai->record, *p = &ai->play; 984*55102Storek 985*55102Storek if (p->gain != ~0) 986*55102Storek ausetpgain(sc, p->gain); 987*55102Storek if (r->gain != ~0) 988*55102Storek ausetrgain(sc, r->gain); 989*55102Storek if (ai->monitor_gain != ~0) 990*55102Storek ausetmgain(sc, p->gain); 991*55102Storek if (p->port == AUDIO_SPEAKER) { 992*55102Storek sc->sc_map.mr_mmr2 |= AMD_MMR2_LS; 993*55102Storek audio_setmmr2(sc->sc_au.au_amd, sc->sc_map.mr_mmr2); 994*55102Storek } else if (p->port == AUDIO_HEADPHONE) { 995*55102Storek sc->sc_map.mr_mmr2 &=~ AMD_MMR2_LS; 996*55102Storek audio_setmmr2(sc->sc_au.au_amd, sc->sc_map.mr_mmr2); 997*55102Storek } 998*55102Storek /* 999*55102Storek * The bsd driver does not distinguish between paused and active. 1000*55102Storek * (In the sun driver, not active means samples are not ouput 1001*55102Storek * at all, but paused means the last streams buffer is drained 1002*55102Storek * and then output stops.) If either are 0, then when stop output. 1003*55102Storek * Otherwise, if either are non-zero, we resume. 1004*55102Storek */ 1005*55102Storek if (p->pause == 0 || p->active == 0) 1006*55102Storek sc->sc_au.au_wb.cb_pause = 0; 1007*55102Storek else if (p->pause != (u_char)~0 || p->active != (u_char)~0) 1008*55102Storek sc->sc_au.au_wb.cb_pause = 1; 1009*55102Storek if (r->pause == 0 || r->active == 0) 1010*55102Storek sc->sc_au.au_rb.cb_pause = 0; 1011*55102Storek else if (r->pause != (u_char)~0 || r->active != (u_char)~0) 1012*55102Storek sc->sc_au.au_rb.cb_pause = 1; 1013*55102Storek 1014*55102Storek return (0); 1015*55102Storek } 1016*55102Storek 1017*55102Storek static int 1018*55102Storek audiogetinfo(sc, ai) 1019*55102Storek struct audio_softc *sc; 1020*55102Storek struct audio_info *ai; 1021*55102Storek { 1022*55102Storek struct audio_prinfo *r = &ai->record, *p = &ai->play; 1023*55102Storek 1024*55102Storek p->sample_rate = r->sample_rate = 8000; 1025*55102Storek p->channels = r->channels = 1; 1026*55102Storek p->precision = r->precision = 8; 1027*55102Storek p->encoding = r->encoding = AUDIO_ENCODING_ULAW; 1028*55102Storek 1029*55102Storek ai->monitor_gain = sc->sc_mlevel; 1030*55102Storek r->gain = sc->sc_rlevel; 1031*55102Storek p->gain = sc->sc_plevel; 1032*55102Storek r->port = 1; p->port = (sc->sc_map.mr_mmr2 & AMD_MMR2_LS) ? 1033*55102Storek AUDIO_SPEAKER : AUDIO_HEADPHONE; 1034*55102Storek 1035*55102Storek p->pause = sc->sc_au.au_wb.cb_pause; 1036*55102Storek r->pause = sc->sc_au.au_rb.cb_pause; 1037*55102Storek p->error = sc->sc_au.au_wb.cb_drops != 0; 1038*55102Storek r->error = sc->sc_au.au_rb.cb_drops != 0; 1039*55102Storek 1040*55102Storek p->open = sc->sc_open; 1041*55102Storek r->open = sc->sc_open; 1042*55102Storek 1043*55102Storek p->samples = sc->sc_au.au_stamp - sc->sc_au.au_wb.cb_pdrops; 1044*55102Storek r->samples = sc->sc_au.au_stamp - sc->sc_au.au_rb.cb_pdrops; 1045*55102Storek 1046*55102Storek p->seek = sc->sc_wseek; 1047*55102Storek r->seek = sc->sc_rseek; 1048*55102Storek 1049*55102Storek ai->blocksize = sc->sc_au.au_blksize; 1050*55102Storek ai->hiwat = sc->sc_au.au_hiwat; 1051*55102Storek ai->lowat = sc->sc_au.au_lowat; 1052*55102Storek 1053*55102Storek return (0); 1054*55102Storek } 1055*55102Storek 1056*55102Storek static int 1057*55102Storek sunaudiogetinfo(sc, ai) 1058*55102Storek struct audio_softc *sc; 1059*55102Storek struct sun_audio_info *ai; 1060*55102Storek { 1061*55102Storek struct sun_audio_prinfo *r = &ai->record, *p = &ai->play; 1062*55102Storek 1063*55102Storek p->sample_rate = r->sample_rate = 8000; 1064*55102Storek p->channels = r->channels = 1; 1065*55102Storek p->precision = r->precision = 8; 1066*55102Storek p->encoding = r->encoding = AUDIO_ENCODING_ULAW; 1067*55102Storek 1068*55102Storek ai->monitor_gain = sc->sc_mlevel; 1069*55102Storek r->gain = sc->sc_rlevel; 1070*55102Storek p->gain = sc->sc_plevel; 1071*55102Storek r->port = 1; p->port = (sc->sc_map.mr_mmr2 & AMD_MMR2_LS) ? 1072*55102Storek AUDIO_SPEAKER : AUDIO_HEADPHONE; 1073*55102Storek 1074*55102Storek p->active = p->pause = sc->sc_au.au_wb.cb_pause; 1075*55102Storek r->active = r->pause = sc->sc_au.au_rb.cb_pause; 1076*55102Storek p->error = sc->sc_au.au_wb.cb_drops != 0; 1077*55102Storek r->error = sc->sc_au.au_rb.cb_drops != 0; 1078*55102Storek 1079*55102Storek p->waiting = 0; 1080*55102Storek r->waiting = 0; 1081*55102Storek p->eof = 0; 1082*55102Storek r->eof = 0; 1083*55102Storek 1084*55102Storek p->open = sc->sc_open; 1085*55102Storek r->open = sc->sc_open; 1086*55102Storek 1087*55102Storek p->samples = sc->sc_au.au_stamp - sc->sc_au.au_wb.cb_pdrops; 1088*55102Storek r->samples = sc->sc_au.au_stamp - sc->sc_au.au_rb.cb_pdrops; 1089*55102Storek 1090*55102Storek return (0); 1091*55102Storek } 1092*55102Storek #endif 1093