2 * File attributes for Mediated devices
4 * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
5 * Author: Neo Jia <cjia@nvidia.com>
6 * Kirti Wankhede <kwankhede@nvidia.com>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
13 #include <linux/sysfs.h>
14 #include <linux/ctype.h>
15 #include <linux/device.h>
16 #include <linux/slab.h>
17 #include <linux/uuid.h>
18 #include <linux/mdev.h>
20 #include "mdev_private.h"
22 /* Static functions */
24 static ssize_t
mdev_type_attr_show(struct kobject
*kobj
,
25 struct attribute
*__attr
, char *buf
)
27 struct mdev_type_attribute
*attr
= to_mdev_type_attr(__attr
);
28 struct mdev_type
*type
= to_mdev_type(kobj
);
32 ret
= attr
->show(kobj
, type
->parent
->dev
, buf
);
36 static ssize_t
mdev_type_attr_store(struct kobject
*kobj
,
37 struct attribute
*__attr
,
38 const char *buf
, size_t count
)
40 struct mdev_type_attribute
*attr
= to_mdev_type_attr(__attr
);
41 struct mdev_type
*type
= to_mdev_type(kobj
);
45 ret
= attr
->store(&type
->kobj
, type
->parent
->dev
, buf
, count
);
49 static const struct sysfs_ops mdev_type_sysfs_ops
= {
50 .show
= mdev_type_attr_show
,
51 .store
= mdev_type_attr_store
,
54 static ssize_t
create_store(struct kobject
*kobj
, struct device
*dev
,
55 const char *buf
, size_t count
)
61 if ((count
< UUID_STRING_LEN
) || (count
> UUID_STRING_LEN
+ 1))
64 str
= kstrndup(buf
, count
, GFP_KERNEL
);
68 ret
= uuid_le_to_bin(str
, &uuid
);
73 ret
= mdev_device_create(kobj
, dev
, uuid
);
80 MDEV_TYPE_ATTR_WO(create
);
82 static void mdev_type_release(struct kobject
*kobj
)
84 struct mdev_type
*type
= to_mdev_type(kobj
);
86 pr_debug("Releasing group %s\n", kobj
->name
);
90 static struct kobj_type mdev_type_ktype
= {
91 .sysfs_ops
= &mdev_type_sysfs_ops
,
92 .release
= mdev_type_release
,
95 struct mdev_type
*add_mdev_supported_type(struct mdev_parent
*parent
,
96 struct attribute_group
*group
)
98 struct mdev_type
*type
;
102 pr_err("%s: Type name empty!\n", __func__
);
103 return ERR_PTR(-EINVAL
);
106 type
= kzalloc(sizeof(*type
), GFP_KERNEL
);
108 return ERR_PTR(-ENOMEM
);
110 type
->kobj
.kset
= parent
->mdev_types_kset
;
112 ret
= kobject_init_and_add(&type
->kobj
, &mdev_type_ktype
, NULL
,
113 "%s-%s", dev_driver_string(parent
->dev
),
120 ret
= sysfs_create_file(&type
->kobj
, &mdev_type_attr_create
.attr
);
122 goto attr_create_failed
;
124 type
->devices_kobj
= kobject_create_and_add("devices", &type
->kobj
);
125 if (!type
->devices_kobj
) {
127 goto attr_devices_failed
;
130 ret
= sysfs_create_files(&type
->kobj
,
131 (const struct attribute
**)group
->attrs
);
138 type
->parent
= parent
;
142 kobject_put(type
->devices_kobj
);
144 sysfs_remove_file(&type
->kobj
, &mdev_type_attr_create
.attr
);
146 kobject_del(&type
->kobj
);
147 kobject_put(&type
->kobj
);
151 static void remove_mdev_supported_type(struct mdev_type
*type
)
153 sysfs_remove_files(&type
->kobj
,
154 (const struct attribute
**)type
->group
->attrs
);
155 kobject_put(type
->devices_kobj
);
156 sysfs_remove_file(&type
->kobj
, &mdev_type_attr_create
.attr
);
157 kobject_del(&type
->kobj
);
158 kobject_put(&type
->kobj
);
161 static int add_mdev_supported_type_groups(struct mdev_parent
*parent
)
165 for (i
= 0; parent
->ops
->supported_type_groups
[i
]; i
++) {
166 struct mdev_type
*type
;
168 type
= add_mdev_supported_type(parent
,
169 parent
->ops
->supported_type_groups
[i
]);
171 struct mdev_type
*ltype
, *tmp
;
173 list_for_each_entry_safe(ltype
, tmp
, &parent
->type_list
,
175 list_del(<ype
->next
);
176 remove_mdev_supported_type(ltype
);
178 return PTR_ERR(type
);
180 list_add(&type
->next
, &parent
->type_list
);
185 /* mdev sysfs functions */
186 void parent_remove_sysfs_files(struct mdev_parent
*parent
)
188 struct mdev_type
*type
, *tmp
;
190 list_for_each_entry_safe(type
, tmp
, &parent
->type_list
, next
) {
191 list_del(&type
->next
);
192 remove_mdev_supported_type(type
);
195 sysfs_remove_groups(&parent
->dev
->kobj
, parent
->ops
->dev_attr_groups
);
196 kset_unregister(parent
->mdev_types_kset
);
199 int parent_create_sysfs_files(struct mdev_parent
*parent
)
203 parent
->mdev_types_kset
= kset_create_and_add("mdev_supported_types",
204 NULL
, &parent
->dev
->kobj
);
206 if (!parent
->mdev_types_kset
)
209 INIT_LIST_HEAD(&parent
->type_list
);
211 ret
= sysfs_create_groups(&parent
->dev
->kobj
,
212 parent
->ops
->dev_attr_groups
);
216 ret
= add_mdev_supported_type_groups(parent
);
218 sysfs_remove_groups(&parent
->dev
->kobj
,
219 parent
->ops
->dev_attr_groups
);
224 kset_unregister(parent
->mdev_types_kset
);
228 static ssize_t
remove_store(struct device
*dev
, struct device_attribute
*attr
,
229 const char *buf
, size_t count
)
233 if (kstrtoul(buf
, 0, &val
) < 0)
236 if (val
&& device_remove_file_self(dev
, attr
)) {
239 ret
= mdev_device_remove(dev
, false);
241 device_create_file(dev
, attr
);
249 static DEVICE_ATTR_WO(remove
);
251 static const struct attribute
*mdev_device_attrs
[] = {
252 &dev_attr_remove
.attr
,
256 int mdev_create_sysfs_files(struct device
*dev
, struct mdev_type
*type
)
260 ret
= sysfs_create_link(type
->devices_kobj
, &dev
->kobj
, dev_name(dev
));
264 ret
= sysfs_create_link(&dev
->kobj
, &type
->kobj
, "mdev_type");
266 goto type_link_failed
;
268 ret
= sysfs_create_files(&dev
->kobj
, mdev_device_attrs
);
270 goto create_files_failed
;
275 sysfs_remove_link(&dev
->kobj
, "mdev_type");
277 sysfs_remove_link(type
->devices_kobj
, dev_name(dev
));
281 void mdev_remove_sysfs_files(struct device
*dev
, struct mdev_type
*type
)
283 sysfs_remove_link(&dev
->kobj
, "mdev_type");
284 sysfs_remove_link(type
->devices_kobj
, dev_name(dev
));
285 sysfs_remove_files(&dev
->kobj
, mdev_device_attrs
);