- add support for more than 2 audio channels. [1]
- add support for more sample rates Submitted by: [1] ariff (earlier version), Hans Petter Selasky
This commit is contained in:
parent
f1ea98c024
commit
afbfddd901
@ -87,20 +87,27 @@
|
||||
#include <dev/sound/chip.h>
|
||||
#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 = 2;
|
||||
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 @@ struct uaudio_chan {
|
||||
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_write_clear_stall_callback;
|
||||
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 @@ uaudio_chan_dump_ep_desc(const usb2_endpoint_descriptor_audio_t *ed)
|
||||
|
||||
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 @@ uaudio_chan_fill_info_sub(struct uaudio_softc *sc, struct usb_device *udev,
|
||||
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 @@ uaudio_chan_fill_info_sub(struct uaudio_softc *sc, struct usb_device *udev,
|
||||
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 @@ uaudio_chan_fill_info_sub(struct uaudio_softc *sc, struct usb_device *udev,
|
||||
}
|
||||
}
|
||||
|
||||
/* 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,14 +1108,24 @@ uaudio_chan_fill_info(struct uaudio_softc *sc, struct usb_device *udev)
|
||||
/* 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 (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)) {
|
||||
sc->sc_sndstat_valid = 1;
|
||||
@ -1099,8 +1134,14 @@ uaudio_chan_fill_info(struct uaudio_softc *sc, struct usb_device *udev)
|
||||
|
||||
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 @@ done:
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 @@ uaudio_chan_play_callback(struct usb_xfer *xfer, usb_error_t error)
|
||||
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 @@ uaudio_chan_play_callback(struct usb_xfer *xfer, usb_error_t error)
|
||||
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 @@ uaudio_chan_record_callback(struct usb_xfer *xfer, usb_error_t error)
|
||||
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 @@ uaudio_chan_record_callback(struct usb_xfer *xfer, usb_error_t error)
|
||||
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 @@ uaudio_chan_record_callback(struct usb_xfer *xfer, usb_error_t error)
|
||||
|
||||
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 @@ uaudio_chan_record_callback(struct usb_xfer *xfer, usb_error_t error)
|
||||
|
||||
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);
|
||||
@ -1295,6 +1335,8 @@ uaudio_chan_init(struct uaudio_softc *sc, struct snd_dbuf *b,
|
||||
&sc->sc_play_chan : &sc->sc_rec_chan);
|
||||
uint32_t buf_size;
|
||||
uint32_t frames;
|
||||
uint32_t format;
|
||||
uint16_t fps;
|
||||
uint8_t endpoint;
|
||||
uint8_t blocks;
|
||||
uint8_t iface_index;
|
||||
@ -1302,7 +1344,9 @@ uaudio_chan_init(struct uaudio_softc *sc, struct snd_dbuf *b,
|
||||
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 {
|
||||
@ -1310,10 +1354,6 @@ uaudio_chan_init(struct uaudio_softc *sc, struct snd_dbuf *b,
|
||||
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;
|
||||
@ -1329,15 +1369,34 @@ uaudio_chan_init(struct uaudio_softc *sc, struct snd_dbuf *b,
|
||||
ch->pcm_ch = c;
|
||||
ch->pcm_mtx = c->lock;
|
||||
|
||||
if (ch->p_asf1d->bNrChannels >= 2)
|
||||
ch->pcm_cap.fmtlist[0] =
|
||||
SND_FORMAT(ch->p_fmt->freebsd_fmt, 2, 0);
|
||||
else
|
||||
ch->pcm_cap.fmtlist[0] =
|
||||
SND_FORMAT(ch->p_fmt->freebsd_fmt, 1, 0);
|
||||
format = ch->p_fmt->freebsd_fmt;
|
||||
|
||||
switch (ch->p_asf1d->bNrChannels) {
|
||||
case 2:
|
||||
/* stereo */
|
||||
format = SND_FORMAT(format, 2, 0);
|
||||
break;
|
||||
case 1:
|
||||
/* mono */
|
||||
format = SND_FORMAT(format, 1, 0);
|
||||
break;
|
||||
default:
|
||||
/* surround and more */
|
||||
format = feeder_matrix_default_format(
|
||||
SND_FORMAT(format, ch->p_asf1d->bNrChannels, 0));
|
||||
break;
|
||||
}
|
||||
|
||||
ch->pcm_cap.fmtlist[0] = format;
|
||||
ch->pcm_cap.fmtlist[1] = 0;
|
||||
|
||||
/* check if format is not supported */
|
||||
|
||||
if (format == 0) {
|
||||
DPRINTF("The selected audio format is not supported\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* set alternate interface corresponding to the mode */
|
||||
|
||||
endpoint = ch->p_ed1->bEndpointAddress;
|
||||
@ -1377,10 +1436,27 @@ uaudio_chan_init(struct uaudio_softc *sc, struct snd_dbuf *b,
|
||||
|
||||
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");
|
||||
|
Loading…
x
Reference in New Issue
Block a user