summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJacob Meuser <jakemsr@cvs.openbsd.org>2009-11-26 15:45:26 +0000
committerJacob Meuser <jakemsr@cvs.openbsd.org>2009-11-26 15:45:26 +0000
commit2eab2dc813ec882e57aabd5f2c91e77135447adb (patch)
tree341e2e4a6b469896917694941916a1ca4df61261
parentad412571972769ea82e0ed7f2db6ad03b4bf44da (diff)
allow USB xfer requests to use up to 16 frames per xfer, depending on
blocksize
-rw-r--r--sys/dev/usb/uaudio.c91
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