2 * Configfs entries for device-tree
4 * Copyright (C) 2013 - Pantelis Antoniou <panto@antoniou-consulting.com>
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
11 #include <linux/ctype.h>
12 #include <linux/cpu.h>
13 #include <linux/module.h>
15 #include <linux/of_fdt.h>
16 #include <linux/spinlock.h>
17 #include <linux/slab.h>
18 #include <linux/proc_fs.h>
19 #include <linux/configfs.h>
20 #include <linux/types.h>
21 #include <linux/stat.h>
22 #include <linux/limits.h>
23 #include <linux/file.h>
24 #include <linux/vmalloc.h>
25 #include <linux/firmware.h>
26 #include <linux/sizes.h>
28 #include "of_private.h"
30 struct cfs_overlay_item
{
31 struct config_item item
;
35 const struct firmware
*fw
;
36 struct device_node
*overlay
;
43 static int create_overlay(struct cfs_overlay_item
*overlay
, void *blob
)
47 /* unflatten the tree */
48 of_fdt_unflatten_tree(blob
, NULL
, &overlay
->overlay
);
49 if (overlay
->overlay
== NULL
) {
50 pr_err("%s: failed to unflatten tree\n", __func__
);
54 pr_debug("%s: unflattened OK\n", __func__
);
56 /* mark it as detached */
57 of_node_set_flag(overlay
->overlay
, OF_DETACHED
);
59 /* perform resolution */
60 err
= of_resolve_phandles(overlay
->overlay
);
62 pr_err("%s: Failed to resolve tree\n", __func__
);
65 pr_debug("%s: resolved OK\n", __func__
);
67 err
= of_overlay_create(overlay
->overlay
);
69 pr_err("%s: Failed to create overlay (err=%d)\n",
79 static inline struct cfs_overlay_item
*to_cfs_overlay_item(
80 struct config_item
*item
)
82 return item
? container_of(item
, struct cfs_overlay_item
, item
) : NULL
;
85 static ssize_t
cfs_overlay_item_path_show(struct config_item
*item
,
88 struct cfs_overlay_item
*overlay
= to_cfs_overlay_item(item
);
89 return sprintf(page
, "%s\n", overlay
->path
);
92 static ssize_t
cfs_overlay_item_path_store(struct config_item
*item
,
93 const char *page
, size_t count
)
95 struct cfs_overlay_item
*overlay
= to_cfs_overlay_item(item
);
100 /* if it's set do not allow changes */
101 if (overlay
->path
[0] != '\0' || overlay
->dtbo_size
> 0)
104 /* copy to path buffer (and make sure it's always zero terminated */
105 count
= snprintf(overlay
->path
, sizeof(overlay
->path
) - 1, "%s", p
);
106 overlay
->path
[sizeof(overlay
->path
) - 1] = '\0';
108 /* strip trailing newlines */
109 s
= overlay
->path
+ strlen(overlay
->path
);
110 while (s
> overlay
->path
&& *--s
== '\n')
113 pr_debug("%s: path is '%s'\n", __func__
, overlay
->path
);
115 err
= request_firmware(&overlay
->fw
, overlay
->path
, NULL
);
119 err
= create_overlay(overlay
, (void *)overlay
->fw
->data
);
127 release_firmware(overlay
->fw
);
130 overlay
->path
[0] = '\0';
134 static ssize_t
cfs_overlay_item_status_show(struct config_item
*item
,
137 struct cfs_overlay_item
*overlay
= to_cfs_overlay_item(item
);
139 return sprintf(page
, "%s\n",
140 overlay
->ov_id
>= 0 ? "applied" : "unapplied");
143 CONFIGFS_ATTR(cfs_overlay_item_
, path
);
144 CONFIGFS_ATTR_RO(cfs_overlay_item_
, status
);
146 static struct configfs_attribute
*cfs_overlay_attrs
[] = {
147 &cfs_overlay_item_attr_path
,
148 &cfs_overlay_item_attr_status
,
152 ssize_t
cfs_overlay_item_dtbo_read(struct config_item
*item
,
153 void *buf
, size_t max_count
)
155 struct cfs_overlay_item
*overlay
= to_cfs_overlay_item(item
);
157 pr_debug("%s: buf=%p max_count=%zu\n", __func__
,
160 if (overlay
->dtbo
== NULL
)
163 /* copy if buffer provided */
165 /* the buffer must be large enough */
166 if (overlay
->dtbo_size
> max_count
)
169 memcpy(buf
, overlay
->dtbo
, overlay
->dtbo_size
);
172 return overlay
->dtbo_size
;
175 ssize_t
cfs_overlay_item_dtbo_write(struct config_item
*item
,
176 const void *buf
, size_t count
)
178 struct cfs_overlay_item
*overlay
= to_cfs_overlay_item(item
);
181 /* if it's set do not allow changes */
182 if (overlay
->path
[0] != '\0' || overlay
->dtbo_size
> 0)
185 /* copy the contents */
186 overlay
->dtbo
= kmemdup(buf
, count
, GFP_KERNEL
);
187 if (overlay
->dtbo
== NULL
)
190 overlay
->dtbo_size
= count
;
192 err
= create_overlay(overlay
, overlay
->dtbo
);
199 kfree(overlay
->dtbo
);
200 overlay
->dtbo
= NULL
;
201 overlay
->dtbo_size
= 0;
206 CONFIGFS_BIN_ATTR(cfs_overlay_item_
, dtbo
, NULL
, SZ_1M
);
208 static struct configfs_bin_attribute
*cfs_overlay_bin_attrs
[] = {
209 &cfs_overlay_item_attr_dtbo
,
213 static void cfs_overlay_release(struct config_item
*item
)
215 struct cfs_overlay_item
*overlay
= to_cfs_overlay_item(item
);
217 if (overlay
->ov_id
>= 0)
218 of_overlay_destroy(overlay
->ov_id
);
220 release_firmware(overlay
->fw
);
221 /* kfree with NULL is safe */
222 kfree(overlay
->dtbo
);
226 static struct configfs_item_operations cfs_overlay_item_ops
= {
227 .release
= cfs_overlay_release
,
230 static struct config_item_type cfs_overlay_type
= {
231 .ct_item_ops
= &cfs_overlay_item_ops
,
232 .ct_attrs
= cfs_overlay_attrs
,
233 .ct_bin_attrs
= cfs_overlay_bin_attrs
,
234 .ct_owner
= THIS_MODULE
,
237 static struct config_item
*cfs_overlay_group_make_item(
238 struct config_group
*group
, const char *name
)
240 struct cfs_overlay_item
*overlay
;
242 overlay
= kzalloc(sizeof(*overlay
), GFP_KERNEL
);
244 return ERR_PTR(-ENOMEM
);
247 config_item_init_type_name(&overlay
->item
, name
, &cfs_overlay_type
);
248 return &overlay
->item
;
251 static void cfs_overlay_group_drop_item(struct config_group
*group
,
252 struct config_item
*item
)
254 struct cfs_overlay_item
*overlay
= to_cfs_overlay_item(item
);
256 config_item_put(&overlay
->item
);
259 static struct configfs_group_operations overlays_ops
= {
260 .make_item
= cfs_overlay_group_make_item
,
261 .drop_item
= cfs_overlay_group_drop_item
,
264 static struct config_item_type overlays_type
= {
265 .ct_group_ops
= &overlays_ops
,
266 .ct_owner
= THIS_MODULE
,
269 static struct configfs_group_operations of_cfs_ops
= {
270 /* empty - we don't allow anything to be created */
273 static struct config_item_type of_cfs_type
= {
274 .ct_group_ops
= &of_cfs_ops
,
275 .ct_owner
= THIS_MODULE
,
278 struct config_group of_cfs_overlay_group
;
280 static struct configfs_subsystem of_cfs_subsys
= {
283 .ci_namebuf
= "device-tree",
284 .ci_type
= &of_cfs_type
,
287 .su_mutex
= __MUTEX_INITIALIZER(of_cfs_subsys
.su_mutex
),
290 static int __init
of_cfs_init(void)
294 pr_info("%s\n", __func__
);
296 config_group_init(&of_cfs_subsys
.su_group
);
297 config_group_init_type_name(&of_cfs_overlay_group
, "overlays",
299 configfs_add_default_group(&of_cfs_overlay_group
,
300 &of_cfs_subsys
.su_group
);
302 ret
= configfs_register_subsystem(&of_cfs_subsys
);
304 pr_err("%s: failed to register subsys\n", __func__
);
307 pr_info("%s: OK\n", __func__
);
311 late_initcall(of_cfs_init
);