summaryrefslogtreecommitdiffstats
path: root/sys/dev/sound
diff options
context:
space:
mode:
authorhselasky <hselasky@FreeBSD.org>2015-06-03 15:32:43 +0000
committerhselasky <hselasky@FreeBSD.org>2015-06-03 15:32:43 +0000
commit79cd6230a5ab8914948a63f3edd0eb3baae36865 (patch)
tree3d2dd1d36683dc01586692410c01bd4910fb4cf3 /sys/dev/sound
parent02441119bc168497d2df4672b0666f72aa513093 (diff)
downloadFreeBSD-src-79cd6230a5ab8914948a63f3edd0eb3baae36865.zip
FreeBSD-src-79cd6230a5ab8914948a63f3edd0eb3baae36865.tar.gz
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.
Diffstat (limited to 'sys/dev/sound')
-rw-r--r--sys/dev/sound/pcm/channel.c147
-rw-r--r--sys/dev/sound/pcm/channel.h1
-rw-r--r--sys/dev/sound/pcm/feeder_chain.c35
-rw-r--r--sys/dev/sound/pcm/sound.h8
-rw-r--r--sys/dev/sound/usb/uaudio.c41
5 files changed, 119 insertions, 113 deletions
diff --git a/sys/dev/sound/pcm/channel.c b/sys/dev/sound/pcm/channel.c
index 75b02d0..6a3609b 100644
--- a/sys/dev/sound/pcm/channel.c
+++ b/sys/dev/sound/pcm/channel.c
@@ -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;
-
- 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)
+ i = sscanf(b2, "%d.%d", &ch, &ext);
+
+ 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);
-
- 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 (strlen(tmp) == 0)
+ /* check there is at least one channel */
+ if (ch <= ext)
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;
- }
+ for (i = 0; afmt_tab[i].name != NULL; i++) {
+ 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);
-
- strlcpy(buf, tmp, len);
-
- return (snd_str2afmt(buf));
+ return (0);
}
int
diff --git a/sys/dev/sound/pcm/channel.h b/sys/dev/sound/pcm/channel.h
index 6601b54..45f43b5 100644
--- a/sys/dev/sound/pcm/channel.h
+++ b/sys/dev/sound/pcm/channel.h
@@ -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];
diff --git a/sys/dev/sound/pcm/feeder_chain.c b/sys/dev/sound/pcm/feeder_chain.c
index 92a1cf5..76fdeaf 100644
--- a/sys/dev/sound/pcm/feeder_chain.c
+++ b/sys/dev/sound/pcm/feeder_chain.c
@@ -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)
diff --git a/sys/dev/sound/pcm/sound.h b/sys/dev/sound/pcm/sound.h
index 80cc645..db983dc 100644
--- a/sys/dev/sound/pcm/sound.h
+++ b/sys/dev/sound/pcm/sound.h
@@ -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)
diff --git a/sys/dev/sound/usb/uaudio.c b/sys/dev/sound/usb/uaudio.c
index f3a6de5..0855134 100644
--- a/sys/dev/sound/usb/uaudio.c
+++ b/sys/dev/sound/usb/uaudio.c
@@ -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--) {
OpenPOWER on IntegriCloud