2019-05-29 16:57:59 -07:00
// SPDX-License-Identifier: GPL-2.0-only
2014-04-25 22:45:15 +09:00
/*
* bebob_command . c - driver for BeBoB based devices
*
* Copyright ( c ) 2013 - 2014 Takashi Sakamoto
*/
# include "./bebob.h"
2014-04-25 22:45:21 +09:00
int avc_audio_set_selector ( struct fw_unit * unit , unsigned int subunit_id ,
unsigned int fb_id , unsigned int num )
{
u8 * buf ;
int err ;
buf = kzalloc ( 12 , GFP_KERNEL ) ;
if ( buf = = NULL )
return - ENOMEM ;
buf [ 0 ] = 0x00 ; /* AV/C CONTROL */
buf [ 1 ] = 0x08 | ( 0x07 & subunit_id ) ; /* AUDIO SUBUNIT ID */
buf [ 2 ] = 0xb8 ; /* FUNCTION BLOCK */
buf [ 3 ] = 0x80 ; /* type is 'selector'*/
buf [ 4 ] = 0xff & fb_id ; /* function block id */
buf [ 5 ] = 0x10 ; /* control attribute is CURRENT */
buf [ 6 ] = 0x02 ; /* selector length is 2 */
buf [ 7 ] = 0xff & num ; /* input function block plug number */
buf [ 8 ] = 0x01 ; /* control selector is SELECTOR_CONTROL */
err = fcp_avc_transaction ( unit , buf , 12 , buf , 12 ,
BIT ( 1 ) | BIT ( 2 ) | BIT ( 3 ) | BIT ( 4 ) | BIT ( 5 ) |
BIT ( 6 ) | BIT ( 7 ) | BIT ( 8 ) ) ;
2017-04-03 21:13:55 +09:00
if ( err < 0 )
;
else if ( err < 9 )
2014-04-25 22:45:21 +09:00
err = - EIO ;
else if ( buf [ 0 ] = = 0x08 ) /* NOT IMPLEMENTED */
err = - ENOSYS ;
else if ( buf [ 0 ] = = 0x0a ) /* REJECTED */
err = - EINVAL ;
2017-04-03 21:13:55 +09:00
else
2014-04-25 22:45:21 +09:00
err = 0 ;
kfree ( buf ) ;
return err ;
}
int avc_audio_get_selector ( struct fw_unit * unit , unsigned int subunit_id ,
unsigned int fb_id , unsigned int * num )
{
u8 * buf ;
int err ;
buf = kzalloc ( 12 , GFP_KERNEL ) ;
if ( buf = = NULL )
return - ENOMEM ;
buf [ 0 ] = 0x01 ; /* AV/C STATUS */
buf [ 1 ] = 0x08 | ( 0x07 & subunit_id ) ; /* AUDIO SUBUNIT ID */
buf [ 2 ] = 0xb8 ; /* FUNCTION BLOCK */
buf [ 3 ] = 0x80 ; /* type is 'selector'*/
buf [ 4 ] = 0xff & fb_id ; /* function block id */
buf [ 5 ] = 0x10 ; /* control attribute is CURRENT */
buf [ 6 ] = 0x02 ; /* selector length is 2 */
buf [ 7 ] = 0xff ; /* input function block plug number */
buf [ 8 ] = 0x01 ; /* control selector is SELECTOR_CONTROL */
err = fcp_avc_transaction ( unit , buf , 12 , buf , 12 ,
BIT ( 1 ) | BIT ( 2 ) | BIT ( 3 ) | BIT ( 4 ) | BIT ( 5 ) |
BIT ( 6 ) | BIT ( 8 ) ) ;
2017-04-03 21:13:55 +09:00
if ( err < 0 )
;
else if ( err < 9 )
2014-04-25 22:45:21 +09:00
err = - EIO ;
else if ( buf [ 0 ] = = 0x08 ) /* NOT IMPLEMENTED */
err = - ENOSYS ;
else if ( buf [ 0 ] = = 0x0a ) /* REJECTED */
err = - EINVAL ;
else if ( buf [ 0 ] = = 0x0b ) /* IN TRANSITION */
err = - EAGAIN ;
if ( err < 0 )
goto end ;
* num = buf [ 7 ] ;
err = 0 ;
end :
kfree ( buf ) ;
return err ;
}
2014-04-25 22:45:15 +09:00
static inline void
avc_bridgeco_fill_extension_addr ( u8 * buf , u8 * addr )
{
buf [ 1 ] = addr [ 0 ] ;
memcpy ( buf + 4 , addr + 1 , 5 ) ;
}
static inline void
avc_bridgeco_fill_plug_info_extension_command ( u8 * buf , u8 * addr ,
unsigned int itype )
{
buf [ 0 ] = 0x01 ; /* AV/C STATUS */
buf [ 2 ] = 0x02 ; /* AV/C GENERAL PLUG INFO */
buf [ 3 ] = 0xc0 ; /* BridgeCo extension */
avc_bridgeco_fill_extension_addr ( buf , addr ) ;
buf [ 9 ] = itype ; /* info type */
}
int avc_bridgeco_get_plug_type ( struct fw_unit * unit ,
u8 addr [ AVC_BRIDGECO_ADDR_BYTES ] ,
enum avc_bridgeco_plug_type * type )
{
u8 * buf ;
int err ;
buf = kzalloc ( 12 , GFP_KERNEL ) ;
if ( buf = = NULL )
return - ENOMEM ;
/* Info type is 'plug type'. */
avc_bridgeco_fill_plug_info_extension_command ( buf , addr , 0x00 ) ;
err = fcp_avc_transaction ( unit , buf , 12 , buf , 12 ,
BIT ( 1 ) | BIT ( 2 ) | BIT ( 3 ) | BIT ( 4 ) | BIT ( 5 ) |
BIT ( 6 ) | BIT ( 7 ) | BIT ( 9 ) ) ;
2017-04-03 21:13:55 +09:00
if ( err < 0 )
;
else if ( err < 11 )
2014-04-25 22:45:15 +09:00
err = - EIO ;
else if ( buf [ 0 ] = = 0x08 ) /* NOT IMPLEMENTED */
err = - ENOSYS ;
else if ( buf [ 0 ] = = 0x0a ) /* REJECTED */
err = - EINVAL ;
else if ( buf [ 0 ] = = 0x0b ) /* IN TRANSITION */
err = - EAGAIN ;
if ( err < 0 )
goto end ;
* type = buf [ 10 ] ;
err = 0 ;
end :
kfree ( buf ) ;
return err ;
}
int avc_bridgeco_get_plug_ch_pos ( struct fw_unit * unit ,
u8 addr [ AVC_BRIDGECO_ADDR_BYTES ] ,
u8 * buf , unsigned int len )
{
int err ;
/* Info type is 'channel position'. */
avc_bridgeco_fill_plug_info_extension_command ( buf , addr , 0x03 ) ;
err = fcp_avc_transaction ( unit , buf , 12 , buf , 256 ,
BIT ( 1 ) | BIT ( 2 ) | BIT ( 3 ) | BIT ( 4 ) |
BIT ( 5 ) | BIT ( 6 ) | BIT ( 7 ) | BIT ( 9 ) ) ;
2017-04-03 21:13:55 +09:00
if ( err < 0 )
;
else if ( err < 11 )
2014-04-25 22:45:15 +09:00
err = - EIO ;
else if ( buf [ 0 ] = = 0x08 ) /* NOT IMPLEMENTED */
err = - ENOSYS ;
else if ( buf [ 0 ] = = 0x0a ) /* REJECTED */
err = - EINVAL ;
else if ( buf [ 0 ] = = 0x0b ) /* IN TRANSITION */
err = - EAGAIN ;
if ( err < 0 )
goto end ;
/* Pick up specific data. */
memmove ( buf , buf + 10 , err - 10 ) ;
err = 0 ;
end :
return err ;
}
int avc_bridgeco_get_plug_section_type ( struct fw_unit * unit ,
u8 addr [ AVC_BRIDGECO_ADDR_BYTES ] ,
unsigned int id , u8 * type )
{
u8 * buf ;
int err ;
/* section info includes charactors but this module don't need it */
buf = kzalloc ( 12 , GFP_KERNEL ) ;
if ( buf = = NULL )
return - ENOMEM ;
/* Info type is 'section info'. */
avc_bridgeco_fill_plug_info_extension_command ( buf , addr , 0x07 ) ;
buf [ 10 ] = 0xff & + + id ; /* section id */
err = fcp_avc_transaction ( unit , buf , 12 , buf , 12 ,
BIT ( 1 ) | BIT ( 2 ) | BIT ( 3 ) | BIT ( 4 ) | BIT ( 5 ) |
BIT ( 6 ) | BIT ( 7 ) | BIT ( 9 ) | BIT ( 10 ) ) ;
2017-04-03 21:13:55 +09:00
if ( err < 0 )
;
else if ( err < 12 )
2014-04-25 22:45:15 +09:00
err = - EIO ;
else if ( buf [ 0 ] = = 0x08 ) /* NOT IMPLEMENTED */
err = - ENOSYS ;
else if ( buf [ 0 ] = = 0x0a ) /* REJECTED */
err = - EINVAL ;
else if ( buf [ 0 ] = = 0x0b ) /* IN TRANSITION */
err = - EAGAIN ;
if ( err < 0 )
goto end ;
* type = buf [ 11 ] ;
err = 0 ;
end :
kfree ( buf ) ;
return err ;
}
int avc_bridgeco_get_plug_input ( struct fw_unit * unit ,
u8 addr [ AVC_BRIDGECO_ADDR_BYTES ] , u8 input [ 7 ] )
{
int err ;
u8 * buf ;
buf = kzalloc ( 18 , GFP_KERNEL ) ;
if ( buf = = NULL )
return - ENOMEM ;
/* Info type is 'plug input'. */
avc_bridgeco_fill_plug_info_extension_command ( buf , addr , 0x05 ) ;
err = fcp_avc_transaction ( unit , buf , 16 , buf , 16 ,
BIT ( 1 ) | BIT ( 2 ) | BIT ( 3 ) | BIT ( 4 ) | BIT ( 5 ) |
BIT ( 6 ) | BIT ( 7 ) ) ;
2017-04-03 21:13:55 +09:00
if ( err < 0 )
;
else if ( err < 16 )
2014-04-25 22:45:15 +09:00
err = - EIO ;
else if ( buf [ 0 ] = = 0x08 ) /* NOT IMPLEMENTED */
err = - ENOSYS ;
else if ( buf [ 0 ] = = 0x0a ) /* REJECTED */
err = - EINVAL ;
else if ( buf [ 0 ] = = 0x0b ) /* IN TRANSITION */
err = - EAGAIN ;
if ( err < 0 )
goto end ;
memcpy ( input , buf + 10 , 5 ) ;
err = 0 ;
end :
kfree ( buf ) ;
return err ;
}
int avc_bridgeco_get_plug_strm_fmt ( struct fw_unit * unit ,
u8 addr [ AVC_BRIDGECO_ADDR_BYTES ] , u8 * buf ,
unsigned int * len , unsigned int eid )
{
int err ;
/* check given buffer */
if ( ( buf = = NULL ) | | ( * len < 12 ) ) {
err = - EINVAL ;
goto end ;
}
buf [ 0 ] = 0x01 ; /* AV/C STATUS */
buf [ 2 ] = 0x2f ; /* AV/C STREAM FORMAT SUPPORT */
buf [ 3 ] = 0xc1 ; /* Bridgeco extension - List Request */
avc_bridgeco_fill_extension_addr ( buf , addr ) ;
buf [ 10 ] = 0xff & eid ; /* Entry ID */
err = fcp_avc_transaction ( unit , buf , 12 , buf , * len ,
BIT ( 1 ) | BIT ( 2 ) | BIT ( 3 ) | BIT ( 4 ) | BIT ( 5 ) |
BIT ( 6 ) | BIT ( 7 ) | BIT ( 10 ) ) ;
2017-04-03 21:13:55 +09:00
if ( err < 0 )
;
else if ( err < 12 )
2014-04-25 22:45:15 +09:00
err = - EIO ;
else if ( buf [ 0 ] = = 0x08 ) /* NOT IMPLEMENTED */
err = - ENOSYS ;
else if ( buf [ 0 ] = = 0x0a ) /* REJECTED */
err = - EINVAL ;
else if ( buf [ 0 ] = = 0x0b ) /* IN TRANSITION */
err = - EAGAIN ;
else if ( buf [ 10 ] ! = eid )
err = - EIO ;
if ( err < 0 )
goto end ;
/* Pick up 'stream format info'. */
memmove ( buf , buf + 11 , err - 11 ) ;
* len = err - 11 ;
err = 0 ;
end :
return err ;
}