2012-01-03 14:59:38 +01:00
/* Industrial I/O event handling
*
* Copyright ( c ) 2008 Jonathan Cameron
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms of the GNU General Public License version 2 as published by
* the Free Software Foundation .
*
* Based on elements of hwmon and input subsystems .
*/
# include <linux/anon_inodes.h>
# include <linux/device.h>
# include <linux/fs.h>
# include <linux/kernel.h>
2012-01-03 14:59:39 +01:00
# include <linux/kfifo.h>
2012-01-03 14:59:38 +01:00
# include <linux/module.h>
2012-01-03 14:59:41 +01:00
# include <linux/poll.h>
2012-01-03 14:59:38 +01:00
# include <linux/sched.h>
# include <linux/slab.h>
# include <linux/uaccess.h>
# include <linux/wait.h>
2012-04-25 15:54:58 +01:00
# include <linux/iio/iio.h>
2012-01-03 14:59:38 +01:00
# include "iio_core.h"
2012-04-25 15:54:58 +01:00
# include <linux/iio/sysfs.h>
# include <linux/iio/events.h>
2012-01-03 14:59:38 +01:00
/**
* struct iio_event_interface - chrdev interface for an event line
* @ wait : wait queue to allow blocking reads of events
* @ det_events : list of detected events
* @ dev_attr_list : list of event interface sysfs attribute
* @ flags : file operations related flags including busy flag .
* @ group : event interface sysfs attribute group
*/
struct iio_event_interface {
wait_queue_head_t wait ;
2012-01-03 14:59:39 +01:00
DECLARE_KFIFO ( det_events , struct iio_event_data , 16 ) ;
2012-01-03 14:59:38 +01:00
struct list_head dev_attr_list ;
unsigned long flags ;
struct attribute_group group ;
} ;
int iio_push_event ( struct iio_dev * indio_dev , u64 ev_code , s64 timestamp )
{
struct iio_event_interface * ev_int = indio_dev - > event_interface ;
2012-01-03 14:59:39 +01:00
struct iio_event_data ev ;
2013-03-07 19:53:00 +00:00
unsigned long flags ;
2012-01-03 14:59:39 +01:00
int copied ;
2012-01-03 14:59:38 +01:00
/* Does anyone care? */
2013-03-07 19:53:00 +00:00
spin_lock_irqsave ( & ev_int - > wait . lock , flags ) ;
2012-01-03 14:59:38 +01:00
if ( test_bit ( IIO_BUSY_BIT_POS , & ev_int - > flags ) ) {
2012-01-03 14:59:39 +01:00
ev . id = ev_code ;
ev . timestamp = timestamp ;
2013-11-14 14:32:17 -08:00
copied = kfifo_put ( & ev_int - > det_events , ev ) ;
2012-01-03 14:59:39 +01:00
if ( copied ! = 0 )
2012-01-03 14:59:41 +01:00
wake_up_locked_poll ( & ev_int - > wait , POLLIN ) ;
2012-01-03 14:59:40 +01:00
}
2013-03-07 19:53:00 +00:00
spin_unlock_irqrestore ( & ev_int - > wait . lock , flags ) ;
2012-01-03 14:59:38 +01:00
2012-01-03 14:59:39 +01:00
return 0 ;
2012-01-03 14:59:38 +01:00
}
EXPORT_SYMBOL ( iio_push_event ) ;
2012-01-03 14:59:41 +01:00
/**
* iio_event_poll ( ) - poll the event queue to find out if it has data
*/
static unsigned int iio_event_poll ( struct file * filep ,
struct poll_table_struct * wait )
{
2013-09-18 21:02:00 +01:00
struct iio_dev * indio_dev = filep - > private_data ;
struct iio_event_interface * ev_int = indio_dev - > event_interface ;
2012-01-03 14:59:41 +01:00
unsigned int events = 0 ;
2013-10-04 12:06:00 +01:00
if ( ! indio_dev - > info )
return - ENODEV ;
2012-01-03 14:59:41 +01:00
poll_wait ( filep , & ev_int - > wait , wait ) ;
2013-03-07 19:53:00 +00:00
spin_lock_irq ( & ev_int - > wait . lock ) ;
2012-01-03 14:59:41 +01:00
if ( ! kfifo_is_empty ( & ev_int - > det_events ) )
events = POLLIN | POLLRDNORM ;
2013-03-07 19:53:00 +00:00
spin_unlock_irq ( & ev_int - > wait . lock ) ;
2012-01-03 14:59:41 +01:00
return events ;
}
2012-01-03 14:59:38 +01:00
static ssize_t iio_event_chrdev_read ( struct file * filep ,
char __user * buf ,
size_t count ,
loff_t * f_ps )
{
2013-09-18 21:02:00 +01:00
struct iio_dev * indio_dev = filep - > private_data ;
struct iio_event_interface * ev_int = indio_dev - > event_interface ;
2012-01-03 14:59:39 +01:00
unsigned int copied ;
2012-01-03 14:59:38 +01:00
int ret ;
2013-10-04 12:06:00 +01:00
if ( ! indio_dev - > info )
return - ENODEV ;
2012-01-03 14:59:39 +01:00
if ( count < sizeof ( struct iio_event_data ) )
2012-01-03 14:59:38 +01:00
return - EINVAL ;
2013-03-07 19:53:00 +00:00
spin_lock_irq ( & ev_int - > wait . lock ) ;
2012-01-03 14:59:39 +01:00
if ( kfifo_is_empty ( & ev_int - > det_events ) ) {
2012-01-03 14:59:38 +01:00
if ( filep - > f_flags & O_NONBLOCK ) {
ret = - EAGAIN ;
2012-01-03 14:59:40 +01:00
goto error_unlock ;
2012-01-03 14:59:38 +01:00
}
/* Blocking on device; waiting for something to be there */
2013-03-07 19:53:00 +00:00
ret = wait_event_interruptible_locked_irq ( ev_int - > wait ,
2013-10-04 12:07:00 +01:00
! kfifo_is_empty ( & ev_int - > det_events ) | |
indio_dev - > info = = NULL ) ;
2012-01-03 14:59:38 +01:00
if ( ret )
2012-01-03 14:59:40 +01:00
goto error_unlock ;
2013-10-04 12:07:00 +01:00
if ( indio_dev - > info = = NULL ) {
ret = - ENODEV ;
goto error_unlock ;
}
2012-01-03 14:59:38 +01:00
/* Single access device so no one else can get the data */
}
2012-01-03 14:59:39 +01:00
ret = kfifo_to_user ( & ev_int - > det_events , buf , count , & copied ) ;
2012-01-03 14:59:38 +01:00
2012-01-03 14:59:40 +01:00
error_unlock :
2013-03-07 19:53:00 +00:00
spin_unlock_irq ( & ev_int - > wait . lock ) ;
2012-01-03 14:59:40 +01:00
2012-01-03 14:59:39 +01:00
return ret ? ret : copied ;
2012-01-03 14:59:38 +01:00
}
static int iio_event_chrdev_release ( struct inode * inode , struct file * filep )
{
2013-09-18 21:02:00 +01:00
struct iio_dev * indio_dev = filep - > private_data ;
struct iio_event_interface * ev_int = indio_dev - > event_interface ;
2012-01-03 14:59:38 +01:00
2013-03-07 19:53:00 +00:00
spin_lock_irq ( & ev_int - > wait . lock ) ;
2012-01-03 14:59:42 +01:00
__clear_bit ( IIO_BUSY_BIT_POS , & ev_int - > flags ) ;
2012-01-03 14:59:38 +01:00
/*
* In order to maintain a clean state for reopening ,
* clear out any awaiting events . The mask will prevent
* any new __iio_push_event calls running .
*/
2012-01-03 14:59:39 +01:00
kfifo_reset_out ( & ev_int - > det_events ) ;
2013-03-07 19:53:00 +00:00
spin_unlock_irq ( & ev_int - > wait . lock ) ;
2012-01-03 14:59:38 +01:00
2013-09-18 21:02:00 +01:00
iio_device_put ( indio_dev ) ;
2012-01-03 14:59:38 +01:00
return 0 ;
}
static const struct file_operations iio_event_chrdev_fileops = {
. read = iio_event_chrdev_read ,
2012-01-03 14:59:41 +01:00
. poll = iio_event_poll ,
2012-01-03 14:59:38 +01:00
. release = iio_event_chrdev_release ,
. owner = THIS_MODULE ,
. llseek = noop_llseek ,
} ;
int iio_event_getfd ( struct iio_dev * indio_dev )
{
struct iio_event_interface * ev_int = indio_dev - > event_interface ;
int fd ;
if ( ev_int = = NULL )
return - ENODEV ;
2013-03-07 19:53:00 +00:00
spin_lock_irq ( & ev_int - > wait . lock ) ;
2012-01-03 14:59:42 +01:00
if ( __test_and_set_bit ( IIO_BUSY_BIT_POS , & ev_int - > flags ) ) {
2013-03-07 19:53:00 +00:00
spin_unlock_irq ( & ev_int - > wait . lock ) ;
2012-01-03 14:59:38 +01:00
return - EBUSY ;
}
2013-03-07 19:53:00 +00:00
spin_unlock_irq ( & ev_int - > wait . lock ) ;
2013-09-18 21:02:00 +01:00
iio_device_get ( indio_dev ) ;
fd = anon_inode_getfd ( " iio:event " , & iio_event_chrdev_fileops ,
2013-09-25 08:59:04 -07:00
indio_dev , O_RDONLY | O_CLOEXEC ) ;
2012-01-03 14:59:38 +01:00
if ( fd < 0 ) {
2013-03-07 19:53:00 +00:00
spin_lock_irq ( & ev_int - > wait . lock ) ;
2012-01-03 14:59:42 +01:00
__clear_bit ( IIO_BUSY_BIT_POS , & ev_int - > flags ) ;
2013-03-07 19:53:00 +00:00
spin_unlock_irq ( & ev_int - > wait . lock ) ;
2013-09-18 21:02:00 +01:00
iio_device_put ( indio_dev ) ;
2012-01-03 14:59:38 +01:00
}
return fd ;
}
static const char * const iio_ev_type_text [ ] = {
[ IIO_EV_TYPE_THRESH ] = " thresh " ,
[ IIO_EV_TYPE_MAG ] = " mag " ,
[ IIO_EV_TYPE_ROC ] = " roc " ,
[ IIO_EV_TYPE_THRESH_ADAPTIVE ] = " thresh_adaptive " ,
[ IIO_EV_TYPE_MAG_ADAPTIVE ] = " mag_adaptive " ,
} ;
static const char * const iio_ev_dir_text [ ] = {
[ IIO_EV_DIR_EITHER ] = " either " ,
[ IIO_EV_DIR_RISING ] = " rising " ,
[ IIO_EV_DIR_FALLING ] = " falling "
} ;
2013-10-07 15:11:00 +01:00
static const char * const iio_ev_info_text [ ] = {
[ IIO_EV_INFO_ENABLE ] = " en " ,
[ IIO_EV_INFO_VALUE ] = " value " ,
2013-10-07 15:11:00 +01:00
[ IIO_EV_INFO_HYSTERESIS ] = " hysteresis " ,
2013-10-07 15:11:00 +01:00
} ;
static enum iio_event_direction iio_ev_attr_dir ( struct iio_dev_attr * attr )
{
return attr - > c - > event_spec [ attr - > address & 0xffff ] . dir ;
}
static enum iio_event_type iio_ev_attr_type ( struct iio_dev_attr * attr )
{
return attr - > c - > event_spec [ attr - > address & 0xffff ] . type ;
}
static enum iio_event_info iio_ev_attr_info ( struct iio_dev_attr * attr )
{
return ( attr - > address > > 16 ) & 0xffff ;
}
2012-01-03 14:59:38 +01:00
static ssize_t iio_ev_state_store ( struct device * dev ,
struct device_attribute * attr ,
const char * buf ,
size_t len )
{
2012-05-12 15:39:33 +02:00
struct iio_dev * indio_dev = dev_to_iio_dev ( dev ) ;
2012-01-03 14:59:38 +01:00
struct iio_dev_attr * this_attr = to_iio_dev_attr ( attr ) ;
int ret ;
bool val ;
ret = strtobool ( buf , & val ) ;
if ( ret < 0 )
return ret ;
2013-10-07 15:11:00 +01:00
if ( indio_dev - > info - > write_event_config )
ret = indio_dev - > info - > write_event_config ( indio_dev ,
this_attr - > address , val ) ;
else
ret = indio_dev - > info - > write_event_config_new ( indio_dev ,
this_attr - > c , iio_ev_attr_type ( this_attr ) ,
iio_ev_attr_dir ( this_attr ) , val ) ;
2012-01-03 14:59:38 +01:00
return ( ret < 0 ) ? ret : len ;
}
static ssize_t iio_ev_state_show ( struct device * dev ,
struct device_attribute * attr ,
char * buf )
{
2012-05-12 15:39:33 +02:00
struct iio_dev * indio_dev = dev_to_iio_dev ( dev ) ;
2012-01-03 14:59:38 +01:00
struct iio_dev_attr * this_attr = to_iio_dev_attr ( attr ) ;
2013-10-07 15:11:00 +01:00
int val ;
2012-01-03 14:59:38 +01:00
2013-10-07 15:11:00 +01:00
if ( indio_dev - > info - > read_event_config )
val = indio_dev - > info - > read_event_config ( indio_dev ,
this_attr - > address ) ;
else
val = indio_dev - > info - > read_event_config_new ( indio_dev ,
this_attr - > c , iio_ev_attr_type ( this_attr ) ,
iio_ev_attr_dir ( this_attr ) ) ;
2012-01-03 14:59:38 +01:00
if ( val < 0 )
return val ;
else
return sprintf ( buf , " %d \n " , val ) ;
}
static ssize_t iio_ev_value_show ( struct device * dev ,
struct device_attribute * attr ,
char * buf )
{
2012-05-12 15:39:33 +02:00
struct iio_dev * indio_dev = dev_to_iio_dev ( dev ) ;
2012-01-03 14:59:38 +01:00
struct iio_dev_attr * this_attr = to_iio_dev_attr ( attr ) ;
2013-10-07 15:11:00 +01:00
int val , val2 ;
int ret ;
2012-01-03 14:59:38 +01:00
2013-10-07 15:11:00 +01:00
if ( indio_dev - > info - > read_event_value ) {
ret = indio_dev - > info - > read_event_value ( indio_dev ,
this_attr - > address , & val ) ;
if ( ret < 0 )
return ret ;
return sprintf ( buf , " %d \n " , val ) ;
} else {
ret = indio_dev - > info - > read_event_value_new ( indio_dev ,
this_attr - > c , iio_ev_attr_type ( this_attr ) ,
iio_ev_attr_dir ( this_attr ) , iio_ev_attr_info ( this_attr ) ,
& val , & val2 ) ;
if ( ret < 0 )
return ret ;
return iio_format_value ( buf , ret , val , val2 ) ;
}
2012-01-03 14:59:38 +01:00
}
static ssize_t iio_ev_value_store ( struct device * dev ,
struct device_attribute * attr ,
const char * buf ,
size_t len )
{
2012-05-12 15:39:33 +02:00
struct iio_dev * indio_dev = dev_to_iio_dev ( dev ) ;
2012-01-03 14:59:38 +01:00
struct iio_dev_attr * this_attr = to_iio_dev_attr ( attr ) ;
2013-10-07 15:11:00 +01:00
int val , val2 ;
2012-01-03 14:59:38 +01:00
int ret ;
2013-10-07 15:11:00 +01:00
if ( ! indio_dev - > info - > write_event_value & &
! indio_dev - > info - > write_event_value_new )
2012-01-03 14:59:38 +01:00
return - EINVAL ;
2013-10-07 15:11:00 +01:00
if ( indio_dev - > info - > write_event_value ) {
ret = kstrtoint ( buf , 10 , & val ) ;
if ( ret )
return ret ;
ret = indio_dev - > info - > write_event_value ( indio_dev ,
this_attr - > address , val ) ;
} else {
ret = iio_str_to_fixpoint ( buf , 100000 , & val , & val2 ) ;
if ( ret )
return ret ;
ret = indio_dev - > info - > write_event_value_new ( indio_dev ,
this_attr - > c , iio_ev_attr_type ( this_attr ) ,
iio_ev_attr_dir ( this_attr ) , iio_ev_attr_info ( this_attr ) ,
val , val2 ) ;
}
2012-01-03 14:59:38 +01:00
if ( ret < 0 )
return ret ;
return len ;
}
2013-10-07 15:11:00 +01:00
static int iio_device_add_event ( struct iio_dev * indio_dev ,
const struct iio_chan_spec * chan , unsigned int spec_index ,
enum iio_event_type type , enum iio_event_direction dir ,
enum iio_shared_by shared_by , const unsigned long * mask )
{
ssize_t ( * show ) ( struct device * , struct device_attribute * , char * ) ;
ssize_t ( * store ) ( struct device * , struct device_attribute * ,
const char * , size_t ) ;
unsigned int attrcount = 0 ;
unsigned int i ;
char * postfix ;
int ret ;
for_each_set_bit ( i , mask , sizeof ( * mask ) ) {
postfix = kasprintf ( GFP_KERNEL , " %s_%s_%s " ,
iio_ev_type_text [ type ] , iio_ev_dir_text [ dir ] ,
iio_ev_info_text [ i ] ) ;
if ( postfix = = NULL )
return - ENOMEM ;
if ( i = = IIO_EV_INFO_ENABLE ) {
show = iio_ev_state_show ;
store = iio_ev_state_store ;
} else {
show = iio_ev_value_show ;
store = iio_ev_value_store ;
}
ret = __iio_add_chan_devattr ( postfix , chan , show , store ,
( i < < 16 ) | spec_index , shared_by , & indio_dev - > dev ,
& indio_dev - > event_interface - > dev_attr_list ) ;
kfree ( postfix ) ;
if ( ret )
return ret ;
attrcount + + ;
}
return attrcount ;
}
static int iio_device_add_event_sysfs_new ( struct iio_dev * indio_dev ,
struct iio_chan_spec const * chan )
{
int ret = 0 , i , attrcount = 0 ;
enum iio_event_direction dir ;
enum iio_event_type type ;
for ( i = 0 ; i < chan - > num_event_specs ; i + + ) {
type = chan - > event_spec [ i ] . type ;
dir = chan - > event_spec [ i ] . dir ;
ret = iio_device_add_event ( indio_dev , chan , i , type , dir ,
IIO_SEPARATE , & chan - > event_spec [ i ] . mask_separate ) ;
if ( ret < 0 )
goto error_ret ;
attrcount + = ret ;
ret = iio_device_add_event ( indio_dev , chan , i , type , dir ,
IIO_SHARED_BY_TYPE ,
& chan - > event_spec [ i ] . mask_shared_by_type ) ;
if ( ret < 0 )
goto error_ret ;
attrcount + = ret ;
ret = iio_device_add_event ( indio_dev , chan , i , type , dir ,
IIO_SHARED_BY_DIR ,
& chan - > event_spec [ i ] . mask_shared_by_dir ) ;
if ( ret < 0 )
goto error_ret ;
attrcount + = ret ;
ret = iio_device_add_event ( indio_dev , chan , i , type , dir ,
IIO_SHARED_BY_ALL ,
& chan - > event_spec [ i ] . mask_shared_by_all ) ;
if ( ret < 0 )
goto error_ret ;
attrcount + = ret ;
}
ret = attrcount ;
error_ret :
return ret ;
}
static int iio_device_add_event_sysfs_old ( struct iio_dev * indio_dev ,
2012-01-03 14:59:38 +01:00
struct iio_chan_spec const * chan )
{
int ret = 0 , i , attrcount = 0 ;
u64 mask = 0 ;
char * postfix ;
if ( ! chan - > event_mask )
return 0 ;
for_each_set_bit ( i , & chan - > event_mask , sizeof ( chan - > event_mask ) * 8 ) {
postfix = kasprintf ( GFP_KERNEL , " %s_%s_en " ,
iio_ev_type_text [ i / IIO_EV_DIR_MAX ] ,
iio_ev_dir_text [ i % IIO_EV_DIR_MAX ] ) ;
if ( postfix = = NULL ) {
ret = - ENOMEM ;
goto error_ret ;
}
if ( chan - > modified )
2013-09-18 10:21:00 +01:00
mask = IIO_MOD_EVENT_CODE ( chan - > type , 0 , chan - > channel2 ,
2012-01-03 14:59:38 +01:00
i / IIO_EV_DIR_MAX ,
i % IIO_EV_DIR_MAX ) ;
else if ( chan - > differential )
mask = IIO_EVENT_CODE ( chan - > type ,
0 , 0 ,
i % IIO_EV_DIR_MAX ,
i / IIO_EV_DIR_MAX ,
0 ,
chan - > channel ,
chan - > channel2 ) ;
else
mask = IIO_UNMOD_EVENT_CODE ( chan - > type ,
chan - > channel ,
i / IIO_EV_DIR_MAX ,
i % IIO_EV_DIR_MAX ) ;
ret = __iio_add_chan_devattr ( postfix ,
chan ,
& iio_ev_state_show ,
iio_ev_state_store ,
mask ,
0 ,
& indio_dev - > dev ,
& indio_dev - > event_interface - >
dev_attr_list ) ;
kfree ( postfix ) ;
if ( ret )
goto error_ret ;
attrcount + + ;
postfix = kasprintf ( GFP_KERNEL , " %s_%s_value " ,
iio_ev_type_text [ i / IIO_EV_DIR_MAX ] ,
iio_ev_dir_text [ i % IIO_EV_DIR_MAX ] ) ;
if ( postfix = = NULL ) {
ret = - ENOMEM ;
goto error_ret ;
}
ret = __iio_add_chan_devattr ( postfix , chan ,
iio_ev_value_show ,
iio_ev_value_store ,
mask ,
0 ,
& indio_dev - > dev ,
& indio_dev - > event_interface - >
dev_attr_list ) ;
kfree ( postfix ) ;
if ( ret )
goto error_ret ;
attrcount + + ;
}
ret = attrcount ;
error_ret :
return ret ;
}
2013-10-07 15:11:00 +01:00
static int iio_device_add_event_sysfs ( struct iio_dev * indio_dev ,
struct iio_chan_spec const * chan )
{
if ( chan - > event_mask )
return iio_device_add_event_sysfs_old ( indio_dev , chan ) ;
else
return iio_device_add_event_sysfs_new ( indio_dev , chan ) ;
}
2012-01-03 14:59:38 +01:00
static inline int __iio_add_event_config_attrs ( struct iio_dev * indio_dev )
{
int j , ret , attrcount = 0 ;
/* Dynically created from the channels array */
for ( j = 0 ; j < indio_dev - > num_channels ; j + + ) {
ret = iio_device_add_event_sysfs ( indio_dev ,
& indio_dev - > channels [ j ] ) ;
if ( ret < 0 )
drivers/iio/industrialio-event.c: eliminate possible double free
The function __iio_add_event_config_attrs is only called once, by the
function iio_device_register_eventset. If the call fails,
iio_device_register_eventset calls __iio_remove_event_config_attrs. There
is thus no need for __iio_add_event_config_attrs to also call
__iio_remove_event_config_attrs on failure.
A simplified version of the semantic match that finds this problem is as
follows: (http://coccinelle.lip6.fr/)
// <smpl>
@r@
identifier f,free,a;
parameter list[n] ps;
type T;
expression e;
@@
f(ps,T a,...) {
... when any
when != a = e
if(...) { ... free(a); ... return ...; }
... when any
}
@@
identifier r.f,r.free;
expression x,a;
expression list[r.n] xs;
@@
* x = f(xs,a,...);
if (...) { ... free(a); ... return ...; }
// </smpl>
Signed-off-by: Julia Lawall <Julia.Lawall@lip6.fr>
Signed-off-by: Jonathan Cameron <jic23@kernel.org>
2012-10-21 11:52:00 +01:00
return ret ;
2012-01-03 14:59:38 +01:00
attrcount + = ret ;
}
return attrcount ;
}
static bool iio_check_for_dynamic_events ( struct iio_dev * indio_dev )
{
int j ;
2013-10-07 15:11:00 +01:00
for ( j = 0 ; j < indio_dev - > num_channels ; j + + ) {
2012-01-03 14:59:38 +01:00
if ( indio_dev - > channels [ j ] . event_mask ! = 0 )
return true ;
2013-10-07 15:11:00 +01:00
if ( indio_dev - > channels [ j ] . num_event_specs ! = 0 )
return true ;
}
2012-01-03 14:59:38 +01:00
return false ;
}
static void iio_setup_ev_int ( struct iio_event_interface * ev_int )
{
2012-01-03 14:59:39 +01:00
INIT_KFIFO ( ev_int - > det_events ) ;
2012-01-03 14:59:38 +01:00
init_waitqueue_head ( & ev_int - > wait ) ;
}
static const char * iio_event_group_name = " events " ;
int iio_device_register_eventset ( struct iio_dev * indio_dev )
{
struct iio_dev_attr * p ;
int ret = 0 , attrcount_orig = 0 , attrcount , attrn ;
struct attribute * * attr ;
if ( ! ( indio_dev - > info - > event_attrs | |
iio_check_for_dynamic_events ( indio_dev ) ) )
return 0 ;
indio_dev - > event_interface =
kzalloc ( sizeof ( struct iio_event_interface ) , GFP_KERNEL ) ;
if ( indio_dev - > event_interface = = NULL ) {
ret = - ENOMEM ;
goto error_ret ;
}
2012-07-03 10:55:40 +02:00
INIT_LIST_HEAD ( & indio_dev - > event_interface - > dev_attr_list ) ;
2012-01-03 14:59:38 +01:00
iio_setup_ev_int ( indio_dev - > event_interface ) ;
if ( indio_dev - > info - > event_attrs ! = NULL ) {
attr = indio_dev - > info - > event_attrs - > attrs ;
while ( * attr + + ! = NULL )
attrcount_orig + + ;
}
attrcount = attrcount_orig ;
if ( indio_dev - > channels ) {
ret = __iio_add_event_config_attrs ( indio_dev ) ;
if ( ret < 0 )
goto error_free_setup_event_lines ;
attrcount + = ret ;
}
indio_dev - > event_interface - > group . name = iio_event_group_name ;
indio_dev - > event_interface - > group . attrs = kcalloc ( attrcount + 1 ,
sizeof ( indio_dev - > event_interface - > group . attrs [ 0 ] ) ,
GFP_KERNEL ) ;
if ( indio_dev - > event_interface - > group . attrs = = NULL ) {
ret = - ENOMEM ;
goto error_free_setup_event_lines ;
}
if ( indio_dev - > info - > event_attrs )
memcpy ( indio_dev - > event_interface - > group . attrs ,
indio_dev - > info - > event_attrs - > attrs ,
sizeof ( indio_dev - > event_interface - > group . attrs [ 0 ] )
* attrcount_orig ) ;
attrn = attrcount_orig ;
/* Add all elements from the list. */
list_for_each_entry ( p ,
& indio_dev - > event_interface - > dev_attr_list ,
l )
indio_dev - > event_interface - > group . attrs [ attrn + + ] =
& p - > dev_attr . attr ;
indio_dev - > groups [ indio_dev - > groupcounter + + ] =
& indio_dev - > event_interface - > group ;
return 0 ;
error_free_setup_event_lines :
2013-10-07 12:50:00 +01:00
iio_free_chan_devattr_list ( & indio_dev - > event_interface - > dev_attr_list ) ;
2012-01-03 14:59:38 +01:00
kfree ( indio_dev - > event_interface ) ;
error_ret :
return ret ;
}
2013-10-04 12:07:00 +01:00
/**
* iio_device_wakeup_eventset - Wakes up the event waitqueue
* @ indio_dev : The IIO device
*
* Wakes up the event waitqueue used for poll ( ) and blocking read ( ) .
* Should usually be called when the device is unregistered .
*/
void iio_device_wakeup_eventset ( struct iio_dev * indio_dev )
{
if ( indio_dev - > event_interface = = NULL )
return ;
wake_up ( & indio_dev - > event_interface - > wait ) ;
}
2012-01-03 14:59:38 +01:00
void iio_device_unregister_eventset ( struct iio_dev * indio_dev )
{
if ( indio_dev - > event_interface = = NULL )
return ;
2013-10-07 12:50:00 +01:00
iio_free_chan_devattr_list ( & indio_dev - > event_interface - > dev_attr_list ) ;
2012-01-03 14:59:38 +01:00
kfree ( indio_dev - > event_interface - > group . attrs ) ;
kfree ( indio_dev - > event_interface ) ;
}