diff options
| author | Alfred Perlstein <alfred@FreeBSD.org> | 2009-01-04 00:12:01 +0000 |
|---|---|---|
| committer | Alfred Perlstein <alfred@FreeBSD.org> | 2009-01-04 00:12:01 +0000 |
| commit | d5474fd85f6d8044976511534faa78061d078efe (patch) | |
| tree | 6a212d791777cd056f5b3466272b0be92152182e /sys/dev/usb2/sound | |
| parent | 17c98d6dabbf9ca3b4b2ad4d9bfca987fb74276c (diff) | |
Notes
Diffstat (limited to 'sys/dev/usb2/sound')
| -rw-r--r-- | sys/dev/usb2/sound/uaudio2.c | 170 |
1 files changed, 76 insertions, 94 deletions
diff --git a/sys/dev/usb2/sound/uaudio2.c b/sys/dev/usb2/sound/uaudio2.c index b843ef13d9f4..614db85d8be2 100644 --- a/sys/dev/usb2/sound/uaudio2.c +++ b/sys/dev/usb2/sound/uaudio2.c @@ -80,22 +80,27 @@ #include <dev/sound/chip.h> #include "feeder_if.h" +static int uaudio_default_rate = 96000; +static int uaudio_default_bits = 32; +static int uaudio_default_channels = 2; + #if USB_DEBUG static int uaudio_debug = 0; SYSCTL_NODE(_hw_usb2, OID_AUTO, uaudio, CTLFLAG_RW, 0, "USB uaudio"); SYSCTL_INT(_hw_usb2_uaudio, OID_AUTO, debug, CTLFLAG_RW, &uaudio_debug, 0, "uaudio debug level"); +SYSCTL_INT(_hw_usb2_uaudio, OID_AUTO, default_rate, CTLFLAG_RW, + &uaudio_default_rate, 0, "uaudio default sample rate"); +SYSCTL_INT(_hw_usb2_uaudio, OID_AUTO, default_bits, CTLFLAG_RW, + &uaudio_default_bits, 0, "uaudio default sample bits"); +SYSCTL_INT(_hw_usb2_uaudio, OID_AUTO, default_channels, CTLFLAG_RW, + &uaudio_default_channels, 0, "uaudio default sample channels"); #endif -static uint32_t uaudio_default_rate = 96000; -static uint8_t uaudio_default_bits = 32; -static uint8_t uaudio_default_channels = 2; - +#define UAUDIO_MINFRAMES 16 /* must be factor of 8 due HS-USB */ #define UAUDIO_NCHANBUFS 2 /* number of outstanding request */ -#define UAUDIO_NFRAMES 25 /* ms of sound in each request */ #define UAUDIO_RECURSE_LIMIT 24 /* rounds */ -#define UAUDIO_DEFAULT_BUFSZ ((2 * 96000 * 4 * 2) / (1000 / UAUDIO_NCHANBUFS)) /* bytes */ #define MAKE_WORD(h,l) (((h) << 8) | (l)) #define BIT_TEST(bm,bno) (((bm)[(bno) / 8] >> (7 - ((bno) % 8))) & 1) @@ -154,6 +159,7 @@ struct uaudio_chan { uint8_t *cur; /* current position in upper layer * buffer */ + uint32_t intr_size; /* in bytes */ uint32_t block_size; uint32_t sample_rate; uint32_t format; @@ -389,13 +395,13 @@ static const char *uaudio_mixer_get_terminal_name(uint16_t); #endif static const struct usb2_config - uaudio_cfg_record_full_speed[UAUDIO_NCHANBUFS] = { + uaudio_cfg_record[UAUDIO_NCHANBUFS] = { [0] = { .type = UE_ISOCHRONOUS, .endpoint = UE_ADDR_ANY, .direction = UE_DIR_IN, .mh.bufsize = 0, /* use "wMaxPacketSize * frames" */ - .mh.frames = UAUDIO_NFRAMES, + .mh.frames = UAUDIO_MINFRAMES, .mh.flags = {.short_xfer_ok = 1,}, .mh.callback = &uaudio_chan_record_callback, }, @@ -405,66 +411,20 @@ static const struct usb2_config .endpoint = UE_ADDR_ANY, .direction = UE_DIR_IN, .mh.bufsize = 0, /* use "wMaxPacketSize * frames" */ - .mh.frames = UAUDIO_NFRAMES, + .mh.frames = UAUDIO_MINFRAMES, .mh.flags = {.short_xfer_ok = 1,}, .mh.callback = &uaudio_chan_record_callback, }, }; static const struct usb2_config - uaudio_cfg_record_high_speed[UAUDIO_NCHANBUFS] = { - [0] = { - .type = UE_ISOCHRONOUS, - .endpoint = UE_ADDR_ANY, - .direction = UE_DIR_IN, - .mh.bufsize = 0, /* use "wMaxPacketSize * frames" */ - .mh.frames = (UAUDIO_NFRAMES * 8), - .mh.flags = {.short_xfer_ok = 1,}, - .mh.callback = &uaudio_chan_record_callback, - }, - - [1] = { - .type = UE_ISOCHRONOUS, - .endpoint = UE_ADDR_ANY, - .direction = UE_DIR_IN, - .mh.bufsize = 0, /* use "wMaxPacketSize * frames" */ - .mh.frames = (UAUDIO_NFRAMES * 8), - .mh.flags = {.short_xfer_ok = 1,}, - .mh.callback = &uaudio_chan_record_callback, - }, -}; - -static const struct usb2_config - uaudio_cfg_play_full_speed[UAUDIO_NCHANBUFS] = { - [0] = { - .type = UE_ISOCHRONOUS, - .endpoint = UE_ADDR_ANY, - .direction = UE_DIR_OUT, - .mh.bufsize = 0, /* use "wMaxPacketSize * frames" */ - .mh.frames = UAUDIO_NFRAMES, - .mh.flags = {.short_xfer_ok = 1,}, - .mh.callback = &uaudio_chan_play_callback, - }, - - [1] = { - .type = UE_ISOCHRONOUS, - .endpoint = UE_ADDR_ANY, - .direction = UE_DIR_OUT, - .mh.bufsize = 0, /* use "wMaxPacketSize * frames" */ - .mh.frames = UAUDIO_NFRAMES, - .mh.flags = {.short_xfer_ok = 1,}, - .mh.callback = &uaudio_chan_play_callback, - }, -}; - -static const struct usb2_config - uaudio_cfg_play_high_speed[UAUDIO_NCHANBUFS] = { + uaudio_cfg_play[UAUDIO_NCHANBUFS] = { [0] = { .type = UE_ISOCHRONOUS, .endpoint = UE_ADDR_ANY, .direction = UE_DIR_OUT, .mh.bufsize = 0, /* use "wMaxPacketSize * frames" */ - .mh.frames = (UAUDIO_NFRAMES * 8), + .mh.frames = UAUDIO_MINFRAMES, .mh.flags = {.short_xfer_ok = 1,}, .mh.callback = &uaudio_chan_play_callback, }, @@ -474,7 +434,7 @@ static const struct usb2_config .endpoint = UE_ADDR_ANY, .direction = UE_DIR_OUT, .mh.bufsize = 0, /* use "wMaxPacketSize * frames" */ - .mh.frames = (UAUDIO_NFRAMES * 8), + .mh.frames = UAUDIO_MINFRAMES, .mh.flags = {.short_xfer_ok = 1,}, .mh.callback = &uaudio_chan_play_callback, }, @@ -706,10 +666,6 @@ uaudio_attach_sub(device_t dev, kobj_class_t mixer_class, kobj_class_t chan_clas struct uaudio_softc *sc = device_get_softc(device_get_parent(dev)); char status[SND_STATUSLEN]; - if (bootverbose) { - device_printf(dev, "using a default buffer " - "size of %u bytes\n", UAUDIO_DEFAULT_BUFSZ); - } uaudio_mixer_init(sc); if (sc->sc_uq_audio_swap_lr) { @@ -1066,19 +1022,20 @@ uaudio_chan_fill_info_sub(struct uaudio_softc *sc, struct usb2_device *udev, chan->iface_index = curidx; chan->iface_alt_index = alt_index; - chan->usb2_cfg = - (ep_dir == UE_DIR_IN) ? - ((fps == 1000) ? - uaudio_cfg_record_full_speed : - uaudio_cfg_record_high_speed) : - ((fps == 1000) ? - uaudio_cfg_play_full_speed : - uaudio_cfg_play_high_speed); - + if (ep_dir == UE_DIR_IN) + chan->usb2_cfg = + uaudio_cfg_record; + else + chan->usb2_cfg = + uaudio_cfg_play; sample_size = ((chan->p_asf1d->bNrChannels * chan->p_asf1d->bBitResolution) / 8); + /* + * NOTE: "chan->bytes_per_frame" + * should not be zero! + */ chan->bytes_per_frame = ((rate / fps) * sample_size); if (sc->sc_sndstat_valid) { @@ -1103,15 +1060,26 @@ uaudio_chan_fill_info(struct uaudio_softc *sc, struct usb2_device *udev) { uint32_t rate = uaudio_default_rate; uint32_t z; - uint16_t fps = (usb2_get_speed(udev) == USB_SPEED_HIGH) ? 8000 : 1000; + uint16_t fps = usb2_get_isoc_fps(udev); uint8_t bits = uaudio_default_bits; uint8_t y; uint8_t channels = uaudio_default_channels; uint8_t x; bits -= (bits % 8); + if ((bits == 0) || (bits > 32)) { + /* set a valid value */ + bits = 32; + } rate -= (rate % fps); - + if ((rate == 0) || (rate > 192000)) { + /* set a valid value */ + rate = 192000 - (192000 % fps); + } + if ((channels == 0) || (channels > 2)) { + /* set a valid value */ + channels = 2; + } if (sbuf_new(&sc->sc_sndstat, NULL, 4096, SBUF_AUTOEXTEND)) { sc->sc_sndstat_valid = 1; } @@ -1141,21 +1109,23 @@ uaudio_chan_play_callback(struct usb2_xfer *xfer) { struct uaudio_chan *ch = xfer->priv_sc; uint32_t *p_len = xfer->frlengths; - uint32_t total = (sndbuf_getblkcnt(ch->pcm_buf) * - sndbuf_getblksz(ch->pcm_buf)) / 2; + uint32_t total; uint32_t blockcount; uint32_t n; uint32_t offset; /* allow dynamic sizing of play buffer */ + total = ch->intr_size; + + /* allow dynamic sizing of play buffer */ blockcount = total / ch->bytes_per_frame; - /* align to 8 units */ - blockcount &= ~7; + /* align units */ + blockcount -= (blockcount % UAUDIO_MINFRAMES); /* range check - min */ if (blockcount == 0) { - blockcount = 8; + blockcount = UAUDIO_MINFRAMES; } /* range check - max */ if (blockcount > xfer->max_frame_count) { @@ -1230,21 +1200,23 @@ uaudio_chan_record_callback(struct usb2_xfer *xfer) uint32_t *p_len = xfer->frlengths; uint32_t n; uint32_t m; - uint32_t total = (sndbuf_getblkcnt(ch->pcm_buf) * - sndbuf_getblksz(ch->pcm_buf)) / 2; + uint32_t total; uint32_t blockcount; uint32_t offset0; uint32_t offset1; /* allow dynamic sizing of play buffer */ + total = ch->intr_size; + + /* allow dynamic sizing of play buffer */ blockcount = total / ch->bytes_per_frame; - /* align to 8 units */ - blockcount &= ~7; + /* align units */ + blockcount -= (blockcount % UAUDIO_MINFRAMES); /* range check - min */ if (blockcount == 0) { - blockcount = 8; + blockcount = UAUDIO_MINFRAMES; } /* range check - max */ if (blockcount > xfer->max_frame_count) { @@ -1326,21 +1298,30 @@ uaudio_chan_init(struct uaudio_softc *sc, struct snd_dbuf *b, { struct uaudio_chan *ch = ((dir == PCMDIR_PLAY) ? &sc->sc_play_chan : &sc->sc_rec_chan); + uint32_t buf_size; uint8_t endpoint; uint8_t iface_index; uint8_t alt_index; usb2_error_t err; - ch->buf = malloc(UAUDIO_DEFAULT_BUFSZ, M_DEVBUF, M_WAITOK | M_ZERO); + /* compute required buffer size */ + buf_size = (ch->bytes_per_frame * UAUDIO_MINFRAMES); + + /* setup interrupt interval */ + ch->intr_size = buf_size; + /* double buffering */ + buf_size *= 2; + + ch->buf = malloc(buf_size, M_DEVBUF, M_WAITOK | M_ZERO); if (ch->buf == NULL) { goto error; } - if (sndbuf_setup(b, ch->buf, UAUDIO_DEFAULT_BUFSZ) != 0) { + if (sndbuf_setup(b, ch->buf, buf_size) != 0) { goto error; } ch->start = ch->buf; - ch->end = ch->buf + UAUDIO_DEFAULT_BUFSZ; + ch->end = ch->buf + buf_size; ch->cur = ch->buf; ch->pcm_ch = c; ch->pcm_mtx = c->lock; @@ -1437,16 +1418,14 @@ int uaudio_chan_set_param_fragments(struct uaudio_chan *ch, uint32_t blocksize, uint32_t blockcount) { - uint32_t max = sndbuf_getmaxsize(ch->pcm_buf); - - RANGE(blocksize, 128, max / 2); - - blockcount = max / blocksize; - RANGE(blockcount, 2, 512); + /* we only support one size */ + blocksize = ch->intr_size; + blockcount = 2; if ((sndbuf_getblksz(ch->pcm_buf) != blocksize) || (sndbuf_getblkcnt(ch->pcm_buf) != blockcount)) { - + DPRINTFN(1, "resizing to %u x " + "%u bytes\n", blockcount, blocksize); if (sndbuf_resize(ch->pcm_buf, blockcount, blocksize)) { DPRINTFN(0, "failed to resize sound buffer, count=%u, " "size=%u\n", blockcount, blocksize); @@ -2672,7 +2651,10 @@ uaudio_mixer_fill_info(struct uaudio_softc *sc, struct usb2_device *udev, DPRINTF("invalid Audio Control header\n"); goto done; } - wTotalLen = UGETW(cd->wTotalLength); + /* "wTotalLen" is allowed to be corrupt */ + wTotalLen = UGETW(acdp->wTotalLength) - acdp->bLength; + + /* get USB audio revision */ sc->sc_audio_rev = UGETW(acdp->bcdADC); DPRINTFN(3, "found AC header, vers=%03x, len=%d\n", |
