File Index
Files and directories
Sign in
FILE

dev-sync-probe.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpio/dev-sync-probe.c C
 1// SPDX-License-Identifier: GPL-2.0-or-later
 2/*
 3 * Common code for drivers creating fake platform devices.
 4 *
 5 * Provides synchronous device creation: waits for probe completion and
 6 * returns the probe success or error status to the device creator.
 7 *
 8 * Copyright (C) 2021 Bartosz Golaszewski <brgl@bgdev.pl>
 9 * Copyright (C) 2025 Koichiro Den <koichiro.den@canonical.com>
10 */
11
12#include <linux/device.h>
13#include <linux/slab.h>
14
15#include "dev-sync-probe.h"
16
17static int dev_sync_probe_notifier_call(struct notifier_block *nb,
18					unsigned long action, void *data)
19{
20	struct dev_sync_probe_data *pdata;
21	struct device *dev = data;
22
23	pdata = container_of(nb, struct dev_sync_probe_data, bus_notifier);
24	if (!device_match_name(dev, pdata->name))
25		return NOTIFY_DONE;
26
27	switch (action) {
28	case BUS_NOTIFY_BOUND_DRIVER:
29		pdata->driver_bound = true;
30		break;
31	case BUS_NOTIFY_DRIVER_NOT_BOUND:
32		pdata->driver_bound = false;
33		break;
34	default:
35		return NOTIFY_DONE;
36	}
37
38	complete(&pdata->probe_completion);
39	return NOTIFY_OK;
40}
41
42void dev_sync_probe_init(struct dev_sync_probe_data *data)
43{
44	memset(data, 0, sizeof(*data));
45	init_completion(&data->probe_completion);
46	data->bus_notifier.notifier_call = dev_sync_probe_notifier_call;
47}
48EXPORT_SYMBOL_GPL(dev_sync_probe_init);
49
50int dev_sync_probe_register(struct dev_sync_probe_data *data,
51			    struct platform_device_info *pdevinfo)
52{
53	struct platform_device *pdev;
54	char *name;
55
56	name = kasprintf(GFP_KERNEL, "%s.%d", pdevinfo->name, pdevinfo->id);
57	if (!name)
58		return -ENOMEM;
59
60	data->driver_bound = false;
61	data->name = name;
62	reinit_completion(&data->probe_completion);
63	bus_register_notifier(&platform_bus_type, &data->bus_notifier);
64
65	pdev = platform_device_register_full(pdevinfo);
66	if (IS_ERR(pdev)) {
67		bus_unregister_notifier(&platform_bus_type, &data->bus_notifier);
68		kfree(data->name);
69		return PTR_ERR(pdev);
70	}
71
72	wait_for_completion(&data->probe_completion);
73	bus_unregister_notifier(&platform_bus_type, &data->bus_notifier);
74
75	if (!data->driver_bound) {
76		platform_device_unregister(pdev);
77		kfree(data->name);
78		return -ENXIO;
79	}
80
81	data->pdev = pdev;
82	return 0;
83}
84EXPORT_SYMBOL_GPL(dev_sync_probe_register);
85
86void dev_sync_probe_unregister(struct dev_sync_probe_data *data)
87{
88	platform_device_unregister(data->pdev);
89	kfree(data->name);
90	data->pdev = NULL;
91}
92EXPORT_SYMBOL_GPL(dev_sync_probe_unregister);
93
94MODULE_AUTHOR("Bartosz Golaszewski <brgl@bgdev.pl>");
95MODULE_AUTHOR("Koichiro Den <koichiro.den@canonical.com>");
96MODULE_DESCRIPTION("Utilities for synchronous fake device creation");
97MODULE_LICENSE("GPL");
~/ Read-only file preview.