From owner-p4-projects@FreeBSD.ORG Wed Dec 16 19:22:47 2009 Return-Path: Delivered-To: p4-projects@freebsd.org Received: by hub.freebsd.org (Postfix, from userid 32767) id BE7961065676; Wed, 16 Dec 2009 19:22:47 +0000 (UTC) Delivered-To: perforce@FreeBSD.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 82F591065670 for ; Wed, 16 Dec 2009 19:22:47 +0000 (UTC) (envelope-from hselasky@FreeBSD.org) Received: from repoman.freebsd.org (repoman.freebsd.org [IPv6:2001:4f8:fff6::29]) by mx1.freebsd.org (Postfix) with ESMTP id 6FA518FC18 for ; Wed, 16 Dec 2009 19:22:47 +0000 (UTC) Received: from repoman.freebsd.org (localhost [127.0.0.1]) by repoman.freebsd.org (8.14.3/8.14.3) with ESMTP id nBGJMlWu040173 for ; Wed, 16 Dec 2009 19:22:47 GMT (envelope-from hselasky@FreeBSD.org) Received: (from perforce@localhost) by repoman.freebsd.org (8.14.3/8.14.3/Submit) id nBGJMlc6040171 for perforce@freebsd.org; Wed, 16 Dec 2009 19:22:47 GMT (envelope-from hselasky@FreeBSD.org) Date: Wed, 16 Dec 2009 19:22:47 GMT Message-Id: <200912161922.nBGJMlc6040171@repoman.freebsd.org> X-Authentication-Warning: repoman.freebsd.org: perforce set sender to hselasky@FreeBSD.org using -f From: Hans Petter Selasky To: Perforce Change Reviews Precedence: bulk Cc: Subject: PERFORCE change 171845 for review X-BeenThere: p4-projects@freebsd.org X-Mailman-Version: 2.1.5 List-Id: p4 projects tree changes List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 16 Dec 2009 19:22:48 -0000 http://p4web.freebsd.org/chv.cgi?CH=171845 Change 171845 by hselasky@hselasky_laptop001 on 2009/12/16 19:22:24 USB audio: - add support for more sample rates - add more tunables Affected files ... .. //depot/projects/usb/src/sys/dev/sound/usb/uaudio.c#65 edit Differences ... ==== //depot/projects/usb/src/sys/dev/sound/usb/uaudio.c#65 (text+ko) ==== @@ -87,20 +87,27 @@ #include #include "feeder_if.h" -static int uaudio_default_rate = 96000; +static int uaudio_default_rate = 0; /* use rate list */ static int uaudio_default_bits = 32; -static int uaudio_default_channels = 16; +static int uaudio_default_channels = 0; /* use default */ #if USB_DEBUG static int uaudio_debug = 0; SYSCTL_NODE(_hw_usb, OID_AUTO, uaudio, CTLFLAG_RW, 0, "USB uaudio"); + SYSCTL_INT(_hw_usb_uaudio, OID_AUTO, debug, CTLFLAG_RW, &uaudio_debug, 0, "uaudio debug level"); + +TUNABLE_INT("hw.usb.uaudio.default_rate", &uaudio_default_rate); SYSCTL_INT(_hw_usb_uaudio, OID_AUTO, default_rate, CTLFLAG_RW, &uaudio_default_rate, 0, "uaudio default sample rate"); + +TUNABLE_INT("hw.usb.uaudio.default_bits", &uaudio_default_bits); SYSCTL_INT(_hw_usb_uaudio, OID_AUTO, default_bits, CTLFLAG_RW, &uaudio_default_bits, 0, "uaudio default sample bits"); + +TUNABLE_INT("hw.usb.uaudio.default_channels", &uaudio_default_channels); SYSCTL_INT(_hw_usb_uaudio, OID_AUTO, default_channels, CTLFLAG_RW, &uaudio_default_channels, 0, "uaudio default sample channels"); #endif @@ -169,10 +176,16 @@ uint32_t intr_size; /* in bytes */ uint32_t intr_frames; /* in units */ uint32_t sample_rate; + uint32_t frames_per_second; + uint32_t sample_rem; + uint32_t sample_curr; + uint32_t format; uint32_t pcm_format[2]; - uint16_t bytes_per_frame; + uint16_t bytes_per_frame[2]; + + uint16_t sample_size; uint8_t valid; uint8_t iface_index; @@ -330,7 +343,7 @@ static usb_callback_t umidi_bulk_write_callback; static void uaudio_chan_fill_info_sub(struct uaudio_softc *, - struct usb_device *, uint32_t, uint16_t, uint8_t, uint8_t); + struct usb_device *, uint32_t, uint8_t, uint8_t); static void uaudio_chan_fill_info(struct uaudio_softc *, struct usb_device *); static void uaudio_mixer_add_ctl_sub(struct uaudio_softc *, @@ -787,8 +800,7 @@ static void uaudio_chan_fill_info_sub(struct uaudio_softc *sc, struct usb_device *udev, - uint32_t rate, uint16_t fps, uint8_t channels, - uint8_t bit_resolution) + uint32_t rate, uint8_t channels, uint8_t bit_resolution) { struct usb_descriptor *desc = NULL; const struct usb2_audio_streaming_interface_descriptor *asid = NULL; @@ -811,7 +823,6 @@ uint8_t bBitResolution; uint8_t x; uint8_t audio_if = 0; - uint8_t sample_size; while ((desc = usb_desc_foreach(cd, desc))) { @@ -1040,16 +1051,10 @@ chan->usb2_cfg = uaudio_cfg_play; - sample_size = (( + chan->sample_size = (( UAUDIO_MAX_CHAN(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) { sbuf_printf(&sc->sc_sndstat, "\n\t" "mode %d.%d:(%s) %dch, %d/%dbit, %s, %dHz", @@ -1067,12 +1072,32 @@ } } +/* This structure defines all the supported rates. */ + +static const uint32_t uaudio_rate_list[] = { + 96000, + 88000, + 80000, + 72000, + 64000, + 56000, + 48000, + 44100, + 40000, + 32000, + 24000, + 22050, + 16000, + 11025, + 8000, + 0 +}; + static void uaudio_chan_fill_info(struct uaudio_softc *sc, struct usb_device *udev) { uint32_t rate = uaudio_default_rate; - uint32_t z; - uint16_t fps = usbd_get_isoc_fps(udev); + uint8_t z; uint8_t bits = uaudio_default_bits; uint8_t y; uint8_t channels = uaudio_default_channels; @@ -1083,13 +1108,23 @@ /* 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 > 16)) { - /* set a valid value */ + if (channels == 0) { + switch (usbd_get_speed(udev)) { + case USB_SPEED_LOW: + case USB_SPEED_FULL: + /* + * Due to high bandwidth usage and problems + * with HIGH-speed split transactions we + * disable surround setups on FULL-speed USB + * by default + */ + channels = 2; + break; + default: + channels = 16; + break; + } + } else if (channels > 16) { channels = 16; } if (sbuf_new(&sc->sc_sndstat, NULL, 4096, SBUF_AUTOEXTEND)) { @@ -1099,8 +1134,14 @@ for (x = channels; x; x--) { for (y = bits; y; y -= 8) { - for (z = rate; z; z -= fps) { - uaudio_chan_fill_info_sub(sc, udev, z, fps, x, y); + + /* try user defined rate, if any */ + if (rate != 0) + uaudio_chan_fill_info_sub(sc, udev, rate, x, y); + + /* try find a matching rate, if any */ + for (z = 0; uaudio_rate_list[z]; z++) { + uaudio_chan_fill_info_sub(sc, udev, uaudio_rate_list[z], x, y); if (sc->sc_rec_chan.valid && sc->sc_play_chan.valid) { @@ -1116,18 +1157,6 @@ } } -/* - * The following function sets up data size and block count for the - * next audio transfer. - */ -static void -uaudio_setup_blockcount(struct uaudio_chan *ch, - uint32_t *total, uint32_t *blockcount) -{ - *total = ch->intr_size; - *blockcount = ch->intr_frames; -} - static void uaudio_chan_play_callback(struct usb_xfer *xfer, usb_error_t error) { @@ -1137,12 +1166,11 @@ uint32_t blockcount; uint32_t n; uint32_t offset; - int actlen, sumlen; + int actlen; + int sumlen; usbd_xfer_status(xfer, &actlen, &sumlen, NULL, NULL); - uaudio_setup_blockcount(ch, &total, &blockcount); - if (ch->end == ch->start) { DPRINTF("no buffer!\n"); return; @@ -1153,22 +1181,39 @@ tr_transferred: if (actlen < sumlen) { DPRINTF("short transfer, " - "%d of %d bytes\n", actlen, total); + "%d of %d bytes\n", actlen, sumlen); } chn_intr(ch->pcm_ch); case USB_ST_SETUP: - if (ch->bytes_per_frame > usbd_xfer_max_framelen(xfer)) { + if (ch->bytes_per_frame[1] > usbd_xfer_max_framelen(xfer)) { DPRINTF("bytes per transfer, %d, " "exceeds maximum, %d!\n", - ch->bytes_per_frame, + ch->bytes_per_frame[1], usbd_xfer_max_framelen(xfer)); break; } - /* setup frame length */ + + blockcount = ch->intr_frames; + + /* setup number of frames */ usbd_xfer_set_frames(xfer, blockcount); - for (n = 0; n != blockcount; n++) - usbd_xfer_set_frame_len(xfer, n, ch->bytes_per_frame); + + /* reset total length */ + total = 0; + + /* setup frame lengths */ + for (n = 0; n != blockcount; n++) { + ch->sample_curr += ch->sample_rem; + if (ch->sample_curr >= ch->frames_per_second) { + ch->sample_curr -= ch->frames_per_second; + usbd_xfer_set_frame_len(xfer, n, ch->bytes_per_frame[1]); + total += ch->bytes_per_frame[1]; + } else { + usbd_xfer_set_frame_len(xfer, n, ch->bytes_per_frame[0]); + total += ch->bytes_per_frame[0]; + } + } DPRINTFN(6, "transfer %d bytes\n", total); @@ -1210,7 +1255,6 @@ struct usb_page_cache *pc; uint32_t n; uint32_t m; - uint32_t total; uint32_t blockcount; uint32_t offset0; uint32_t offset1; @@ -1222,8 +1266,6 @@ usbd_xfer_status(xfer, &actlen, NULL, NULL, &nframes); mfl = usbd_xfer_max_framelen(xfer); - uaudio_setup_blockcount(ch, &total, &blockcount); - if (ch->end == ch->start) { DPRINTF("no buffer!\n"); return; @@ -1231,12 +1273,8 @@ switch (USB_GET_STATE(xfer)) { case USB_ST_TRANSFERRED: - if (actlen < total) { - DPRINTF("short transfer, " - "%d of %d bytes\n", actlen, total); - } else { - DPRINTFN(6, "transferred %d bytes\n", actlen); - } + + DPRINTFN(6, "transferred %d bytes\n", actlen); offset0 = 0; pc = usbd_xfer_get_frame(xfer, 0); @@ -1271,6 +1309,8 @@ case USB_ST_SETUP: tr_setup: + blockcount = ch->intr_frames; + usbd_xfer_set_frames(xfer, blockcount); for (n = 0; n < blockcount; n++) { usbd_xfer_set_frame_len(xfer, n, mfl); @@ -1296,6 +1336,7 @@ uint32_t buf_size; uint32_t frames; uint32_t format; + uint16_t fps; uint8_t endpoint; uint8_t blocks; uint8_t iface_index; @@ -1303,7 +1344,9 @@ uint8_t fps_shift; usb_error_t err; - if (usbd_get_isoc_fps(sc->sc_udev) < 8000) { + fps = usbd_get_isoc_fps(sc->sc_udev); + + if (fps < 8000) { /* FULL speed USB */ frames = 8; } else { @@ -1311,10 +1354,6 @@ frames = UAUDIO_NFRAMES; } - /* compute required buffer size */ - - buf_size = (ch->bytes_per_frame * frames); - /* setup play/record format */ ch->pcm_cap.fmtlist = ch->pcm_format; @@ -1397,10 +1436,27 @@ fps_shift = usbd_xfer_get_fps_shift(ch->xfer[0]); - /* setup frame sizes */ + /* down shift number of frames per second, if any */ + fps >>= fps_shift; + frames >>= fps_shift; + + /* bytes per frame should not be zero */ + ch->bytes_per_frame[0] = ((ch->sample_rate / fps) * ch->sample_size); + ch->bytes_per_frame[1] = (((ch->sample_rate + fps - 1) / fps) * ch->sample_size); + + /* setup data rate dithering, if any */ + ch->frames_per_second = fps; + ch->sample_rem = ch->sample_rate % fps; + ch->sample_curr = 0; + ch->frames_per_second = fps; + + /* compute required buffer size */ + buf_size = (ch->bytes_per_frame[1] * frames); + ch->intr_size = buf_size; - ch->intr_frames = (frames >> fps_shift); - ch->bytes_per_frame <<= fps_shift; + ch->intr_frames = frames; + + DPRINTF("fps=%d sample_rem=%d\n", fps, ch->sample_rem); if (ch->intr_frames == 0) { DPRINTF("frame shift is too high!\n");