diff options
| author | Takashi Iwai <[email protected]> | 2018-04-02 19:50:41 +0200 | 
|---|---|---|
| committer | Takashi Iwai <[email protected]> | 2018-04-02 19:50:59 +0200 | 
| commit | bc334cb61b9ee6e85b9bb01519989a3ae8fe03f6 (patch) | |
| tree | 34424a812537fe11beeee727b30b19c67193fe36 /sound/usb/format.c | |
| parent | 5607dddbfca774fb38bffadcb077fe03aa4ac5c6 (diff) | |
| parent | b44d419b98fae759b4f746186b1d1c8d01d962f2 (diff) | |
Merge branch 'for-next' into for-linus
Preparation for 4.17 merge.
Signed-off-by: Takashi Iwai <[email protected]>
Diffstat (limited to 'sound/usb/format.c')
| -rw-r--r-- | sound/usb/format.c | 93 | 
1 files changed, 76 insertions, 17 deletions
diff --git a/sound/usb/format.c b/sound/usb/format.c index 2c44386e5569..49e7ec6d2399 100644 --- a/sound/usb/format.c +++ b/sound/usb/format.c @@ -20,6 +20,7 @@  #include <linux/usb.h>  #include <linux/usb/audio.h>  #include <linux/usb/audio-v2.h> +#include <linux/usb/audio-v3.h>  #include <sound/core.h>  #include <sound/pcm.h> @@ -39,11 +40,11 @@   * @dev: usb device   * @fp: audioformat record   * @format: the format tag (wFormatTag) - * @fmt: the format type descriptor + * @fmt: the format type descriptor (v1/v2) or AudioStreaming descriptor (v3)   */  static u64 parse_audio_format_i_type(struct snd_usb_audio *chip,  				     struct audioformat *fp, -				     unsigned int format, void *_fmt) +				     u64 format, void *_fmt)  {  	int sample_width, sample_bytes;  	u64 pcm_formats = 0; @@ -54,7 +55,7 @@ static u64 parse_audio_format_i_type(struct snd_usb_audio *chip,  		struct uac_format_type_i_discrete_descriptor *fmt = _fmt;  		sample_width = fmt->bBitResolution;  		sample_bytes = fmt->bSubframeSize; -		format = 1 << format; +		format = 1ULL << format;  		break;  	} @@ -69,6 +70,18 @@ static u64 parse_audio_format_i_type(struct snd_usb_audio *chip,  		format <<= 1;  		break;  	} +	case UAC_VERSION_3: { +		struct uac3_as_header_descriptor *as = _fmt; + +		sample_width = as->bBitResolution; +		sample_bytes = as->bSubslotSize; + +		if (format & UAC3_FORMAT_TYPE_I_RAW_DATA) +			pcm_formats |= SNDRV_PCM_FMTBIT_SPECIAL; + +		format <<= 1; +		break; +	}  	}  	if ((pcm_formats == 0) && @@ -137,7 +150,7 @@ static u64 parse_audio_format_i_type(struct snd_usb_audio *chip,  	}  	if (format & ~0x3f) {  		usb_audio_info(chip, -			 "%u:%d : unsupported format bits %#x\n", +			 "%u:%d : unsupported format bits %#llx\n",  			 fp->iface, fp->altsetting, format);  	} @@ -281,15 +294,16 @@ static int parse_uac2_sample_rate_range(struct snd_usb_audio *chip,  /*   * parse the format descriptor and stores the possible sample rates - * on the audioformat table (audio class v2). + * on the audioformat table (audio class v2 and v3).   */ -static int parse_audio_format_rates_v2(struct snd_usb_audio *chip, +static int parse_audio_format_rates_v2v3(struct snd_usb_audio *chip,  				       struct audioformat *fp)  {  	struct usb_device *dev = chip->dev;  	unsigned char tmp[2], *data;  	int nr_triplets, data_size, ret = 0; -	int clock = snd_usb_clock_find_source(chip, fp->clock, false); +	int clock = snd_usb_clock_find_source(chip, fp->protocol, +					      fp->clock, false);  	if (clock < 0) {  		dev_err(&dev->dev, @@ -368,13 +382,30 @@ err:   * parse the format type I and III descriptors   */  static int parse_audio_format_i(struct snd_usb_audio *chip, -				struct audioformat *fp, unsigned int format, -				struct uac_format_type_i_continuous_descriptor *fmt) +				struct audioformat *fp, u64 format, +				void *_fmt)  {  	snd_pcm_format_t pcm_format; +	unsigned int fmt_type;  	int ret; -	if (fmt->bFormatType == UAC_FORMAT_TYPE_III) { +	switch (fp->protocol) { +	default: +	case UAC_VERSION_1: +	case UAC_VERSION_2: { +		struct uac_format_type_i_continuous_descriptor *fmt = _fmt; + +		fmt_type = fmt->bFormatType; +		break; +	} +	case UAC_VERSION_3: { +		/* fp->fmt_type is already set in this case */ +		fmt_type = fp->fmt_type; +		break; +	} +	} + +	if (fmt_type == UAC_FORMAT_TYPE_III) {  		/* FIXME: the format type is really IECxxx  		 *        but we give normal PCM format to get the existing  		 *        apps working... @@ -393,7 +424,7 @@ static int parse_audio_format_i(struct snd_usb_audio *chip,  		}  		fp->formats = pcm_format_to_bits(pcm_format);  	} else { -		fp->formats = parse_audio_format_i_type(chip, fp, format, fmt); +		fp->formats = parse_audio_format_i_type(chip, fp, format, _fmt);  		if (!fp->formats)  			return -EINVAL;  	} @@ -405,15 +436,20 @@ static int parse_audio_format_i(struct snd_usb_audio *chip,  	 */  	switch (fp->protocol) {  	default: -	case UAC_VERSION_1: +	case UAC_VERSION_1: { +		struct uac_format_type_i_continuous_descriptor *fmt = _fmt; +  		fp->channels = fmt->bNrChannels;  		ret = parse_audio_format_rates_v1(chip, fp, (unsigned char *) fmt, 7);  		break; +	}  	case UAC_VERSION_2: +	case UAC_VERSION_3: {  		/* fp->channels is already set in this case */ -		ret = parse_audio_format_rates_v2(chip, fp); +		ret = parse_audio_format_rates_v2v3(chip, fp);  		break;  	} +	}  	if (fp->channels < 1) {  		usb_audio_err(chip, @@ -430,7 +466,7 @@ static int parse_audio_format_i(struct snd_usb_audio *chip,   */  static int parse_audio_format_ii(struct snd_usb_audio *chip,  				 struct audioformat *fp, -				 int format, void *_fmt) +				 u64 format, void *_fmt)  {  	int brate, framesize, ret; @@ -445,7 +481,7 @@ static int parse_audio_format_ii(struct snd_usb_audio *chip,  		break;  	default:  		usb_audio_info(chip, -			 "%u:%d : unknown format tag %#x is detected.  processed as MPEG.\n", +			 "%u:%d : unknown format tag %#llx is detected.  processed as MPEG.\n",  			 fp->iface, fp->altsetting, format);  		fp->formats = SNDRV_PCM_FMTBIT_MPEG;  		break; @@ -470,7 +506,7 @@ static int parse_audio_format_ii(struct snd_usb_audio *chip,  		framesize = le16_to_cpu(fmt->wSamplesPerFrame);  		usb_audio_info(chip, "found format II with max.bitrate = %d, frame size=%d\n", brate, framesize);  		fp->frame_size = framesize; -		ret = parse_audio_format_rates_v2(chip, fp); +		ret = parse_audio_format_rates_v2v3(chip, fp);  		break;  	}  	} @@ -479,7 +515,7 @@ static int parse_audio_format_ii(struct snd_usb_audio *chip,  }  int snd_usb_parse_audio_format(struct snd_usb_audio *chip, -			       struct audioformat *fp, unsigned int format, +			       struct audioformat *fp, u64 format,  			       struct uac_format_type_i_continuous_descriptor *fmt,  			       int stream)  { @@ -520,3 +556,26 @@ int snd_usb_parse_audio_format(struct snd_usb_audio *chip,  	return 0;  } +int snd_usb_parse_audio_format_v3(struct snd_usb_audio *chip, +			       struct audioformat *fp, +			       struct uac3_as_header_descriptor *as, +			       int stream) +{ +	u64 format = le64_to_cpu(as->bmFormats); +	int err; + +	/* +	 * Type I format bits are D0..D6 +	 * This test works because type IV is not supported +	 */ +	if (format & 0x7f) +		fp->fmt_type = UAC_FORMAT_TYPE_I; +	else +		fp->fmt_type = UAC_FORMAT_TYPE_III; + +	err = parse_audio_format_i(chip, fp, format, as); +	if (err < 0) +		return err; + +	return 0; +}  |