diff options
author | Jacob Meuser <jakemsr@cvs.openbsd.org> | 2009-11-26 15:45:26 +0000 |
---|---|---|
committer | Jacob Meuser <jakemsr@cvs.openbsd.org> | 2009-11-26 15:45:26 +0000 |
commit | 2eab2dc813ec882e57aabd5f2c91e77135447adb (patch) | |
tree | 341e2e4a6b469896917694941916a1ca4df61261 | |
parent | ad412571972769ea82e0ed7f2db6ad03b4bf44da (diff) |
allow USB xfer requests to use up to 16 frames per xfer, depending on
blocksize
-rw-r--r-- | sys/dev/usb/uaudio.c | 91 |
1 files changed, 67 insertions, 24 deletions
diff --git a/sys/dev/usb/uaudio.c b/sys/dev/usb/uaudio.c index 0fe4051a95d..e818abb1047 100644 --- a/sys/dev/usb/uaudio.c +++ b/sys/dev/usb/uaudio.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uaudio.c,v 1.69 2009/11/26 15:34:15 jakemsr Exp $ */ +/* $OpenBSD: uaudio.c,v 1.70 2009/11/26 15:45:25 jakemsr Exp $ */ /* $NetBSD: uaudio.c,v 1.90 2004/10/29 17:12:53 kent Exp $ */ /* @@ -76,7 +76,8 @@ int uaudiodebug = 0; #endif #define UAUDIO_NCHANBUFS 3 /* number of outstanding request */ -#define UAUDIO_NFRAMES 2 /* ms of sound in each request */ +#define UAUDIO_MIN_FRAMES 2 /* ms of sound in each request */ +#define UAUDIO_MAX_FRAMES 16 #define UAUDIO_MAX_ALTS 32 /* max alt settings allowed by driver */ @@ -127,6 +128,9 @@ struct chan { u_int fraction; /* fraction/1000 is the extra samples/frame */ u_int residue; /* accumulates the fractional samples */ u_int nframes; /* # of frames per transfer */ + u_int usb_fps; + u_int maxpktsize; + u_int reqms; /* usb request data duration, in ms */ u_char *start; /* upper layer buffer start */ u_char *end; /* upper layer buffer end */ @@ -141,8 +145,8 @@ struct chan { struct chan *chan; usbd_xfer_handle xfer; u_char *buffer; - u_int16_t sizes[UAUDIO_NFRAMES]; - u_int16_t offsets[UAUDIO_NFRAMES]; + u_int16_t sizes[UAUDIO_MAX_FRAMES]; + u_int16_t offsets[UAUDIO_MAX_FRAMES]; u_int16_t size; } chanbufs[UAUDIO_NCHANBUFS]; @@ -483,10 +487,14 @@ int uaudio_detach(struct device *self, int flags) { struct uaudio_softc *sc = (struct uaudio_softc *)self; - int rv = 0; + struct chan *pchan = &sc->sc_playchan; + struct chan *rchan = &sc->sc_recchan; + int ms, rv = 0; /* Wait for outstanding requests to complete. */ - usbd_delay_ms(sc->sc_udev, UAUDIO_NCHANBUFS * UAUDIO_NFRAMES); + ms = max(sc->sc_alts[pchan->altidx].sc_busy ? pchan->reqms : 0, + sc->sc_alts[rchan->altidx].sc_busy ? rchan->reqms : 0); + usbd_delay_ms(sc->sc_udev, UAUDIO_NCHANBUFS * ms); if (sc->sc_audiodev != NULL) rv = config_detach(sc->sc_audiodev, flags); @@ -2088,8 +2096,14 @@ int uaudio_drain(void *addr) { struct uaudio_softc *sc = addr; + struct chan *pchan = &sc->sc_playchan; + struct chan *rchan = &sc->sc_recchan; + int ms; - usbd_delay_ms(sc->sc_udev, UAUDIO_NCHANBUFS * UAUDIO_NFRAMES); + /* Wait for outstanding requests to complete. */ + ms = max(sc->sc_alts[pchan->altidx].sc_busy ? pchan->reqms : 0, + sc->sc_alts[rchan->altidx].sc_busy ? rchan->reqms : 0); + usbd_delay_ms(sc->sc_udev, UAUDIO_NCHANBUFS * ms); return (0); } @@ -2694,10 +2708,10 @@ uaudio_chan_ptransfer(struct chan *ch) for (i = 0; i < ch->nframes; i++) { size = ch->bytes_per_frame; residue += ch->fraction; - if (residue >= USB_FRAMES_PER_SECOND) { + if (residue >= ch->usb_fps) { if ((ch->sc->sc_altflags & UA_NOFRAC) == 0) size += ch->sample_size; - residue -= USB_FRAMES_PER_SECOND; + residue -= ch->usb_fps; } cb->sizes[i] = size; total += size; @@ -2896,24 +2910,31 @@ void uaudio_chan_init(struct chan *ch, int altidx, const struct audio_params *param, int maxpktsize) { - int samples_per_frame, sample_size; + int samples_per_frame; ch->altidx = altidx; - sample_size = param->precision * param->factor * param->channels / 8; - samples_per_frame = param->sample_rate / USB_FRAMES_PER_SECOND; - ch->sample_size = sample_size; + ch->maxpktsize = maxpktsize; ch->sample_rate = param->sample_rate; - if (maxpktsize == 0) { - ch->fraction = param->sample_rate % USB_FRAMES_PER_SECOND; - ch->bytes_per_frame = samples_per_frame * sample_size; - ch->nframes = UAUDIO_NFRAMES; + ch->sample_size = param->factor * param->channels * + param->precision / NBBY; + ch->usb_fps = USB_FRAMES_PER_SECOND; + + /* + * Use UAUDIO_MIN_FRAMES here, so uaudio_round_blocksize() can + * make sure the blocksize duration will be > 1 USB frame. + */ + samples_per_frame = ch->sample_rate / ch->usb_fps; + if (ch->maxpktsize == 0) { + ch->fraction = ch->sample_rate % ch->usb_fps; + ch->bytes_per_frame = samples_per_frame * ch->sample_size; + ch->nframes = UAUDIO_MIN_FRAMES; } else { ch->fraction = 0; - ch->bytes_per_frame = maxpktsize; - ch->nframes = UAUDIO_NFRAMES * samples_per_frame * - sample_size / maxpktsize; - if (ch->nframes > UAUDIO_NFRAMES) - ch->nframes = UAUDIO_NFRAMES; + ch->bytes_per_frame = ch->maxpktsize; + ch->nframes = UAUDIO_MIN_FRAMES * samples_per_frame * + ch->sample_size / ch->maxpktsize; + if (ch->nframes > UAUDIO_MAX_FRAMES) + ch->nframes = UAUDIO_MAX_FRAMES; else if (ch->nframes < 1) ch->nframes = 1; } @@ -2926,10 +2947,32 @@ uaudio_chan_set_param(struct chan *ch, u_char *start, u_char *end, int blksize) ch->start = start; ch->end = end; ch->cur = start; - ch->blksize = blksize; ch->transferred = 0; - ch->curchanbuf = 0; + ch->blksize = blksize; + + /* + * Recompute nframes based on blksize, but make sure nframes + * is not longer in time duration than blksize. Rounding helps. + */ + if (ch->maxpktsize) { + ch->nframes = ch->blksize / ch->maxpktsize; + } else { + ch->nframes = (ch->blksize / ch->sample_size) * + ch->usb_fps / ch->sample_rate; + } + ch->nframes = ch->blksize / ch->bytes_per_frame; + if (ch->nframes > UAUDIO_MAX_FRAMES) + ch->nframes = UAUDIO_MAX_FRAMES; + else if (ch->nframes < 1) + ch->nframes = 1; + + ch->reqms = ch->bytes_per_frame / ch->sample_size * + ch->nframes * 1000 / ch->sample_rate; + + DPRINTF(("%s: alt=%d blk=%d maxpkt=%u bpf=%u rate=%u nframes=%u reqms=%u\n", + __func__, ch->altidx, ch->blksize, ch->maxpktsize, + ch->bytes_per_frame, ch->sample_rate, ch->nframes, ch->reqms)); } int |