summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTzung-Bi Shih <tzungbi@kernel.org>2026-05-25 08:26:51 +0300
committerTzung-Bi Shih <tzungbi@kernel.org>2026-05-28 05:17:30 +0300
commit5ad1406881102bc3e94fd25311d1728dfaf435a2 (patch)
tree5caff6c8f3d4c6f0b86922104a65ae73463fa0a3
parentace8ee71e8ef4d6ef5a6501469df95237e1f7406 (diff)
downloadlinux-5ad1406881102bc3e94fd25311d1728dfaf435a2.tar.xz
platform/chrome: cros_ec_chardev: Introduce chardev_data
Introduce struct chardev_pdata to hold platform driver data. The platform driver data is allocated by kzalloc() instead of devm variant, allowing for managed cleanup that can eventually extend beyond device removal if files are still open. Reviewed-by: Jason Gunthorpe <jgg@nvidia.com> Link: https://lore.kernel.org/r/20260525052654.4076429-2-tzungbi@kernel.org Signed-off-by: Tzung-Bi Shih <tzungbi@kernel.org>
-rw-r--r--drivers/platform/chrome/cros_ec_chardev.c51
1 files changed, 39 insertions, 12 deletions
diff --git a/drivers/platform/chrome/cros_ec_chardev.c b/drivers/platform/chrome/cros_ec_chardev.c
index 002be3352100..e7012e44a006 100644
--- a/drivers/platform/chrome/cros_ec_chardev.c
+++ b/drivers/platform/chrome/cros_ec_chardev.c
@@ -13,6 +13,7 @@
#include <linux/init.h>
#include <linux/device.h>
#include <linux/fs.h>
+#include <linux/kref.h>
#include <linux/miscdevice.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
@@ -31,6 +32,21 @@
/* Arbitrary bounded size for the event queue */
#define CROS_MAX_EVENT_LEN PAGE_SIZE
+/*
+ * Platform device driver data.
+ */
+struct chardev_pdata {
+ struct miscdevice misc;
+ struct kref kref;
+};
+
+static void chardev_pdata_release(struct kref *kref)
+{
+ struct chardev_pdata *pdata = container_of(kref, typeof(*pdata), kref);
+
+ kfree(pdata);
+}
+
struct chardev_priv {
struct cros_ec_device *ec_dev;
struct notifier_block notifier;
@@ -374,28 +390,39 @@ static int cros_ec_chardev_probe(struct platform_device *pdev)
{
struct cros_ec_dev *ec = dev_get_drvdata(pdev->dev.parent);
struct cros_ec_platform *ec_platform = dev_get_platdata(ec->dev);
- struct miscdevice *misc;
+ struct chardev_pdata *pdata;
+ int ret;
- /* Create a char device: we want to create it anew */
- misc = devm_kzalloc(&pdev->dev, sizeof(*misc), GFP_KERNEL);
- if (!misc)
+ pdata = kzalloc_obj(*pdata);
+ if (!pdata)
return -ENOMEM;
- misc->minor = MISC_DYNAMIC_MINOR;
- misc->fops = &chardev_fops;
- misc->name = ec_platform->ec_name;
- misc->parent = pdev->dev.parent;
+ platform_set_drvdata(pdev, pdata);
+ kref_init(&pdata->kref);
- dev_set_drvdata(&pdev->dev, misc);
+ pdata->misc.minor = MISC_DYNAMIC_MINOR;
+ pdata->misc.fops = &chardev_fops;
+ pdata->misc.name = ec_platform->ec_name;
+ pdata->misc.parent = pdev->dev.parent;
- return misc_register(misc);
+ ret = misc_register(&pdata->misc);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to register misc device\n");
+ goto err_put_pdata;
+ }
+
+ return 0;
+err_put_pdata:
+ kref_put(&pdata->kref, chardev_pdata_release);
+ return ret;
}
static void cros_ec_chardev_remove(struct platform_device *pdev)
{
- struct miscdevice *misc = dev_get_drvdata(&pdev->dev);
+ struct chardev_pdata *pdata = platform_get_drvdata(pdev);
- misc_deregister(misc);
+ misc_deregister(&pdata->misc);
+ kref_put(&pdata->kref, chardev_pdata_release);
}
static const struct platform_device_id cros_ec_chardev_id[] = {