Commit | Line | Data |
---|---|---|
b2441318 | 1 | /* SPDX-License-Identifier: GPL-2.0 */ |
88af8bbe SAS |
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) \ | |
45b6a73f | 11 | static ssize_t __struct##_##__name##_store(struct config_item *item, \ |
88af8bbe SAS |
12 | const char *page, size_t len) \ |
13 | { \ | |
45b6a73f | 14 | struct __struct *gs = to_##__struct(item); \ |
88af8bbe SAS |
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) \ | |
45b6a73f | 24 | static ssize_t __struct##_##__name##_show(struct config_item *item, char *page) \ |
88af8bbe | 25 | { \ |
45b6a73f | 26 | struct __struct *gs = to_##__struct(item); \ |
88af8bbe SAS |
27 | return sprintf(page, "%s\n", gs->__name ?: ""); \ |
28 | } | |
29 | ||
88af8bbe SAS |
30 | #define GS_STRINGS_RW(struct_name, _name) \ |
31 | GS_STRINGS_R(struct_name, _name) \ | |
32 | GS_STRINGS_W(struct_name, _name) \ | |
45b6a73f | 33 | CONFIGFS_ATTR(struct_name##_, _name) |
88af8bbe SAS |
34 | |
35 | #define USB_CONFIG_STRING_RW_OPS(struct_in) \ | |
88af8bbe SAS |
36 | static struct configfs_item_operations struct_in##_langid_item_ops = { \ |
37 | .release = struct_in##_attr_release, \ | |
88af8bbe SAS |
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 |