diff options
-rw-r--r-- | drivers/usb/gadget/Kconfig | 1 | ||||
-rw-r--r-- | drivers/usb/gadget/Makefile | 2 | ||||
-rw-r--r-- | drivers/usb/gadget/composite.c | 1 | ||||
-rw-r--r-- | drivers/usb/gadget/configfs.c | 1003 | ||||
-rw-r--r-- | drivers/usb/gadget/f_acm.c | 55 | ||||
-rw-r--r-- | include/linux/usb/composite.h | 3 | ||||
-rw-r--r-- | include/linux/usb/gadget_configfs.h | 110 |
7 files changed, 1174 insertions, 1 deletions
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index e1d3e0803cd5..74a29de8f254 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig | |||
@@ -493,6 +493,7 @@ endmenu | |||
493 | # composite based drivers | 493 | # composite based drivers |
494 | config USB_LIBCOMPOSITE | 494 | config USB_LIBCOMPOSITE |
495 | tristate | 495 | tristate |
496 | select CONFIGFS_FS | ||
496 | depends on USB_GADGET | 497 | depends on USB_GADGET |
497 | 498 | ||
498 | config USB_F_ACM | 499 | config USB_F_ACM |
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index 82fb22511356..96e72433cd31 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile | |||
@@ -6,7 +6,7 @@ ccflags-$(CONFIG_USB_GADGET_DEBUG) := -DDEBUG | |||
6 | obj-$(CONFIG_USB_GADGET) += udc-core.o | 6 | obj-$(CONFIG_USB_GADGET) += udc-core.o |
7 | obj-$(CONFIG_USB_LIBCOMPOSITE) += libcomposite.o | 7 | obj-$(CONFIG_USB_LIBCOMPOSITE) += libcomposite.o |
8 | libcomposite-y := usbstring.o config.o epautoconf.o | 8 | libcomposite-y := usbstring.o config.o epautoconf.o |
9 | libcomposite-y += composite.o functions.o | 9 | libcomposite-y += composite.o functions.o configfs.o |
10 | obj-$(CONFIG_USB_DUMMY_HCD) += dummy_hcd.o | 10 | obj-$(CONFIG_USB_DUMMY_HCD) += dummy_hcd.o |
11 | obj-$(CONFIG_USB_NET2272) += net2272.o | 11 | obj-$(CONFIG_USB_NET2272) += net2272.o |
12 | obj-$(CONFIG_USB_NET2280) += net2280.o | 12 | obj-$(CONFIG_USB_NET2280) += net2280.o |
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index c0d62b278610..55f4df60f327 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c | |||
@@ -1637,6 +1637,7 @@ void composite_dev_cleanup(struct usb_composite_dev *cdev) | |||
1637 | kfree(cdev->req->buf); | 1637 | kfree(cdev->req->buf); |
1638 | usb_ep_free_request(cdev->gadget->ep0, cdev->req); | 1638 | usb_ep_free_request(cdev->gadget->ep0, cdev->req); |
1639 | } | 1639 | } |
1640 | cdev->next_string_id = 0; | ||
1640 | device_remove_file(&cdev->gadget->dev, &dev_attr_suspended); | 1641 | device_remove_file(&cdev->gadget->dev, &dev_attr_suspended); |
1641 | } | 1642 | } |
1642 | 1643 | ||
diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c new file mode 100644 index 000000000000..a34633a898a1 --- /dev/null +++ b/drivers/usb/gadget/configfs.c | |||
@@ -0,0 +1,1003 @@ | |||
1 | #include <linux/configfs.h> | ||
2 | #include <linux/module.h> | ||
3 | #include <linux/slab.h> | ||
4 | #include <linux/device.h> | ||
5 | #include <linux/usb/composite.h> | ||
6 | #include <linux/usb/gadget_configfs.h> | ||
7 | |||
8 | int check_user_usb_string(const char *name, | ||
9 | struct usb_gadget_strings *stringtab_dev) | ||
10 | { | ||
11 | unsigned primary_lang; | ||
12 | unsigned sub_lang; | ||
13 | u16 num; | ||
14 | int ret; | ||
15 | |||
16 | ret = kstrtou16(name, 0, &num); | ||
17 | if (ret) | ||
18 | return ret; | ||
19 | |||
20 | primary_lang = num & 0x3ff; | ||
21 | sub_lang = num >> 10; | ||
22 | |||
23 | /* simple sanity check for valid langid */ | ||
24 | switch (primary_lang) { | ||
25 | case 0: | ||
26 | case 0x62 ... 0xfe: | ||
27 | case 0x100 ... 0x3ff: | ||
28 | return -EINVAL; | ||
29 | } | ||
30 | if (!sub_lang) | ||
31 | return -EINVAL; | ||
32 | |||
33 | stringtab_dev->language = num; | ||
34 | return 0; | ||
35 | } | ||
36 | |||
37 | #define MAX_NAME_LEN 40 | ||
38 | #define MAX_USB_STRING_LANGS 2 | ||
39 | |||
40 | struct gadget_info { | ||
41 | struct config_group group; | ||
42 | struct config_group functions_group; | ||
43 | struct config_group configs_group; | ||
44 | struct config_group strings_group; | ||
45 | struct config_group *default_groups[4]; | ||
46 | |||
47 | struct mutex lock; | ||
48 | struct usb_gadget_strings *gstrings[MAX_USB_STRING_LANGS + 1]; | ||
49 | struct list_head string_list; | ||
50 | struct list_head available_func; | ||
51 | |||
52 | const char *udc_name; | ||
53 | #ifdef CONFIG_USB_OTG | ||
54 | struct usb_otg_descriptor otg; | ||
55 | #endif | ||
56 | struct usb_composite_driver composite; | ||
57 | struct usb_composite_dev cdev; | ||
58 | }; | ||
59 | |||
60 | struct config_usb_cfg { | ||
61 | struct config_group group; | ||
62 | struct config_group strings_group; | ||
63 | struct config_group *default_groups[2]; | ||
64 | struct list_head string_list; | ||
65 | struct usb_configuration c; | ||
66 | struct list_head func_list; | ||
67 | struct usb_gadget_strings *gstrings[MAX_USB_STRING_LANGS + 1]; | ||
68 | }; | ||
69 | |||
70 | struct gadget_strings { | ||
71 | struct usb_gadget_strings stringtab_dev; | ||
72 | struct usb_string strings[USB_GADGET_FIRST_AVAIL_IDX]; | ||
73 | char *manufacturer; | ||
74 | char *product; | ||
75 | char *serialnumber; | ||
76 | |||
77 | struct config_group group; | ||
78 | struct list_head list; | ||
79 | }; | ||
80 | |||
81 | struct gadget_config_name { | ||
82 | struct usb_gadget_strings stringtab_dev; | ||
83 | struct usb_string strings; | ||
84 | char *configuration; | ||
85 | |||
86 | struct config_group group; | ||
87 | struct list_head list; | ||
88 | }; | ||
89 | |||
90 | static int usb_string_copy(const char *s, char **s_copy) | ||
91 | { | ||
92 | int ret; | ||
93 | char *str; | ||
94 | char *copy = *s_copy; | ||
95 | ret = strlen(s); | ||
96 | if (ret > 126) | ||
97 | return -EOVERFLOW; | ||
98 | |||
99 | str = kstrdup(s, GFP_KERNEL); | ||
100 | if (!str) | ||
101 | return -ENOMEM; | ||
102 | if (str[ret - 1] == '\n') | ||
103 | str[ret - 1] = '\0'; | ||
104 | kfree(copy); | ||
105 | *s_copy = str; | ||
106 | return 0; | ||
107 | } | ||
108 | |||
109 | CONFIGFS_ATTR_STRUCT(gadget_info); | ||
110 | CONFIGFS_ATTR_STRUCT(config_usb_cfg); | ||
111 | |||
112 | #define GI_DEVICE_DESC_ITEM_ATTR(name) \ | ||
113 | static struct gadget_info_attribute gadget_cdev_desc_##name = \ | ||
114 | __CONFIGFS_ATTR(name, S_IRUGO | S_IWUSR, \ | ||
115 | gadget_dev_desc_##name##_show, \ | ||
116 | gadget_dev_desc_##name##_store) | ||
117 | |||
118 | #define GI_DEVICE_DESC_SIMPLE_R_u8(__name) \ | ||
119 | static ssize_t gadget_dev_desc_##__name##_show(struct gadget_info *gi, \ | ||
120 | char *page) \ | ||
121 | { \ | ||
122 | return sprintf(page, "0x%02x\n", gi->cdev.desc.__name); \ | ||
123 | } | ||
124 | |||
125 | #define GI_DEVICE_DESC_SIMPLE_R_u16(__name) \ | ||
126 | static ssize_t gadget_dev_desc_##__name##_show(struct gadget_info *gi, \ | ||
127 | char *page) \ | ||
128 | { \ | ||
129 | return sprintf(page, "0x%04x\n", le16_to_cpup(&gi->cdev.desc.__name)); \ | ||
130 | } | ||
131 | |||
132 | |||
133 | #define GI_DEVICE_DESC_SIMPLE_W_u8(_name) \ | ||
134 | static ssize_t gadget_dev_desc_##_name##_store(struct gadget_info *gi, \ | ||
135 | const char *page, size_t len) \ | ||
136 | { \ | ||
137 | u8 val; \ | ||
138 | int ret; \ | ||
139 | ret = kstrtou8(page, 0, &val); \ | ||
140 | if (ret) \ | ||
141 | return ret; \ | ||
142 | gi->cdev.desc._name = val; \ | ||
143 | return len; \ | ||
144 | } | ||
145 | |||
146 | #define GI_DEVICE_DESC_SIMPLE_W_u16(_name) \ | ||
147 | static ssize_t gadget_dev_desc_##_name##_store(struct gadget_info *gi, \ | ||
148 | const char *page, size_t len) \ | ||
149 | { \ | ||
150 | u16 val; \ | ||
151 | int ret; \ | ||
152 | ret = kstrtou16(page, 0, &val); \ | ||
153 | if (ret) \ | ||
154 | return ret; \ | ||
155 | gi->cdev.desc._name = cpu_to_le16p(&val); \ | ||
156 | return len; \ | ||
157 | } | ||
158 | |||
159 | #define GI_DEVICE_DESC_SIMPLE_RW(_name, _type) \ | ||
160 | GI_DEVICE_DESC_SIMPLE_R_##_type(_name) \ | ||
161 | GI_DEVICE_DESC_SIMPLE_W_##_type(_name) | ||
162 | |||
163 | GI_DEVICE_DESC_SIMPLE_R_u16(bcdUSB); | ||
164 | GI_DEVICE_DESC_SIMPLE_RW(bDeviceClass, u8); | ||
165 | GI_DEVICE_DESC_SIMPLE_RW(bDeviceSubClass, u8); | ||
166 | GI_DEVICE_DESC_SIMPLE_RW(bDeviceProtocol, u8); | ||
167 | GI_DEVICE_DESC_SIMPLE_RW(bMaxPacketSize0, u8); | ||
168 | GI_DEVICE_DESC_SIMPLE_RW(idVendor, u16); | ||
169 | GI_DEVICE_DESC_SIMPLE_RW(idProduct, u16); | ||
170 | GI_DEVICE_DESC_SIMPLE_R_u16(bcdDevice); | ||
171 | |||
172 | static ssize_t is_valid_bcd(u16 bcd_val) | ||
173 | { | ||
174 | if ((bcd_val & 0xf) > 9) | ||
175 | return -EINVAL; | ||
176 | if (((bcd_val >> 4) & 0xf) > 9) | ||
177 | return -EINVAL; | ||
178 | if (((bcd_val >> 8) & 0xf) > 9) | ||
179 | return -EINVAL; | ||
180 | if (((bcd_val >> 12) & 0xf) > 9) | ||
181 | return -EINVAL; | ||
182 | return 0; | ||
183 | } | ||
184 | |||
185 | static ssize_t gadget_dev_desc_bcdDevice_store(struct gadget_info *gi, | ||
186 | const char *page, size_t len) | ||
187 | { | ||
188 | u16 bcdDevice; | ||
189 | int ret; | ||
190 | |||
191 | ret = kstrtou16(page, 0, &bcdDevice); | ||
192 | if (ret) | ||
193 | return ret; | ||
194 | ret = is_valid_bcd(bcdDevice); | ||
195 | if (ret) | ||
196 | return ret; | ||
197 | |||
198 | gi->cdev.desc.bcdDevice = cpu_to_le16(bcdDevice); | ||
199 | return len; | ||
200 | } | ||
201 | |||
202 | static ssize_t gadget_dev_desc_bcdUSB_store(struct gadget_info *gi, | ||
203 | const char *page, size_t len) | ||
204 | { | ||
205 | u16 bcdUSB; | ||
206 | int ret; | ||
207 | |||
208 | ret = kstrtou16(page, 0, &bcdUSB); | ||
209 | if (ret) | ||
210 | return ret; | ||
211 | ret = is_valid_bcd(bcdUSB); | ||
212 | if (ret) | ||
213 | return ret; | ||
214 | |||
215 | gi->cdev.desc.bcdUSB = cpu_to_le16(bcdUSB); | ||
216 | return len; | ||
217 | } | ||
218 | |||
219 | static ssize_t gadget_dev_desc_UDC_show(struct gadget_info *gi, char *page) | ||
220 | { | ||
221 | return sprintf(page, "%s\n", gi->udc_name ?: ""); | ||
222 | } | ||
223 | |||
224 | static int unregister_gadget(struct gadget_info *gi) | ||
225 | { | ||
226 | int ret; | ||
227 | |||
228 | if (!gi->udc_name) | ||
229 | return -ENODEV; | ||
230 | |||
231 | ret = usb_gadget_unregister_driver(&gi->composite.gadget_driver); | ||
232 | if (ret) | ||
233 | return ret; | ||
234 | kfree(gi->udc_name); | ||
235 | gi->udc_name = NULL; | ||
236 | return 0; | ||
237 | } | ||
238 | |||
239 | static ssize_t gadget_dev_desc_UDC_store(struct gadget_info *gi, | ||
240 | const char *page, size_t len) | ||
241 | { | ||
242 | char *name; | ||
243 | int ret; | ||
244 | |||
245 | name = kstrdup(page, GFP_KERNEL); | ||
246 | if (!name) | ||
247 | return -ENOMEM; | ||
248 | if (name[len - 1] == '\n') | ||
249 | name[len - 1] = '\0'; | ||
250 | |||
251 | mutex_lock(&gi->lock); | ||
252 | |||
253 | if (!strlen(name)) { | ||
254 | ret = unregister_gadget(gi); | ||
255 | if (ret) | ||
256 | goto err; | ||
257 | } else { | ||
258 | if (gi->udc_name) { | ||
259 | ret = -EBUSY; | ||
260 | goto err; | ||
261 | } | ||
262 | ret = udc_attach_driver(name, &gi->composite.gadget_driver); | ||
263 | if (ret) | ||
264 | goto err; | ||
265 | gi->udc_name = name; | ||
266 | } | ||
267 | mutex_unlock(&gi->lock); | ||
268 | return len; | ||
269 | err: | ||
270 | kfree(name); | ||
271 | mutex_unlock(&gi->lock); | ||
272 | return ret; | ||
273 | } | ||
274 | |||
275 | GI_DEVICE_DESC_ITEM_ATTR(bDeviceClass); | ||
276 | GI_DEVICE_DESC_ITEM_ATTR(bDeviceSubClass); | ||
277 | GI_DEVICE_DESC_ITEM_ATTR(bDeviceProtocol); | ||
278 | GI_DEVICE_DESC_ITEM_ATTR(bMaxPacketSize0); | ||
279 | GI_DEVICE_DESC_ITEM_ATTR(idVendor); | ||
280 | GI_DEVICE_DESC_ITEM_ATTR(idProduct); | ||
281 | GI_DEVICE_DESC_ITEM_ATTR(bcdDevice); | ||
282 | GI_DEVICE_DESC_ITEM_ATTR(bcdUSB); | ||
283 | GI_DEVICE_DESC_ITEM_ATTR(UDC); | ||
284 | |||
285 | static struct configfs_attribute *gadget_root_attrs[] = { | ||
286 | &gadget_cdev_desc_bDeviceClass.attr, | ||
287 | &gadget_cdev_desc_bDeviceSubClass.attr, | ||
288 | &gadget_cdev_desc_bDeviceProtocol.attr, | ||
289 | &gadget_cdev_desc_bMaxPacketSize0.attr, | ||
290 | &gadget_cdev_desc_idVendor.attr, | ||
291 | &gadget_cdev_desc_idProduct.attr, | ||
292 | &gadget_cdev_desc_bcdDevice.attr, | ||
293 | &gadget_cdev_desc_bcdUSB.attr, | ||
294 | &gadget_cdev_desc_UDC.attr, | ||
295 | NULL, | ||
296 | }; | ||
297 | |||
298 | static inline struct gadget_info *to_gadget_info(struct config_item *item) | ||
299 | { | ||
300 | return container_of(to_config_group(item), struct gadget_info, group); | ||
301 | } | ||
302 | |||
303 | static inline struct gadget_strings *to_gadget_strings(struct config_item *item) | ||
304 | { | ||
305 | return container_of(to_config_group(item), struct gadget_strings, | ||
306 | group); | ||
307 | } | ||
308 | |||
309 | static inline struct gadget_config_name *to_gadget_config_name( | ||
310 | struct config_item *item) | ||
311 | { | ||
312 | return container_of(to_config_group(item), struct gadget_config_name, | ||
313 | group); | ||
314 | } | ||
315 | |||
316 | static inline struct config_usb_cfg *to_config_usb_cfg(struct config_item *item) | ||
317 | { | ||
318 | return container_of(to_config_group(item), struct config_usb_cfg, | ||
319 | group); | ||
320 | } | ||
321 | |||
322 | static inline struct usb_function_instance *to_usb_function_instance( | ||
323 | struct config_item *item) | ||
324 | { | ||
325 | return container_of(to_config_group(item), | ||
326 | struct usb_function_instance, group); | ||
327 | } | ||
328 | |||
329 | static void gadget_info_attr_release(struct config_item *item) | ||
330 | { | ||
331 | struct gadget_info *gi = to_gadget_info(item); | ||
332 | |||
333 | WARN_ON(!list_empty(&gi->cdev.configs)); | ||
334 | WARN_ON(!list_empty(&gi->string_list)); | ||
335 | WARN_ON(!list_empty(&gi->available_func)); | ||
336 | kfree(gi->composite.gadget_driver.function); | ||
337 | kfree(gi); | ||
338 | } | ||
339 | |||
340 | CONFIGFS_ATTR_OPS(gadget_info); | ||
341 | |||
342 | static struct configfs_item_operations gadget_root_item_ops = { | ||
343 | .release = gadget_info_attr_release, | ||
344 | .show_attribute = gadget_info_attr_show, | ||
345 | .store_attribute = gadget_info_attr_store, | ||
346 | }; | ||
347 | |||
348 | static void gadget_config_attr_release(struct config_item *item) | ||
349 | { | ||
350 | struct config_usb_cfg *cfg = to_config_usb_cfg(item); | ||
351 | |||
352 | WARN_ON(!list_empty(&cfg->c.functions)); | ||
353 | list_del(&cfg->c.list); | ||
354 | kfree(cfg->c.label); | ||
355 | kfree(cfg); | ||
356 | } | ||
357 | |||
358 | static int config_usb_cfg_link( | ||
359 | struct config_item *usb_cfg_ci, | ||
360 | struct config_item *usb_func_ci) | ||
361 | { | ||
362 | struct config_usb_cfg *cfg = to_config_usb_cfg(usb_cfg_ci); | ||
363 | struct usb_composite_dev *cdev = cfg->c.cdev; | ||
364 | struct gadget_info *gi = container_of(cdev, struct gadget_info, cdev); | ||
365 | |||
366 | struct config_group *group = to_config_group(usb_func_ci); | ||
367 | struct usb_function_instance *fi = container_of(group, | ||
368 | struct usb_function_instance, group); | ||
369 | struct usb_function_instance *a_fi; | ||
370 | struct usb_function *f; | ||
371 | int ret; | ||
372 | |||
373 | mutex_lock(&gi->lock); | ||
374 | /* | ||
375 | * Make sure this function is from within our _this_ gadget and not | ||
376 | * from another gadget or a random directory. | ||
377 | * Also a function instance can only be linked once. | ||
378 | */ | ||
379 | list_for_each_entry(a_fi, &gi->available_func, cfs_list) { | ||
380 | if (a_fi == fi) | ||
381 | break; | ||
382 | } | ||
383 | if (a_fi != fi) { | ||
384 | ret = -EINVAL; | ||
385 | goto out; | ||
386 | } | ||
387 | |||
388 | list_for_each_entry(f, &cfg->func_list, list) { | ||
389 | if (f->fi == fi) { | ||
390 | ret = -EEXIST; | ||
391 | goto out; | ||
392 | } | ||
393 | } | ||
394 | |||
395 | f = usb_get_function(fi); | ||
396 | if (IS_ERR(f)) { | ||
397 | ret = PTR_ERR(f); | ||
398 | goto out; | ||
399 | } | ||
400 | |||
401 | /* stash the function until we bind it to the gadget */ | ||
402 | list_add_tail(&f->list, &cfg->func_list); | ||
403 | ret = 0; | ||
404 | out: | ||
405 | mutex_unlock(&gi->lock); | ||
406 | return ret; | ||
407 | } | ||
408 | |||
409 | static int config_usb_cfg_unlink( | ||
410 | struct config_item *usb_cfg_ci, | ||
411 | struct config_item *usb_func_ci) | ||
412 | { | ||
413 | struct config_usb_cfg *cfg = to_config_usb_cfg(usb_cfg_ci); | ||
414 | struct usb_composite_dev *cdev = cfg->c.cdev; | ||
415 | struct gadget_info *gi = container_of(cdev, struct gadget_info, cdev); | ||
416 | |||
417 | struct config_group *group = to_config_group(usb_func_ci); | ||
418 | struct usb_function_instance *fi = container_of(group, | ||
419 | struct usb_function_instance, group); | ||
420 | struct usb_function *f; | ||
421 | |||
422 | /* | ||
423 | * ideally I would like to forbid to unlink functions while a gadget is | ||
424 | * bound to an UDC. Since this isn't possible at the moment, we simply | ||
425 | * force an unbind, the function is available here and then we can | ||
426 | * remove the function. | ||
427 | */ | ||
428 | mutex_lock(&gi->lock); | ||
429 | if (gi->udc_name) | ||
430 | unregister_gadget(gi); | ||
431 | WARN_ON(gi->udc_name); | ||
432 | |||
433 | list_for_each_entry(f, &cfg->func_list, list) { | ||
434 | if (f->fi == fi) { | ||
435 | list_del(&f->list); | ||
436 | usb_put_function(f); | ||
437 | mutex_unlock(&gi->lock); | ||
438 | return 0; | ||
439 | } | ||
440 | } | ||
441 | mutex_unlock(&gi->lock); | ||
442 | __WARN_printf("Unable to locate function to unbind\n"); | ||
443 | return 0; | ||
444 | } | ||
445 | |||
446 | CONFIGFS_ATTR_OPS(config_usb_cfg); | ||
447 | |||
448 | static struct configfs_item_operations gadget_config_item_ops = { | ||
449 | .release = gadget_config_attr_release, | ||
450 | .show_attribute = config_usb_cfg_attr_show, | ||
451 | .store_attribute = config_usb_cfg_attr_store, | ||
452 | .allow_link = config_usb_cfg_link, | ||
453 | .drop_link = config_usb_cfg_unlink, | ||
454 | }; | ||
455 | |||
456 | |||
457 | static ssize_t gadget_config_desc_MaxPower_show(struct config_usb_cfg *cfg, | ||
458 | char *page) | ||
459 | { | ||
460 | return sprintf(page, "%u\n", cfg->c.MaxPower); | ||
461 | } | ||
462 | |||
463 | static ssize_t gadget_config_desc_MaxPower_store(struct config_usb_cfg *cfg, | ||
464 | const char *page, size_t len) | ||
465 | { | ||
466 | u16 val; | ||
467 | int ret; | ||
468 | ret = kstrtou16(page, 0, &val); | ||
469 | if (ret) | ||
470 | return ret; | ||
471 | if (DIV_ROUND_UP(val, 8) > 0xff) | ||
472 | return -ERANGE; | ||
473 | cfg->c.MaxPower = val; | ||
474 | return len; | ||
475 | } | ||
476 | |||
477 | static ssize_t gadget_config_desc_bmAttributes_show(struct config_usb_cfg *cfg, | ||
478 | char *page) | ||
479 | { | ||
480 | return sprintf(page, "0x%02x\n", cfg->c.bmAttributes); | ||
481 | } | ||
482 | |||
483 | static ssize_t gadget_config_desc_bmAttributes_store(struct config_usb_cfg *cfg, | ||
484 | const char *page, size_t len) | ||
485 | { | ||
486 | u8 val; | ||
487 | int ret; | ||
488 | ret = kstrtou8(page, 0, &val); | ||
489 | if (ret) | ||
490 | return ret; | ||
491 | if (!(val & USB_CONFIG_ATT_ONE)) | ||
492 | return -EINVAL; | ||
493 | if (val & ~(USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER | | ||
494 | USB_CONFIG_ATT_WAKEUP)) | ||
495 | return -EINVAL; | ||
496 | cfg->c.bmAttributes = val; | ||
497 | return len; | ||
498 | } | ||
499 | |||
500 | #define CFG_CONFIG_DESC_ITEM_ATTR(name) \ | ||
501 | static struct config_usb_cfg_attribute gadget_usb_cfg_##name = \ | ||
502 | __CONFIGFS_ATTR(name, S_IRUGO | S_IWUSR, \ | ||
503 | gadget_config_desc_##name##_show, \ | ||
504 | gadget_config_desc_##name##_store) | ||
505 | |||
506 | CFG_CONFIG_DESC_ITEM_ATTR(MaxPower); | ||
507 | CFG_CONFIG_DESC_ITEM_ATTR(bmAttributes); | ||
508 | |||
509 | static struct configfs_attribute *gadget_config_attrs[] = { | ||
510 | &gadget_usb_cfg_MaxPower.attr, | ||
511 | &gadget_usb_cfg_bmAttributes.attr, | ||
512 | NULL, | ||
513 | }; | ||
514 | |||
515 | static struct config_item_type gadget_config_type = { | ||
516 | .ct_item_ops = &gadget_config_item_ops, | ||
517 | .ct_attrs = gadget_config_attrs, | ||
518 | .ct_owner = THIS_MODULE, | ||
519 | }; | ||
520 | |||
521 | static struct config_item_type gadget_root_type = { | ||
522 | .ct_item_ops = &gadget_root_item_ops, | ||
523 | .ct_attrs = gadget_root_attrs, | ||
524 | .ct_owner = THIS_MODULE, | ||
525 | }; | ||
526 | |||
527 | static void composite_init_dev(struct usb_composite_dev *cdev) | ||
528 | { | ||
529 | spin_lock_init(&cdev->lock); | ||
530 | INIT_LIST_HEAD(&cdev->configs); | ||
531 | INIT_LIST_HEAD(&cdev->gstrings); | ||
532 | } | ||
533 | |||
534 | static struct config_group *function_make( | ||
535 | struct config_group *group, | ||
536 | const char *name) | ||
537 | { | ||
538 | struct gadget_info *gi; | ||
539 | struct usb_function_instance *fi; | ||
540 | char buf[MAX_NAME_LEN]; | ||
541 | char *func_name; | ||
542 | char *instance_name; | ||
543 | int ret; | ||
544 | |||
545 | ret = snprintf(buf, MAX_NAME_LEN, "%s", name); | ||
546 | if (ret >= MAX_NAME_LEN) | ||
547 | return ERR_PTR(-ENAMETOOLONG); | ||
548 | |||
549 | func_name = buf; | ||
550 | instance_name = strchr(func_name, '.'); | ||
551 | if (!instance_name) { | ||
552 | pr_err("Unable to locate . in FUNC.INSTANCE\n"); | ||
553 | return ERR_PTR(-EINVAL); | ||
554 | } | ||
555 | *instance_name = '\0'; | ||
556 | instance_name++; | ||
557 | |||
558 | fi = usb_get_function_instance(func_name); | ||
559 | if (IS_ERR(fi)) | ||
560 | return ERR_PTR(PTR_ERR(fi)); | ||
561 | |||
562 | ret = config_item_set_name(&fi->group.cg_item, name); | ||
563 | if (ret) { | ||
564 | usb_put_function_instance(fi); | ||
565 | return ERR_PTR(ret); | ||
566 | } | ||
567 | |||
568 | gi = container_of(group, struct gadget_info, functions_group); | ||
569 | |||
570 | mutex_lock(&gi->lock); | ||
571 | list_add_tail(&fi->cfs_list, &gi->available_func); | ||
572 | mutex_unlock(&gi->lock); | ||
573 | return &fi->group; | ||
574 | } | ||
575 | |||
576 | static void function_drop( | ||
577 | struct config_group *group, | ||
578 | struct config_item *item) | ||
579 | { | ||
580 | struct usb_function_instance *fi = to_usb_function_instance(item); | ||
581 | struct gadget_info *gi; | ||
582 | |||
583 | gi = container_of(group, struct gadget_info, functions_group); | ||
584 | |||
585 | mutex_lock(&gi->lock); | ||
586 | list_del(&fi->cfs_list); | ||
587 | mutex_unlock(&gi->lock); | ||
588 | config_item_put(item); | ||
589 | } | ||
590 | |||
591 | static struct configfs_group_operations functions_ops = { | ||
592 | .make_group = &function_make, | ||
593 | .drop_item = &function_drop, | ||
594 | }; | ||
595 | |||
596 | static struct config_item_type functions_type = { | ||
597 | .ct_group_ops = &functions_ops, | ||
598 | .ct_owner = THIS_MODULE, | ||
599 | }; | ||
600 | |||
601 | CONFIGFS_ATTR_STRUCT(gadget_config_name); | ||
602 | GS_STRINGS_RW(gadget_config_name, configuration); | ||
603 | |||
604 | static struct configfs_attribute *gadget_config_name_langid_attrs[] = { | ||
605 | &gadget_config_name_configuration.attr, | ||
606 | NULL, | ||
607 | }; | ||
608 | |||
609 | static void gadget_config_name_attr_release(struct config_item *item) | ||
610 | { | ||
611 | struct gadget_config_name *cn = to_gadget_config_name(item); | ||
612 | |||
613 | kfree(cn->configuration); | ||
614 | |||
615 | list_del(&cn->list); | ||
616 | kfree(cn); | ||
617 | } | ||
618 | |||
619 | USB_CONFIG_STRING_RW_OPS(gadget_config_name); | ||
620 | USB_CONFIG_STRINGS_LANG(gadget_config_name, config_usb_cfg); | ||
621 | |||
622 | static struct config_group *config_desc_make( | ||
623 | struct config_group *group, | ||
624 | const char *name) | ||
625 | { | ||
626 | struct gadget_info *gi; | ||
627 | struct config_usb_cfg *cfg; | ||
628 | char buf[MAX_NAME_LEN]; | ||
629 | char *num_str; | ||
630 | u8 num; | ||
631 | int ret; | ||
632 | |||
633 | gi = container_of(group, struct gadget_info, configs_group); | ||
634 | ret = snprintf(buf, MAX_NAME_LEN, "%s", name); | ||
635 | if (ret >= MAX_NAME_LEN) | ||
636 | return ERR_PTR(-ENAMETOOLONG); | ||
637 | |||
638 | num_str = strchr(buf, '.'); | ||
639 | if (!num_str) { | ||
640 | pr_err("Unable to locate . in name.bConfigurationValue\n"); | ||
641 | return ERR_PTR(-EINVAL); | ||
642 | } | ||
643 | |||
644 | *num_str = '\0'; | ||
645 | num_str++; | ||
646 | |||
647 | if (!strlen(buf)) | ||
648 | return ERR_PTR(-EINVAL); | ||
649 | |||
650 | ret = kstrtou8(num_str, 0, &num); | ||
651 | if (ret) | ||
652 | return ERR_PTR(ret); | ||
653 | |||
654 | cfg = kzalloc(sizeof(*cfg), GFP_KERNEL); | ||
655 | if (!cfg) | ||
656 | return ERR_PTR(-ENOMEM); | ||
657 | cfg->c.label = kstrdup(buf, GFP_KERNEL); | ||
658 | if (!cfg->c.label) { | ||
659 | ret = -ENOMEM; | ||
660 | goto err; | ||
661 | } | ||
662 | cfg->c.bConfigurationValue = num; | ||
663 | cfg->c.MaxPower = CONFIG_USB_GADGET_VBUS_DRAW; | ||
664 | cfg->c.bmAttributes = USB_CONFIG_ATT_ONE; | ||
665 | INIT_LIST_HEAD(&cfg->string_list); | ||
666 | INIT_LIST_HEAD(&cfg->func_list); | ||
667 | |||
668 | cfg->group.default_groups = cfg->default_groups; | ||
669 | cfg->default_groups[0] = &cfg->strings_group; | ||
670 | |||
671 | config_group_init_type_name(&cfg->group, name, | ||
672 | &gadget_config_type); | ||
673 | config_group_init_type_name(&cfg->strings_group, "strings", | ||
674 | &gadget_config_name_strings_type); | ||
675 | |||
676 | ret = usb_add_config_only(&gi->cdev, &cfg->c); | ||
677 | if (ret) | ||
678 | goto err; | ||
679 | |||
680 | return &cfg->group; | ||
681 | err: | ||
682 | kfree(cfg->c.label); | ||
683 | kfree(cfg); | ||
684 | return ERR_PTR(ret); | ||
685 | } | ||
686 | |||
687 | static void config_desc_drop( | ||
688 | struct config_group *group, | ||
689 | struct config_item *item) | ||
690 | { | ||
691 | config_item_put(item); | ||
692 | } | ||
693 | |||
694 | static struct configfs_group_operations config_desc_ops = { | ||
695 | .make_group = &config_desc_make, | ||
696 | .drop_item = &config_desc_drop, | ||
697 | }; | ||
698 | |||
699 | static struct config_item_type config_desc_type = { | ||
700 | .ct_group_ops = &config_desc_ops, | ||
701 | .ct_owner = THIS_MODULE, | ||
702 | }; | ||
703 | |||
704 | CONFIGFS_ATTR_STRUCT(gadget_strings); | ||
705 | GS_STRINGS_RW(gadget_strings, manufacturer); | ||
706 | GS_STRINGS_RW(gadget_strings, product); | ||
707 | GS_STRINGS_RW(gadget_strings, serialnumber); | ||
708 | |||
709 | static struct configfs_attribute *gadget_strings_langid_attrs[] = { | ||
710 | &gadget_strings_manufacturer.attr, | ||
711 | &gadget_strings_product.attr, | ||
712 | &gadget_strings_serialnumber.attr, | ||
713 | NULL, | ||
714 | }; | ||
715 | |||
716 | static void gadget_strings_attr_release(struct config_item *item) | ||
717 | { | ||
718 | struct gadget_strings *gs = to_gadget_strings(item); | ||
719 | |||
720 | kfree(gs->manufacturer); | ||
721 | kfree(gs->product); | ||
722 | kfree(gs->serialnumber); | ||
723 | |||
724 | list_del(&gs->list); | ||
725 | kfree(gs); | ||
726 | } | ||
727 | |||
728 | USB_CONFIG_STRING_RW_OPS(gadget_strings); | ||
729 | USB_CONFIG_STRINGS_LANG(gadget_strings, gadget_info); | ||
730 | |||
731 | static int configfs_do_nothing(struct usb_composite_dev *cdev) | ||
732 | { | ||
733 | __WARN(); | ||
734 | return -EINVAL; | ||
735 | } | ||
736 | |||
737 | int composite_dev_prepare(struct usb_composite_driver *composite, | ||
738 | struct usb_composite_dev *dev); | ||
739 | |||
740 | static void purge_configs_funcs(struct gadget_info *gi) | ||
741 | { | ||
742 | struct usb_configuration *c; | ||
743 | |||
744 | list_for_each_entry(c, &gi->cdev.configs, list) { | ||
745 | struct usb_function *f, *tmp; | ||
746 | struct config_usb_cfg *cfg; | ||
747 | |||
748 | cfg = container_of(c, struct config_usb_cfg, c); | ||
749 | |||
750 | list_for_each_entry_safe(f, tmp, &c->functions, list) { | ||
751 | |||
752 | list_move_tail(&f->list, &cfg->func_list); | ||
753 | if (f->unbind) { | ||
754 | dev_err(&gi->cdev.gadget->dev, "unbind function" | ||
755 | " '%s'/%p\n", f->name, f); | ||
756 | f->unbind(c, f); | ||
757 | } | ||
758 | } | ||
759 | c->next_interface_id = 0; | ||
760 | c->superspeed = 0; | ||
761 | c->highspeed = 0; | ||
762 | c->fullspeed = 0; | ||
763 | } | ||
764 | } | ||
765 | |||
766 | static int configfs_composite_bind(struct usb_gadget *gadget, | ||
767 | struct usb_gadget_driver *gdriver) | ||
768 | { | ||
769 | struct usb_composite_driver *composite = to_cdriver(gdriver); | ||
770 | struct gadget_info *gi = container_of(composite, | ||
771 | struct gadget_info, composite); | ||
772 | struct usb_composite_dev *cdev = &gi->cdev; | ||
773 | struct usb_configuration *c; | ||
774 | struct usb_string *s; | ||
775 | unsigned i; | ||
776 | int ret; | ||
777 | |||
778 | /* the gi->lock is hold by the caller */ | ||
779 | cdev->gadget = gadget; | ||
780 | set_gadget_data(gadget, cdev); | ||
781 | ret = composite_dev_prepare(composite, cdev); | ||
782 | if (ret) | ||
783 | return ret; | ||
784 | /* and now the gadget bind */ | ||
785 | ret = -EINVAL; | ||
786 | |||
787 | if (list_empty(&gi->cdev.configs)) { | ||
788 | pr_err("Need atleast one configuration in %s.\n", | ||
789 | gi->composite.name); | ||
790 | goto err_comp_cleanup; | ||
791 | } | ||
792 | |||
793 | |||
794 | list_for_each_entry(c, &gi->cdev.configs, list) { | ||
795 | struct config_usb_cfg *cfg; | ||
796 | |||
797 | cfg = container_of(c, struct config_usb_cfg, c); | ||
798 | if (list_empty(&cfg->func_list)) { | ||
799 | pr_err("Config %s/%d of %s needs atleast one function.\n", | ||
800 | c->label, c->bConfigurationValue, | ||
801 | gi->composite.name); | ||
802 | goto err_comp_cleanup; | ||
803 | } | ||
804 | } | ||
805 | |||
806 | /* init all strings */ | ||
807 | if (!list_empty(&gi->string_list)) { | ||
808 | struct gadget_strings *gs; | ||
809 | |||
810 | i = 0; | ||
811 | list_for_each_entry(gs, &gi->string_list, list) { | ||
812 | |||
813 | gi->gstrings[i] = &gs->stringtab_dev; | ||
814 | gs->stringtab_dev.strings = gs->strings; | ||
815 | gs->strings[USB_GADGET_MANUFACTURER_IDX].s = | ||
816 | gs->manufacturer; | ||
817 | gs->strings[USB_GADGET_PRODUCT_IDX].s = gs->product; | ||
818 | gs->strings[USB_GADGET_SERIAL_IDX].s = gs->serialnumber; | ||
819 | i++; | ||
820 | } | ||
821 | gi->gstrings[i] = NULL; | ||
822 | s = usb_gstrings_attach(&gi->cdev, gi->gstrings, | ||
823 | USB_GADGET_FIRST_AVAIL_IDX); | ||
824 | if (IS_ERR(s)) | ||
825 | goto err_comp_cleanup; | ||
826 | |||
827 | gi->cdev.desc.iManufacturer = s[USB_GADGET_MANUFACTURER_IDX].id; | ||
828 | gi->cdev.desc.iProduct = s[USB_GADGET_PRODUCT_IDX].id; | ||
829 | gi->cdev.desc.iSerialNumber = s[USB_GADGET_SERIAL_IDX].id; | ||
830 | } | ||
831 | |||
832 | /* Go through all configs, attach all functions */ | ||
833 | list_for_each_entry(c, &gi->cdev.configs, list) { | ||
834 | struct config_usb_cfg *cfg; | ||
835 | struct usb_function *f; | ||
836 | struct usb_function *tmp; | ||
837 | struct gadget_config_name *cn; | ||
838 | |||
839 | cfg = container_of(c, struct config_usb_cfg, c); | ||
840 | if (!list_empty(&cfg->string_list)) { | ||
841 | i = 0; | ||
842 | list_for_each_entry(cn, &cfg->string_list, list) { | ||
843 | cfg->gstrings[i] = &cn->stringtab_dev; | ||
844 | cn->stringtab_dev.strings = &cn->strings; | ||
845 | cn->strings.s = cn->configuration; | ||
846 | i++; | ||
847 | } | ||
848 | cfg->gstrings[i] = NULL; | ||
849 | s = usb_gstrings_attach(&gi->cdev, cfg->gstrings, 1); | ||
850 | if (IS_ERR(s)) | ||
851 | goto err_comp_cleanup; | ||
852 | c->iConfiguration = s[0].id; | ||
853 | } | ||
854 | |||
855 | list_for_each_entry_safe(f, tmp, &cfg->func_list, list) { | ||
856 | list_del(&f->list); | ||
857 | ret = usb_add_function(c, f); | ||
858 | if (ret) | ||
859 | goto err_purge_funcs; | ||
860 | } | ||
861 | usb_ep_autoconfig_reset(cdev->gadget); | ||
862 | } | ||
863 | usb_ep_autoconfig_reset(cdev->gadget); | ||
864 | return 0; | ||
865 | |||
866 | err_purge_funcs: | ||
867 | purge_configs_funcs(gi); | ||
868 | err_comp_cleanup: | ||
869 | composite_dev_cleanup(cdev); | ||
870 | return ret; | ||
871 | } | ||
872 | |||
873 | static void configfs_composite_unbind(struct usb_gadget *gadget) | ||
874 | { | ||
875 | struct usb_composite_dev *cdev; | ||
876 | struct gadget_info *gi; | ||
877 | |||
878 | /* the gi->lock is hold by the caller */ | ||
879 | |||
880 | cdev = get_gadget_data(gadget); | ||
881 | gi = container_of(cdev, struct gadget_info, cdev); | ||
882 | |||
883 | purge_configs_funcs(gi); | ||
884 | composite_dev_cleanup(cdev); | ||
885 | usb_ep_autoconfig_reset(cdev->gadget); | ||
886 | cdev->gadget = NULL; | ||
887 | set_gadget_data(gadget, NULL); | ||
888 | } | ||
889 | |||
890 | static const struct usb_gadget_driver configfs_driver_template = { | ||
891 | .bind = configfs_composite_bind, | ||
892 | .unbind = configfs_composite_unbind, | ||
893 | |||
894 | .setup = composite_setup, | ||
895 | .disconnect = composite_disconnect, | ||
896 | |||
897 | .max_speed = USB_SPEED_SUPER, | ||
898 | .driver = { | ||
899 | .owner = THIS_MODULE, | ||
900 | .name = "configfs-gadget", | ||
901 | }, | ||
902 | }; | ||
903 | |||
904 | static struct config_group *gadgets_make( | ||
905 | struct config_group *group, | ||
906 | const char *name) | ||
907 | { | ||
908 | struct gadget_info *gi; | ||
909 | |||
910 | gi = kzalloc(sizeof(*gi), GFP_KERNEL); | ||
911 | if (!gi) | ||
912 | return ERR_PTR(-ENOMEM); | ||
913 | |||
914 | gi->group.default_groups = gi->default_groups; | ||
915 | gi->group.default_groups[0] = &gi->functions_group; | ||
916 | gi->group.default_groups[1] = &gi->configs_group; | ||
917 | gi->group.default_groups[2] = &gi->strings_group; | ||
918 | |||
919 | config_group_init_type_name(&gi->functions_group, "functions", | ||
920 | &functions_type); | ||
921 | config_group_init_type_name(&gi->configs_group, "configs", | ||
922 | &config_desc_type); | ||
923 | config_group_init_type_name(&gi->strings_group, "strings", | ||
924 | &gadget_strings_strings_type); | ||
925 | |||
926 | gi->composite.bind = configfs_do_nothing; | ||
927 | gi->composite.unbind = configfs_do_nothing; | ||
928 | gi->composite.suspend = NULL; | ||
929 | gi->composite.resume = NULL; | ||
930 | gi->composite.max_speed = USB_SPEED_SUPER; | ||
931 | |||
932 | mutex_init(&gi->lock); | ||
933 | INIT_LIST_HEAD(&gi->string_list); | ||
934 | INIT_LIST_HEAD(&gi->available_func); | ||
935 | |||
936 | composite_init_dev(&gi->cdev); | ||
937 | gi->cdev.desc.bLength = USB_DT_DEVICE_SIZE; | ||
938 | gi->cdev.desc.bDescriptorType = USB_DT_DEVICE; | ||
939 | gi->cdev.desc.bcdDevice = cpu_to_le16(get_default_bcdDevice()); | ||
940 | |||
941 | gi->composite.gadget_driver = configfs_driver_template; | ||
942 | |||
943 | gi->composite.gadget_driver.function = kstrdup(name, GFP_KERNEL); | ||
944 | gi->composite.name = gi->composite.gadget_driver.function; | ||
945 | |||
946 | if (!gi->composite.gadget_driver.function) | ||
947 | goto err; | ||
948 | |||
949 | #ifdef CONFIG_USB_OTG | ||
950 | gi->otg.bLength = sizeof(struct usb_otg_descriptor); | ||
951 | gi->otg.bDescriptorType = USB_DT_OTG; | ||
952 | gi->otg.bmAttributes = USB_OTG_SRP | USB_OTG_HNP; | ||
953 | #endif | ||
954 | |||
955 | config_group_init_type_name(&gi->group, name, | ||
956 | &gadget_root_type); | ||
957 | return &gi->group; | ||
958 | err: | ||
959 | kfree(gi); | ||
960 | return ERR_PTR(-ENOMEM); | ||
961 | } | ||
962 | |||
963 | static void gadgets_drop(struct config_group *group, struct config_item *item) | ||
964 | { | ||
965 | config_item_put(item); | ||
966 | } | ||
967 | |||
968 | static struct configfs_group_operations gadgets_ops = { | ||
969 | .make_group = &gadgets_make, | ||
970 | .drop_item = &gadgets_drop, | ||
971 | }; | ||
972 | |||
973 | static struct config_item_type gadgets_type = { | ||
974 | .ct_group_ops = &gadgets_ops, | ||
975 | .ct_owner = THIS_MODULE, | ||
976 | }; | ||
977 | |||
978 | static struct configfs_subsystem gadget_subsys = { | ||
979 | .su_group = { | ||
980 | .cg_item = { | ||
981 | .ci_namebuf = "usb_gadget", | ||
982 | .ci_type = &gadgets_type, | ||
983 | }, | ||
984 | }, | ||
985 | .su_mutex = __MUTEX_INITIALIZER(gadget_subsys.su_mutex), | ||
986 | }; | ||
987 | |||
988 | static int __init gadget_cfs_init(void) | ||
989 | { | ||
990 | int ret; | ||
991 | |||
992 | config_group_init(&gadget_subsys.su_group); | ||
993 | |||
994 | ret = configfs_register_subsystem(&gadget_subsys); | ||
995 | return ret; | ||
996 | } | ||
997 | module_init(gadget_cfs_init); | ||
998 | |||
999 | static void __exit gadget_cfs_exit(void) | ||
1000 | { | ||
1001 | configfs_unregister_subsystem(&gadget_subsys); | ||
1002 | } | ||
1003 | module_exit(gadget_cfs_exit); | ||
diff --git a/drivers/usb/gadget/f_acm.c b/drivers/usb/gadget/f_acm.c index ba7daaaad148..4b7e33e5d9c6 100644 --- a/drivers/usb/gadget/f_acm.c +++ b/drivers/usb/gadget/f_acm.c | |||
@@ -763,6 +763,59 @@ static struct usb_function *acm_alloc_func(struct usb_function_instance *fi) | |||
763 | return &acm->port.func; | 763 | return &acm->port.func; |
764 | } | 764 | } |
765 | 765 | ||
766 | static inline struct f_serial_opts *to_f_serial_opts(struct config_item *item) | ||
767 | { | ||
768 | return container_of(to_config_group(item), struct f_serial_opts, | ||
769 | func_inst.group); | ||
770 | } | ||
771 | |||
772 | CONFIGFS_ATTR_STRUCT(f_serial_opts); | ||
773 | static ssize_t f_acm_attr_show(struct config_item *item, | ||
774 | struct configfs_attribute *attr, | ||
775 | char *page) | ||
776 | { | ||
777 | struct f_serial_opts *opts = to_f_serial_opts(item); | ||
778 | struct f_serial_opts_attribute *f_serial_opts_attr = | ||
779 | container_of(attr, struct f_serial_opts_attribute, attr); | ||
780 | ssize_t ret = 0; | ||
781 | |||
782 | if (f_serial_opts_attr->show) | ||
783 | ret = f_serial_opts_attr->show(opts, page); | ||
784 | return ret; | ||
785 | } | ||
786 | |||
787 | static void acm_attr_release(struct config_item *item) | ||
788 | { | ||
789 | struct f_serial_opts *opts = to_f_serial_opts(item); | ||
790 | |||
791 | usb_put_function_instance(&opts->func_inst); | ||
792 | } | ||
793 | |||
794 | static struct configfs_item_operations acm_item_ops = { | ||
795 | .release = acm_attr_release, | ||
796 | .show_attribute = f_acm_attr_show, | ||
797 | }; | ||
798 | |||
799 | static ssize_t f_acm_port_num_show(struct f_serial_opts *opts, char *page) | ||
800 | { | ||
801 | return sprintf(page, "%u\n", opts->port_num); | ||
802 | } | ||
803 | |||
804 | static struct f_serial_opts_attribute f_acm_port_num = | ||
805 | __CONFIGFS_ATTR_RO(port_num, f_acm_port_num_show); | ||
806 | |||
807 | |||
808 | static struct configfs_attribute *acm_attrs[] = { | ||
809 | &f_acm_port_num.attr, | ||
810 | NULL, | ||
811 | }; | ||
812 | |||
813 | static struct config_item_type acm_func_type = { | ||
814 | .ct_item_ops = &acm_item_ops, | ||
815 | .ct_attrs = acm_attrs, | ||
816 | .ct_owner = THIS_MODULE, | ||
817 | }; | ||
818 | |||
766 | static void acm_free_instance(struct usb_function_instance *fi) | 819 | static void acm_free_instance(struct usb_function_instance *fi) |
767 | { | 820 | { |
768 | struct f_serial_opts *opts; | 821 | struct f_serial_opts *opts; |
@@ -786,6 +839,8 @@ static struct usb_function_instance *acm_alloc_instance(void) | |||
786 | kfree(opts); | 839 | kfree(opts); |
787 | return ERR_PTR(ret); | 840 | return ERR_PTR(ret); |
788 | } | 841 | } |
842 | config_group_init_type_name(&opts->func_inst.group, "", | ||
843 | &acm_func_type); | ||
789 | return &opts->func_inst; | 844 | return &opts->func_inst; |
790 | } | 845 | } |
791 | DECLARE_USB_FUNCTION_INIT(acm, acm_alloc_instance, acm_alloc_func); | 846 | DECLARE_USB_FUNCTION_INIT(acm, acm_alloc_instance, acm_alloc_func); |
diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h index 8860594d6364..5e61589fc166 100644 --- a/include/linux/usb/composite.h +++ b/include/linux/usb/composite.h | |||
@@ -39,6 +39,7 @@ | |||
39 | #include <linux/usb/ch9.h> | 39 | #include <linux/usb/ch9.h> |
40 | #include <linux/usb/gadget.h> | 40 | #include <linux/usb/gadget.h> |
41 | #include <linux/log2.h> | 41 | #include <linux/log2.h> |
42 | #include <linux/configfs.h> | ||
42 | 43 | ||
43 | /* | 44 | /* |
44 | * USB function drivers should return USB_GADGET_DELAYED_STATUS if they | 45 | * USB function drivers should return USB_GADGET_DELAYED_STATUS if they |
@@ -464,6 +465,8 @@ struct usb_function_driver { | |||
464 | }; | 465 | }; |
465 | 466 | ||
466 | struct usb_function_instance { | 467 | struct usb_function_instance { |
468 | struct config_group group; | ||
469 | struct list_head cfs_list; | ||
467 | struct usb_function_driver *fd; | 470 | struct usb_function_driver *fd; |
468 | void (*free_func_inst)(struct usb_function_instance *inst); | 471 | void (*free_func_inst)(struct usb_function_instance *inst); |
469 | }; | 472 | }; |
diff --git a/include/linux/usb/gadget_configfs.h b/include/linux/usb/gadget_configfs.h new file mode 100644 index 000000000000..d74c0ae989d5 --- /dev/null +++ b/include/linux/usb/gadget_configfs.h | |||
@@ -0,0 +1,110 @@ | |||
1 | #ifndef __GADGET_CONFIGFS__ | ||
2 | #define __GADGET_CONFIGFS__ | ||
3 | |||
4 | #include <linux/configfs.h> | ||
5 | |||
6 | int check_user_usb_string(const char *name, | ||
7 | struct usb_gadget_strings *stringtab_dev); | ||
8 | |||
9 | #define GS_STRINGS_W(__struct, __name) \ | ||
10 | static ssize_t __struct##_##__name##_store(struct __struct *gs, \ | ||
11 | const char *page, size_t len) \ | ||
12 | { \ | ||
13 | int ret; \ | ||
14 | \ | ||
15 | ret = usb_string_copy(page, &gs->__name); \ | ||
16 | if (ret) \ | ||
17 | return ret; \ | ||
18 | return len; \ | ||
19 | } | ||
20 | |||
21 | #define GS_STRINGS_R(__struct, __name) \ | ||
22 | static ssize_t __struct##_##__name##_show(struct __struct *gs, \ | ||
23 | char *page) \ | ||
24 | { \ | ||
25 | return sprintf(page, "%s\n", gs->__name ?: ""); \ | ||
26 | } | ||
27 | |||
28 | #define GS_STRING_ITEM_ATTR(struct_name, name) \ | ||
29 | static struct struct_name##_attribute struct_name##_##name = \ | ||
30 | __CONFIGFS_ATTR(name, S_IRUGO | S_IWUSR, \ | ||
31 | struct_name##_##name##_show, \ | ||
32 | struct_name##_##name##_store) | ||
33 | |||
34 | #define GS_STRINGS_RW(struct_name, _name) \ | ||
35 | GS_STRINGS_R(struct_name, _name) \ | ||
36 | GS_STRINGS_W(struct_name, _name) \ | ||
37 | GS_STRING_ITEM_ATTR(struct_name, _name) | ||
38 | |||
39 | #define USB_CONFIG_STRING_RW_OPS(struct_in) \ | ||
40 | CONFIGFS_ATTR_OPS(struct_in); \ | ||
41 | \ | ||
42 | static struct configfs_item_operations struct_in##_langid_item_ops = { \ | ||
43 | .release = struct_in##_attr_release, \ | ||
44 | .show_attribute = struct_in##_attr_show, \ | ||
45 | .store_attribute = struct_in##_attr_store, \ | ||
46 | }; \ | ||
47 | \ | ||
48 | static struct config_item_type struct_in##_langid_type = { \ | ||
49 | .ct_item_ops = &struct_in##_langid_item_ops, \ | ||
50 | .ct_attrs = struct_in##_langid_attrs, \ | ||
51 | .ct_owner = THIS_MODULE, \ | ||
52 | } | ||
53 | |||
54 | #define USB_CONFIG_STRINGS_LANG(struct_in, struct_member) \ | ||
55 | static struct config_group *struct_in##_strings_make( \ | ||
56 | struct config_group *group, \ | ||
57 | const char *name) \ | ||
58 | { \ | ||
59 | struct struct_member *gi; \ | ||
60 | struct struct_in *gs; \ | ||
61 | struct struct_in *new; \ | ||
62 | int langs = 0; \ | ||
63 | int ret; \ | ||
64 | \ | ||
65 | new = kzalloc(sizeof(*new), GFP_KERNEL); \ | ||
66 | if (!new) \ | ||
67 | return ERR_PTR(-ENOMEM); \ | ||
68 | \ | ||
69 | ret = check_user_usb_string(name, &new->stringtab_dev); \ | ||
70 | if (ret) \ | ||
71 | goto err; \ | ||
72 | config_group_init_type_name(&new->group, name, \ | ||
73 | &struct_in##_langid_type); \ | ||
74 | \ | ||
75 | gi = container_of(group, struct struct_member, strings_group); \ | ||
76 | ret = -EEXIST; \ | ||
77 | list_for_each_entry(gs, &gi->string_list, list) { \ | ||
78 | if (gs->stringtab_dev.language == new->stringtab_dev.language) \ | ||
79 | goto err; \ | ||
80 | langs++; \ | ||
81 | } \ | ||
82 | ret = -EOVERFLOW; \ | ||
83 | if (langs >= MAX_USB_STRING_LANGS) \ | ||
84 | goto err; \ | ||
85 | \ | ||
86 | list_add_tail(&new->list, &gi->string_list); \ | ||
87 | return &new->group; \ | ||
88 | err: \ | ||
89 | kfree(new); \ | ||
90 | return ERR_PTR(ret); \ | ||
91 | } \ | ||
92 | \ | ||
93 | static void struct_in##_strings_drop( \ | ||
94 | struct config_group *group, \ | ||
95 | struct config_item *item) \ | ||
96 | { \ | ||
97 | config_item_put(item); \ | ||
98 | } \ | ||
99 | \ | ||
100 | static struct configfs_group_operations struct_in##_strings_ops = { \ | ||
101 | .make_group = &struct_in##_strings_make, \ | ||
102 | .drop_item = &struct_in##_strings_drop, \ | ||
103 | }; \ | ||
104 | \ | ||
105 | static struct config_item_type struct_in##_strings_type = { \ | ||
106 | .ct_group_ops = &struct_in##_strings_ops, \ | ||
107 | .ct_owner = THIS_MODULE, \ | ||
108 | } | ||
109 | |||
110 | #endif | ||