blob: b853ef136004b2710de033dee919603353d901ee [file] [log] [blame]
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright 2020 Google LLC.
*/
#include <linux/idr.h>
#include <linux/module.h>
#include <linux/slab.h>
#include "icr-core.h"
static struct class *icr_class;
static DEFINE_IDA(icr_instance_ida);
static ssize_t open_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct icr_data *data = dev_get_drvdata(dev);
return data->ops->open_show(dev->parent, attr, buf);
}
static ssize_t open_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct icr_data *data = dev_get_drvdata(dev);
return data->ops->open_store(dev->parent, attr, buf, count);
}
static DEVICE_ATTR_RW(open);
static struct attribute *icr_attrs[] = {
&dev_attr_open.attr,
NULL
};
ATTRIBUTE_GROUPS(icr);
struct device *icr_core_register(struct device *dev, const struct icr_ops *ops)
{
struct device *new_dev;
struct icr_data *icr_data;
int ret;
icr_data = kmalloc(sizeof(*icr_data), GFP_KERNEL);
if (!icr_data) {
ret = -ENOMEM;
goto out;
}
icr_data->id = ida_simple_get(&icr_instance_ida, 0, 0, GFP_KERNEL);
if (icr_data->id < 0) {
pr_err("Failed to allocate id\n");
ret = icr_data->id;
goto out_free_icr_data;
}
icr_data->ops = ops;
new_dev = device_create_with_groups(icr_class, dev, 0, icr_data, icr_groups, "icr%d",
icr_data->id);
if (IS_ERR(new_dev)) {
ret = PTR_ERR(new_dev);
goto out_free_id;
}
return new_dev;
out_free_id:
ida_simple_remove(&icr_instance_ida, icr_data->id);
out_free_icr_data:
kfree(icr_data);
out:
return ERR_PTR(ret);
}
EXPORT_SYMBOL_GPL(icr_core_register);
void icr_core_unregister(struct device *icr_dev)
{
struct icr_data *data = dev_get_drvdata(icr_dev);
ida_simple_remove(&icr_instance_ida, data->id);
device_unregister(icr_dev);
kfree(data);
}
EXPORT_SYMBOL_GPL(icr_core_unregister);
int __init icr_core_init(void)
{
icr_class = class_create(THIS_MODULE, "icr");
if (IS_ERR(icr_class)) {
pr_err("Failed to create icr class\n");
return PTR_ERR(icr_class);
}
return 0;
}
void __exit icr_core_exit(void)
{
class_destroy(icr_class);
icr_class = NULL;
}
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("ICR core module");
module_init(icr_core_init);
module_exit(icr_core_exit);