svn commit: r283950 - in stable/10/sys: dev/sound/pcm dev/sound/usb sys

Hans Petter Selasky hselasky at FreeBSD.org
Wed Jun 3 15:32:45 UTC 2015


Author: hselasky
Date: Wed Jun  3 15:32:43 2015
New Revision: 283950
URL: https://svnweb.freebsd.org/changeset/base/283950

Log:
  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.

Modified:
  stable/10/sys/dev/sound/pcm/channel.c
  stable/10/sys/dev/sound/pcm/channel.h
  stable/10/sys/dev/sound/pcm/feeder_chain.c
  stable/10/sys/dev/sound/pcm/sound.h
  stable/10/sys/dev/sound/usb/uaudio.c
  stable/10/sys/sys/param.h
Directory Properties:
  stable/10/   (props changed)

Modified: stable/10/sys/dev/sound/pcm/channel.c
==============================================================================
--- stable/10/sys/dev/sound/pcm/channel.c	Wed Jun  3 15:18:32 2015	(r283949)
+++ stable/10/sys/dev/sound/pcm/channel.c	Wed Jun  3 15:32:43 2015	(r283950)
@@ -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));
-		}
-	}
+	i = sscanf(b2, "%d.%d", &ch, &ext);
 
-	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);
-
-	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

Modified: stable/10/sys/dev/sound/pcm/channel.h
==============================================================================
--- stable/10/sys/dev/sound/pcm/channel.h	Wed Jun  3 15:18:32 2015	(r283949)
+++ stable/10/sys/dev/sound/pcm/channel.h	Wed Jun  3 15:32:43 2015	(r283950)
@@ -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];
 

Modified: stable/10/sys/dev/sound/pcm/feeder_chain.c
==============================================================================
--- stable/10/sys/dev/sound/pcm/feeder_chain.c	Wed Jun  3 15:18:32 2015	(r283949)
+++ stable/10/sys/dev/sound/pcm/feeder_chain.c	Wed Jun  3 15:32:43 2015	(r283950)
@@ -562,6 +562,20 @@ feeder_build_mixer(struct pcm_channel *c
 	((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)

Modified: stable/10/sys/dev/sound/pcm/sound.h
==============================================================================
--- stable/10/sys/dev/sound/pcm/sound.h	Wed Jun  3 15:18:32 2015	(r283949)
+++ stable/10/sys/dev/sound/pcm/sound.h	Wed Jun  3 15:32:43 2015	(r283950)
@@ -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)
 

Modified: stable/10/sys/dev/sound/usb/uaudio.c
==============================================================================
--- stable/10/sys/dev/sound/usb/uaudio.c	Wed Jun  3 15:18:32 2015	(r283949)
+++ stable/10/sys/dev/sound/usb/uaudio.c	Wed Jun  3 15:32:43 2015	(r283950)
@@ -121,6 +121,8 @@ SYSCTL_INT(_hw_usb_uaudio, OID_AUTO, def
 #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_cla
 		 */
 		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_
 
 		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_
 		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_soft
 			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--) {

Modified: stable/10/sys/sys/param.h
==============================================================================
--- stable/10/sys/sys/param.h	Wed Jun  3 15:18:32 2015	(r283949)
+++ stable/10/sys/sys/param.h	Wed Jun  3 15:32:43 2015	(r283950)
@@ -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,


More information about the svn-src-all mailing list