Jonathan writes:
1st set of IIO fixes for the 5.19 cycle.
Most of these have been in next for a long time. Unfortunately there
was one stray patch in the branch (wasn't a fix), so I've just rebased
to remove that.
* testing
- Fix a missing MODULE_LICENSE() warning by restricting possible build
configs.
* Various drivers
- Fix ordering of iio_get_trigger() being called before
iio_trigger_register()
* adi,admv1014
- Fix dubious x & !y warning.
* adi,axi-adc
- Fix missing of_node_put() in error and normal paths.
* aspeed,adc
- Add missing of_node_put()
* fsl,mma8452
- Fix broken probing from device tree.
- Drop check on return value of i2c write to device to cause reset as
ACK will be missing (device reset before sending it).
* fsl,vf610
- Fix documentation of in_conversion_mode ABI.
* iio-trig-sysfs
- Ensure irq work has finished before freeing the trigger.
* invensense,mpu3050
- Disable regulators in error path.
* invensense,icm42600
- Fix collision of enum value of 0 with error path where 0 is no match.
* renesas,rzg2l_Adc
- Add missing fwnode_handle_put() in error path.
* rescale
- Fix a boolean logic bug for detection of raw + scale affecting an
obscure corner case.
* semtech,sx9324
- Check return value of read of pin_defs
* st,stm32-adc:
- Fix interaction across ADC instances for some supported devices.
- Drop false spurious IRQ messages.
- Fix calibration value handling. If we can't calibrate don't expose the
vref_int channel.
- Fix maximum clock rate for stm32pm15x
* ti,ads131e08
- Add missing fwnode_handle_put() in error paths.
* xilinx,ams
- Fix variable checked for error from platform_get_irq()
* x-powers,axp288
- Overide TS_PIN bias current for boards where it is not correctly
initialized.
* yamaha,yas530
- Fix inverted check on calibration data being all zeros.
* tag 'iio-fixes-for-5.19a' of https://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio: (26 commits)
iio:proximity:sx9324: Check ret value of device_property_read_u32_array()
iio: accel: mma8452: ignore the return value of reset operation
iio: adc: stm32: fix maximum clock rate for stm32mp15x
iio: adc: stm32: fix vrefint wrong calibration value handling
iio: imu: inv_icm42600: Fix broken icm42600 (chip id 0 value)
iio: adc: vf610: fix conversion mode sysfs node name
iio: adc: adi-axi-adc: Fix refcount leak in adi_axi_adc_attach_client
iio: test: fix missing MODULE_LICENSE for IIO_RESCALE=m
iio:humidity:hts221: rearrange iio trigger get and register
iio:chemical:ccs811: rearrange iio trigger get and register
iio:accel:mxc4005: rearrange iio trigger get and register
iio:accel:kxcjk-1013: rearrange iio trigger get and register
iio:accel:bma180: rearrange iio trigger get and register
iio: afe: rescale: Fix boolean logic bug
iio: adc: aspeed: Fix refcount leak in aspeed_adc_set_trim_data
iio: adc: stm32: Fix IRQs on STM32F4 by removing custom spurious IRQs message
iio: adc: stm32: Fix ADCs iteration in irq handler
iio: adc: ti-ads131e08: add missing fwnode_handle_put() in ads131e08_alloc_channels()
iio: adc: rzg2l_adc: add missing fwnode_handle_put() in rzg2l_adc_parse_properties()
iio: trigger: sysfs: fix use-after-free on remove
...
222 lines
4.7 KiB
C
222 lines
4.7 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
/*
|
|
* Copyright 2011 Analog Devices Inc.
|
|
*/
|
|
|
|
#include <linux/kernel.h>
|
|
#include <linux/module.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/list.h>
|
|
#include <linux/irq_work.h>
|
|
|
|
#include <linux/iio/iio.h>
|
|
#include <linux/iio/trigger.h>
|
|
|
|
struct iio_sysfs_trig {
|
|
struct iio_trigger *trig;
|
|
struct irq_work work;
|
|
int id;
|
|
struct list_head l;
|
|
};
|
|
|
|
static LIST_HEAD(iio_sysfs_trig_list);
|
|
static DEFINE_MUTEX(iio_sysfs_trig_list_mut);
|
|
|
|
static int iio_sysfs_trigger_probe(int id);
|
|
static ssize_t iio_sysfs_trig_add(struct device *dev,
|
|
struct device_attribute *attr,
|
|
const char *buf,
|
|
size_t len)
|
|
{
|
|
int ret;
|
|
unsigned long input;
|
|
|
|
ret = kstrtoul(buf, 10, &input);
|
|
if (ret)
|
|
return ret;
|
|
ret = iio_sysfs_trigger_probe(input);
|
|
if (ret)
|
|
return ret;
|
|
return len;
|
|
}
|
|
static DEVICE_ATTR(add_trigger, S_IWUSR, NULL, &iio_sysfs_trig_add);
|
|
|
|
static int iio_sysfs_trigger_remove(int id);
|
|
static ssize_t iio_sysfs_trig_remove(struct device *dev,
|
|
struct device_attribute *attr,
|
|
const char *buf,
|
|
size_t len)
|
|
{
|
|
int ret;
|
|
unsigned long input;
|
|
|
|
ret = kstrtoul(buf, 10, &input);
|
|
if (ret)
|
|
return ret;
|
|
ret = iio_sysfs_trigger_remove(input);
|
|
if (ret)
|
|
return ret;
|
|
return len;
|
|
}
|
|
|
|
static DEVICE_ATTR(remove_trigger, S_IWUSR, NULL, &iio_sysfs_trig_remove);
|
|
|
|
static struct attribute *iio_sysfs_trig_attrs[] = {
|
|
&dev_attr_add_trigger.attr,
|
|
&dev_attr_remove_trigger.attr,
|
|
NULL,
|
|
};
|
|
|
|
static const struct attribute_group iio_sysfs_trig_group = {
|
|
.attrs = iio_sysfs_trig_attrs,
|
|
};
|
|
|
|
static const struct attribute_group *iio_sysfs_trig_groups[] = {
|
|
&iio_sysfs_trig_group,
|
|
NULL
|
|
};
|
|
|
|
|
|
/* Nothing to actually do upon release */
|
|
static void iio_trigger_sysfs_release(struct device *dev)
|
|
{
|
|
}
|
|
|
|
static struct device iio_sysfs_trig_dev = {
|
|
.bus = &iio_bus_type,
|
|
.groups = iio_sysfs_trig_groups,
|
|
.release = &iio_trigger_sysfs_release,
|
|
};
|
|
|
|
static void iio_sysfs_trigger_work(struct irq_work *work)
|
|
{
|
|
struct iio_sysfs_trig *trig = container_of(work, struct iio_sysfs_trig,
|
|
work);
|
|
|
|
iio_trigger_poll(trig->trig);
|
|
}
|
|
|
|
static ssize_t iio_sysfs_trigger_poll(struct device *dev,
|
|
struct device_attribute *attr, const char *buf, size_t count)
|
|
{
|
|
struct iio_trigger *trig = to_iio_trigger(dev);
|
|
struct iio_sysfs_trig *sysfs_trig = iio_trigger_get_drvdata(trig);
|
|
|
|
irq_work_queue(&sysfs_trig->work);
|
|
|
|
return count;
|
|
}
|
|
|
|
static DEVICE_ATTR(trigger_now, S_IWUSR, NULL, iio_sysfs_trigger_poll);
|
|
|
|
static struct attribute *iio_sysfs_trigger_attrs[] = {
|
|
&dev_attr_trigger_now.attr,
|
|
NULL,
|
|
};
|
|
|
|
static const struct attribute_group iio_sysfs_trigger_attr_group = {
|
|
.attrs = iio_sysfs_trigger_attrs,
|
|
};
|
|
|
|
static const struct attribute_group *iio_sysfs_trigger_attr_groups[] = {
|
|
&iio_sysfs_trigger_attr_group,
|
|
NULL
|
|
};
|
|
|
|
static int iio_sysfs_trigger_probe(int id)
|
|
{
|
|
struct iio_sysfs_trig *t;
|
|
int ret;
|
|
bool foundit = false;
|
|
|
|
mutex_lock(&iio_sysfs_trig_list_mut);
|
|
list_for_each_entry(t, &iio_sysfs_trig_list, l)
|
|
if (id == t->id) {
|
|
foundit = true;
|
|
break;
|
|
}
|
|
if (foundit) {
|
|
ret = -EINVAL;
|
|
goto out1;
|
|
}
|
|
t = kmalloc(sizeof(*t), GFP_KERNEL);
|
|
if (t == NULL) {
|
|
ret = -ENOMEM;
|
|
goto out1;
|
|
}
|
|
t->id = id;
|
|
t->trig = iio_trigger_alloc(&iio_sysfs_trig_dev, "sysfstrig%d", id);
|
|
if (!t->trig) {
|
|
ret = -ENOMEM;
|
|
goto free_t;
|
|
}
|
|
|
|
t->trig->dev.groups = iio_sysfs_trigger_attr_groups;
|
|
iio_trigger_set_drvdata(t->trig, t);
|
|
|
|
t->work = IRQ_WORK_INIT_HARD(iio_sysfs_trigger_work);
|
|
|
|
ret = iio_trigger_register(t->trig);
|
|
if (ret)
|
|
goto out2;
|
|
list_add(&t->l, &iio_sysfs_trig_list);
|
|
__module_get(THIS_MODULE);
|
|
mutex_unlock(&iio_sysfs_trig_list_mut);
|
|
return 0;
|
|
|
|
out2:
|
|
iio_trigger_free(t->trig);
|
|
free_t:
|
|
kfree(t);
|
|
out1:
|
|
mutex_unlock(&iio_sysfs_trig_list_mut);
|
|
return ret;
|
|
}
|
|
|
|
static int iio_sysfs_trigger_remove(int id)
|
|
{
|
|
struct iio_sysfs_trig *t = NULL, *iter;
|
|
|
|
mutex_lock(&iio_sysfs_trig_list_mut);
|
|
list_for_each_entry(iter, &iio_sysfs_trig_list, l)
|
|
if (id == iter->id) {
|
|
t = iter;
|
|
break;
|
|
}
|
|
if (!t) {
|
|
mutex_unlock(&iio_sysfs_trig_list_mut);
|
|
return -EINVAL;
|
|
}
|
|
|
|
iio_trigger_unregister(t->trig);
|
|
irq_work_sync(&t->work);
|
|
iio_trigger_free(t->trig);
|
|
|
|
list_del(&t->l);
|
|
kfree(t);
|
|
module_put(THIS_MODULE);
|
|
mutex_unlock(&iio_sysfs_trig_list_mut);
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int __init iio_sysfs_trig_init(void)
|
|
{
|
|
device_initialize(&iio_sysfs_trig_dev);
|
|
dev_set_name(&iio_sysfs_trig_dev, "iio_sysfs_trigger");
|
|
return device_add(&iio_sysfs_trig_dev);
|
|
}
|
|
module_init(iio_sysfs_trig_init);
|
|
|
|
static void __exit iio_sysfs_trig_exit(void)
|
|
{
|
|
device_unregister(&iio_sysfs_trig_dev);
|
|
}
|
|
module_exit(iio_sysfs_trig_exit);
|
|
|
|
MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
|
|
MODULE_DESCRIPTION("Sysfs based trigger for the iio subsystem");
|
|
MODULE_LICENSE("GPL v2");
|
|
MODULE_ALIAS("platform:iio-trig-sysfs");
|