2019-06-04 10:11:33 +02:00
// SPDX-License-Identifier: GPL-2.0-only
2015-05-09 11:26:47 +01:00
/*
* PCM DRM helpers
*/
# include <linux/export.h>
# include <linux/types.h>
# include <sound/asoundef.h>
# include <sound/pcm.h>
2016-03-31 16:35:58 +03:00
# include <sound/pcm_params.h>
2015-05-09 11:26:47 +01:00
# include <sound/pcm_iec958.h>
2021-05-25 15:23:44 +02:00
/**
* snd_pcm_create_iec958_consumer_default - create default consumer format IEC958 channel status
* @ cs : channel status buffer , at least four bytes
* @ len : length of channel status buffer
*
* Create the consumer format channel status data in @ cs of maximum size
* @ len . When relevant , the configuration - dependant bits will be set as
* unspecified .
*
* Drivers should then call einter snd_pcm_fill_iec958_consumer ( ) or
* snd_pcm_fill_iec958_consumer_hw_params ( ) to replace these unspecified
* bits by their actual values .
*
* Drivers may wish to tweak the contents of the buffer after creation .
*
* Returns : length of buffer , or negative error code if something failed .
*/
int snd_pcm_create_iec958_consumer_default ( u8 * cs , size_t len )
2015-05-09 11:26:47 +01:00
{
if ( len < 4 )
return - EINVAL ;
2021-05-25 15:23:44 +02:00
memset ( cs , 0 , len ) ;
cs [ 0 ] = IEC958_AES0_CON_NOT_COPYRIGHT | IEC958_AES0_CON_EMPHASIS_NONE ;
cs [ 1 ] = IEC958_AES1_CON_GENERAL ;
cs [ 2 ] = IEC958_AES2_CON_SOURCE_UNSPEC | IEC958_AES2_CON_CHANNEL_UNSPEC ;
cs [ 3 ] = IEC958_AES3_CON_CLOCK_1000PPM | IEC958_AES3_CON_FS_NOTID ;
if ( len > 4 )
cs [ 4 ] = IEC958_AES4_CON_WORDLEN_NOTID ;
return len ;
}
EXPORT_SYMBOL_GPL ( snd_pcm_create_iec958_consumer_default ) ;
static int fill_iec958_consumer ( uint rate , uint sample_width ,
u8 * cs , size_t len )
{
if ( len < 4 )
2015-05-09 11:26:47 +01:00
return - EINVAL ;
2021-05-25 15:23:44 +02:00
if ( ( cs [ 3 ] & IEC958_AES3_CON_FS ) = = IEC958_AES3_CON_FS_NOTID ) {
unsigned int fs ;
switch ( rate ) {
case 32000 :
fs = IEC958_AES3_CON_FS_32000 ;
break ;
case 44100 :
fs = IEC958_AES3_CON_FS_44100 ;
break ;
case 48000 :
fs = IEC958_AES3_CON_FS_48000 ;
break ;
case 88200 :
fs = IEC958_AES3_CON_FS_88200 ;
break ;
case 96000 :
fs = IEC958_AES3_CON_FS_96000 ;
break ;
case 176400 :
fs = IEC958_AES3_CON_FS_176400 ;
break ;
case 192000 :
fs = IEC958_AES3_CON_FS_192000 ;
break ;
default :
return - EINVAL ;
}
cs [ 3 ] & = ~ IEC958_AES3_CON_FS ;
cs [ 3 ] | = fs ;
2015-05-09 11:26:47 +01:00
}
2021-05-25 15:23:44 +02:00
if ( len > 4 & &
( cs [ 4 ] & IEC958_AES4_CON_WORDLEN ) = = IEC958_AES4_CON_WORDLEN_NOTID ) {
unsigned int ws ;
2016-03-31 16:35:58 +03:00
switch ( sample_width ) {
2015-05-09 11:26:47 +01:00
case 16 :
ws = IEC958_AES4_CON_WORDLEN_20_16 ;
break ;
case 18 :
ws = IEC958_AES4_CON_WORDLEN_22_18 ;
break ;
case 20 :
ws = IEC958_AES4_CON_WORDLEN_20_16 |
IEC958_AES4_CON_MAX_WORDLEN_24 ;
break ;
case 24 :
2016-03-31 16:35:59 +03:00
case 32 : /* Assume 24-bit width for 32-bit samples. */
2015-05-09 11:26:47 +01:00
ws = IEC958_AES4_CON_WORDLEN_24_20 |
IEC958_AES4_CON_MAX_WORDLEN_24 ;
break ;
default :
return - EINVAL ;
}
2021-05-25 15:23:44 +02:00
cs [ 4 ] & = ~ IEC958_AES4_CON_WORDLEN ;
cs [ 4 ] | = ws ;
}
2015-05-09 11:26:47 +01:00
2021-05-25 15:23:44 +02:00
return len ;
}
2015-05-09 11:26:47 +01:00
2021-05-25 15:23:44 +02:00
/**
* snd_pcm_fill_iec958_consumer - Fill consumer format IEC958 channel status
* @ runtime : pcm runtime structure with - > rate filled in
* @ cs : channel status buffer , at least four bytes
* @ len : length of channel status buffer
*
* Fill the unspecified bits in an IEC958 status bits array using the
* parameters of the PCM runtime @ runtime .
*
* Drivers may wish to tweak the contents of the buffer after its been
* filled .
*
* Returns : length of buffer , or negative error code if something failed .
*/
int snd_pcm_fill_iec958_consumer ( struct snd_pcm_runtime * runtime ,
u8 * cs , size_t len )
{
return fill_iec958_consumer ( runtime - > rate ,
snd_pcm_format_width ( runtime - > format ) ,
cs , len ) ;
}
EXPORT_SYMBOL_GPL ( snd_pcm_fill_iec958_consumer ) ;
2015-05-09 11:26:47 +01:00
2021-05-25 15:23:44 +02:00
/**
* snd_pcm_fill_iec958_consumer_hw_params - Fill consumer format IEC958 channel status
* @ params : the hw_params instance for extracting rate and sample format
* @ cs : channel status buffer , at least four bytes
* @ len : length of channel status buffer
*
* Fill the unspecified bits in an IEC958 status bits array using the
* parameters of the PCM hardware parameters @ params .
*
* Drivers may wish to tweak the contents of the buffer after its been
* filled . .
*
* Returns : length of buffer , or negative error code if something failed .
*/
int snd_pcm_fill_iec958_consumer_hw_params ( struct snd_pcm_hw_params * params ,
u8 * cs , size_t len )
{
return fill_iec958_consumer ( params_rate ( params ) , params_width ( params ) , cs , len ) ;
2015-05-09 11:26:47 +01:00
}
2021-05-25 15:23:44 +02:00
EXPORT_SYMBOL_GPL ( snd_pcm_fill_iec958_consumer_hw_params ) ;
2016-03-31 16:35:58 +03:00
/**
* snd_pcm_create_iec958_consumer - create consumer format IEC958 channel status
* @ runtime : pcm runtime structure with - > rate filled in
* @ cs : channel status buffer , at least four bytes
* @ len : length of channel status buffer
*
* Create the consumer format channel status data in @ cs of maximum size
* @ len corresponding to the parameters of the PCM runtime @ runtime .
*
* Drivers may wish to tweak the contents of the buffer after creation .
*
* Returns : length of buffer , or negative error code if something failed .
*/
int snd_pcm_create_iec958_consumer ( struct snd_pcm_runtime * runtime , u8 * cs ,
size_t len )
{
2021-05-25 15:23:44 +02:00
int ret ;
ret = snd_pcm_create_iec958_consumer_default ( cs , len ) ;
if ( ret < 0 )
return ret ;
return snd_pcm_fill_iec958_consumer ( runtime , cs , len ) ;
2016-03-31 16:35:58 +03:00
}
2015-05-09 11:26:47 +01:00
EXPORT_SYMBOL ( snd_pcm_create_iec958_consumer ) ;
2016-03-31 16:35:58 +03:00
/**
* snd_pcm_create_iec958_consumer_hw_params - create IEC958 channel status
2020-07-02 14:38:42 -05:00
* @ params : the hw_params instance for extracting rate and sample format
2016-03-31 16:35:58 +03:00
* @ cs : channel status buffer , at least four bytes
* @ len : length of channel status buffer
*
* Create the consumer format channel status data in @ cs of maximum size
* @ len corresponding to the parameters of the PCM runtime @ runtime .
*
* Drivers may wish to tweak the contents of the buffer after creation .
*
* Returns : length of buffer , or negative error code if something failed .
*/
int snd_pcm_create_iec958_consumer_hw_params ( struct snd_pcm_hw_params * params ,
u8 * cs , size_t len )
{
2021-05-25 15:23:44 +02:00
int ret ;
ret = snd_pcm_create_iec958_consumer_default ( cs , len ) ;
if ( ret < 0 )
return ret ;
return fill_iec958_consumer ( params_rate ( params ) , params_width ( params ) , cs , len ) ;
2016-03-31 16:35:58 +03:00
}
EXPORT_SYMBOL ( snd_pcm_create_iec958_consumer_hw_params ) ;