linux/drivers/iio/industrialio-sw-device.c
<<
>>
Prefs
   1/*
   2 * The Industrial I/O core, software IIO devices functions
   3 *
   4 * Copyright (c) 2016 Intel Corporation
   5 *
   6 * This program is free software; you can redistribute it and/or modify it
   7 * under the terms of the GNU General Public License version 2 as published by
   8 * the Free Software Foundation.
   9 */
  10
  11#include <linux/module.h>
  12#include <linux/init.h>
  13#include <linux/kmod.h>
  14#include <linux/list.h>
  15#include <linux/slab.h>
  16
  17#include <linux/iio/sw_device.h>
  18#include <linux/iio/configfs.h>
  19#include <linux/configfs.h>
  20
  21static struct config_group *iio_devices_group;
  22static const struct config_item_type iio_device_type_group_type;
  23
  24static const struct config_item_type iio_devices_group_type = {
  25        .ct_owner = THIS_MODULE,
  26};
  27
  28static LIST_HEAD(iio_device_types_list);
  29static DEFINE_MUTEX(iio_device_types_lock);
  30
  31static
  32struct iio_sw_device_type *__iio_find_sw_device_type(const char *name,
  33                                                     unsigned len)
  34{
  35        struct iio_sw_device_type *d = NULL, *iter;
  36
  37        list_for_each_entry(iter, &iio_device_types_list, list)
  38                if (!strcmp(iter->name, name)) {
  39                        d = iter;
  40                        break;
  41                }
  42
  43        return d;
  44}
  45
  46int iio_register_sw_device_type(struct iio_sw_device_type *d)
  47{
  48        struct iio_sw_device_type *iter;
  49        int ret = 0;
  50
  51        mutex_lock(&iio_device_types_lock);
  52        iter = __iio_find_sw_device_type(d->name, strlen(d->name));
  53        if (iter)
  54                ret = -EBUSY;
  55        else
  56                list_add_tail(&d->list, &iio_device_types_list);
  57        mutex_unlock(&iio_device_types_lock);
  58
  59        if (ret)
  60                return ret;
  61
  62        d->group = configfs_register_default_group(iio_devices_group, d->name,
  63                                                &iio_device_type_group_type);
  64        if (IS_ERR(d->group))
  65                ret = PTR_ERR(d->group);
  66
  67        return ret;
  68}
  69EXPORT_SYMBOL(iio_register_sw_device_type);
  70
  71void iio_unregister_sw_device_type(struct iio_sw_device_type *dt)
  72{
  73        struct iio_sw_device_type *iter;
  74
  75        mutex_lock(&iio_device_types_lock);
  76        iter = __iio_find_sw_device_type(dt->name, strlen(dt->name));
  77        if (iter)
  78                list_del(&dt->list);
  79        mutex_unlock(&iio_device_types_lock);
  80
  81        configfs_unregister_default_group(dt->group);
  82}
  83EXPORT_SYMBOL(iio_unregister_sw_device_type);
  84
  85static
  86struct iio_sw_device_type *iio_get_sw_device_type(const char *name)
  87{
  88        struct iio_sw_device_type *dt;
  89
  90        mutex_lock(&iio_device_types_lock);
  91        dt = __iio_find_sw_device_type(name, strlen(name));
  92        if (dt && !try_module_get(dt->owner))
  93                dt = NULL;
  94        mutex_unlock(&iio_device_types_lock);
  95
  96        return dt;
  97}
  98
  99struct iio_sw_device *iio_sw_device_create(const char *type, const char *name)
 100{
 101        struct iio_sw_device *d;
 102        struct iio_sw_device_type *dt;
 103
 104        dt = iio_get_sw_device_type(type);
 105        if (!dt) {
 106                pr_err("Invalid device type: %s\n", type);
 107                return ERR_PTR(-EINVAL);
 108        }
 109        d = dt->ops->probe(name);
 110        if (IS_ERR(d))
 111                goto out_module_put;
 112
 113        d->device_type = dt;
 114
 115        return d;
 116out_module_put:
 117        module_put(dt->owner);
 118        return d;
 119}
 120EXPORT_SYMBOL(iio_sw_device_create);
 121
 122void iio_sw_device_destroy(struct iio_sw_device *d)
 123{
 124        struct iio_sw_device_type *dt = d->device_type;
 125
 126        dt->ops->remove(d);
 127        module_put(dt->owner);
 128}
 129EXPORT_SYMBOL(iio_sw_device_destroy);
 130
 131static struct config_group *device_make_group(struct config_group *group,
 132                                              const char *name)
 133{
 134        struct iio_sw_device *d;
 135
 136        d = iio_sw_device_create(group->cg_item.ci_name, name);
 137        if (IS_ERR(d))
 138                return ERR_CAST(d);
 139
 140        config_item_set_name(&d->group.cg_item, "%s", name);
 141
 142        return &d->group;
 143}
 144
 145static void device_drop_group(struct config_group *group,
 146                              struct config_item *item)
 147{
 148        struct iio_sw_device *d = to_iio_sw_device(item);
 149
 150        iio_sw_device_destroy(d);
 151        config_item_put(item);
 152}
 153
 154static struct configfs_group_operations device_ops = {
 155        .make_group     = &device_make_group,
 156        .drop_item      = &device_drop_group,
 157};
 158
 159static const struct config_item_type iio_device_type_group_type = {
 160        .ct_group_ops = &device_ops,
 161        .ct_owner       = THIS_MODULE,
 162};
 163
 164static int __init iio_sw_device_init(void)
 165{
 166        iio_devices_group =
 167                configfs_register_default_group(&iio_configfs_subsys.su_group,
 168                                                "devices",
 169                                                &iio_devices_group_type);
 170        return PTR_ERR_OR_ZERO(iio_devices_group);
 171}
 172module_init(iio_sw_device_init);
 173
 174static void __exit iio_sw_device_exit(void)
 175{
 176        configfs_unregister_default_group(iio_devices_group);
 177}
 178module_exit(iio_sw_device_exit);
 179
 180MODULE_AUTHOR("Daniel Baluta <daniel.baluta@intel.com>");
 181MODULE_DESCRIPTION("Industrial I/O software devices support");
 182MODULE_LICENSE("GPL v2");
 183