1 | /* SPDX-License-Identifier: GPL-2.0 */ |
2 | #ifndef __GADGET_CONFIGFS__ |
3 | #define __GADGET_CONFIGFS__ |
4 | |
5 | #include <linux/configfs.h> |
6 | |
7 | int check_user_usb_string(const char *name, |
8 | struct usb_gadget_strings *stringtab_dev); |
9 | |
10 | #define GS_STRINGS_W(__struct, __name) \ |
11 | static ssize_t __struct##_##__name##_store(struct config_item *item, \ |
12 | const char *page, size_t len) \ |
13 | { \ |
14 | struct __struct *gs = to_##__struct(item); \ |
15 | int ret; \ |
16 | \ |
17 | ret = usb_string_copy(page, &gs->__name); \ |
18 | if (ret) \ |
19 | return ret; \ |
20 | return len; \ |
21 | } |
22 | |
23 | #define GS_STRINGS_R(__struct, __name) \ |
24 | static ssize_t __struct##_##__name##_show(struct config_item *item, char *page) \ |
25 | { \ |
26 | struct __struct *gs = to_##__struct(item); \ |
27 | return sprintf(page, "%s\n", gs->__name ?: ""); \ |
28 | } |
29 | |
30 | #define GS_STRINGS_RW(struct_name, _name) \ |
31 | GS_STRINGS_R(struct_name, _name) \ |
32 | GS_STRINGS_W(struct_name, _name) \ |
33 | CONFIGFS_ATTR(struct_name##_, _name) |
34 | |
35 | #define USB_CONFIG_STRING_RW_OPS(struct_in) \ |
36 | static struct configfs_item_operations struct_in##_langid_item_ops = { \ |
37 | .release = struct_in##_attr_release, \ |
38 | }; \ |
39 | \ |
40 | static struct config_item_type struct_in##_langid_type = { \ |
41 | .ct_item_ops = &struct_in##_langid_item_ops, \ |
42 | .ct_attrs = struct_in##_langid_attrs, \ |
43 | .ct_owner = THIS_MODULE, \ |
44 | } |
45 | |
46 | #define USB_CONFIG_STRINGS_LANG(struct_in, struct_member) \ |
47 | static struct config_group *struct_in##_strings_make( \ |
48 | struct config_group *group, \ |
49 | const char *name) \ |
50 | { \ |
51 | struct struct_member *gi; \ |
52 | struct struct_in *gs; \ |
53 | struct struct_in *new; \ |
54 | int langs = 0; \ |
55 | int ret; \ |
56 | \ |
57 | new = kzalloc(sizeof(*new), GFP_KERNEL); \ |
58 | if (!new) \ |
59 | return ERR_PTR(-ENOMEM); \ |
60 | \ |
61 | ret = check_user_usb_string(name, &new->stringtab_dev); \ |
62 | if (ret) \ |
63 | goto err; \ |
64 | config_group_init_type_name(&new->group, name, \ |
65 | &struct_in##_langid_type); \ |
66 | \ |
67 | gi = container_of(group, struct struct_member, strings_group); \ |
68 | ret = -EEXIST; \ |
69 | list_for_each_entry(gs, &gi->string_list, list) { \ |
70 | if (gs->stringtab_dev.language == new->stringtab_dev.language) \ |
71 | goto err; \ |
72 | langs++; \ |
73 | } \ |
74 | ret = -EOVERFLOW; \ |
75 | if (langs >= MAX_USB_STRING_LANGS) \ |
76 | goto err; \ |
77 | \ |
78 | list_add_tail(&new->list, &gi->string_list); \ |
79 | return &new->group; \ |
80 | err: \ |
81 | kfree(new); \ |
82 | return ERR_PTR(ret); \ |
83 | } \ |
84 | \ |
85 | static void struct_in##_strings_drop( \ |
86 | struct config_group *group, \ |
87 | struct config_item *item) \ |
88 | { \ |
89 | config_item_put(item); \ |
90 | } \ |
91 | \ |
92 | static struct configfs_group_operations struct_in##_strings_ops = { \ |
93 | .make_group = &struct_in##_strings_make, \ |
94 | .drop_item = &struct_in##_strings_drop, \ |
95 | }; \ |
96 | \ |
97 | static struct config_item_type struct_in##_strings_type = { \ |
98 | .ct_group_ops = &struct_in##_strings_ops, \ |
99 | .ct_owner = THIS_MODULE, \ |
100 | } |
101 | |
102 | #endif |
103 | |