18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * The Industrial I/O core, software IIO devices functions 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2016 Intel Corporation 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/module.h> 98c2ecf20Sopenharmony_ci#include <linux/init.h> 108c2ecf20Sopenharmony_ci#include <linux/kmod.h> 118c2ecf20Sopenharmony_ci#include <linux/list.h> 128c2ecf20Sopenharmony_ci#include <linux/slab.h> 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include <linux/iio/sw_device.h> 158c2ecf20Sopenharmony_ci#include <linux/iio/configfs.h> 168c2ecf20Sopenharmony_ci#include <linux/configfs.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_cistatic struct config_group *iio_devices_group; 198c2ecf20Sopenharmony_cistatic const struct config_item_type iio_device_type_group_type; 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_cistatic const struct config_item_type iio_devices_group_type = { 228c2ecf20Sopenharmony_ci .ct_owner = THIS_MODULE, 238c2ecf20Sopenharmony_ci}; 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_cistatic LIST_HEAD(iio_device_types_list); 268c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(iio_device_types_lock); 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_cistatic 298c2ecf20Sopenharmony_cistruct iio_sw_device_type *__iio_find_sw_device_type(const char *name, 308c2ecf20Sopenharmony_ci unsigned len) 318c2ecf20Sopenharmony_ci{ 328c2ecf20Sopenharmony_ci struct iio_sw_device_type *d = NULL, *iter; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci list_for_each_entry(iter, &iio_device_types_list, list) 358c2ecf20Sopenharmony_ci if (!strcmp(iter->name, name)) { 368c2ecf20Sopenharmony_ci d = iter; 378c2ecf20Sopenharmony_ci break; 388c2ecf20Sopenharmony_ci } 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci return d; 418c2ecf20Sopenharmony_ci} 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ciint iio_register_sw_device_type(struct iio_sw_device_type *d) 448c2ecf20Sopenharmony_ci{ 458c2ecf20Sopenharmony_ci struct iio_sw_device_type *iter; 468c2ecf20Sopenharmony_ci int ret = 0; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci mutex_lock(&iio_device_types_lock); 498c2ecf20Sopenharmony_ci iter = __iio_find_sw_device_type(d->name, strlen(d->name)); 508c2ecf20Sopenharmony_ci if (iter) 518c2ecf20Sopenharmony_ci ret = -EBUSY; 528c2ecf20Sopenharmony_ci else 538c2ecf20Sopenharmony_ci list_add_tail(&d->list, &iio_device_types_list); 548c2ecf20Sopenharmony_ci mutex_unlock(&iio_device_types_lock); 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci if (ret) 578c2ecf20Sopenharmony_ci return ret; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci d->group = configfs_register_default_group(iio_devices_group, d->name, 608c2ecf20Sopenharmony_ci &iio_device_type_group_type); 618c2ecf20Sopenharmony_ci if (IS_ERR(d->group)) 628c2ecf20Sopenharmony_ci ret = PTR_ERR(d->group); 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci return ret; 658c2ecf20Sopenharmony_ci} 668c2ecf20Sopenharmony_ciEXPORT_SYMBOL(iio_register_sw_device_type); 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_civoid iio_unregister_sw_device_type(struct iio_sw_device_type *dt) 698c2ecf20Sopenharmony_ci{ 708c2ecf20Sopenharmony_ci struct iio_sw_device_type *iter; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci mutex_lock(&iio_device_types_lock); 738c2ecf20Sopenharmony_ci iter = __iio_find_sw_device_type(dt->name, strlen(dt->name)); 748c2ecf20Sopenharmony_ci if (iter) 758c2ecf20Sopenharmony_ci list_del(&dt->list); 768c2ecf20Sopenharmony_ci mutex_unlock(&iio_device_types_lock); 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci configfs_unregister_default_group(dt->group); 798c2ecf20Sopenharmony_ci} 808c2ecf20Sopenharmony_ciEXPORT_SYMBOL(iio_unregister_sw_device_type); 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_cistatic 838c2ecf20Sopenharmony_cistruct iio_sw_device_type *iio_get_sw_device_type(const char *name) 848c2ecf20Sopenharmony_ci{ 858c2ecf20Sopenharmony_ci struct iio_sw_device_type *dt; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci mutex_lock(&iio_device_types_lock); 888c2ecf20Sopenharmony_ci dt = __iio_find_sw_device_type(name, strlen(name)); 898c2ecf20Sopenharmony_ci if (dt && !try_module_get(dt->owner)) 908c2ecf20Sopenharmony_ci dt = NULL; 918c2ecf20Sopenharmony_ci mutex_unlock(&iio_device_types_lock); 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci return dt; 948c2ecf20Sopenharmony_ci} 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_cistruct iio_sw_device *iio_sw_device_create(const char *type, const char *name) 978c2ecf20Sopenharmony_ci{ 988c2ecf20Sopenharmony_ci struct iio_sw_device *d; 998c2ecf20Sopenharmony_ci struct iio_sw_device_type *dt; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci dt = iio_get_sw_device_type(type); 1028c2ecf20Sopenharmony_ci if (!dt) { 1038c2ecf20Sopenharmony_ci pr_err("Invalid device type: %s\n", type); 1048c2ecf20Sopenharmony_ci return ERR_PTR(-EINVAL); 1058c2ecf20Sopenharmony_ci } 1068c2ecf20Sopenharmony_ci d = dt->ops->probe(name); 1078c2ecf20Sopenharmony_ci if (IS_ERR(d)) 1088c2ecf20Sopenharmony_ci goto out_module_put; 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci d->device_type = dt; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci return d; 1138c2ecf20Sopenharmony_ciout_module_put: 1148c2ecf20Sopenharmony_ci module_put(dt->owner); 1158c2ecf20Sopenharmony_ci return d; 1168c2ecf20Sopenharmony_ci} 1178c2ecf20Sopenharmony_ciEXPORT_SYMBOL(iio_sw_device_create); 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_civoid iio_sw_device_destroy(struct iio_sw_device *d) 1208c2ecf20Sopenharmony_ci{ 1218c2ecf20Sopenharmony_ci struct iio_sw_device_type *dt = d->device_type; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci dt->ops->remove(d); 1248c2ecf20Sopenharmony_ci module_put(dt->owner); 1258c2ecf20Sopenharmony_ci} 1268c2ecf20Sopenharmony_ciEXPORT_SYMBOL(iio_sw_device_destroy); 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_cistatic struct config_group *device_make_group(struct config_group *group, 1298c2ecf20Sopenharmony_ci const char *name) 1308c2ecf20Sopenharmony_ci{ 1318c2ecf20Sopenharmony_ci struct iio_sw_device *d; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci d = iio_sw_device_create(group->cg_item.ci_name, name); 1348c2ecf20Sopenharmony_ci if (IS_ERR(d)) 1358c2ecf20Sopenharmony_ci return ERR_CAST(d); 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci config_item_set_name(&d->group.cg_item, "%s", name); 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci return &d->group; 1408c2ecf20Sopenharmony_ci} 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_cistatic void device_drop_group(struct config_group *group, 1438c2ecf20Sopenharmony_ci struct config_item *item) 1448c2ecf20Sopenharmony_ci{ 1458c2ecf20Sopenharmony_ci struct iio_sw_device *d = to_iio_sw_device(item); 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci iio_sw_device_destroy(d); 1488c2ecf20Sopenharmony_ci config_item_put(item); 1498c2ecf20Sopenharmony_ci} 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_cistatic struct configfs_group_operations device_ops = { 1528c2ecf20Sopenharmony_ci .make_group = &device_make_group, 1538c2ecf20Sopenharmony_ci .drop_item = &device_drop_group, 1548c2ecf20Sopenharmony_ci}; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_cistatic const struct config_item_type iio_device_type_group_type = { 1578c2ecf20Sopenharmony_ci .ct_group_ops = &device_ops, 1588c2ecf20Sopenharmony_ci .ct_owner = THIS_MODULE, 1598c2ecf20Sopenharmony_ci}; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_cistatic int __init iio_sw_device_init(void) 1628c2ecf20Sopenharmony_ci{ 1638c2ecf20Sopenharmony_ci iio_devices_group = 1648c2ecf20Sopenharmony_ci configfs_register_default_group(&iio_configfs_subsys.su_group, 1658c2ecf20Sopenharmony_ci "devices", 1668c2ecf20Sopenharmony_ci &iio_devices_group_type); 1678c2ecf20Sopenharmony_ci return PTR_ERR_OR_ZERO(iio_devices_group); 1688c2ecf20Sopenharmony_ci} 1698c2ecf20Sopenharmony_cimodule_init(iio_sw_device_init); 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_cistatic void __exit iio_sw_device_exit(void) 1728c2ecf20Sopenharmony_ci{ 1738c2ecf20Sopenharmony_ci configfs_unregister_default_group(iio_devices_group); 1748c2ecf20Sopenharmony_ci} 1758c2ecf20Sopenharmony_cimodule_exit(iio_sw_device_exit); 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ciMODULE_AUTHOR("Daniel Baluta <daniel.baluta@intel.com>"); 1788c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Industrial I/O software devices support"); 1798c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 180