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
This commit is contained in:
Hans Petter Selasky 2015-05-08 17:07:11 +00:00
parent 4ece1a889b
commit 9dd1273385

View File

@ -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--) {