drivers/platform/chrome/cros_ec_chardev.c
Source file repositories/reference/linux-study-clean/drivers/platform/chrome/cros_ec_chardev.c
File Facts
- System
- Linux kernel
- Corpus path
drivers/platform/chrome/cros_ec_chardev.c- Extension
.c- Size
- 12445 bytes
- Lines
- 507
- Domain
- Driver Families
- Bucket
- drivers/platform
- Inferred role
- Driver Families: operation-table or driver-model contract
- Status
- pattern implementation candidate
Why This File Exists
Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.
- Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.
- Defines an operation table; this is where Linux turns generic core objects into subsystem-specific behavior.
- Touches user memory; correctness depends on fault-safe copying and privilege boundary handling.
- Uses kernel synchronization; read lock ordering, sleepability, and interrupt context assumptions before translating.
- Allocates kernel memory; connect allocation flags and lifetime to context constraints.
- Defines or uses C structs; map object ownership, embedded links, reference counts, and lock ownership.
Dependency Surface
linux/init.hlinux/device.hlinux/fs.hlinux/kref.hlinux/miscdevice.hlinux/mod_devicetable.hlinux/module.hlinux/notifier.hlinux/platform_data/cros_ec_chardev.hlinux/platform_data/cros_ec_commands.hlinux/platform_data/cros_ec_proto.hlinux/platform_device.hlinux/poll.hlinux/rwsem.hlinux/slab.hlinux/types.hlinux/uaccess.h
Detected Declarations
struct chardev_pdatastruct chardev_privstruct ec_eventfunction chardev_pdata_releasefunction cros_ec_chardev_relay_eventfunction ec_get_versionfunction cros_ec_chardev_mkbp_eventfunction cros_ec_chardev_openfunction cros_ec_chardev_pollfunction cros_ec_chardev_readfunction cros_ec_chardev_releasefunction list_for_each_entry_safefunction cros_ec_chardev_ioctl_xcmdfunction cros_ec_chardev_ioctl_readmemfunction cros_ec_chardev_ioctlfunction cros_ec_chardev_probefunction cros_ec_chardev_remove
Annotated Snippet
static const struct file_operations chardev_fops = {
.open = cros_ec_chardev_open,
.poll = cros_ec_chardev_poll,
.read = cros_ec_chardev_read,
.release = cros_ec_chardev_release,
.unlocked_ioctl = cros_ec_chardev_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = cros_ec_chardev_ioctl,
#endif
};
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 chardev_pdata *pdata;
int ret;
pdata = kzalloc_obj(*pdata);
if (!pdata)
return -ENOMEM;
platform_set_drvdata(pdev, pdata);
kref_init(&pdata->kref);
init_rwsem(&pdata->ec_dev_sem);
pdata->ec_dev = ec->ec_dev;
pdata->cmd_offset = ec->cmd_offset;
BLOCKING_INIT_NOTIFIER_HEAD(&pdata->subscribers);
pdata->relay.notifier_call = cros_ec_chardev_relay_event;
ret = blocking_notifier_chain_register(&pdata->ec_dev->event_notifier,
&pdata->relay);
if (ret) {
dev_err(&pdev->dev, "failed to register event notifier\n");
goto err_put_pdata;
}
pdata->misc.minor = MISC_DYNAMIC_MINOR;
pdata->misc.fops = &chardev_fops;
pdata->misc.name = ec_platform->ec_name;
pdata->misc.parent = pdev->dev.parent;
ret = misc_register(&pdata->misc);
if (ret) {
dev_err(&pdev->dev, "failed to register misc device\n");
goto err_unregister_notifier;
}
return 0;
err_unregister_notifier:
blocking_notifier_chain_unregister(&pdata->ec_dev->event_notifier,
&pdata->relay);
err_put_pdata:
kref_put(&pdata->kref, chardev_pdata_release);
return ret;
}
static void cros_ec_chardev_remove(struct platform_device *pdev)
{
struct chardev_pdata *pdata = platform_get_drvdata(pdev);
struct cros_ec_device *ec_dev = pdata->ec_dev;
/* stop new fops from being created */
misc_deregister(&pdata->misc);
/* stop existing fops from running */
scoped_guard(rwsem_write, &pdata->ec_dev_sem)
pdata->ec_dev = NULL;
blocking_notifier_chain_unregister(&ec_dev->event_notifier,
&pdata->relay);
kref_put(&pdata->kref, chardev_pdata_release);
}
static const struct platform_device_id cros_ec_chardev_id[] = {
{ DRV_NAME, 0 },
{}
};
MODULE_DEVICE_TABLE(platform, cros_ec_chardev_id);
static struct platform_driver cros_ec_chardev_driver = {
.driver = {
.name = DRV_NAME,
},
.probe = cros_ec_chardev_probe,
.remove = cros_ec_chardev_remove,
.id_table = cros_ec_chardev_id,
};
module_platform_driver(cros_ec_chardev_driver);
MODULE_AUTHOR("Enric Balletbo i Serra <enric.balletbo@collabora.com>");
Annotation
- Immediate include surface: `linux/init.h`, `linux/device.h`, `linux/fs.h`, `linux/kref.h`, `linux/miscdevice.h`, `linux/mod_devicetable.h`, `linux/module.h`, `linux/notifier.h`.
- Detected declarations: `struct chardev_pdata`, `struct chardev_priv`, `struct ec_event`, `function chardev_pdata_release`, `function cros_ec_chardev_relay_event`, `function ec_get_version`, `function cros_ec_chardev_mkbp_event`, `function cros_ec_chardev_open`, `function cros_ec_chardev_poll`, `function cros_ec_chardev_read`.
- Atlas domain: Driver Families / drivers/platform.
- Implementation status: pattern implementation candidate.
- This snippet crosses the user/kernel memory boundary; validate fault handling and access checks before translating the pattern.
- Synchronization appears in or near this file; preserve lock ordering, sleepability, and interrupt-context constraints.
Implementation Notes
- This generated page is the file-by-file coverage layer; curated subsystem chapters should link here when they synthesize a multi-file control flow.
- Core OS pages should be promoted from atlas-only to deep-reviewed when they explain data structures, invariants, locking, lifecycle, and C implementation snippets.
- Driver-family pages are intentionally pattern-oriented unless they are part of the selected PCIe/NVMe representative device path.