📄 bsd_audio.c
字号:
register int error; while (!AUCB_EMPTY(&sc->sc_au.au_wb)) if ((error = audio_sleep(&sc->sc_au.au_wb, 0)) != 0) return (error); return (0);}/* * Close an audio chip. *//* ARGSUSED */intAUDIOCLOSE(dev, flags, ifmt, p){ register struct audio_softc *sc = SOFTC(dev); register volatile struct amd7930 *amd; register struct aucb *cb; register int s; /* * Block until output drains, but allow ^C interrupt. */ sc->sc_au.au_lowat = 0; /* avoid excessive wakeups */ s = splaudio(); /* * If there is pending output, let it drain (unless * the output is paused). */ cb = &sc->sc_au.au_wb; if (!AUCB_EMPTY(cb) && !cb->cb_pause) (void)audio_drain(sc); /* * Disable interrupts, clear open flag, and done. */ amd = sc->sc_au.au_amd; amd->cr = AMDR_INIT; amd->dr = AMD_INIT_PMS_ACTIVE | AMD_INIT_INT_DISABLE; splx(s); sc->sc_open = 0; return (0);}intaudio_sleep(cb, thresh) register struct aucb *cb; register int thresh;{ register int error; register int s = splaudio(); cb->cb_thresh = thresh; error = tsleep((caddr_t)cb, (PZERO + 1) | PCATCH, "audio", 0); splx(s); return (error);}/* ARGSUSED */intAUDIOREAD(dev, uio, ioflag){ register struct audio_softc *sc = SOFTC(dev); register struct aucb *cb; register int n, head, taildata, error; register int blocksize = sc->sc_au.au_blksize; if (uio->uio_resid == 0) return (0); cb = &sc->sc_au.au_rb; error = 0; cb->cb_drops = 0; sc->sc_rseek = sc->sc_au.au_stamp - AUCB_LEN(cb); do { while (AUCB_LEN(cb) < blocksize) {#ifndef SUNOS if (ioflag & IO_NDELAY) { error = EWOULDBLOCK; return (error); }#endif if ((error = audio_sleep(cb, blocksize)) != 0) return (error); } /* * The space calculation can only err on the short * side if an interrupt occurs during processing: * only cb_tail is altered in the interrupt code. */ head = cb->cb_head; if ((n = AUCB_LEN(cb)) > uio->uio_resid) n = uio->uio_resid; taildata = AUCB_SIZE - head; if (n > taildata) { error = UIOMOVE((caddr_t)cb->cb_data + head, taildata, UIO_READ, uio); if (error == 0) error = UIOMOVE((caddr_t)cb->cb_data, n - taildata, UIO_READ, uio); } else error = UIOMOVE((caddr_t)cb->cb_data + head, n, UIO_READ, uio); if (error) break; head = AUCB_MOD(head + n); cb->cb_head = head; } while (uio->uio_resid >= blocksize); return (error);}/* ARGSUSED */intAUDIOWRITE(dev, uio, ioflag){ register struct audio_softc *sc = SOFTC(dev); register struct aucb *cb = &sc->sc_au.au_wb; register int n, tail, tailspace, error, first, watermark; error = 0; first = 1; while (uio->uio_resid > 0) { watermark = sc->sc_au.au_hiwat; while (AUCB_LEN(cb) > watermark) {#ifndef SUNOS if (ioflag & IO_NDELAY) { error = EWOULDBLOCK; return (error); }#endif if ((error = audio_sleep(cb, watermark)) != 0) return (error); watermark = sc->sc_au.au_lowat; } /* * The only value that can change on an interrupt is * cb->cb_head. We only pull that out once to decide * how much to write into cb_data; if we lose a race * and cb_head changes, we will merely be overly * conservative. For a legitimate time stamp, * however, we need to synchronize the accesses to * au_stamp and cb_head at a high ipl below. */ tail = cb->cb_tail; if ((n = (AUCB_SIZE - 1) - AUCB_LEN(cb)) > uio->uio_resid) { n = uio->uio_resid; if (cb->cb_head == tail && n <= sc->sc_au.au_blksize && sc->sc_au.au_stamp - sc->sc_wseek > 400) { /* * the write is 'small', the buffer is empty * and we have been silent for at least 50ms * so we might be dealing with an application * that writes frames synchronously with * reading them. If so, we need an output * backlog to cover scheduling delays or * there will be gaps in the sound output. * Also take this opportunity to reset the * buffer pointers in case we ended up on * a bad boundary (odd byte, blksize bytes * from end, etc.). */ register u_int* ip; register int muzero = 0x7f7f7f7f; register int i = splaudio(); cb->cb_head = cb->cb_tail = 0; splx(i); tail = sc->sc_au.au_backlog; ip = (u_int*)cb->cb_data; for (i = tail >> 2; --i >= 0; ) *ip++ = muzero; } } tailspace = AUCB_SIZE - tail; if (n > tailspace) { /* write first part at tail and rest at head */ error = UIOMOVE((caddr_t)cb->cb_data + tail, tailspace, UIO_WRITE, uio); if (error == 0) error = UIOMOVE((caddr_t)cb->cb_data, n - tailspace, UIO_WRITE, uio); } else error = UIOMOVE((caddr_t)cb->cb_data + tail, n, UIO_WRITE, uio); if (error) break; tail = AUCB_MOD(tail + n); if (first) { register int s = splaudio(); sc->sc_wseek = AUCB_LEN(cb) + sc->sc_au.au_stamp + 1; /* * To guarantee that a write is contiguous in the * sample space, we clear the drop count the first * time through. If we later get drops, we will * break out of the loop below, before writing * a new frame. */ cb->cb_drops = 0; cb->cb_tail = tail; splx(s); first = 0; } else { if (cb->cb_drops != 0) break; cb->cb_tail = tail; } } return (error);}/* Sun audio compatibility */struct sun_audio_prinfo { u_int sample_rate; u_int channels; u_int precision; u_int encoding; u_int gain; u_int port; u_int reserved0[4]; u_int samples; u_int eof; u_char pause; u_char error; u_char waiting; u_char reserved1[3]; u_char open; u_char active;};struct sun_audio_info { struct sun_audio_prinfo play; struct sun_audio_prinfo record; u_int monitor_gain; u_int reserved[4];};#ifndef SUNOS#define SUNAUDIO_GETINFO _IOR('A', 1, struct sun_audio_info)#define SUNAUDIO_SETINFO _IOWR('A', 2, struct sun_audio_info)#else#define SUNAUDIO_GETINFO _IOR(A, 1, struct sun_audio_info)#define SUNAUDIO_SETINFO _IOWR(A, 2, struct sun_audio_info)#endif/* ARGSUSED */intAUDIOIOCTL(dev, cmd, addr, flag, p){ register struct audio_softc *sc = SOFTC(dev); int error = 0, s; switch (cmd) { case AUDIO_GETMAP: bcopy((caddr_t)&sc->sc_map, addr, sizeof(sc->sc_map)); break; case AUDIO_SETMAP: bcopy(addr, (caddr_t)&sc->sc_map, sizeof(sc->sc_map)); sc->sc_map.mr_mmr2 &= 0x7f; audio_setmap(sc->sc_au.au_amd, &sc->sc_map); break; case AUDIO_FLUSH: s = splaudio(); AUCB_INIT(&sc->sc_au.au_rb); AUCB_INIT(&sc->sc_au.au_wb); sc->sc_au.au_stamp = 0; splx(s); sc->sc_wseek = 0; sc->sc_rseek = 0; break; /* * Number of read samples dropped. We don't know where or * when they were dropped. */ case AUDIO_RERROR: *(int *)addr = sc->sc_au.au_rb.cb_drops != 0; break; /* * How many samples will elapse until mike hears the first * sample of what we last wrote? */ case AUDIO_WSEEK: s = splaudio(); *(u_long *)addr = sc->sc_wseek - sc->sc_au.au_stamp + AUCB_LEN(&sc->sc_au.au_rb); splx(s); break; case AUDIO_SETINFO: error = audiosetinfo(sc, (struct audio_info *)addr); break; case AUDIO_GETINFO: error = audiogetinfo(sc, (struct audio_info *)addr); break; case SUNAUDIO_GETINFO: error = sunaudiogetinfo(sc, (struct sun_audio_info *)addr); break; case SUNAUDIO_SETINFO: error = sunaudiosetinfo(sc, (struct sun_audio_info *)addr); break; case AUDIO_DRAIN: error = audio_drain(sc); break; default: error = EINVAL; break; } return (error);}/* ARGSUSED */intAUDIOSELECT(dev, rw, p){ register struct audio_softc *sc = SOFTC(dev); register struct aucb *cb; register int s = splaudio(); switch (rw) { case FREAD: cb = &sc->sc_au.au_rb; if (AUCB_LEN(cb) >= sc->sc_au.au_blksize) { splx(s); return (1); } selrecord(p, &sc->sc_rsel); cb->cb_thresh = sc->sc_au.au_blksize; break; case FWRITE: cb = &sc->sc_au.au_wb; if (AUCB_LEN(cb) <= sc->sc_au.au_lowat) { splx(s); return (1); } selrecord(p, &sc->sc_wsel); cb->cb_thresh = sc->sc_au.au_lowat; break; } splx(s); return (0);}#ifdef AUDIO_C_HANDLERintaudiohwintr(au0) void *au0;{#ifdef SUNOS register struct auio *au = audio_au;#else register struct auio *au = au0;#endif register volatile struct amd7930 *amd = au->au_amd; register struct aucb *cb; register int h, t, k; k = amd->ir; /* clear interrupt */ ++au->au_stamp; /* receive incoming data */ cb = &au->au_rb; h = cb->cb_head; t = cb->cb_tail; k = AUCB_MOD(t + 1); if (h == k) cb->cb_drops++; else if (cb->cb_pause != 0) cb->cb_pdrops++; else { cb->cb_data[t] = amd->bbrb; cb->cb_tail = t = k; } if (AUCB_MOD(t - h) >= cb->cb_thresh) { cb->cb_thresh = AUCB_SIZE; cb->cb_waking = 1; AUDIO_SET_SWINTR; } /* send outgoing data */ cb = &au->au_wb; h = cb->cb_head; t = cb->cb_tail; if (h == t) cb->cb_drops++; else if (cb->cb_pause != 0) cb->cb_pdrops++; else { cb->cb_head = h = AUCB_MOD(h + 1); amd->bbtb = cb->cb_data[h]; } if (AUCB_MOD(t - h) <= cb->cb_thresh) { cb->cb_thresh = -1; cb->cb_waking = 1; AUDIO_SET_SWINTR;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -