From e88a1dfd3e17536971b129f0e01f5ac9d71e277f Mon Sep 17 00:00:00 2001 From: hselasky Date: Fri, 8 May 2015 17:07:11 +0000 Subject: Add support for more than 8 audio channels per PCM stream for USB audio class compliant devices under FreeBSD. Tested using 16 recording and 16 playback audio channels simultaneously. MFC after: 2 weeks --- sys/dev/sound/usb/uaudio.c | 41 +++++++++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 14 deletions(-) (limited to 'sys/dev/sound') diff --git a/sys/dev/sound/usb/uaudio.c b/sys/dev/sound/usb/uaudio.c index 8822bf0..c255a19 100644 --- a/sys/dev/sound/usb/uaudio.c +++ b/sys/dev/sound/usb/uaudio.c @@ -115,6 +115,8 @@ SYSCTL_INT(_hw_usb_uaudio, OID_AUTO, default_channels, CTLFLAG_RWTUN, #define UAUDIO_NFRAMES 64 /* must be factor of 8 due HS-USB */ #define UAUDIO_NCHANBUFS 2 /* number of outstanding request */ #define UAUDIO_RECURSE_LIMIT 255 /* rounds */ +#define UAUDIO_CHANNELS_MAX MIN(64, AFMT_CHANNEL_MAX) +#define UAUDIO_MATRIX_MAX 8 /* channels */ #define MAKE_WORD(h,l) (((h) << 8) | (l)) #define BIT_TEST(bm,bno) (((bm)[(bno) / 8] >> (7 - ((bno) % 8))) & 1) @@ -346,6 +348,7 @@ struct uaudio_softc { uint8_t sc_uq_au_no_xu:1; uint8_t sc_uq_bad_adc:1; uint8_t sc_uq_au_vendor_class:1; + uint8_t sc_pcm_bitperfect:1; }; struct uaudio_terminal_node { @@ -1062,6 +1065,10 @@ uaudio_attach_sub(device_t dev, kobj_class_t mixer_class, kobj_class_t chan_clas */ uaudio_pcm_setflags(dev, SD_F_SOFTPCMVOL); } + if (sc->sc_pcm_bitperfect) { + DPRINTF("device needs bitperfect by default\n"); + uaudio_pcm_setflags(dev, SD_F_BITPERFECT); + } if (mixer_init(dev, mixer_class, sc)) goto detach; sc->sc_mixer_init = 1; @@ -1826,19 +1833,21 @@ uaudio_chan_fill_info_sub(struct uaudio_softc *sc, struct usb_device *udev, format = chan_alt->p_fmt->freebsd_fmt; + /* get default SND_FORMAT() */ + format = SND_FORMAT(format, chan_alt->channels, 0); + switch (chan_alt->channels) { - case 2: - /* stereo */ - format = SND_FORMAT(format, 2, 0); - break; + uint32_t temp_fmt; case 1: - /* mono */ - format = SND_FORMAT(format, 1, 0); + case 2: + /* mono and stereo */ break; default: /* surround and more */ - format = feeder_matrix_default_format( - SND_FORMAT(format, chan_alt->channels, 0)); + temp_fmt = feeder_matrix_default_format(format); + /* if multichannel, then format can be zero */ + if (temp_fmt != 0) + format = temp_fmt; break; } @@ -1865,6 +1874,10 @@ uaudio_chan_fill_info_sub(struct uaudio_softc *sc, struct usb_device *udev, chan->pcm_cap.fmtlist = chan->pcm_format; chan->pcm_cap.fmtlist[0] = format; + /* check if device needs bitperfect */ + if (chan_alt->channels > UAUDIO_MATRIX_MAX) + sc->sc_pcm_bitperfect = 1; + if (rate < chan->pcm_cap.minspeed || chan->pcm_cap.minspeed == 0) chan->pcm_cap.minspeed = rate; if (rate > chan->pcm_cap.maxspeed || chan->pcm_cap.maxspeed == 0) @@ -1939,15 +1952,15 @@ uaudio_chan_fill_info(struct uaudio_softc *sc, struct usb_device *udev) channels = 4; break; default: - channels = 16; + channels = UAUDIO_CHANNELS_MAX; break; } - } else if (channels > 16) { - channels = 16; - } - if (sbuf_new(&sc->sc_sndstat, NULL, 4096, SBUF_AUTOEXTEND)) { + } else if (channels > UAUDIO_CHANNELS_MAX) + channels = UAUDIO_CHANNELS_MAX; + + if (sbuf_new(&sc->sc_sndstat, NULL, 4096, SBUF_AUTOEXTEND)) sc->sc_sndstat_valid = 1; - } + /* try to search for a valid config */ for (x = channels; x; x--) { -- cgit v1.1