MFC r282650 and r282651:
Extend the maximum number of allowed PCM channels in a PCM stream to 127 and decrease the maximum number of sub-channels to 1. These definitions are only used inside the kernel and can be changed later if more than one sub-channel is desired. This has been done to allow so-called USB audio rack modules to work with FreeBSD. 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. Bump the FreeBSD version to force recompiling all external modules.
This commit is contained in:
parent
02441119bc
commit
79cd6230a5
@ -1029,32 +1029,17 @@ static const struct {
|
||||
{ NULL, NULL, NULL, 0 }
|
||||
};
|
||||
|
||||
static const struct {
|
||||
char *name, *alias1, *alias2;
|
||||
int matrix_id;
|
||||
} matrix_id_tab[] = {
|
||||
{ "1.0", "1", "mono", SND_CHN_MATRIX_1_0 },
|
||||
{ "2.0", "2", "stereo", SND_CHN_MATRIX_2_0 },
|
||||
{ "2.1", NULL, NULL, SND_CHN_MATRIX_2_1 },
|
||||
{ "3.0", "3", NULL, SND_CHN_MATRIX_3_0 },
|
||||
{ "3.1", NULL, NULL, SND_CHN_MATRIX_3_1 },
|
||||
{ "4.0", "4", "quad", SND_CHN_MATRIX_4_0 },
|
||||
{ "4.1", NULL, NULL, SND_CHN_MATRIX_4_1 },
|
||||
{ "5.0", "5", NULL, SND_CHN_MATRIX_5_0 },
|
||||
{ "5.1", "6", NULL, SND_CHN_MATRIX_5_1 },
|
||||
{ "6.0", NULL, NULL, SND_CHN_MATRIX_6_0 },
|
||||
{ "6.1", "7", NULL, SND_CHN_MATRIX_6_1 },
|
||||
{ "7.0", NULL, NULL, SND_CHN_MATRIX_7_0 },
|
||||
{ "7.1", "8", NULL, SND_CHN_MATRIX_7_1 },
|
||||
{ NULL, NULL, NULL, SND_CHN_MATRIX_UNKNOWN }
|
||||
};
|
||||
|
||||
uint32_t
|
||||
snd_str2afmt(const char *req)
|
||||
{
|
||||
uint32_t i, afmt;
|
||||
int matrix_id;
|
||||
char b1[8], b2[8];
|
||||
int ext;
|
||||
int ch;
|
||||
int i;
|
||||
char b1[8];
|
||||
char b2[8];
|
||||
|
||||
memset(b1, 0, sizeof(b1));
|
||||
memset(b2, 0, sizeof(b2));
|
||||
|
||||
i = sscanf(req, "%5[^:]:%6s", b1, b2);
|
||||
|
||||
@ -1068,88 +1053,78 @@ snd_str2afmt(const char *req)
|
||||
} else
|
||||
return (0);
|
||||
|
||||
afmt = 0;
|
||||
matrix_id = SND_CHN_MATRIX_UNKNOWN;
|
||||
i = sscanf(b2, "%d.%d", &ch, &ext);
|
||||
|
||||
for (i = 0; afmt == 0 && afmt_tab[i].name != NULL; i++) {
|
||||
if (strcasecmp(afmt_tab[i].name, b1) == 0 ||
|
||||
(afmt_tab[i].alias1 != NULL &&
|
||||
strcasecmp(afmt_tab[i].alias1, b1) == 0) ||
|
||||
(afmt_tab[i].alias2 != NULL &&
|
||||
strcasecmp(afmt_tab[i].alias2, b1) == 0)) {
|
||||
afmt = afmt_tab[i].afmt;
|
||||
strlcpy(b1, afmt_tab[i].name, sizeof(b1));
|
||||
}
|
||||
}
|
||||
|
||||
if (afmt == 0)
|
||||
if (i == 0) {
|
||||
if (strcasecmp(b2, "mono") == 0) {
|
||||
ch = 1;
|
||||
ext = 0;
|
||||
} else if (strcasecmp(b2, "stereo") == 0) {
|
||||
ch = 2;
|
||||
ext = 0;
|
||||
} else if (strcasecmp(b2, "quad") == 0) {
|
||||
ch = 4;
|
||||
ext = 0;
|
||||
} else
|
||||
return (0);
|
||||
} else if (i == 1) {
|
||||
if (ch < 1 || ch > AFMT_CHANNEL_MAX)
|
||||
return (0);
|
||||
ext = 0;
|
||||
} else if (i == 2) {
|
||||
if (ext < 0 || ext > AFMT_EXTCHANNEL_MAX)
|
||||
return (0);
|
||||
if (ch < 1 || (ch + ext) > AFMT_CHANNEL_MAX)
|
||||
return (0);
|
||||
} else
|
||||
return (0);
|
||||
|
||||
for (i = 0; matrix_id == SND_CHN_MATRIX_UNKNOWN &&
|
||||
matrix_id_tab[i].name != NULL; i++) {
|
||||
if (strcmp(matrix_id_tab[i].name, b2) == 0 ||
|
||||
(matrix_id_tab[i].alias1 != NULL &&
|
||||
strcmp(matrix_id_tab[i].alias1, b2) == 0) ||
|
||||
(matrix_id_tab[i].alias2 != NULL &&
|
||||
strcasecmp(matrix_id_tab[i].alias2, b2) == 0)) {
|
||||
matrix_id = matrix_id_tab[i].matrix_id;
|
||||
strlcpy(b2, matrix_id_tab[i].name, sizeof(b2));
|
||||
for (i = 0; afmt_tab[i].name != NULL; i++) {
|
||||
if (strcasecmp(afmt_tab[i].name, b1) != 0) {
|
||||
if (afmt_tab[i].alias1 == NULL)
|
||||
continue;
|
||||
if (strcasecmp(afmt_tab[i].alias1, b1) != 0) {
|
||||
if (afmt_tab[i].alias2 == NULL)
|
||||
continue;
|
||||
if (strcasecmp(afmt_tab[i].alias2, b1) != 0)
|
||||
continue;
|
||||
}
|
||||
}
|
||||
/* found a match */
|
||||
return (SND_FORMAT(afmt_tab[i].afmt, ch + ext, ext));
|
||||
}
|
||||
|
||||
if (matrix_id == SND_CHN_MATRIX_UNKNOWN)
|
||||
return (0);
|
||||
|
||||
#ifndef _KERNEL
|
||||
printf("Parse OK: '%s' -> '%s:%s' %d\n", req, b1, b2,
|
||||
(int)(b2[0]) - '0' + (int)(b2[2]) - '0');
|
||||
#endif
|
||||
|
||||
return (SND_FORMAT(afmt, b2[0] - '0' + b2[2] - '0', b2[2] - '0'));
|
||||
/* not a valid format */
|
||||
return (0);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
snd_afmt2str(uint32_t afmt, char *buf, size_t len)
|
||||
{
|
||||
uint32_t i, enc, ch, ext;
|
||||
char tmp[AFMTSTR_LEN];
|
||||
uint32_t enc;
|
||||
uint32_t ext;
|
||||
uint32_t ch;
|
||||
int i;
|
||||
|
||||
if (buf == NULL || len < AFMTSTR_LEN)
|
||||
return (0);
|
||||
|
||||
|
||||
bzero(tmp, sizeof(tmp));
|
||||
memset(buf, 0, len);
|
||||
|
||||
enc = AFMT_ENCODING(afmt);
|
||||
ch = AFMT_CHANNEL(afmt);
|
||||
ext = AFMT_EXTCHANNEL(afmt);
|
||||
|
||||
/* check there is at least one channel */
|
||||
if (ch <= ext)
|
||||
return (0);
|
||||
for (i = 0; afmt_tab[i].name != NULL; i++) {
|
||||
if (enc == afmt_tab[i].afmt) {
|
||||
strlcpy(tmp, afmt_tab[i].name, sizeof(tmp));
|
||||
strlcat(tmp, ":", sizeof(tmp));
|
||||
break;
|
||||
}
|
||||
if (enc != afmt_tab[i].afmt)
|
||||
continue;
|
||||
/* found a match */
|
||||
snprintf(buf, len, "%s:%d.%d",
|
||||
afmt_tab[i].name, ch - ext, ext);
|
||||
return (SND_FORMAT(enc, ch, ext));
|
||||
}
|
||||
|
||||
if (strlen(tmp) == 0)
|
||||
return (0);
|
||||
|
||||
for (i = 0; matrix_id_tab[i].name != NULL; i++) {
|
||||
if (ch == (matrix_id_tab[i].name[0] - '0' +
|
||||
matrix_id_tab[i].name[2] - '0') &&
|
||||
ext == (matrix_id_tab[i].name[2] - '0')) {
|
||||
strlcat(tmp, matrix_id_tab[i].name, sizeof(tmp));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (strlen(tmp) == 0)
|
||||
return (0);
|
||||
|
||||
strlcpy(buf, tmp, len);
|
||||
|
||||
return (snd_str2afmt(buf));
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -162,6 +162,7 @@ struct pcm_channel {
|
||||
} channels;
|
||||
|
||||
struct pcmchan_matrix matrix;
|
||||
struct pcmchan_matrix matrix_scratch;
|
||||
|
||||
int volume[SND_VOL_C_MAX][SND_CHN_T_VOL_MAX];
|
||||
|
||||
|
@ -562,6 +562,20 @@ feeder_build_mixer(struct pcm_channel *c, struct feeder_chain_desc *cdesc)
|
||||
((c)->mode == FEEDER_CHAIN_LEAN && \
|
||||
!((c)->current.afmt & (AFMT_S16_NE | AFMT_S32_NE)))))
|
||||
|
||||
static void
|
||||
feeder_default_matrix(struct pcmchan_matrix *m, uint32_t fmt, int id)
|
||||
{
|
||||
int x;
|
||||
|
||||
memset(m, 0, sizeof(*m));
|
||||
|
||||
m->id = id;
|
||||
m->channels = AFMT_CHANNEL(fmt);
|
||||
m->ext = AFMT_EXTCHANNEL(fmt);
|
||||
for (x = 0; x != SND_CHN_T_MAX; x++)
|
||||
m->offset[x] = -1;
|
||||
}
|
||||
|
||||
int
|
||||
feeder_chain(struct pcm_channel *c)
|
||||
{
|
||||
@ -642,10 +656,10 @@ feeder_chain(struct pcm_channel *c)
|
||||
*/
|
||||
hwmatrix = CHANNEL_GETMATRIX(c->methods, c->devinfo, hwfmt);
|
||||
if (hwmatrix == NULL) {
|
||||
device_printf(c->dev,
|
||||
"%s(): failed to acquire hw matrix [0x%08x]\n",
|
||||
__func__, hwfmt);
|
||||
return (ENODEV);
|
||||
/* setup a default matrix */
|
||||
hwmatrix = &c->matrix_scratch;
|
||||
feeder_default_matrix(hwmatrix, hwfmt,
|
||||
SND_CHN_MATRIX_UNKNOWN);
|
||||
}
|
||||
/* ..... and rebuild hwfmt. */
|
||||
hwfmt = SND_FORMAT(hwfmt, hwmatrix->channels, hwmatrix->ext);
|
||||
@ -657,13 +671,14 @@ feeder_chain(struct pcm_channel *c)
|
||||
softmatrix->ext != AFMT_EXTCHANNEL(softfmt)) {
|
||||
softmatrix = feeder_matrix_format_map(softfmt);
|
||||
if (softmatrix == NULL) {
|
||||
device_printf(c->dev,
|
||||
"%s(): failed to acquire soft matrix [0x%08x]\n",
|
||||
__func__, softfmt);
|
||||
return (ENODEV);
|
||||
/* setup a default matrix */
|
||||
softmatrix = &c->matrix;
|
||||
feeder_default_matrix(softmatrix, softfmt,
|
||||
SND_CHN_MATRIX_PCMCHANNEL);
|
||||
} else {
|
||||
c->matrix = *softmatrix;
|
||||
c->matrix.id = SND_CHN_MATRIX_PCMCHANNEL;
|
||||
}
|
||||
c->matrix = *softmatrix;
|
||||
c->matrix.id = SND_CHN_MATRIX_PCMCHANNEL;
|
||||
}
|
||||
softfmt = SND_FORMAT(softfmt, softmatrix->channels, softmatrix->ext);
|
||||
if (softfmt != c->format)
|
||||
|
@ -220,10 +220,12 @@ struct snd_mixer;
|
||||
* ~(0xb00ff7ff)
|
||||
*/
|
||||
#define AFMT_ENCODING_MASK 0xf00fffff
|
||||
#define AFMT_CHANNEL_MASK 0x01f00000
|
||||
#define AFMT_CHANNEL_MASK 0x07f00000
|
||||
#define AFMT_CHANNEL_SHIFT 20
|
||||
#define AFMT_EXTCHANNEL_MASK 0x0e000000
|
||||
#define AFMT_EXTCHANNEL_SHIFT 25
|
||||
#define AFMT_CHANNEL_MAX 0x7f
|
||||
#define AFMT_EXTCHANNEL_MASK 0x08000000
|
||||
#define AFMT_EXTCHANNEL_SHIFT 27
|
||||
#define AFMT_EXTCHANNEL_MAX 1
|
||||
|
||||
#define AFMT_ENCODING(v) ((v) & AFMT_ENCODING_MASK)
|
||||
|
||||
|
@ -121,6 +121,8 @@ SYSCTL_INT(_hw_usb_uaudio, OID_AUTO, default_channels, CTLFLAG_RW,
|
||||
#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)
|
||||
@ -352,6 +354,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 {
|
||||
@ -1068,6 +1071,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;
|
||||
@ -1842,19 +1849,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;
|
||||
}
|
||||
|
||||
@ -1881,6 +1890,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)
|
||||
@ -1955,15 +1968,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--) {
|
||||
|
@ -58,7 +58,7 @@
|
||||
* in the range 5 to 9.
|
||||
*/
|
||||
#undef __FreeBSD_version
|
||||
#define __FreeBSD_version 1001516 /* Master, propagated to newvers */
|
||||
#define __FreeBSD_version 1001517 /* Master, propagated to newvers */
|
||||
|
||||
/*
|
||||
* __FreeBSD_kernel__ indicates that this system uses the kernel of FreeBSD,
|
||||
|
Loading…
x
Reference in New Issue
Block a user