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>
2011-05-25 11:09:01 +04:00
# include <sound/control.h>
2010-03-04 21:46:13 +03:00
# include <sound/core.h>
# include <sound/info.h>
# include <sound/pcm.h>
# include "usbaudio.h"
# include "card.h"
2010-03-11 23:13:23 +03:00
# include "mixer.h"
2010-03-11 23:13:22 +03:00
# include "mixer_quirks.h"
2010-03-04 21:46:13 +03:00
# include "midi.h"
# include "quirks.h"
# include "helper.h"
# include "endpoint.h"
# include "pcm.h"
2010-06-16 19:57:31 +04:00
# include "clock.h"
2010-03-04 21:46:13 +03:00
/*
* handle the quirks for the contained interfaces
*/
static int create_composite_quirk ( struct snd_usb_audio * chip ,
struct usb_interface * iface ,
struct usb_driver * driver ,
const struct snd_usb_audio_quirk * quirk )
{
int probed_ifnum = get_iface_desc ( iface - > altsetting ) - > bInterfaceNumber ;
int err ;
for ( quirk = quirk - > data ; quirk - > ifnum > = 0 ; + + quirk ) {
iface = usb_ifnum_to_if ( chip - > dev , quirk - > ifnum ) ;
if ( ! iface )
continue ;
if ( quirk - > ifnum ! = probed_ifnum & &
usb_interface_claimed ( iface ) )
continue ;
err = snd_usb_create_quirk ( chip , iface , driver , quirk ) ;
if ( err < 0 )
return err ;
if ( quirk - > ifnum ! = probed_ifnum )
usb_driver_claim_interface ( driver , iface , ( void * ) - 1L ) ;
}
return 0 ;
}
static int ignore_interface_quirk ( struct snd_usb_audio * chip ,
struct usb_interface * iface ,
struct usb_driver * driver ,
const struct snd_usb_audio_quirk * quirk )
{
return 0 ;
}
/*
* Allow alignment on audio sub - slot ( channel samples ) rather than
* on audio slots ( audio frames )
*/
static int create_align_transfer_quirk ( struct snd_usb_audio * chip ,
struct usb_interface * iface ,
struct usb_driver * driver ,
const struct snd_usb_audio_quirk * quirk )
{
chip - > txfr_quirk = 1 ;
return 1 ; /* Continue with creating streams and mixer */
}
static int create_any_midi_quirk ( struct snd_usb_audio * chip ,
struct usb_interface * intf ,
struct usb_driver * driver ,
const struct snd_usb_audio_quirk * quirk )
{
return snd_usbmidi_create ( chip - > card , intf , & chip - > midi_list , quirk ) ;
}
/*
* create a stream for an interface with proper descriptors
*/
static int create_standard_audio_quirk ( struct snd_usb_audio * chip ,
struct usb_interface * iface ,
struct usb_driver * driver ,
const struct snd_usb_audio_quirk * quirk )
{
struct usb_host_interface * alts ;
struct usb_interface_descriptor * altsd ;
int err ;
alts = & iface - > altsetting [ 0 ] ;
altsd = get_iface_desc ( alts ) ;
err = snd_usb_parse_audio_endpoints ( chip , altsd - > bInterfaceNumber ) ;
if ( err < 0 ) {
snd_printk ( KERN_ERR " cannot setup if %d: error %d \n " ,
altsd - > bInterfaceNumber , err ) ;
return err ;
}
/* reset the current interface */
usb_set_interface ( chip - > dev , altsd - > bInterfaceNumber , 0 ) ;
return 0 ;
}
/*
* create a stream for an endpoint / altsetting without proper descriptors
*/
static int create_fixed_stream_quirk ( struct snd_usb_audio * chip ,
struct usb_interface * iface ,
struct usb_driver * driver ,
const struct snd_usb_audio_quirk * quirk )
{
struct audioformat * fp ;
struct usb_host_interface * alts ;
int stream , err ;
unsigned * rate_table = NULL ;
fp = kmemdup ( quirk - > data , sizeof ( * fp ) , GFP_KERNEL ) ;
if ( ! fp ) {
snd_printk ( KERN_ERR " cannot memdup \n " ) ;
return - ENOMEM ;
}
if ( fp - > nr_rates > 0 ) {
rate_table = kmalloc ( sizeof ( int ) * fp - > nr_rates , GFP_KERNEL ) ;
if ( ! rate_table ) {
kfree ( fp ) ;
return - ENOMEM ;
}
memcpy ( rate_table , fp - > rate_table , sizeof ( int ) * fp - > nr_rates ) ;
fp - > rate_table = rate_table ;
}
stream = ( fp - > endpoint & USB_DIR_IN )
? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK ;
err = snd_usb_add_audio_endpoint ( chip , stream , fp ) ;
if ( err < 0 ) {
kfree ( fp ) ;
kfree ( rate_table ) ;
return err ;
}
if ( fp - > iface ! = get_iface_desc ( & iface - > altsetting [ 0 ] ) - > bInterfaceNumber | |
fp - > altset_idx > = iface - > num_altsetting ) {
kfree ( fp ) ;
kfree ( rate_table ) ;
return - EINVAL ;
}
alts = & iface - > altsetting [ fp - > altset_idx ] ;
fp - > datainterval = snd_usb_parse_datainterval ( chip , alts ) ;
fp - > maxpacksize = le16_to_cpu ( get_endpoint ( alts , 0 ) - > wMaxPacketSize ) ;
usb_set_interface ( chip - > dev , fp - > iface , 0 ) ;
2010-03-04 21:46:17 +03:00
snd_usb_init_pitch ( chip , fp - > iface , alts , fp ) ;
snd_usb_init_sample_rate ( chip , fp - > iface , alts , fp , fp - > rate_max ) ;
2010-03-04 21:46:13 +03:00
return 0 ;
}
/*
* Create a stream for an Edirol UA - 700 / UA - 25 / UA - 4F X interface .
* The only way to detect the sample rate is by looking at wMaxPacketSize .
*/
static int create_uaxx_quirk ( struct snd_usb_audio * chip ,
struct usb_interface * iface ,
struct usb_driver * driver ,
const struct snd_usb_audio_quirk * quirk )
{
static const struct audioformat ua_format = {
2010-03-04 21:46:15 +03:00
. formats = SNDRV_PCM_FMTBIT_S24_3LE ,
2010-03-04 21:46:13 +03:00
. channels = 2 ,
. fmt_type = UAC_FORMAT_TYPE_I ,
. altsetting = 1 ,
. altset_idx = 1 ,
. rates = SNDRV_PCM_RATE_CONTINUOUS ,
} ;
struct usb_host_interface * alts ;
struct usb_interface_descriptor * altsd ;
struct audioformat * fp ;
int stream , err ;
/* both PCM and MIDI interfaces have 2 or more altsettings */
if ( iface - > num_altsetting < 2 )
return - ENXIO ;
alts = & iface - > altsetting [ 1 ] ;
altsd = get_iface_desc ( alts ) ;
if ( altsd - > bNumEndpoints = = 2 ) {
static const struct snd_usb_midi_endpoint_info ua700_ep = {
. out_cables = 0x0003 ,
. in_cables = 0x0003
} ;
static const struct snd_usb_audio_quirk ua700_quirk = {
. type = QUIRK_MIDI_FIXED_ENDPOINT ,
. data = & ua700_ep
} ;
static const struct snd_usb_midi_endpoint_info uaxx_ep = {
. out_cables = 0x0001 ,
. in_cables = 0x0001
} ;
static const struct snd_usb_audio_quirk uaxx_quirk = {
. type = QUIRK_MIDI_FIXED_ENDPOINT ,
. data = & uaxx_ep
} ;
const struct snd_usb_audio_quirk * quirk =
chip - > usb_id = = USB_ID ( 0x0582 , 0x002b )
? & ua700_quirk : & uaxx_quirk ;
return snd_usbmidi_create ( chip - > card , iface ,
& chip - > midi_list , quirk ) ;
}
if ( altsd - > bNumEndpoints ! = 1 )
return - ENXIO ;
fp = kmalloc ( sizeof ( * fp ) , GFP_KERNEL ) ;
if ( ! fp )
return - ENOMEM ;
memcpy ( fp , & ua_format , sizeof ( * fp ) ) ;
fp - > iface = altsd - > bInterfaceNumber ;
fp - > endpoint = get_endpoint ( alts , 0 ) - > bEndpointAddress ;
fp - > ep_attr = get_endpoint ( alts , 0 ) - > bmAttributes ;
fp - > datainterval = 0 ;
fp - > maxpacksize = le16_to_cpu ( get_endpoint ( alts , 0 ) - > wMaxPacketSize ) ;
switch ( fp - > maxpacksize ) {
case 0x120 :
fp - > rate_max = fp - > rate_min = 44100 ;
break ;
case 0x138 :
case 0x140 :
fp - > rate_max = fp - > rate_min = 48000 ;
break ;
case 0x258 :
case 0x260 :
fp - > rate_max = fp - > rate_min = 96000 ;
break ;
default :
snd_printk ( KERN_ERR " unknown sample rate \n " ) ;
kfree ( fp ) ;
return - ENXIO ;
}
stream = ( fp - > endpoint & USB_DIR_IN )
? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK ;
err = snd_usb_add_audio_endpoint ( chip , stream , fp ) ;
if ( err < 0 ) {
kfree ( fp ) ;
return err ;
}
usb_set_interface ( chip - > dev , fp - > iface , 0 ) ;
return 0 ;
}
/*
* audio - interface quirks
*
* returns zero if no standard audio / MIDI parsing is needed .
2011-03-31 05:57:33 +04:00
* returns a positive value if standard audio / midi interfaces are parsed
2010-03-04 21:46:13 +03:00
* after this .
* returns a negative value at error .
*/
int snd_usb_create_quirk ( struct snd_usb_audio * chip ,
struct usb_interface * iface ,
struct usb_driver * driver ,
const struct snd_usb_audio_quirk * quirk )
{
typedef int ( * quirk_func_t ) ( struct snd_usb_audio * ,
struct usb_interface * ,
struct usb_driver * ,
const struct snd_usb_audio_quirk * ) ;
static const quirk_func_t quirk_funcs [ ] = {
[ QUIRK_IGNORE_INTERFACE ] = ignore_interface_quirk ,
[ QUIRK_COMPOSITE ] = create_composite_quirk ,
[ QUIRK_MIDI_STANDARD_INTERFACE ] = create_any_midi_quirk ,
[ QUIRK_MIDI_FIXED_ENDPOINT ] = create_any_midi_quirk ,
[ QUIRK_MIDI_YAMAHA ] = create_any_midi_quirk ,
[ QUIRK_MIDI_MIDIMAN ] = create_any_midi_quirk ,
[ QUIRK_MIDI_NOVATION ] = create_any_midi_quirk ,
2010-10-22 20:20:48 +04:00
[ QUIRK_MIDI_RAW_BYTES ] = create_any_midi_quirk ,
2010-03-04 21:46:13 +03:00
[ QUIRK_MIDI_EMAGIC ] = create_any_midi_quirk ,
[ QUIRK_MIDI_CME ] = create_any_midi_quirk ,
2010-05-20 23:31:10 +04:00
[ QUIRK_MIDI_AKAI ] = create_any_midi_quirk ,
2010-03-04 21:46:13 +03:00
[ QUIRK_AUDIO_STANDARD_INTERFACE ] = create_standard_audio_quirk ,
[ QUIRK_AUDIO_FIXED_ENDPOINT ] = create_fixed_stream_quirk ,
[ QUIRK_AUDIO_EDIROL_UAXX ] = create_uaxx_quirk ,
[ QUIRK_AUDIO_ALIGN_TRANSFER ] = create_align_transfer_quirk
} ;
if ( quirk - > type < QUIRK_TYPE_COUNT ) {
return quirk_funcs [ quirk - > type ] ( chip , iface , driver , quirk ) ;
} else {
snd_printd ( KERN_ERR " invalid quirk type %d \n " , quirk - > type ) ;
return - ENXIO ;
}
}
/*
* boot quirks
*/
# define EXTIGY_FIRMWARE_SIZE_OLD 794
# define EXTIGY_FIRMWARE_SIZE_NEW 483
static int snd_usb_extigy_boot_quirk ( struct usb_device * dev , struct usb_interface * intf )
{
struct usb_host_config * config = dev - > actconfig ;
int err ;
if ( le16_to_cpu ( get_cfg_desc ( config ) - > wTotalLength ) = = EXTIGY_FIRMWARE_SIZE_OLD | |
le16_to_cpu ( get_cfg_desc ( config ) - > wTotalLength ) = = EXTIGY_FIRMWARE_SIZE_NEW ) {
snd_printdd ( " sending Extigy boot sequence... \n " ) ;
/* Send message to force it to reconnect with full interface. */
err = snd_usb_ctl_msg ( dev , usb_sndctrlpipe ( dev , 0 ) ,
0x10 , 0x43 , 0x0001 , 0x000a , NULL , 0 , 1000 ) ;
if ( err < 0 ) snd_printdd ( " error sending boot message: %d \n " , err ) ;
err = usb_get_descriptor ( dev , USB_DT_DEVICE , 0 ,
& dev - > descriptor , sizeof ( dev - > descriptor ) ) ;
config = dev - > actconfig ;
if ( err < 0 ) snd_printdd ( " error usb_get_descriptor: %d \n " , err ) ;
err = usb_reset_configuration ( dev ) ;
if ( err < 0 ) snd_printdd ( " error usb_reset_configuration: %d \n " , err ) ;
snd_printdd ( " extigy_boot: new boot length = %d \n " ,
le16_to_cpu ( get_cfg_desc ( config ) - > wTotalLength ) ) ;
return - ENODEV ; /* quit this anyway */
}
return 0 ;
}
static int snd_usb_audigy2nx_boot_quirk ( struct usb_device * dev )
{
u8 buf = 1 ;
snd_usb_ctl_msg ( dev , usb_rcvctrlpipe ( dev , 0 ) , 0x2a ,
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_OTHER ,
0 , 0 , & buf , 1 , 1000 ) ;
if ( buf = = 0 ) {
snd_usb_ctl_msg ( dev , usb_sndctrlpipe ( dev , 0 ) , 0x29 ,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER ,
1 , 2000 , NULL , 0 , 1000 ) ;
return - ENODEV ;
}
return 0 ;
}
/*
* C - Media CM106 / CM106 + have four 16 - bit internal registers that are nicely
* documented in the device ' s data sheet .
*/
static int snd_usb_cm106_write_int_reg ( struct usb_device * dev , int reg , u16 value )
{
u8 buf [ 4 ] ;
buf [ 0 ] = 0x20 ;
buf [ 1 ] = value & 0xff ;
buf [ 2 ] = ( value > > 8 ) & 0xff ;
buf [ 3 ] = reg ;
return snd_usb_ctl_msg ( dev , usb_sndctrlpipe ( dev , 0 ) , USB_REQ_SET_CONFIGURATION ,
USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_ENDPOINT ,
0 , 0 , & buf , 4 , 1000 ) ;
}
static int snd_usb_cm106_boot_quirk ( struct usb_device * dev )
{
/*
* Enable line - out driver mode , set headphone source to front
* channels , enable stereo mic .
*/
return snd_usb_cm106_write_int_reg ( dev , 2 , 0x8004 ) ;
}
/*
* C - Media CM6206 is based on CM106 with two additional
* registers that are not documented in the data sheet .
* Values here are chosen based on sniffing USB traffic
* under Windows .
*/
static int snd_usb_cm6206_boot_quirk ( struct usb_device * dev )
{
int err , reg ;
int val [ ] = { 0x200c , 0x3000 , 0xf800 , 0x143f , 0x0000 , 0x3000 } ;
for ( reg = 0 ; reg < ARRAY_SIZE ( val ) ; reg + + ) {
err = snd_usb_cm106_write_int_reg ( dev , reg , val [ reg ] ) ;
if ( err < 0 )
return err ;
}
return err ;
}
/*
* This call will put the synth in " USB send " mode , i . e it will send MIDI
* messages through USB ( this is disabled at startup ) . The synth will
* acknowledge by sending a sysex on endpoint 0x85 and by displaying a USB
* sign on its LCD . Values here are chosen based on sniffing USB traffic
* under Windows .
*/
static int snd_usb_accessmusic_boot_quirk ( struct usb_device * dev )
{
int err , actual_length ;
/* "midi send" enable */
static const u8 seq [ ] = { 0x4e , 0x73 , 0x52 , 0x01 } ;
void * buf = kmemdup ( seq , ARRAY_SIZE ( seq ) , GFP_KERNEL ) ;
if ( ! buf )
return - ENOMEM ;
err = usb_interrupt_msg ( dev , usb_sndintpipe ( dev , 0x05 ) , buf ,
ARRAY_SIZE ( seq ) , & actual_length , 1000 ) ;
kfree ( buf ) ;
if ( err < 0 )
return err ;
return 0 ;
}
2011-02-11 14:08:06 +03:00
/*
* Some sound cards from Native Instruments are in fact compliant to the USB
* audio standard of version 2 and other approved USB standards , even though
* they come up as vendor - specific device when first connected .
*
* However , they can be told to come up with a new set of descriptors
* upon their next enumeration , and the interfaces announced by the new
* descriptors will then be handled by the kernel ' s class drivers . As the
* product ID will also change , no further checks are required .
*/
static int snd_usb_nativeinstruments_boot_quirk ( struct usb_device * dev )
{
int ret = usb_control_msg ( dev , usb_sndctrlpipe ( dev , 0 ) ,
0xaf , USB_TYPE_VENDOR | USB_RECIP_DEVICE ,
cpu_to_le16 ( 1 ) , 0 , NULL , 0 , 1000 ) ;
if ( ret < 0 )
return ret ;
usb_reset_device ( dev ) ;
/* return -EAGAIN, so the creation of an audio interface for this
* temporary device is aborted . The device will reconnect with a
* new product ID */
return - EAGAIN ;
}
2010-03-04 21:46:13 +03:00
/*
* Setup quirks
*/
# define AUDIOPHILE_SET 0x01 /* if set, parse device_setup */
# define AUDIOPHILE_SET_DTS 0x02 /* if set, enable DTS Digital Output */
# define AUDIOPHILE_SET_96K 0x04 /* 48-96KHz rate if set, 8-48KHz otherwise */
# define AUDIOPHILE_SET_24B 0x08 /* 24bits sample if set, 16bits otherwise */
# define AUDIOPHILE_SET_DI 0x10 /* if set, enable Digital Input */
# define AUDIOPHILE_SET_MASK 0x1F /* bit mask for setup value */
# define AUDIOPHILE_SET_24B_48K_DI 0x19 /* value for 24bits+48KHz+Digital Input */
# define AUDIOPHILE_SET_24B_48K_NOTDI 0x09 /* value for 24bits+48KHz+No Digital Input */
# define AUDIOPHILE_SET_16B_48K_DI 0x11 /* value for 16bits+48KHz+Digital Input */
# define AUDIOPHILE_SET_16B_48K_NOTDI 0x01 /* value for 16bits+48KHz+No Digital Input */
static int audiophile_skip_setting_quirk ( struct snd_usb_audio * chip ,
int iface ,
int altno )
{
/* Reset ALL ifaces to 0 altsetting.
* Call it for every possible altsetting of every interface .
*/
usb_set_interface ( chip - > dev , iface , 0 ) ;
if ( chip - > setup & AUDIOPHILE_SET ) {
if ( ( chip - > setup & AUDIOPHILE_SET_DTS )
& & altno ! = 6 )
return 1 ; /* skip this altsetting */
if ( ( chip - > setup & AUDIOPHILE_SET_96K )
& & altno ! = 1 )
return 1 ; /* skip this altsetting */
if ( ( chip - > setup & AUDIOPHILE_SET_MASK ) = =
AUDIOPHILE_SET_24B_48K_DI & & altno ! = 2 )
return 1 ; /* skip this altsetting */
if ( ( chip - > setup & AUDIOPHILE_SET_MASK ) = =
AUDIOPHILE_SET_24B_48K_NOTDI & & altno ! = 3 )
return 1 ; /* skip this altsetting */
if ( ( chip - > setup & AUDIOPHILE_SET_MASK ) = =
AUDIOPHILE_SET_16B_48K_DI & & altno ! = 4 )
return 1 ; /* skip this altsetting */
if ( ( chip - > setup & AUDIOPHILE_SET_MASK ) = =
AUDIOPHILE_SET_16B_48K_NOTDI & & altno ! = 5 )
return 1 ; /* skip this altsetting */
}
return 0 ; /* keep this altsetting */
}
int snd_usb_apply_interface_quirk ( struct snd_usb_audio * chip ,
int iface ,
int altno )
{
/* audiophile usb: skip altsets incompatible with device_setup */
if ( chip - > usb_id = = USB_ID ( 0x0763 , 0x2003 ) )
return audiophile_skip_setting_quirk ( chip , iface , altno ) ;
return 0 ;
}
int snd_usb_apply_boot_quirk ( struct usb_device * dev ,
struct usb_interface * intf ,
const struct snd_usb_audio_quirk * quirk )
{
u32 id = USB_ID ( le16_to_cpu ( dev - > descriptor . idVendor ) ,
le16_to_cpu ( dev - > descriptor . idProduct ) ) ;
2011-02-11 14:34:12 +03:00
switch ( id ) {
case USB_ID ( 0x041e , 0x3000 ) :
/* SB Extigy needs special boot-up sequence */
/* if more models come, this will go to the quirk list. */
2010-03-04 21:46:13 +03:00
return snd_usb_extigy_boot_quirk ( dev , intf ) ;
2011-02-11 14:34:12 +03:00
case USB_ID ( 0x041e , 0x3020 ) :
/* SB Audigy 2 NX needs its own boot-up magic, too */
2010-03-04 21:46:13 +03:00
return snd_usb_audigy2nx_boot_quirk ( dev ) ;
2011-02-11 14:34:12 +03:00
case USB_ID ( 0x10f5 , 0x0200 ) :
/* C-Media CM106 / Turtle Beach Audio Advantage Roadie */
2010-03-04 21:46:13 +03:00
return snd_usb_cm106_boot_quirk ( dev ) ;
2011-02-11 14:34:12 +03:00
case USB_ID ( 0x0d8c , 0x0102 ) :
/* C-Media CM6206 / CM106-Like Sound Device */
2011-04-28 18:18:40 +04:00
case USB_ID ( 0x0ccd , 0x00b1 ) : /* Terratec Aureon 7.1 USB */
2010-03-04 21:46:13 +03:00
return snd_usb_cm6206_boot_quirk ( dev ) ;
2011-02-11 14:34:12 +03:00
case USB_ID ( 0x133e , 0x0815 ) :
/* Access Music VirusTI Desktop */
2010-03-04 21:46:13 +03:00
return snd_usb_accessmusic_boot_quirk ( dev ) ;
2011-05-18 13:28:41 +04:00
case USB_ID ( 0x17cc , 0x1000 ) : /* Komplete Audio 6 */
2011-02-11 14:34:12 +03:00
case USB_ID ( 0x17cc , 0x1010 ) : /* Traktor Audio 6 */
case USB_ID ( 0x17cc , 0x1020 ) : /* Traktor Audio 10 */
2011-02-11 14:08:06 +03:00
return snd_usb_nativeinstruments_boot_quirk ( dev ) ;
2011-02-11 14:34:12 +03:00
}
2011-02-11 14:08:06 +03:00
2010-03-04 21:46:13 +03:00
return 0 ;
}
/*
* check if the device uses big - endian samples
*/
int snd_usb_is_big_endian_format ( struct snd_usb_audio * chip , struct audioformat * fp )
{
switch ( chip - > usb_id ) {
case USB_ID ( 0x0763 , 0x2001 ) : /* M-Audio Quattro: captured data only */
if ( fp - > endpoint & USB_DIR_IN )
return 1 ;
break ;
case USB_ID ( 0x0763 , 0x2003 ) : /* M-Audio Audiophile USB */
if ( chip - > setup = = 0x00 | |
fp - > altsetting = = 1 | | fp - > altsetting = = 2 | | fp - > altsetting = = 3 )
return 1 ;
}
return 0 ;
}
/*
2011-02-08 09:22:36 +03:00
* For E - Mu 0404U SB / 0202U SB / TrackerPre / 0204 sample rate should be set for device ,
2010-03-04 21:46:13 +03:00
* not for interface .
*/
enum {
EMU_QUIRK_SR_44100HZ = 0 ,
EMU_QUIRK_SR_48000HZ ,
EMU_QUIRK_SR_88200HZ ,
EMU_QUIRK_SR_96000HZ ,
EMU_QUIRK_SR_176400HZ ,
EMU_QUIRK_SR_192000HZ
} ;
static void set_format_emu_quirk ( struct snd_usb_substream * subs ,
struct audioformat * fmt )
{
unsigned char emu_samplerate_id = 0 ;
/* When capture is active
* sample rate shouldn ' t be changed
* by playback substream
*/
if ( subs - > direction = = SNDRV_PCM_STREAM_PLAYBACK ) {
if ( subs - > stream - > substream [ SNDRV_PCM_STREAM_CAPTURE ] . interface ! = - 1 )
return ;
}
switch ( fmt - > rate_min ) {
case 48000 :
emu_samplerate_id = EMU_QUIRK_SR_48000HZ ;
break ;
case 88200 :
emu_samplerate_id = EMU_QUIRK_SR_88200HZ ;
break ;
case 96000 :
emu_samplerate_id = EMU_QUIRK_SR_96000HZ ;
break ;
case 176400 :
emu_samplerate_id = EMU_QUIRK_SR_176400HZ ;
break ;
case 192000 :
emu_samplerate_id = EMU_QUIRK_SR_192000HZ ;
break ;
default :
emu_samplerate_id = EMU_QUIRK_SR_44100HZ ;
break ;
}
snd_emuusb_set_samplerate ( subs - > stream - > chip , emu_samplerate_id ) ;
}
void snd_usb_set_format_quirk ( struct snd_usb_substream * subs ,
struct audioformat * fmt )
{
switch ( subs - > stream - > chip - > usb_id ) {
case USB_ID ( 0x041e , 0x3f02 ) : /* E-Mu 0202 USB */
case USB_ID ( 0x041e , 0x3f04 ) : /* E-Mu 0404 USB */
case USB_ID ( 0x041e , 0x3f0a ) : /* E-Mu Tracker Pre */
2011-02-08 09:22:36 +03:00
case USB_ID ( 0x041e , 0x3f19 ) : /* E-Mu 0204 USB */
2010-03-04 21:46:13 +03:00
set_format_emu_quirk ( subs , fmt ) ;
break ;
}
}