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"
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 ,
int format , void * _fmt ,
int protocol )
{
int sample_width , sample_bytes ;
2010-03-04 21:46:16 +03:00
u64 pcm_formats ;
2010-03-04 21:46:13 +03:00
switch ( protocol ) {
case UAC_VERSION_1 : {
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 ;
2010-03-04 21:46:16 +03:00
format < < = 1 ;
2010-03-04 21:46:13 +03:00
break ;
}
default :
return - EINVAL ;
}
2010-03-04 21:46:16 +03:00
pcm_formats = 0 ;
2010-03-04 21:46:13 +03:00
2010-03-04 21:46:16 +03:00
if ( format = = 0 | | format = = ( 1 < < UAC_FORMAT_TYPE_I_UNDEFINED ) ) {
/* 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 ) ) {
2010-03-04 21:46:13 +03:00
if ( sample_width > sample_bytes * 8 ) {
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 ) ;
}
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 ) ;
return - 1 ;
}
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 " ) ;
return - 1 ;
}
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 */
if ( rate = = 48000 & & nr_rates = = 1 & &
( chip - > usb_id = = USB_ID ( 0x0d8c , 0x0201 ) | |
chip - > usb_id = = USB_ID ( 0x0d8c , 0x0102 ) ) & &
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 " ) ;
return - 1 ;
}
} 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 ;
}
/*
* 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 ,
struct audioformat * fp ,
struct usb_host_interface * iface )
{
struct usb_device * dev = chip - > dev ;
unsigned char tmp [ 2 ] , * data ;
int i , nr_rates , data_size , ret = 0 ;
2010-05-31 16:51:31 +04:00
int clock = snd_usb_clock_find_source ( chip , chip - > ctrl_intf , fp - > clock ) ;
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-05-31 16:51:31 +04:00
UAC2_CS_CONTROL_SAM_FREQ < < 8 , clock < < 8 ,
2010-03-11 23:13:21 +03:00
tmp , sizeof ( tmp ) , 1000 ) ;
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 ;
}
nr_rates = ( tmp [ 1 ] < < 8 ) | tmp [ 0 ] ;
data_size = 2 + 12 * nr_rates ;
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 ,
UAC2_CS_CONTROL_SAM_FREQ < < 8 , clock < < 8 ,
data , data_size , 1000 ) ;
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 ;
}
fp - > rate_table = kmalloc ( sizeof ( int ) * nr_rates , GFP_KERNEL ) ;
if ( ! fp - > rate_table ) {
ret = - ENOMEM ;
goto err_free ;
}
fp - > nr_rates = 0 ;
fp - > rate_min = fp - > rate_max = 0 ;
for ( i = 0 ; i < nr_rates ; i + + ) {
int rate = combine_quad ( & data [ 2 + 12 * i ] ) ;
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 + + ;
}
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 ,
2010-05-26 20:11:36 +04:00
struct audioformat * fp , int format ,
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 ;
int pcm_format , ret ;
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 ;
}
2010-03-04 21:46:16 +03:00
fp - > formats = 1uLL < < 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 )
2010-03-04 21:46:13 +03:00
return - 1 ;
}
/* 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 ) {
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 */
ret = parse_audio_format_rates_v2 ( chip , fp , iface ) ;
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 ) ;
return - 1 ;
}
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 ) {
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 ;
ret = parse_audio_format_rates_v2 ( chip , fp , iface ) ;
break ;
}
}
return ret ;
}
int snd_usb_parse_audio_format ( struct snd_usb_audio * chip , struct audioformat * fp ,
2010-05-26 20:11:36 +04:00
int format , struct uac_format_type_i_continuous_descriptor * fmt ,
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 ;
}