Annotation of sys/dev/audio.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: audio.c,v 1.72 2007/08/08 05:51:23 jakemsr Exp $ */
! 2: /* $NetBSD: audio.c,v 1.119 1999/11/09 16:50:47 augustss Exp $ */
! 3:
! 4: /*
! 5: * Copyright (c) 1991-1993 Regents of the University of California.
! 6: * All rights reserved.
! 7: *
! 8: * Redistribution and use in source and binary forms, with or without
! 9: * modification, are permitted provided that the following conditions
! 10: * are met:
! 11: * 1. Redistributions of source code must retain the above copyright
! 12: * notice, this list of conditions and the following disclaimer.
! 13: * 2. Redistributions in binary form must reproduce the above copyright
! 14: * notice, this list of conditions and the following disclaimer in the
! 15: * documentation and/or other materials provided with the distribution.
! 16: * 3. All advertising materials mentioning features or use of this software
! 17: * must display the following acknowledgement:
! 18: * This product includes software developed by the Computer Systems
! 19: * Engineering Group at Lawrence Berkeley Laboratory.
! 20: * 4. Neither the name of the University nor of the Laboratory may be used
! 21: * to endorse or promote products derived from this software without
! 22: * specific prior written permission.
! 23: *
! 24: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
! 25: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 26: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 27: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
! 28: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 29: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 30: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 31: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 32: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 33: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 34: * SUCH DAMAGE.
! 35: */
! 36:
! 37: /*
! 38: * This is a (partially) SunOS-compatible /dev/audio driver for NetBSD.
! 39: *
! 40: * This code tries to do something half-way sensible with
! 41: * half-duplex hardware, such as with the SoundBlaster hardware. With
! 42: * half-duplex hardware allowing O_RDWR access doesn't really make
! 43: * sense. However, closing and opening the device to "turn around the
! 44: * line" is relatively expensive and costs a card reset (which can
! 45: * take some time, at least for the SoundBlaster hardware). Instead
! 46: * we allow O_RDWR access, and provide an ioctl to set the "mode",
! 47: * i.e. playing or recording.
! 48: *
! 49: * If you write to a half-duplex device in record mode, the data is
! 50: * tossed. If you read from the device in play mode, you get silence
! 51: * filled buffers at the rate at which samples are naturally
! 52: * generated.
! 53: *
! 54: * If you try to set both play and record mode on a half-duplex
! 55: * device, playing takes precedence.
! 56: */
! 57:
! 58: /*
! 59: * Todo:
! 60: * - Add softaudio() isr processing for wakeup, poll, signals,
! 61: * and silence fill.
! 62: */
! 63:
! 64: #include "audio.h"
! 65: #if NAUDIO > 0
! 66:
! 67: #include <sys/param.h>
! 68: #include <sys/ioctl.h>
! 69: #include <sys/fcntl.h>
! 70: #include <sys/vnode.h>
! 71: #include <sys/selinfo.h>
! 72: #include <sys/poll.h>
! 73: #include <sys/malloc.h>
! 74: #include <sys/proc.h>
! 75: #include <sys/systm.h>
! 76: #include <sys/syslog.h>
! 77: #include <sys/kernel.h>
! 78: #include <sys/signalvar.h>
! 79: #include <sys/conf.h>
! 80: #include <sys/audioio.h>
! 81: #include <sys/device.h>
! 82:
! 83: #include <dev/audio_if.h>
! 84: #include <dev/audiovar.h>
! 85:
! 86: #include <dev/rndvar.h>
! 87:
! 88: #include <machine/endian.h>
! 89:
! 90: #include "wskbd.h" /* NWSKBD (mixer tuning using keyboard) */
! 91:
! 92: #ifdef AUDIO_DEBUG
! 93: #define DPRINTF(x) if (audiodebug) printf x
! 94: #define DPRINTFN(n,x) if (audiodebug>(n)) printf x
! 95: int audiodebug = 0;
! 96: #else
! 97: #define DPRINTF(x)
! 98: #define DPRINTFN(n,x)
! 99: #endif
! 100:
! 101: #define ROUNDSIZE(x) x &= -16 /* round to nice boundary */
! 102:
! 103: int audio_blk_ms = AUDIO_BLK_MS;
! 104:
! 105: int audiosetinfo(struct audio_softc *, struct audio_info *);
! 106: int audiogetinfo(struct audio_softc *, struct audio_info *);
! 107:
! 108: int audio_open(dev_t, struct audio_softc *, int, int, struct proc *);
! 109: int audio_close(dev_t, int, int, struct proc *);
! 110: int audio_read(dev_t, struct uio *, int);
! 111: int audio_write(dev_t, struct uio *, int);
! 112: int audio_ioctl(dev_t, u_long, caddr_t, int, struct proc *);
! 113: int audio_poll(dev_t, int, struct proc *);
! 114: paddr_t audio_mmap(dev_t, off_t, int);
! 115:
! 116: int mixer_open(dev_t, struct audio_softc *, int, int, struct proc *);
! 117: int mixer_close(dev_t, int, int, struct proc *);
! 118: int mixer_ioctl(dev_t, u_long, caddr_t, int, struct proc *);
! 119: static void mixer_remove(struct audio_softc *, struct proc *p);
! 120: static void mixer_signal(struct audio_softc *);
! 121:
! 122: void audio_init_record(struct audio_softc *);
! 123: void audio_init_play(struct audio_softc *);
! 124: int audiostartr(struct audio_softc *);
! 125: int audiostartp(struct audio_softc *);
! 126: void audio_rint(void *);
! 127: void audio_pint(void *);
! 128: int audio_check_params(struct audio_params *);
! 129:
! 130: void audio_calc_blksize(struct audio_softc *, int);
! 131: void audio_fill_silence(struct audio_params *, u_char *, int);
! 132: int audio_silence_copyout(struct audio_softc *, int, struct uio *);
! 133:
! 134: void audio_init_ringbuffer(struct audio_ringbuffer *);
! 135: int audio_initbufs(struct audio_softc *);
! 136: void audio_calcwater(struct audio_softc *);
! 137: static __inline int audio_sleep_timo(int *, char *, int);
! 138: static __inline int audio_sleep(int *, char *);
! 139: static __inline void audio_wakeup(int *);
! 140: void audio_selwakeup(struct audio_softc *sc, int play);
! 141: int audio_drain(struct audio_softc *);
! 142: void audio_clear(struct audio_softc *);
! 143: static __inline void audio_pint_silence(struct audio_softc *, struct audio_ringbuffer *, u_char *, int);
! 144:
! 145: int audio_alloc_ring(struct audio_softc *, struct audio_ringbuffer *, int, int);
! 146: void audio_free_ring(struct audio_softc *, struct audio_ringbuffer *);
! 147:
! 148: int audioprint(void *, const char *);
! 149:
! 150: int audioprobe(struct device *, void *, void *);
! 151: void audioattach(struct device *, struct device *, void *);
! 152: int audiodetach(struct device *, int);
! 153: int audioactivate(struct device *, enum devact);
! 154:
! 155: struct portname {
! 156: char *name;
! 157: int mask;
! 158: };
! 159: static struct portname itable[] = {
! 160: { AudioNmicrophone, AUDIO_MICROPHONE },
! 161: { AudioNline, AUDIO_LINE_IN },
! 162: { AudioNcd, AUDIO_CD },
! 163: { 0 }
! 164: };
! 165: static struct portname otable[] = {
! 166: { AudioNspeaker, AUDIO_SPEAKER },
! 167: { AudioNheadphone, AUDIO_HEADPHONE },
! 168: { AudioNline, AUDIO_LINE_OUT },
! 169: { 0 }
! 170: };
! 171: void au_check_ports(struct audio_softc *, struct au_mixer_ports *,
! 172: mixer_devinfo_t *, int, char *, char *,
! 173: struct portname *);
! 174: int au_set_gain(struct audio_softc *, struct au_mixer_ports *,
! 175: int, int);
! 176: void au_get_gain(struct audio_softc *, struct au_mixer_ports *,
! 177: u_int *, u_char *);
! 178: int au_set_port(struct audio_softc *, struct au_mixer_ports *,
! 179: u_int);
! 180: int au_get_port(struct audio_softc *, struct au_mixer_ports *);
! 181: int au_get_lr_value(struct audio_softc *, mixer_ctrl_t *,
! 182: int *, int *r);
! 183: int au_set_lr_value(struct audio_softc *, mixer_ctrl_t *,
! 184: int, int);
! 185: int au_portof(struct audio_softc *, char *);
! 186:
! 187:
! 188: /* The default audio mode: 8 kHz mono ulaw */
! 189: struct audio_params audio_default =
! 190: { 8000, AUDIO_ENCODING_ULAW, 8, 1, 0, 1 };
! 191:
! 192: struct cfattach audio_ca = {
! 193: sizeof(struct audio_softc), audioprobe, audioattach,
! 194: audiodetach, audioactivate
! 195: };
! 196:
! 197: struct cfdriver audio_cd = {
! 198: NULL, "audio", DV_DULL
! 199: };
! 200:
! 201: void filt_audiowdetach(struct knote *);
! 202: int filt_audiowrite(struct knote *, long);
! 203:
! 204: struct filterops audiowrite_filtops =
! 205: { 1, NULL, filt_audiowdetach, filt_audiowrite};
! 206:
! 207: void filt_audiordetach(struct knote *);
! 208: int filt_audioread(struct knote *, long);
! 209:
! 210: struct filterops audioread_filtops =
! 211: { 1, NULL, filt_audiordetach, filt_audioread};
! 212:
! 213: #if NWSKBD > 0
! 214: /* Mixer manipulation using keyboard */
! 215: int wskbd_get_mixerdev(struct audio_softc *, int, int *);
! 216: int wskbd_set_mixervolume(long);
! 217: #endif
! 218:
! 219: int
! 220: audioprobe(struct device *parent, void *match, void *aux)
! 221: {
! 222: struct audio_attach_args *sa = aux;
! 223:
! 224: DPRINTF(("audioprobe: type=%d sa=%p hw=%p\n",
! 225: sa->type, sa, sa->hwif));
! 226: return (sa->type == AUDIODEV_TYPE_AUDIO) ? 1 : 0;
! 227: }
! 228:
! 229: void
! 230: audioattach(struct device *parent, struct device *self, void *aux)
! 231: {
! 232: struct audio_softc *sc = (void *)self;
! 233: struct audio_attach_args *sa = aux;
! 234: struct audio_hw_if *hwp = sa->hwif;
! 235: void *hdlp = sa->hdl;
! 236: int error;
! 237: mixer_devinfo_t mi;
! 238: int iclass, oclass, mclass;
! 239:
! 240: printf("\n");
! 241:
! 242: #ifdef DIAGNOSTIC
! 243: if (hwp == 0 ||
! 244: hwp->open == 0 ||
! 245: hwp->close == 0 ||
! 246: hwp->query_encoding == 0 ||
! 247: hwp->set_params == 0 ||
! 248: (hwp->start_output == 0 && hwp->trigger_output == 0) ||
! 249: (hwp->start_input == 0 && hwp->trigger_input == 0) ||
! 250: hwp->halt_output == 0 ||
! 251: hwp->halt_input == 0 ||
! 252: hwp->getdev == 0 ||
! 253: hwp->set_port == 0 ||
! 254: hwp->get_port == 0 ||
! 255: hwp->query_devinfo == 0 ||
! 256: hwp->get_props == 0) {
! 257: printf("audio: missing method\n");
! 258: sc->hw_if = 0;
! 259: return;
! 260: }
! 261: #endif
! 262:
! 263: sc->hw_if = hwp;
! 264: sc->hw_hdl = hdlp;
! 265: sc->sc_dev = parent;
! 266:
! 267: error = audio_alloc_ring(sc, &sc->sc_pr, AUMODE_PLAY, AU_RING_SIZE);
! 268: if (error) {
! 269: sc->hw_if = 0;
! 270: printf("audio: could not allocate play buffer\n");
! 271: return;
! 272: }
! 273: error = audio_alloc_ring(sc, &sc->sc_rr, AUMODE_RECORD, AU_RING_SIZE);
! 274: if (error) {
! 275: audio_free_ring(sc, &sc->sc_pr);
! 276: sc->hw_if = 0;
! 277: printf("audio: could not allocate record buffer\n");
! 278: return;
! 279: }
! 280:
! 281: /*
! 282: * Set default softc params
! 283: */
! 284: sc->sc_pparams = audio_default;
! 285: sc->sc_rparams = audio_default;
! 286:
! 287: /* Set up some default values */
! 288: sc->sc_blkset = 0;
! 289: audio_calc_blksize(sc, AUMODE_RECORD);
! 290: audio_calc_blksize(sc, AUMODE_PLAY);
! 291: audio_init_ringbuffer(&sc->sc_rr);
! 292: audio_init_ringbuffer(&sc->sc_pr);
! 293: audio_calcwater(sc);
! 294:
! 295: iclass = oclass = mclass = -1;
! 296: sc->sc_inports.index = -1;
! 297: sc->sc_inports.nports = 0;
! 298: sc->sc_inports.isenum = 0;
! 299: sc->sc_inports.allports = 0;
! 300: sc->sc_outports.index = -1;
! 301: sc->sc_outports.nports = 0;
! 302: sc->sc_outports.isenum = 0;
! 303: sc->sc_outports.allports = 0;
! 304: sc->sc_monitor_port = -1;
! 305: for(mi.index = 0; ; mi.index++) {
! 306: if (hwp->query_devinfo(hdlp, &mi) != 0)
! 307: break;
! 308: if (mi.type == AUDIO_MIXER_CLASS &&
! 309: strcmp(mi.label.name, AudioCrecord) == 0)
! 310: iclass = mi.index;
! 311: if (mi.type == AUDIO_MIXER_CLASS &&
! 312: strcmp(mi.label.name, AudioCmonitor) == 0)
! 313: mclass = mi.index;
! 314: if (mi.type == AUDIO_MIXER_CLASS &&
! 315: strcmp(mi.label.name, AudioCoutputs) == 0)
! 316: oclass = mi.index;
! 317: }
! 318: for(mi.index = 0; ; mi.index++) {
! 319: if (hwp->query_devinfo(hdlp, &mi) != 0)
! 320: break;
! 321: if (mi.type == AUDIO_MIXER_CLASS)
! 322: continue;
! 323: au_check_ports(sc, &sc->sc_inports, &mi, iclass,
! 324: AudioNsource, AudioNrecord, itable);
! 325: au_check_ports(sc, &sc->sc_outports, &mi, oclass,
! 326: AudioNoutput, AudioNmaster, otable);
! 327: if (mi.mixer_class == mclass &&
! 328: (strcmp(mi.label.name, AudioNmonitor) == 0))
! 329: sc->sc_monitor_port = mi.index;
! 330: if ((sc->sc_monitor_port == -1) && (mi.mixer_class == oclass) &&
! 331: (strcmp(mi.label.name, AudioNmonitor) == 0))
! 332: sc->sc_monitor_port = mi.index;
! 333: }
! 334: DPRINTF(("audio_attach: inputs ports=0x%x, output ports=0x%x\n",
! 335: sc->sc_inports.allports, sc->sc_outports.allports));
! 336: }
! 337:
! 338: int
! 339: audioactivate(struct device *self, enum devact act)
! 340: {
! 341: struct audio_softc *sc = (struct audio_softc *)self;
! 342:
! 343: switch (act) {
! 344: case DVACT_ACTIVATE:
! 345: break;
! 346:
! 347: case DVACT_DEACTIVATE:
! 348: sc->sc_dying = 1;
! 349: break;
! 350: }
! 351: return (0);
! 352: }
! 353:
! 354: int
! 355: audiodetach(struct device *self, int flags)
! 356: {
! 357: struct audio_softc *sc = (struct audio_softc *)self;
! 358: int maj, mn;
! 359: int s;
! 360:
! 361: DPRINTF(("audio_detach: sc=%p flags=%d\n", sc, flags));
! 362:
! 363: sc->sc_dying = 1;
! 364:
! 365: wakeup(&sc->sc_wchan);
! 366: wakeup(&sc->sc_rchan);
! 367: s = splaudio();
! 368: if (--sc->sc_refcnt >= 0) {
! 369: if (tsleep(&sc->sc_refcnt, PZERO, "auddet", hz * 120))
! 370: printf("audiodetach: %s didn't detach\n",
! 371: sc->dev.dv_xname);
! 372: }
! 373: splx(s);
! 374:
! 375: /* free resources */
! 376: audio_free_ring(sc, &sc->sc_pr);
! 377: audio_free_ring(sc, &sc->sc_rr);
! 378:
! 379: /* locate the major number */
! 380: for (maj = 0; maj < nchrdev; maj++)
! 381: if (cdevsw[maj].d_open == audioopen)
! 382: break;
! 383:
! 384: /* Nuke the vnodes for any open instances (calls close). */
! 385: mn = self->dv_unit;
! 386: vdevgone(maj, mn | SOUND_DEVICE, mn | SOUND_DEVICE, VCHR);
! 387: vdevgone(maj, mn | AUDIO_DEVICE, mn | AUDIO_DEVICE, VCHR);
! 388: vdevgone(maj, mn | AUDIOCTL_DEVICE, mn | AUDIOCTL_DEVICE, VCHR);
! 389: vdevgone(maj, mn | MIXER_DEVICE, mn | MIXER_DEVICE, VCHR);
! 390:
! 391: return (0);
! 392: }
! 393:
! 394: int
! 395: au_portof(struct audio_softc *sc, char *name)
! 396: {
! 397: mixer_devinfo_t mi;
! 398:
! 399: for(mi.index = 0;
! 400: sc->hw_if->query_devinfo(sc->hw_hdl, &mi) == 0;
! 401: mi.index++)
! 402: if (strcmp(mi.label.name, name) == 0)
! 403: return mi.index;
! 404: return -1;
! 405: }
! 406:
! 407: void
! 408: au_check_ports(struct audio_softc *sc, struct au_mixer_ports *ports,
! 409: mixer_devinfo_t *mi, int cls, char *name, char *mname, struct portname *tbl)
! 410: {
! 411: int i, j;
! 412:
! 413: if (mi->mixer_class != cls)
! 414: return;
! 415: if (strcmp(mi->label.name, mname) == 0) {
! 416: ports->master = mi->index;
! 417: return;
! 418: }
! 419: if (strcmp(mi->label.name, name) != 0)
! 420: return;
! 421: if (mi->type == AUDIO_MIXER_ENUM) {
! 422: ports->index = mi->index;
! 423: for(i = 0; tbl[i].name; i++) {
! 424: for(j = 0; j < mi->un.e.num_mem; j++) {
! 425: if (strcmp(mi->un.e.member[j].label.name,
! 426: tbl[i].name) == 0) {
! 427: ports->aumask[ports->nports] = tbl[i].mask;
! 428: ports->misel [ports->nports] = mi->un.e.member[j].ord;
! 429: ports->miport[ports->nports++] =
! 430: au_portof(sc, mi->un.e.member[j].label.name);
! 431: ports->allports |= tbl[i].mask;
! 432: }
! 433: }
! 434: }
! 435: ports->isenum = 1;
! 436: } else if (mi->type == AUDIO_MIXER_SET) {
! 437: ports->index = mi->index;
! 438: for(i = 0; tbl[i].name; i++) {
! 439: for(j = 0; j < mi->un.s.num_mem; j++) {
! 440: if (strcmp(mi->un.s.member[j].label.name,
! 441: tbl[i].name) == 0) {
! 442: ports->aumask[ports->nports] = tbl[i].mask;
! 443: ports->misel [ports->nports] = mi->un.s.member[j].mask;
! 444: ports->miport[ports->nports++] =
! 445: au_portof(sc, mi->un.s.member[j].label.name);
! 446: ports->allports |= tbl[i].mask;
! 447: }
! 448: }
! 449: }
! 450: }
! 451: }
! 452:
! 453: /*
! 454: * Called from hardware driver. This is where the MI audio driver gets
! 455: * probed/attached to the hardware driver.
! 456: */
! 457: struct device *
! 458: audio_attach_mi(struct audio_hw_if *ahwp, void *hdlp, struct device *dev)
! 459: {
! 460: struct audio_attach_args arg;
! 461:
! 462: #ifdef DIAGNOSTIC
! 463: if (ahwp == NULL) {
! 464: printf ("audio_attach_mi: NULL\n");
! 465: return 0;
! 466: }
! 467: #endif
! 468:
! 469: arg.type = AUDIODEV_TYPE_AUDIO;
! 470: arg.hwif = ahwp;
! 471: arg.hdl = hdlp;
! 472: return config_found(dev, &arg, audioprint);
! 473: }
! 474:
! 475: #if NAUDIO > 0
! 476: int
! 477: audioprint(void *aux, const char *pnp)
! 478: {
! 479: struct audio_attach_args *arg = aux;
! 480: const char *type;
! 481:
! 482: if (pnp != NULL) {
! 483: switch (arg->type) {
! 484: case AUDIODEV_TYPE_AUDIO:
! 485: type = "audio";
! 486: break;
! 487: case AUDIODEV_TYPE_OPL:
! 488: type = "opl";
! 489: break;
! 490: case AUDIODEV_TYPE_MPU:
! 491: type = "mpu";
! 492: break;
! 493: default:
! 494: panic("audioprint: unknown type %d", arg->type);
! 495: }
! 496: printf("%s at %s", type, pnp);
! 497: }
! 498: return (UNCONF);
! 499: }
! 500:
! 501: #endif /* NAUDIO > 0 */
! 502:
! 503: #ifdef AUDIO_DEBUG
! 504: void audio_printsc(struct audio_softc *);
! 505: void audio_print_params(char *, struct audio_params *);
! 506:
! 507: void
! 508: audio_printsc(struct audio_softc *sc)
! 509: {
! 510: printf("hwhandle %p hw_if %p ", sc->hw_hdl, sc->hw_if);
! 511: printf("open 0x%x mode 0x%x\n", sc->sc_open, sc->sc_mode);
! 512: printf("rchan 0x%x wchan 0x%x ", sc->sc_rchan, sc->sc_wchan);
! 513: printf("rring used 0x%x pring used=%d\n", sc->sc_rr.used, sc->sc_pr.used);
! 514: printf("rbus 0x%x pbus 0x%x ", sc->sc_rbus, sc->sc_pbus);
! 515: printf("blksize %d", sc->sc_pr.blksize);
! 516: printf("hiwat %d lowat %d\n", sc->sc_pr.usedhigh, sc->sc_pr.usedlow);
! 517: }
! 518:
! 519: void
! 520: audio_print_params(char *s, struct audio_params *p)
! 521: {
! 522: printf("audio: %s sr=%ld, enc=%d, chan=%d, prec=%d\n", s,
! 523: p->sample_rate, p->encoding, p->channels, p->precision);
! 524: }
! 525: #endif
! 526:
! 527: int
! 528: audio_alloc_ring(struct audio_softc *sc, struct audio_ringbuffer *r,
! 529: int direction, int bufsize)
! 530: {
! 531: struct audio_hw_if *hw = sc->hw_if;
! 532: void *hdl = sc->hw_hdl;
! 533: /*
! 534: * Alloc DMA play and record buffers
! 535: */
! 536: if (bufsize < AUMINBUF)
! 537: bufsize = AUMINBUF;
! 538: ROUNDSIZE(bufsize);
! 539: if (hw->round_buffersize)
! 540: bufsize = hw->round_buffersize(hdl, direction, bufsize);
! 541: r->bufsize = bufsize;
! 542: if (hw->allocm)
! 543: r->start = hw->allocm(hdl, direction, r->bufsize, M_DEVBUF,
! 544: M_WAITOK);
! 545: else
! 546: r->start = malloc(bufsize, M_DEVBUF, M_WAITOK);
! 547: if (r->start == 0)
! 548: return ENOMEM;
! 549: return 0;
! 550: }
! 551:
! 552: void
! 553: audio_free_ring(struct audio_softc *sc, struct audio_ringbuffer *r)
! 554: {
! 555: if (sc->hw_if->freem) {
! 556: sc->hw_if->freem(sc->hw_hdl, r->start, M_DEVBUF);
! 557: } else {
! 558: free(r->start, M_DEVBUF);
! 559: }
! 560: }
! 561:
! 562: int
! 563: audioopen(dev_t dev, int flags, int ifmt, struct proc *p)
! 564: {
! 565: int unit = AUDIOUNIT(dev);
! 566: struct audio_softc *sc;
! 567: int error;
! 568:
! 569: if (unit >= audio_cd.cd_ndevs ||
! 570: (sc = audio_cd.cd_devs[unit]) == NULL)
! 571: return ENXIO;
! 572:
! 573: if (sc->sc_dying)
! 574: return (EIO);
! 575:
! 576: if (!sc->hw_if)
! 577: return (ENXIO);
! 578:
! 579: sc->sc_refcnt ++;
! 580: switch (AUDIODEV(dev)) {
! 581: case SOUND_DEVICE:
! 582: case AUDIO_DEVICE:
! 583: case AUDIOCTL_DEVICE:
! 584: error = audio_open(dev, sc, flags, ifmt, p);
! 585: break;
! 586: case MIXER_DEVICE:
! 587: error = mixer_open(dev, sc, flags, ifmt, p);
! 588: break;
! 589: default:
! 590: error = ENXIO;
! 591: break;
! 592: }
! 593:
! 594: if (--sc->sc_refcnt < 0)
! 595: wakeup(&sc->sc_refcnt);
! 596:
! 597: return (error);
! 598: }
! 599:
! 600: int
! 601: audioclose(dev_t dev, int flags, int ifmt, struct proc *p)
! 602: {
! 603:
! 604: switch (AUDIODEV(dev)) {
! 605: case SOUND_DEVICE:
! 606: case AUDIO_DEVICE:
! 607: return (audio_close(dev, flags, ifmt, p));
! 608: case MIXER_DEVICE:
! 609: return (mixer_close(dev, flags, ifmt, p));
! 610: case AUDIOCTL_DEVICE:
! 611: return 0;
! 612: default:
! 613: return (ENXIO);
! 614: }
! 615: }
! 616:
! 617: int
! 618: audioread(dev_t dev, struct uio *uio, int ioflag)
! 619: {
! 620: int unit = AUDIOUNIT(dev);
! 621: struct audio_softc *sc;
! 622: int error;
! 623:
! 624: if (unit >= audio_cd.cd_ndevs ||
! 625: (sc = audio_cd.cd_devs[unit]) == NULL)
! 626: return ENXIO;
! 627:
! 628: if (sc->sc_dying)
! 629: return (EIO);
! 630:
! 631: sc->sc_refcnt ++;
! 632: switch (AUDIODEV(dev)) {
! 633: case SOUND_DEVICE:
! 634: case AUDIO_DEVICE:
! 635: error = audio_read(dev, uio, ioflag);
! 636: break;
! 637: case AUDIOCTL_DEVICE:
! 638: case MIXER_DEVICE:
! 639: error = ENODEV;
! 640: break;
! 641: default:
! 642: error = ENXIO;
! 643: break;
! 644: }
! 645:
! 646: if (--sc->sc_refcnt < 0)
! 647: wakeup(&sc->sc_refcnt);
! 648: return (error);
! 649: }
! 650:
! 651: int
! 652: audiowrite(dev_t dev, struct uio *uio, int ioflag)
! 653: {
! 654: int unit = AUDIOUNIT(dev);
! 655: struct audio_softc *sc;
! 656: int error;
! 657:
! 658: if (unit >= audio_cd.cd_ndevs ||
! 659: (sc = audio_cd.cd_devs[unit]) == NULL)
! 660: return ENXIO;
! 661:
! 662: if (sc->sc_dying)
! 663: return (EIO);
! 664:
! 665: sc->sc_refcnt ++;
! 666: switch (AUDIODEV(dev)) {
! 667: case SOUND_DEVICE:
! 668: case AUDIO_DEVICE:
! 669: error = audio_write(dev, uio, ioflag);
! 670: break;
! 671: case AUDIOCTL_DEVICE:
! 672: case MIXER_DEVICE:
! 673: error = ENODEV;
! 674: break;
! 675: default:
! 676: error = ENXIO;
! 677: break;
! 678: }
! 679:
! 680: if (--sc->sc_refcnt < 0)
! 681: wakeup(&sc->sc_refcnt);
! 682: return (error);
! 683: }
! 684:
! 685: int
! 686: audioioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
! 687: {
! 688: int unit = AUDIOUNIT(dev);
! 689: struct audio_softc *sc;
! 690: int error;
! 691:
! 692: if (unit >= audio_cd.cd_ndevs ||
! 693: (sc = audio_cd.cd_devs[unit]) == NULL)
! 694: return ENXIO;
! 695:
! 696: if (sc->sc_dying)
! 697: return (EIO);
! 698:
! 699: sc->sc_refcnt ++;
! 700: switch (AUDIODEV(dev)) {
! 701: case SOUND_DEVICE:
! 702: case AUDIO_DEVICE:
! 703: case AUDIOCTL_DEVICE:
! 704: error = audio_ioctl(dev, cmd, addr, flag, p);
! 705: break;
! 706: case MIXER_DEVICE:
! 707: error = mixer_ioctl(dev, cmd, addr, flag, p);
! 708: break;
! 709: default:
! 710: error = ENXIO;
! 711: break;
! 712: }
! 713:
! 714: if (--sc->sc_refcnt < 0)
! 715: wakeup(&sc->sc_refcnt);
! 716: return (error);
! 717: }
! 718:
! 719: int
! 720: audiopoll(dev_t dev, int events, struct proc *p)
! 721: {
! 722: int unit = AUDIOUNIT(dev);
! 723: struct audio_softc *sc;
! 724: int error;
! 725:
! 726: if (unit >= audio_cd.cd_ndevs ||
! 727: (sc = audio_cd.cd_devs[unit]) == NULL)
! 728: return POLLERR;
! 729:
! 730: if (sc->sc_dying)
! 731: return POLLERR;
! 732:
! 733: sc->sc_refcnt ++;
! 734: switch (AUDIODEV(dev)) {
! 735: case SOUND_DEVICE:
! 736: case AUDIO_DEVICE:
! 737: error = audio_poll(dev, events, p);
! 738: break;
! 739: case AUDIOCTL_DEVICE:
! 740: case MIXER_DEVICE:
! 741: error = 0;
! 742: break;
! 743: default:
! 744: error = 0;
! 745: break;
! 746: }
! 747:
! 748: if (--sc->sc_refcnt < 0)
! 749: wakeup(&sc->sc_refcnt);
! 750: return (error);
! 751: }
! 752:
! 753: paddr_t
! 754: audiommap(dev_t dev, off_t off, int prot)
! 755: {
! 756: int unit = AUDIOUNIT(dev);
! 757: struct audio_softc *sc;
! 758: int ret;
! 759:
! 760: if (unit >= audio_cd.cd_ndevs ||
! 761: (sc = audio_cd.cd_devs[unit]) == NULL)
! 762: return (-1);
! 763:
! 764: if (sc->sc_dying)
! 765: return (-1);
! 766:
! 767: sc->sc_refcnt ++;
! 768: switch (AUDIODEV(dev)) {
! 769: case SOUND_DEVICE:
! 770: case AUDIO_DEVICE:
! 771: ret = audio_mmap(dev, off, prot);
! 772: break;
! 773: case AUDIOCTL_DEVICE:
! 774: case MIXER_DEVICE:
! 775: ret = -1;
! 776: break;
! 777: default:
! 778: ret = -1;
! 779: break;
! 780: }
! 781:
! 782: if (--sc->sc_refcnt < 0)
! 783: wakeup(&sc->sc_refcnt);
! 784: return (ret);
! 785: }
! 786:
! 787: /*
! 788: * Audio driver
! 789: */
! 790: void
! 791: audio_init_ringbuffer(struct audio_ringbuffer *rp)
! 792: {
! 793: int nblks;
! 794: int blksize = rp->blksize;
! 795:
! 796: if (blksize < AUMINBLK)
! 797: blksize = AUMINBLK;
! 798: nblks = rp->bufsize / blksize;
! 799: if (nblks < AUMINNOBLK) {
! 800: nblks = AUMINNOBLK;
! 801: blksize = rp->bufsize / nblks;
! 802: ROUNDSIZE(blksize);
! 803: }
! 804: DPRINTF(("audio_init_ringbuffer: blksize=%d\n", blksize));
! 805: rp->blksize = blksize;
! 806: rp->maxblks = nblks;
! 807: rp->used = 0;
! 808: rp->end = rp->start + nblks * blksize;
! 809: rp->inp = rp->outp = rp->start;
! 810: rp->stamp = 0;
! 811: rp->stamp_last = 0;
! 812: rp->drops = 0;
! 813: rp->pdrops = 0;
! 814: rp->copying = 0;
! 815: rp->needfill = 0;
! 816: rp->mmapped = 0;
! 817: }
! 818:
! 819: int
! 820: audio_initbufs(struct audio_softc *sc)
! 821: {
! 822: struct audio_hw_if *hw = sc->hw_if;
! 823: int error;
! 824:
! 825: DPRINTF(("audio_initbufs: mode=0x%x\n", sc->sc_mode));
! 826: audio_init_ringbuffer(&sc->sc_rr);
! 827: if (hw->init_input && (sc->sc_mode & AUMODE_RECORD)) {
! 828: error = hw->init_input(sc->hw_hdl, sc->sc_rr.start,
! 829: sc->sc_rr.end - sc->sc_rr.start);
! 830: if (error)
! 831: return error;
! 832: }
! 833:
! 834: audio_init_ringbuffer(&sc->sc_pr);
! 835: sc->sc_sil_count = 0;
! 836: if (hw->init_output && (sc->sc_mode & AUMODE_PLAY)) {
! 837: error = hw->init_output(sc->hw_hdl, sc->sc_pr.start,
! 838: sc->sc_pr.end - sc->sc_pr.start);
! 839: if (error)
! 840: return error;
! 841: }
! 842:
! 843: #ifdef AUDIO_INTR_TIME
! 844: sc->sc_pnintr = 0;
! 845: sc->sc_pblktime = (u_long)(
! 846: (u_long)sc->sc_pr.blksize * 100000 /
! 847: (u_long)(sc->sc_pparams.precision / NBBY *
! 848: sc->sc_pparams.channels *
! 849: sc->sc_pparams.sample_rate)) * 10;
! 850: DPRINTF(("audio: play blktime = %lu for %d\n",
! 851: sc->sc_pblktime, sc->sc_pr.blksize));
! 852: sc->sc_rnintr = 0;
! 853: sc->sc_rblktime = (u_long)(
! 854: (u_long)sc->sc_rr.blksize * 100000 /
! 855: (u_long)(sc->sc_rparams.precision / NBBY *
! 856: sc->sc_rparams.channels *
! 857: sc->sc_rparams.sample_rate)) * 10;
! 858: DPRINTF(("audio: record blktime = %lu for %d\n",
! 859: sc->sc_rblktime, sc->sc_rr.blksize));
! 860: #endif
! 861:
! 862: return 0;
! 863: }
! 864:
! 865: void
! 866: audio_calcwater(struct audio_softc *sc)
! 867: {
! 868: sc->sc_pr.usedhigh = sc->sc_pr.end - sc->sc_pr.start;
! 869: sc->sc_pr.usedlow = sc->sc_pr.usedhigh * 3 / 4; /* set lowater at 75% */
! 870: if (sc->sc_pr.usedlow == sc->sc_pr.usedhigh)
! 871: sc->sc_pr.usedlow -= sc->sc_pr.blksize;
! 872: sc->sc_rr.usedhigh = sc->sc_rr.end - sc->sc_rr.start - sc->sc_rr.blksize;
! 873: sc->sc_rr.usedlow = 0;
! 874: }
! 875:
! 876: static __inline int
! 877: audio_sleep_timo(int *chan, char *label, int timo)
! 878: {
! 879: int st;
! 880:
! 881: if (!label)
! 882: label = "audio";
! 883:
! 884: DPRINTFN(3, ("audio_sleep_timo: chan=%p, label=%s, timo=%d\n",
! 885: chan, label, timo));
! 886: *chan = 1;
! 887: st = tsleep(chan, PWAIT | PCATCH, label, timo);
! 888: *chan = 0;
! 889: #ifdef AUDIO_DEBUG
! 890: if (st != 0)
! 891: printf("audio_sleep: woke up st=%d\n", st);
! 892: #endif
! 893: return (st);
! 894: }
! 895:
! 896: static __inline int
! 897: audio_sleep(int *chan, char *label)
! 898: {
! 899: return audio_sleep_timo(chan, label, 0);
! 900: }
! 901:
! 902: /* call at splaudio() */
! 903: static __inline void
! 904: audio_wakeup(int *chan)
! 905: {
! 906: DPRINTFN(3, ("audio_wakeup: chan=%p, *chan=%d\n", chan, *chan));
! 907: if (*chan) {
! 908: wakeup(chan);
! 909: *chan = 0;
! 910: }
! 911: }
! 912:
! 913: int
! 914: audio_open(dev_t dev, struct audio_softc *sc, int flags, int ifmt,
! 915: struct proc *p)
! 916: {
! 917: int error;
! 918: int mode;
! 919: struct audio_info ai;
! 920:
! 921: DPRINTF(("audio_open: dev=0x%x flags=0x%x sc=%p hdl=%p\n", dev, flags, sc, sc->hw_hdl));
! 922:
! 923: if (ISDEVAUDIOCTL(dev))
! 924: return 0;
! 925:
! 926: if ((sc->sc_open & (AUOPEN_READ|AUOPEN_WRITE)) != 0)
! 927: return (EBUSY);
! 928:
! 929: error = sc->hw_if->open(sc->hw_hdl, flags);
! 930: if (error)
! 931: return (error);
! 932:
! 933: sc->sc_async_audio = 0;
! 934: sc->sc_rchan = 0;
! 935: sc->sc_wchan = 0;
! 936: sc->sc_blkset = 0; /* Block sizes not set yet */
! 937: sc->sc_sil_count = 0;
! 938: sc->sc_rbus = 0;
! 939: sc->sc_pbus = 0;
! 940: sc->sc_eof = 0;
! 941: sc->sc_playdrop = 0;
! 942:
! 943: sc->sc_full_duplex = 0;
! 944: /* doesn't always work right on SB.
! 945: (flags & (FWRITE|FREAD)) == (FWRITE|FREAD) &&
! 946: (sc->hw_if->get_props(sc->hw_hdl) & AUDIO_PROP_FULLDUPLEX);
! 947: */
! 948:
! 949: mode = 0;
! 950: if (flags & FREAD) {
! 951: sc->sc_open |= AUOPEN_READ;
! 952: mode |= AUMODE_RECORD;
! 953: }
! 954: if (flags & FWRITE) {
! 955: sc->sc_open |= AUOPEN_WRITE;
! 956: mode |= AUMODE_PLAY | AUMODE_PLAY_ALL;
! 957: }
! 958:
! 959: /*
! 960: * Multiplex device: /dev/audio (MU-Law) and /dev/sound (linear)
! 961: * The /dev/audio is always (re)set to 8-bit MU-Law mono
! 962: * For the other devices, you get what they were last set to.
! 963: */
! 964: if (ISDEVAUDIO(dev)) {
! 965: /* /dev/audio */
! 966: sc->sc_rparams = audio_default;
! 967: sc->sc_pparams = audio_default;
! 968: }
! 969: #ifdef DIAGNOSTIC
! 970: /*
! 971: * Sample rate and precision are supposed to be set to proper
! 972: * default values by the hardware driver, so that it may give
! 973: * us these values.
! 974: */
! 975: if (sc->sc_rparams.precision == 0 || sc->sc_pparams.precision == 0) {
! 976: printf("audio_open: 0 precision\n");
! 977: error = EINVAL;
! 978: goto bad;
! 979: }
! 980: #endif
! 981:
! 982: AUDIO_INITINFO(&ai);
! 983: ai.record.sample_rate = sc->sc_rparams.sample_rate;
! 984: ai.record.encoding = sc->sc_rparams.encoding;
! 985: ai.record.channels = sc->sc_rparams.channels;
! 986: ai.record.precision = sc->sc_rparams.precision;
! 987: ai.record.pause = 0;
! 988: ai.play.sample_rate = sc->sc_pparams.sample_rate;
! 989: ai.play.encoding = sc->sc_pparams.encoding;
! 990: ai.play.channels = sc->sc_pparams.channels;
! 991: ai.play.precision = sc->sc_pparams.precision;
! 992: ai.play.pause = 0;
! 993: ai.mode = mode;
! 994: sc->sc_pr.blksize = sc->sc_rr.blksize = 0; /* force recalculation */
! 995: error = audiosetinfo(sc, &ai);
! 996: if (error)
! 997: goto bad;
! 998:
! 999: DPRINTF(("audio_open: done sc_mode = 0x%x\n", sc->sc_mode));
! 1000:
! 1001: return 0;
! 1002:
! 1003: bad:
! 1004: sc->hw_if->close(sc->hw_hdl);
! 1005: sc->sc_open = 0;
! 1006: sc->sc_mode = 0;
! 1007: sc->sc_full_duplex = 0;
! 1008: return error;
! 1009: }
! 1010:
! 1011: /*
! 1012: * Must be called from task context.
! 1013: */
! 1014: void
! 1015: audio_init_record(struct audio_softc *sc)
! 1016: {
! 1017: int s = splaudio();
! 1018:
! 1019: if (sc->hw_if->speaker_ctl &&
! 1020: (!sc->sc_full_duplex || (sc->sc_mode & AUMODE_PLAY) == 0))
! 1021: sc->hw_if->speaker_ctl(sc->hw_hdl, SPKR_OFF);
! 1022: splx(s);
! 1023: }
! 1024:
! 1025: /*
! 1026: * Must be called from task context.
! 1027: */
! 1028: void
! 1029: audio_init_play(struct audio_softc *sc)
! 1030: {
! 1031: int s = splaudio();
! 1032:
! 1033: sc->sc_wstamp = sc->sc_pr.stamp;
! 1034: if (sc->hw_if->speaker_ctl)
! 1035: sc->hw_if->speaker_ctl(sc->hw_hdl, SPKR_ON);
! 1036: splx(s);
! 1037: }
! 1038:
! 1039: int
! 1040: audio_drain(struct audio_softc *sc)
! 1041: {
! 1042: int error, drops;
! 1043: struct audio_ringbuffer *cb = &sc->sc_pr;
! 1044: int s;
! 1045:
! 1046: DPRINTF(("audio_drain: enter busy=%d used=%d\n",
! 1047: sc->sc_pbus, sc->sc_pr.used));
! 1048: if (sc->sc_pr.mmapped || sc->sc_pr.used <= 0)
! 1049: return 0;
! 1050: if (!sc->sc_pbus) {
! 1051: /* We've never started playing, probably because the
! 1052: * block was too short. Pad it and start now.
! 1053: */
! 1054: int cc;
! 1055: u_char *inp = cb->inp;
! 1056:
! 1057: cc = cb->blksize - (inp - cb->start) % cb->blksize;
! 1058: if (sc->sc_pparams.sw_code) {
! 1059: int ncc = cc / sc->sc_pparams.factor;
! 1060: audio_fill_silence(&sc->sc_pparams, inp, ncc);
! 1061: sc->sc_pparams.sw_code(sc->hw_hdl, inp, ncc);
! 1062: } else
! 1063: audio_fill_silence(&sc->sc_pparams, inp, cc);
! 1064: inp += cc;
! 1065: if (inp >= cb->end)
! 1066: inp = cb->start;
! 1067: s = splaudio();
! 1068: cb->used += cc;
! 1069: cb->inp = inp;
! 1070: error = audiostartp(sc);
! 1071: splx(s);
! 1072: if (error)
! 1073: return error;
! 1074: }
! 1075: /*
! 1076: * Play until a silence block has been played, then we
! 1077: * know all has been drained.
! 1078: * XXX This should be done some other way to avoid
! 1079: * playing silence.
! 1080: */
! 1081: #ifdef DIAGNOSTIC
! 1082: if (cb->copying) {
! 1083: printf("audio_drain: copying in progress!?!\n");
! 1084: cb->copying = 0;
! 1085: }
! 1086: #endif
! 1087: drops = cb->drops;
! 1088: error = 0;
! 1089: s = splaudio();
! 1090: while (cb->drops == drops && !error) {
! 1091: DPRINTF(("audio_drain: used=%d, drops=%ld\n", sc->sc_pr.used, cb->drops));
! 1092: /*
! 1093: * When the process is exiting, it ignores all signals and
! 1094: * we can't interrupt this sleep, so we set a timeout just in case.
! 1095: */
! 1096: error = audio_sleep_timo(&sc->sc_wchan, "aud_dr", 30*hz);
! 1097: if (sc->sc_dying)
! 1098: error = EIO;
! 1099: }
! 1100: splx(s);
! 1101: return error;
! 1102: }
! 1103:
! 1104: /*
! 1105: * Close an audio chip.
! 1106: */
! 1107: /* ARGSUSED */
! 1108: int
! 1109: audio_close(dev_t dev, int flags, int ifmt, struct proc *p)
! 1110: {
! 1111: int unit = AUDIOUNIT(dev);
! 1112: struct audio_softc *sc = audio_cd.cd_devs[unit];
! 1113: struct audio_hw_if *hw = sc->hw_if;
! 1114: int s;
! 1115:
! 1116: DPRINTF(("audio_close: unit=%d flags=0x%x\n", unit, flags));
! 1117:
! 1118: s = splaudio();
! 1119: /* Stop recording. */
! 1120: if ((flags & FREAD) && sc->sc_rbus) {
! 1121: /*
! 1122: * XXX Some drivers (e.g. SB) use the same routine
! 1123: * to halt input and output so don't halt input if
! 1124: * in full duplex mode. These drivers should be fixed.
! 1125: */
! 1126: if (!sc->sc_full_duplex || sc->hw_if->halt_input != sc->hw_if->halt_output)
! 1127: sc->hw_if->halt_input(sc->hw_hdl);
! 1128: sc->sc_rbus = 0;
! 1129: }
! 1130: /*
! 1131: * Block until output drains, but allow ^C interrupt.
! 1132: */
! 1133: sc->sc_pr.usedlow = sc->sc_pr.blksize; /* avoid excessive wakeups */
! 1134: /*
! 1135: * If there is pending output, let it drain (unless
! 1136: * the output is paused).
! 1137: */
! 1138: if ((flags & FWRITE) && sc->sc_pbus) {
! 1139: if (!sc->sc_pr.pause && !audio_drain(sc) && hw->drain)
! 1140: (void)hw->drain(sc->hw_hdl);
! 1141: sc->hw_if->halt_output(sc->hw_hdl);
! 1142: sc->sc_pbus = 0;
! 1143: }
! 1144:
! 1145: hw->close(sc->hw_hdl);
! 1146:
! 1147: /*
! 1148: * If flags has neither read nor write then reset both
! 1149: * directions. Encountered when someone runs revoke(2).
! 1150: */
! 1151:
! 1152: if ((flags & FREAD) || ((flags & (FREAD|FWRITE)) == 0)) {
! 1153: sc->sc_open &= ~AUOPEN_READ;
! 1154: sc->sc_mode &= ~AUMODE_RECORD;
! 1155: }
! 1156: if ((flags & FWRITE) || ((flags & (FREAD|FWRITE)) == 0)) {
! 1157: sc->sc_open &= ~AUOPEN_WRITE;
! 1158: sc->sc_mode &= ~(AUMODE_PLAY|AUMODE_PLAY_ALL);
! 1159: }
! 1160:
! 1161: sc->sc_async_audio = 0;
! 1162: sc->sc_full_duplex = 0;
! 1163: splx(s);
! 1164: DPRINTF(("audio_close: done\n"));
! 1165:
! 1166: return (0);
! 1167: }
! 1168:
! 1169: int
! 1170: audio_read(dev_t dev, struct uio *uio, int ioflag)
! 1171: {
! 1172: int unit = AUDIOUNIT(dev);
! 1173: struct audio_softc *sc = audio_cd.cd_devs[unit];
! 1174: struct audio_ringbuffer *cb = &sc->sc_rr;
! 1175: u_char *outp;
! 1176: int error, s, used, cc, n;
! 1177:
! 1178: if (cb->mmapped)
! 1179: return EINVAL;
! 1180:
! 1181: DPRINTFN(1,("audio_read: cc=%d mode=%d\n",
! 1182: uio->uio_resid, sc->sc_mode));
! 1183:
! 1184: error = 0;
! 1185: /*
! 1186: * If hardware is half-duplex and currently playing, return
! 1187: * silence blocks based on the number of blocks we have output.
! 1188: */
! 1189: if (!sc->sc_full_duplex &&
! 1190: (sc->sc_mode & AUMODE_PLAY)) {
! 1191: while (uio->uio_resid > 0 && !error) {
! 1192: s = splaudio();
! 1193: for(;;) {
! 1194: cc = sc->sc_pr.stamp - sc->sc_wstamp;
! 1195: if (cc > 0)
! 1196: break;
! 1197: DPRINTF(("audio_read: stamp=%lu, wstamp=%lu\n",
! 1198: sc->sc_pr.stamp, sc->sc_wstamp));
! 1199: if (ioflag & IO_NDELAY) {
! 1200: splx(s);
! 1201: return EWOULDBLOCK;
! 1202: }
! 1203: error = audio_sleep(&sc->sc_rchan, "aud_hr");
! 1204: if (sc->sc_dying)
! 1205: error = EIO;
! 1206: if (error) {
! 1207: splx(s);
! 1208: return error;
! 1209: }
! 1210: }
! 1211: splx(s);
! 1212:
! 1213: if (uio->uio_resid < cc / sc->sc_rparams.factor)
! 1214: cc = uio->uio_resid * sc->sc_rparams.factor;
! 1215: DPRINTFN(1, ("audio_read: reading in write mode, cc=%d\n", cc));
! 1216: error = audio_silence_copyout(sc,
! 1217: cc / sc->sc_rparams.factor, uio);
! 1218: sc->sc_wstamp += cc;
! 1219: }
! 1220: return (error);
! 1221: }
! 1222: while (uio->uio_resid > 0 && !error) {
! 1223: s = splaudio();
! 1224: while (cb->used <= 0) {
! 1225: if (!sc->sc_rbus && !sc->sc_rr.pause) {
! 1226: error = audiostartr(sc);
! 1227: if (error) {
! 1228: splx(s);
! 1229: return error;
! 1230: }
! 1231: }
! 1232: if (ioflag & IO_NDELAY) {
! 1233: splx(s);
! 1234: return (EWOULDBLOCK);
! 1235: }
! 1236: DPRINTFN(2, ("audio_read: sleep used=%d\n", cb->used));
! 1237: error = audio_sleep(&sc->sc_rchan, "aud_rd");
! 1238: if (sc->sc_dying)
! 1239: error = EIO;
! 1240: if (error) {
! 1241: splx(s);
! 1242: return error;
! 1243: }
! 1244: }
! 1245: used = cb->used;
! 1246: outp = cb->outp;
! 1247: cb->copying = 1;
! 1248: splx(s);
! 1249: cc = used - cb->usedlow; /* maximum to read */
! 1250: n = cb->end - outp;
! 1251: if (n < cc)
! 1252: cc = n; /* don't read beyond end of buffer */
! 1253:
! 1254: /* and no more than we want */
! 1255: if (uio->uio_resid < cc / sc->sc_rparams.factor)
! 1256: cc = uio->uio_resid * sc->sc_rparams.factor;
! 1257:
! 1258: if (sc->sc_rparams.sw_code)
! 1259: sc->sc_rparams.sw_code(sc->hw_hdl, outp, cc);
! 1260: DPRINTFN(1,("audio_read: outp=%p, cc=%d\n", outp, cc));
! 1261: error = uiomove(outp, cc / sc->sc_rparams.factor, uio);
! 1262: used -= cc;
! 1263: outp += cc;
! 1264: if (outp >= cb->end)
! 1265: outp = cb->start;
! 1266: s = splaudio();
! 1267: cb->outp = outp;
! 1268: cb->used = used;
! 1269: cb->copying = 0;
! 1270: splx(s);
! 1271: }
! 1272: return (error);
! 1273: }
! 1274:
! 1275: void
! 1276: audio_clear(struct audio_softc *sc)
! 1277: {
! 1278: int s = splaudio();
! 1279:
! 1280: if (sc->sc_rbus) {
! 1281: audio_wakeup(&sc->sc_rchan);
! 1282: sc->hw_if->halt_input(sc->hw_hdl);
! 1283: sc->sc_rbus = 0;
! 1284: }
! 1285: if (sc->sc_pbus) {
! 1286: audio_wakeup(&sc->sc_wchan);
! 1287: sc->hw_if->halt_output(sc->hw_hdl);
! 1288: sc->sc_pbus = 0;
! 1289: }
! 1290: splx(s);
! 1291: }
! 1292:
! 1293: void
! 1294: audio_calc_blksize(struct audio_softc *sc, int mode)
! 1295: {
! 1296: struct audio_hw_if *hw = sc->hw_if;
! 1297: struct audio_params *parm;
! 1298: struct audio_ringbuffer *rb;
! 1299: int bs;
! 1300:
! 1301: if (sc->sc_blkset)
! 1302: return;
! 1303:
! 1304: if (mode == AUMODE_PLAY) {
! 1305: parm = &sc->sc_pparams;
! 1306: rb = &sc->sc_pr;
! 1307: } else {
! 1308: parm = &sc->sc_rparams;
! 1309: rb = &sc->sc_rr;
! 1310: }
! 1311:
! 1312: bs = parm->sample_rate * audio_blk_ms / 1000 *
! 1313: parm->channels * parm->precision / NBBY *
! 1314: parm->factor;
! 1315: ROUNDSIZE(bs);
! 1316: if (hw->round_blocksize)
! 1317: bs = hw->round_blocksize(sc->hw_hdl, bs);
! 1318: rb->blksize = bs;
! 1319:
! 1320: DPRINTF(("audio_calc_blksize: %s blksize=%d\n",
! 1321: mode == AUMODE_PLAY ? "play" : "record", bs));
! 1322: }
! 1323:
! 1324: void
! 1325: audio_fill_silence(struct audio_params *params, u_char *p, int n)
! 1326: {
! 1327: u_char auzero0, auzero1 = 0; /* initialize to please gcc */
! 1328: int nfill = 1;
! 1329:
! 1330: switch (params->encoding) {
! 1331: case AUDIO_ENCODING_ULAW:
! 1332: auzero0 = 0x7f;
! 1333: break;
! 1334: case AUDIO_ENCODING_ALAW:
! 1335: auzero0 = 0x55;
! 1336: break;
! 1337: case AUDIO_ENCODING_MPEG_L1_STREAM:
! 1338: case AUDIO_ENCODING_MPEG_L1_PACKETS:
! 1339: case AUDIO_ENCODING_MPEG_L1_SYSTEM:
! 1340: case AUDIO_ENCODING_MPEG_L2_STREAM:
! 1341: case AUDIO_ENCODING_MPEG_L2_PACKETS:
! 1342: case AUDIO_ENCODING_MPEG_L2_SYSTEM:
! 1343: case AUDIO_ENCODING_ADPCM: /* is this right XXX */
! 1344: case AUDIO_ENCODING_SLINEAR_LE:
! 1345: case AUDIO_ENCODING_SLINEAR_BE:
! 1346: auzero0 = 0; /* fortunately this works for both 8 and 16 bits */
! 1347: break;
! 1348: case AUDIO_ENCODING_ULINEAR_LE:
! 1349: case AUDIO_ENCODING_ULINEAR_BE:
! 1350: if (params->precision == 16) {
! 1351: nfill = 2;
! 1352: if (params->encoding == AUDIO_ENCODING_ULINEAR_LE) {
! 1353: auzero0 = 0;
! 1354: auzero1 = 0x80;
! 1355: } else {
! 1356: auzero0 = 0x80;
! 1357: auzero1 = 0;
! 1358: }
! 1359: } else
! 1360: auzero0 = 0x80;
! 1361: break;
! 1362: default:
! 1363: DPRINTF(("audio: bad encoding %d\n", params->encoding));
! 1364: auzero0 = 0;
! 1365: break;
! 1366: }
! 1367: if (nfill == 1) {
! 1368: while (--n >= 0)
! 1369: *p++ = auzero0; /* XXX memset */
! 1370: } else /* nfill must be 2 */ {
! 1371: while (n > 1) {
! 1372: *p++ = auzero0;
! 1373: *p++ = auzero1;
! 1374: n -= 2;
! 1375: }
! 1376: }
! 1377: }
! 1378:
! 1379: int
! 1380: audio_silence_copyout(struct audio_softc *sc, int n, struct uio *uio)
! 1381: {
! 1382: int error;
! 1383: int k;
! 1384: u_char zerobuf[128];
! 1385:
! 1386: audio_fill_silence(&sc->sc_rparams, zerobuf, sizeof zerobuf);
! 1387:
! 1388: error = 0;
! 1389: while (n > 0 && uio->uio_resid > 0 && !error) {
! 1390: k = min(n, min(uio->uio_resid, sizeof zerobuf));
! 1391: error = uiomove(zerobuf, k, uio);
! 1392: n -= k;
! 1393: }
! 1394: return (error);
! 1395: }
! 1396:
! 1397: int
! 1398: audio_write(dev_t dev, struct uio *uio, int ioflag)
! 1399: {
! 1400: int unit = AUDIOUNIT(dev);
! 1401: struct audio_softc *sc = audio_cd.cd_devs[unit];
! 1402: struct audio_ringbuffer *cb = &sc->sc_pr;
! 1403: u_char *inp, *einp;
! 1404: int saveerror, error, s, n, cc, used;
! 1405:
! 1406: DPRINTFN(2, ("audio_write: sc=%p(unit=%d) count=%d used=%d(hi=%d)\n", sc, unit,
! 1407: uio->uio_resid, sc->sc_pr.used, sc->sc_pr.usedhigh));
! 1408:
! 1409: if (cb->mmapped)
! 1410: return EINVAL;
! 1411:
! 1412: if (uio->uio_resid == 0) {
! 1413: sc->sc_eof++;
! 1414: return 0;
! 1415: }
! 1416:
! 1417: /*
! 1418: * If half-duplex and currently recording, throw away data.
! 1419: */
! 1420: if (!sc->sc_full_duplex &&
! 1421: (sc->sc_mode & AUMODE_RECORD)) {
! 1422: uio->uio_offset += uio->uio_resid;
! 1423: uio->uio_resid = 0;
! 1424: DPRINTF(("audio_write: half-dpx read busy\n"));
! 1425: return (0);
! 1426: }
! 1427:
! 1428: if (!(sc->sc_mode & AUMODE_PLAY_ALL) && sc->sc_playdrop > 0) {
! 1429: n = min(sc->sc_playdrop, uio->uio_resid * sc->sc_pparams.factor);
! 1430: DPRINTF(("audio_write: playdrop %d\n", n));
! 1431: uio->uio_offset += n / sc->sc_pparams.factor;
! 1432: uio->uio_resid -= n / sc->sc_pparams.factor;
! 1433: sc->sc_playdrop -= n;
! 1434: if (uio->uio_resid == 0)
! 1435: return 0;
! 1436: }
! 1437:
! 1438: DPRINTFN(1, ("audio_write: sr=%ld, enc=%d, prec=%d, chan=%d, sw=%p, fact=%d\n",
! 1439: sc->sc_pparams.sample_rate, sc->sc_pparams.encoding,
! 1440: sc->sc_pparams.precision, sc->sc_pparams.channels,
! 1441: sc->sc_pparams.sw_code, sc->sc_pparams.factor));
! 1442:
! 1443: error = 0;
! 1444: while (uio->uio_resid > 0 && !error) {
! 1445: s = splaudio();
! 1446: while (cb->used >= cb->usedhigh) {
! 1447: DPRINTFN(2, ("audio_write: sleep used=%d lowat=%d hiwat=%d\n",
! 1448: cb->used, cb->usedlow, cb->usedhigh));
! 1449: if (ioflag & IO_NDELAY) {
! 1450: splx(s);
! 1451: return (EWOULDBLOCK);
! 1452: }
! 1453: error = audio_sleep(&sc->sc_wchan, "aud_wr");
! 1454: if (sc->sc_dying)
! 1455: error = EIO;
! 1456: if (error) {
! 1457: splx(s);
! 1458: return error;
! 1459: }
! 1460: }
! 1461: used = cb->used;
! 1462: inp = cb->inp;
! 1463: cb->copying = 1;
! 1464: splx(s);
! 1465: cc = cb->usedhigh - used; /* maximum to write */
! 1466: n = cb->end - inp;
! 1467: if (sc->sc_pparams.factor != 1) {
! 1468: /* Compensate for software coding expansion factor. */
! 1469: n /= sc->sc_pparams.factor;
! 1470: cc /= sc->sc_pparams.factor;
! 1471: }
! 1472: if (n < cc)
! 1473: cc = n; /* don't write beyond end of buffer */
! 1474: if (uio->uio_resid < cc)
! 1475: cc = uio->uio_resid; /* and no more than we have */
! 1476:
! 1477: #ifdef DIAGNOSTIC
! 1478: /*
! 1479: * This should never happen since the block size and and
! 1480: * block pointers are always nicely aligned.
! 1481: */
! 1482: if (cc == 0) {
! 1483: printf("audio_write: cc == 0, swcode=%p, factor=%d\n",
! 1484: sc->sc_pparams.sw_code, sc->sc_pparams.factor);
! 1485: cb->copying = 0;
! 1486: return EINVAL;
! 1487: }
! 1488: #endif
! 1489: DPRINTFN(1, ("audio_write: uiomove cc=%d inp=%p, left=%d\n",
! 1490: cc, inp, uio->uio_resid));
! 1491: n = uio->uio_resid;
! 1492: error = uiomove(inp, cc, uio);
! 1493: cc = n - uio->uio_resid; /* number of bytes actually moved */
! 1494: #ifdef AUDIO_DEBUG
! 1495: if (error)
! 1496: printf("audio_write:(1) uiomove failed %d; cc=%d inp=%p\n",
! 1497: error, cc, inp);
! 1498: #endif
! 1499: /*
! 1500: * Continue even if uiomove() failed because we may have
! 1501: * gotten a partial block.
! 1502: */
! 1503:
! 1504: if (sc->sc_pparams.sw_code) {
! 1505: sc->sc_pparams.sw_code(sc->hw_hdl, inp, cc);
! 1506: /* Adjust count after the expansion. */
! 1507: cc *= sc->sc_pparams.factor;
! 1508: DPRINTFN(1, ("audio_write: expanded cc=%d\n", cc));
! 1509: }
! 1510:
! 1511: einp = cb->inp + cc;
! 1512: if (einp >= cb->end)
! 1513: einp = cb->start;
! 1514:
! 1515: s = splaudio();
! 1516: /*
! 1517: * This is a very suboptimal way of keeping track of
! 1518: * silence in the buffer, but it is simple.
! 1519: */
! 1520: sc->sc_sil_count = 0;
! 1521:
! 1522: cb->inp = einp;
! 1523: cb->used += cc;
! 1524: /* If the interrupt routine wants the last block filled AND
! 1525: * the copy did not fill the last block completely it needs to
! 1526: * be padded.
! 1527: */
! 1528: if (cb->needfill &&
! 1529: (inp - cb->start) / cb->blksize ==
! 1530: (einp - cb->start) / cb->blksize) {
! 1531: /* Figure out how many bytes there is to a block boundary. */
! 1532: cc = cb->blksize - (einp - cb->start) % cb->blksize;
! 1533: DPRINTF(("audio_write: partial fill %d\n", cc));
! 1534: } else
! 1535: cc = 0;
! 1536: cb->needfill = 0;
! 1537: cb->copying = 0;
! 1538: if (!sc->sc_pbus && !cb->pause) {
! 1539: saveerror = error;
! 1540: error = audiostartp(sc);
! 1541: if (saveerror != 0) {
! 1542: /* Report the first error that occurred. */
! 1543: error = saveerror;
! 1544: }
! 1545: }
! 1546: splx(s);
! 1547: if (cc) {
! 1548: DPRINTFN(1, ("audio_write: fill %d\n", cc));
! 1549: if (sc->sc_pparams.sw_code) {
! 1550: int ncc = cc / sc->sc_pparams.factor;
! 1551: audio_fill_silence(&sc->sc_pparams, einp, ncc);
! 1552: sc->sc_pparams.sw_code(sc->hw_hdl, einp, ncc);
! 1553: } else
! 1554: audio_fill_silence(&sc->sc_pparams, einp, cc);
! 1555: }
! 1556: }
! 1557: return (error);
! 1558: }
! 1559:
! 1560: int
! 1561: audio_ioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
! 1562: {
! 1563: int unit = AUDIOUNIT(dev);
! 1564: struct audio_softc *sc = audio_cd.cd_devs[unit];
! 1565: struct audio_hw_if *hw = sc->hw_if;
! 1566: struct audio_offset *ao;
! 1567: int error = 0, s, offs, fd;
! 1568: int rbus, pbus;
! 1569:
! 1570: DPRINTF(("audio_ioctl(%d,'%c',%d)\n",
! 1571: IOCPARM_LEN(cmd), IOCGROUP(cmd), cmd&0xff));
! 1572: switch (cmd) {
! 1573: case FIONBIO:
! 1574: /* All handled in the upper FS layer. */
! 1575: break;
! 1576:
! 1577: case FIOASYNC:
! 1578: if (*(int *)addr) {
! 1579: if (sc->sc_async_audio)
! 1580: return (EBUSY);
! 1581: sc->sc_async_audio = p;
! 1582: DPRINTF(("audio_ioctl: FIOASYNC %p\n", p));
! 1583: } else
! 1584: sc->sc_async_audio = 0;
! 1585: break;
! 1586:
! 1587: case AUDIO_FLUSH:
! 1588: DPRINTF(("AUDIO_FLUSH\n"));
! 1589: rbus = sc->sc_rbus;
! 1590: pbus = sc->sc_pbus;
! 1591: audio_clear(sc);
! 1592: s = splaudio();
! 1593: error = audio_initbufs(sc);
! 1594: if (error) {
! 1595: splx(s);
! 1596: return error;
! 1597: }
! 1598: sc->sc_rr.pause = 0;
! 1599: sc->sc_pr.pause = 0;
! 1600: if ((sc->sc_mode & AUMODE_PLAY) && !sc->sc_pbus && pbus)
! 1601: error = audiostartp(sc);
! 1602: if (!error &&
! 1603: (sc->sc_mode & AUMODE_RECORD) && !sc->sc_rbus && rbus)
! 1604: error = audiostartr(sc);
! 1605: splx(s);
! 1606: break;
! 1607:
! 1608: /*
! 1609: * Number of read (write) samples dropped. We don't know where or
! 1610: * when they were dropped.
! 1611: *
! 1612: * The audio_ringbuffer->drops count is the number of buffer
! 1613: * sample size bytes. Convert it to userland sample size bytes,
! 1614: * then convert to samples. There is no easy way to get the
! 1615: * buffer sample size, but the userland sample size can be
! 1616: * calculated with userland channels and userland precision.
! 1617: *
! 1618: * original formula:
! 1619: * sc->sc_rr.drops /
! 1620: * sc->sc_rparams.factor /
! 1621: * (sc->sc_rparams.channels * (sc->sc_rparams.precision / NBBY))
! 1622: */
! 1623: case AUDIO_RERROR:
! 1624: *(int *)addr = (sc->sc_rr.drops * NBBY) /
! 1625: (sc->sc_rparams.factor * sc->sc_rparams.channels *
! 1626: sc->sc_rparams.precision);
! 1627: break;
! 1628:
! 1629: case AUDIO_PERROR:
! 1630: *(int *)addr = (sc->sc_pr.drops * NBBY) /
! 1631: (sc->sc_pparams.factor * sc->sc_pparams.channels *
! 1632: sc->sc_pparams.precision);
! 1633: break;
! 1634:
! 1635: /*
! 1636: * Offsets into buffer.
! 1637: */
! 1638: case AUDIO_GETIOFFS:
! 1639: s = splaudio();
! 1640: /* figure out where next DMA will start */
! 1641: ao = (struct audio_offset *)addr;
! 1642: ao->samples = sc->sc_rr.stamp;
! 1643: ao->deltablks = (sc->sc_rr.stamp - sc->sc_rr.stamp_last) / sc->sc_rr.blksize;
! 1644: sc->sc_rr.stamp_last = sc->sc_rr.stamp;
! 1645: ao->offset = sc->sc_rr.inp - sc->sc_rr.start;
! 1646: splx(s);
! 1647: break;
! 1648:
! 1649: case AUDIO_GETOOFFS:
! 1650: s = splaudio();
! 1651: /* figure out where next DMA will start */
! 1652: ao = (struct audio_offset *)addr;
! 1653: offs = sc->sc_pr.outp - sc->sc_pr.start + sc->sc_pr.blksize;
! 1654: if (sc->sc_pr.start + offs >= sc->sc_pr.end)
! 1655: offs = 0;
! 1656: ao->samples = sc->sc_pr.stamp;
! 1657: ao->deltablks = (sc->sc_pr.stamp - sc->sc_pr.stamp_last) / sc->sc_pr.blksize;
! 1658: sc->sc_pr.stamp_last = sc->sc_pr.stamp;
! 1659: ao->offset = offs;
! 1660: splx(s);
! 1661: break;
! 1662:
! 1663: /*
! 1664: * How many bytes will elapse until mike hears the first
! 1665: * sample of what we write next?
! 1666: */
! 1667: case AUDIO_WSEEK:
! 1668: *(u_long *)addr = sc->sc_pr.used / sc->sc_pparams.factor;
! 1669: break;
! 1670:
! 1671: case AUDIO_SETINFO:
! 1672: DPRINTF(("AUDIO_SETINFO mode=0x%x\n", sc->sc_mode));
! 1673: error = audiosetinfo(sc, (struct audio_info *)addr);
! 1674: break;
! 1675:
! 1676: case AUDIO_GETINFO:
! 1677: DPRINTF(("AUDIO_GETINFO\n"));
! 1678: error = audiogetinfo(sc, (struct audio_info *)addr);
! 1679: break;
! 1680:
! 1681: case AUDIO_DRAIN:
! 1682: DPRINTF(("AUDIO_DRAIN\n"));
! 1683: error = audio_drain(sc);
! 1684: if (!error && hw->drain)
! 1685: error = hw->drain(sc->hw_hdl);
! 1686: break;
! 1687:
! 1688: case AUDIO_GETDEV:
! 1689: DPRINTF(("AUDIO_GETDEV\n"));
! 1690: error = hw->getdev(sc->hw_hdl, (audio_device_t *)addr);
! 1691: break;
! 1692:
! 1693: case AUDIO_GETENC:
! 1694: DPRINTF(("AUDIO_GETENC\n"));
! 1695: /* Pass read/write info down to query_encoding */
! 1696: ((struct audio_encoding *)addr)->flags = sc->sc_open;
! 1697: error = hw->query_encoding(sc->hw_hdl, (struct audio_encoding *)addr);
! 1698: break;
! 1699:
! 1700: case AUDIO_GETFD:
! 1701: DPRINTF(("AUDIO_GETFD\n"));
! 1702: *(int *)addr = sc->sc_full_duplex;
! 1703: break;
! 1704:
! 1705: case AUDIO_SETFD:
! 1706: DPRINTF(("AUDIO_SETFD\n"));
! 1707: fd = *(int *)addr;
! 1708: if (hw->get_props(sc->hw_hdl) & AUDIO_PROP_FULLDUPLEX) {
! 1709: if (hw->setfd)
! 1710: error = hw->setfd(sc->hw_hdl, fd);
! 1711: else
! 1712: error = 0;
! 1713: if (!error)
! 1714: sc->sc_full_duplex = fd;
! 1715: } else {
! 1716: if (fd)
! 1717: error = ENOTTY;
! 1718: else
! 1719: error = 0;
! 1720: }
! 1721: break;
! 1722:
! 1723: case AUDIO_GETPROPS:
! 1724: DPRINTF(("AUDIO_GETPROPS\n"));
! 1725: *(int *)addr = hw->get_props(sc->hw_hdl);
! 1726: break;
! 1727:
! 1728: default:
! 1729: DPRINTF(("audio_ioctl: unknown ioctl\n"));
! 1730: error = ENOTTY;
! 1731: break;
! 1732: }
! 1733: DPRINTF(("audio_ioctl(%d,'%c',%d) result %d\n",
! 1734: IOCPARM_LEN(cmd), IOCGROUP(cmd), cmd&0xff, error));
! 1735: return (error);
! 1736: }
! 1737:
! 1738: void
! 1739: audio_selwakeup(struct audio_softc *sc, int play)
! 1740: {
! 1741: struct selinfo *si;
! 1742:
! 1743: si = play? &sc->sc_wsel : &sc->sc_rsel;
! 1744:
! 1745: audio_wakeup(play? &sc->sc_wchan : &sc->sc_rchan);
! 1746: selwakeup(si);
! 1747: if (sc->sc_async_audio)
! 1748: psignal(sc->sc_async_audio, SIGIO);
! 1749: KNOTE(&si->si_note, 0);
! 1750: }
! 1751:
! 1752: #define AUDIO_FILTREAD(sc) ( \
! 1753: (!sc->sc_full_duplex && (sc->sc_mode & AUMODE_PLAY)) ? \
! 1754: sc->sc_pr.stamp > sc->sc_wstamp : sc->sc_rr.used > sc->sc_rr.usedlow)
! 1755:
! 1756: #define AUDIO_FILTWRITE(sc) ( \
! 1757: (!sc->sc_full_duplex && (sc->sc_mode & AUMODE_RECORD)) || \
! 1758: (!(sc->sc_mode & AUMODE_PLAY_ALL) && sc->sc_playdrop > 0) || \
! 1759: (sc->sc_pr.used <= sc->sc_pr.usedlow))
! 1760:
! 1761: int
! 1762: audio_poll(dev_t dev, int events, struct proc *p)
! 1763: {
! 1764: int unit = AUDIOUNIT(dev);
! 1765: struct audio_softc *sc = audio_cd.cd_devs[unit];
! 1766: int revents = 0, s = splaudio();
! 1767:
! 1768: DPRINTF(("audio_poll: events=0x%x mode=%d\n", events, sc->sc_mode));
! 1769:
! 1770: if (events & (POLLIN | POLLRDNORM)) {
! 1771: if (AUDIO_FILTREAD(sc))
! 1772: revents |= events & (POLLIN | POLLRDNORM);
! 1773: }
! 1774: if (events & (POLLOUT | POLLWRNORM)) {
! 1775: if (AUDIO_FILTWRITE(sc))
! 1776: revents |= events & (POLLOUT | POLLWRNORM);
! 1777: }
! 1778: if (revents == 0) {
! 1779: if (events & (POLLIN | POLLRDNORM))
! 1780: selrecord(p, &sc->sc_rsel);
! 1781: if (events & (POLLOUT | POLLWRNORM))
! 1782: selrecord(p, &sc->sc_wsel);
! 1783: }
! 1784: splx(s);
! 1785: return (revents);
! 1786: }
! 1787:
! 1788: paddr_t
! 1789: audio_mmap(dev_t dev, off_t off, int prot)
! 1790: {
! 1791: int s;
! 1792: int unit = AUDIOUNIT(dev);
! 1793: struct audio_softc *sc = audio_cd.cd_devs[unit];
! 1794: struct audio_hw_if *hw = sc->hw_if;
! 1795: struct audio_ringbuffer *cb;
! 1796:
! 1797: DPRINTF(("audio_mmap: off=%d, prot=%d\n", off, prot));
! 1798:
! 1799: if (!(hw->get_props(sc->hw_hdl) & AUDIO_PROP_MMAP) || !hw->mappage)
! 1800: return -1;
! 1801: #if 0
! 1802: /* XXX
! 1803: * The idea here was to use the protection to determine if
! 1804: * we are mapping the read or write buffer, but it fails.
! 1805: * The VM system is broken in (at least) two ways.
! 1806: * 1) If you map memory VM_PROT_WRITE you SIGSEGV
! 1807: * when writing to it, so VM_PROT_READ|VM_PROT_WRITE
! 1808: * has to be used for mmapping the play buffer.
! 1809: * 2) Even if calling mmap() with VM_PROT_READ|VM_PROT_WRITE
! 1810: * audio_mmap will get called at some point with VM_PROT_READ
! 1811: * only.
! 1812: * So, alas, we always map the play buffer for now.
! 1813: */
! 1814: if (prot == (VM_PROT_READ|VM_PROT_WRITE) ||
! 1815: prot == VM_PROT_WRITE)
! 1816: cb = &sc->sc_pr;
! 1817: else if (prot == VM_PROT_READ)
! 1818: cb = &sc->sc_rr;
! 1819: else
! 1820: return -1;
! 1821: #else
! 1822: cb = &sc->sc_pr;
! 1823: #endif
! 1824:
! 1825: if ((u_int)off >= cb->bufsize)
! 1826: return -1;
! 1827: if (!cb->mmapped) {
! 1828: cb->mmapped = 1;
! 1829: if (cb == &sc->sc_pr) {
! 1830: audio_fill_silence(&sc->sc_pparams, cb->start, cb->bufsize);
! 1831: s = splaudio();
! 1832: if (!sc->sc_pbus && !sc->sc_pr.pause)
! 1833: (void)audiostartp(sc);
! 1834: splx(s);
! 1835: } else {
! 1836: s = splaudio();
! 1837: if (!sc->sc_rbus && !sc->sc_rr.pause)
! 1838: (void)audiostartr(sc);
! 1839: splx(s);
! 1840: }
! 1841: }
! 1842:
! 1843: return hw->mappage(sc->hw_hdl, cb->start, off, prot);
! 1844: }
! 1845:
! 1846: int
! 1847: audiostartr(struct audio_softc *sc)
! 1848: {
! 1849: int error;
! 1850:
! 1851: DPRINTF(("audiostartr: start=%p used=%d(hi=%d) mmapped=%d\n",
! 1852: sc->sc_rr.start, sc->sc_rr.used, sc->sc_rr.usedhigh,
! 1853: sc->sc_rr.mmapped));
! 1854:
! 1855: if (sc->hw_if->trigger_input)
! 1856: error = sc->hw_if->trigger_input(sc->hw_hdl, sc->sc_rr.start,
! 1857: sc->sc_rr.end, sc->sc_rr.blksize,
! 1858: audio_rint, (void *)sc, &sc->sc_rparams);
! 1859: else
! 1860: error = sc->hw_if->start_input(sc->hw_hdl, sc->sc_rr.start,
! 1861: sc->sc_rr.blksize, audio_rint, (void *)sc);
! 1862: if (error) {
! 1863: DPRINTF(("audiostartr failed: %d\n", error));
! 1864: return error;
! 1865: }
! 1866: sc->sc_rbus = 1;
! 1867: return 0;
! 1868: }
! 1869:
! 1870: int
! 1871: audiostartp(struct audio_softc *sc)
! 1872: {
! 1873: int error;
! 1874:
! 1875: DPRINTF(("audiostartp: start=%p used=%d(hi=%d) mmapped=%d\n",
! 1876: sc->sc_pr.start, sc->sc_pr.used, sc->sc_pr.usedhigh,
! 1877: sc->sc_pr.mmapped));
! 1878:
! 1879: if (!sc->sc_pr.mmapped && sc->sc_pr.used < sc->sc_pr.blksize)
! 1880: return 0;
! 1881:
! 1882: if (sc->hw_if->trigger_output)
! 1883: error = sc->hw_if->trigger_output(sc->hw_hdl, sc->sc_pr.start,
! 1884: sc->sc_pr.end, sc->sc_pr.blksize,
! 1885: audio_pint, (void *)sc, &sc->sc_pparams);
! 1886: else
! 1887: error = sc->hw_if->start_output(sc->hw_hdl, sc->sc_pr.outp,
! 1888: sc->sc_pr.blksize, audio_pint, (void *)sc);
! 1889: if (error) {
! 1890: DPRINTF(("audiostartp failed: %d\n", error));
! 1891: return error;
! 1892: }
! 1893: sc->sc_pbus = 1;
! 1894: return 0;
! 1895: }
! 1896:
! 1897: /*
! 1898: * When the play interrupt routine finds that the write isn't keeping
! 1899: * the buffer filled it will insert silence in the buffer to make up
! 1900: * for this. The part of the buffer that is filled with silence
! 1901: * is kept track of in a very approximate way: it starts at sc_sil_start
! 1902: * and extends sc_sil_count bytes. If there is already silence in
! 1903: * the requested area nothing is done; so when the whole buffer is
! 1904: * silent nothing happens. When the writer starts again sc_sil_count
! 1905: * is set to 0.
! 1906: */
! 1907: /* XXX
! 1908: * Putting silence into the output buffer should not really be done
! 1909: * at splaudio, but there is no softaudio level to do it at yet.
! 1910: */
! 1911: static __inline void
! 1912: audio_pint_silence(struct audio_softc *sc, struct audio_ringbuffer *cb,
! 1913: u_char *inp, int cc)
! 1914: {
! 1915: u_char *s, *e, *p, *q;
! 1916:
! 1917: if (sc->sc_sil_count > 0) {
! 1918: s = sc->sc_sil_start; /* start of silence */
! 1919: e = s + sc->sc_sil_count; /* end of silence, may be beyond end */
! 1920: p = inp; /* adjusted pointer to area to fill */
! 1921: if (p < s)
! 1922: p += cb->end - cb->start;
! 1923: q = p+cc;
! 1924: /* Check if there is already silence. */
! 1925: if (!(s <= p && p < e &&
! 1926: s <= q && q <= e)) {
! 1927: if (s <= p)
! 1928: sc->sc_sil_count = max(sc->sc_sil_count, q-s);
! 1929: DPRINTFN(5, ("audio_pint_silence: fill cc=%d inp=%p, count=%d size=%d\n",
! 1930: cc, inp, sc->sc_sil_count, (int)(cb->end - cb->start)));
! 1931:
! 1932: if (sc->sc_pparams.sw_code) {
! 1933: int ncc = cc / sc->sc_pparams.factor;
! 1934: audio_fill_silence(&sc->sc_pparams, inp, ncc);
! 1935: sc->sc_pparams.sw_code(sc->hw_hdl, inp, ncc);
! 1936: } else
! 1937: audio_fill_silence(&sc->sc_pparams, inp, cc);
! 1938:
! 1939: } else {
! 1940: DPRINTFN(5, ("audio_pint_silence: already silent cc=%d inp=%p\n", cc, inp));
! 1941:
! 1942: }
! 1943: } else {
! 1944: sc->sc_sil_start = inp;
! 1945: sc->sc_sil_count = cc;
! 1946: DPRINTFN(5, ("audio_pint_silence: start fill %p %d\n",
! 1947: inp, cc));
! 1948:
! 1949: if (sc->sc_pparams.sw_code) {
! 1950: int ncc = cc / sc->sc_pparams.factor;
! 1951: audio_fill_silence(&sc->sc_pparams, inp, ncc);
! 1952: sc->sc_pparams.sw_code(sc->hw_hdl, inp, ncc);
! 1953: } else
! 1954: audio_fill_silence(&sc->sc_pparams, inp, cc);
! 1955:
! 1956: }
! 1957: }
! 1958:
! 1959: /*
! 1960: * Called from HW driver module on completion of dma output.
! 1961: * Start output of new block, wrap in ring buffer if needed.
! 1962: * If no more buffers to play, output zero instead.
! 1963: * Do a wakeup if necessary.
! 1964: */
! 1965: void
! 1966: audio_pint(void *v)
! 1967: {
! 1968: struct audio_softc *sc = v;
! 1969: struct audio_hw_if *hw = sc->hw_if;
! 1970: struct audio_ringbuffer *cb = &sc->sc_pr;
! 1971: u_char *inp;
! 1972: int cc;
! 1973: int blksize;
! 1974: int error;
! 1975:
! 1976: if (!sc->sc_open)
! 1977: return; /* ignore interrupt if not open */
! 1978:
! 1979: blksize = cb->blksize;
! 1980:
! 1981: add_audio_randomness((long)cb);
! 1982:
! 1983: cb->outp += blksize;
! 1984: if (cb->outp >= cb->end)
! 1985: cb->outp = cb->start;
! 1986: cb->stamp += blksize;
! 1987: if (cb->mmapped) {
! 1988: DPRINTFN(5, ("audio_pint: mmapped outp=%p cc=%d inp=%p\n",
! 1989: cb->outp, blksize, cb->inp));
! 1990: if (!hw->trigger_output)
! 1991: (void)hw->start_output(sc->hw_hdl, cb->outp,
! 1992: blksize, audio_pint, (void *)sc);
! 1993: return;
! 1994: }
! 1995:
! 1996: #ifdef AUDIO_INTR_TIME
! 1997: {
! 1998: struct timeval tv;
! 1999: u_long t;
! 2000: microtime(&tv);
! 2001: t = tv.tv_usec + 1000000 * tv.tv_sec;
! 2002: if (sc->sc_pnintr) {
! 2003: long lastdelta, totdelta;
! 2004: lastdelta = t - sc->sc_plastintr - sc->sc_pblktime;
! 2005: if (lastdelta > sc->sc_pblktime / 3) {
! 2006: printf("audio: play interrupt(%d) off relative by %ld us (%lu)\n",
! 2007: sc->sc_pnintr, lastdelta, sc->sc_pblktime);
! 2008: }
! 2009: totdelta = t - sc->sc_pfirstintr - sc->sc_pblktime * sc->sc_pnintr;
! 2010: if (totdelta > sc->sc_pblktime) {
! 2011: printf("audio: play interrupt(%d) off absolute by %ld us (%lu) (LOST)\n",
! 2012: sc->sc_pnintr, totdelta, sc->sc_pblktime);
! 2013: sc->sc_pnintr++; /* avoid repeated messages */
! 2014: }
! 2015: } else
! 2016: sc->sc_pfirstintr = t;
! 2017: sc->sc_plastintr = t;
! 2018: sc->sc_pnintr++;
! 2019: }
! 2020: #endif
! 2021:
! 2022: cb->used -= blksize;
! 2023: if (cb->used < blksize) {
! 2024: /* we don't have a full block to use */
! 2025: if (cb->copying) {
! 2026: /* writer is in progress, don't disturb */
! 2027: cb->needfill = 1;
! 2028: DPRINTFN(1, ("audio_pint: copying in progress\n"));
! 2029: } else {
! 2030: inp = cb->inp;
! 2031: cc = blksize - (inp - cb->start) % blksize;
! 2032: if (cb->pause)
! 2033: cb->pdrops += cc;
! 2034: else {
! 2035: cb->drops += cc;
! 2036: sc->sc_playdrop += cc;
! 2037: }
! 2038: audio_pint_silence(sc, cb, inp, cc);
! 2039: inp += cc;
! 2040: if (inp >= cb->end)
! 2041: inp = cb->start;
! 2042: cb->inp = inp;
! 2043: cb->used += cc;
! 2044:
! 2045: /* Clear next block so we keep ahead of the DMA. */
! 2046: if (cb->used + cc < cb->usedhigh)
! 2047: audio_pint_silence(sc, cb, inp, blksize);
! 2048: }
! 2049: }
! 2050:
! 2051: DPRINTFN(5, ("audio_pint: outp=%p cc=%d\n", cb->outp, blksize));
! 2052: if (!hw->trigger_output) {
! 2053: error = hw->start_output(sc->hw_hdl, cb->outp, blksize,
! 2054: audio_pint, (void *)sc);
! 2055: if (error) {
! 2056: /* XXX does this really help? */
! 2057: DPRINTF(("audio_pint restart failed: %d\n", error));
! 2058: audio_clear(sc);
! 2059: }
! 2060: }
! 2061:
! 2062: DPRINTFN(2, ("audio_pint: mode=%d pause=%d used=%d lowat=%d\n",
! 2063: sc->sc_mode, cb->pause, cb->used, cb->usedlow));
! 2064: if ((sc->sc_mode & AUMODE_PLAY) && !cb->pause &&
! 2065: cb->used <= cb->usedlow)
! 2066: audio_selwakeup(sc, 1);
! 2067:
! 2068: /* Possible to return one or more "phantom blocks" now. */
! 2069: if (!sc->sc_full_duplex && sc->sc_rchan)
! 2070: audio_selwakeup(sc, 0);
! 2071: }
! 2072:
! 2073: /*
! 2074: * Called from HW driver module on completion of dma input.
! 2075: * Mark it as input in the ring buffer (fiddle pointers).
! 2076: * Do a wakeup if necessary.
! 2077: */
! 2078: void
! 2079: audio_rint(void *v)
! 2080: {
! 2081: struct audio_softc *sc = v;
! 2082: struct audio_hw_if *hw = sc->hw_if;
! 2083: struct audio_ringbuffer *cb = &sc->sc_rr;
! 2084: int blksize;
! 2085: int error;
! 2086:
! 2087: if (!sc->sc_open)
! 2088: return; /* ignore interrupt if not open */
! 2089:
! 2090: add_audio_randomness((long)cb);
! 2091:
! 2092: blksize = cb->blksize;
! 2093:
! 2094: cb->inp += blksize;
! 2095: if (cb->inp >= cb->end)
! 2096: cb->inp = cb->start;
! 2097: cb->stamp += blksize;
! 2098: if (cb->mmapped) {
! 2099: DPRINTFN(2, ("audio_rint: mmapped inp=%p cc=%d\n",
! 2100: cb->inp, blksize));
! 2101: if (!hw->trigger_input)
! 2102: (void)hw->start_input(sc->hw_hdl, cb->inp, blksize,
! 2103: audio_rint, (void *)sc);
! 2104: return;
! 2105: }
! 2106:
! 2107: #ifdef AUDIO_INTR_TIME
! 2108: {
! 2109: struct timeval tv;
! 2110: u_long t;
! 2111: microtime(&tv);
! 2112: t = tv.tv_usec + 1000000 * tv.tv_sec;
! 2113: if (sc->sc_rnintr) {
! 2114: long lastdelta, totdelta;
! 2115: lastdelta = t - sc->sc_rlastintr - sc->sc_rblktime;
! 2116: if (lastdelta > sc->sc_rblktime / 5) {
! 2117: printf("audio: record interrupt(%d) off relative by %ld us (%lu)\n",
! 2118: sc->sc_rnintr, lastdelta, sc->sc_rblktime);
! 2119: }
! 2120: totdelta = t - sc->sc_rfirstintr - sc->sc_rblktime * sc->sc_rnintr;
! 2121: if (totdelta > sc->sc_rblktime / 2) {
! 2122: sc->sc_rnintr++;
! 2123: printf("audio: record interrupt(%d) off absolute by %ld us (%lu)\n",
! 2124: sc->sc_rnintr, totdelta, sc->sc_rblktime);
! 2125: sc->sc_rnintr++; /* avoid repeated messages */
! 2126: }
! 2127: } else
! 2128: sc->sc_rfirstintr = t;
! 2129: sc->sc_rlastintr = t;
! 2130: sc->sc_rnintr++;
! 2131: }
! 2132: #endif
! 2133:
! 2134: cb->used += blksize;
! 2135: if (cb->pause) {
! 2136: DPRINTFN(1, ("audio_rint: pdrops %lu\n", cb->pdrops));
! 2137: cb->pdrops += blksize;
! 2138: cb->outp += blksize;
! 2139: cb->used -= blksize;
! 2140: } else if (cb->used + blksize >= cb->usedhigh && !cb->copying) {
! 2141: DPRINTFN(1, ("audio_rint: drops %lu\n", cb->drops));
! 2142: cb->drops += blksize;
! 2143: cb->outp += blksize;
! 2144: cb->used -= blksize;
! 2145: }
! 2146:
! 2147: DPRINTFN(2, ("audio_rint: inp=%p cc=%d used=%d\n",
! 2148: cb->inp, blksize, cb->used));
! 2149: if (!hw->trigger_input) {
! 2150: error = hw->start_input(sc->hw_hdl, cb->inp, blksize,
! 2151: audio_rint, (void *)sc);
! 2152: if (error) {
! 2153: /* XXX does this really help? */
! 2154: DPRINTF(("audio_rint: restart failed: %d\n", error));
! 2155: audio_clear(sc);
! 2156: }
! 2157: }
! 2158:
! 2159: audio_selwakeup(sc, 0);
! 2160: }
! 2161:
! 2162: int
! 2163: audio_check_params(struct audio_params *p)
! 2164: {
! 2165: if (p->encoding == AUDIO_ENCODING_PCM16) {
! 2166: if (p->precision == 8)
! 2167: p->encoding = AUDIO_ENCODING_ULINEAR;
! 2168: else
! 2169: p->encoding = AUDIO_ENCODING_SLINEAR;
! 2170: } else if (p->encoding == AUDIO_ENCODING_PCM8) {
! 2171: if (p->precision == 8)
! 2172: p->encoding = AUDIO_ENCODING_ULINEAR;
! 2173: else
! 2174: return EINVAL;
! 2175: }
! 2176:
! 2177: if (p->encoding == AUDIO_ENCODING_SLINEAR)
! 2178: #if BYTE_ORDER == LITTLE_ENDIAN
! 2179: p->encoding = AUDIO_ENCODING_SLINEAR_LE;
! 2180: #else
! 2181: p->encoding = AUDIO_ENCODING_SLINEAR_BE;
! 2182: #endif
! 2183: if (p->encoding == AUDIO_ENCODING_ULINEAR)
! 2184: #if BYTE_ORDER == LITTLE_ENDIAN
! 2185: p->encoding = AUDIO_ENCODING_ULINEAR_LE;
! 2186: #else
! 2187: p->encoding = AUDIO_ENCODING_ULINEAR_BE;
! 2188: #endif
! 2189:
! 2190: switch (p->encoding) {
! 2191: case AUDIO_ENCODING_ULAW:
! 2192: case AUDIO_ENCODING_ALAW:
! 2193: case AUDIO_ENCODING_ADPCM:
! 2194: if (p->precision != 8)
! 2195: return (EINVAL);
! 2196: break;
! 2197: case AUDIO_ENCODING_SLINEAR_LE:
! 2198: case AUDIO_ENCODING_SLINEAR_BE:
! 2199: case AUDIO_ENCODING_ULINEAR_LE:
! 2200: case AUDIO_ENCODING_ULINEAR_BE:
! 2201: if (p->precision != 8 && p->precision != 16)
! 2202: return (EINVAL);
! 2203: break;
! 2204: case AUDIO_ENCODING_MPEG_L1_STREAM:
! 2205: case AUDIO_ENCODING_MPEG_L1_PACKETS:
! 2206: case AUDIO_ENCODING_MPEG_L1_SYSTEM:
! 2207: case AUDIO_ENCODING_MPEG_L2_STREAM:
! 2208: case AUDIO_ENCODING_MPEG_L2_PACKETS:
! 2209: case AUDIO_ENCODING_MPEG_L2_SYSTEM:
! 2210: break;
! 2211: default:
! 2212: return (EINVAL);
! 2213: }
! 2214:
! 2215: if (p->channels < 1 || p->channels > 8) /* sanity check # of channels */
! 2216: return (EINVAL);
! 2217:
! 2218: return (0);
! 2219: }
! 2220:
! 2221: int
! 2222: au_set_lr_value(struct audio_softc *sc, mixer_ctrl_t *ct, int l, int r)
! 2223: {
! 2224: ct->type = AUDIO_MIXER_VALUE;
! 2225: ct->un.value.num_channels = 2;
! 2226: ct->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = l;
! 2227: ct->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = r;
! 2228: if (sc->hw_if->set_port(sc->hw_hdl, ct) == 0)
! 2229: return 0;
! 2230: ct->un.value.num_channels = 1;
! 2231: ct->un.value.level[AUDIO_MIXER_LEVEL_MONO] = (l+r)/2;
! 2232: return sc->hw_if->set_port(sc->hw_hdl, ct);
! 2233: }
! 2234:
! 2235: int
! 2236: au_set_gain(struct audio_softc *sc, struct au_mixer_ports *ports, int gain,
! 2237: int balance)
! 2238: {
! 2239: mixer_ctrl_t ct;
! 2240: int i, error;
! 2241: int l, r;
! 2242: u_int mask;
! 2243: int nset;
! 2244:
! 2245: if (balance == AUDIO_MID_BALANCE) {
! 2246: l = r = gain;
! 2247: } else if (balance < AUDIO_MID_BALANCE) {
! 2248: r = gain;
! 2249: l = (balance * gain) / AUDIO_MID_BALANCE;
! 2250: } else {
! 2251: l = gain;
! 2252: r = ((AUDIO_RIGHT_BALANCE - balance) * gain)
! 2253: / AUDIO_MID_BALANCE;
! 2254: }
! 2255: DPRINTF(("au_set_gain: gain=%d balance=%d, l=%d r=%d\n",
! 2256: gain, balance, l, r));
! 2257:
! 2258: if (ports->index == -1) {
! 2259: usemaster:
! 2260: if (ports->master == -1)
! 2261: return 0; /* just ignore it silently */
! 2262: ct.dev = ports->master;
! 2263: error = au_set_lr_value(sc, &ct, l, r);
! 2264: } else {
! 2265: ct.dev = ports->index;
! 2266: if (ports->isenum) {
! 2267: ct.type = AUDIO_MIXER_ENUM;
! 2268: error = sc->hw_if->get_port(sc->hw_hdl, &ct);
! 2269: if (error)
! 2270: return error;
! 2271: for(i = 0; i < ports->nports; i++) {
! 2272: if (ports->misel[i] == ct.un.ord) {
! 2273: ct.dev = ports->miport[i];
! 2274: if (ct.dev == -1 ||
! 2275: au_set_lr_value(sc, &ct, l, r))
! 2276: goto usemaster;
! 2277: else
! 2278: break;
! 2279: }
! 2280: }
! 2281: } else {
! 2282: ct.type = AUDIO_MIXER_SET;
! 2283: error = sc->hw_if->get_port(sc->hw_hdl, &ct);
! 2284: if (error)
! 2285: return error;
! 2286: mask = ct.un.mask;
! 2287: nset = 0;
! 2288: for(i = 0; i < ports->nports; i++) {
! 2289: if (ports->misel[i] & mask) {
! 2290: ct.dev = ports->miport[i];
! 2291: if (ct.dev != -1 &&
! 2292: au_set_lr_value(sc, &ct, l, r) == 0)
! 2293: nset++;
! 2294: }
! 2295: }
! 2296: if (nset == 0)
! 2297: goto usemaster;
! 2298: }
! 2299: }
! 2300: if (!error)
! 2301: mixer_signal(sc);
! 2302: return error;
! 2303: }
! 2304:
! 2305: int
! 2306: au_get_lr_value(struct audio_softc *sc, mixer_ctrl_t *ct, int *l, int *r)
! 2307: {
! 2308: int error;
! 2309:
! 2310: ct->un.value.num_channels = 2;
! 2311: if (sc->hw_if->get_port(sc->hw_hdl, ct) == 0) {
! 2312: *l = ct->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
! 2313: *r = ct->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
! 2314: } else {
! 2315: ct->un.value.num_channels = 1;
! 2316: error = sc->hw_if->get_port(sc->hw_hdl, ct);
! 2317: if (error)
! 2318: return error;
! 2319: *r = *l = ct->un.value.level[AUDIO_MIXER_LEVEL_MONO];
! 2320: }
! 2321: return 0;
! 2322: }
! 2323:
! 2324: void
! 2325: au_get_gain(struct audio_softc *sc, struct au_mixer_ports *ports, u_int *pgain,
! 2326: u_char *pbalance)
! 2327: {
! 2328: mixer_ctrl_t ct;
! 2329: int i, l, r, n;
! 2330: int lgain = AUDIO_MAX_GAIN/2, rgain = AUDIO_MAX_GAIN/2;
! 2331:
! 2332: if (ports->index == -1) {
! 2333: usemaster:
! 2334: if (ports->master == -1)
! 2335: goto bad;
! 2336: ct.dev = ports->master;
! 2337: ct.type = AUDIO_MIXER_VALUE;
! 2338: if (au_get_lr_value(sc, &ct, &lgain, &rgain))
! 2339: goto bad;
! 2340: } else {
! 2341: ct.dev = ports->index;
! 2342: if (ports->isenum) {
! 2343: ct.type = AUDIO_MIXER_ENUM;
! 2344: if (sc->hw_if->get_port(sc->hw_hdl, &ct))
! 2345: goto bad;
! 2346: ct.type = AUDIO_MIXER_VALUE;
! 2347: for(i = 0; i < ports->nports; i++) {
! 2348: if (ports->misel[i] == ct.un.ord) {
! 2349: ct.dev = ports->miport[i];
! 2350: if (ct.dev == -1 ||
! 2351: au_get_lr_value(sc, &ct,
! 2352: &lgain, &rgain))
! 2353: goto usemaster;
! 2354: else
! 2355: break;
! 2356: }
! 2357: }
! 2358: } else {
! 2359: ct.type = AUDIO_MIXER_SET;
! 2360: if (sc->hw_if->get_port(sc->hw_hdl, &ct))
! 2361: goto bad;
! 2362: ct.type = AUDIO_MIXER_VALUE;
! 2363: lgain = rgain = n = 0;
! 2364: for(i = 0; i < ports->nports; i++) {
! 2365: if (ports->misel[i] & ct.un.mask) {
! 2366: ct.dev = ports->miport[i];
! 2367: if (ct.dev == -1 ||
! 2368: au_get_lr_value(sc, &ct, &l, &r))
! 2369: goto usemaster;
! 2370: else {
! 2371: lgain += l;
! 2372: rgain += r;
! 2373: n++;
! 2374: }
! 2375: }
! 2376: }
! 2377: if (n != 0) {
! 2378: lgain /= n;
! 2379: rgain /= n;
! 2380: }
! 2381: }
! 2382: }
! 2383: bad:
! 2384: if (lgain == rgain) { /* handles lgain==rgain==0 */
! 2385: *pgain = lgain;
! 2386: *pbalance = AUDIO_MID_BALANCE;
! 2387: } else if (lgain < rgain) {
! 2388: *pgain = rgain;
! 2389: *pbalance = (AUDIO_MID_BALANCE * lgain) / rgain;
! 2390: } else /* lgain > rgain */ {
! 2391: *pgain = lgain;
! 2392: *pbalance = AUDIO_RIGHT_BALANCE -
! 2393: (AUDIO_MID_BALANCE * rgain) / lgain;
! 2394: }
! 2395: }
! 2396:
! 2397: int
! 2398: au_set_port(struct audio_softc *sc, struct au_mixer_ports *ports, u_int port)
! 2399: {
! 2400: mixer_ctrl_t ct;
! 2401: int i, error;
! 2402:
! 2403: if (port == 0) /* allow this special case */
! 2404: return 0;
! 2405:
! 2406: if (ports->index == -1)
! 2407: return EINVAL;
! 2408: ct.dev = ports->index;
! 2409: if (ports->isenum) {
! 2410: if (port & (port-1))
! 2411: return EINVAL; /* Only one port allowed */
! 2412: ct.type = AUDIO_MIXER_ENUM;
! 2413: error = EINVAL;
! 2414: for(i = 0; i < ports->nports; i++)
! 2415: if (ports->aumask[i] == port) {
! 2416: ct.un.ord = ports->misel[i];
! 2417: error = sc->hw_if->set_port(sc->hw_hdl, &ct);
! 2418: break;
! 2419: }
! 2420: } else {
! 2421: ct.type = AUDIO_MIXER_SET;
! 2422: ct.un.mask = 0;
! 2423: for(i = 0; i < ports->nports; i++)
! 2424: if (ports->aumask[i] & port)
! 2425: ct.un.mask |= ports->misel[i];
! 2426: if (port != 0 && ct.un.mask == 0)
! 2427: error = EINVAL;
! 2428: else
! 2429: error = sc->hw_if->set_port(sc->hw_hdl, &ct);
! 2430: }
! 2431: if (!error)
! 2432: mixer_signal(sc);
! 2433: return error;
! 2434: }
! 2435:
! 2436: int
! 2437: au_get_port(struct audio_softc *sc, struct au_mixer_ports *ports)
! 2438: {
! 2439: mixer_ctrl_t ct;
! 2440: int i, aumask;
! 2441:
! 2442: if (ports->index == -1)
! 2443: return 0;
! 2444: ct.dev = ports->index;
! 2445: ct.type = ports->isenum ? AUDIO_MIXER_ENUM : AUDIO_MIXER_SET;
! 2446: if (sc->hw_if->get_port(sc->hw_hdl, &ct))
! 2447: return 0;
! 2448: aumask = 0;
! 2449: if (ports->isenum) {
! 2450: for(i = 0; i < ports->nports; i++)
! 2451: if (ct.un.ord == ports->misel[i])
! 2452: aumask = ports->aumask[i];
! 2453: } else {
! 2454: for(i = 0; i < ports->nports; i++)
! 2455: if (ct.un.mask & ports->misel[i])
! 2456: aumask |= ports->aumask[i];
! 2457: }
! 2458: return aumask;
! 2459: }
! 2460:
! 2461: int
! 2462: audiosetinfo(struct audio_softc *sc, struct audio_info *ai)
! 2463: {
! 2464: struct audio_prinfo *r = &ai->record, *p = &ai->play;
! 2465: int cleared;
! 2466: int s, setmode, modechange = 0;
! 2467: int error;
! 2468: struct audio_hw_if *hw = sc->hw_if;
! 2469: struct audio_params pp, rp;
! 2470: int np, nr;
! 2471: unsigned int blks;
! 2472: int oldpblksize, oldrblksize;
! 2473: int rbus, pbus;
! 2474: u_int gain;
! 2475: u_char balance;
! 2476:
! 2477: if (hw == 0) /* HW has not attached */
! 2478: return(ENXIO);
! 2479:
! 2480: rbus = sc->sc_rbus;
! 2481: pbus = sc->sc_pbus;
! 2482: error = 0;
! 2483: cleared = 0;
! 2484:
! 2485: pp = sc->sc_pparams; /* Temporary encoding storage in */
! 2486: rp = sc->sc_rparams; /* case setting the modes fails. */
! 2487: nr = np = 0;
! 2488:
! 2489: if (p->sample_rate != ~0) {
! 2490: pp.sample_rate = p->sample_rate;
! 2491: np++;
! 2492: }
! 2493: if (r->sample_rate != ~0) {
! 2494: rp.sample_rate = r->sample_rate;
! 2495: nr++;
! 2496: }
! 2497: if (p->encoding != ~0) {
! 2498: pp.encoding = p->encoding;
! 2499: np++;
! 2500: }
! 2501: if (r->encoding != ~0) {
! 2502: rp.encoding = r->encoding;
! 2503: nr++;
! 2504: }
! 2505: if (p->precision != ~0) {
! 2506: pp.precision = p->precision;
! 2507: np++;
! 2508: }
! 2509: if (r->precision != ~0) {
! 2510: rp.precision = r->precision;
! 2511: nr++;
! 2512: }
! 2513: if (p->channels != ~0) {
! 2514: pp.channels = p->channels;
! 2515: np++;
! 2516: }
! 2517: if (r->channels != ~0) {
! 2518: rp.channels = r->channels;
! 2519: nr++;
! 2520: }
! 2521: #ifdef AUDIO_DEBUG
! 2522: if (audiodebug && nr)
! 2523: audio_print_params("Setting record params", &rp);
! 2524: if (audiodebug && np)
! 2525: audio_print_params("Setting play params", &pp);
! 2526: #endif
! 2527: if (nr && (error = audio_check_params(&rp)))
! 2528: return error;
! 2529: if (np && (error = audio_check_params(&pp)))
! 2530: return error;
! 2531: setmode = 0;
! 2532: if (nr) {
! 2533: if (!cleared)
! 2534: audio_clear(sc);
! 2535: modechange = cleared = 1;
! 2536: rp.sw_code = 0;
! 2537: rp.factor = 1;
! 2538: setmode |= AUMODE_RECORD;
! 2539: }
! 2540: if (np) {
! 2541: if (!cleared)
! 2542: audio_clear(sc);
! 2543: modechange = cleared = 1;
! 2544: pp.sw_code = 0;
! 2545: pp.factor = 1;
! 2546: setmode |= AUMODE_PLAY;
! 2547: }
! 2548:
! 2549: if (ai->mode != ~0) {
! 2550: if (!cleared)
! 2551: audio_clear(sc);
! 2552: modechange = cleared = 1;
! 2553: sc->sc_mode = ai->mode;
! 2554: if (sc->sc_mode & AUMODE_PLAY_ALL)
! 2555: sc->sc_mode |= AUMODE_PLAY;
! 2556: if ((sc->sc_mode & AUMODE_PLAY) && !sc->sc_full_duplex)
! 2557: /* Play takes precedence */
! 2558: sc->sc_mode &= ~AUMODE_RECORD;
! 2559: }
! 2560:
! 2561: if (modechange) {
! 2562: int indep = hw->get_props(sc->hw_hdl) & AUDIO_PROP_INDEPENDENT;
! 2563: if (!indep) {
! 2564: if (setmode == AUMODE_RECORD)
! 2565: pp = rp;
! 2566: else if (setmode == AUMODE_PLAY)
! 2567: rp = pp;
! 2568: }
! 2569: error = hw->set_params(sc->hw_hdl, setmode,
! 2570: sc->sc_mode & (AUMODE_PLAY | AUMODE_RECORD), &pp, &rp);
! 2571: if (error)
! 2572: return (error);
! 2573: if (!indep) {
! 2574: if (setmode == AUMODE_RECORD) {
! 2575: pp.sample_rate = rp.sample_rate;
! 2576: pp.encoding = rp.encoding;
! 2577: pp.channels = rp.channels;
! 2578: pp.precision = rp.precision;
! 2579: } else if (setmode == AUMODE_PLAY) {
! 2580: rp.sample_rate = pp.sample_rate;
! 2581: rp.encoding = pp.encoding;
! 2582: rp.channels = pp.channels;
! 2583: rp.precision = pp.precision;
! 2584: }
! 2585: }
! 2586: sc->sc_rparams = rp;
! 2587: sc->sc_pparams = pp;
! 2588: }
! 2589:
! 2590: oldpblksize = sc->sc_pr.blksize;
! 2591: oldrblksize = sc->sc_rr.blksize;
! 2592: /* Play params can affect the record params, so recalculate blksize. */
! 2593: if (nr || np) {
! 2594: audio_calc_blksize(sc, AUMODE_RECORD);
! 2595: audio_calc_blksize(sc, AUMODE_PLAY);
! 2596: }
! 2597: #ifdef AUDIO_DEBUG
! 2598: if (audiodebug > 1 && nr)
! 2599: audio_print_params("After setting record params", &sc->sc_rparams);
! 2600: if (audiodebug > 1 && np)
! 2601: audio_print_params("After setting play params", &sc->sc_pparams);
! 2602: #endif
! 2603:
! 2604: if (p->port != ~0) {
! 2605: if (!cleared)
! 2606: audio_clear(sc);
! 2607: cleared = 1;
! 2608:
! 2609: error = au_set_port(sc, &sc->sc_outports, p->port);
! 2610: if (error)
! 2611: return(error);
! 2612: }
! 2613: if (r->port != ~0) {
! 2614: if (!cleared)
! 2615: audio_clear(sc);
! 2616: cleared = 1;
! 2617:
! 2618: error = au_set_port(sc, &sc->sc_inports, r->port);
! 2619: if (error)
! 2620: return(error);
! 2621: }
! 2622: if (p->gain != ~0) {
! 2623: au_get_gain(sc, &sc->sc_outports, &gain, &balance);
! 2624: error = au_set_gain(sc, &sc->sc_outports, p->gain, balance);
! 2625: if (error)
! 2626: return(error);
! 2627: }
! 2628: if (r->gain != ~0) {
! 2629: au_get_gain(sc, &sc->sc_inports, &gain, &balance);
! 2630: error = au_set_gain(sc, &sc->sc_inports, r->gain, balance);
! 2631: if (error)
! 2632: return(error);
! 2633: }
! 2634:
! 2635: if (p->balance != (u_char)~0) {
! 2636: au_get_gain(sc, &sc->sc_outports, &gain, &balance);
! 2637: error = au_set_gain(sc, &sc->sc_outports, gain, p->balance);
! 2638: if (error)
! 2639: return(error);
! 2640: }
! 2641: if (r->balance != (u_char)~0) {
! 2642: au_get_gain(sc, &sc->sc_inports, &gain, &balance);
! 2643: error = au_set_gain(sc, &sc->sc_inports, gain, r->balance);
! 2644: if (error)
! 2645: return(error);
! 2646: }
! 2647:
! 2648: if (ai->monitor_gain != ~0 &&
! 2649: sc->sc_monitor_port != -1) {
! 2650: mixer_ctrl_t ct;
! 2651:
! 2652: ct.dev = sc->sc_monitor_port;
! 2653: ct.type = AUDIO_MIXER_VALUE;
! 2654: ct.un.value.num_channels = 1;
! 2655: ct.un.value.level[AUDIO_MIXER_LEVEL_MONO] = ai->monitor_gain;
! 2656: error = sc->hw_if->set_port(sc->hw_hdl, &ct);
! 2657: if (error)
! 2658: return(error);
! 2659: }
! 2660:
! 2661: if (ai->blocksize != ~0) {
! 2662: /* Block size specified explicitly. */
! 2663: if (!cleared)
! 2664: audio_clear(sc);
! 2665: cleared = 1;
! 2666:
! 2667: if (ai->blocksize == 0) {
! 2668: audio_calc_blksize(sc, AUMODE_RECORD);
! 2669: audio_calc_blksize(sc, AUMODE_PLAY);
! 2670: sc->sc_blkset = 0;
! 2671: } else {
! 2672: int rbs = ai->blocksize * sc->sc_rparams.factor;
! 2673: int pbs = ai->blocksize * sc->sc_pparams.factor;
! 2674: if (hw->round_blocksize) {
! 2675: rbs = hw->round_blocksize(sc->hw_hdl, rbs);
! 2676: pbs = hw->round_blocksize(sc->hw_hdl, pbs);
! 2677: }
! 2678: sc->sc_rr.blksize = rbs;
! 2679: sc->sc_pr.blksize = pbs;
! 2680: sc->sc_blkset = 1;
! 2681: }
! 2682: }
! 2683:
! 2684: if (ai->mode != ~0) {
! 2685: if (sc->sc_mode & AUMODE_PLAY)
! 2686: audio_init_play(sc);
! 2687: if (sc->sc_mode & AUMODE_RECORD)
! 2688: audio_init_record(sc);
! 2689: }
! 2690:
! 2691: if (hw->commit_settings) {
! 2692: error = hw->commit_settings(sc->hw_hdl);
! 2693: if (error)
! 2694: return (error);
! 2695: }
! 2696:
! 2697: if (cleared) {
! 2698: s = splaudio();
! 2699: error = audio_initbufs(sc);
! 2700: if (error) goto err;
! 2701: if (sc->sc_pr.blksize != oldpblksize ||
! 2702: sc->sc_rr.blksize != oldrblksize)
! 2703: audio_calcwater(sc);
! 2704: if ((sc->sc_mode & AUMODE_PLAY) &&
! 2705: pbus && !sc->sc_pbus && !sc->sc_pr.pause)
! 2706: error = audiostartp(sc);
! 2707: if (!error &&
! 2708: (sc->sc_mode & AUMODE_RECORD) &&
! 2709: rbus && !sc->sc_rbus && !sc->sc_rr.pause)
! 2710: error = audiostartr(sc);
! 2711: err:
! 2712: splx(s);
! 2713: if (error)
! 2714: return error;
! 2715: }
! 2716:
! 2717: /* Change water marks after initializing the buffers. */
! 2718: if (ai->hiwat != ~0) {
! 2719: blks = ai->hiwat;
! 2720: if (blks > sc->sc_pr.maxblks)
! 2721: blks = sc->sc_pr.maxblks;
! 2722: if (blks < 2)
! 2723: blks = 2;
! 2724: sc->sc_pr.usedhigh = blks * sc->sc_pr.blksize;
! 2725: }
! 2726: if (ai->lowat != ~0) {
! 2727: blks = ai->lowat;
! 2728: if (blks > sc->sc_pr.maxblks - 1)
! 2729: blks = sc->sc_pr.maxblks - 1;
! 2730: sc->sc_pr.usedlow = blks * sc->sc_pr.blksize;
! 2731: }
! 2732: if (ai->hiwat != ~0 || ai->lowat != ~0) {
! 2733: if (sc->sc_pr.usedlow > sc->sc_pr.usedhigh - sc->sc_pr.blksize)
! 2734: sc->sc_pr.usedlow = sc->sc_pr.usedhigh - sc->sc_pr.blksize;
! 2735: }
! 2736:
! 2737: if (p->pause != (u_char)~0) {
! 2738: sc->sc_pr.pause = p->pause;
! 2739: if (!p->pause && !sc->sc_pbus && (sc->sc_mode & AUMODE_PLAY)) {
! 2740: s = splaudio();
! 2741: error = audiostartp(sc);
! 2742: splx(s);
! 2743: if (error)
! 2744: return error;
! 2745: }
! 2746: }
! 2747: if (r->pause != (u_char)~0) {
! 2748: sc->sc_rr.pause = r->pause;
! 2749: if (!r->pause && !sc->sc_rbus && (sc->sc_mode & AUMODE_RECORD)) {
! 2750: s = splaudio();
! 2751: error = audiostartr(sc);
! 2752: splx(s);
! 2753: if (error)
! 2754: return error;
! 2755: }
! 2756: }
! 2757:
! 2758: return (0);
! 2759: }
! 2760:
! 2761: int
! 2762: audiogetinfo(struct audio_softc *sc, struct audio_info *ai)
! 2763: {
! 2764: struct audio_prinfo *r = &ai->record, *p = &ai->play;
! 2765: struct audio_hw_if *hw = sc->hw_if;
! 2766:
! 2767: if (hw == 0) /* HW has not attached */
! 2768: return(ENXIO);
! 2769:
! 2770: p->sample_rate = sc->sc_pparams.sample_rate;
! 2771: r->sample_rate = sc->sc_rparams.sample_rate;
! 2772: p->channels = sc->sc_pparams.channels;
! 2773: r->channels = sc->sc_rparams.channels;
! 2774: p->precision = sc->sc_pparams.precision;
! 2775: r->precision = sc->sc_rparams.precision;
! 2776: p->encoding = sc->sc_pparams.encoding;
! 2777: r->encoding = sc->sc_rparams.encoding;
! 2778:
! 2779: r->port = au_get_port(sc, &sc->sc_inports);
! 2780: p->port = au_get_port(sc, &sc->sc_outports);
! 2781:
! 2782: r->avail_ports = sc->sc_inports.allports;
! 2783: p->avail_ports = sc->sc_outports.allports;
! 2784:
! 2785: au_get_gain(sc, &sc->sc_inports, &r->gain, &r->balance);
! 2786: au_get_gain(sc, &sc->sc_outports, &p->gain, &p->balance);
! 2787:
! 2788: if (sc->sc_monitor_port != -1) {
! 2789: mixer_ctrl_t ct;
! 2790:
! 2791: ct.dev = sc->sc_monitor_port;
! 2792: ct.type = AUDIO_MIXER_VALUE;
! 2793: ct.un.value.num_channels = 1;
! 2794: if (sc->hw_if->get_port(sc->hw_hdl, &ct))
! 2795: ai->monitor_gain = 0;
! 2796: else
! 2797: ai->monitor_gain =
! 2798: ct.un.value.level[AUDIO_MIXER_LEVEL_MONO];
! 2799: } else
! 2800: ai->monitor_gain = 0;
! 2801:
! 2802: p->seek = sc->sc_pr.used / sc->sc_pparams.factor;
! 2803: r->seek = sc->sc_rr.used / sc->sc_rparams.factor;
! 2804:
! 2805: p->samples = sc->sc_pr.stamp - sc->sc_pr.drops;
! 2806: r->samples = sc->sc_rr.stamp - sc->sc_rr.drops;
! 2807:
! 2808: p->eof = sc->sc_eof;
! 2809: r->eof = 0;
! 2810:
! 2811: p->pause = sc->sc_pr.pause;
! 2812: r->pause = sc->sc_rr.pause;
! 2813:
! 2814: p->error = sc->sc_pr.drops != 0;
! 2815: r->error = sc->sc_rr.drops != 0;
! 2816:
! 2817: p->waiting = r->waiting = 0; /* open never hangs */
! 2818:
! 2819: p->open = (sc->sc_open & AUOPEN_WRITE) != 0;
! 2820: r->open = (sc->sc_open & AUOPEN_READ) != 0;
! 2821:
! 2822: p->active = sc->sc_pbus;
! 2823: r->active = sc->sc_rbus;
! 2824:
! 2825: p->buffer_size = sc->sc_pr.bufsize / sc->sc_pparams.factor;
! 2826: r->buffer_size = sc->sc_rr.bufsize / sc->sc_rparams.factor;
! 2827:
! 2828: if ((ai->blocksize = sc->sc_pr.blksize / sc->sc_pparams.factor) != 0) {
! 2829: ai->hiwat = sc->sc_pr.usedhigh / sc->sc_pr.blksize;
! 2830: ai->lowat = sc->sc_pr.usedlow / sc->sc_pr.blksize;
! 2831: } else {
! 2832: ai->hiwat = ai->lowat = 0;
! 2833: }
! 2834: ai->mode = sc->sc_mode;
! 2835:
! 2836: return (0);
! 2837: }
! 2838:
! 2839: /*
! 2840: * Mixer driver
! 2841: */
! 2842: int
! 2843: mixer_open(dev_t dev, struct audio_softc *sc, int flags, int ifmt,
! 2844: struct proc *p)
! 2845: {
! 2846: DPRINTF(("mixer_open: dev=0x%x flags=0x%x sc=%p\n", dev, flags, sc));
! 2847:
! 2848: return (0);
! 2849: }
! 2850:
! 2851: /*
! 2852: * Remove a process from those to be signalled on mixer activity.
! 2853: */
! 2854: static void
! 2855: mixer_remove(struct audio_softc *sc, struct proc *p)
! 2856: {
! 2857: struct mixer_asyncs **pm, *m;
! 2858:
! 2859: for(pm = &sc->sc_async_mixer; *pm; pm = &(*pm)->next) {
! 2860: if ((*pm)->proc == p) {
! 2861: m = *pm;
! 2862: *pm = m->next;
! 2863: free(m, M_DEVBUF);
! 2864: return;
! 2865: }
! 2866: }
! 2867: }
! 2868:
! 2869: /*
! 2870: * Signal all processes waitinf for the mixer.
! 2871: */
! 2872: static void
! 2873: mixer_signal(struct audio_softc *sc)
! 2874: {
! 2875: struct mixer_asyncs *m;
! 2876:
! 2877: for(m = sc->sc_async_mixer; m; m = m->next)
! 2878: psignal(m->proc, SIGIO);
! 2879: }
! 2880:
! 2881: /*
! 2882: * Close a mixer device
! 2883: */
! 2884: /* ARGSUSED */
! 2885: int
! 2886: mixer_close(dev_t dev, int flags, int ifmt, struct proc *p)
! 2887: {
! 2888: int unit = AUDIOUNIT(dev);
! 2889: struct audio_softc *sc = audio_cd.cd_devs[unit];
! 2890:
! 2891: DPRINTF(("mixer_close: unit %d\n", AUDIOUNIT(dev)));
! 2892:
! 2893: mixer_remove(sc, p);
! 2894:
! 2895: return (0);
! 2896: }
! 2897:
! 2898: int
! 2899: mixer_ioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
! 2900: {
! 2901: int unit = AUDIOUNIT(dev);
! 2902: struct audio_softc *sc = audio_cd.cd_devs[unit];
! 2903: struct audio_hw_if *hw = sc->hw_if;
! 2904: int error = EINVAL;
! 2905:
! 2906: DPRINTF(("mixer_ioctl(%d,'%c',%d)\n",
! 2907: IOCPARM_LEN(cmd), IOCGROUP(cmd), cmd&0xff));
! 2908:
! 2909: switch (cmd) {
! 2910: case FIOASYNC:
! 2911: mixer_remove(sc, p); /* remove old entry */
! 2912: if (*(int *)addr) {
! 2913: struct mixer_asyncs *ma;
! 2914: ma = malloc(sizeof (struct mixer_asyncs),
! 2915: M_DEVBUF, M_WAITOK);
! 2916: ma->next = sc->sc_async_mixer;
! 2917: ma->proc = p;
! 2918: sc->sc_async_mixer = ma;
! 2919: }
! 2920: error = 0;
! 2921: break;
! 2922:
! 2923: case AUDIO_GETDEV:
! 2924: DPRINTF(("AUDIO_GETDEV\n"));
! 2925: error = hw->getdev(sc->hw_hdl, (audio_device_t *)addr);
! 2926: break;
! 2927:
! 2928: case AUDIO_MIXER_DEVINFO:
! 2929: DPRINTF(("AUDIO_MIXER_DEVINFO\n"));
! 2930: ((mixer_devinfo_t *)addr)->un.v.delta = 0; /* default */
! 2931: error = hw->query_devinfo(sc->hw_hdl, (mixer_devinfo_t *)addr);
! 2932: break;
! 2933:
! 2934: case AUDIO_MIXER_READ:
! 2935: DPRINTF(("AUDIO_MIXER_READ\n"));
! 2936: error = hw->get_port(sc->hw_hdl, (mixer_ctrl_t *)addr);
! 2937: break;
! 2938:
! 2939: case AUDIO_MIXER_WRITE:
! 2940: if (!(flag & FWRITE))
! 2941: return (EACCES);
! 2942: DPRINTF(("AUDIO_MIXER_WRITE\n"));
! 2943: error = hw->set_port(sc->hw_hdl, (mixer_ctrl_t *)addr);
! 2944: if (!error && hw->commit_settings)
! 2945: error = hw->commit_settings(sc->hw_hdl);
! 2946: if (!error)
! 2947: mixer_signal(sc);
! 2948: break;
! 2949:
! 2950: default:
! 2951: error = ENOTTY;
! 2952: break;
! 2953: }
! 2954: DPRINTF(("mixer_ioctl(%d,'%c',%d) result %d\n",
! 2955: IOCPARM_LEN(cmd), IOCGROUP(cmd), cmd&0xff, error));
! 2956: return (error);
! 2957: }
! 2958: #endif
! 2959:
! 2960: int
! 2961: audiokqfilter(dev_t dev, struct knote *kn)
! 2962: {
! 2963: int unit = AUDIOUNIT(dev);
! 2964: struct audio_softc *sc = audio_cd.cd_devs[unit];
! 2965: struct klist *klist;
! 2966: int s;
! 2967:
! 2968: switch (kn->kn_filter) {
! 2969: case EVFILT_READ:
! 2970: klist = &sc->sc_rsel.si_note;
! 2971: kn->kn_fop = &audioread_filtops;
! 2972: break;
! 2973: case EVFILT_WRITE:
! 2974: klist = &sc->sc_wsel.si_note;
! 2975: kn->kn_fop = &audiowrite_filtops;
! 2976: break;
! 2977: default:
! 2978: return (1);
! 2979: }
! 2980: kn->kn_hook = (void *)sc;
! 2981:
! 2982: s = splaudio();
! 2983: SLIST_INSERT_HEAD(klist, kn, kn_selnext);
! 2984: splx(s);
! 2985:
! 2986: return (0);
! 2987: }
! 2988:
! 2989: void
! 2990: filt_audiordetach(struct knote *kn)
! 2991: {
! 2992: struct audio_softc *sc = (struct audio_softc *)kn->kn_hook;
! 2993: int s = splaudio();
! 2994:
! 2995: SLIST_REMOVE(&sc->sc_rsel.si_note, kn, knote, kn_selnext);
! 2996: splx(s);
! 2997: }
! 2998:
! 2999: int
! 3000: filt_audioread(struct knote *kn, long hint)
! 3001: {
! 3002: struct audio_softc *sc = (struct audio_softc *)kn->kn_hook;
! 3003:
! 3004: return AUDIO_FILTREAD(sc);
! 3005: }
! 3006:
! 3007: void
! 3008: filt_audiowdetach(struct knote *kn)
! 3009: {
! 3010: struct audio_softc *sc = (struct audio_softc *)kn->kn_hook;
! 3011: int s = splaudio();
! 3012:
! 3013: SLIST_REMOVE(&sc->sc_wsel.si_note, kn, knote, kn_selnext);
! 3014: splx(s);
! 3015: }
! 3016:
! 3017: int
! 3018: filt_audiowrite(struct knote *kn, long hint)
! 3019: {
! 3020: struct audio_softc *sc = (struct audio_softc *)kn->kn_hook;
! 3021:
! 3022: return AUDIO_FILTWRITE(sc);
! 3023: }
! 3024:
! 3025: #if NAUDIO > 0 && NWSKBD > 0
! 3026: int
! 3027: wskbd_get_mixerdev(struct audio_softc *sc, int dir, int *index)
! 3028: {
! 3029: mixer_devinfo_t mi;
! 3030: int mixer_class;
! 3031: int error;
! 3032:
! 3033: /* looking for ``outputs'' */
! 3034: for (mi.index = 0; ; mi.index++) {
! 3035: error = sc->hw_if->query_devinfo(sc->hw_hdl, &mi);
! 3036: if (error != 0)
! 3037: return (-1);
! 3038:
! 3039: if (mi.type == AUDIO_MIXER_CLASS &&
! 3040: strcmp(mi.label.name, AudioCoutputs) == 0) {
! 3041: mixer_class = mi.mixer_class;
! 3042: break;
! 3043: }
! 3044: }
! 3045:
! 3046: /*
! 3047: * looking for ``outputs.master''
! 3048: * start mi.index from 0 because ''outputs.master'' can precede
! 3049: * ''outputs''.
! 3050: */
! 3051: for (mi.index = 0; ; mi.index++) {
! 3052: error = sc->hw_if->query_devinfo(sc->hw_hdl, &mi);
! 3053: if (error != 0)
! 3054: return (-1);
! 3055:
! 3056: if (mi.type == AUDIO_MIXER_VALUE &&
! 3057: mi.mixer_class == mixer_class &&
! 3058: strcmp(mi.label.name, AudioNmaster) == 0) {
! 3059: if (dir == 0) {
! 3060: /* looking for ``outputs.master.mute'' */
! 3061: if (mi.next < 0)
! 3062: return (-1);
! 3063:
! 3064: mi.index = mi.next;
! 3065: error = sc->hw_if->query_devinfo(sc->hw_hdl,
! 3066: &mi);
! 3067: if (error != 0)
! 3068: return (-1);
! 3069:
! 3070: if (mi.type != AUDIO_MIXER_ENUM ||
! 3071: strcmp(mi.label.name, AudioNmute) != 0)
! 3072: return (-1);
! 3073: }
! 3074:
! 3075: *index = mi.index;
! 3076: return (0);
! 3077: }
! 3078: }
! 3079:
! 3080: return (-1);
! 3081: }
! 3082:
! 3083: int
! 3084: wskbd_set_mixervolume(long dir)
! 3085: {
! 3086: struct audio_softc *sc;
! 3087: mixer_devinfo_t mi;
! 3088: mixer_ctrl_t ct;
! 3089: int l, r;
! 3090: int error;
! 3091:
! 3092: if (audio_cd.cd_ndevs == 0 || (sc = audio_cd.cd_devs[0]) == NULL) {
! 3093: DPRINTF(("wskbd_set_mixervolume: audio_cd\n"));
! 3094: return (ENXIO);
! 3095: }
! 3096:
! 3097: error = wskbd_get_mixerdev(sc, dir, &ct.dev);
! 3098: if (error == -1) {
! 3099: DPRINTF(("wskbd_set_mixervolume: wskbd_get_mixerdev\n"));
! 3100: return (ENXIO);
! 3101: }
! 3102:
! 3103: if (dir == 0) {
! 3104: /*
! 3105: * Mute.
! 3106: * Use mixer_ioctl() for writing. It does many things for us.
! 3107: */
! 3108: ct.type = AUDIO_MIXER_ENUM;
! 3109: error = sc->hw_if->get_port(sc->hw_hdl, &ct);
! 3110: if (error != 0) {
! 3111: DPRINTF(("wskbd_set_mixervolume:"
! 3112: " get_port: %d\n", error));
! 3113: return (error);
! 3114: }
! 3115:
! 3116: ct.un.ord = !ct.un.ord; /* toggle */
! 3117:
! 3118: error = mixer_ioctl(MIXER_DEVICE,
! 3119: AUDIO_MIXER_WRITE, (caddr_t)&ct, FWRITE, curproc);
! 3120: if (error != 0) {
! 3121: DPRINTF(("wskbd_set_mixervolume:"
! 3122: " mixer_ioctl: %d\n", error));
! 3123: return (error);
! 3124: }
! 3125: } else {
! 3126: mi.index = ct.dev;
! 3127: error = sc->hw_if->query_devinfo(sc->hw_hdl, &mi);
! 3128: if (error != 0) {
! 3129: DPRINTF(("wskbd_set_mixervolume:"
! 3130: " query_devinfo: %d\n", error));
! 3131: return (error);
! 3132: }
! 3133:
! 3134: ct.type = AUDIO_MIXER_VALUE;
! 3135:
! 3136: error = au_get_lr_value(sc, &ct, &l, &r);
! 3137: if (error != 0) {
! 3138: DPRINTF(("wskbd_set_mixervolume:"
! 3139: " au_get_lr_value: %d\n", error));
! 3140: return (error);
! 3141: }
! 3142:
! 3143: if (dir > 0) {
! 3144: /*
! 3145: * Raise volume
! 3146: */
! 3147: if (l > AUDIO_MAX_GAIN - mi.un.v.delta)
! 3148: l = AUDIO_MAX_GAIN;
! 3149: else
! 3150: l += mi.un.v.delta;
! 3151:
! 3152: if (r > AUDIO_MAX_GAIN - mi.un.v.delta)
! 3153: r = AUDIO_MAX_GAIN;
! 3154: else
! 3155: r += mi.un.v.delta;
! 3156:
! 3157: } else {
! 3158: /*
! 3159: * Lower volume
! 3160: */
! 3161: if (l < AUDIO_MIN_GAIN + mi.un.v.delta)
! 3162: l = AUDIO_MIN_GAIN;
! 3163: else
! 3164: l -= mi.un.v.delta;
! 3165:
! 3166: if (r < AUDIO_MIN_GAIN + mi.un.v.delta)
! 3167: r = AUDIO_MIN_GAIN;
! 3168: else
! 3169: r -= mi.un.v.delta;
! 3170: }
! 3171:
! 3172: error = au_set_lr_value(sc, &ct, l, r);
! 3173: if (error != 0) {
! 3174: DPRINTF(("wskbd_set_mixervolume:"
! 3175: " au_set_lr_value: %d\n", error));
! 3176: return (error);
! 3177: }
! 3178: }
! 3179:
! 3180: return (0);
! 3181: }
! 3182: #endif /* NAUDIO > 0 && NWSKBD > 0 */
CVSweb