2010-03-04 21:46:13 +03:00
/*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*
*/
# 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>
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"
# include "debug.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 )
* @ fmt : the format type descriptor
*/
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 ,
2013-03-17 16:07:24 +04:00
unsigned int format , void * _fmt ,
2010-03-04 21:46:13 +03:00
int protocol )
{
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
switch ( 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 ;
sample_width = fmt - > bBitResolution ;
sample_bytes = fmt - > bSubframeSize ;
2010-03-04 21:46:16 +03:00
format = 1 < < 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
if ( format & UAC2_FORMAT_TYPE_I_RAW_DATA )
pcm_formats | = SNDRV_PCM_FMTBIT_SPECIAL ;
2010-03-04 21:46:16 +03:00
format < < = 1 ;
2010-03-04 21:46:13 +03:00
break ;
}
}
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... */
2010-03-04 21:46:13 +03:00
snd_printdd ( KERN_INFO " %d:%u:%d : format type 0 is detected, processed as PCM \n " ,
chip - > dev - > devnum , 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 ) ) {
2011-01-10 18:30:54 +03:00
if ( chip - > usb_id = = USB_ID ( 0x0582 , 0x0016 ) /* Edirol SD-90 */ & &
sample_width = = 24 & & sample_bytes = = 2 )
sample_bytes = 3 ;
else if ( sample_width > sample_bytes * 8 ) {
2010-03-04 21:46:13 +03:00
snd_printk ( KERN_INFO " %d:%u:%d : sample bitwidth %d in over sample bytes %d \n " ,
chip - > dev - > devnum , fp - > iface , fp - > altsetting ,
sample_width , sample_bytes ) ;
}
/* 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 :
snd_printk ( KERN_INFO " %d:%u:%d : unsupported sample bitwidth %d in %d bytes \n " ,
chip - > dev - > devnum , fp - > iface , fp - > altsetting ,
sample_width , sample_bytes ) ;
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 ) {
snd_printk ( KERN_INFO " %d:%u:%d : unsupported format bits %#x \n " ,
2010-03-04 21:46:13 +03:00
chip - > dev - > devnum , fp - > iface , fp - > altsetting , format ) ;
}
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
}
/*
* 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 ) ) {
snd_printk ( KERN_ERR " %d:%u:%d : invalid UAC_FORMAT_TYPE desc \n " ,
chip - > dev - > devnum , 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 ;
fp - > rate_table = kmalloc ( sizeof ( int ) * nr_rates , GFP_KERNEL ) ;
if ( fp - > rate_table = = NULL ) {
snd_printk ( KERN_ERR " cannot malloc \n " ) ;
2012-11-21 13:55:56 +04:00
return - ENOMEM ;
2010-03-04 21:46:13 +03:00
}
fp - > nr_rates = 0 ;
fp - > rate_min = fp - > rate_max = 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 ;
/* Creative VF0470 Live Cam reports 16 kHz instead of 8kHz */
if ( rate = = 16000 & & chip - > usb_id = = USB_ID ( 0x041e , 0x4068 ) )
rate = 8000 ;
fp - > rate_table [ fp - > nr_rates ] = rate ;
if ( ! fp - > rate_min | | rate < fp - > rate_min )
fp - > rate_min = rate ;
if ( ! fp - > rate_max | | rate > fp - > rate_max )
fp - > rate_max = rate ;
fp - > rates | = snd_pcm_rate_to_rate_bit ( rate ) ;
fp - > nr_rates + + ;
}
if ( ! fp - > nr_rates ) {
hwc_debug ( " All rates were zero. Skipping format! \n " ) ;
2012-11-21 13:55:56 +04:00
return - EINVAL ;
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 ] ) ;
}
return 0 ;
}
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 .
*/
static int parse_uac2_sample_rate_range ( struct audioformat * fp , int nr_triplets ,
const unsigned char * data )
{
int i , nr_rates = 0 ;
fp - > rates = fp - > rate_min = fp - > rate_max = 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 ) {
if ( fp - > rate_table )
fp - > rate_table [ nr_rates ] = rate ;
if ( ! fp - > rate_min | | rate < fp - > rate_min )
fp - > rate_min = rate ;
if ( ! fp - > rate_max | | rate > fp - > rate_max )
fp - > rate_max = rate ;
fp - > rates | = snd_pcm_rate_to_rate_bit ( rate ) ;
nr_rates + + ;
2012-02-14 14:18:48 +04:00
if ( nr_rates > = MAX_NR_RATES ) {
2012-01-08 18:02:52 +04:00
snd_printk ( KERN_ERR " invalid uac2 rates \n " ) ;
break ;
}
2010-06-11 19:46:33 +04:00
/* avoid endless loop */
if ( res = = 0 )
break ;
}
}
return nr_rates ;
}
2010-03-04 21:46:13 +03:00
/*
* parse the format descriptor and stores the possible sample rates
* on the audioformat table ( audio class v2 ) .
*/
static int parse_audio_format_rates_v2 ( 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 ;
2010-06-11 19:46:33 +04:00
int nr_triplets , data_size , ret = 0 ;
2013-04-04 01:18:54 +04:00
int clock = snd_usb_clock_find_source ( chip , fp - > clock , false ) ;
2010-03-04 21:46:13 +03:00
2010-06-11 19:34:19 +04:00
if ( clock < 0 ) {
snd_printk ( KERN_ERR " %s(): unable to find clock source (clock %d) \n " ,
__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 ) {
2010-05-31 16:51:31 +04:00
snd_printk ( KERN_ERR " %s(): unable to retrieve number of sample rates (clock %d) \n " ,
__func__ , clock ) ;
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 ) {
2010-05-31 16:51:31 +04:00
snd_printk ( KERN_ERR " %s(): unable to retrieve sample rate range (clock %d) \n " ,
__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 ;
fp - > nr_rates = parse_uac2_sample_rate_range ( fp , nr_triplets , data ) ;
if ( fp - > nr_rates = = 0 ) {
/* SNDRV_PCM_RATE_CONTINUOUS */
ret = 0 ;
goto err_free ;
}
fp - > rate_table = kmalloc ( sizeof ( int ) * fp - > nr_rates , 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 */
parse_uac2_sample_rate_range ( fp , nr_triplets , data ) ;
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 ,
2013-03-17 16:07:24 +04:00
struct audioformat * fp , unsigned int format ,
2010-05-26 20:11:36 +04:00
struct uac_format_type_i_continuous_descriptor * fmt ,
2010-03-04 21:46:13 +03:00
struct usb_host_interface * iface )
{
struct usb_interface_descriptor * altsd = get_iface_desc ( iface ) ;
int protocol = altsd - > bInterfaceProtocol ;
2013-04-23 03:00:41 +04:00
snd_pcm_format_t pcm_format ;
int ret ;
2010-03-04 21:46:13 +03:00
if ( fmt - > bFormatType = = UAC_FORMAT_TYPE_III ) {
/* 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 {
2010-03-04 21:46:16 +03:00
fp - > formats = parse_audio_format_i_type ( chip , fp , format ,
fmt , protocol ) ;
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 .
*/
switch ( protocol ) {
2010-09-03 12:53:11 +04:00
default :
snd_printdd ( KERN_WARNING " %d:%u:%d : invalid protocol version %d, assuming v1 \n " ,
chip - > dev - > devnum , fp - > iface , fp - > altsetting , protocol ) ;
/* fall through */
2010-03-04 21:46:13 +03:00
case UAC_VERSION_1 :
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 ;
case UAC_VERSION_2 :
/* fp->channels is already set in this case */
2010-06-16 19:57:31 +04:00
ret = parse_audio_format_rates_v2 ( chip , fp ) ;
2010-03-04 21:46:13 +03:00
break ;
}
if ( fp - > channels < 1 ) {
snd_printk ( KERN_ERR " %d:%u:%d : invalid channels %d \n " ,
chip - > dev - > devnum , 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 ,
int format , void * _fmt ,
struct usb_host_interface * iface )
{
int brate , framesize , ret ;
struct usb_interface_descriptor * altsd = get_iface_desc ( iface ) ;
int protocol = altsd - > bInterfaceProtocol ;
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 :
snd_printd ( KERN_INFO " %d:%u:%d : unknown format tag %#x is detected. processed as MPEG. \n " ,
chip - > dev - > devnum , 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 ;
switch ( protocol ) {
2010-09-03 12:53:11 +04:00
default :
snd_printdd ( KERN_WARNING " %d:%u:%d : invalid protocol version %d, assuming v1 \n " ,
chip - > dev - > devnum , fp - > iface , fp - > altsetting , protocol ) ;
/* fall through */
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 ) ;
snd_printd ( KERN_INFO " found format II with max.bitrate = %d, frame size=%d \n " , brate , framesize ) ;
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 ) ;
snd_printd ( KERN_INFO " found format II with max.bitrate = %d, frame size=%d \n " , brate , framesize ) ;
fp - > frame_size = framesize ;
2010-06-16 19:57:31 +04:00
ret = parse_audio_format_rates_v2 ( 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 ,
struct audioformat * fp , unsigned int format ,
struct uac_format_type_i_continuous_descriptor * fmt ,
2010-05-26 20:11:36 +04:00
int stream , struct usb_host_interface * iface )
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 :
err = parse_audio_format_i ( chip , fp , format , fmt , iface ) ;
break ;
case UAC_FORMAT_TYPE_II :
err = parse_audio_format_ii ( chip , fp , format , fmt , iface ) ;
break ;
default :
snd_printd ( KERN_INFO " %d:%u:%d : format type %d is not supported yet \n " ,
2010-05-26 20:11:36 +04:00
chip - > dev - > devnum , 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 ;
}