2019-05-19 15:08:20 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2011-02-11 16:09:10 +03:00
# include <linux/slab.h>
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/device.h>
# include <linux/workqueue.h>
# include <linux/kfifo.h>
# include <linux/mutex.h>
2017-01-02 22:28:31 +03:00
# include <linux/iio/iio.h>
2017-01-02 22:28:30 +03:00
# include <linux/iio/buffer.h>
2012-04-25 18:54:58 +04:00
# include <linux/iio/kfifo_buf.h>
2017-01-02 22:28:34 +03:00
# include <linux/iio/buffer_impl.h>
2012-06-30 16:52:00 +04:00
# include <linux/sched.h>
2013-09-15 19:31:00 +04:00
# include <linux/poll.h>
2011-02-11 16:09:10 +03:00
2011-08-30 15:32:43 +04:00
struct iio_kfifo {
2011-09-21 14:15:57 +04:00
struct iio_buffer buffer ;
2011-08-30 15:32:43 +04:00
struct kfifo kf ;
2013-10-15 12:30:00 +04:00
struct mutex user_lock ;
2011-08-30 15:32:43 +04:00
int update_needed ;
} ;
2011-09-21 14:15:57 +04:00
# define iio_to_kfifo(r) container_of(r, struct iio_kfifo, buffer)
2011-05-18 17:42:24 +04:00
2011-02-11 16:09:10 +03:00
static inline int __iio_allocate_kfifo ( struct iio_kfifo * buf ,
2018-03-27 00:27:51 +03:00
size_t bytes_per_datum , unsigned int length )
2011-02-11 16:09:10 +03:00
{
if ( ( length = = 0 ) | | ( bytes_per_datum = = 0 ) )
return - EINVAL ;
2018-03-27 00:27:52 +03:00
/*
* Make sure we don ' t overflow an unsigned int after kfifo rounds up to
* the next power of 2.
*/
if ( roundup_pow_of_two ( length ) > UINT_MAX / bytes_per_datum )
return - EINVAL ;
2012-06-30 16:52:00 +04:00
return __kfifo_alloc ( ( struct __kfifo * ) & buf - > kf , length ,
bytes_per_datum , GFP_KERNEL ) ;
2011-02-11 16:09:10 +03:00
}
2011-09-21 14:15:57 +04:00
static int iio_request_update_kfifo ( struct iio_buffer * r )
2011-02-11 16:09:10 +03:00
{
int ret = 0 ;
struct iio_kfifo * buf = iio_to_kfifo ( r ) ;
2013-10-15 12:30:00 +04:00
mutex_lock ( & buf - > user_lock ) ;
2013-10-15 12:30:00 +04:00
if ( buf - > update_needed ) {
kfifo_free ( & buf - > kf ) ;
ret = __iio_allocate_kfifo ( buf , buf - > buffer . bytes_per_datum ,
2011-09-21 14:15:57 +04:00
buf - > buffer . length ) ;
2015-05-02 15:31:16 +03:00
if ( ret > = 0 )
buf - > update_needed = false ;
2013-10-15 12:30:00 +04:00
} else {
kfifo_reset_out ( & buf - > kf ) ;
}
2013-10-15 12:30:00 +04:00
mutex_unlock ( & buf - > user_lock ) ;
2013-10-15 12:30:00 +04:00
2011-02-11 16:09:10 +03:00
return ret ;
}
2011-12-19 18:23:48 +04:00
static int iio_mark_update_needed_kfifo ( struct iio_buffer * r )
2011-02-11 16:09:10 +03:00
{
2011-12-19 18:23:48 +04:00
struct iio_kfifo * kf = iio_to_kfifo ( r ) ;
kf - > update_needed = true ;
2011-02-11 16:09:10 +03:00
return 0 ;
}
2011-12-19 18:23:48 +04:00
static int iio_set_bytes_per_datum_kfifo ( struct iio_buffer * r , size_t bpd )
2011-02-11 16:09:10 +03:00
{
2011-12-19 18:23:48 +04:00
if ( r - > bytes_per_datum ! = bpd ) {
r - > bytes_per_datum = bpd ;
iio_mark_update_needed_kfifo ( r ) ;
}
2011-02-11 16:09:10 +03:00
return 0 ;
}
2018-03-27 00:27:51 +03:00
static int iio_set_length_kfifo ( struct iio_buffer * r , unsigned int length )
2011-02-11 16:09:10 +03:00
{
2012-06-30 16:52:00 +04:00
/* Avoid an invalid state */
if ( length < 2 )
length = 2 ;
2011-02-11 16:09:10 +03:00
if ( r - > length ! = length ) {
r - > length = length ;
2011-12-19 18:23:48 +04:00
iio_mark_update_needed_kfifo ( r ) ;
2011-02-11 16:09:10 +03:00
}
return 0 ;
}
2011-09-21 14:15:57 +04:00
static int iio_store_to_kfifo ( struct iio_buffer * r ,
2013-09-15 20:50:00 +04:00
const void * data )
2011-02-11 16:09:10 +03:00
{
int ret ;
struct iio_kfifo * kf = iio_to_kfifo ( r ) ;
2012-06-30 16:52:00 +04:00
ret = kfifo_in ( & kf - > kf , data , 1 ) ;
if ( ret ! = 1 )
2011-02-11 16:09:10 +03:00
return - EBUSY ;
return 0 ;
}
2019-12-11 13:43:00 +03:00
static int iio_read_kfifo ( struct iio_buffer * r , size_t n , char __user * buf )
2011-02-11 16:09:10 +03:00
{
int ret , copied ;
struct iio_kfifo * kf = iio_to_kfifo ( r ) ;
2013-10-15 12:30:00 +04:00
if ( mutex_lock_interruptible ( & kf - > user_lock ) )
return - ERESTARTSYS ;
2011-12-12 12:33:14 +04:00
2013-10-15 12:30:00 +04:00
if ( ! kfifo_initialized ( & kf - > kf ) | | n < kfifo_esize ( & kf - > kf ) )
ret = - EINVAL ;
else
ret = kfifo_to_user ( & kf - > kf , buf , n , & copied ) ;
mutex_unlock ( & kf - > user_lock ) ;
if ( ret < 0 )
return ret ;
2011-02-11 16:09:10 +03:00
return copied ;
}
2011-05-18 17:42:24 +04:00
2015-03-22 21:33:38 +03:00
static size_t iio_kfifo_buf_data_available ( struct iio_buffer * r )
2013-11-25 18:56:00 +04:00
{
struct iio_kfifo * kf = iio_to_kfifo ( r ) ;
2015-03-22 21:33:38 +03:00
size_t samples ;
2013-11-25 18:56:00 +04:00
mutex_lock ( & kf - > user_lock ) ;
2015-03-22 21:33:38 +03:00
samples = kfifo_len ( & kf - > kf ) ;
2013-11-25 18:56:00 +04:00
mutex_unlock ( & kf - > user_lock ) ;
2015-03-22 21:33:38 +03:00
return samples ;
2013-11-25 18:56:00 +04:00
}
2013-10-04 15:06:00 +04:00
static void iio_kfifo_buffer_release ( struct iio_buffer * buffer )
{
2013-10-15 12:30:00 +04:00
struct iio_kfifo * kf = iio_to_kfifo ( buffer ) ;
2013-10-15 12:30:00 +04:00
mutex_destroy ( & kf - > user_lock ) ;
2013-10-15 12:30:00 +04:00
kfifo_free ( & kf - > kf ) ;
kfree ( kf ) ;
2013-10-04 15:06:00 +04:00
}
2021-10-07 11:00:31 +03:00
static size_t iio_kfifo_buf_space_available ( struct iio_buffer * r )
{
struct iio_kfifo * kf = iio_to_kfifo ( r ) ;
size_t avail ;
mutex_lock ( & kf - > user_lock ) ;
avail = kfifo_avail ( & kf - > kf ) ;
mutex_unlock ( & kf - > user_lock ) ;
return avail ;
}
static int iio_kfifo_remove_from ( struct iio_buffer * r , void * data )
{
int ret ;
struct iio_kfifo * kf = iio_to_kfifo ( r ) ;
if ( kfifo_size ( & kf - > kf ) < 1 )
return - EBUSY ;
ret = kfifo_out ( & kf - > kf , data , 1 ) ;
if ( ret ! = 1 )
return - EBUSY ;
wake_up_interruptible_poll ( & r - > pollq , EPOLLOUT | EPOLLWRNORM ) ;
return 0 ;
}
static int iio_kfifo_write ( struct iio_buffer * r , size_t n ,
const char __user * buf )
{
struct iio_kfifo * kf = iio_to_kfifo ( r ) ;
int ret , copied ;
mutex_lock ( & kf - > user_lock ) ;
if ( ! kfifo_initialized ( & kf - > kf ) | | n < kfifo_esize ( & kf - > kf ) )
ret = - EINVAL ;
else
ret = kfifo_from_user ( & kf - > kf , buf , n , & copied ) ;
mutex_unlock ( & kf - > user_lock ) ;
if ( ret )
return ret ;
return copied ;
}
2012-01-03 14:02:51 +04:00
static const struct iio_buffer_access_funcs kfifo_access_funcs = {
2011-05-18 17:42:24 +04:00
. store_to = & iio_store_to_kfifo ,
2019-12-11 13:43:00 +03:00
. read = & iio_read_kfifo ,
2013-11-25 18:56:00 +04:00
. data_available = iio_kfifo_buf_data_available ,
2021-10-07 11:00:31 +03:00
. remove_from = & iio_kfifo_remove_from ,
. write = & iio_kfifo_write ,
. space_available = & iio_kfifo_buf_space_available ,
2011-05-18 17:42:24 +04:00
. request_update = & iio_request_update_kfifo ,
. set_bytes_per_datum = & iio_set_bytes_per_datum_kfifo ,
. set_length = & iio_set_length_kfifo ,
2013-10-04 15:06:00 +04:00
. release = & iio_kfifo_buffer_release ,
2015-05-29 19:14:21 +03:00
. modes = INDIO_BUFFER_SOFTWARE | INDIO_BUFFER_TRIGGERED ,
2011-05-18 17:42:24 +04:00
} ;
2012-01-03 14:02:51 +04:00
2014-12-19 20:39:24 +03:00
struct iio_buffer * iio_kfifo_allocate ( void )
2012-01-03 14:02:51 +04:00
{
struct iio_kfifo * kf ;
2014-12-19 20:39:24 +03:00
kf = kzalloc ( sizeof ( * kf ) , GFP_KERNEL ) ;
2012-01-03 14:02:51 +04:00
if ( ! kf )
return NULL ;
2014-12-19 20:39:24 +03:00
2012-01-03 14:02:51 +04:00
kf - > update_needed = true ;
iio_buffer_init ( & kf - > buffer ) ;
kf - > buffer . access = & kfifo_access_funcs ;
2012-06-30 16:52:00 +04:00
kf - > buffer . length = 2 ;
2013-10-15 12:30:00 +04:00
mutex_init ( & kf - > user_lock ) ;
2014-12-19 20:39:24 +03:00
2012-01-03 14:02:51 +04:00
return & kf - > buffer ;
}
EXPORT_SYMBOL ( iio_kfifo_allocate ) ;
void iio_kfifo_free ( struct iio_buffer * r )
{
2013-10-04 15:06:00 +04:00
iio_buffer_put ( r ) ;
2012-01-03 14:02:51 +04:00
}
EXPORT_SYMBOL ( iio_kfifo_free ) ;
2011-05-18 17:42:24 +04:00
2014-12-19 20:39:25 +03:00
static void devm_iio_kfifo_release ( struct device * dev , void * res )
{
iio_kfifo_free ( * ( struct iio_buffer * * ) res ) ;
}
/**
2021-03-14 19:46:55 +03:00
* devm_iio_kfifo_allocate - Resource - managed iio_kfifo_allocate ( )
2014-12-19 20:39:25 +03:00
* @ dev : Device to allocate kfifo buffer for
*
* RETURNS :
* Pointer to allocated iio_buffer on success , NULL on failure .
*/
2021-02-15 13:40:24 +03:00
static struct iio_buffer * devm_iio_kfifo_allocate ( struct device * dev )
2014-12-19 20:39:25 +03:00
{
struct iio_buffer * * ptr , * r ;
ptr = devres_alloc ( devm_iio_kfifo_release , sizeof ( * ptr ) , GFP_KERNEL ) ;
if ( ! ptr )
return NULL ;
r = iio_kfifo_allocate ( ) ;
if ( r ) {
* ptr = r ;
devres_add ( dev , ptr ) ;
} else {
devres_free ( ptr ) ;
}
return r ;
}
2021-02-15 13:40:21 +03:00
/**
2021-03-11 12:10:42 +03:00
* devm_iio_kfifo_buffer_setup_ext - Allocate a kfifo buffer & attach it to an IIO device
2021-02-15 13:40:21 +03:00
* @ dev : Device object to which to attach the life - time of this kfifo buffer
* @ indio_dev : The device the buffer should be attached to
* @ setup_ops : The setup_ops required to configure the HW part of the buffer ( optional )
2021-03-11 12:10:42 +03:00
* @ buffer_attrs : Extra sysfs buffer attributes for this IIO buffer
2021-02-15 13:40:21 +03:00
*
* This function allocates a kfifo buffer via devm_iio_kfifo_allocate ( ) and
* attaches it to the IIO device via iio_device_attach_buffer ( ) .
* This is meant to be a bit of a short - hand / helper function as there are a few
* drivers that seem to do this .
*/
2021-03-11 12:10:42 +03:00
int devm_iio_kfifo_buffer_setup_ext ( struct device * dev ,
struct iio_dev * indio_dev ,
const struct iio_buffer_setup_ops * setup_ops ,
const struct attribute * * buffer_attrs )
2021-02-15 13:40:21 +03:00
{
struct iio_buffer * buffer ;
buffer = devm_iio_kfifo_allocate ( dev ) ;
if ( ! buffer )
return - ENOMEM ;
2022-02-07 17:38:39 +03:00
indio_dev - > modes | = INDIO_BUFFER_SOFTWARE ;
2021-02-15 13:40:21 +03:00
indio_dev - > setup_ops = setup_ops ;
2021-03-11 12:10:42 +03:00
buffer - > attrs = buffer_attrs ;
2021-02-15 13:40:38 +03:00
return iio_device_attach_buffer ( indio_dev , buffer ) ;
2021-02-15 13:40:21 +03:00
}
2021-03-11 12:10:42 +03:00
EXPORT_SYMBOL_GPL ( devm_iio_kfifo_buffer_setup_ext ) ;
2021-02-15 13:40:21 +03:00
2011-02-11 16:09:10 +03:00
MODULE_LICENSE ( " GPL " ) ;