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>
2012-04-25 18:54:58 +04:00
# include <linux/iio/kfifo_buf.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 ;
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 ,
int bytes_per_datum , int length )
{
if ( ( length = = 0 ) | | ( bytes_per_datum = = 0 ) )
return - EINVAL ;
2011-09-21 14:15:57 +04:00
__iio_update_buffer ( & buf - > buffer , bytes_per_datum , length ) ;
2011-02-11 16:09:10 +03:00
return kfifo_alloc ( & buf - > kf , bytes_per_datum * length , GFP_KERNEL ) ;
}
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 ) ;
if ( ! buf - > update_needed )
goto error_ret ;
kfifo_free ( & buf - > kf ) ;
2011-09-21 14:15:57 +04:00
ret = __iio_allocate_kfifo ( buf , buf - > buffer . bytes_per_datum ,
buf - > buffer . length ) ;
2011-02-11 16:09:10 +03:00
error_ret :
return ret ;
}
2011-09-21 14:15:57 +04:00
static int iio_get_length_kfifo ( struct iio_buffer * r )
2011-02-11 16:09:10 +03:00
{
return r - > length ;
}
2011-09-21 14:15:57 +04:00
static IIO_BUFFER_ENABLE_ATTR ;
static IIO_BUFFER_LENGTH_ATTR ;
2011-02-11 16:09:10 +03:00
static struct attribute * iio_kfifo_attributes [ ] = {
& dev_attr_length . attr ,
& dev_attr_enable . attr ,
NULL ,
} ;
static struct attribute_group iio_kfifo_attribute_group = {
. attrs = iio_kfifo_attributes ,
2011-08-30 15:32:47 +04:00
. name = " buffer " ,
2011-02-11 16:09:10 +03:00
} ;
2011-09-21 14:15:57 +04:00
static int iio_get_bytes_per_datum_kfifo ( struct iio_buffer * r )
2011-02-11 16:09:10 +03:00
{
return r - > bytes_per_datum ;
}
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 ;
}
2011-09-21 14:15:57 +04:00
static int iio_set_length_kfifo ( struct iio_buffer * r , int length )
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 ,
2011-05-18 17:42:24 +04:00
u8 * data ,
s64 timestamp )
2011-02-11 16:09:10 +03:00
{
int ret ;
struct iio_kfifo * kf = iio_to_kfifo ( r ) ;
ret = kfifo_in ( & kf - > kf , data , r - > bytes_per_datum ) ;
2011-10-26 20:27:40 +04:00
if ( ret ! = r - > bytes_per_datum )
2011-02-11 16:09:10 +03:00
return - EBUSY ;
return 0 ;
}
2011-09-21 14:15:57 +04:00
static int iio_read_first_n_kfifo ( struct iio_buffer * r ,
2011-05-18 17:41:02 +04:00
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 ) ;
2011-12-12 12:33:14 +04:00
if ( n < r - > bytes_per_datum )
return - EINVAL ;
n = rounddown ( n , r - > bytes_per_datum ) ;
ret = kfifo_to_user ( & kf - > kf , buf , n , & copied ) ;
2011-02-11 16:09:10 +03:00
return copied ;
}
2011-05-18 17:42:24 +04:00
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 ,
. read_first_n = & iio_read_first_n_kfifo ,
. request_update = & iio_request_update_kfifo ,
. get_bytes_per_datum = & iio_get_bytes_per_datum_kfifo ,
. set_bytes_per_datum = & iio_set_bytes_per_datum_kfifo ,
. get_length = & iio_get_length_kfifo ,
. set_length = & iio_set_length_kfifo ,
} ;
2012-01-03 14:02:51 +04:00
struct iio_buffer * iio_kfifo_allocate ( struct iio_dev * indio_dev )
{
struct iio_kfifo * kf ;
kf = kzalloc ( sizeof * kf , GFP_KERNEL ) ;
if ( ! kf )
return NULL ;
kf - > update_needed = true ;
iio_buffer_init ( & kf - > buffer ) ;
kf - > buffer . attrs = & iio_kfifo_attribute_group ;
kf - > buffer . access = & kfifo_access_funcs ;
return & kf - > buffer ;
}
EXPORT_SYMBOL ( iio_kfifo_allocate ) ;
void iio_kfifo_free ( struct iio_buffer * r )
{
kfree ( iio_to_kfifo ( r ) ) ;
}
EXPORT_SYMBOL ( iio_kfifo_free ) ;
2011-05-18 17:42:24 +04:00
2011-02-11 16:09:10 +03:00
MODULE_LICENSE ( " GPL " ) ;