cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

iio-trig-sysfs.c (4820B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright 2011 Analog Devices Inc.
      4 */
      5
      6#include <linux/kernel.h>
      7#include <linux/module.h>
      8#include <linux/platform_device.h>
      9#include <linux/slab.h>
     10#include <linux/list.h>
     11#include <linux/irq_work.h>
     12
     13#include <linux/iio/iio.h>
     14#include <linux/iio/trigger.h>
     15
     16struct iio_sysfs_trig {
     17	struct iio_trigger *trig;
     18	struct irq_work work;
     19	int id;
     20	struct list_head l;
     21};
     22
     23static LIST_HEAD(iio_sysfs_trig_list);
     24static DEFINE_MUTEX(iio_sysfs_trig_list_mut);
     25
     26static int iio_sysfs_trigger_probe(int id);
     27static ssize_t iio_sysfs_trig_add(struct device *dev,
     28				  struct device_attribute *attr,
     29				  const char *buf,
     30				  size_t len)
     31{
     32	int ret;
     33	unsigned long input;
     34
     35	ret = kstrtoul(buf, 10, &input);
     36	if (ret)
     37		return ret;
     38	ret = iio_sysfs_trigger_probe(input);
     39	if (ret)
     40		return ret;
     41	return len;
     42}
     43static DEVICE_ATTR(add_trigger, S_IWUSR, NULL, &iio_sysfs_trig_add);
     44
     45static int iio_sysfs_trigger_remove(int id);
     46static ssize_t iio_sysfs_trig_remove(struct device *dev,
     47				     struct device_attribute *attr,
     48				     const char *buf,
     49				     size_t len)
     50{
     51	int ret;
     52	unsigned long input;
     53
     54	ret = kstrtoul(buf, 10, &input);
     55	if (ret)
     56		return ret;
     57	ret = iio_sysfs_trigger_remove(input);
     58	if (ret)
     59		return ret;
     60	return len;
     61}
     62
     63static DEVICE_ATTR(remove_trigger, S_IWUSR, NULL, &iio_sysfs_trig_remove);
     64
     65static struct attribute *iio_sysfs_trig_attrs[] = {
     66	&dev_attr_add_trigger.attr,
     67	&dev_attr_remove_trigger.attr,
     68	NULL,
     69};
     70
     71static const struct attribute_group iio_sysfs_trig_group = {
     72	.attrs = iio_sysfs_trig_attrs,
     73};
     74
     75static const struct attribute_group *iio_sysfs_trig_groups[] = {
     76	&iio_sysfs_trig_group,
     77	NULL
     78};
     79
     80
     81/* Nothing to actually do upon release */
     82static void iio_trigger_sysfs_release(struct device *dev)
     83{
     84}
     85
     86static struct device iio_sysfs_trig_dev = {
     87	.bus = &iio_bus_type,
     88	.groups = iio_sysfs_trig_groups,
     89	.release = &iio_trigger_sysfs_release,
     90};
     91
     92static void iio_sysfs_trigger_work(struct irq_work *work)
     93{
     94	struct iio_sysfs_trig *trig = container_of(work, struct iio_sysfs_trig,
     95							work);
     96
     97	iio_trigger_poll(trig->trig);
     98}
     99
    100static ssize_t iio_sysfs_trigger_poll(struct device *dev,
    101		struct device_attribute *attr, const char *buf, size_t count)
    102{
    103	struct iio_trigger *trig = to_iio_trigger(dev);
    104	struct iio_sysfs_trig *sysfs_trig = iio_trigger_get_drvdata(trig);
    105
    106	irq_work_queue(&sysfs_trig->work);
    107
    108	return count;
    109}
    110
    111static DEVICE_ATTR(trigger_now, S_IWUSR, NULL, iio_sysfs_trigger_poll);
    112
    113static struct attribute *iio_sysfs_trigger_attrs[] = {
    114	&dev_attr_trigger_now.attr,
    115	NULL,
    116};
    117
    118static const struct attribute_group iio_sysfs_trigger_attr_group = {
    119	.attrs = iio_sysfs_trigger_attrs,
    120};
    121
    122static const struct attribute_group *iio_sysfs_trigger_attr_groups[] = {
    123	&iio_sysfs_trigger_attr_group,
    124	NULL
    125};
    126
    127static int iio_sysfs_trigger_probe(int id)
    128{
    129	struct iio_sysfs_trig *t;
    130	int ret;
    131	bool foundit = false;
    132
    133	mutex_lock(&iio_sysfs_trig_list_mut);
    134	list_for_each_entry(t, &iio_sysfs_trig_list, l)
    135		if (id == t->id) {
    136			foundit = true;
    137			break;
    138		}
    139	if (foundit) {
    140		ret = -EINVAL;
    141		goto out1;
    142	}
    143	t = kmalloc(sizeof(*t), GFP_KERNEL);
    144	if (t == NULL) {
    145		ret = -ENOMEM;
    146		goto out1;
    147	}
    148	t->id = id;
    149	t->trig = iio_trigger_alloc(&iio_sysfs_trig_dev, "sysfstrig%d", id);
    150	if (!t->trig) {
    151		ret = -ENOMEM;
    152		goto free_t;
    153	}
    154
    155	t->trig->dev.groups = iio_sysfs_trigger_attr_groups;
    156	iio_trigger_set_drvdata(t->trig, t);
    157
    158	t->work = IRQ_WORK_INIT_HARD(iio_sysfs_trigger_work);
    159
    160	ret = iio_trigger_register(t->trig);
    161	if (ret)
    162		goto out2;
    163	list_add(&t->l, &iio_sysfs_trig_list);
    164	__module_get(THIS_MODULE);
    165	mutex_unlock(&iio_sysfs_trig_list_mut);
    166	return 0;
    167
    168out2:
    169	iio_trigger_free(t->trig);
    170free_t:
    171	kfree(t);
    172out1:
    173	mutex_unlock(&iio_sysfs_trig_list_mut);
    174	return ret;
    175}
    176
    177static int iio_sysfs_trigger_remove(int id)
    178{
    179	struct iio_sysfs_trig *t = NULL, *iter;
    180
    181	mutex_lock(&iio_sysfs_trig_list_mut);
    182	list_for_each_entry(iter, &iio_sysfs_trig_list, l)
    183		if (id == iter->id) {
    184			t = iter;
    185			break;
    186		}
    187	if (!t) {
    188		mutex_unlock(&iio_sysfs_trig_list_mut);
    189		return -EINVAL;
    190	}
    191
    192	iio_trigger_unregister(t->trig);
    193	irq_work_sync(&t->work);
    194	iio_trigger_free(t->trig);
    195
    196	list_del(&t->l);
    197	kfree(t);
    198	module_put(THIS_MODULE);
    199	mutex_unlock(&iio_sysfs_trig_list_mut);
    200	return 0;
    201}
    202
    203
    204static int __init iio_sysfs_trig_init(void)
    205{
    206	device_initialize(&iio_sysfs_trig_dev);
    207	dev_set_name(&iio_sysfs_trig_dev, "iio_sysfs_trigger");
    208	return device_add(&iio_sysfs_trig_dev);
    209}
    210module_init(iio_sysfs_trig_init);
    211
    212static void __exit iio_sysfs_trig_exit(void)
    213{
    214	device_unregister(&iio_sysfs_trig_dev);
    215}
    216module_exit(iio_sysfs_trig_exit);
    217
    218MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
    219MODULE_DESCRIPTION("Sysfs based trigger for the iio subsystem");
    220MODULE_LICENSE("GPL v2");
    221MODULE_ALIAS("platform:iio-trig-sysfs");