2019-05-27 09:55:05 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
2010-05-31 16:51:31 +04:00
/*
* Clock domain and sample rate management functions
*/
# include <linux/bitops.h>
# include <linux/init.h>
# include <linux/string.h>
# include <linux/usb.h>
# include <linux/usb/audio.h>
# include <linux/usb/audio-v2.h>
2018-03-21 03:03:59 +03:00
# include <linux/usb/audio-v3.h>
2010-05-31 16:51:31 +04:00
# include <sound/core.h>
# include <sound/info.h>
# include <sound/pcm.h>
# include "usbaudio.h"
# include "card.h"
# include "helper.h"
2010-06-16 19:57:27 +04:00
# include "clock.h"
2013-04-09 20:56:03 +04:00
# include "quirks.h"
2010-05-31 16:51:31 +04:00
2018-04-03 18:34:57 +03:00
static void * find_uac_clock_desc ( struct usb_host_interface * iface , int id ,
bool ( * validator ) ( void * , int ) , u8 type )
2010-05-31 16:51:31 +04:00
{
2018-04-03 18:34:57 +03:00
void * cs = NULL ;
2010-05-31 16:51:31 +04:00
2018-04-03 18:34:57 +03:00
while ( ( cs = snd_usb_find_csint_desc ( iface - > extra , iface - > extralen ,
cs , type ) ) ) {
if ( validator ( cs , id ) )
2010-05-31 16:51:31 +04:00
return cs ;
}
return NULL ;
}
2018-04-03 18:34:57 +03:00
static bool validate_clock_source_v2 ( void * p , int id )
2018-03-21 03:03:59 +03:00
{
2018-04-03 18:34:57 +03:00
struct uac_clock_source_descriptor * cs = p ;
2019-08-22 10:25:27 +03:00
return cs - > bClockID = = id ;
2018-03-21 03:03:59 +03:00
}
2018-04-03 18:34:57 +03:00
static bool validate_clock_source_v3 ( void * p , int id )
2010-05-31 16:51:31 +04:00
{
2018-04-03 18:34:57 +03:00
struct uac3_clock_source_descriptor * cs = p ;
2019-08-22 10:25:27 +03:00
return cs - > bClockID = = id ;
2010-05-31 16:51:31 +04:00
}
2018-04-03 18:34:57 +03:00
static bool validate_clock_selector_v2 ( void * p , int id )
2018-03-21 03:03:59 +03:00
{
2018-04-03 18:34:57 +03:00
struct uac_clock_selector_descriptor * cs = p ;
2019-08-22 10:25:27 +03:00
return cs - > bClockID = = id ;
2018-03-21 03:03:59 +03:00
}
2018-04-03 18:34:57 +03:00
static bool validate_clock_selector_v3 ( void * p , int id )
2010-05-31 16:51:31 +04:00
{
2018-04-03 18:34:57 +03:00
struct uac3_clock_selector_descriptor * cs = p ;
2019-08-22 10:25:27 +03:00
return cs - > bClockID = = id ;
2010-05-31 16:51:31 +04:00
}
2018-04-03 18:34:57 +03:00
static bool validate_clock_multiplier_v2 ( void * p , int id )
2018-03-21 03:03:59 +03:00
{
2018-04-03 18:34:57 +03:00
struct uac_clock_multiplier_descriptor * cs = p ;
2019-08-22 10:25:27 +03:00
return cs - > bClockID = = id ;
2018-04-03 18:34:57 +03:00
}
2018-03-21 03:03:59 +03:00
2018-04-03 18:34:57 +03:00
static bool validate_clock_multiplier_v3 ( void * p , int id )
{
struct uac3_clock_multiplier_descriptor * cs = p ;
2019-08-22 10:25:27 +03:00
return cs - > bClockID = = id ;
2018-04-03 18:34:57 +03:00
}
2018-03-21 03:03:59 +03:00
2018-04-03 18:34:57 +03:00
# define DEFINE_FIND_HELPER(name, obj, validator, type) \
static obj * name ( struct usb_host_interface * iface , int id ) \
{ \
return find_uac_clock_desc ( iface , id , validator , type ) ; \
2018-03-21 03:03:59 +03:00
}
2018-04-03 18:34:57 +03:00
DEFINE_FIND_HELPER ( snd_usb_find_clock_source ,
struct uac_clock_source_descriptor ,
validate_clock_source_v2 , UAC2_CLOCK_SOURCE ) ;
DEFINE_FIND_HELPER ( snd_usb_find_clock_source_v3 ,
struct uac3_clock_source_descriptor ,
validate_clock_source_v3 , UAC3_CLOCK_SOURCE ) ;
DEFINE_FIND_HELPER ( snd_usb_find_clock_selector ,
struct uac_clock_selector_descriptor ,
validate_clock_selector_v2 , UAC2_CLOCK_SELECTOR ) ;
DEFINE_FIND_HELPER ( snd_usb_find_clock_selector_v3 ,
struct uac3_clock_selector_descriptor ,
validate_clock_selector_v3 , UAC3_CLOCK_SELECTOR ) ;
DEFINE_FIND_HELPER ( snd_usb_find_clock_multiplier ,
struct uac_clock_multiplier_descriptor ,
validate_clock_multiplier_v2 , UAC2_CLOCK_MULTIPLIER ) ;
DEFINE_FIND_HELPER ( snd_usb_find_clock_multiplier_v3 ,
struct uac3_clock_multiplier_descriptor ,
validate_clock_multiplier_v3 , UAC3_CLOCK_MULTIPLIER ) ;
2010-05-31 16:51:31 +04:00
static int uac_clock_selector_get_val ( struct snd_usb_audio * chip , int selector_id )
{
unsigned char buf ;
int ret ;
ret = snd_usb_ctl_msg ( chip - > dev , usb_rcvctrlpipe ( chip - > dev , 0 ) ,
UAC2_CS_CUR ,
USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN ,
2010-06-11 19:34:20 +04:00
UAC2_CX_CLOCK_SELECTOR < < 8 ,
snd_usb_ctrl_intf ( chip ) | ( selector_id < < 8 ) ,
2011-09-26 23:15:27 +04:00
& buf , sizeof ( buf ) ) ;
2010-05-31 16:51:31 +04:00
if ( ret < 0 )
return ret ;
return buf ;
}
2013-04-04 01:18:55 +04:00
static int uac_clock_selector_set_val ( struct snd_usb_audio * chip , int selector_id ,
unsigned char pin )
{
int ret ;
ret = snd_usb_ctl_msg ( chip - > dev , usb_sndctrlpipe ( chip - > dev , 0 ) ,
UAC2_CS_CUR ,
USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT ,
UAC2_CX_CLOCK_SELECTOR < < 8 ,
snd_usb_ctrl_intf ( chip ) | ( selector_id < < 8 ) ,
& pin , sizeof ( pin ) ) ;
if ( ret < 0 )
return ret ;
if ( ret ! = sizeof ( pin ) ) {
2014-02-26 16:02:17 +04:00
usb_audio_err ( chip ,
" setting selector (id %d) unexpected length %d \n " ,
selector_id , ret ) ;
2013-04-04 01:18:55 +04:00
return - EINVAL ;
}
ret = uac_clock_selector_get_val ( chip , selector_id ) ;
if ( ret < 0 )
return ret ;
if ( ret ! = pin ) {
2014-02-26 16:02:17 +04:00
usb_audio_err ( chip ,
" setting selector (id %d) to %x failed (current: %d) \n " ,
selector_id , pin , ret ) ;
2013-04-04 01:18:55 +04:00
return - EINVAL ;
}
return ret ;
}
2020-02-13 02:54:50 +03:00
static bool uac_clock_source_is_valid_quirk ( struct snd_usb_audio * chip ,
struct audioformat * fmt ,
int source_id )
{
2020-02-29 18:18:15 +03:00
bool ret = false ;
int count ;
unsigned char data ;
struct usb_device * dev = chip - > dev ;
2020-02-13 02:54:50 +03:00
if ( fmt - > protocol = = UAC_VERSION_2 ) {
struct uac_clock_source_descriptor * cs_desc =
snd_usb_find_clock_source ( chip - > ctrl_intf , source_id ) ;
if ( ! cs_desc )
return false ;
2020-02-29 18:18:15 +03:00
/*
* Assume the clock is valid if clock source supports only one
* single sample rate , the terminal is connected directly to it
* ( there is no clock selector ) and clock type is internal .
* This is to deal with some Denon DJ controllers that always
* reports that clock is invalid .
*/
if ( fmt - > nr_rates = = 1 & &
( fmt - > clock & 0xff ) = = cs_desc - > bClockID & &
( cs_desc - > bmAttributes & 0x3 ) ! =
UAC_CLOCK_SOURCE_TYPE_EXT )
return true ;
}
/*
* MOTU MicroBook IIc
* Sample rate changes takes more than 2 seconds for this device . Clock
* validity request returns false during that period .
*/
if ( chip - > usb_id = = USB_ID ( 0x07fd , 0x0004 ) ) {
count = 0 ;
while ( ( ! ret ) & & ( count < 50 ) ) {
int err ;
msleep ( 100 ) ;
err = snd_usb_ctl_msg ( dev , usb_rcvctrlpipe ( dev , 0 ) , UAC2_CS_CUR ,
USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN ,
UAC2_CS_CONTROL_CLOCK_VALID < < 8 ,
snd_usb_ctrl_intf ( chip ) | ( source_id < < 8 ) ,
& data , sizeof ( data ) ) ;
if ( err < 0 ) {
dev_warn ( & dev - > dev ,
" %s(): cannot get clock validity for id %d \n " ,
__func__ , source_id ) ;
return false ;
}
ret = ! ! data ;
count + + ;
}
2020-02-13 02:54:50 +03:00
}
2020-02-29 18:18:15 +03:00
return ret ;
2020-02-13 02:54:50 +03:00
}
2018-03-21 03:03:59 +03:00
static bool uac_clock_source_is_valid ( struct snd_usb_audio * chip ,
2020-02-13 02:54:50 +03:00
struct audioformat * fmt ,
2018-03-21 03:03:59 +03:00
int source_id )
2010-05-31 16:51:31 +04:00
{
int err ;
unsigned char data ;
struct usb_device * dev = chip - > dev ;
2018-03-21 03:03:59 +03:00
u32 bmControls ;
2020-02-13 02:54:50 +03:00
if ( fmt - > protocol = = UAC_VERSION_3 ) {
2018-03-21 03:03:59 +03:00
struct uac3_clock_source_descriptor * cs_desc =
snd_usb_find_clock_source_v3 ( chip - > ctrl_intf , source_id ) ;
if ( ! cs_desc )
2019-10-29 20:52:00 +03:00
return false ;
2018-03-21 03:03:59 +03:00
bmControls = le32_to_cpu ( cs_desc - > bmControls ) ;
} else { /* UAC_VERSION_1/2 */
struct uac_clock_source_descriptor * cs_desc =
snd_usb_find_clock_source ( chip - > ctrl_intf , source_id ) ;
if ( ! cs_desc )
2019-10-29 20:52:00 +03:00
return false ;
2018-03-21 03:03:59 +03:00
bmControls = cs_desc - > bmControls ;
}
2011-05-18 13:28:44 +04:00
/* If a clock source can't tell us whether it's valid, we assume it is */
2018-03-21 03:03:59 +03:00
if ( ! uac_v2v3_control_is_readable ( bmControls ,
2018-03-23 00:39:55 +03:00
UAC2_CS_CONTROL_CLOCK_VALID ) )
2019-10-29 20:52:00 +03:00
return true ;
2010-05-31 16:51:31 +04:00
err = snd_usb_ctl_msg ( dev , usb_rcvctrlpipe ( dev , 0 ) , UAC2_CS_CUR ,
USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN ,
2010-06-11 19:34:20 +04:00
UAC2_CS_CONTROL_CLOCK_VALID < < 8 ,
snd_usb_ctrl_intf ( chip ) | ( source_id < < 8 ) ,
2011-09-26 23:15:27 +04:00
& data , sizeof ( data ) ) ;
2010-05-31 16:51:31 +04:00
if ( err < 0 ) {
2014-02-26 16:02:17 +04:00
dev_warn ( & dev - > dev ,
" %s(): cannot get clock validity for id %d \n " ,
2010-05-31 16:51:31 +04:00
__func__ , source_id ) ;
2019-10-29 20:52:00 +03:00
return false ;
2010-05-31 16:51:31 +04:00
}
2020-02-13 02:54:50 +03:00
if ( data )
return true ;
else
return uac_clock_source_is_valid_quirk ( chip , fmt , source_id ) ;
2010-05-31 16:51:31 +04:00
}
2020-02-13 02:54:50 +03:00
static int __uac_clock_find_source ( struct snd_usb_audio * chip ,
struct audioformat * fmt , int entity_id ,
2018-03-21 03:03:59 +03:00
unsigned long * visited , bool validate )
2010-05-31 16:51:31 +04:00
{
struct uac_clock_source_descriptor * source ;
struct uac_clock_selector_descriptor * selector ;
struct uac_clock_multiplier_descriptor * multiplier ;
entity_id & = 0xff ;
if ( test_and_set_bit ( entity_id , visited ) ) {
2014-02-26 16:02:17 +04:00
usb_audio_warn ( chip ,
" %s(): recursive clock topology detected, id %d. \n " ,
__func__ , entity_id ) ;
2010-05-31 16:51:31 +04:00
return - EINVAL ;
}
/* first, see if the ID we're looking for is a clock source already */
2010-06-16 19:57:31 +04:00
source = snd_usb_find_clock_source ( chip - > ctrl_intf , entity_id ) ;
2013-04-04 01:18:54 +04:00
if ( source ) {
entity_id = source - > bClockID ;
2020-02-13 02:54:50 +03:00
if ( validate & & ! uac_clock_source_is_valid ( chip , fmt ,
2018-03-21 03:03:59 +03:00
entity_id ) ) {
2014-02-26 16:02:17 +04:00
usb_audio_err ( chip ,
" clock source %d is not valid, cannot use \n " ,
entity_id ) ;
2013-04-04 01:18:54 +04:00
return - ENXIO ;
}
return entity_id ;
}
2010-05-31 16:51:31 +04:00
2010-06-16 19:57:31 +04:00
selector = snd_usb_find_clock_selector ( chip - > ctrl_intf , entity_id ) ;
2010-05-31 16:51:31 +04:00
if ( selector ) {
2013-04-04 01:18:55 +04:00
int ret , i , cur ;
2010-05-31 16:51:31 +04:00
/* the entity ID we are looking for is a selector.
* find out what it currently selects */
ret = uac_clock_selector_get_val ( chip , selector - > bClockID ) ;
if ( ret < 0 )
return ret ;
2010-06-16 19:57:30 +04:00
/* Selector values are one-based */
2010-05-31 16:51:31 +04:00
if ( ret > selector - > bNrInPins | | ret < 1 ) {
2014-02-26 16:02:17 +04:00
usb_audio_err ( chip ,
2010-05-31 16:51:31 +04:00
" %s(): selector reported illegal value, id %d, ret %d \n " ,
__func__ , selector - > bClockID , ret ) ;
return - EINVAL ;
}
2013-04-04 01:18:55 +04:00
cur = ret ;
2020-02-13 02:54:50 +03:00
ret = __uac_clock_find_source ( chip , fmt ,
selector - > baCSourceID [ ret - 1 ] ,
visited , validate ) ;
2013-04-04 01:18:56 +04:00
if ( ! validate | | ret > 0 | | ! chip - > autoclock )
2013-04-04 01:18:55 +04:00
return ret ;
/* The current clock source is invalid, try others. */
for ( i = 1 ; i < = selector - > bNrInPins ; i + + ) {
int err ;
if ( i = = cur )
continue ;
2020-02-13 02:54:50 +03:00
ret = __uac_clock_find_source ( chip , fmt ,
selector - > baCSourceID [ i - 1 ] ,
visited , true ) ;
2013-04-04 01:18:55 +04:00
if ( ret < 0 )
continue ;
err = uac_clock_selector_set_val ( chip , entity_id , i ) ;
if ( err < 0 )
continue ;
2014-02-26 16:02:17 +04:00
usb_audio_info ( chip ,
" found and selected valid clock source %d \n " ,
ret ) ;
2013-04-04 01:18:55 +04:00
return ret ;
}
return - ENXIO ;
2010-05-31 16:51:31 +04:00
}
/* FIXME: multipliers only act as pass-thru element for now */
2010-06-16 19:57:31 +04:00
multiplier = snd_usb_find_clock_multiplier ( chip - > ctrl_intf , entity_id ) ;
2010-05-31 16:51:31 +04:00
if ( multiplier )
2020-02-13 02:54:50 +03:00
return __uac_clock_find_source ( chip , fmt ,
multiplier - > bCSourceID ,
visited , validate ) ;
2010-05-31 16:51:31 +04:00
return - EINVAL ;
}
2020-02-13 02:54:50 +03:00
static int __uac3_clock_find_source ( struct snd_usb_audio * chip ,
struct audioformat * fmt , int entity_id ,
unsigned long * visited , bool validate )
2018-03-21 03:03:59 +03:00
{
struct uac3_clock_source_descriptor * source ;
struct uac3_clock_selector_descriptor * selector ;
struct uac3_clock_multiplier_descriptor * multiplier ;
entity_id & = 0xff ;
if ( test_and_set_bit ( entity_id , visited ) ) {
usb_audio_warn ( chip ,
" %s(): recursive clock topology detected, id %d. \n " ,
__func__ , entity_id ) ;
return - EINVAL ;
}
/* first, see if the ID we're looking for is a clock source already */
source = snd_usb_find_clock_source_v3 ( chip - > ctrl_intf , entity_id ) ;
if ( source ) {
entity_id = source - > bClockID ;
2020-02-13 02:54:50 +03:00
if ( validate & & ! uac_clock_source_is_valid ( chip , fmt ,
2018-03-21 03:03:59 +03:00
entity_id ) ) {
usb_audio_err ( chip ,
" clock source %d is not valid, cannot use \n " ,
entity_id ) ;
return - ENXIO ;
}
return entity_id ;
}
selector = snd_usb_find_clock_selector_v3 ( chip - > ctrl_intf , entity_id ) ;
if ( selector ) {
int ret , i , cur ;
/* the entity ID we are looking for is a selector.
* find out what it currently selects */
ret = uac_clock_selector_get_val ( chip , selector - > bClockID ) ;
if ( ret < 0 )
return ret ;
/* Selector values are one-based */
if ( ret > selector - > bNrInPins | | ret < 1 ) {
usb_audio_err ( chip ,
" %s(): selector reported illegal value, id %d, ret %d \n " ,
__func__ , selector - > bClockID , ret ) ;
return - EINVAL ;
}
cur = ret ;
2020-02-13 02:54:50 +03:00
ret = __uac3_clock_find_source ( chip , fmt ,
selector - > baCSourceID [ ret - 1 ] ,
2018-03-21 03:03:59 +03:00
visited , validate ) ;
if ( ! validate | | ret > 0 | | ! chip - > autoclock )
return ret ;
/* The current clock source is invalid, try others. */
for ( i = 1 ; i < = selector - > bNrInPins ; i + + ) {
int err ;
if ( i = = cur )
continue ;
2020-02-13 02:54:50 +03:00
ret = __uac3_clock_find_source ( chip , fmt ,
selector - > baCSourceID [ i - 1 ] ,
visited , true ) ;
2018-03-21 03:03:59 +03:00
if ( ret < 0 )
continue ;
err = uac_clock_selector_set_val ( chip , entity_id , i ) ;
if ( err < 0 )
continue ;
usb_audio_info ( chip ,
" found and selected valid clock source %d \n " ,
ret ) ;
return ret ;
}
return - ENXIO ;
}
/* FIXME: multipliers only act as pass-thru element for now */
multiplier = snd_usb_find_clock_multiplier_v3 ( chip - > ctrl_intf ,
entity_id ) ;
if ( multiplier )
2020-02-13 02:54:50 +03:00
return __uac3_clock_find_source ( chip , fmt ,
multiplier - > bCSourceID ,
2018-03-21 03:03:59 +03:00
visited , validate ) ;
return - EINVAL ;
}
2010-06-16 19:57:30 +04:00
/*
* For all kinds of sample rate settings and other device queries ,
* the clock source ( end - leaf ) must be used . However , clock selectors ,
* clock multipliers and sample rate converters may be specified as
* clock source input to terminal . This functions walks the clock path
* to its end and tries to find the source .
*
* The ' visited ' bitfield is used internally to detect recursive loops .
*
* Returns the clock source UnitID ( > = 0 ) on success , or an error .
*/
2020-02-13 02:54:50 +03:00
int snd_usb_clock_find_source ( struct snd_usb_audio * chip ,
struct audioformat * fmt , bool validate )
2010-05-31 16:51:31 +04:00
{
DECLARE_BITMAP ( visited , 256 ) ;
memset ( visited , 0 , sizeof ( visited ) ) ;
2018-03-21 03:03:59 +03:00
2020-02-13 02:54:50 +03:00
switch ( fmt - > protocol ) {
2018-03-21 03:03:59 +03:00
case UAC_VERSION_2 :
2020-02-13 02:54:50 +03:00
return __uac_clock_find_source ( chip , fmt , fmt - > clock , visited ,
2018-03-21 03:03:59 +03:00
validate ) ;
case UAC_VERSION_3 :
2020-02-13 02:54:50 +03:00
return __uac3_clock_find_source ( chip , fmt , fmt - > clock , visited ,
2018-03-21 03:03:59 +03:00
validate ) ;
default :
return - EINVAL ;
}
2010-05-31 16:51:31 +04:00
}
static int set_sample_rate_v1 ( struct snd_usb_audio * chip , int iface ,
struct usb_host_interface * alts ,
struct audioformat * fmt , int rate )
{
struct usb_device * dev = chip - > dev ;
unsigned int ep ;
unsigned char data [ 3 ] ;
int err , crate ;
2016-03-15 17:20:58 +03:00
if ( get_iface_desc ( alts ) - > bNumEndpoints < 1 )
return - EINVAL ;
2010-05-31 16:51:31 +04:00
ep = get_endpoint ( alts , 0 ) - > bEndpointAddress ;
/* if endpoint doesn't have sampling rate control, bail out */
2010-07-08 18:38:01 +04:00
if ( ! ( fmt - > attributes & UAC_EP_CS_ATTR_SAMPLE_RATE ) )
2010-05-31 16:51:31 +04:00
return 0 ;
data [ 0 ] = rate ;
data [ 1 ] = rate > > 8 ;
data [ 2 ] = rate > > 16 ;
2018-05-27 16:18:22 +03:00
err = snd_usb_ctl_msg ( dev , usb_sndctrlpipe ( dev , 0 ) , UAC_SET_CUR ,
USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_OUT ,
UAC_EP_CS_ATTR_SAMPLE_RATE < < 8 , ep ,
data , sizeof ( data ) ) ;
if ( err < 0 ) {
2014-02-26 16:02:17 +04:00
dev_err ( & dev - > dev , " %d:%d: cannot set freq %d to ep %#x \n " ,
iface , fmt - > altsetting , rate , ep ) ;
2010-05-31 16:51:31 +04:00
return err ;
}
2015-02-16 23:44:33 +03:00
/* Don't check the sample rate for devices which we know don't
* support reading */
if ( snd_usb_get_sample_rate_quirk ( chip ) )
return 0 ;
2016-04-29 12:49:04 +03:00
/* the firmware is likely buggy, don't repeat to fail too many times */
if ( chip - > sample_rate_read_error > 2 )
return 0 ;
2015-02-16 23:44:33 +03:00
2018-05-27 16:18:22 +03:00
err = snd_usb_ctl_msg ( dev , usb_rcvctrlpipe ( dev , 0 ) , UAC_GET_CUR ,
USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_IN ,
UAC_EP_CS_ATTR_SAMPLE_RATE < < 8 , ep ,
data , sizeof ( data ) ) ;
if ( err < 0 ) {
2014-02-26 16:02:17 +04:00
dev_err ( & dev - > dev , " %d:%d: cannot get freq at ep %#x \n " ,
iface , fmt - > altsetting , ep ) ;
2016-04-29 12:49:04 +03:00
chip - > sample_rate_read_error + + ;
2010-05-31 16:51:31 +04:00
return 0 ; /* some devices don't support reading */
}
crate = data [ 0 ] | ( data [ 1 ] < < 8 ) | ( data [ 2 ] < < 16 ) ;
if ( crate ! = rate ) {
2014-02-26 16:02:17 +04:00
dev_warn ( & dev - > dev , " current rate %d is different from the runtime rate %d \n " , crate , rate ) ;
2010-05-31 16:51:31 +04:00
// runtime->rate = crate;
}
return 0 ;
}
2018-03-21 03:03:59 +03:00
static int get_sample_rate_v2v3 ( struct snd_usb_audio * chip , int iface ,
2013-04-03 21:08:29 +04:00
int altsetting , int clock )
{
struct usb_device * dev = chip - > dev ;
2013-04-04 01:18:53 +04:00
__le32 data ;
2013-04-03 21:08:29 +04:00
int err ;
err = snd_usb_ctl_msg ( dev , usb_rcvctrlpipe ( dev , 0 ) , UAC2_CS_CUR ,
USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN ,
UAC2_CS_CONTROL_SAM_FREQ < < 8 ,
snd_usb_ctrl_intf ( chip ) | ( clock < < 8 ) ,
2013-04-04 01:18:53 +04:00
& data , sizeof ( data ) ) ;
2013-04-03 21:08:29 +04:00
if ( err < 0 ) {
2018-03-21 03:03:59 +03:00
dev_warn ( & dev - > dev , " %d:%d: cannot get freq (v2/v3): err %d \n " ,
2014-02-26 16:02:17 +04:00
iface , altsetting , err ) ;
2013-04-03 21:08:29 +04:00
return 0 ;
}
2013-04-04 01:18:53 +04:00
return le32_to_cpu ( data ) ;
2013-04-03 21:08:29 +04:00
}
2018-03-21 03:03:59 +03:00
static int set_sample_rate_v2v3 ( struct snd_usb_audio * chip , int iface ,
2010-05-31 16:51:31 +04:00
struct usb_host_interface * alts ,
struct audioformat * fmt , int rate )
{
struct usb_device * dev = chip - > dev ;
2013-04-04 01:18:53 +04:00
__le32 data ;
2013-03-27 01:10:05 +04:00
int err , cur_rate , prev_rate ;
2013-04-04 01:18:55 +04:00
int clock ;
2013-04-04 01:18:58 +04:00
bool writeable ;
2018-03-21 03:03:59 +03:00
u32 bmControls ;
2010-05-31 16:51:31 +04:00
2018-07-18 23:41:05 +03:00
/* First, try to find a valid clock. This may trigger
* automatic clock selection if the current clock is not
* valid .
*/
2020-02-13 02:54:50 +03:00
clock = snd_usb_clock_find_source ( chip , fmt , true ) ;
2018-07-18 23:41:05 +03:00
if ( clock < 0 ) {
/* We did not find a valid clock, but that might be
* because the current sample rate does not match an
* external clock source . Try again without validation
* and we will do another validation after setting the
* rate .
*/
2020-02-13 02:54:50 +03:00
clock = snd_usb_clock_find_source ( chip , fmt , false ) ;
2018-07-18 23:41:05 +03:00
if ( clock < 0 )
return clock ;
}
2010-05-31 16:51:31 +04:00
2018-03-21 03:03:59 +03:00
prev_rate = get_sample_rate_v2v3 ( chip , iface , fmt - > altsetting , clock ) ;
2013-04-25 16:32:24 +04:00
if ( prev_rate = = rate )
2018-07-18 23:41:05 +03:00
goto validation ;
2013-03-27 01:10:05 +04:00
2018-03-21 03:03:59 +03:00
if ( fmt - > protocol = = UAC_VERSION_3 ) {
struct uac3_clock_source_descriptor * cs_desc ;
cs_desc = snd_usb_find_clock_source_v3 ( chip - > ctrl_intf , clock ) ;
bmControls = le32_to_cpu ( cs_desc - > bmControls ) ;
} else {
struct uac_clock_source_descriptor * cs_desc ;
cs_desc = snd_usb_find_clock_source ( chip - > ctrl_intf , clock ) ;
bmControls = cs_desc - > bmControls ;
}
2018-03-23 00:39:55 +03:00
writeable = uac_v2v3_control_is_writeable ( bmControls ,
UAC2_CS_CONTROL_SAM_FREQ ) ;
2013-04-04 01:18:58 +04:00
if ( writeable ) {
data = cpu_to_le32 ( rate ) ;
err = snd_usb_ctl_msg ( dev , usb_sndctrlpipe ( dev , 0 ) , UAC2_CS_CUR ,
USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT ,
UAC2_CS_CONTROL_SAM_FREQ < < 8 ,
snd_usb_ctrl_intf ( chip ) | ( clock < < 8 ) ,
& data , sizeof ( data ) ) ;
if ( err < 0 ) {
2014-02-26 16:02:17 +04:00
usb_audio_err ( chip ,
2018-03-21 03:03:59 +03:00
" %d:%d: cannot set freq %d (v2/v3): err %d \n " ,
2014-02-26 16:02:17 +04:00
iface , fmt - > altsetting , rate , err ) ;
2013-04-04 01:18:58 +04:00
return err ;
}
2010-05-31 16:51:31 +04:00
2018-03-21 03:03:59 +03:00
cur_rate = get_sample_rate_v2v3 ( chip , iface ,
fmt - > altsetting , clock ) ;
2013-04-04 01:18:58 +04:00
} else {
cur_rate = prev_rate ;
}
2010-05-31 16:51:31 +04:00
2013-03-27 01:10:05 +04:00
if ( cur_rate ! = rate ) {
2013-04-04 01:18:58 +04:00
if ( ! writeable ) {
2014-02-26 16:02:17 +04:00
usb_audio_warn ( chip ,
" %d:%d: freq mismatch (RO clock): req %d, clock runs @%d \n " ,
iface , fmt - > altsetting , rate , cur_rate ) ;
2013-04-04 01:18:58 +04:00
return - ENXIO ;
}
2014-02-26 16:02:17 +04:00
usb_audio_dbg ( chip ,
" current rate %d is different from the runtime rate %d \n " ,
cur_rate , rate ) ;
2013-03-27 01:10:05 +04:00
}
/* Some devices doesn't respond to sample rate changes while the
* interface is active . */
if ( rate ! = prev_rate ) {
usb_set_interface ( dev , iface , 0 ) ;
2013-04-09 20:56:03 +04:00
snd_usb_set_interface_quirk ( dev ) ;
2013-03-27 01:10:05 +04:00
usb_set_interface ( dev , iface , fmt - > altsetting ) ;
2013-04-09 20:56:03 +04:00
snd_usb_set_interface_quirk ( dev ) ;
2013-03-27 01:10:05 +04:00
}
2010-05-31 16:51:31 +04:00
2018-07-18 23:41:05 +03:00
validation :
/* validate clock after rate change */
2020-02-13 02:54:50 +03:00
if ( ! uac_clock_source_is_valid ( chip , fmt , clock ) )
2018-07-18 23:41:05 +03:00
return - ENXIO ;
2010-05-31 16:51:31 +04:00
return 0 ;
}
int snd_usb_init_sample_rate ( struct snd_usb_audio * chip , int iface ,
struct usb_host_interface * alts ,
struct audioformat * fmt , int rate )
{
2013-02-01 00:39:17 +04:00
switch ( fmt - > protocol ) {
2010-05-31 16:51:31 +04:00
case UAC_VERSION_1 :
2010-09-03 12:53:11 +04:00
default :
2010-05-31 16:51:31 +04:00
return set_sample_rate_v1 ( chip , iface , alts , fmt , rate ) ;
2018-03-21 03:03:59 +03:00
case UAC_VERSION_3 :
2018-05-04 04:24:04 +03:00
if ( chip - > badd_profile > = UAC3_FUNCTION_SUBCLASS_GENERIC_IO ) {
if ( rate ! = UAC3_BADD_SAMPLING_RATE )
return - ENXIO ;
else
return 0 ;
}
2020-07-08 23:32:36 +03:00
fallthrough ;
2018-05-04 04:24:04 +03:00
case UAC_VERSION_2 :
2018-03-21 03:03:59 +03:00
return set_sample_rate_v2v3 ( chip , iface , alts , fmt , rate ) ;
2010-05-31 16:51:31 +04:00
}
}