2012-06-30 23:06:00 +04:00
# include <linux/kernel.h>
# include <linux/slab.h>
# include <linux/err.h>
# include <linux/export.h>
# include <linux/iio/buffer.h>
# include <linux/iio/consumer.h>
struct iio_cb_buffer {
struct iio_buffer buffer ;
2013-09-15 20:50:00 +04:00
int ( * cb ) ( const void * data , void * private ) ;
2012-06-30 23:06:00 +04:00
void * private ;
struct iio_channel * channels ;
} ;
2013-10-04 15:06:00 +04:00
static struct iio_cb_buffer * buffer_to_cb_buffer ( struct iio_buffer * buffer )
2012-06-30 23:06:00 +04:00
{
2013-10-04 15:06:00 +04:00
return container_of ( buffer , struct iio_cb_buffer , buffer ) ;
}
2012-06-30 23:06:00 +04:00
2013-10-04 15:06:00 +04:00
static int iio_buffer_cb_store_to ( struct iio_buffer * buffer , const void * data )
{
struct iio_cb_buffer * cb_buff = buffer_to_cb_buffer ( buffer ) ;
2012-06-30 23:06:00 +04:00
return cb_buff - > cb ( data , cb_buff - > private ) ;
}
2013-10-04 15:06:00 +04:00
static void iio_buffer_cb_release ( struct iio_buffer * buffer )
{
struct iio_cb_buffer * cb_buff = buffer_to_cb_buffer ( buffer ) ;
kfree ( cb_buff - > buffer . scan_mask ) ;
kfree ( cb_buff ) ;
}
2013-09-15 20:09:00 +04:00
static const struct iio_buffer_access_funcs iio_cb_access = {
2012-06-30 23:06:00 +04:00
. store_to = & iio_buffer_cb_store_to ,
2013-10-04 15:06:00 +04:00
. release = & iio_buffer_cb_release ,
2012-06-30 23:06:00 +04:00
} ;
2013-02-01 01:43:00 +04:00
struct iio_cb_buffer * iio_channel_get_all_cb ( struct device * dev ,
2013-09-15 20:50:00 +04:00
int ( * cb ) ( const void * data ,
2012-06-30 23:06:00 +04:00
void * private ) ,
void * private )
{
int ret ;
struct iio_cb_buffer * cb_buff ;
struct iio_dev * indio_dev ;
struct iio_channel * chan ;
cb_buff = kzalloc ( sizeof ( * cb_buff ) , GFP_KERNEL ) ;
if ( cb_buff = = NULL ) {
ret = - ENOMEM ;
goto error_ret ;
}
2013-09-19 00:02:00 +04:00
iio_buffer_init ( & cb_buff - > buffer ) ;
2012-06-30 23:06:00 +04:00
cb_buff - > private = private ;
cb_buff - > cb = cb ;
cb_buff - > buffer . access = & iio_cb_access ;
INIT_LIST_HEAD ( & cb_buff - > buffer . demux_list ) ;
2013-02-01 01:43:00 +04:00
cb_buff - > channels = iio_channel_get_all ( dev ) ;
2012-06-30 23:06:00 +04:00
if ( IS_ERR ( cb_buff - > channels ) ) {
ret = PTR_ERR ( cb_buff - > channels ) ;
goto error_free_cb_buff ;
}
indio_dev = cb_buff - > channels [ 0 ] . indio_dev ;
cb_buff - > buffer . scan_mask
= kcalloc ( BITS_TO_LONGS ( indio_dev - > masklength ) , sizeof ( long ) ,
GFP_KERNEL ) ;
if ( cb_buff - > buffer . scan_mask = = NULL ) {
ret = - ENOMEM ;
goto error_release_channels ;
}
chan = & cb_buff - > channels [ 0 ] ;
while ( chan - > indio_dev ) {
if ( chan - > indio_dev ! = indio_dev ) {
ret = - EINVAL ;
2013-05-23 01:41:00 +04:00
goto error_free_scan_mask ;
2012-06-30 23:06:00 +04:00
}
set_bit ( chan - > channel - > scan_index ,
cb_buff - > buffer . scan_mask ) ;
chan + + ;
}
return cb_buff ;
2013-05-23 01:41:00 +04:00
error_free_scan_mask :
kfree ( cb_buff - > buffer . scan_mask ) ;
2012-06-30 23:06:00 +04:00
error_release_channels :
iio_channel_release_all ( cb_buff - > channels ) ;
error_free_cb_buff :
kfree ( cb_buff ) ;
error_ret :
return ERR_PTR ( ret ) ;
}
EXPORT_SYMBOL_GPL ( iio_channel_get_all_cb ) ;
int iio_channel_start_all_cb ( struct iio_cb_buffer * cb_buff )
{
return iio_update_buffers ( cb_buff - > channels [ 0 ] . indio_dev ,
& cb_buff - > buffer ,
NULL ) ;
}
EXPORT_SYMBOL_GPL ( iio_channel_start_all_cb ) ;
void iio_channel_stop_all_cb ( struct iio_cb_buffer * cb_buff )
{
iio_update_buffers ( cb_buff - > channels [ 0 ] . indio_dev ,
NULL ,
& cb_buff - > buffer ) ;
}
EXPORT_SYMBOL_GPL ( iio_channel_stop_all_cb ) ;
void iio_channel_release_all_cb ( struct iio_cb_buffer * cb_buff )
{
iio_channel_release_all ( cb_buff - > channels ) ;
2013-10-04 15:06:00 +04:00
iio_buffer_put ( & cb_buff - > buffer ) ;
2012-06-30 23:06:00 +04:00
}
EXPORT_SYMBOL_GPL ( iio_channel_release_all_cb ) ;
struct iio_channel
* iio_channel_cb_get_channels ( const struct iio_cb_buffer * cb_buffer )
{
return cb_buffer - > channels ;
}
EXPORT_SYMBOL_GPL ( iio_channel_cb_get_channels ) ;