2019-05-27 09:55:05 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
2010-03-04 21:46:13 +03:00
/*
*/
# include <linux/init.h>
2010-03-29 09:02:50 +04:00
# include <linux/slab.h>
2010-03-04 21:46:13 +03:00
# include <linux/usb.h>
# include <linux/usb/audio.h>
2010-03-11 23:13:20 +03:00
# include <linux/usb/audio-v2.h>
2018-03-21 03:03:59 +03:00
# include <linux/usb/audio-v3.h>
2010-03-04 21:46:13 +03:00
# include <sound/core.h>
# include <sound/pcm.h>
# include "usbaudio.h"
# include "card.h"
# include "quirks.h"
# include "helper.h"
2010-05-31 16:51:31 +04:00
# include "clock.h"
2011-05-18 13:28:40 +04:00
# include "format.h"
2010-03-04 21:46:13 +03:00
/*
* parse the audio format type I descriptor
* and returns the corresponding pcm format
*
* @ dev : usb device
* @ fp : audioformat record
* @ format : the format tag ( wFormatTag )
2018-03-21 03:03:59 +03:00
* @ fmt : the format type descriptor ( v1 / v2 ) or AudioStreaming descriptor ( v3 )
2010-03-04 21:46:13 +03:00
*/
2010-03-04 21:46:16 +03:00
static u64 parse_audio_format_i_type ( struct snd_usb_audio * chip ,
2010-03-04 21:46:13 +03:00
struct audioformat * fp ,
2018-03-21 03:03:59 +03:00
u64 format , void * _fmt )
2010-03-04 21:46:13 +03:00
{
int sample_width , sample_bytes ;
2013-03-17 16:07:25 +04:00
u64 pcm_formats = 0 ;
2010-03-04 21:46:13 +03:00
2013-02-01 00:39:17 +04:00
switch ( fp - > protocol ) {
2010-09-03 12:53:11 +04:00
case UAC_VERSION_1 :
default : {
2010-03-04 21:46:13 +03:00
struct uac_format_type_i_discrete_descriptor * fmt = _fmt ;
2020-12-09 11:45:51 +03:00
if ( format > = 64 )
return 0 ; /* invalid format */
2010-03-04 21:46:13 +03:00
sample_width = fmt - > bBitResolution ;
sample_bytes = fmt - > bSubframeSize ;
2018-03-29 12:03:19 +03:00
format = 1ULL < < format ;
2010-03-04 21:46:13 +03:00
break ;
}
case UAC_VERSION_2 : {
struct uac_format_type_i_ext_descriptor * fmt = _fmt ;
sample_width = fmt - > bBitResolution ;
sample_bytes = fmt - > bSubslotSize ;
2013-03-17 16:07:25 +04:00
2018-06-13 01:43:01 +03:00
if ( format & UAC2_FORMAT_TYPE_I_RAW_DATA ) {
2013-03-17 16:07:25 +04:00
pcm_formats | = SNDRV_PCM_FMTBIT_SPECIAL ;
2018-06-13 01:43:01 +03:00
/* flag potentially raw DSD capable altsettings */
fp - > dsd_raw = true ;
}
2013-03-17 16:07:25 +04:00
2010-03-04 21:46:16 +03:00
format < < = 1 ;
2010-03-04 21:46:13 +03:00
break ;
}
2018-03-21 03:03:59 +03:00
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 ;
}
2010-03-04 21:46:13 +03:00
}
2019-02-18 01:17:21 +03:00
fp - > fmt_bits = sample_width ;
2013-03-17 16:07:25 +04:00
if ( ( pcm_formats = = 0 ) & &
( format = = 0 | | format = = ( 1 < < UAC_FORMAT_TYPE_I_UNDEFINED ) ) ) {
2010-03-04 21:46:16 +03:00
/* some devices don't define this correctly... */
2014-02-26 16:02:17 +04:00
usb_audio_info ( chip , " %u:%d : format type 0 is detected, processed as PCM \n " ,
fp - > iface , fp - > altsetting ) ;
2010-03-04 21:46:16 +03:00
format = 1 < < UAC_FORMAT_TYPE_I_PCM ;
}
if ( format & ( 1 < < UAC_FORMAT_TYPE_I_PCM ) ) {
2015-04-21 05:23:57 +03:00
if ( ( ( chip - > usb_id = = USB_ID ( 0x0582 , 0x0016 ) ) | |
/* Edirol SD-90 */
( chip - > usb_id = = USB_ID ( 0x0582 , 0x000c ) ) ) & &
/* Roland SC-D70 */
2011-01-10 18:30:54 +03:00
sample_width = = 24 & & sample_bytes = = 2 )
sample_bytes = 3 ;
else if ( sample_width > sample_bytes * 8 ) {
2014-02-26 16:02:17 +04:00
usb_audio_info ( chip , " %u:%d : sample bitwidth %d in over sample bytes %d \n " ,
fp - > iface , fp - > altsetting ,
sample_width , sample_bytes ) ;
2010-03-04 21:46:13 +03:00
}
/* check the format byte size */
switch ( sample_bytes ) {
case 1 :
2010-03-04 21:46:16 +03:00
pcm_formats | = SNDRV_PCM_FMTBIT_S8 ;
2010-03-04 21:46:13 +03:00
break ;
case 2 :
if ( snd_usb_is_big_endian_format ( chip , fp ) )
2010-03-04 21:46:16 +03:00
pcm_formats | = SNDRV_PCM_FMTBIT_S16_BE ; /* grrr, big endian!! */
2010-03-04 21:46:13 +03:00
else
2010-03-04 21:46:16 +03:00
pcm_formats | = SNDRV_PCM_FMTBIT_S16_LE ;
2010-03-04 21:46:13 +03:00
break ;
case 3 :
if ( snd_usb_is_big_endian_format ( chip , fp ) )
2010-03-04 21:46:16 +03:00
pcm_formats | = SNDRV_PCM_FMTBIT_S24_3BE ; /* grrr, big endian!! */
2010-03-04 21:46:13 +03:00
else
2010-03-04 21:46:16 +03:00
pcm_formats | = SNDRV_PCM_FMTBIT_S24_3LE ;
2010-03-04 21:46:13 +03:00
break ;
case 4 :
2010-03-04 21:46:16 +03:00
pcm_formats | = SNDRV_PCM_FMTBIT_S32_LE ;
2010-03-04 21:46:13 +03:00
break ;
default :
2014-02-26 16:02:17 +04:00
usb_audio_info ( chip ,
" %u:%d : unsupported sample bitwidth %d in %d bytes \n " ,
fp - > iface , fp - > altsetting ,
sample_width , sample_bytes ) ;
2010-03-04 21:46:13 +03:00
break ;
}
2010-03-04 21:46:16 +03:00
}
if ( format & ( 1 < < UAC_FORMAT_TYPE_I_PCM8 ) ) {
2010-03-04 21:46:13 +03:00
/* Dallas DS4201 workaround: it advertises U8 format, but really
supports S8 . */
if ( chip - > usb_id = = USB_ID ( 0x04fa , 0x4201 ) )
2010-03-04 21:46:16 +03:00
pcm_formats | = SNDRV_PCM_FMTBIT_S8 ;
else
pcm_formats | = SNDRV_PCM_FMTBIT_U8 ;
}
if ( format & ( 1 < < UAC_FORMAT_TYPE_I_IEEE_FLOAT ) ) {
pcm_formats | = SNDRV_PCM_FMTBIT_FLOAT_LE ;
}
if ( format & ( 1 < < UAC_FORMAT_TYPE_I_ALAW ) ) {
pcm_formats | = SNDRV_PCM_FMTBIT_A_LAW ;
}
if ( format & ( 1 < < UAC_FORMAT_TYPE_I_MULAW ) ) {
pcm_formats | = SNDRV_PCM_FMTBIT_MU_LAW ;
}
if ( format & ~ 0x3f ) {
2014-02-26 16:02:17 +04:00
usb_audio_info ( chip ,
2018-03-21 03:03:59 +03:00
" %u:%d : unsupported format bits %#llx \n " ,
2014-02-26 16:02:17 +04:00
fp - > iface , fp - > altsetting , format ) ;
2010-03-04 21:46:13 +03:00
}
2013-04-16 20:01:40 +04:00
pcm_formats | = snd_usb_interface_dsd_format_quirks ( chip , fp , sample_bytes ) ;
2010-03-04 21:46:16 +03:00
return pcm_formats ;
2010-03-04 21:46:13 +03:00
}
2020-02-11 14:14:19 +03:00
static int set_fixed_rate ( struct audioformat * fp , int rate , int rate_bits )
{
kfree ( fp - > rate_table ) ;
fp - > rate_table = kmalloc ( sizeof ( int ) , GFP_KERNEL ) ;
if ( ! fp - > rate_table )
return - ENOMEM ;
fp - > nr_rates = 1 ;
fp - > rate_min = rate ;
fp - > rate_max = rate ;
fp - > rates = rate_bits ;
fp - > rate_table [ 0 ] = rate ;
return 0 ;
}
2010-03-04 21:46:13 +03:00
2020-11-23 11:53:38 +03:00
/* set up rate_min, rate_max and rates from the rate table */
static void set_rate_table_min_max ( struct audioformat * fp )
{
unsigned int rate ;
int i ;
fp - > rate_min = INT_MAX ;
fp - > rate_max = 0 ;
fp - > rates = 0 ;
for ( i = 0 ; i < fp - > nr_rates ; i + + ) {
rate = fp - > rate_table [ i ] ;
fp - > rate_min = min ( fp - > rate_min , rate ) ;
fp - > rate_max = max ( fp - > rate_max , rate ) ;
fp - > rates | = snd_pcm_rate_to_rate_bit ( rate ) ;
}
}
2010-03-04 21:46:13 +03:00
/*
* parse the format descriptor and stores the possible sample rates
* on the audioformat table ( audio class v1 ) .
*
* @ dev : usb device
* @ fp : audioformat record
* @ fmt : the format descriptor
* @ offset : the start offset of descriptor pointing the rate type
* ( 7 for type I and II , 8 for type II )
*/
static int parse_audio_format_rates_v1 ( struct snd_usb_audio * chip , struct audioformat * fp ,
unsigned char * fmt , int offset )
{
int nr_rates = fmt [ offset ] ;
if ( fmt [ 0 ] < offset + 1 + 3 * ( nr_rates ? nr_rates : 2 ) ) {
2014-02-26 16:02:17 +04:00
usb_audio_err ( chip ,
" %u:%d : invalid UAC_FORMAT_TYPE desc \n " ,
fp - > iface , fp - > altsetting ) ;
2012-11-21 13:55:56 +04:00
return - EINVAL ;
2010-03-04 21:46:13 +03:00
}
if ( nr_rates ) {
/*
* build the rate table and bitmap flags
*/
int r , idx ;
treewide: kmalloc() -> kmalloc_array()
The kmalloc() function has a 2-factor argument form, kmalloc_array(). This
patch replaces cases of:
kmalloc(a * b, gfp)
with:
kmalloc_array(a * b, gfp)
as well as handling cases of:
kmalloc(a * b * c, gfp)
with:
kmalloc(array3_size(a, b, c), gfp)
as it's slightly less ugly than:
kmalloc_array(array_size(a, b), c, gfp)
This does, however, attempt to ignore constant size factors like:
kmalloc(4 * 1024, gfp)
though any constants defined via macros get caught up in the conversion.
Any factors with a sizeof() of "unsigned char", "char", and "u8" were
dropped, since they're redundant.
The tools/ directory was manually excluded, since it has its own
implementation of kmalloc().
The Coccinelle script used for this was:
// Fix redundant parens around sizeof().
@@
type TYPE;
expression THING, E;
@@
(
kmalloc(
- (sizeof(TYPE)) * E
+ sizeof(TYPE) * E
, ...)
|
kmalloc(
- (sizeof(THING)) * E
+ sizeof(THING) * E
, ...)
)
// Drop single-byte sizes and redundant parens.
@@
expression COUNT;
typedef u8;
typedef __u8;
@@
(
kmalloc(
- sizeof(u8) * (COUNT)
+ COUNT
, ...)
|
kmalloc(
- sizeof(__u8) * (COUNT)
+ COUNT
, ...)
|
kmalloc(
- sizeof(char) * (COUNT)
+ COUNT
, ...)
|
kmalloc(
- sizeof(unsigned char) * (COUNT)
+ COUNT
, ...)
|
kmalloc(
- sizeof(u8) * COUNT
+ COUNT
, ...)
|
kmalloc(
- sizeof(__u8) * COUNT
+ COUNT
, ...)
|
kmalloc(
- sizeof(char) * COUNT
+ COUNT
, ...)
|
kmalloc(
- sizeof(unsigned char) * COUNT
+ COUNT
, ...)
)
// 2-factor product with sizeof(type/expression) and identifier or constant.
@@
type TYPE;
expression THING;
identifier COUNT_ID;
constant COUNT_CONST;
@@
(
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * (COUNT_ID)
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * COUNT_ID
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * (COUNT_CONST)
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * COUNT_CONST
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * (COUNT_ID)
+ COUNT_ID, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * COUNT_ID
+ COUNT_ID, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * (COUNT_CONST)
+ COUNT_CONST, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * COUNT_CONST
+ COUNT_CONST, sizeof(THING)
, ...)
)
// 2-factor product, only identifiers.
@@
identifier SIZE, COUNT;
@@
- kmalloc
+ kmalloc_array
(
- SIZE * COUNT
+ COUNT, SIZE
, ...)
// 3-factor product with 1 sizeof(type) or sizeof(expression), with
// redundant parens removed.
@@
expression THING;
identifier STRIDE, COUNT;
type TYPE;
@@
(
kmalloc(
- sizeof(TYPE) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kmalloc(
- sizeof(TYPE) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kmalloc(
- sizeof(TYPE) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kmalloc(
- sizeof(TYPE) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kmalloc(
- sizeof(THING) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kmalloc(
- sizeof(THING) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kmalloc(
- sizeof(THING) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kmalloc(
- sizeof(THING) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
)
// 3-factor product with 2 sizeof(variable), with redundant parens removed.
@@
expression THING1, THING2;
identifier COUNT;
type TYPE1, TYPE2;
@@
(
kmalloc(
- sizeof(TYPE1) * sizeof(TYPE2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
kmalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
kmalloc(
- sizeof(THING1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
kmalloc(
- sizeof(THING1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
kmalloc(
- sizeof(TYPE1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
|
kmalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
)
// 3-factor product, only identifiers, with redundant parens removed.
@@
identifier STRIDE, SIZE, COUNT;
@@
(
kmalloc(
- (COUNT) * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- COUNT * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- COUNT * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- (COUNT) * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- COUNT * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- (COUNT) * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- (COUNT) * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- COUNT * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
)
// Any remaining multi-factor products, first at least 3-factor products,
// when they're not all constants...
@@
expression E1, E2, E3;
constant C1, C2, C3;
@@
(
kmalloc(C1 * C2 * C3, ...)
|
kmalloc(
- (E1) * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
|
kmalloc(
- (E1) * (E2) * E3
+ array3_size(E1, E2, E3)
, ...)
|
kmalloc(
- (E1) * (E2) * (E3)
+ array3_size(E1, E2, E3)
, ...)
|
kmalloc(
- E1 * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
)
// And then all remaining 2 factors products when they're not all constants,
// keeping sizeof() as the second factor argument.
@@
expression THING, E1, E2;
type TYPE;
constant C1, C2, C3;
@@
(
kmalloc(sizeof(THING) * C2, ...)
|
kmalloc(sizeof(TYPE) * C2, ...)
|
kmalloc(C1 * C2 * C3, ...)
|
kmalloc(C1 * C2, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * (E2)
+ E2, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * E2
+ E2, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * (E2)
+ E2, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * E2
+ E2, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- (E1) * E2
+ E1, E2
, ...)
|
- kmalloc
+ kmalloc_array
(
- (E1) * (E2)
+ E1, E2
, ...)
|
- kmalloc
+ kmalloc_array
(
- E1 * E2
+ E1, E2
, ...)
)
Signed-off-by: Kees Cook <keescook@chromium.org>
2018-06-12 23:55:00 +03:00
fp - > rate_table = kmalloc_array ( nr_rates , sizeof ( int ) ,
GFP_KERNEL ) ;
2016-08-21 05:17:36 +03:00
if ( fp - > rate_table = = NULL )
2012-11-21 13:55:56 +04:00
return - ENOMEM ;
2010-03-04 21:46:13 +03:00
fp - > nr_rates = 0 ;
for ( r = 0 , idx = offset + 1 ; r < nr_rates ; r + + , idx + = 3 ) {
unsigned int rate = combine_triple ( & fmt [ idx ] ) ;
if ( ! rate )
continue ;
/* C-Media CM6501 mislabels its 96 kHz altsetting */
2011-04-28 18:18:40 +04:00
/* Terratec Aureon 7.1 USB C-Media 6206, too */
2010-03-04 21:46:13 +03:00
if ( rate = = 48000 & & nr_rates = = 1 & &
( chip - > usb_id = = USB_ID ( 0x0d8c , 0x0201 ) | |
2011-04-28 18:18:40 +04:00
chip - > usb_id = = USB_ID ( 0x0d8c , 0x0102 ) | |
chip - > usb_id = = USB_ID ( 0x0ccd , 0x00b1 ) ) & &
2010-03-04 21:46:13 +03:00
fp - > altsetting = = 5 & & fp - > maxpacksize = = 392 )
rate = 96000 ;
2014-01-14 16:42:57 +04:00
/* Creative VF0420/VF0470 Live Cams report 16 kHz instead of 8kHz */
if ( rate = = 16000 & &
( chip - > usb_id = = USB_ID ( 0x041e , 0x4064 ) | |
chip - > usb_id = = USB_ID ( 0x041e , 0x4068 ) ) )
2010-03-04 21:46:13 +03:00
rate = 8000 ;
2020-11-23 11:53:38 +03:00
fp - > rate_table [ fp - > nr_rates + + ] = rate ;
2010-03-04 21:46:13 +03:00
}
if ( ! fp - > nr_rates ) {
2020-11-23 11:53:18 +03:00
usb_audio_info ( chip ,
" %u:%d: All rates were zero \n " ,
fp - > iface , fp - > altsetting ) ;
2012-11-21 13:55:56 +04:00
return - EINVAL ;
2010-03-04 21:46:13 +03:00
}
2020-11-23 11:53:38 +03:00
set_rate_table_min_max ( fp ) ;
2010-03-04 21:46:13 +03:00
} else {
/* continuous rates */
fp - > rates = SNDRV_PCM_RATE_CONTINUOUS ;
fp - > rate_min = combine_triple ( & fmt [ offset + 1 ] ) ;
fp - > rate_max = combine_triple ( & fmt [ offset + 4 ] ) ;
}
2020-02-11 14:14:19 +03:00
/* Jabra Evolve 65 headset */
if ( chip - > usb_id = = USB_ID ( 0x0b0e , 0x030b ) ) {
/* only 48kHz for playback while keeping 16kHz for capture */
if ( fp - > nr_rates ! = 1 )
return set_fixed_rate ( fp , 48000 , SNDRV_PCM_RATE_48000 ) ;
}
2010-03-04 21:46:13 +03:00
return 0 ;
}
2020-02-15 04:23:35 +03:00
/*
* Presonus Studio 1810 c supports a limited set of sampling
* rates per altsetting but reports the full set each time .
* If we don ' t filter out the unsupported rates and attempt
* to configure the card , it will hang refusing to do any
* further audio I / O until a hard reset is performed .
*
* The list of supported rates per altsetting ( set of available
* I / O channels ) is described in the owner ' s manual , section 2.2 .
*/
static bool s1810c_valid_sample_rate ( struct audioformat * fp ,
unsigned int rate )
{
switch ( fp - > altsetting ) {
case 1 :
/* All ADAT ports available */
return rate < = 48000 ;
case 2 :
/* Half of ADAT ports available */
return ( rate = = 88200 | | rate = = 96000 ) ;
case 3 :
/* Analog I/O only (no S/PDIF nor ADAT) */
return rate > = 176400 ;
default :
return false ;
}
return false ;
}
2020-04-18 20:58:15 +03:00
/*
* Many Focusrite devices supports a limited set of sampling rates per
* altsetting . Maximum rate is exposed in the last 4 bytes of Format Type
* descriptor which has a non - standard bLength = 10.
*/
static bool focusrite_valid_sample_rate ( struct snd_usb_audio * chip ,
struct audioformat * fp ,
unsigned int rate )
{
struct usb_interface * iface ;
struct usb_host_interface * alts ;
unsigned char * fmt ;
unsigned int max_rate ;
iface = usb_ifnum_to_if ( chip - > dev , fp - > iface ) ;
if ( ! iface )
return true ;
alts = & iface - > altsetting [ fp - > altset_idx ] ;
fmt = snd_usb_find_csint_desc ( alts - > extra , alts - > extralen ,
NULL , UAC_FORMAT_TYPE ) ;
if ( ! fmt )
return true ;
if ( fmt [ 0 ] = = 10 ) { /* bLength */
max_rate = combine_quad ( & fmt [ 6 ] ) ;
/* Validate max rate */
if ( max_rate ! = 48000 & &
max_rate ! = 96000 & &
max_rate ! = 192000 & &
max_rate ! = 384000 ) {
usb_audio_info ( chip ,
" %u:%d : unexpected max rate: %u \n " ,
fp - > iface , fp - > altsetting , max_rate ) ;
return true ;
}
return rate < = max_rate ;
}
return true ;
}
2010-06-11 19:46:33 +04:00
/*
* Helper function to walk the array of sample rate triplets reported by
* the device . The problem is that we need to parse whole array first to
* get to know how many sample rates we have to expect .
* Then fp - > rate_table can be allocated and filled .
*/
2014-02-26 16:02:17 +04:00
static int parse_uac2_sample_rate_range ( struct snd_usb_audio * chip ,
struct audioformat * fp , int nr_triplets ,
2010-06-11 19:46:33 +04:00
const unsigned char * data )
{
int i , nr_rates = 0 ;
for ( i = 0 ; i < nr_triplets ; i + + ) {
int min = combine_quad ( & data [ 2 + 12 * i ] ) ;
int max = combine_quad ( & data [ 6 + 12 * i ] ) ;
int res = combine_quad ( & data [ 10 + 12 * i ] ) ;
2012-01-08 18:02:52 +04:00
unsigned int rate ;
2010-06-11 19:46:33 +04:00
if ( ( max < 0 ) | | ( min < 0 ) | | ( res < 0 ) | | ( max < min ) )
continue ;
/*
* for ranges with res = = 1 , we announce a continuous sample
* rate range , and this function should return 0 for no further
* parsing .
*/
if ( res = = 1 ) {
fp - > rate_min = min ;
fp - > rate_max = max ;
fp - > rates = SNDRV_PCM_RATE_CONTINUOUS ;
return 0 ;
}
for ( rate = min ; rate < = max ; rate + = res ) {
2020-02-15 04:23:35 +03:00
/* Filter out invalid rates on Presonus Studio 1810c */
if ( chip - > usb_id = = USB_ID ( 0x0194f , 0x010c ) & &
! s1810c_valid_sample_rate ( fp , rate ) )
goto skip_rate ;
2020-04-18 20:58:15 +03:00
/* Filter out invalid rates on Focusrite devices */
if ( USB_ID_VENDOR ( chip - > usb_id ) = = 0x1235 & &
! focusrite_valid_sample_rate ( chip , fp , rate ) )
goto skip_rate ;
2010-06-11 19:46:33 +04:00
if ( fp - > rate_table )
fp - > rate_table [ nr_rates ] = rate ;
nr_rates + + ;
2012-02-14 14:18:48 +04:00
if ( nr_rates > = MAX_NR_RATES ) {
2014-02-26 16:02:17 +04:00
usb_audio_err ( chip , " invalid uac2 rates \n " ) ;
2012-01-08 18:02:52 +04:00
break ;
}
2010-06-11 19:46:33 +04:00
2020-02-15 04:23:35 +03:00
skip_rate :
2010-06-11 19:46:33 +04:00
/* avoid endless loop */
if ( res = = 0 )
break ;
}
}
return nr_rates ;
}
2020-06-15 03:11:47 +03:00
/* Line6 Helix series and the Rode Rodecaster Pro don't support the
* UAC2_CS_RANGE usb function call . Return a static table of known
* clock rates .
2019-07-07 11:27:34 +03:00
*/
static int line6_parse_audio_format_rates_quirk ( struct snd_usb_audio * chip ,
struct audioformat * fp )
{
switch ( chip - > usb_id ) {
2020-01-05 11:19:00 +03:00
case USB_ID ( 0x0e41 , 0x4241 ) : /* Line6 Helix */
case USB_ID ( 0x0e41 , 0x4242 ) : /* Line6 Helix Rack */
case USB_ID ( 0x0e41 , 0x4244 ) : /* Line6 Helix LT */
case USB_ID ( 0x0e41 , 0x4246 ) : /* Line6 HX-Stomp */
2020-10-20 09:14:09 +03:00
case USB_ID ( 0x0e41 , 0x4247 ) : /* Line6 Pod Go */
2020-01-26 11:31:34 +03:00
case USB_ID ( 0x0e41 , 0x4248 ) : /* Line6 Helix >= fw 2.82 */
case USB_ID ( 0x0e41 , 0x4249 ) : /* Line6 Helix Rack >= fw 2.82 */
case USB_ID ( 0x0e41 , 0x424a ) : /* Line6 Helix LT >= fw 2.82 */
2020-06-15 03:11:47 +03:00
case USB_ID ( 0x19f7 , 0x0011 ) : /* Rode Rodecaster Pro */
2020-02-11 14:14:19 +03:00
return set_fixed_rate ( fp , 48000 , SNDRV_PCM_RATE_48000 ) ;
2019-07-07 11:27:34 +03:00
}
return - ENODEV ;
}
2020-11-23 11:53:09 +03:00
/* check whether the given altsetting is supported for the already set rate */
static bool check_valid_altsetting_v2v3 ( struct snd_usb_audio * chip , int iface ,
int altsetting )
{
struct usb_device * dev = chip - > dev ;
__le64 raw_data = 0 ;
u64 data ;
int err ;
/* we assume 64bit is enough for any altsettings */
if ( snd_BUG_ON ( altsetting > = 64 - 8 ) )
return false ;
2021-05-21 16:37:42 +03:00
err = snd_usb_ctl_msg ( dev , usb_rcvctrlpipe ( dev , 0 ) , UAC2_CS_CUR ,
2020-11-23 11:53:09 +03:00
USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN ,
UAC2_AS_VAL_ALT_SETTINGS < < 8 ,
iface , & raw_data , sizeof ( raw_data ) ) ;
if ( err < 0 )
return false ;
data = le64_to_cpu ( raw_data ) ;
/* first byte contains the bitmap size */
if ( ( data & 0xff ) * 8 < altsetting )
return false ;
if ( data & ( 1ULL < < ( altsetting + 8 ) ) )
return true ;
return false ;
}
/*
* Validate each sample rate with the altsetting
* Rebuild the rate table if only partial values are valid
*/
static int validate_sample_rate_table_v2v3 ( struct snd_usb_audio * chip ,
struct audioformat * fp ,
int clock )
{
struct usb_device * dev = chip - > dev ;
unsigned int * table ;
unsigned int nr_rates ;
int i , err ;
2021-01-23 18:58:42 +03:00
/* performing the rate verification may lead to unexpected USB bus
* behavior afterwards by some unknown reason . Do this only for the
* known devices .
*/
switch ( USB_ID_VENDOR ( chip - > usb_id ) ) {
case 0x07fd : /* MOTU */
break ;
default :
return 0 ; /* don't perform the validation as default */
}
2020-11-23 11:53:09 +03:00
table = kcalloc ( fp - > nr_rates , sizeof ( * table ) , GFP_KERNEL ) ;
if ( ! table )
return - ENOMEM ;
/* clear the interface altsetting at first */
usb_set_interface ( dev , fp - > iface , 0 ) ;
nr_rates = 0 ;
for ( i = 0 ; i < fp - > nr_rates ; i + + ) {
err = snd_usb_set_sample_rate_v2v3 ( chip , fp , clock ,
fp - > rate_table [ i ] ) ;
if ( err < 0 )
continue ;
2020-11-23 11:53:38 +03:00
if ( check_valid_altsetting_v2v3 ( chip , fp - > iface , fp - > altsetting ) )
2020-11-23 11:53:09 +03:00
table [ nr_rates + + ] = fp - > rate_table [ i ] ;
}
if ( ! nr_rates ) {
usb_audio_dbg ( chip ,
" No valid sample rate available for %d:%d, assuming a firmware bug \n " ,
fp - > iface , fp - > altsetting ) ;
nr_rates = fp - > nr_rates ; /* continue as is */
}
if ( fp - > nr_rates = = nr_rates ) {
kfree ( table ) ;
return 0 ;
}
kfree ( fp - > rate_table ) ;
fp - > rate_table = table ;
fp - > nr_rates = nr_rates ;
return 0 ;
}
2010-03-04 21:46:13 +03:00
/*
* parse the format descriptor and stores the possible sample rates
2018-03-21 03:03:59 +03:00
* on the audioformat table ( audio class v2 and v3 ) .
2010-03-04 21:46:13 +03:00
*/
2018-03-21 03:03:59 +03:00
static int parse_audio_format_rates_v2v3 ( struct snd_usb_audio * chip ,
2010-06-16 19:57:31 +04:00
struct audioformat * fp )
2010-03-04 21:46:13 +03:00
{
struct usb_device * dev = chip - > dev ;
unsigned char tmp [ 2 ] , * data ;
2019-07-07 11:27:34 +03:00
int nr_triplets , data_size , ret = 0 , ret_l6 ;
2020-02-13 02:54:50 +03:00
int clock = snd_usb_clock_find_source ( chip , fp , false ) ;
2010-03-04 21:46:13 +03:00
2010-06-11 19:34:19 +04:00
if ( clock < 0 ) {
2014-02-26 16:02:17 +04:00
dev_err ( & dev - > dev ,
" %s(): unable to find clock source (clock %d) \n " ,
2010-06-11 19:34:19 +04:00
__func__ , clock ) ;
goto err ;
}
2010-03-04 21:46:13 +03:00
/* get the number of sample rates first by only fetching 2 bytes */
ret = snd_usb_ctl_msg ( dev , usb_rcvctrlpipe ( dev , 0 ) , UAC2_CS_RANGE ,
USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN ,
2010-06-11 19:34:20 +04:00
UAC2_CS_CONTROL_SAM_FREQ < < 8 ,
snd_usb_ctrl_intf ( chip ) | ( clock < < 8 ) ,
2011-09-26 23:15:27 +04:00
tmp , sizeof ( tmp ) ) ;
2010-03-04 21:46:13 +03:00
if ( ret < 0 ) {
2019-07-07 11:27:34 +03:00
/* line6 helix devices don't support UAC2_CS_CONTROL_SAM_FREQ call */
ret_l6 = line6_parse_audio_format_rates_quirk ( chip , fp ) ;
if ( ret_l6 = = - ENODEV ) {
/* no line6 device found continue showing the error */
dev_err ( & dev - > dev ,
" %s(): unable to retrieve number of sample rates (clock %d) \n " ,
__func__ , clock ) ;
goto err ;
}
if ( ret_l6 = = 0 ) {
dev_info ( & dev - > dev ,
" %s(): unable to retrieve number of sample rates: set it to a predefined value (clock %d). \n " ,
2010-05-31 16:51:31 +04:00
__func__ , clock ) ;
2019-07-07 11:27:34 +03:00
return 0 ;
}
ret = ret_l6 ;
2010-03-04 21:46:13 +03:00
goto err ;
}
2010-06-11 19:46:33 +04:00
nr_triplets = ( tmp [ 1 ] < < 8 ) | tmp [ 0 ] ;
data_size = 2 + 12 * nr_triplets ;
2010-03-04 21:46:13 +03:00
data = kzalloc ( data_size , GFP_KERNEL ) ;
if ( ! data ) {
ret = - ENOMEM ;
goto err ;
}
/* now get the full information */
ret = snd_usb_ctl_msg ( dev , usb_rcvctrlpipe ( dev , 0 ) , UAC2_CS_RANGE ,
2010-05-31 16:51:31 +04:00
USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN ,
2010-06-11 19:34:20 +04:00
UAC2_CS_CONTROL_SAM_FREQ < < 8 ,
snd_usb_ctrl_intf ( chip ) | ( clock < < 8 ) ,
2011-09-26 23:15:27 +04:00
data , data_size ) ;
2010-03-04 21:46:13 +03:00
if ( ret < 0 ) {
2014-02-26 16:02:17 +04:00
dev_err ( & dev - > dev ,
" %s(): unable to retrieve sample rate range (clock %d) \n " ,
2010-05-31 16:51:31 +04:00
__func__ , clock ) ;
2010-03-04 21:46:13 +03:00
ret = - EINVAL ;
goto err_free ;
}
2010-06-11 19:46:33 +04:00
/* Call the triplet parser, and make sure fp->rate_table is NULL.
* We just use the return value to know how many sample rates we
* will have to deal with . */
kfree ( fp - > rate_table ) ;
fp - > rate_table = NULL ;
2014-02-26 16:02:17 +04:00
fp - > nr_rates = parse_uac2_sample_rate_range ( chip , fp , nr_triplets , data ) ;
2010-06-11 19:46:33 +04:00
if ( fp - > nr_rates = = 0 ) {
/* SNDRV_PCM_RATE_CONTINUOUS */
ret = 0 ;
goto err_free ;
}
treewide: kmalloc() -> kmalloc_array()
The kmalloc() function has a 2-factor argument form, kmalloc_array(). This
patch replaces cases of:
kmalloc(a * b, gfp)
with:
kmalloc_array(a * b, gfp)
as well as handling cases of:
kmalloc(a * b * c, gfp)
with:
kmalloc(array3_size(a, b, c), gfp)
as it's slightly less ugly than:
kmalloc_array(array_size(a, b), c, gfp)
This does, however, attempt to ignore constant size factors like:
kmalloc(4 * 1024, gfp)
though any constants defined via macros get caught up in the conversion.
Any factors with a sizeof() of "unsigned char", "char", and "u8" were
dropped, since they're redundant.
The tools/ directory was manually excluded, since it has its own
implementation of kmalloc().
The Coccinelle script used for this was:
// Fix redundant parens around sizeof().
@@
type TYPE;
expression THING, E;
@@
(
kmalloc(
- (sizeof(TYPE)) * E
+ sizeof(TYPE) * E
, ...)
|
kmalloc(
- (sizeof(THING)) * E
+ sizeof(THING) * E
, ...)
)
// Drop single-byte sizes and redundant parens.
@@
expression COUNT;
typedef u8;
typedef __u8;
@@
(
kmalloc(
- sizeof(u8) * (COUNT)
+ COUNT
, ...)
|
kmalloc(
- sizeof(__u8) * (COUNT)
+ COUNT
, ...)
|
kmalloc(
- sizeof(char) * (COUNT)
+ COUNT
, ...)
|
kmalloc(
- sizeof(unsigned char) * (COUNT)
+ COUNT
, ...)
|
kmalloc(
- sizeof(u8) * COUNT
+ COUNT
, ...)
|
kmalloc(
- sizeof(__u8) * COUNT
+ COUNT
, ...)
|
kmalloc(
- sizeof(char) * COUNT
+ COUNT
, ...)
|
kmalloc(
- sizeof(unsigned char) * COUNT
+ COUNT
, ...)
)
// 2-factor product with sizeof(type/expression) and identifier or constant.
@@
type TYPE;
expression THING;
identifier COUNT_ID;
constant COUNT_CONST;
@@
(
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * (COUNT_ID)
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * COUNT_ID
+ COUNT_ID, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * (COUNT_CONST)
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * COUNT_CONST
+ COUNT_CONST, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * (COUNT_ID)
+ COUNT_ID, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * COUNT_ID
+ COUNT_ID, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * (COUNT_CONST)
+ COUNT_CONST, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * COUNT_CONST
+ COUNT_CONST, sizeof(THING)
, ...)
)
// 2-factor product, only identifiers.
@@
identifier SIZE, COUNT;
@@
- kmalloc
+ kmalloc_array
(
- SIZE * COUNT
+ COUNT, SIZE
, ...)
// 3-factor product with 1 sizeof(type) or sizeof(expression), with
// redundant parens removed.
@@
expression THING;
identifier STRIDE, COUNT;
type TYPE;
@@
(
kmalloc(
- sizeof(TYPE) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kmalloc(
- sizeof(TYPE) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kmalloc(
- sizeof(TYPE) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kmalloc(
- sizeof(TYPE) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(TYPE))
, ...)
|
kmalloc(
- sizeof(THING) * (COUNT) * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kmalloc(
- sizeof(THING) * (COUNT) * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kmalloc(
- sizeof(THING) * COUNT * (STRIDE)
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
|
kmalloc(
- sizeof(THING) * COUNT * STRIDE
+ array3_size(COUNT, STRIDE, sizeof(THING))
, ...)
)
// 3-factor product with 2 sizeof(variable), with redundant parens removed.
@@
expression THING1, THING2;
identifier COUNT;
type TYPE1, TYPE2;
@@
(
kmalloc(
- sizeof(TYPE1) * sizeof(TYPE2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
kmalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
, ...)
|
kmalloc(
- sizeof(THING1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
kmalloc(
- sizeof(THING1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(THING1), sizeof(THING2))
, ...)
|
kmalloc(
- sizeof(TYPE1) * sizeof(THING2) * COUNT
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
|
kmalloc(
- sizeof(TYPE1) * sizeof(THING2) * (COUNT)
+ array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
, ...)
)
// 3-factor product, only identifiers, with redundant parens removed.
@@
identifier STRIDE, SIZE, COUNT;
@@
(
kmalloc(
- (COUNT) * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- COUNT * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- COUNT * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- (COUNT) * (STRIDE) * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- COUNT * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- (COUNT) * STRIDE * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- (COUNT) * (STRIDE) * (SIZE)
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
|
kmalloc(
- COUNT * STRIDE * SIZE
+ array3_size(COUNT, STRIDE, SIZE)
, ...)
)
// Any remaining multi-factor products, first at least 3-factor products,
// when they're not all constants...
@@
expression E1, E2, E3;
constant C1, C2, C3;
@@
(
kmalloc(C1 * C2 * C3, ...)
|
kmalloc(
- (E1) * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
|
kmalloc(
- (E1) * (E2) * E3
+ array3_size(E1, E2, E3)
, ...)
|
kmalloc(
- (E1) * (E2) * (E3)
+ array3_size(E1, E2, E3)
, ...)
|
kmalloc(
- E1 * E2 * E3
+ array3_size(E1, E2, E3)
, ...)
)
// And then all remaining 2 factors products when they're not all constants,
// keeping sizeof() as the second factor argument.
@@
expression THING, E1, E2;
type TYPE;
constant C1, C2, C3;
@@
(
kmalloc(sizeof(THING) * C2, ...)
|
kmalloc(sizeof(TYPE) * C2, ...)
|
kmalloc(C1 * C2 * C3, ...)
|
kmalloc(C1 * C2, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * (E2)
+ E2, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(TYPE) * E2
+ E2, sizeof(TYPE)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * (E2)
+ E2, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- sizeof(THING) * E2
+ E2, sizeof(THING)
, ...)
|
- kmalloc
+ kmalloc_array
(
- (E1) * E2
+ E1, E2
, ...)
|
- kmalloc
+ kmalloc_array
(
- (E1) * (E2)
+ E1, E2
, ...)
|
- kmalloc
+ kmalloc_array
(
- E1 * E2
+ E1, E2
, ...)
)
Signed-off-by: Kees Cook <keescook@chromium.org>
2018-06-12 23:55:00 +03:00
fp - > rate_table = kmalloc_array ( fp - > nr_rates , sizeof ( int ) , GFP_KERNEL ) ;
2010-03-04 21:46:13 +03:00
if ( ! fp - > rate_table ) {
ret = - ENOMEM ;
goto err_free ;
}
2010-06-11 19:46:33 +04:00
/* Call the triplet parser again, but this time, fp->rate_table is
* allocated , so the rates will be stored */
2014-02-26 16:02:17 +04:00
parse_uac2_sample_rate_range ( chip , fp , nr_triplets , data ) ;
2010-03-04 21:46:13 +03:00
2020-11-23 11:53:09 +03:00
ret = validate_sample_rate_table_v2v3 ( chip , fp , clock ) ;
2020-11-23 11:53:38 +03:00
if ( ret < 0 )
goto err_free ;
set_rate_table_min_max ( fp ) ;
2020-11-23 11:53:09 +03:00
2010-03-04 21:46:13 +03:00
err_free :
kfree ( data ) ;
err :
return ret ;
}
/*
* parse the format type I and III descriptors
*/
static int parse_audio_format_i ( struct snd_usb_audio * chip ,
2018-03-21 03:03:59 +03:00
struct audioformat * fp , u64 format ,
void * _fmt )
2010-03-04 21:46:13 +03:00
{
2013-04-23 03:00:41 +04:00
snd_pcm_format_t pcm_format ;
2018-03-21 03:03:59 +03:00
unsigned int fmt_type ;
2013-04-23 03:00:41 +04:00
int ret ;
2010-03-04 21:46:13 +03:00
2018-03-21 03:03:59 +03:00
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 ) {
2010-03-04 21:46:13 +03:00
/* FIXME: the format type is really IECxxx
* but we give normal PCM format to get the existing
* apps working . . .
*/
switch ( chip - > usb_id ) {
case USB_ID ( 0x0763 , 0x2003 ) : /* M-Audio Audiophile USB */
if ( chip - > setup = = 0x00 & &
fp - > altsetting = = 6 )
pcm_format = SNDRV_PCM_FORMAT_S16_BE ;
else
pcm_format = SNDRV_PCM_FORMAT_S16_LE ;
break ;
default :
pcm_format = SNDRV_PCM_FORMAT_S16_LE ;
}
2013-04-23 03:00:41 +04:00
fp - > formats = pcm_format_to_bits ( pcm_format ) ;
2010-03-04 21:46:13 +03:00
} else {
2018-03-21 03:03:59 +03:00
fp - > formats = parse_audio_format_i_type ( chip , fp , format , _fmt ) ;
2010-03-04 21:46:16 +03:00
if ( ! fp - > formats )
2012-11-21 13:55:56 +04:00
return - EINVAL ;
2010-03-04 21:46:13 +03:00
}
/* gather possible sample rates */
/* audio class v1 reports possible sample rates as part of the
* proprietary class specific descriptor .
* audio class v2 uses class specific EP0 range requests for that .
*/
2013-02-01 00:39:17 +04:00
switch ( fp - > protocol ) {
2010-09-03 12:53:11 +04:00
default :
2018-03-21 03:03:59 +03:00
case UAC_VERSION_1 : {
struct uac_format_type_i_continuous_descriptor * fmt = _fmt ;
2010-03-04 21:46:13 +03:00
fp - > channels = fmt - > bNrChannels ;
2010-05-26 20:11:36 +04:00
ret = parse_audio_format_rates_v1 ( chip , fp , ( unsigned char * ) fmt , 7 ) ;
2010-03-04 21:46:13 +03:00
break ;
2018-03-21 03:03:59 +03:00
}
2010-03-04 21:46:13 +03:00
case UAC_VERSION_2 :
2018-03-21 03:03:59 +03:00
case UAC_VERSION_3 : {
2010-03-04 21:46:13 +03:00
/* fp->channels is already set in this case */
2018-03-21 03:03:59 +03:00
ret = parse_audio_format_rates_v2v3 ( chip , fp ) ;
2010-03-04 21:46:13 +03:00
break ;
}
2018-03-21 03:03:59 +03:00
}
2010-03-04 21:46:13 +03:00
if ( fp - > channels < 1 ) {
2014-02-26 16:02:17 +04:00
usb_audio_err ( chip ,
" %u:%d : invalid channels %d \n " ,
fp - > iface , fp - > altsetting , fp - > channels ) ;
2012-11-21 13:55:56 +04:00
return - EINVAL ;
2010-03-04 21:46:13 +03:00
}
return ret ;
}
/*
* parse the format type II descriptor
*/
static int parse_audio_format_ii ( struct snd_usb_audio * chip ,
struct audioformat * fp ,
2018-03-21 03:03:59 +03:00
u64 format , void * _fmt )
2010-03-04 21:46:13 +03:00
{
int brate , framesize , ret ;
switch ( format ) {
case UAC_FORMAT_TYPE_II_AC3 :
/* FIXME: there is no AC3 format defined yet */
2010-03-04 21:46:15 +03:00
// fp->formats = SNDRV_PCM_FMTBIT_AC3;
fp - > formats = SNDRV_PCM_FMTBIT_U8 ; /* temporary hack to receive byte streams */
2010-03-04 21:46:13 +03:00
break ;
case UAC_FORMAT_TYPE_II_MPEG :
2010-03-04 21:46:15 +03:00
fp - > formats = SNDRV_PCM_FMTBIT_MPEG ;
2010-03-04 21:46:13 +03:00
break ;
default :
2014-02-26 16:02:17 +04:00
usb_audio_info ( chip ,
2018-03-21 03:03:59 +03:00
" %u:%d : unknown format tag %#llx is detected. processed as MPEG. \n " ,
2014-02-26 16:02:17 +04:00
fp - > iface , fp - > altsetting , format ) ;
2010-03-04 21:46:15 +03:00
fp - > formats = SNDRV_PCM_FMTBIT_MPEG ;
2010-03-04 21:46:13 +03:00
break ;
}
fp - > channels = 1 ;
2013-02-01 00:39:17 +04:00
switch ( fp - > protocol ) {
2010-09-03 12:53:11 +04:00
default :
2010-03-04 21:46:13 +03:00
case UAC_VERSION_1 : {
struct uac_format_type_ii_discrete_descriptor * fmt = _fmt ;
brate = le16_to_cpu ( fmt - > wMaxBitRate ) ;
framesize = le16_to_cpu ( fmt - > wSamplesPerFrame ) ;
2014-02-26 16:02:17 +04:00
usb_audio_info ( chip , " found format II with max.bitrate = %d, frame size=%d \n " , brate , framesize ) ;
2010-03-04 21:46:13 +03:00
fp - > frame_size = framesize ;
ret = parse_audio_format_rates_v1 ( chip , fp , _fmt , 8 ) ; /* fmt[8..] sample rates */
break ;
}
case UAC_VERSION_2 : {
struct uac_format_type_ii_ext_descriptor * fmt = _fmt ;
brate = le16_to_cpu ( fmt - > wMaxBitRate ) ;
framesize = le16_to_cpu ( fmt - > wSamplesPerFrame ) ;
2014-02-26 16:02:17 +04:00
usb_audio_info ( chip , " found format II with max.bitrate = %d, frame size=%d \n " , brate , framesize ) ;
2010-03-04 21:46:13 +03:00
fp - > frame_size = framesize ;
2018-03-21 03:03:59 +03:00
ret = parse_audio_format_rates_v2v3 ( chip , fp ) ;
2010-03-04 21:46:13 +03:00
break ;
}
}
return ret ;
}
2013-03-17 16:07:24 +04:00
int snd_usb_parse_audio_format ( struct snd_usb_audio * chip ,
2018-03-21 03:03:59 +03:00
struct audioformat * fp , u64 format ,
2013-03-17 16:07:24 +04:00
struct uac_format_type_i_continuous_descriptor * fmt ,
2013-02-01 00:39:17 +04:00
int stream )
2010-03-04 21:46:13 +03:00
{
int err ;
2010-05-26 20:11:36 +04:00
switch ( fmt - > bFormatType ) {
2010-03-04 21:46:13 +03:00
case UAC_FORMAT_TYPE_I :
case UAC_FORMAT_TYPE_III :
2013-02-01 00:39:17 +04:00
err = parse_audio_format_i ( chip , fp , format , fmt ) ;
2010-03-04 21:46:13 +03:00
break ;
case UAC_FORMAT_TYPE_II :
2013-02-01 00:39:17 +04:00
err = parse_audio_format_ii ( chip , fp , format , fmt ) ;
2010-03-04 21:46:13 +03:00
break ;
default :
2014-02-26 16:02:17 +04:00
usb_audio_info ( chip ,
" %u:%d : format type %d is not supported yet \n " ,
fp - > iface , fp - > altsetting ,
fmt - > bFormatType ) ;
2010-05-26 20:11:37 +04:00
return - ENOTSUPP ;
2010-03-04 21:46:13 +03:00
}
2010-05-26 20:11:36 +04:00
fp - > fmt_type = fmt - > bFormatType ;
2010-03-04 21:46:13 +03:00
if ( err < 0 )
return err ;
# if 1
/* FIXME: temporary hack for extigy/audigy 2 nx/zs */
/* extigy apparently supports sample rates other than 48k
* but not in ordinary way . so we enable only 48 k atm .
*/
if ( chip - > usb_id = = USB_ID ( 0x041e , 0x3000 ) | |
chip - > usb_id = = USB_ID ( 0x041e , 0x3020 ) | |
chip - > usb_id = = USB_ID ( 0x041e , 0x3061 ) ) {
2010-05-26 20:11:36 +04:00
if ( fmt - > bFormatType = = UAC_FORMAT_TYPE_I & &
2010-03-04 21:46:13 +03:00
fp - > rates ! = SNDRV_PCM_RATE_48000 & &
fp - > rates ! = SNDRV_PCM_RATE_96000 )
2010-05-26 20:11:37 +04:00
return - ENOTSUPP ;
2010-03-04 21:46:13 +03:00
}
# endif
return 0 ;
}
2018-03-21 03:03:59 +03:00
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 ;
}