diff options
author | hselasky <hselasky@FreeBSD.org> | 2015-06-03 15:32:43 +0000 |
---|---|---|
committer | hselasky <hselasky@FreeBSD.org> | 2015-06-03 15:32:43 +0000 |
commit | 79cd6230a5ab8914948a63f3edd0eb3baae36865 (patch) | |
tree | 3d2dd1d36683dc01586692410c01bd4910fb4cf3 /sys/dev/sound | |
parent | 02441119bc168497d2df4672b0666f72aa513093 (diff) | |
download | FreeBSD-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.c | 147 | ||||
-rw-r--r-- | sys/dev/sound/pcm/channel.h | 1 | ||||
-rw-r--r-- | sys/dev/sound/pcm/feeder_chain.c | 35 | ||||
-rw-r--r-- | sys/dev/sound/pcm/sound.h | 8 | ||||
-rw-r--r-- | sys/dev/sound/usb/uaudio.c | 41 |
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--) { |