Skip to content

Commit f875ad9

Browse files
author
andy_chi
committed
Enable a simple user-space driven DT overlay interface
Change-Id: I6e9f71d8b46df65abd698378b8994988c7fa5651
1 parent de5c3c4 commit f875ad9

3 files changed

Lines changed: 389 additions & 0 deletions

File tree

drivers/of/Kconfig

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,4 +112,11 @@ config OF_OVERLAY
112112
While this option is selected automatically when needed, you can
113113
enable it manually to improve device tree unit test coverage.
114114

115+
config OF_CONFIGFS
116+
bool "Device Tree Overlay ConfigFS interface"
117+
select CONFIGFS_FS
118+
select OF_OVERLAY
119+
help
120+
Enable a simple user-space driven DT overlay interface.
121+
115122
endif # OF

drivers/of/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
obj-y = base.o device.o platform.o
2+
obj-$(CONFIG_OF_CONFIGFS) += dtbocfg.o
23
obj-$(CONFIG_OF_DYNAMIC) += dynamic.o
34
obj-$(CONFIG_OF_FLATTREE) += fdt.o
45
obj-$(CONFIG_OF_EARLY_FLATTREE) += fdt_address.o

drivers/of/dtbocfg.c

Lines changed: 381 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,381 @@
1+
/*********************************************************************************
2+
*
3+
* Copyright (C) 2016-2017 Ichiro Kawazome
4+
* All rights reserved.
5+
*
6+
* Redistribution and use in source and binary forms, with or without
7+
* modification, are permitted provided that the following conditions
8+
* are met:
9+
*
10+
* 1. Redistributions of source code must retain the above copyright
11+
* notice, this list of conditions and the following disclaimer.
12+
*
13+
* 2. Redistributions in binary form must reproduce the above copyright
14+
* notice, this list of conditions and the following disclaimer in
15+
* the documentation and/or other materials provided with the
16+
* distribution.
17+
*
18+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19+
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20+
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21+
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22+
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23+
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24+
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25+
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26+
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27+
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29+
*
30+
********************************************************************************/
31+
#include <linux/slab.h>
32+
#include <linux/module.h>
33+
#include <linux/of.h>
34+
#include <linux/of_fdt.h>
35+
#include <linux/configfs.h>
36+
#include <linux/types.h>
37+
#include <linux/stat.h>
38+
#include <linux/limits.h>
39+
#include <linux/file.h>
40+
#include <linux/version.h>
41+
42+
/**
43+
* Device Tree Overlay Item Structure
44+
*/
45+
struct dtbocfg_overlay_item {
46+
struct config_item item;
47+
struct device_node* node;
48+
int id;
49+
void* dtbo;
50+
int dtbo_size;
51+
};
52+
53+
/**
54+
* dtbocfg_overlay_create() - Create Device Tree Overlay
55+
* @overlay: Pointer to Device Tree Overlay Item
56+
* return Success(0) or Error Status.
57+
*/
58+
static int dtbocfg_overlay_item_create(struct dtbocfg_overlay_item *overlay)
59+
{
60+
int ret_val;
61+
62+
#if (LINUX_VERSION_CODE >= 0x040700)
63+
of_fdt_unflatten_tree(overlay->dtbo, NULL, &overlay->node);
64+
#else
65+
of_fdt_unflatten_tree(overlay->dtbo, &overlay->node);
66+
#endif
67+
if (overlay->node == NULL) {
68+
pr_err("%s: failed to unflatten tree\n", __func__);
69+
ret_val = -EINVAL;
70+
goto failed;
71+
}
72+
pr_debug("%s: unflattened OK\n", __func__);
73+
74+
of_node_set_flag(overlay->node, OF_DETACHED);
75+
76+
ret_val = of_resolve_phandles(overlay->node);
77+
if (ret_val != 0) {
78+
pr_err("%s: Failed to resolve tree\n", __func__);
79+
goto failed;
80+
}
81+
pr_debug("%s: resolved OK\n", __func__);
82+
83+
ret_val = of_overlay_create(overlay->node);
84+
if (ret_val < 0) {
85+
pr_err("%s: Failed to create overlay (ret_val=%d)\n", __func__, ret_val);
86+
goto failed;
87+
}
88+
overlay->id = ret_val;
89+
pr_debug("%s: create OK\n", __func__);
90+
return 0;
91+
92+
failed:
93+
return ret_val;
94+
}
95+
96+
/**
97+
* dtbocfg_overlay_item_release() - Relase Device Tree Overlay
98+
* @overlay: Pointer to Device Tree Overlay Item
99+
* return none
100+
*/
101+
static void dtbocfg_overlay_item_release(struct dtbocfg_overlay_item *overlay)
102+
{
103+
if (overlay->id >= 0) {
104+
of_overlay_destroy(overlay->id);
105+
overlay->id = -1;
106+
}
107+
}
108+
109+
/**
110+
* container_of_dtbocfg_overlay_item() - Get Device Tree Overlay Item Pointer from Configuration Item
111+
* @item: Pointer to Configuration Item
112+
* return Pointer to Device Tree Overlay Item
113+
*/
114+
static inline struct dtbocfg_overlay_item* container_of_dtbocfg_overlay_item(struct config_item *item)
115+
{
116+
return item ? container_of(item, struct dtbocfg_overlay_item, item) : NULL;
117+
}
118+
119+
/**
120+
* dtbocfg_overlay_item_status_store() - Set Status Attibute
121+
* @item: Pointer to Configuration Item
122+
* @page: Pointer to Value Buffer
123+
* @count: Size of Value Buffer Size
124+
* return Stored Size or Error Status.
125+
*/
126+
static ssize_t dtbocfg_overlay_item_status_store(struct config_item *item, const char *buf, size_t count)
127+
{
128+
struct dtbocfg_overlay_item *overlay = container_of_dtbocfg_overlay_item(item);
129+
ssize_t status;
130+
unsigned long value;
131+
if (0 != (status = kstrtoul(buf, 10, &value))) {
132+
goto failed;
133+
}
134+
if (value == 0) {
135+
if (overlay->id >= 0) {
136+
dtbocfg_overlay_item_release(overlay);
137+
}
138+
} else {
139+
if (overlay->id < 0) {
140+
dtbocfg_overlay_item_create(overlay);
141+
}
142+
}
143+
return count;
144+
failed:
145+
return -EPERM;
146+
}
147+
148+
/**
149+
* dtbocfg_overlay_item_status_show() - Show Status Attibute
150+
* @item : Pointer to Configuration Item
151+
* @page : Pointer to Value for Store
152+
* return String Size or Error Status.
153+
*/
154+
static ssize_t dtbocfg_overlay_item_status_show(struct config_item *item, char *page)
155+
{
156+
struct dtbocfg_overlay_item *overlay = container_of_dtbocfg_overlay_item(item);
157+
return sprintf(page, "%d\n", overlay->id >= 0 ? 1 : 0);
158+
}
159+
160+
/**
161+
* dtbocfg_overlay_item_dtbo_store() - Store Device Tree Blob to Configuration Item
162+
* @item : Pointer to Configuration Item
163+
* @page : Pointer to Value Buffer
164+
* @count: Size of Value Buffer
165+
* return Stored Size or Error Status.
166+
*/
167+
static ssize_t dtbocfg_overlay_item_dtbo_store(struct config_item *item, const char *buf, size_t count)
168+
{
169+
struct dtbocfg_overlay_item *overlay = container_of_dtbocfg_overlay_item(item);
170+
171+
if (overlay->dtbo_size > 0) {
172+
if (overlay->id >= 0) {
173+
return -EPERM;
174+
}
175+
kfree(overlay->dtbo);
176+
overlay->dtbo = NULL;
177+
overlay->dtbo_size = 0;
178+
}
179+
180+
overlay->dtbo = kmemdup(buf, count, GFP_KERNEL);
181+
if (overlay->dtbo == NULL) {
182+
overlay->dtbo_size = 0;
183+
return -ENOMEM;
184+
} else {
185+
overlay->dtbo_size = count;
186+
return count;
187+
}
188+
}
189+
190+
/**
191+
* dtbocfg_overlay_item_dtbo_show() - Read Device Tree Blob from Configuration Item
192+
* @item : Pointer to Configuration Item
193+
* @page : Pointer to Value for Store
194+
* return Read Size
195+
*/
196+
static ssize_t dtbocfg_overlay_item_dtbo_show(struct config_item *item, char *buf)
197+
{
198+
struct dtbocfg_overlay_item *overlay = container_of_dtbocfg_overlay_item(item);
199+
200+
if (overlay->dtbo == NULL)
201+
return 0;
202+
203+
if (overlay->dtbo_size > PAGE_SIZE)
204+
return -EINVAL;
205+
206+
if (buf != NULL)
207+
memcpy(buf, overlay->dtbo, overlay->dtbo_size);
208+
209+
return overlay->dtbo_size;
210+
}
211+
212+
/**
213+
* Device Tree Blob Overlay Attribute Structure
214+
*/
215+
CONFIGFS_ATTR(dtbocfg_overlay_item_, dtbo );
216+
CONFIGFS_ATTR(dtbocfg_overlay_item_, status);
217+
218+
static struct configfs_attribute *dtbocfg_overlay_attrs[] = {
219+
&dtbocfg_overlay_item_attr_status,
220+
&dtbocfg_overlay_item_attr_dtbo,
221+
NULL,
222+
};
223+
224+
/**
225+
* dtbocfg_overlay_release() - Release Device Tree Overlay Item
226+
* @item : Pointer to Configuration Item
227+
* Return None
228+
*/
229+
static void dtbocfg_overlay_release(struct config_item *item)
230+
{
231+
struct dtbocfg_overlay_item *overlay = container_of_dtbocfg_overlay_item(item);
232+
233+
pr_debug("%s\n", __func__);
234+
235+
dtbocfg_overlay_item_release(overlay);
236+
237+
if (overlay->dtbo) {
238+
kfree(overlay->dtbo);
239+
overlay->dtbo = NULL;
240+
overlay->dtbo_size = 0;
241+
}
242+
243+
kfree(overlay);
244+
}
245+
246+
/**
247+
* Device Tree Blob Overlay Item Structure
248+
*/
249+
static struct configfs_item_operations dtbocfg_overlay_item_ops = {
250+
.release = dtbocfg_overlay_release,
251+
};
252+
253+
static struct config_item_type dtbocfg_overlay_item_type = {
254+
.ct_item_ops = &dtbocfg_overlay_item_ops,
255+
.ct_attrs = dtbocfg_overlay_attrs,
256+
.ct_owner = THIS_MODULE,
257+
};
258+
259+
/**
260+
* dtbocfg_overlay_group_make_item() - Make Device Tree Overlay Group Item
261+
* @group: Pointer to Configuration Group
262+
* @name : Pointer to Group Name
263+
* Return Pointer to Device Tree Overlay Group Item
264+
*/
265+
static struct config_item *dtbocfg_overlay_group_make_item(struct config_group *group, const char *name)
266+
{
267+
struct dtbocfg_overlay_item *overlay;
268+
269+
pr_debug("%s\n", __func__);
270+
271+
overlay = kzalloc(sizeof(*overlay), GFP_KERNEL);
272+
273+
if (!overlay)
274+
return ERR_PTR(-ENOMEM);
275+
overlay->id = -1;
276+
overlay->dtbo = NULL;
277+
overlay->dtbo_size = 0;
278+
279+
config_item_init_type_name(&overlay->item, name, &dtbocfg_overlay_item_type);
280+
return &overlay->item;
281+
}
282+
283+
/**
284+
* dtbocfg_overlay_group_drop_item() - Drop Device Tree Overlay Group Item
285+
* @group: Pointer to Configuration Group
286+
* @item : Pointer to Device Tree Overlay Group Item
287+
*/
288+
static void dtbocfg_overlay_group_drop_item(struct config_group *group, struct config_item *item)
289+
{
290+
struct dtbocfg_overlay_item *overlay = container_of_dtbocfg_overlay_item(item);
291+
292+
pr_debug("%s\n", __func__);
293+
294+
config_item_put(&overlay->item);
295+
}
296+
297+
/**
298+
* Device Tree Blob Overlay Sub Group Structures
299+
*/
300+
static struct configfs_group_operations dtbocfg_overlays_ops = {
301+
.make_item = dtbocfg_overlay_group_make_item,
302+
.drop_item = dtbocfg_overlay_group_drop_item,
303+
};
304+
305+
static struct config_item_type dtbocfg_overlays_type = {
306+
.ct_group_ops = &dtbocfg_overlays_ops,
307+
.ct_owner = THIS_MODULE,
308+
};
309+
310+
static struct config_group dtbocfg_overlay_group;
311+
312+
/**
313+
* Device Tree Blob Overlay Root Sub System Structures
314+
*/
315+
static struct configfs_group_operations dtbocfg_root_ops = {
316+
/* empty - we don't allow anything to be created */
317+
};
318+
319+
static struct config_item_type dtbocfg_root_type = {
320+
.ct_group_ops = &dtbocfg_root_ops,
321+
.ct_owner = THIS_MODULE,
322+
};
323+
324+
static struct configfs_subsystem dtbocfg_root_subsys = {
325+
.su_group = {
326+
.cg_item = {
327+
.ci_namebuf = "device-tree",
328+
.ci_type = &dtbocfg_root_type,
329+
},
330+
},
331+
.su_mutex = __MUTEX_INITIALIZER(dtbocfg_root_subsys.su_mutex),
332+
};
333+
334+
/**
335+
* dtbocfg_module_init()
336+
*/
337+
static int __init dtbocfg_module_init(void)
338+
{
339+
int retval = 0;
340+
341+
pr_info("%s\n", __func__);
342+
343+
config_group_init(&dtbocfg_root_subsys.su_group);
344+
config_group_init_type_name(&dtbocfg_overlay_group, "overlays", &dtbocfg_overlays_type);
345+
346+
retval = configfs_register_subsystem(&dtbocfg_root_subsys);
347+
if (retval != 0) {
348+
pr_err( "%s: couldn't register subsys\n", __func__);
349+
goto register_subsystem_failed;
350+
}
351+
352+
retval = configfs_register_group(&dtbocfg_root_subsys.su_group, &dtbocfg_overlay_group);
353+
if (retval != 0) {
354+
pr_err( "%s: couldn't register group\n", __func__);
355+
goto register_group_failed;
356+
}
357+
358+
pr_info("%s: OK\n", __func__);
359+
return 0;
360+
361+
register_group_failed:
362+
configfs_unregister_subsystem(&dtbocfg_root_subsys);
363+
register_subsystem_failed:
364+
return retval;
365+
}
366+
367+
/**
368+
* dtbocfg_module_exit()
369+
*/
370+
static void __exit dtbocfg_module_exit(void)
371+
{
372+
configfs_unregister_group(&dtbocfg_overlay_group);
373+
configfs_unregister_subsystem(&dtbocfg_root_subsys);
374+
}
375+
376+
module_init(dtbocfg_module_init);
377+
module_exit(dtbocfg_module_exit);
378+
379+
MODULE_AUTHOR("ikwzm");
380+
MODULE_DESCRIPTION("Device Tree Overlay Configuration File System");
381+
MODULE_LICENSE("Dual BSD/GPL");

0 commit comments

Comments
 (0)