2019-05-27 09:55:15 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2011-12-23 09:06:39 +04:00
/*
* compress_core . c - compress offload core
*
* Copyright ( C ) 2011 Intel Corporation
* Authors : Vinod Koul < vinod . koul @ linux . intel . com >
* Pierre - Louis Bossart < pierre - louis . bossart @ linux . intel . com >
* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
*
* ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~
*/
# define FORMAT(fmt) "%s: %d: " fmt, __func__, __LINE__
# define pr_fmt(fmt) KBUILD_MODNAME ": " FORMAT(fmt)
# include <linux/file.h>
# include <linux/fs.h>
# include <linux/list.h>
2013-04-18 14:03:46 +04:00
# include <linux/math64.h>
2011-12-23 09:06:39 +04:00
# include <linux/mm.h>
# include <linux/mutex.h>
# include <linux/poll.h>
# include <linux/slab.h>
# include <linux/sched.h>
2013-04-18 14:03:46 +04:00
# include <linux/types.h>
2011-12-23 09:06:39 +04:00
# include <linux/uio.h>
# include <linux/uaccess.h>
# include <linux/module.h>
2015-12-07 09:38:31 +03:00
# include <linux/compat.h>
2011-12-23 09:06:39 +04:00
# include <sound/core.h>
# include <sound/initval.h>
2015-11-25 16:00:23 +03:00
# include <sound/info.h>
2011-12-23 09:06:39 +04:00
# include <sound/compress_params.h>
# include <sound/compress_offload.h>
# include <sound/compress_driver.h>
2016-01-25 15:59:21 +03:00
/* struct snd_compr_codec_caps overflows the ioctl bit size for some
* architectures , so we need to disable the relevant ioctls .
*/
# if _IOC_SIZEBITS < 14
# define COMPR_CODEC_CAPS_OVERFLOW
# endif
2011-12-23 09:06:39 +04:00
/* TODO:
* - add substream support for multiple devices in case of
* SND_DYNAMIC_MINORS is not used
* - Multiple node representation
* driver should be able to register multiple nodes
*/
struct snd_compr_file {
unsigned long caps ;
struct snd_compr_stream stream ;
} ;
2016-06-13 16:17:10 +03:00
static void error_delayed_work ( struct work_struct * work ) ;
2011-12-23 09:06:39 +04:00
/*
* a note on stream states used :
2016-03-04 17:55:30 +03:00
* we use following states in the compressed core
2011-12-23 09:06:39 +04:00
* SNDRV_PCM_STATE_OPEN : When stream has been opened .
* SNDRV_PCM_STATE_SETUP : When stream has been initialized . This is done by
2016-03-04 17:55:30 +03:00
* calling SNDRV_COMPRESS_SET_PARAMS . Running streams will come to this
2011-12-23 09:06:39 +04:00
* state at stop by calling SNDRV_COMPRESS_STOP , or at end of drain .
2016-03-04 17:55:29 +03:00
* SNDRV_PCM_STATE_PREPARED : When a stream has been written to ( for
* playback only ) . User after setting up stream writes the data buffer
* before starting the stream .
2011-12-23 09:06:39 +04:00
* SNDRV_PCM_STATE_RUNNING : When stream has been started and is
* decoding / encoding and rendering / capturing data .
* SNDRV_PCM_STATE_DRAINING : When stream is draining current data . This is done
* by calling SNDRV_COMPRESS_DRAIN .
* SNDRV_PCM_STATE_PAUSED : When stream is paused . This is done by calling
* SNDRV_COMPRESS_PAUSE . It can be stopped or resumed by calling
* SNDRV_COMPRESS_STOP or SNDRV_COMPRESS_RESUME respectively .
*/
static int snd_compr_open ( struct inode * inode , struct file * f )
{
struct snd_compr * compr ;
struct snd_compr_file * data ;
struct snd_compr_runtime * runtime ;
enum snd_compr_direction dirn ;
int maj = imajor ( inode ) ;
int ret ;
2012-09-11 15:12:43 +04:00
if ( ( f - > f_flags & O_ACCMODE ) = = O_WRONLY )
2011-12-23 09:06:39 +04:00
dirn = SND_COMPRESS_PLAYBACK ;
2012-09-11 15:12:43 +04:00
else if ( ( f - > f_flags & O_ACCMODE ) = = O_RDONLY )
2011-12-23 09:06:39 +04:00
dirn = SND_COMPRESS_CAPTURE ;
2012-09-11 15:12:43 +04:00
else
2011-12-23 09:06:39 +04:00
return - EINVAL ;
if ( maj = = snd_major )
compr = snd_lookup_minor_data ( iminor ( inode ) ,
SNDRV_DEVICE_TYPE_COMPRESS ) ;
else
return - EBADFD ;
if ( compr = = NULL ) {
pr_err ( " no device data!!! \n " ) ;
return - ENODEV ;
}
if ( dirn ! = compr - > direction ) {
pr_err ( " this device doesn't support this direction \n " ) ;
2012-10-16 15:05:59 +04:00
snd_card_unref ( compr - > card ) ;
2011-12-23 09:06:39 +04:00
return - EINVAL ;
}
data = kzalloc ( sizeof ( * data ) , GFP_KERNEL ) ;
2012-10-16 15:05:59 +04:00
if ( ! data ) {
snd_card_unref ( compr - > card ) ;
2011-12-23 09:06:39 +04:00
return - ENOMEM ;
2012-10-16 15:05:59 +04:00
}
2016-06-13 16:17:10 +03:00
INIT_DELAYED_WORK ( & data - > stream . error_work , error_delayed_work ) ;
2011-12-23 09:06:39 +04:00
data - > stream . ops = compr - > ops ;
data - > stream . direction = dirn ;
data - > stream . private_data = compr - > private_data ;
data - > stream . device = compr ;
runtime = kzalloc ( sizeof ( * runtime ) , GFP_KERNEL ) ;
if ( ! runtime ) {
kfree ( data ) ;
2012-10-16 15:05:59 +04:00
snd_card_unref ( compr - > card ) ;
2011-12-23 09:06:39 +04:00
return - ENOMEM ;
}
runtime - > state = SNDRV_PCM_STATE_OPEN ;
init_waitqueue_head ( & runtime - > sleep ) ;
data - > stream . runtime = runtime ;
f - > private_data = ( void * ) data ;
mutex_lock ( & compr - > lock ) ;
ret = compr - > ops - > open ( & data - > stream ) ;
mutex_unlock ( & compr - > lock ) ;
if ( ret ) {
kfree ( runtime ) ;
kfree ( data ) ;
}
2012-10-16 15:05:59 +04:00
snd_card_unref ( compr - > card ) ;
2014-03-19 16:59:39 +04:00
return ret ;
2011-12-23 09:06:39 +04:00
}
static int snd_compr_free ( struct inode * inode , struct file * f )
{
struct snd_compr_file * data = f - > private_data ;
2013-09-13 20:43:16 +04:00
struct snd_compr_runtime * runtime = data - > stream . runtime ;
2016-06-13 16:17:10 +03:00
cancel_delayed_work_sync ( & data - > stream . error_work ) ;
2013-09-13 20:43:16 +04:00
switch ( runtime - > state ) {
case SNDRV_PCM_STATE_RUNNING :
case SNDRV_PCM_STATE_DRAINING :
case SNDRV_PCM_STATE_PAUSED :
data - > stream . ops - > trigger ( & data - > stream , SNDRV_PCM_TRIGGER_STOP ) ;
break ;
default :
break ;
}
2011-12-23 09:06:39 +04:00
data - > stream . ops - > free ( & data - > stream ) ;
2018-11-15 21:13:21 +03:00
if ( ! data - > stream . runtime - > dma_buffer_p )
kfree ( data - > stream . runtime - > buffer ) ;
2011-12-23 09:06:39 +04:00
kfree ( data - > stream . runtime ) ;
kfree ( data ) ;
return 0 ;
}
2013-02-11 17:44:53 +04:00
static int snd_compr_update_tstamp ( struct snd_compr_stream * stream ,
2011-12-23 09:06:39 +04:00
struct snd_compr_tstamp * tstamp )
{
if ( ! stream - > ops - > pointer )
2013-02-11 17:44:53 +04:00
return - ENOTSUPP ;
2011-12-23 09:06:39 +04:00
stream - > ops - > pointer ( stream , tstamp ) ;
pr_debug ( " dsp consumed till %d total %d bytes \n " ,
tstamp - > byte_offset , tstamp - > copied_total ) ;
2013-04-18 14:01:03 +04:00
if ( stream - > direction = = SND_COMPRESS_PLAYBACK )
stream - > runtime - > total_bytes_transferred = tstamp - > copied_total ;
else
stream - > runtime - > total_bytes_available = tstamp - > copied_total ;
2013-02-11 17:44:53 +04:00
return 0 ;
2011-12-23 09:06:39 +04:00
}
static size_t snd_compr_calc_avail ( struct snd_compr_stream * stream ,
struct snd_compr_avail * avail )
{
2013-02-11 17:44:53 +04:00
memset ( avail , 0 , sizeof ( * avail ) ) ;
2011-12-23 09:06:39 +04:00
snd_compr_update_tstamp ( stream , & avail - > tstamp ) ;
2013-02-11 17:44:53 +04:00
/* Still need to return avail even if tstamp can't be filled in */
2011-12-23 09:06:39 +04:00
if ( stream - > runtime - > total_bytes_available = = 0 & &
2013-04-18 14:01:03 +04:00
stream - > runtime - > state = = SNDRV_PCM_STATE_SETUP & &
stream - > direction = = SND_COMPRESS_PLAYBACK ) {
2011-12-23 09:06:39 +04:00
pr_debug ( " detected init and someone forgot to do a write \n " ) ;
return stream - > runtime - > buffer_size ;
}
pr_debug ( " app wrote %lld, DSP consumed %lld \n " ,
stream - > runtime - > total_bytes_available ,
stream - > runtime - > total_bytes_transferred ) ;
if ( stream - > runtime - > total_bytes_available = =
stream - > runtime - > total_bytes_transferred ) {
2013-04-18 14:01:03 +04:00
if ( stream - > direction = = SND_COMPRESS_PLAYBACK ) {
pr_debug ( " both pointers are same, returning full avail \n " ) ;
return stream - > runtime - > buffer_size ;
} else {
pr_debug ( " both pointers are same, returning no avail \n " ) ;
return 0 ;
}
2011-12-23 09:06:39 +04:00
}
2013-04-18 14:01:03 +04:00
avail - > avail = stream - > runtime - > total_bytes_available -
stream - > runtime - > total_bytes_transferred ;
if ( stream - > direction = = SND_COMPRESS_PLAYBACK )
avail - > avail = stream - > runtime - > buffer_size - avail - > avail ;
2013-04-18 13:59:23 +04:00
pr_debug ( " ret avail as %lld \n " , avail - > avail ) ;
return avail - > avail ;
2011-12-23 09:06:39 +04:00
}
static inline size_t snd_compr_get_avail ( struct snd_compr_stream * stream )
{
struct snd_compr_avail avail ;
return snd_compr_calc_avail ( stream , & avail ) ;
}
static int
snd_compr_ioctl_avail ( struct snd_compr_stream * stream , unsigned long arg )
{
struct snd_compr_avail ioctl_avail ;
size_t avail ;
avail = snd_compr_calc_avail ( stream , & ioctl_avail ) ;
ioctl_avail . avail = avail ;
2016-06-13 16:17:10 +03:00
switch ( stream - > runtime - > state ) {
case SNDRV_PCM_STATE_OPEN :
return - EBADFD ;
case SNDRV_PCM_STATE_XRUN :
return - EPIPE ;
default :
break ;
}
2011-12-23 09:06:39 +04:00
if ( copy_to_user ( ( __u64 __user * ) arg ,
& ioctl_avail , sizeof ( ioctl_avail ) ) )
return - EFAULT ;
return 0 ;
}
static int snd_compr_write_data ( struct snd_compr_stream * stream ,
const char __user * buf , size_t count )
{
void * dstn ;
size_t copy ;
struct snd_compr_runtime * runtime = stream - > runtime ;
2013-04-18 14:03:46 +04:00
/* 64-bit Modulus */
u64 app_pointer = div64_u64 ( runtime - > total_bytes_available ,
runtime - > buffer_size ) ;
app_pointer = runtime - > total_bytes_available -
( app_pointer * runtime - > buffer_size ) ;
2011-12-23 09:06:39 +04:00
2013-04-18 14:03:46 +04:00
dstn = runtime - > buffer + app_pointer ;
2011-12-23 09:06:39 +04:00
pr_debug ( " copying %ld at %lld \n " ,
2013-04-18 14:03:46 +04:00
( unsigned long ) count , app_pointer ) ;
if ( count < runtime - > buffer_size - app_pointer ) {
2011-12-23 09:06:39 +04:00
if ( copy_from_user ( dstn , buf , count ) )
return - EFAULT ;
} else {
2013-04-18 14:03:46 +04:00
copy = runtime - > buffer_size - app_pointer ;
2011-12-23 09:06:39 +04:00
if ( copy_from_user ( dstn , buf , copy ) )
return - EFAULT ;
if ( copy_from_user ( runtime - > buffer , buf + copy , count - copy ) )
return - EFAULT ;
}
/* if DSP cares, let it know data has been written */
if ( stream - > ops - > ack )
stream - > ops - > ack ( stream , count ) ;
return count ;
}
static ssize_t snd_compr_write ( struct file * f , const char __user * buf ,
size_t count , loff_t * offset )
{
struct snd_compr_file * data = f - > private_data ;
struct snd_compr_stream * stream ;
size_t avail ;
int retval ;
if ( snd_BUG_ON ( ! data ) )
return - EFAULT ;
stream = & data - > stream ;
mutex_lock ( & stream - > device - > lock ) ;
/* write is allowed when stream is running or has been steup */
2016-05-04 16:59:11 +03:00
switch ( stream - > runtime - > state ) {
case SNDRV_PCM_STATE_SETUP :
case SNDRV_PCM_STATE_PREPARED :
case SNDRV_PCM_STATE_RUNNING :
break ;
default :
2011-12-23 09:06:39 +04:00
mutex_unlock ( & stream - > device - > lock ) ;
return - EBADFD ;
}
avail = snd_compr_get_avail ( stream ) ;
pr_debug ( " avail returned %ld \n " , ( unsigned long ) avail ) ;
/* calculate how much we can write to buffer */
if ( avail > count )
avail = count ;
2013-04-18 14:01:38 +04:00
if ( stream - > ops - > copy ) {
char __user * cbuf = ( char __user * ) buf ;
retval = stream - > ops - > copy ( stream , cbuf , avail ) ;
} else {
2011-12-23 09:06:39 +04:00
retval = snd_compr_write_data ( stream , buf , avail ) ;
2013-04-18 14:01:38 +04:00
}
2011-12-23 09:06:39 +04:00
if ( retval > 0 )
stream - > runtime - > total_bytes_available + = retval ;
/* while initiating the stream, write should be called before START
* call , so in setup move state */
if ( stream - > runtime - > state = = SNDRV_PCM_STATE_SETUP ) {
stream - > runtime - > state = SNDRV_PCM_STATE_PREPARED ;
pr_debug ( " stream prepared, Houston we are good to go \n " ) ;
}
mutex_unlock ( & stream - > device - > lock ) ;
return retval ;
}
static ssize_t snd_compr_read ( struct file * f , char __user * buf ,
size_t count , loff_t * offset )
{
2013-04-18 14:02:08 +04:00
struct snd_compr_file * data = f - > private_data ;
struct snd_compr_stream * stream ;
size_t avail ;
int retval ;
if ( snd_BUG_ON ( ! data ) )
return - EFAULT ;
stream = & data - > stream ;
mutex_lock ( & stream - > device - > lock ) ;
2013-04-29 12:55:23 +04:00
/* read is allowed when stream is running, paused, draining and setup
* ( yes setup is state which we transition to after stop , so if user
* wants to read data after stop we allow that )
*/
switch ( stream - > runtime - > state ) {
case SNDRV_PCM_STATE_OPEN :
case SNDRV_PCM_STATE_PREPARED :
case SNDRV_PCM_STATE_SUSPENDED :
case SNDRV_PCM_STATE_DISCONNECTED :
2013-04-18 14:02:08 +04:00
retval = - EBADFD ;
goto out ;
2016-06-13 16:17:10 +03:00
case SNDRV_PCM_STATE_XRUN :
retval = - EPIPE ;
goto out ;
2013-04-18 14:02:08 +04:00
}
avail = snd_compr_get_avail ( stream ) ;
pr_debug ( " avail returned %ld \n " , ( unsigned long ) avail ) ;
/* calculate how much we can read from buffer */
if ( avail > count )
avail = count ;
if ( stream - > ops - > copy ) {
retval = stream - > ops - > copy ( stream , buf , avail ) ;
} else {
retval = - ENXIO ;
goto out ;
}
if ( retval > 0 )
stream - > runtime - > total_bytes_transferred + = retval ;
out :
mutex_unlock ( & stream - > device - > lock ) ;
return retval ;
2011-12-23 09:06:39 +04:00
}
static int snd_compr_mmap ( struct file * f , struct vm_area_struct * vma )
{
return - ENXIO ;
}
2017-07-03 06:27:36 +03:00
static __poll_t snd_compr_get_poll ( struct snd_compr_stream * stream )
2011-12-23 09:06:39 +04:00
{
if ( stream - > direction = = SND_COMPRESS_PLAYBACK )
2018-02-12 01:34:03 +03:00
return EPOLLOUT | EPOLLWRNORM ;
2011-12-23 09:06:39 +04:00
else
2018-02-12 01:34:03 +03:00
return EPOLLIN | EPOLLRDNORM ;
2011-12-23 09:06:39 +04:00
}
2017-07-03 06:27:36 +03:00
static __poll_t snd_compr_poll ( struct file * f , poll_table * wait )
2011-12-23 09:06:39 +04:00
{
struct snd_compr_file * data = f - > private_data ;
struct snd_compr_stream * stream ;
size_t avail ;
2017-07-03 06:27:36 +03:00
__poll_t retval = 0 ;
2011-12-23 09:06:39 +04:00
if ( snd_BUG_ON ( ! data ) )
2018-02-12 01:34:03 +03:00
return EPOLLERR ;
2016-05-04 16:59:09 +03:00
2011-12-23 09:06:39 +04:00
stream = & data - > stream ;
mutex_lock ( & stream - > device - > lock ) ;
2016-06-13 16:17:10 +03:00
switch ( stream - > runtime - > state ) {
case SNDRV_PCM_STATE_OPEN :
case SNDRV_PCM_STATE_XRUN :
2018-02-12 01:34:03 +03:00
retval = snd_compr_get_poll ( stream ) | EPOLLERR ;
2011-12-23 09:06:39 +04:00
goto out ;
2016-06-13 16:17:10 +03:00
default :
break ;
2011-12-23 09:06:39 +04:00
}
2016-06-13 16:17:10 +03:00
2011-12-23 09:06:39 +04:00
poll_wait ( f , & stream - > runtime - > sleep , wait ) ;
avail = snd_compr_get_avail ( stream ) ;
pr_debug ( " avail is %ld \n " , ( unsigned long ) avail ) ;
/* check if we have at least one fragment to fill */
switch ( stream - > runtime - > state ) {
case SNDRV_PCM_STATE_DRAINING :
/* stream has been woken up after drain is complete
* draining done so set stream state to stopped
*/
retval = snd_compr_get_poll ( stream ) ;
stream - > runtime - > state = SNDRV_PCM_STATE_SETUP ;
break ;
case SNDRV_PCM_STATE_RUNNING :
case SNDRV_PCM_STATE_PREPARED :
case SNDRV_PCM_STATE_PAUSED :
if ( avail > = stream - > runtime - > fragment_size )
retval = snd_compr_get_poll ( stream ) ;
break ;
default :
2018-02-12 01:34:03 +03:00
retval = snd_compr_get_poll ( stream ) | EPOLLERR ;
2011-12-23 09:06:39 +04:00
break ;
}
out :
mutex_unlock ( & stream - > device - > lock ) ;
return retval ;
}
static int
snd_compr_get_caps ( struct snd_compr_stream * stream , unsigned long arg )
{
int retval ;
struct snd_compr_caps caps ;
if ( ! stream - > ops - > get_caps )
return - ENXIO ;
2013-04-21 15:07:29 +04:00
memset ( & caps , 0 , sizeof ( caps ) ) ;
2011-12-23 09:06:39 +04:00
retval = stream - > ops - > get_caps ( stream , & caps ) ;
if ( retval )
goto out ;
if ( copy_to_user ( ( void __user * ) arg , & caps , sizeof ( caps ) ) )
retval = - EFAULT ;
out :
return retval ;
}
2016-01-25 15:59:21 +03:00
# ifndef COMPR_CODEC_CAPS_OVERFLOW
2011-12-23 09:06:39 +04:00
static int
snd_compr_get_codec_caps ( struct snd_compr_stream * stream , unsigned long arg )
{
int retval ;
struct snd_compr_codec_caps * caps ;
if ( ! stream - > ops - > get_codec_caps )
return - ENXIO ;
2013-04-22 12:38:26 +04:00
caps = kzalloc ( sizeof ( * caps ) , GFP_KERNEL ) ;
2011-12-23 09:06:39 +04:00
if ( ! caps )
return - ENOMEM ;
retval = stream - > ops - > get_codec_caps ( stream , caps ) ;
if ( retval )
goto out ;
if ( copy_to_user ( ( void __user * ) arg , caps , sizeof ( * caps ) ) )
retval = - EFAULT ;
out :
kfree ( caps ) ;
return retval ;
}
2016-01-25 15:59:21 +03:00
# endif /* !COMPR_CODEC_CAPS_OVERFLOW */
2011-12-23 09:06:39 +04:00
2020-02-18 17:39:17 +03:00
int snd_compr_malloc_pages ( struct snd_compr_stream * stream , size_t size )
{
struct snd_dma_buffer * dmab ;
int ret ;
if ( snd_BUG_ON ( ! ( stream ) | | ! ( stream ) - > runtime ) )
return - EINVAL ;
dmab = kzalloc ( sizeof ( * dmab ) , GFP_KERNEL ) ;
if ( ! dmab )
return - ENOMEM ;
dmab - > dev = stream - > dma_buffer . dev ;
ret = snd_dma_alloc_pages ( dmab - > dev . type , dmab - > dev . dev , size , dmab ) ;
if ( ret < 0 ) {
kfree ( dmab ) ;
return ret ;
}
snd_compr_set_runtime_buffer ( stream , dmab ) ;
stream - > runtime - > dma_bytes = size ;
return 1 ;
}
EXPORT_SYMBOL ( snd_compr_malloc_pages ) ;
int snd_compr_free_pages ( struct snd_compr_stream * stream )
{
2020-09-03 00:21:21 +03:00
struct snd_compr_runtime * runtime ;
2020-02-18 17:39:17 +03:00
if ( snd_BUG_ON ( ! ( stream ) | | ! ( stream ) - > runtime ) )
return - EINVAL ;
2020-09-03 00:21:21 +03:00
runtime = stream - > runtime ;
2020-02-18 17:39:17 +03:00
if ( runtime - > dma_area = = NULL )
return 0 ;
if ( runtime - > dma_buffer_p ! = & stream - > dma_buffer ) {
/* It's a newly allocated buffer. Release it now. */
snd_dma_free_pages ( runtime - > dma_buffer_p ) ;
kfree ( runtime - > dma_buffer_p ) ;
}
snd_compr_set_runtime_buffer ( stream , NULL ) ;
return 0 ;
}
EXPORT_SYMBOL ( snd_compr_free_pages ) ;
2011-12-23 09:06:39 +04:00
/* revisit this with snd_pcm_preallocate_xxx */
static int snd_compr_allocate_buffer ( struct snd_compr_stream * stream ,
struct snd_compr_params * params )
{
unsigned int buffer_size ;
2018-11-15 21:13:21 +03:00
void * buffer = NULL ;
2011-12-23 09:06:39 +04:00
buffer_size = params - > buffer . fragment_size * params - > buffer . fragments ;
if ( stream - > ops - > copy ) {
buffer = NULL ;
/* if copy is defined the driver will be required to copy
* the data from core
*/
} else {
2018-11-15 21:13:21 +03:00
if ( stream - > runtime - > dma_buffer_p ) {
if ( buffer_size > stream - > runtime - > dma_buffer_p - > bytes )
dev_err ( & stream - > device - > dev ,
" Not enough DMA buffer " ) ;
else
buffer = stream - > runtime - > dma_buffer_p - > area ;
} else {
buffer = kmalloc ( buffer_size , GFP_KERNEL ) ;
}
2011-12-23 09:06:39 +04:00
if ( ! buffer )
return - ENOMEM ;
}
stream - > runtime - > fragment_size = params - > buffer . fragment_size ;
stream - > runtime - > fragments = params - > buffer . fragments ;
stream - > runtime - > buffer = buffer ;
stream - > runtime - > buffer_size = buffer_size ;
return 0 ;
}
2012-09-17 10:21:25 +04:00
static int snd_compress_check_input ( struct snd_compr_params * params )
{
/* first let's check the buffer parameter's */
if ( params - > buffer . fragment_size = = 0 | |
2019-10-21 12:54:32 +03:00
params - > buffer . fragments > U32_MAX / params - > buffer . fragment_size | |
2018-12-21 12:06:58 +03:00
params - > buffer . fragments = = 0 )
2012-09-17 10:21:25 +04:00
return - EINVAL ;
2012-09-17 10:21:26 +04:00
/* now codec parameters */
if ( params - > codec . id = = 0 | | params - > codec . id > SND_AUDIOCODEC_MAX )
return - EINVAL ;
if ( params - > codec . ch_in = = 0 | | params - > codec . ch_out = = 0 )
return - EINVAL ;
2012-09-17 10:21:25 +04:00
return 0 ;
}
2011-12-23 09:06:39 +04:00
static int
snd_compr_set_params ( struct snd_compr_stream * stream , unsigned long arg )
{
struct snd_compr_params * params ;
int retval ;
if ( stream - > runtime - > state = = SNDRV_PCM_STATE_OPEN ) {
/*
* we should allow parameter change only when stream has been
* opened not in other cases
*/
2016-08-21 22:02:06 +03:00
params = memdup_user ( ( void __user * ) arg , sizeof ( * params ) ) ;
if ( IS_ERR ( params ) )
return PTR_ERR ( params ) ;
2012-09-17 10:21:25 +04:00
retval = snd_compress_check_input ( params ) ;
if ( retval )
goto out ;
2011-12-23 09:06:39 +04:00
retval = snd_compr_allocate_buffer ( stream , params ) ;
if ( retval ) {
2012-01-24 00:02:57 +04:00
retval = - ENOMEM ;
goto out ;
2011-12-23 09:06:39 +04:00
}
2012-09-17 10:21:25 +04:00
2011-12-23 09:06:39 +04:00
retval = stream - > ops - > set_params ( stream , params ) ;
if ( retval )
goto out ;
2013-04-18 14:02:08 +04:00
2013-02-14 15:22:51 +04:00
stream - > metadata_set = false ;
stream - > next_track = false ;
2013-04-18 14:02:08 +04:00
2019-07-22 12:24:33 +03:00
stream - > runtime - > state = SNDRV_PCM_STATE_SETUP ;
2012-01-24 00:02:57 +04:00
} else {
2011-12-23 09:06:39 +04:00
return - EPERM ;
2012-01-24 00:02:57 +04:00
}
2011-12-23 09:06:39 +04:00
out :
kfree ( params ) ;
return retval ;
}
static int
snd_compr_get_params ( struct snd_compr_stream * stream , unsigned long arg )
{
struct snd_codec * params ;
int retval ;
if ( ! stream - > ops - > get_params )
return - EBADFD ;
2013-04-22 12:38:26 +04:00
params = kzalloc ( sizeof ( * params ) , GFP_KERNEL ) ;
2011-12-23 09:06:39 +04:00
if ( ! params )
return - ENOMEM ;
retval = stream - > ops - > get_params ( stream , params ) ;
if ( retval )
goto out ;
if ( copy_to_user ( ( char __user * ) arg , params , sizeof ( * params ) ) )
retval = - EFAULT ;
out :
kfree ( params ) ;
return retval ;
}
2013-02-14 15:22:51 +04:00
static int
snd_compr_get_metadata ( struct snd_compr_stream * stream , unsigned long arg )
{
struct snd_compr_metadata metadata ;
int retval ;
if ( ! stream - > ops - > get_metadata )
return - ENXIO ;
if ( copy_from_user ( & metadata , ( void __user * ) arg , sizeof ( metadata ) ) )
return - EFAULT ;
retval = stream - > ops - > get_metadata ( stream , & metadata ) ;
if ( retval ! = 0 )
return retval ;
if ( copy_to_user ( ( void __user * ) arg , & metadata , sizeof ( metadata ) ) )
return - EFAULT ;
return 0 ;
}
static int
snd_compr_set_metadata ( struct snd_compr_stream * stream , unsigned long arg )
{
struct snd_compr_metadata metadata ;
int retval ;
if ( ! stream - > ops - > set_metadata )
return - ENXIO ;
/*
* we should allow parameter change only when stream has been
* opened not in other cases
*/
if ( copy_from_user ( & metadata , ( void __user * ) arg , sizeof ( metadata ) ) )
return - EFAULT ;
retval = stream - > ops - > set_metadata ( stream , & metadata ) ;
stream - > metadata_set = true ;
return retval ;
}
2011-12-23 09:06:39 +04:00
static inline int
snd_compr_tstamp ( struct snd_compr_stream * stream , unsigned long arg )
{
2013-02-11 17:44:53 +04:00
struct snd_compr_tstamp tstamp = { 0 } ;
int ret ;
2011-12-23 09:06:39 +04:00
2013-02-11 17:44:53 +04:00
ret = snd_compr_update_tstamp ( stream , & tstamp ) ;
if ( ret = = 0 )
ret = copy_to_user ( ( struct snd_compr_tstamp __user * ) arg ,
& tstamp , sizeof ( tstamp ) ) ? - EFAULT : 0 ;
return ret ;
2011-12-23 09:06:39 +04:00
}
static int snd_compr_pause ( struct snd_compr_stream * stream )
{
int retval ;
2020-11-26 15:34:52 +03:00
switch ( stream - > runtime - > state ) {
case SNDRV_PCM_STATE_RUNNING :
retval = stream - > ops - > trigger ( stream , SNDRV_PCM_TRIGGER_PAUSE_PUSH ) ;
if ( ! retval )
stream - > runtime - > state = SNDRV_PCM_STATE_PAUSED ;
break ;
case SNDRV_PCM_STATE_DRAINING :
if ( ! stream - > device - > use_pause_in_draining )
return - EPERM ;
retval = stream - > ops - > trigger ( stream , SNDRV_PCM_TRIGGER_PAUSE_PUSH ) ;
if ( ! retval )
stream - > pause_in_draining = true ;
break ;
default :
2011-12-23 09:06:39 +04:00
return - EPERM ;
2020-11-26 15:34:52 +03:00
}
2011-12-23 09:06:39 +04:00
return retval ;
}
static int snd_compr_resume ( struct snd_compr_stream * stream )
{
int retval ;
2020-11-26 15:34:52 +03:00
switch ( stream - > runtime - > state ) {
case SNDRV_PCM_STATE_PAUSED :
retval = stream - > ops - > trigger ( stream , SNDRV_PCM_TRIGGER_PAUSE_RELEASE ) ;
if ( ! retval )
stream - > runtime - > state = SNDRV_PCM_STATE_RUNNING ;
break ;
case SNDRV_PCM_STATE_DRAINING :
if ( ! stream - > pause_in_draining )
return - EPERM ;
retval = stream - > ops - > trigger ( stream , SNDRV_PCM_TRIGGER_PAUSE_RELEASE ) ;
if ( ! retval )
stream - > pause_in_draining = false ;
break ;
default :
2011-12-23 09:06:39 +04:00
return - EPERM ;
2020-11-26 15:34:52 +03:00
}
2011-12-23 09:06:39 +04:00
return retval ;
}
static int snd_compr_start ( struct snd_compr_stream * stream )
{
int retval ;
2019-07-22 12:24:33 +03:00
switch ( stream - > runtime - > state ) {
case SNDRV_PCM_STATE_SETUP :
if ( stream - > direction ! = SND_COMPRESS_CAPTURE )
return - EPERM ;
break ;
case SNDRV_PCM_STATE_PREPARED :
break ;
default :
2011-12-23 09:06:39 +04:00
return - EPERM ;
2019-07-22 12:24:33 +03:00
}
2011-12-23 09:06:39 +04:00
retval = stream - > ops - > trigger ( stream , SNDRV_PCM_TRIGGER_START ) ;
if ( ! retval )
stream - > runtime - > state = SNDRV_PCM_STATE_RUNNING ;
return retval ;
}
static int snd_compr_stop ( struct snd_compr_stream * stream )
{
int retval ;
2019-07-22 12:24:34 +03:00
switch ( stream - > runtime - > state ) {
case SNDRV_PCM_STATE_OPEN :
case SNDRV_PCM_STATE_SETUP :
case SNDRV_PCM_STATE_PREPARED :
2011-12-23 09:06:39 +04:00
return - EPERM ;
2019-07-22 12:24:34 +03:00
default :
break ;
}
2011-12-23 09:06:39 +04:00
retval = stream - > ops - > trigger ( stream , SNDRV_PCM_TRIGGER_STOP ) ;
if ( ! retval ) {
2020-06-29 16:47:37 +03:00
/* clear flags and stop any drain wait */
stream - > partial_drain = false ;
stream - > metadata_set = false ;
2020-11-26 15:34:52 +03:00
stream - > pause_in_draining = false ;
2013-10-24 15:07:31 +04:00
snd_compr_drain_notify ( stream ) ;
2012-06-12 14:46:18 +04:00
stream - > runtime - > total_bytes_available = 0 ;
stream - > runtime - > total_bytes_transferred = 0 ;
2011-12-23 09:06:39 +04:00
}
return retval ;
}
2016-06-13 16:17:10 +03:00
static void error_delayed_work ( struct work_struct * work )
{
struct snd_compr_stream * stream ;
stream = container_of ( work , struct snd_compr_stream , error_work . work ) ;
mutex_lock ( & stream - > device - > lock ) ;
stream - > ops - > trigger ( stream , SNDRV_PCM_TRIGGER_STOP ) ;
wake_up ( & stream - > runtime - > sleep ) ;
mutex_unlock ( & stream - > device - > lock ) ;
}
2022-07-13 13:47:53 +03:00
/**
2016-06-13 16:17:10 +03:00
* snd_compr_stop_error : Report a fatal error on a stream
* @ stream : pointer to stream
* @ state : state to transition the stream to
*
* Stop the stream and set its state .
*
* Should be called with compressed device lock held .
2022-07-13 13:47:56 +03:00
*
* Return : zero if successful , or a negative error code
2016-06-13 16:17:10 +03:00
*/
int snd_compr_stop_error ( struct snd_compr_stream * stream ,
snd_pcm_state_t state )
{
if ( stream - > runtime - > state = = state )
return 0 ;
stream - > runtime - > state = state ;
pr_debug ( " Changing state to: %d \n " , state ) ;
queue_delayed_work ( system_power_efficient_wq , & stream - > error_work , 0 ) ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( snd_compr_stop_error ) ;
2013-10-24 15:07:31 +04:00
static int snd_compress_wait_for_drain ( struct snd_compr_stream * stream )
{
2013-11-07 13:08:22 +04:00
int ret ;
2013-10-24 15:07:31 +04:00
/*
* We are called with lock held . So drop the lock while we wait for
2016-03-04 21:29:29 +03:00
* drain complete notification from the driver
2013-10-24 15:07:31 +04:00
*
* It is expected that driver will notify the drain completion and then
* stream will be moved to SETUP state , even if draining resulted in an
* error . We can trigger next track after this .
*/
stream - > runtime - > state = SNDRV_PCM_STATE_DRAINING ;
mutex_unlock ( & stream - > device - > lock ) ;
2013-11-07 13:08:22 +04:00
/* we wait for drain to complete here, drain can return when
* interruption occurred , wait returned error or success .
* For the first two cases we don ' t do anything different here and
* return after waking up
*/
ret = wait_event_interruptible ( stream - > runtime - > sleep ,
( stream - > runtime - > state ! = SNDRV_PCM_STATE_DRAINING ) ) ;
if ( ret = = - ERESTARTSYS )
2016-09-16 19:46:41 +03:00
pr_debug ( " wait aborted by a signal \n " ) ;
2013-11-07 13:08:22 +04:00
else if ( ret )
pr_debug ( " wait for drain failed with %d \n " , ret ) ;
2013-10-24 15:07:31 +04:00
wake_up ( & stream - > runtime - > sleep ) ;
mutex_lock ( & stream - > device - > lock ) ;
2013-11-07 13:08:22 +04:00
return ret ;
2013-10-24 15:07:31 +04:00
}
2011-12-23 09:06:39 +04:00
static int snd_compr_drain ( struct snd_compr_stream * stream )
{
int retval ;
2019-07-22 12:24:34 +03:00
switch ( stream - > runtime - > state ) {
case SNDRV_PCM_STATE_OPEN :
case SNDRV_PCM_STATE_SETUP :
case SNDRV_PCM_STATE_PREPARED :
2019-07-22 12:24:36 +03:00
case SNDRV_PCM_STATE_PAUSED :
2011-12-23 09:06:39 +04:00
return - EPERM ;
2019-07-22 12:24:36 +03:00
case SNDRV_PCM_STATE_XRUN :
return - EPIPE ;
2019-07-22 12:24:34 +03:00
default :
break ;
}
2013-10-24 15:07:31 +04:00
2011-12-23 09:06:39 +04:00
retval = stream - > ops - > trigger ( stream , SND_COMPR_TRIGGER_DRAIN ) ;
2013-10-24 15:07:31 +04:00
if ( retval ) {
2013-11-07 13:08:22 +04:00
pr_debug ( " SND_COMPR_TRIGGER_DRAIN failed %d \n " , retval ) ;
2011-12-23 09:06:39 +04:00
wake_up ( & stream - > runtime - > sleep ) ;
2013-10-24 15:07:31 +04:00
return retval ;
2011-12-23 09:06:39 +04:00
}
2013-10-24 15:07:31 +04:00
2013-11-07 13:08:22 +04:00
return snd_compress_wait_for_drain ( stream ) ;
2011-12-23 09:06:39 +04:00
}
2013-02-14 15:22:51 +04:00
static int snd_compr_next_track ( struct snd_compr_stream * stream )
{
int retval ;
/* only a running stream can transition to next track */
if ( stream - > runtime - > state ! = SNDRV_PCM_STATE_RUNNING )
return - EPERM ;
2019-07-22 12:24:35 +03:00
/* next track doesn't have any meaning for capture streams */
if ( stream - > direction = = SND_COMPRESS_CAPTURE )
return - EPERM ;
2016-03-04 21:29:29 +03:00
/* you can signal next track if this is intended to be a gapless stream
2013-02-14 15:22:51 +04:00
* and current track metadata is set
*/
if ( stream - > metadata_set = = false )
return - EPERM ;
retval = stream - > ops - > trigger ( stream , SND_COMPR_TRIGGER_NEXT_TRACK ) ;
if ( retval ! = 0 )
return retval ;
stream - > metadata_set = false ;
stream - > next_track = true ;
return 0 ;
}
static int snd_compr_partial_drain ( struct snd_compr_stream * stream )
{
int retval ;
2019-07-22 12:24:34 +03:00
switch ( stream - > runtime - > state ) {
case SNDRV_PCM_STATE_OPEN :
case SNDRV_PCM_STATE_SETUP :
case SNDRV_PCM_STATE_PREPARED :
2019-07-22 12:24:36 +03:00
case SNDRV_PCM_STATE_PAUSED :
2013-02-14 15:22:51 +04:00
return - EPERM ;
2019-07-22 12:24:36 +03:00
case SNDRV_PCM_STATE_XRUN :
return - EPIPE ;
2019-07-22 12:24:34 +03:00
default :
break ;
}
2019-07-22 12:24:35 +03:00
/* partial drain doesn't have any meaning for capture streams */
if ( stream - > direction = = SND_COMPRESS_CAPTURE )
return - EPERM ;
2013-02-14 15:22:51 +04:00
/* stream can be drained only when next track has been signalled */
if ( stream - > next_track = = false )
return - EPERM ;
2020-06-29 16:47:37 +03:00
stream - > partial_drain = true ;
2013-02-14 15:22:51 +04:00
retval = stream - > ops - > trigger ( stream , SND_COMPR_TRIGGER_PARTIAL_DRAIN ) ;
2013-10-24 15:07:31 +04:00
if ( retval ) {
2013-11-07 13:08:22 +04:00
pr_debug ( " Partial drain returned failure \n " ) ;
2013-10-24 15:07:31 +04:00
wake_up ( & stream - > runtime - > sleep ) ;
return retval ;
}
2013-02-14 15:22:51 +04:00
stream - > next_track = false ;
2013-10-24 15:07:31 +04:00
return snd_compress_wait_for_drain ( stream ) ;
2013-02-14 15:22:51 +04:00
}
2011-12-23 09:06:39 +04:00
static long snd_compr_ioctl ( struct file * f , unsigned int cmd , unsigned long arg )
{
struct snd_compr_file * data = f - > private_data ;
struct snd_compr_stream * stream ;
int retval = - ENOTTY ;
if ( snd_BUG_ON ( ! data ) )
return - EFAULT ;
2016-05-04 16:59:09 +03:00
2011-12-23 09:06:39 +04:00
stream = & data - > stream ;
2016-05-04 16:59:09 +03:00
2011-12-23 09:06:39 +04:00
mutex_lock ( & stream - > device - > lock ) ;
switch ( _IOC_NR ( cmd ) ) {
case _IOC_NR ( SNDRV_COMPRESS_IOCTL_VERSION ) :
2013-07-29 13:40:22 +04:00
retval = put_user ( SNDRV_COMPRESS_VERSION ,
2011-12-23 09:06:39 +04:00
( int __user * ) arg ) ? - EFAULT : 0 ;
break ;
case _IOC_NR ( SNDRV_COMPRESS_GET_CAPS ) :
retval = snd_compr_get_caps ( stream , arg ) ;
break ;
2016-01-25 15:59:21 +03:00
# ifndef COMPR_CODEC_CAPS_OVERFLOW
2011-12-23 09:06:39 +04:00
case _IOC_NR ( SNDRV_COMPRESS_GET_CODEC_CAPS ) :
retval = snd_compr_get_codec_caps ( stream , arg ) ;
break ;
2016-01-25 15:59:21 +03:00
# endif
2011-12-23 09:06:39 +04:00
case _IOC_NR ( SNDRV_COMPRESS_SET_PARAMS ) :
retval = snd_compr_set_params ( stream , arg ) ;
break ;
case _IOC_NR ( SNDRV_COMPRESS_GET_PARAMS ) :
retval = snd_compr_get_params ( stream , arg ) ;
break ;
2013-02-14 15:22:51 +04:00
case _IOC_NR ( SNDRV_COMPRESS_SET_METADATA ) :
retval = snd_compr_set_metadata ( stream , arg ) ;
break ;
case _IOC_NR ( SNDRV_COMPRESS_GET_METADATA ) :
retval = snd_compr_get_metadata ( stream , arg ) ;
break ;
2011-12-23 09:06:39 +04:00
case _IOC_NR ( SNDRV_COMPRESS_TSTAMP ) :
retval = snd_compr_tstamp ( stream , arg ) ;
break ;
case _IOC_NR ( SNDRV_COMPRESS_AVAIL ) :
retval = snd_compr_ioctl_avail ( stream , arg ) ;
break ;
case _IOC_NR ( SNDRV_COMPRESS_PAUSE ) :
retval = snd_compr_pause ( stream ) ;
break ;
case _IOC_NR ( SNDRV_COMPRESS_RESUME ) :
retval = snd_compr_resume ( stream ) ;
break ;
case _IOC_NR ( SNDRV_COMPRESS_START ) :
retval = snd_compr_start ( stream ) ;
break ;
case _IOC_NR ( SNDRV_COMPRESS_STOP ) :
retval = snd_compr_stop ( stream ) ;
break ;
case _IOC_NR ( SNDRV_COMPRESS_DRAIN ) :
retval = snd_compr_drain ( stream ) ;
break ;
2013-02-14 15:22:51 +04:00
case _IOC_NR ( SNDRV_COMPRESS_PARTIAL_DRAIN ) :
retval = snd_compr_partial_drain ( stream ) ;
break ;
case _IOC_NR ( SNDRV_COMPRESS_NEXT_TRACK ) :
retval = snd_compr_next_track ( stream ) ;
break ;
2011-12-23 09:06:39 +04:00
}
mutex_unlock ( & stream - > device - > lock ) ;
return retval ;
}
2015-12-07 09:38:31 +03:00
/* support of 32bit userspace on 64bit platforms */
# ifdef CONFIG_COMPAT
static long snd_compr_ioctl_compat ( struct file * file , unsigned int cmd ,
unsigned long arg )
{
return snd_compr_ioctl ( file , cmd , ( unsigned long ) compat_ptr ( arg ) ) ;
}
# endif
2011-12-23 09:06:39 +04:00
static const struct file_operations snd_compr_file_ops = {
. owner = THIS_MODULE ,
. open = snd_compr_open ,
. release = snd_compr_free ,
. write = snd_compr_write ,
. read = snd_compr_read ,
. unlocked_ioctl = snd_compr_ioctl ,
2015-12-07 09:38:31 +03:00
# ifdef CONFIG_COMPAT
. compat_ioctl = snd_compr_ioctl_compat ,
# endif
2011-12-23 09:06:39 +04:00
. mmap = snd_compr_mmap ,
. poll = snd_compr_poll ,
} ;
static int snd_compress_dev_register ( struct snd_device * device )
{
2020-09-03 00:21:22 +03:00
int ret ;
2011-12-23 09:06:39 +04:00
struct snd_compr * compr ;
if ( snd_BUG_ON ( ! device | | ! device - > device_data ) )
return - EBADFD ;
compr = device - > device_data ;
2017-09-14 15:19:40 +03:00
pr_debug ( " reg device %s, direction %d \n " , compr - > name ,
2011-12-23 09:06:39 +04:00
compr - > direction ) ;
/* register compressed device */
2015-01-30 10:34:58 +03:00
ret = snd_register_device ( SNDRV_DEVICE_TYPE_COMPRESS ,
compr - > card , compr - > device ,
& snd_compr_file_ops , compr , & compr - > dev ) ;
2011-12-23 09:06:39 +04:00
if ( ret < 0 ) {
2016-09-16 19:46:41 +03:00
pr_err ( " snd_register_device failed %d \n " , ret ) ;
2011-12-23 09:06:39 +04:00
return ret ;
}
return ret ;
}
static int snd_compress_dev_disconnect ( struct snd_device * device )
{
struct snd_compr * compr ;
compr = device - > device_data ;
2015-01-30 10:34:58 +03:00
snd_unregister_device ( & compr - > dev ) ;
2011-12-23 09:06:39 +04:00
return 0 ;
}
2015-11-25 16:00:23 +03:00
# ifdef CONFIG_SND_VERBOSE_PROCFS
static void snd_compress_proc_info_read ( struct snd_info_entry * entry ,
struct snd_info_buffer * buffer )
{
struct snd_compr * compr = ( struct snd_compr * ) entry - > private_data ;
snd_iprintf ( buffer , " card: %d \n " , compr - > card - > number ) ;
snd_iprintf ( buffer , " device: %d \n " , compr - > device ) ;
snd_iprintf ( buffer , " stream: %s \n " ,
compr - > direction = = SND_COMPRESS_PLAYBACK
? " PLAYBACK " : " CAPTURE " ) ;
snd_iprintf ( buffer , " id: %s \n " , compr - > id ) ;
}
static int snd_compress_proc_init ( struct snd_compr * compr )
{
struct snd_info_entry * entry ;
char name [ 16 ] ;
sprintf ( name , " compr%i " , compr - > device ) ;
entry = snd_info_create_card_entry ( compr - > card , name ,
compr - > card - > proc_root ) ;
if ( ! entry )
return - ENOMEM ;
2018-05-23 22:20:59 +03:00
entry - > mode = S_IFDIR | 0555 ;
2015-11-25 16:00:23 +03:00
compr - > proc_root = entry ;
entry = snd_info_create_card_entry ( compr - > card , " info " ,
compr - > proc_root ) ;
2019-02-04 16:55:19 +03:00
if ( entry )
2015-11-25 16:00:23 +03:00
snd_info_set_text_ops ( entry , compr ,
snd_compress_proc_info_read ) ;
compr - > proc_info_entry = entry ;
return 0 ;
}
static void snd_compress_proc_done ( struct snd_compr * compr )
{
snd_info_free_entry ( compr - > proc_info_entry ) ;
compr - > proc_info_entry = NULL ;
snd_info_free_entry ( compr - > proc_root ) ;
compr - > proc_root = NULL ;
}
2015-11-25 16:00:24 +03:00
static inline void snd_compress_set_id ( struct snd_compr * compr , const char * id )
{
ALSA: Convert strlcpy to strscpy when return value is unused
strlcpy is deprecated. see: Documentation/process/deprecated.rst
Change the calls that do not use the strlcpy return value to the
preferred strscpy.
Done with cocci script:
@@
expression e1, e2, e3;
@@
- strlcpy(
+ strscpy(
e1, e2, e3);
This cocci script leaves the instances where the return value is
used unchanged.
After this patch, sound/ has 3 uses of strlcpy() that need to be
manually inspected for conversion and changed one day.
$ git grep -w strlcpy sound/
sound/usb/card.c: len = strlcpy(card->longname, s, sizeof(card->longname));
sound/usb/mixer.c: return strlcpy(buf, p->name, buflen);
sound/usb/mixer.c: return strlcpy(buf, p->names[index], buflen);
Miscellenea:
o Remove trailing whitespace in conversion of sound/core/hwdep.c
Link: https://lore.kernel.org/lkml/CAHk-=wgfRnXz0W3D37d01q3JFkr_i_uTL=V6A6G1oUZcprmknw@mail.gmail.com/
Signed-off-by: Joe Perches <joe@perches.com>
Acked-by: Mark Brown <broonie@kernel.org>
Link: https://lore.kernel.org/r/22b393d1790bb268769d0bab7bacf0866dcb0c14.camel@perches.com
Signed-off-by: Takashi Iwai <tiwai@suse.de>
2021-01-04 20:17:34 +03:00
strscpy ( compr - > id , id , sizeof ( compr - > id ) ) ;
2015-11-25 16:00:24 +03:00
}
2015-11-25 16:00:23 +03:00
# else
static inline int snd_compress_proc_init ( struct snd_compr * compr )
{
return 0 ;
}
static inline void snd_compress_proc_done ( struct snd_compr * compr )
{
}
2015-11-25 16:00:24 +03:00
static inline void snd_compress_set_id ( struct snd_compr * compr , const char * id )
{
}
2015-11-25 16:00:23 +03:00
# endif
2015-01-30 10:16:35 +03:00
static int snd_compress_dev_free ( struct snd_device * device )
{
struct snd_compr * compr ;
compr = device - > device_data ;
2015-11-25 16:00:23 +03:00
snd_compress_proc_done ( compr ) ;
2015-01-30 10:16:35 +03:00
put_device ( & compr - > dev ) ;
return 0 ;
}
2022-07-13 13:47:53 +03:00
/**
2011-12-23 09:06:39 +04:00
* snd_compress_new : create new compress device
* @ card : sound card pointer
* @ device : device number
* @ dirn : device direction , should be of type enum snd_compr_direction
2022-07-13 13:47:53 +03:00
* @ id : ID string
2011-12-23 09:06:39 +04:00
* @ compr : compress device pointer
2022-07-13 13:47:56 +03:00
*
* Return : zero if successful , or a negative error code
2011-12-23 09:06:39 +04:00
*/
int snd_compress_new ( struct snd_card * card , int device ,
2015-11-25 16:00:24 +03:00
int dirn , const char * id , struct snd_compr * compr )
2011-12-23 09:06:39 +04:00
{
2020-01-03 11:16:20 +03:00
static const struct snd_device_ops ops = {
2015-01-30 10:16:35 +03:00
. dev_free = snd_compress_dev_free ,
2011-12-23 09:06:39 +04:00
. dev_register = snd_compress_dev_register ,
. dev_disconnect = snd_compress_dev_disconnect ,
} ;
2015-11-25 16:00:23 +03:00
int ret ;
2011-12-23 09:06:39 +04:00
compr - > card = card ;
compr - > device = device ;
compr - > direction = dirn ;
2021-07-14 19:24:24 +03:00
mutex_init ( & compr - > lock ) ;
2015-01-30 10:16:35 +03:00
2015-11-25 16:00:24 +03:00
snd_compress_set_id ( compr , id ) ;
2015-01-30 10:16:35 +03:00
snd_device_initialize ( & compr - > dev , card ) ;
dev_set_name ( & compr - > dev , " comprC%iD%i " , card - > number , device ) ;
2015-11-25 16:00:23 +03:00
ret = snd_device_new ( card , SNDRV_DEV_COMPRESS , compr , & ops ) ;
if ( ret = = 0 )
snd_compress_proc_init ( compr ) ;
return ret ;
2011-12-23 09:06:39 +04:00
}
EXPORT_SYMBOL_GPL ( snd_compress_new ) ;
MODULE_DESCRIPTION ( " ALSA Compressed offload framework " ) ;
MODULE_AUTHOR ( " Vinod Koul <vinod.koul@linux.intel.com> " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;