18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci#include <linux/configfs.h>
38c2ecf20Sopenharmony_ci#include <linux/module.h>
48c2ecf20Sopenharmony_ci#include <linux/slab.h>
58c2ecf20Sopenharmony_ci#include <linux/device.h>
68c2ecf20Sopenharmony_ci#include <linux/nls.h>
78c2ecf20Sopenharmony_ci#include <linux/usb/composite.h>
88c2ecf20Sopenharmony_ci#include <linux/usb/gadget_configfs.h>
98c2ecf20Sopenharmony_ci#include "configfs.h"
108c2ecf20Sopenharmony_ci#include "u_f.h"
118c2ecf20Sopenharmony_ci#include "u_os_desc.h"
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ciint check_user_usb_string(const char *name,
148c2ecf20Sopenharmony_ci		struct usb_gadget_strings *stringtab_dev)
158c2ecf20Sopenharmony_ci{
168c2ecf20Sopenharmony_ci	u16 num;
178c2ecf20Sopenharmony_ci	int ret;
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci	ret = kstrtou16(name, 0, &num);
208c2ecf20Sopenharmony_ci	if (ret)
218c2ecf20Sopenharmony_ci		return ret;
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci	if (!usb_validate_langid(num))
248c2ecf20Sopenharmony_ci		return -EINVAL;
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci	stringtab_dev->language = num;
278c2ecf20Sopenharmony_ci	return 0;
288c2ecf20Sopenharmony_ci}
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci#define MAX_NAME_LEN	40
318c2ecf20Sopenharmony_ci#define MAX_USB_STRING_LANGS 2
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_cistatic const struct usb_descriptor_header *otg_desc[2];
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_cistruct gadget_info {
368c2ecf20Sopenharmony_ci	struct config_group group;
378c2ecf20Sopenharmony_ci	struct config_group functions_group;
388c2ecf20Sopenharmony_ci	struct config_group configs_group;
398c2ecf20Sopenharmony_ci	struct config_group strings_group;
408c2ecf20Sopenharmony_ci	struct config_group os_desc_group;
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci	struct mutex lock;
438c2ecf20Sopenharmony_ci	struct usb_gadget_strings *gstrings[MAX_USB_STRING_LANGS + 1];
448c2ecf20Sopenharmony_ci	struct list_head string_list;
458c2ecf20Sopenharmony_ci	struct list_head available_func;
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci	struct usb_composite_driver composite;
488c2ecf20Sopenharmony_ci	struct usb_composite_dev cdev;
498c2ecf20Sopenharmony_ci	bool use_os_desc;
508c2ecf20Sopenharmony_ci	char b_vendor_code;
518c2ecf20Sopenharmony_ci	char qw_sign[OS_STRING_QW_SIGN_LEN];
528c2ecf20Sopenharmony_ci	spinlock_t spinlock;
538c2ecf20Sopenharmony_ci	bool unbind;
548c2ecf20Sopenharmony_ci};
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_cistatic inline struct gadget_info *to_gadget_info(struct config_item *item)
578c2ecf20Sopenharmony_ci{
588c2ecf20Sopenharmony_ci	 return container_of(to_config_group(item), struct gadget_info, group);
598c2ecf20Sopenharmony_ci}
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_cistruct config_usb_cfg {
628c2ecf20Sopenharmony_ci	struct config_group group;
638c2ecf20Sopenharmony_ci	struct config_group strings_group;
648c2ecf20Sopenharmony_ci	struct list_head string_list;
658c2ecf20Sopenharmony_ci	struct usb_configuration c;
668c2ecf20Sopenharmony_ci	struct list_head func_list;
678c2ecf20Sopenharmony_ci	struct usb_gadget_strings *gstrings[MAX_USB_STRING_LANGS + 1];
688c2ecf20Sopenharmony_ci};
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_cistatic inline struct config_usb_cfg *to_config_usb_cfg(struct config_item *item)
718c2ecf20Sopenharmony_ci{
728c2ecf20Sopenharmony_ci	return container_of(to_config_group(item), struct config_usb_cfg,
738c2ecf20Sopenharmony_ci			group);
748c2ecf20Sopenharmony_ci}
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_cistruct gadget_strings {
778c2ecf20Sopenharmony_ci	struct usb_gadget_strings stringtab_dev;
788c2ecf20Sopenharmony_ci	struct usb_string strings[USB_GADGET_FIRST_AVAIL_IDX];
798c2ecf20Sopenharmony_ci	char *manufacturer;
808c2ecf20Sopenharmony_ci	char *product;
818c2ecf20Sopenharmony_ci	char *serialnumber;
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	struct config_group group;
848c2ecf20Sopenharmony_ci	struct list_head list;
858c2ecf20Sopenharmony_ci};
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_cistruct os_desc {
888c2ecf20Sopenharmony_ci	struct config_group group;
898c2ecf20Sopenharmony_ci};
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_cistruct gadget_config_name {
928c2ecf20Sopenharmony_ci	struct usb_gadget_strings stringtab_dev;
938c2ecf20Sopenharmony_ci	struct usb_string strings;
948c2ecf20Sopenharmony_ci	char *configuration;
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci	struct config_group group;
978c2ecf20Sopenharmony_ci	struct list_head list;
988c2ecf20Sopenharmony_ci};
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci#define USB_MAX_STRING_WITH_NULL_LEN	(USB_MAX_STRING_LEN+1)
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_cistatic int usb_string_copy(const char *s, char **s_copy)
1038c2ecf20Sopenharmony_ci{
1048c2ecf20Sopenharmony_ci	int ret;
1058c2ecf20Sopenharmony_ci	char *str;
1068c2ecf20Sopenharmony_ci	char *copy = *s_copy;
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci	ret = strlen(s);
1098c2ecf20Sopenharmony_ci	if (ret > USB_MAX_STRING_LEN)
1108c2ecf20Sopenharmony_ci		return -EOVERFLOW;
1118c2ecf20Sopenharmony_ci	if (ret < 1)
1128c2ecf20Sopenharmony_ci		return -EINVAL;
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci	if (copy) {
1158c2ecf20Sopenharmony_ci		str = copy;
1168c2ecf20Sopenharmony_ci	} else {
1178c2ecf20Sopenharmony_ci		str = kmalloc(USB_MAX_STRING_WITH_NULL_LEN, GFP_KERNEL);
1188c2ecf20Sopenharmony_ci		if (!str)
1198c2ecf20Sopenharmony_ci			return -ENOMEM;
1208c2ecf20Sopenharmony_ci	}
1218c2ecf20Sopenharmony_ci	strcpy(str, s);
1228c2ecf20Sopenharmony_ci	if (str[ret - 1] == '\n')
1238c2ecf20Sopenharmony_ci		str[ret - 1] = '\0';
1248c2ecf20Sopenharmony_ci	*s_copy = str;
1258c2ecf20Sopenharmony_ci	return 0;
1268c2ecf20Sopenharmony_ci}
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci#define GI_DEVICE_DESC_SIMPLE_R_u8(__name)	\
1298c2ecf20Sopenharmony_cistatic ssize_t gadget_dev_desc_##__name##_show(struct config_item *item, \
1308c2ecf20Sopenharmony_ci			char *page)	\
1318c2ecf20Sopenharmony_ci{	\
1328c2ecf20Sopenharmony_ci	return sprintf(page, "0x%02x\n", \
1338c2ecf20Sopenharmony_ci		to_gadget_info(item)->cdev.desc.__name); \
1348c2ecf20Sopenharmony_ci}
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci#define GI_DEVICE_DESC_SIMPLE_R_u16(__name)	\
1378c2ecf20Sopenharmony_cistatic ssize_t gadget_dev_desc_##__name##_show(struct config_item *item, \
1388c2ecf20Sopenharmony_ci			char *page)	\
1398c2ecf20Sopenharmony_ci{	\
1408c2ecf20Sopenharmony_ci	return sprintf(page, "0x%04x\n", \
1418c2ecf20Sopenharmony_ci		le16_to_cpup(&to_gadget_info(item)->cdev.desc.__name)); \
1428c2ecf20Sopenharmony_ci}
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci#define GI_DEVICE_DESC_SIMPLE_W_u8(_name)		\
1468c2ecf20Sopenharmony_cistatic ssize_t gadget_dev_desc_##_name##_store(struct config_item *item, \
1478c2ecf20Sopenharmony_ci		const char *page, size_t len)		\
1488c2ecf20Sopenharmony_ci{							\
1498c2ecf20Sopenharmony_ci	u8 val;						\
1508c2ecf20Sopenharmony_ci	int ret;					\
1518c2ecf20Sopenharmony_ci	ret = kstrtou8(page, 0, &val);			\
1528c2ecf20Sopenharmony_ci	if (ret)					\
1538c2ecf20Sopenharmony_ci		return ret;				\
1548c2ecf20Sopenharmony_ci	to_gadget_info(item)->cdev.desc._name = val;	\
1558c2ecf20Sopenharmony_ci	return len;					\
1568c2ecf20Sopenharmony_ci}
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci#define GI_DEVICE_DESC_SIMPLE_W_u16(_name)	\
1598c2ecf20Sopenharmony_cistatic ssize_t gadget_dev_desc_##_name##_store(struct config_item *item, \
1608c2ecf20Sopenharmony_ci		const char *page, size_t len)		\
1618c2ecf20Sopenharmony_ci{							\
1628c2ecf20Sopenharmony_ci	u16 val;					\
1638c2ecf20Sopenharmony_ci	int ret;					\
1648c2ecf20Sopenharmony_ci	ret = kstrtou16(page, 0, &val);			\
1658c2ecf20Sopenharmony_ci	if (ret)					\
1668c2ecf20Sopenharmony_ci		return ret;				\
1678c2ecf20Sopenharmony_ci	to_gadget_info(item)->cdev.desc._name = cpu_to_le16p(&val);	\
1688c2ecf20Sopenharmony_ci	return len;					\
1698c2ecf20Sopenharmony_ci}
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci#define GI_DEVICE_DESC_SIMPLE_RW(_name, _type)	\
1728c2ecf20Sopenharmony_ci	GI_DEVICE_DESC_SIMPLE_R_##_type(_name)	\
1738c2ecf20Sopenharmony_ci	GI_DEVICE_DESC_SIMPLE_W_##_type(_name)
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ciGI_DEVICE_DESC_SIMPLE_R_u16(bcdUSB);
1768c2ecf20Sopenharmony_ciGI_DEVICE_DESC_SIMPLE_RW(bDeviceClass, u8);
1778c2ecf20Sopenharmony_ciGI_DEVICE_DESC_SIMPLE_RW(bDeviceSubClass, u8);
1788c2ecf20Sopenharmony_ciGI_DEVICE_DESC_SIMPLE_RW(bDeviceProtocol, u8);
1798c2ecf20Sopenharmony_ciGI_DEVICE_DESC_SIMPLE_RW(bMaxPacketSize0, u8);
1808c2ecf20Sopenharmony_ciGI_DEVICE_DESC_SIMPLE_RW(idVendor, u16);
1818c2ecf20Sopenharmony_ciGI_DEVICE_DESC_SIMPLE_RW(idProduct, u16);
1828c2ecf20Sopenharmony_ciGI_DEVICE_DESC_SIMPLE_R_u16(bcdDevice);
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_cistatic ssize_t is_valid_bcd(u16 bcd_val)
1858c2ecf20Sopenharmony_ci{
1868c2ecf20Sopenharmony_ci	if ((bcd_val & 0xf) > 9)
1878c2ecf20Sopenharmony_ci		return -EINVAL;
1888c2ecf20Sopenharmony_ci	if (((bcd_val >> 4) & 0xf) > 9)
1898c2ecf20Sopenharmony_ci		return -EINVAL;
1908c2ecf20Sopenharmony_ci	if (((bcd_val >> 8) & 0xf) > 9)
1918c2ecf20Sopenharmony_ci		return -EINVAL;
1928c2ecf20Sopenharmony_ci	if (((bcd_val >> 12) & 0xf) > 9)
1938c2ecf20Sopenharmony_ci		return -EINVAL;
1948c2ecf20Sopenharmony_ci	return 0;
1958c2ecf20Sopenharmony_ci}
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_cistatic ssize_t gadget_dev_desc_bcdDevice_store(struct config_item *item,
1988c2ecf20Sopenharmony_ci		const char *page, size_t len)
1998c2ecf20Sopenharmony_ci{
2008c2ecf20Sopenharmony_ci	u16 bcdDevice;
2018c2ecf20Sopenharmony_ci	int ret;
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	ret = kstrtou16(page, 0, &bcdDevice);
2048c2ecf20Sopenharmony_ci	if (ret)
2058c2ecf20Sopenharmony_ci		return ret;
2068c2ecf20Sopenharmony_ci	ret = is_valid_bcd(bcdDevice);
2078c2ecf20Sopenharmony_ci	if (ret)
2088c2ecf20Sopenharmony_ci		return ret;
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci	to_gadget_info(item)->cdev.desc.bcdDevice = cpu_to_le16(bcdDevice);
2118c2ecf20Sopenharmony_ci	return len;
2128c2ecf20Sopenharmony_ci}
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_cistatic ssize_t gadget_dev_desc_bcdUSB_store(struct config_item *item,
2158c2ecf20Sopenharmony_ci		const char *page, size_t len)
2168c2ecf20Sopenharmony_ci{
2178c2ecf20Sopenharmony_ci	u16 bcdUSB;
2188c2ecf20Sopenharmony_ci	int ret;
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci	ret = kstrtou16(page, 0, &bcdUSB);
2218c2ecf20Sopenharmony_ci	if (ret)
2228c2ecf20Sopenharmony_ci		return ret;
2238c2ecf20Sopenharmony_ci	ret = is_valid_bcd(bcdUSB);
2248c2ecf20Sopenharmony_ci	if (ret)
2258c2ecf20Sopenharmony_ci		return ret;
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci	to_gadget_info(item)->cdev.desc.bcdUSB = cpu_to_le16(bcdUSB);
2288c2ecf20Sopenharmony_ci	return len;
2298c2ecf20Sopenharmony_ci}
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_cistatic ssize_t gadget_dev_desc_UDC_show(struct config_item *item, char *page)
2328c2ecf20Sopenharmony_ci{
2338c2ecf20Sopenharmony_ci	struct gadget_info *gi = to_gadget_info(item);
2348c2ecf20Sopenharmony_ci	char *udc_name;
2358c2ecf20Sopenharmony_ci	int ret;
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci	mutex_lock(&gi->lock);
2388c2ecf20Sopenharmony_ci	udc_name = gi->composite.gadget_driver.udc_name;
2398c2ecf20Sopenharmony_ci	ret = sprintf(page, "%s\n", udc_name ?: "");
2408c2ecf20Sopenharmony_ci	mutex_unlock(&gi->lock);
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci	return ret;
2438c2ecf20Sopenharmony_ci}
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_cistatic int unregister_gadget(struct gadget_info *gi)
2468c2ecf20Sopenharmony_ci{
2478c2ecf20Sopenharmony_ci	int ret;
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci	if (!gi->composite.gadget_driver.udc_name)
2508c2ecf20Sopenharmony_ci		return -ENODEV;
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci	ret = usb_gadget_unregister_driver(&gi->composite.gadget_driver);
2538c2ecf20Sopenharmony_ci	if (ret)
2548c2ecf20Sopenharmony_ci		return ret;
2558c2ecf20Sopenharmony_ci	kfree(gi->composite.gadget_driver.udc_name);
2568c2ecf20Sopenharmony_ci	gi->composite.gadget_driver.udc_name = NULL;
2578c2ecf20Sopenharmony_ci	return 0;
2588c2ecf20Sopenharmony_ci}
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_cistatic ssize_t gadget_dev_desc_UDC_store(struct config_item *item,
2618c2ecf20Sopenharmony_ci		const char *page, size_t len)
2628c2ecf20Sopenharmony_ci{
2638c2ecf20Sopenharmony_ci	struct gadget_info *gi = to_gadget_info(item);
2648c2ecf20Sopenharmony_ci	char *name;
2658c2ecf20Sopenharmony_ci	int ret;
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci	if (strlen(page) < len)
2688c2ecf20Sopenharmony_ci		return -EOVERFLOW;
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	name = kstrdup(page, GFP_KERNEL);
2718c2ecf20Sopenharmony_ci	if (!name)
2728c2ecf20Sopenharmony_ci		return -ENOMEM;
2738c2ecf20Sopenharmony_ci	if (name[len - 1] == '\n')
2748c2ecf20Sopenharmony_ci		name[len - 1] = '\0';
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ci	mutex_lock(&gi->lock);
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci	if (!strlen(name)) {
2798c2ecf20Sopenharmony_ci		ret = unregister_gadget(gi);
2808c2ecf20Sopenharmony_ci		if (ret)
2818c2ecf20Sopenharmony_ci			goto err;
2828c2ecf20Sopenharmony_ci		kfree(name);
2838c2ecf20Sopenharmony_ci	} else {
2848c2ecf20Sopenharmony_ci		if (gi->composite.gadget_driver.udc_name) {
2858c2ecf20Sopenharmony_ci			ret = -EBUSY;
2868c2ecf20Sopenharmony_ci			goto err;
2878c2ecf20Sopenharmony_ci		}
2888c2ecf20Sopenharmony_ci		gi->composite.gadget_driver.udc_name = name;
2898c2ecf20Sopenharmony_ci		ret = usb_gadget_probe_driver(&gi->composite.gadget_driver);
2908c2ecf20Sopenharmony_ci		if (ret) {
2918c2ecf20Sopenharmony_ci			gi->composite.gadget_driver.udc_name = NULL;
2928c2ecf20Sopenharmony_ci			goto err;
2938c2ecf20Sopenharmony_ci		}
2948c2ecf20Sopenharmony_ci	}
2958c2ecf20Sopenharmony_ci	mutex_unlock(&gi->lock);
2968c2ecf20Sopenharmony_ci	return len;
2978c2ecf20Sopenharmony_cierr:
2988c2ecf20Sopenharmony_ci	kfree(name);
2998c2ecf20Sopenharmony_ci	mutex_unlock(&gi->lock);
3008c2ecf20Sopenharmony_ci	return ret;
3018c2ecf20Sopenharmony_ci}
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_cistatic ssize_t gadget_dev_desc_max_speed_show(struct config_item *item,
3048c2ecf20Sopenharmony_ci					      char *page)
3058c2ecf20Sopenharmony_ci{
3068c2ecf20Sopenharmony_ci	enum usb_device_speed speed = to_gadget_info(item)->composite.max_speed;
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci	return sprintf(page, "%s\n", usb_speed_string(speed));
3098c2ecf20Sopenharmony_ci}
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_cistatic ssize_t gadget_dev_desc_max_speed_store(struct config_item *item,
3128c2ecf20Sopenharmony_ci					       const char *page, size_t len)
3138c2ecf20Sopenharmony_ci{
3148c2ecf20Sopenharmony_ci	struct gadget_info *gi = to_gadget_info(item);
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci	mutex_lock(&gi->lock);
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci	/* Prevent changing of max_speed after the driver is binded */
3198c2ecf20Sopenharmony_ci	if (gi->composite.gadget_driver.udc_name)
3208c2ecf20Sopenharmony_ci		goto err;
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	if (strncmp(page, "super-speed-plus", 16) == 0)
3238c2ecf20Sopenharmony_ci		gi->composite.max_speed = USB_SPEED_SUPER_PLUS;
3248c2ecf20Sopenharmony_ci	else if (strncmp(page, "super-speed", 11) == 0)
3258c2ecf20Sopenharmony_ci		gi->composite.max_speed = USB_SPEED_SUPER;
3268c2ecf20Sopenharmony_ci	else if (strncmp(page, "high-speed", 10) == 0)
3278c2ecf20Sopenharmony_ci		gi->composite.max_speed = USB_SPEED_HIGH;
3288c2ecf20Sopenharmony_ci	else if (strncmp(page, "full-speed", 10) == 0)
3298c2ecf20Sopenharmony_ci		gi->composite.max_speed = USB_SPEED_FULL;
3308c2ecf20Sopenharmony_ci	else if (strncmp(page, "low-speed", 9) == 0)
3318c2ecf20Sopenharmony_ci		gi->composite.max_speed = USB_SPEED_LOW;
3328c2ecf20Sopenharmony_ci	else
3338c2ecf20Sopenharmony_ci		goto err;
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci	gi->composite.gadget_driver.max_speed = gi->composite.max_speed;
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci	mutex_unlock(&gi->lock);
3388c2ecf20Sopenharmony_ci	return len;
3398c2ecf20Sopenharmony_cierr:
3408c2ecf20Sopenharmony_ci	mutex_unlock(&gi->lock);
3418c2ecf20Sopenharmony_ci	return -EINVAL;
3428c2ecf20Sopenharmony_ci}
3438c2ecf20Sopenharmony_ci
3448c2ecf20Sopenharmony_ciCONFIGFS_ATTR(gadget_dev_desc_, bDeviceClass);
3458c2ecf20Sopenharmony_ciCONFIGFS_ATTR(gadget_dev_desc_, bDeviceSubClass);
3468c2ecf20Sopenharmony_ciCONFIGFS_ATTR(gadget_dev_desc_, bDeviceProtocol);
3478c2ecf20Sopenharmony_ciCONFIGFS_ATTR(gadget_dev_desc_, bMaxPacketSize0);
3488c2ecf20Sopenharmony_ciCONFIGFS_ATTR(gadget_dev_desc_, idVendor);
3498c2ecf20Sopenharmony_ciCONFIGFS_ATTR(gadget_dev_desc_, idProduct);
3508c2ecf20Sopenharmony_ciCONFIGFS_ATTR(gadget_dev_desc_, bcdDevice);
3518c2ecf20Sopenharmony_ciCONFIGFS_ATTR(gadget_dev_desc_, bcdUSB);
3528c2ecf20Sopenharmony_ciCONFIGFS_ATTR(gadget_dev_desc_, UDC);
3538c2ecf20Sopenharmony_ciCONFIGFS_ATTR(gadget_dev_desc_, max_speed);
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_cistatic struct configfs_attribute *gadget_root_attrs[] = {
3568c2ecf20Sopenharmony_ci	&gadget_dev_desc_attr_bDeviceClass,
3578c2ecf20Sopenharmony_ci	&gadget_dev_desc_attr_bDeviceSubClass,
3588c2ecf20Sopenharmony_ci	&gadget_dev_desc_attr_bDeviceProtocol,
3598c2ecf20Sopenharmony_ci	&gadget_dev_desc_attr_bMaxPacketSize0,
3608c2ecf20Sopenharmony_ci	&gadget_dev_desc_attr_idVendor,
3618c2ecf20Sopenharmony_ci	&gadget_dev_desc_attr_idProduct,
3628c2ecf20Sopenharmony_ci	&gadget_dev_desc_attr_bcdDevice,
3638c2ecf20Sopenharmony_ci	&gadget_dev_desc_attr_bcdUSB,
3648c2ecf20Sopenharmony_ci	&gadget_dev_desc_attr_UDC,
3658c2ecf20Sopenharmony_ci	&gadget_dev_desc_attr_max_speed,
3668c2ecf20Sopenharmony_ci	NULL,
3678c2ecf20Sopenharmony_ci};
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_cistatic inline struct gadget_strings *to_gadget_strings(struct config_item *item)
3708c2ecf20Sopenharmony_ci{
3718c2ecf20Sopenharmony_ci	 return container_of(to_config_group(item), struct gadget_strings,
3728c2ecf20Sopenharmony_ci			 group);
3738c2ecf20Sopenharmony_ci}
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_cistatic inline struct gadget_config_name *to_gadget_config_name(
3768c2ecf20Sopenharmony_ci		struct config_item *item)
3778c2ecf20Sopenharmony_ci{
3788c2ecf20Sopenharmony_ci	 return container_of(to_config_group(item), struct gadget_config_name,
3798c2ecf20Sopenharmony_ci			 group);
3808c2ecf20Sopenharmony_ci}
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_cistatic inline struct usb_function_instance *to_usb_function_instance(
3838c2ecf20Sopenharmony_ci		struct config_item *item)
3848c2ecf20Sopenharmony_ci{
3858c2ecf20Sopenharmony_ci	 return container_of(to_config_group(item),
3868c2ecf20Sopenharmony_ci			 struct usb_function_instance, group);
3878c2ecf20Sopenharmony_ci}
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_cistatic void gadget_info_attr_release(struct config_item *item)
3908c2ecf20Sopenharmony_ci{
3918c2ecf20Sopenharmony_ci	struct gadget_info *gi = to_gadget_info(item);
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci	WARN_ON(!list_empty(&gi->cdev.configs));
3948c2ecf20Sopenharmony_ci	WARN_ON(!list_empty(&gi->string_list));
3958c2ecf20Sopenharmony_ci	WARN_ON(!list_empty(&gi->available_func));
3968c2ecf20Sopenharmony_ci	kfree(gi->composite.gadget_driver.function);
3978c2ecf20Sopenharmony_ci	kfree(gi);
3988c2ecf20Sopenharmony_ci}
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_cistatic struct configfs_item_operations gadget_root_item_ops = {
4018c2ecf20Sopenharmony_ci	.release                = gadget_info_attr_release,
4028c2ecf20Sopenharmony_ci};
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_cistatic void gadget_config_attr_release(struct config_item *item)
4058c2ecf20Sopenharmony_ci{
4068c2ecf20Sopenharmony_ci	struct config_usb_cfg *cfg = to_config_usb_cfg(item);
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci	WARN_ON(!list_empty(&cfg->c.functions));
4098c2ecf20Sopenharmony_ci	list_del(&cfg->c.list);
4108c2ecf20Sopenharmony_ci	kfree(cfg->c.label);
4118c2ecf20Sopenharmony_ci	kfree(cfg);
4128c2ecf20Sopenharmony_ci}
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_cistatic int config_usb_cfg_link(
4158c2ecf20Sopenharmony_ci	struct config_item *usb_cfg_ci,
4168c2ecf20Sopenharmony_ci	struct config_item *usb_func_ci)
4178c2ecf20Sopenharmony_ci{
4188c2ecf20Sopenharmony_ci	struct config_usb_cfg *cfg = to_config_usb_cfg(usb_cfg_ci);
4198c2ecf20Sopenharmony_ci	struct usb_composite_dev *cdev = cfg->c.cdev;
4208c2ecf20Sopenharmony_ci	struct gadget_info *gi = container_of(cdev, struct gadget_info, cdev);
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci	struct config_group *group = to_config_group(usb_func_ci);
4238c2ecf20Sopenharmony_ci	struct usb_function_instance *fi = container_of(group,
4248c2ecf20Sopenharmony_ci			struct usb_function_instance, group);
4258c2ecf20Sopenharmony_ci	struct usb_function_instance *a_fi;
4268c2ecf20Sopenharmony_ci	struct usb_function *f;
4278c2ecf20Sopenharmony_ci	int ret;
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_ci	mutex_lock(&gi->lock);
4308c2ecf20Sopenharmony_ci	/*
4318c2ecf20Sopenharmony_ci	 * Make sure this function is from within our _this_ gadget and not
4328c2ecf20Sopenharmony_ci	 * from another gadget or a random directory.
4338c2ecf20Sopenharmony_ci	 * Also a function instance can only be linked once.
4348c2ecf20Sopenharmony_ci	 */
4358c2ecf20Sopenharmony_ci	list_for_each_entry(a_fi, &gi->available_func, cfs_list) {
4368c2ecf20Sopenharmony_ci		if (a_fi == fi)
4378c2ecf20Sopenharmony_ci			break;
4388c2ecf20Sopenharmony_ci	}
4398c2ecf20Sopenharmony_ci	if (a_fi != fi) {
4408c2ecf20Sopenharmony_ci		ret = -EINVAL;
4418c2ecf20Sopenharmony_ci		goto out;
4428c2ecf20Sopenharmony_ci	}
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_ci	list_for_each_entry(f, &cfg->func_list, list) {
4458c2ecf20Sopenharmony_ci		if (f->fi == fi) {
4468c2ecf20Sopenharmony_ci			ret = -EEXIST;
4478c2ecf20Sopenharmony_ci			goto out;
4488c2ecf20Sopenharmony_ci		}
4498c2ecf20Sopenharmony_ci	}
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ci	f = usb_get_function(fi);
4528c2ecf20Sopenharmony_ci	if (IS_ERR(f)) {
4538c2ecf20Sopenharmony_ci		ret = PTR_ERR(f);
4548c2ecf20Sopenharmony_ci		goto out;
4558c2ecf20Sopenharmony_ci	}
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci	/* stash the function until we bind it to the gadget */
4588c2ecf20Sopenharmony_ci	list_add_tail(&f->list, &cfg->func_list);
4598c2ecf20Sopenharmony_ci	ret = 0;
4608c2ecf20Sopenharmony_ciout:
4618c2ecf20Sopenharmony_ci	mutex_unlock(&gi->lock);
4628c2ecf20Sopenharmony_ci	return ret;
4638c2ecf20Sopenharmony_ci}
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_cistatic void config_usb_cfg_unlink(
4668c2ecf20Sopenharmony_ci	struct config_item *usb_cfg_ci,
4678c2ecf20Sopenharmony_ci	struct config_item *usb_func_ci)
4688c2ecf20Sopenharmony_ci{
4698c2ecf20Sopenharmony_ci	struct config_usb_cfg *cfg = to_config_usb_cfg(usb_cfg_ci);
4708c2ecf20Sopenharmony_ci	struct usb_composite_dev *cdev = cfg->c.cdev;
4718c2ecf20Sopenharmony_ci	struct gadget_info *gi = container_of(cdev, struct gadget_info, cdev);
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_ci	struct config_group *group = to_config_group(usb_func_ci);
4748c2ecf20Sopenharmony_ci	struct usb_function_instance *fi = container_of(group,
4758c2ecf20Sopenharmony_ci			struct usb_function_instance, group);
4768c2ecf20Sopenharmony_ci	struct usb_function *f;
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_ci	/*
4798c2ecf20Sopenharmony_ci	 * ideally I would like to forbid to unlink functions while a gadget is
4808c2ecf20Sopenharmony_ci	 * bound to an UDC. Since this isn't possible at the moment, we simply
4818c2ecf20Sopenharmony_ci	 * force an unbind, the function is available here and then we can
4828c2ecf20Sopenharmony_ci	 * remove the function.
4838c2ecf20Sopenharmony_ci	 */
4848c2ecf20Sopenharmony_ci	mutex_lock(&gi->lock);
4858c2ecf20Sopenharmony_ci	if (gi->composite.gadget_driver.udc_name)
4868c2ecf20Sopenharmony_ci		unregister_gadget(gi);
4878c2ecf20Sopenharmony_ci	WARN_ON(gi->composite.gadget_driver.udc_name);
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_ci	list_for_each_entry(f, &cfg->func_list, list) {
4908c2ecf20Sopenharmony_ci		if (f->fi == fi) {
4918c2ecf20Sopenharmony_ci			list_del(&f->list);
4928c2ecf20Sopenharmony_ci			usb_put_function(f);
4938c2ecf20Sopenharmony_ci			mutex_unlock(&gi->lock);
4948c2ecf20Sopenharmony_ci			return;
4958c2ecf20Sopenharmony_ci		}
4968c2ecf20Sopenharmony_ci	}
4978c2ecf20Sopenharmony_ci	mutex_unlock(&gi->lock);
4988c2ecf20Sopenharmony_ci	WARN(1, "Unable to locate function to unbind\n");
4998c2ecf20Sopenharmony_ci}
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_cistatic struct configfs_item_operations gadget_config_item_ops = {
5028c2ecf20Sopenharmony_ci	.release                = gadget_config_attr_release,
5038c2ecf20Sopenharmony_ci	.allow_link             = config_usb_cfg_link,
5048c2ecf20Sopenharmony_ci	.drop_link              = config_usb_cfg_unlink,
5058c2ecf20Sopenharmony_ci};
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_ci
5088c2ecf20Sopenharmony_cistatic ssize_t gadget_config_desc_MaxPower_show(struct config_item *item,
5098c2ecf20Sopenharmony_ci		char *page)
5108c2ecf20Sopenharmony_ci{
5118c2ecf20Sopenharmony_ci	return sprintf(page, "%u\n", to_config_usb_cfg(item)->c.MaxPower);
5128c2ecf20Sopenharmony_ci}
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_cistatic ssize_t gadget_config_desc_MaxPower_store(struct config_item *item,
5158c2ecf20Sopenharmony_ci		const char *page, size_t len)
5168c2ecf20Sopenharmony_ci{
5178c2ecf20Sopenharmony_ci	u16 val;
5188c2ecf20Sopenharmony_ci	int ret;
5198c2ecf20Sopenharmony_ci	ret = kstrtou16(page, 0, &val);
5208c2ecf20Sopenharmony_ci	if (ret)
5218c2ecf20Sopenharmony_ci		return ret;
5228c2ecf20Sopenharmony_ci	if (DIV_ROUND_UP(val, 8) > 0xff)
5238c2ecf20Sopenharmony_ci		return -ERANGE;
5248c2ecf20Sopenharmony_ci	to_config_usb_cfg(item)->c.MaxPower = val;
5258c2ecf20Sopenharmony_ci	return len;
5268c2ecf20Sopenharmony_ci}
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_cistatic ssize_t gadget_config_desc_bmAttributes_show(struct config_item *item,
5298c2ecf20Sopenharmony_ci		char *page)
5308c2ecf20Sopenharmony_ci{
5318c2ecf20Sopenharmony_ci	return sprintf(page, "0x%02x\n",
5328c2ecf20Sopenharmony_ci		to_config_usb_cfg(item)->c.bmAttributes);
5338c2ecf20Sopenharmony_ci}
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_cistatic ssize_t gadget_config_desc_bmAttributes_store(struct config_item *item,
5368c2ecf20Sopenharmony_ci		const char *page, size_t len)
5378c2ecf20Sopenharmony_ci{
5388c2ecf20Sopenharmony_ci	u8 val;
5398c2ecf20Sopenharmony_ci	int ret;
5408c2ecf20Sopenharmony_ci	ret = kstrtou8(page, 0, &val);
5418c2ecf20Sopenharmony_ci	if (ret)
5428c2ecf20Sopenharmony_ci		return ret;
5438c2ecf20Sopenharmony_ci	if (!(val & USB_CONFIG_ATT_ONE))
5448c2ecf20Sopenharmony_ci		return -EINVAL;
5458c2ecf20Sopenharmony_ci	if (val & ~(USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER |
5468c2ecf20Sopenharmony_ci				USB_CONFIG_ATT_WAKEUP))
5478c2ecf20Sopenharmony_ci		return -EINVAL;
5488c2ecf20Sopenharmony_ci	to_config_usb_cfg(item)->c.bmAttributes = val;
5498c2ecf20Sopenharmony_ci	return len;
5508c2ecf20Sopenharmony_ci}
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_ciCONFIGFS_ATTR(gadget_config_desc_, MaxPower);
5538c2ecf20Sopenharmony_ciCONFIGFS_ATTR(gadget_config_desc_, bmAttributes);
5548c2ecf20Sopenharmony_ci
5558c2ecf20Sopenharmony_cistatic struct configfs_attribute *gadget_config_attrs[] = {
5568c2ecf20Sopenharmony_ci	&gadget_config_desc_attr_MaxPower,
5578c2ecf20Sopenharmony_ci	&gadget_config_desc_attr_bmAttributes,
5588c2ecf20Sopenharmony_ci	NULL,
5598c2ecf20Sopenharmony_ci};
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_cistatic const struct config_item_type gadget_config_type = {
5628c2ecf20Sopenharmony_ci	.ct_item_ops	= &gadget_config_item_ops,
5638c2ecf20Sopenharmony_ci	.ct_attrs	= gadget_config_attrs,
5648c2ecf20Sopenharmony_ci	.ct_owner	= THIS_MODULE,
5658c2ecf20Sopenharmony_ci};
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_cistatic const struct config_item_type gadget_root_type = {
5688c2ecf20Sopenharmony_ci	.ct_item_ops	= &gadget_root_item_ops,
5698c2ecf20Sopenharmony_ci	.ct_attrs	= gadget_root_attrs,
5708c2ecf20Sopenharmony_ci	.ct_owner	= THIS_MODULE,
5718c2ecf20Sopenharmony_ci};
5728c2ecf20Sopenharmony_ci
5738c2ecf20Sopenharmony_cistatic void composite_init_dev(struct usb_composite_dev *cdev)
5748c2ecf20Sopenharmony_ci{
5758c2ecf20Sopenharmony_ci	spin_lock_init(&cdev->lock);
5768c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&cdev->configs);
5778c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&cdev->gstrings);
5788c2ecf20Sopenharmony_ci}
5798c2ecf20Sopenharmony_ci
5808c2ecf20Sopenharmony_cistatic struct config_group *function_make(
5818c2ecf20Sopenharmony_ci		struct config_group *group,
5828c2ecf20Sopenharmony_ci		const char *name)
5838c2ecf20Sopenharmony_ci{
5848c2ecf20Sopenharmony_ci	struct gadget_info *gi;
5858c2ecf20Sopenharmony_ci	struct usb_function_instance *fi;
5868c2ecf20Sopenharmony_ci	char buf[MAX_NAME_LEN];
5878c2ecf20Sopenharmony_ci	char *func_name;
5888c2ecf20Sopenharmony_ci	char *instance_name;
5898c2ecf20Sopenharmony_ci	int ret;
5908c2ecf20Sopenharmony_ci
5918c2ecf20Sopenharmony_ci	ret = snprintf(buf, MAX_NAME_LEN, "%s", name);
5928c2ecf20Sopenharmony_ci	if (ret >= MAX_NAME_LEN)
5938c2ecf20Sopenharmony_ci		return ERR_PTR(-ENAMETOOLONG);
5948c2ecf20Sopenharmony_ci
5958c2ecf20Sopenharmony_ci	func_name = buf;
5968c2ecf20Sopenharmony_ci	instance_name = strchr(func_name, '.');
5978c2ecf20Sopenharmony_ci	if (!instance_name) {
5988c2ecf20Sopenharmony_ci		pr_err("Unable to locate . in FUNC.INSTANCE\n");
5998c2ecf20Sopenharmony_ci		return ERR_PTR(-EINVAL);
6008c2ecf20Sopenharmony_ci	}
6018c2ecf20Sopenharmony_ci	*instance_name = '\0';
6028c2ecf20Sopenharmony_ci	instance_name++;
6038c2ecf20Sopenharmony_ci
6048c2ecf20Sopenharmony_ci	fi = usb_get_function_instance(func_name);
6058c2ecf20Sopenharmony_ci	if (IS_ERR(fi))
6068c2ecf20Sopenharmony_ci		return ERR_CAST(fi);
6078c2ecf20Sopenharmony_ci
6088c2ecf20Sopenharmony_ci	ret = config_item_set_name(&fi->group.cg_item, "%s", name);
6098c2ecf20Sopenharmony_ci	if (ret) {
6108c2ecf20Sopenharmony_ci		usb_put_function_instance(fi);
6118c2ecf20Sopenharmony_ci		return ERR_PTR(ret);
6128c2ecf20Sopenharmony_ci	}
6138c2ecf20Sopenharmony_ci	if (fi->set_inst_name) {
6148c2ecf20Sopenharmony_ci		ret = fi->set_inst_name(fi, instance_name);
6158c2ecf20Sopenharmony_ci		if (ret) {
6168c2ecf20Sopenharmony_ci			usb_put_function_instance(fi);
6178c2ecf20Sopenharmony_ci			return ERR_PTR(ret);
6188c2ecf20Sopenharmony_ci		}
6198c2ecf20Sopenharmony_ci	}
6208c2ecf20Sopenharmony_ci
6218c2ecf20Sopenharmony_ci	gi = container_of(group, struct gadget_info, functions_group);
6228c2ecf20Sopenharmony_ci
6238c2ecf20Sopenharmony_ci	mutex_lock(&gi->lock);
6248c2ecf20Sopenharmony_ci	list_add_tail(&fi->cfs_list, &gi->available_func);
6258c2ecf20Sopenharmony_ci	mutex_unlock(&gi->lock);
6268c2ecf20Sopenharmony_ci	return &fi->group;
6278c2ecf20Sopenharmony_ci}
6288c2ecf20Sopenharmony_ci
6298c2ecf20Sopenharmony_cistatic void function_drop(
6308c2ecf20Sopenharmony_ci		struct config_group *group,
6318c2ecf20Sopenharmony_ci		struct config_item *item)
6328c2ecf20Sopenharmony_ci{
6338c2ecf20Sopenharmony_ci	struct usb_function_instance *fi = to_usb_function_instance(item);
6348c2ecf20Sopenharmony_ci	struct gadget_info *gi;
6358c2ecf20Sopenharmony_ci
6368c2ecf20Sopenharmony_ci	gi = container_of(group, struct gadget_info, functions_group);
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_ci	mutex_lock(&gi->lock);
6398c2ecf20Sopenharmony_ci	list_del(&fi->cfs_list);
6408c2ecf20Sopenharmony_ci	mutex_unlock(&gi->lock);
6418c2ecf20Sopenharmony_ci	config_item_put(item);
6428c2ecf20Sopenharmony_ci}
6438c2ecf20Sopenharmony_ci
6448c2ecf20Sopenharmony_cistatic struct configfs_group_operations functions_ops = {
6458c2ecf20Sopenharmony_ci	.make_group     = &function_make,
6468c2ecf20Sopenharmony_ci	.drop_item      = &function_drop,
6478c2ecf20Sopenharmony_ci};
6488c2ecf20Sopenharmony_ci
6498c2ecf20Sopenharmony_cistatic const struct config_item_type functions_type = {
6508c2ecf20Sopenharmony_ci	.ct_group_ops   = &functions_ops,
6518c2ecf20Sopenharmony_ci	.ct_owner       = THIS_MODULE,
6528c2ecf20Sopenharmony_ci};
6538c2ecf20Sopenharmony_ci
6548c2ecf20Sopenharmony_ciGS_STRINGS_RW(gadget_config_name, configuration);
6558c2ecf20Sopenharmony_ci
6568c2ecf20Sopenharmony_cistatic struct configfs_attribute *gadget_config_name_langid_attrs[] = {
6578c2ecf20Sopenharmony_ci	&gadget_config_name_attr_configuration,
6588c2ecf20Sopenharmony_ci	NULL,
6598c2ecf20Sopenharmony_ci};
6608c2ecf20Sopenharmony_ci
6618c2ecf20Sopenharmony_cistatic void gadget_config_name_attr_release(struct config_item *item)
6628c2ecf20Sopenharmony_ci{
6638c2ecf20Sopenharmony_ci	struct gadget_config_name *cn = to_gadget_config_name(item);
6648c2ecf20Sopenharmony_ci
6658c2ecf20Sopenharmony_ci	kfree(cn->configuration);
6668c2ecf20Sopenharmony_ci
6678c2ecf20Sopenharmony_ci	list_del(&cn->list);
6688c2ecf20Sopenharmony_ci	kfree(cn);
6698c2ecf20Sopenharmony_ci}
6708c2ecf20Sopenharmony_ci
6718c2ecf20Sopenharmony_ciUSB_CONFIG_STRING_RW_OPS(gadget_config_name);
6728c2ecf20Sopenharmony_ciUSB_CONFIG_STRINGS_LANG(gadget_config_name, config_usb_cfg);
6738c2ecf20Sopenharmony_ci
6748c2ecf20Sopenharmony_cistatic struct config_group *config_desc_make(
6758c2ecf20Sopenharmony_ci		struct config_group *group,
6768c2ecf20Sopenharmony_ci		const char *name)
6778c2ecf20Sopenharmony_ci{
6788c2ecf20Sopenharmony_ci	struct gadget_info *gi;
6798c2ecf20Sopenharmony_ci	struct config_usb_cfg *cfg;
6808c2ecf20Sopenharmony_ci	char buf[MAX_NAME_LEN];
6818c2ecf20Sopenharmony_ci	char *num_str;
6828c2ecf20Sopenharmony_ci	u8 num;
6838c2ecf20Sopenharmony_ci	int ret;
6848c2ecf20Sopenharmony_ci
6858c2ecf20Sopenharmony_ci	gi = container_of(group, struct gadget_info, configs_group);
6868c2ecf20Sopenharmony_ci	ret = snprintf(buf, MAX_NAME_LEN, "%s", name);
6878c2ecf20Sopenharmony_ci	if (ret >= MAX_NAME_LEN)
6888c2ecf20Sopenharmony_ci		return ERR_PTR(-ENAMETOOLONG);
6898c2ecf20Sopenharmony_ci
6908c2ecf20Sopenharmony_ci	num_str = strchr(buf, '.');
6918c2ecf20Sopenharmony_ci	if (!num_str) {
6928c2ecf20Sopenharmony_ci		pr_err("Unable to locate . in name.bConfigurationValue\n");
6938c2ecf20Sopenharmony_ci		return ERR_PTR(-EINVAL);
6948c2ecf20Sopenharmony_ci	}
6958c2ecf20Sopenharmony_ci
6968c2ecf20Sopenharmony_ci	*num_str = '\0';
6978c2ecf20Sopenharmony_ci	num_str++;
6988c2ecf20Sopenharmony_ci
6998c2ecf20Sopenharmony_ci	if (!strlen(buf))
7008c2ecf20Sopenharmony_ci		return ERR_PTR(-EINVAL);
7018c2ecf20Sopenharmony_ci
7028c2ecf20Sopenharmony_ci	ret = kstrtou8(num_str, 0, &num);
7038c2ecf20Sopenharmony_ci	if (ret)
7048c2ecf20Sopenharmony_ci		return ERR_PTR(ret);
7058c2ecf20Sopenharmony_ci
7068c2ecf20Sopenharmony_ci	cfg = kzalloc(sizeof(*cfg), GFP_KERNEL);
7078c2ecf20Sopenharmony_ci	if (!cfg)
7088c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
7098c2ecf20Sopenharmony_ci	cfg->c.label = kstrdup(buf, GFP_KERNEL);
7108c2ecf20Sopenharmony_ci	if (!cfg->c.label) {
7118c2ecf20Sopenharmony_ci		ret = -ENOMEM;
7128c2ecf20Sopenharmony_ci		goto err;
7138c2ecf20Sopenharmony_ci	}
7148c2ecf20Sopenharmony_ci	cfg->c.bConfigurationValue = num;
7158c2ecf20Sopenharmony_ci	cfg->c.MaxPower = CONFIG_USB_GADGET_VBUS_DRAW;
7168c2ecf20Sopenharmony_ci	cfg->c.bmAttributes = USB_CONFIG_ATT_ONE;
7178c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&cfg->string_list);
7188c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&cfg->func_list);
7198c2ecf20Sopenharmony_ci
7208c2ecf20Sopenharmony_ci	config_group_init_type_name(&cfg->group, name,
7218c2ecf20Sopenharmony_ci				&gadget_config_type);
7228c2ecf20Sopenharmony_ci
7238c2ecf20Sopenharmony_ci	config_group_init_type_name(&cfg->strings_group, "strings",
7248c2ecf20Sopenharmony_ci			&gadget_config_name_strings_type);
7258c2ecf20Sopenharmony_ci	configfs_add_default_group(&cfg->strings_group, &cfg->group);
7268c2ecf20Sopenharmony_ci
7278c2ecf20Sopenharmony_ci	ret = usb_add_config_only(&gi->cdev, &cfg->c);
7288c2ecf20Sopenharmony_ci	if (ret)
7298c2ecf20Sopenharmony_ci		goto err;
7308c2ecf20Sopenharmony_ci
7318c2ecf20Sopenharmony_ci	return &cfg->group;
7328c2ecf20Sopenharmony_cierr:
7338c2ecf20Sopenharmony_ci	kfree(cfg->c.label);
7348c2ecf20Sopenharmony_ci	kfree(cfg);
7358c2ecf20Sopenharmony_ci	return ERR_PTR(ret);
7368c2ecf20Sopenharmony_ci}
7378c2ecf20Sopenharmony_ci
7388c2ecf20Sopenharmony_cistatic void config_desc_drop(
7398c2ecf20Sopenharmony_ci		struct config_group *group,
7408c2ecf20Sopenharmony_ci		struct config_item *item)
7418c2ecf20Sopenharmony_ci{
7428c2ecf20Sopenharmony_ci	config_item_put(item);
7438c2ecf20Sopenharmony_ci}
7448c2ecf20Sopenharmony_ci
7458c2ecf20Sopenharmony_cistatic struct configfs_group_operations config_desc_ops = {
7468c2ecf20Sopenharmony_ci	.make_group     = &config_desc_make,
7478c2ecf20Sopenharmony_ci	.drop_item      = &config_desc_drop,
7488c2ecf20Sopenharmony_ci};
7498c2ecf20Sopenharmony_ci
7508c2ecf20Sopenharmony_cistatic const struct config_item_type config_desc_type = {
7518c2ecf20Sopenharmony_ci	.ct_group_ops   = &config_desc_ops,
7528c2ecf20Sopenharmony_ci	.ct_owner       = THIS_MODULE,
7538c2ecf20Sopenharmony_ci};
7548c2ecf20Sopenharmony_ci
7558c2ecf20Sopenharmony_ciGS_STRINGS_RW(gadget_strings, manufacturer);
7568c2ecf20Sopenharmony_ciGS_STRINGS_RW(gadget_strings, product);
7578c2ecf20Sopenharmony_ciGS_STRINGS_RW(gadget_strings, serialnumber);
7588c2ecf20Sopenharmony_ci
7598c2ecf20Sopenharmony_cistatic struct configfs_attribute *gadget_strings_langid_attrs[] = {
7608c2ecf20Sopenharmony_ci	&gadget_strings_attr_manufacturer,
7618c2ecf20Sopenharmony_ci	&gadget_strings_attr_product,
7628c2ecf20Sopenharmony_ci	&gadget_strings_attr_serialnumber,
7638c2ecf20Sopenharmony_ci	NULL,
7648c2ecf20Sopenharmony_ci};
7658c2ecf20Sopenharmony_ci
7668c2ecf20Sopenharmony_cistatic void gadget_strings_attr_release(struct config_item *item)
7678c2ecf20Sopenharmony_ci{
7688c2ecf20Sopenharmony_ci	struct gadget_strings *gs = to_gadget_strings(item);
7698c2ecf20Sopenharmony_ci
7708c2ecf20Sopenharmony_ci	kfree(gs->manufacturer);
7718c2ecf20Sopenharmony_ci	kfree(gs->product);
7728c2ecf20Sopenharmony_ci	kfree(gs->serialnumber);
7738c2ecf20Sopenharmony_ci
7748c2ecf20Sopenharmony_ci	list_del(&gs->list);
7758c2ecf20Sopenharmony_ci	kfree(gs);
7768c2ecf20Sopenharmony_ci}
7778c2ecf20Sopenharmony_ci
7788c2ecf20Sopenharmony_ciUSB_CONFIG_STRING_RW_OPS(gadget_strings);
7798c2ecf20Sopenharmony_ciUSB_CONFIG_STRINGS_LANG(gadget_strings, gadget_info);
7808c2ecf20Sopenharmony_ci
7818c2ecf20Sopenharmony_cistatic inline struct os_desc *to_os_desc(struct config_item *item)
7828c2ecf20Sopenharmony_ci{
7838c2ecf20Sopenharmony_ci	return container_of(to_config_group(item), struct os_desc, group);
7848c2ecf20Sopenharmony_ci}
7858c2ecf20Sopenharmony_ci
7868c2ecf20Sopenharmony_cistatic inline struct gadget_info *os_desc_item_to_gadget_info(
7878c2ecf20Sopenharmony_ci		struct config_item *item)
7888c2ecf20Sopenharmony_ci{
7898c2ecf20Sopenharmony_ci	return to_gadget_info(to_os_desc(item)->group.cg_item.ci_parent);
7908c2ecf20Sopenharmony_ci}
7918c2ecf20Sopenharmony_ci
7928c2ecf20Sopenharmony_cistatic ssize_t os_desc_use_show(struct config_item *item, char *page)
7938c2ecf20Sopenharmony_ci{
7948c2ecf20Sopenharmony_ci	return sprintf(page, "%d\n",
7958c2ecf20Sopenharmony_ci			os_desc_item_to_gadget_info(item)->use_os_desc);
7968c2ecf20Sopenharmony_ci}
7978c2ecf20Sopenharmony_ci
7988c2ecf20Sopenharmony_cistatic ssize_t os_desc_use_store(struct config_item *item, const char *page,
7998c2ecf20Sopenharmony_ci				 size_t len)
8008c2ecf20Sopenharmony_ci{
8018c2ecf20Sopenharmony_ci	struct gadget_info *gi = os_desc_item_to_gadget_info(item);
8028c2ecf20Sopenharmony_ci	int ret;
8038c2ecf20Sopenharmony_ci	bool use;
8048c2ecf20Sopenharmony_ci
8058c2ecf20Sopenharmony_ci	mutex_lock(&gi->lock);
8068c2ecf20Sopenharmony_ci	ret = strtobool(page, &use);
8078c2ecf20Sopenharmony_ci	if (!ret) {
8088c2ecf20Sopenharmony_ci		gi->use_os_desc = use;
8098c2ecf20Sopenharmony_ci		ret = len;
8108c2ecf20Sopenharmony_ci	}
8118c2ecf20Sopenharmony_ci	mutex_unlock(&gi->lock);
8128c2ecf20Sopenharmony_ci
8138c2ecf20Sopenharmony_ci	return ret;
8148c2ecf20Sopenharmony_ci}
8158c2ecf20Sopenharmony_ci
8168c2ecf20Sopenharmony_cistatic ssize_t os_desc_b_vendor_code_show(struct config_item *item, char *page)
8178c2ecf20Sopenharmony_ci{
8188c2ecf20Sopenharmony_ci	return sprintf(page, "0x%02x\n",
8198c2ecf20Sopenharmony_ci			os_desc_item_to_gadget_info(item)->b_vendor_code);
8208c2ecf20Sopenharmony_ci}
8218c2ecf20Sopenharmony_ci
8228c2ecf20Sopenharmony_cistatic ssize_t os_desc_b_vendor_code_store(struct config_item *item,
8238c2ecf20Sopenharmony_ci					   const char *page, size_t len)
8248c2ecf20Sopenharmony_ci{
8258c2ecf20Sopenharmony_ci	struct gadget_info *gi = os_desc_item_to_gadget_info(item);
8268c2ecf20Sopenharmony_ci	int ret;
8278c2ecf20Sopenharmony_ci	u8 b_vendor_code;
8288c2ecf20Sopenharmony_ci
8298c2ecf20Sopenharmony_ci	mutex_lock(&gi->lock);
8308c2ecf20Sopenharmony_ci	ret = kstrtou8(page, 0, &b_vendor_code);
8318c2ecf20Sopenharmony_ci	if (!ret) {
8328c2ecf20Sopenharmony_ci		gi->b_vendor_code = b_vendor_code;
8338c2ecf20Sopenharmony_ci		ret = len;
8348c2ecf20Sopenharmony_ci	}
8358c2ecf20Sopenharmony_ci	mutex_unlock(&gi->lock);
8368c2ecf20Sopenharmony_ci
8378c2ecf20Sopenharmony_ci	return ret;
8388c2ecf20Sopenharmony_ci}
8398c2ecf20Sopenharmony_ci
8408c2ecf20Sopenharmony_cistatic ssize_t os_desc_qw_sign_show(struct config_item *item, char *page)
8418c2ecf20Sopenharmony_ci{
8428c2ecf20Sopenharmony_ci	struct gadget_info *gi = os_desc_item_to_gadget_info(item);
8438c2ecf20Sopenharmony_ci	int res;
8448c2ecf20Sopenharmony_ci
8458c2ecf20Sopenharmony_ci	res = utf16s_to_utf8s((wchar_t *) gi->qw_sign, OS_STRING_QW_SIGN_LEN,
8468c2ecf20Sopenharmony_ci			      UTF16_LITTLE_ENDIAN, page, PAGE_SIZE - 1);
8478c2ecf20Sopenharmony_ci	page[res++] = '\n';
8488c2ecf20Sopenharmony_ci
8498c2ecf20Sopenharmony_ci	return res;
8508c2ecf20Sopenharmony_ci}
8518c2ecf20Sopenharmony_ci
8528c2ecf20Sopenharmony_cistatic ssize_t os_desc_qw_sign_store(struct config_item *item, const char *page,
8538c2ecf20Sopenharmony_ci				     size_t len)
8548c2ecf20Sopenharmony_ci{
8558c2ecf20Sopenharmony_ci	struct gadget_info *gi = os_desc_item_to_gadget_info(item);
8568c2ecf20Sopenharmony_ci	int res, l;
8578c2ecf20Sopenharmony_ci
8588c2ecf20Sopenharmony_ci	l = min((int)len, OS_STRING_QW_SIGN_LEN >> 1);
8598c2ecf20Sopenharmony_ci	if (page[l - 1] == '\n')
8608c2ecf20Sopenharmony_ci		--l;
8618c2ecf20Sopenharmony_ci
8628c2ecf20Sopenharmony_ci	mutex_lock(&gi->lock);
8638c2ecf20Sopenharmony_ci	res = utf8s_to_utf16s(page, l,
8648c2ecf20Sopenharmony_ci			      UTF16_LITTLE_ENDIAN, (wchar_t *) gi->qw_sign,
8658c2ecf20Sopenharmony_ci			      OS_STRING_QW_SIGN_LEN);
8668c2ecf20Sopenharmony_ci	if (res > 0)
8678c2ecf20Sopenharmony_ci		res = len;
8688c2ecf20Sopenharmony_ci	mutex_unlock(&gi->lock);
8698c2ecf20Sopenharmony_ci
8708c2ecf20Sopenharmony_ci	return res;
8718c2ecf20Sopenharmony_ci}
8728c2ecf20Sopenharmony_ci
8738c2ecf20Sopenharmony_ciCONFIGFS_ATTR(os_desc_, use);
8748c2ecf20Sopenharmony_ciCONFIGFS_ATTR(os_desc_, b_vendor_code);
8758c2ecf20Sopenharmony_ciCONFIGFS_ATTR(os_desc_, qw_sign);
8768c2ecf20Sopenharmony_ci
8778c2ecf20Sopenharmony_cistatic struct configfs_attribute *os_desc_attrs[] = {
8788c2ecf20Sopenharmony_ci	&os_desc_attr_use,
8798c2ecf20Sopenharmony_ci	&os_desc_attr_b_vendor_code,
8808c2ecf20Sopenharmony_ci	&os_desc_attr_qw_sign,
8818c2ecf20Sopenharmony_ci	NULL,
8828c2ecf20Sopenharmony_ci};
8838c2ecf20Sopenharmony_ci
8848c2ecf20Sopenharmony_cistatic void os_desc_attr_release(struct config_item *item)
8858c2ecf20Sopenharmony_ci{
8868c2ecf20Sopenharmony_ci	struct os_desc *os_desc = to_os_desc(item);
8878c2ecf20Sopenharmony_ci	kfree(os_desc);
8888c2ecf20Sopenharmony_ci}
8898c2ecf20Sopenharmony_ci
8908c2ecf20Sopenharmony_cistatic int os_desc_link(struct config_item *os_desc_ci,
8918c2ecf20Sopenharmony_ci			struct config_item *usb_cfg_ci)
8928c2ecf20Sopenharmony_ci{
8938c2ecf20Sopenharmony_ci	struct gadget_info *gi = container_of(to_config_group(os_desc_ci),
8948c2ecf20Sopenharmony_ci					struct gadget_info, os_desc_group);
8958c2ecf20Sopenharmony_ci	struct usb_composite_dev *cdev = &gi->cdev;
8968c2ecf20Sopenharmony_ci	struct config_usb_cfg *c_target =
8978c2ecf20Sopenharmony_ci		container_of(to_config_group(usb_cfg_ci),
8988c2ecf20Sopenharmony_ci			     struct config_usb_cfg, group);
8998c2ecf20Sopenharmony_ci	struct usb_configuration *c;
9008c2ecf20Sopenharmony_ci	int ret;
9018c2ecf20Sopenharmony_ci
9028c2ecf20Sopenharmony_ci	mutex_lock(&gi->lock);
9038c2ecf20Sopenharmony_ci	list_for_each_entry(c, &cdev->configs, list) {
9048c2ecf20Sopenharmony_ci		if (c == &c_target->c)
9058c2ecf20Sopenharmony_ci			break;
9068c2ecf20Sopenharmony_ci	}
9078c2ecf20Sopenharmony_ci	if (c != &c_target->c) {
9088c2ecf20Sopenharmony_ci		ret = -EINVAL;
9098c2ecf20Sopenharmony_ci		goto out;
9108c2ecf20Sopenharmony_ci	}
9118c2ecf20Sopenharmony_ci
9128c2ecf20Sopenharmony_ci	if (cdev->os_desc_config) {
9138c2ecf20Sopenharmony_ci		ret = -EBUSY;
9148c2ecf20Sopenharmony_ci		goto out;
9158c2ecf20Sopenharmony_ci	}
9168c2ecf20Sopenharmony_ci
9178c2ecf20Sopenharmony_ci	cdev->os_desc_config = &c_target->c;
9188c2ecf20Sopenharmony_ci	ret = 0;
9198c2ecf20Sopenharmony_ci
9208c2ecf20Sopenharmony_ciout:
9218c2ecf20Sopenharmony_ci	mutex_unlock(&gi->lock);
9228c2ecf20Sopenharmony_ci	return ret;
9238c2ecf20Sopenharmony_ci}
9248c2ecf20Sopenharmony_ci
9258c2ecf20Sopenharmony_cistatic void os_desc_unlink(struct config_item *os_desc_ci,
9268c2ecf20Sopenharmony_ci			  struct config_item *usb_cfg_ci)
9278c2ecf20Sopenharmony_ci{
9288c2ecf20Sopenharmony_ci	struct gadget_info *gi = container_of(to_config_group(os_desc_ci),
9298c2ecf20Sopenharmony_ci					struct gadget_info, os_desc_group);
9308c2ecf20Sopenharmony_ci	struct usb_composite_dev *cdev = &gi->cdev;
9318c2ecf20Sopenharmony_ci
9328c2ecf20Sopenharmony_ci	mutex_lock(&gi->lock);
9338c2ecf20Sopenharmony_ci	if (gi->composite.gadget_driver.udc_name)
9348c2ecf20Sopenharmony_ci		unregister_gadget(gi);
9358c2ecf20Sopenharmony_ci	cdev->os_desc_config = NULL;
9368c2ecf20Sopenharmony_ci	WARN_ON(gi->composite.gadget_driver.udc_name);
9378c2ecf20Sopenharmony_ci	mutex_unlock(&gi->lock);
9388c2ecf20Sopenharmony_ci}
9398c2ecf20Sopenharmony_ci
9408c2ecf20Sopenharmony_cistatic struct configfs_item_operations os_desc_ops = {
9418c2ecf20Sopenharmony_ci	.release                = os_desc_attr_release,
9428c2ecf20Sopenharmony_ci	.allow_link		= os_desc_link,
9438c2ecf20Sopenharmony_ci	.drop_link		= os_desc_unlink,
9448c2ecf20Sopenharmony_ci};
9458c2ecf20Sopenharmony_ci
9468c2ecf20Sopenharmony_cistatic struct config_item_type os_desc_type = {
9478c2ecf20Sopenharmony_ci	.ct_item_ops	= &os_desc_ops,
9488c2ecf20Sopenharmony_ci	.ct_attrs	= os_desc_attrs,
9498c2ecf20Sopenharmony_ci	.ct_owner	= THIS_MODULE,
9508c2ecf20Sopenharmony_ci};
9518c2ecf20Sopenharmony_ci
9528c2ecf20Sopenharmony_cistatic inline struct usb_os_desc_ext_prop
9538c2ecf20Sopenharmony_ci*to_usb_os_desc_ext_prop(struct config_item *item)
9548c2ecf20Sopenharmony_ci{
9558c2ecf20Sopenharmony_ci	return container_of(item, struct usb_os_desc_ext_prop, item);
9568c2ecf20Sopenharmony_ci}
9578c2ecf20Sopenharmony_ci
9588c2ecf20Sopenharmony_cistatic ssize_t ext_prop_type_show(struct config_item *item, char *page)
9598c2ecf20Sopenharmony_ci{
9608c2ecf20Sopenharmony_ci	return sprintf(page, "%d\n", to_usb_os_desc_ext_prop(item)->type);
9618c2ecf20Sopenharmony_ci}
9628c2ecf20Sopenharmony_ci
9638c2ecf20Sopenharmony_cistatic ssize_t ext_prop_type_store(struct config_item *item,
9648c2ecf20Sopenharmony_ci				   const char *page, size_t len)
9658c2ecf20Sopenharmony_ci{
9668c2ecf20Sopenharmony_ci	struct usb_os_desc_ext_prop *ext_prop = to_usb_os_desc_ext_prop(item);
9678c2ecf20Sopenharmony_ci	struct usb_os_desc *desc = to_usb_os_desc(ext_prop->item.ci_parent);
9688c2ecf20Sopenharmony_ci	u8 type;
9698c2ecf20Sopenharmony_ci	int ret;
9708c2ecf20Sopenharmony_ci
9718c2ecf20Sopenharmony_ci	if (desc->opts_mutex)
9728c2ecf20Sopenharmony_ci		mutex_lock(desc->opts_mutex);
9738c2ecf20Sopenharmony_ci	ret = kstrtou8(page, 0, &type);
9748c2ecf20Sopenharmony_ci	if (ret)
9758c2ecf20Sopenharmony_ci		goto end;
9768c2ecf20Sopenharmony_ci	if (type < USB_EXT_PROP_UNICODE || type > USB_EXT_PROP_UNICODE_MULTI) {
9778c2ecf20Sopenharmony_ci		ret = -EINVAL;
9788c2ecf20Sopenharmony_ci		goto end;
9798c2ecf20Sopenharmony_ci	}
9808c2ecf20Sopenharmony_ci
9818c2ecf20Sopenharmony_ci	if ((ext_prop->type == USB_EXT_PROP_BINARY ||
9828c2ecf20Sopenharmony_ci	    ext_prop->type == USB_EXT_PROP_LE32 ||
9838c2ecf20Sopenharmony_ci	    ext_prop->type == USB_EXT_PROP_BE32) &&
9848c2ecf20Sopenharmony_ci	    (type == USB_EXT_PROP_UNICODE ||
9858c2ecf20Sopenharmony_ci	    type == USB_EXT_PROP_UNICODE_ENV ||
9868c2ecf20Sopenharmony_ci	    type == USB_EXT_PROP_UNICODE_LINK))
9878c2ecf20Sopenharmony_ci		ext_prop->data_len <<= 1;
9888c2ecf20Sopenharmony_ci	else if ((ext_prop->type == USB_EXT_PROP_UNICODE ||
9898c2ecf20Sopenharmony_ci		   ext_prop->type == USB_EXT_PROP_UNICODE_ENV ||
9908c2ecf20Sopenharmony_ci		   ext_prop->type == USB_EXT_PROP_UNICODE_LINK) &&
9918c2ecf20Sopenharmony_ci		   (type == USB_EXT_PROP_BINARY ||
9928c2ecf20Sopenharmony_ci		   type == USB_EXT_PROP_LE32 ||
9938c2ecf20Sopenharmony_ci		   type == USB_EXT_PROP_BE32))
9948c2ecf20Sopenharmony_ci		ext_prop->data_len >>= 1;
9958c2ecf20Sopenharmony_ci	ext_prop->type = type;
9968c2ecf20Sopenharmony_ci	ret = len;
9978c2ecf20Sopenharmony_ci
9988c2ecf20Sopenharmony_ciend:
9998c2ecf20Sopenharmony_ci	if (desc->opts_mutex)
10008c2ecf20Sopenharmony_ci		mutex_unlock(desc->opts_mutex);
10018c2ecf20Sopenharmony_ci	return ret;
10028c2ecf20Sopenharmony_ci}
10038c2ecf20Sopenharmony_ci
10048c2ecf20Sopenharmony_cistatic ssize_t ext_prop_data_show(struct config_item *item, char *page)
10058c2ecf20Sopenharmony_ci{
10068c2ecf20Sopenharmony_ci	struct usb_os_desc_ext_prop *ext_prop = to_usb_os_desc_ext_prop(item);
10078c2ecf20Sopenharmony_ci	int len = ext_prop->data_len;
10088c2ecf20Sopenharmony_ci
10098c2ecf20Sopenharmony_ci	if (ext_prop->type == USB_EXT_PROP_UNICODE ||
10108c2ecf20Sopenharmony_ci	    ext_prop->type == USB_EXT_PROP_UNICODE_ENV ||
10118c2ecf20Sopenharmony_ci	    ext_prop->type == USB_EXT_PROP_UNICODE_LINK)
10128c2ecf20Sopenharmony_ci		len >>= 1;
10138c2ecf20Sopenharmony_ci	memcpy(page, ext_prop->data, len);
10148c2ecf20Sopenharmony_ci
10158c2ecf20Sopenharmony_ci	return len;
10168c2ecf20Sopenharmony_ci}
10178c2ecf20Sopenharmony_ci
10188c2ecf20Sopenharmony_cistatic ssize_t ext_prop_data_store(struct config_item *item,
10198c2ecf20Sopenharmony_ci				   const char *page, size_t len)
10208c2ecf20Sopenharmony_ci{
10218c2ecf20Sopenharmony_ci	struct usb_os_desc_ext_prop *ext_prop = to_usb_os_desc_ext_prop(item);
10228c2ecf20Sopenharmony_ci	struct usb_os_desc *desc = to_usb_os_desc(ext_prop->item.ci_parent);
10238c2ecf20Sopenharmony_ci	char *new_data;
10248c2ecf20Sopenharmony_ci	size_t ret_len = len;
10258c2ecf20Sopenharmony_ci
10268c2ecf20Sopenharmony_ci	if (page[len - 1] == '\n' || page[len - 1] == '\0')
10278c2ecf20Sopenharmony_ci		--len;
10288c2ecf20Sopenharmony_ci	new_data = kmemdup(page, len, GFP_KERNEL);
10298c2ecf20Sopenharmony_ci	if (!new_data)
10308c2ecf20Sopenharmony_ci		return -ENOMEM;
10318c2ecf20Sopenharmony_ci
10328c2ecf20Sopenharmony_ci	if (desc->opts_mutex)
10338c2ecf20Sopenharmony_ci		mutex_lock(desc->opts_mutex);
10348c2ecf20Sopenharmony_ci	kfree(ext_prop->data);
10358c2ecf20Sopenharmony_ci	ext_prop->data = new_data;
10368c2ecf20Sopenharmony_ci	desc->ext_prop_len -= ext_prop->data_len;
10378c2ecf20Sopenharmony_ci	ext_prop->data_len = len;
10388c2ecf20Sopenharmony_ci	desc->ext_prop_len += ext_prop->data_len;
10398c2ecf20Sopenharmony_ci	if (ext_prop->type == USB_EXT_PROP_UNICODE ||
10408c2ecf20Sopenharmony_ci	    ext_prop->type == USB_EXT_PROP_UNICODE_ENV ||
10418c2ecf20Sopenharmony_ci	    ext_prop->type == USB_EXT_PROP_UNICODE_LINK) {
10428c2ecf20Sopenharmony_ci		desc->ext_prop_len -= ext_prop->data_len;
10438c2ecf20Sopenharmony_ci		ext_prop->data_len <<= 1;
10448c2ecf20Sopenharmony_ci		ext_prop->data_len += 2;
10458c2ecf20Sopenharmony_ci		desc->ext_prop_len += ext_prop->data_len;
10468c2ecf20Sopenharmony_ci	}
10478c2ecf20Sopenharmony_ci	if (desc->opts_mutex)
10488c2ecf20Sopenharmony_ci		mutex_unlock(desc->opts_mutex);
10498c2ecf20Sopenharmony_ci	return ret_len;
10508c2ecf20Sopenharmony_ci}
10518c2ecf20Sopenharmony_ci
10528c2ecf20Sopenharmony_ciCONFIGFS_ATTR(ext_prop_, type);
10538c2ecf20Sopenharmony_ciCONFIGFS_ATTR(ext_prop_, data);
10548c2ecf20Sopenharmony_ci
10558c2ecf20Sopenharmony_cistatic struct configfs_attribute *ext_prop_attrs[] = {
10568c2ecf20Sopenharmony_ci	&ext_prop_attr_type,
10578c2ecf20Sopenharmony_ci	&ext_prop_attr_data,
10588c2ecf20Sopenharmony_ci	NULL,
10598c2ecf20Sopenharmony_ci};
10608c2ecf20Sopenharmony_ci
10618c2ecf20Sopenharmony_cistatic void usb_os_desc_ext_prop_release(struct config_item *item)
10628c2ecf20Sopenharmony_ci{
10638c2ecf20Sopenharmony_ci	struct usb_os_desc_ext_prop *ext_prop = to_usb_os_desc_ext_prop(item);
10648c2ecf20Sopenharmony_ci
10658c2ecf20Sopenharmony_ci	kfree(ext_prop); /* frees a whole chunk */
10668c2ecf20Sopenharmony_ci}
10678c2ecf20Sopenharmony_ci
10688c2ecf20Sopenharmony_cistatic struct configfs_item_operations ext_prop_ops = {
10698c2ecf20Sopenharmony_ci	.release		= usb_os_desc_ext_prop_release,
10708c2ecf20Sopenharmony_ci};
10718c2ecf20Sopenharmony_ci
10728c2ecf20Sopenharmony_cistatic struct config_item *ext_prop_make(
10738c2ecf20Sopenharmony_ci		struct config_group *group,
10748c2ecf20Sopenharmony_ci		const char *name)
10758c2ecf20Sopenharmony_ci{
10768c2ecf20Sopenharmony_ci	struct usb_os_desc_ext_prop *ext_prop;
10778c2ecf20Sopenharmony_ci	struct config_item_type *ext_prop_type;
10788c2ecf20Sopenharmony_ci	struct usb_os_desc *desc;
10798c2ecf20Sopenharmony_ci	char *vlabuf;
10808c2ecf20Sopenharmony_ci
10818c2ecf20Sopenharmony_ci	vla_group(data_chunk);
10828c2ecf20Sopenharmony_ci	vla_item(data_chunk, struct usb_os_desc_ext_prop, ext_prop, 1);
10838c2ecf20Sopenharmony_ci	vla_item(data_chunk, struct config_item_type, ext_prop_type, 1);
10848c2ecf20Sopenharmony_ci
10858c2ecf20Sopenharmony_ci	vlabuf = kzalloc(vla_group_size(data_chunk), GFP_KERNEL);
10868c2ecf20Sopenharmony_ci	if (!vlabuf)
10878c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
10888c2ecf20Sopenharmony_ci
10898c2ecf20Sopenharmony_ci	ext_prop = vla_ptr(vlabuf, data_chunk, ext_prop);
10908c2ecf20Sopenharmony_ci	ext_prop_type = vla_ptr(vlabuf, data_chunk, ext_prop_type);
10918c2ecf20Sopenharmony_ci
10928c2ecf20Sopenharmony_ci	desc = container_of(group, struct usb_os_desc, group);
10938c2ecf20Sopenharmony_ci	ext_prop_type->ct_item_ops = &ext_prop_ops;
10948c2ecf20Sopenharmony_ci	ext_prop_type->ct_attrs = ext_prop_attrs;
10958c2ecf20Sopenharmony_ci	ext_prop_type->ct_owner = desc->owner;
10968c2ecf20Sopenharmony_ci
10978c2ecf20Sopenharmony_ci	config_item_init_type_name(&ext_prop->item, name, ext_prop_type);
10988c2ecf20Sopenharmony_ci
10998c2ecf20Sopenharmony_ci	ext_prop->name = kstrdup(name, GFP_KERNEL);
11008c2ecf20Sopenharmony_ci	if (!ext_prop->name) {
11018c2ecf20Sopenharmony_ci		kfree(vlabuf);
11028c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
11038c2ecf20Sopenharmony_ci	}
11048c2ecf20Sopenharmony_ci	desc->ext_prop_len += 14;
11058c2ecf20Sopenharmony_ci	ext_prop->name_len = 2 * strlen(ext_prop->name) + 2;
11068c2ecf20Sopenharmony_ci	if (desc->opts_mutex)
11078c2ecf20Sopenharmony_ci		mutex_lock(desc->opts_mutex);
11088c2ecf20Sopenharmony_ci	desc->ext_prop_len += ext_prop->name_len;
11098c2ecf20Sopenharmony_ci	list_add_tail(&ext_prop->entry, &desc->ext_prop);
11108c2ecf20Sopenharmony_ci	++desc->ext_prop_count;
11118c2ecf20Sopenharmony_ci	if (desc->opts_mutex)
11128c2ecf20Sopenharmony_ci		mutex_unlock(desc->opts_mutex);
11138c2ecf20Sopenharmony_ci
11148c2ecf20Sopenharmony_ci	return &ext_prop->item;
11158c2ecf20Sopenharmony_ci}
11168c2ecf20Sopenharmony_ci
11178c2ecf20Sopenharmony_cistatic void ext_prop_drop(struct config_group *group, struct config_item *item)
11188c2ecf20Sopenharmony_ci{
11198c2ecf20Sopenharmony_ci	struct usb_os_desc_ext_prop *ext_prop = to_usb_os_desc_ext_prop(item);
11208c2ecf20Sopenharmony_ci	struct usb_os_desc *desc = to_usb_os_desc(&group->cg_item);
11218c2ecf20Sopenharmony_ci
11228c2ecf20Sopenharmony_ci	if (desc->opts_mutex)
11238c2ecf20Sopenharmony_ci		mutex_lock(desc->opts_mutex);
11248c2ecf20Sopenharmony_ci	list_del(&ext_prop->entry);
11258c2ecf20Sopenharmony_ci	--desc->ext_prop_count;
11268c2ecf20Sopenharmony_ci	kfree(ext_prop->name);
11278c2ecf20Sopenharmony_ci	desc->ext_prop_len -= (ext_prop->name_len + ext_prop->data_len + 14);
11288c2ecf20Sopenharmony_ci	if (desc->opts_mutex)
11298c2ecf20Sopenharmony_ci		mutex_unlock(desc->opts_mutex);
11308c2ecf20Sopenharmony_ci	config_item_put(item);
11318c2ecf20Sopenharmony_ci}
11328c2ecf20Sopenharmony_ci
11338c2ecf20Sopenharmony_cistatic struct configfs_group_operations interf_grp_ops = {
11348c2ecf20Sopenharmony_ci	.make_item	= &ext_prop_make,
11358c2ecf20Sopenharmony_ci	.drop_item	= &ext_prop_drop,
11368c2ecf20Sopenharmony_ci};
11378c2ecf20Sopenharmony_ci
11388c2ecf20Sopenharmony_cistatic ssize_t interf_grp_compatible_id_show(struct config_item *item,
11398c2ecf20Sopenharmony_ci					     char *page)
11408c2ecf20Sopenharmony_ci{
11418c2ecf20Sopenharmony_ci	memcpy(page, to_usb_os_desc(item)->ext_compat_id, 8);
11428c2ecf20Sopenharmony_ci	return 8;
11438c2ecf20Sopenharmony_ci}
11448c2ecf20Sopenharmony_ci
11458c2ecf20Sopenharmony_cistatic ssize_t interf_grp_compatible_id_store(struct config_item *item,
11468c2ecf20Sopenharmony_ci					      const char *page, size_t len)
11478c2ecf20Sopenharmony_ci{
11488c2ecf20Sopenharmony_ci	struct usb_os_desc *desc = to_usb_os_desc(item);
11498c2ecf20Sopenharmony_ci	int l;
11508c2ecf20Sopenharmony_ci
11518c2ecf20Sopenharmony_ci	l = min_t(int, 8, len);
11528c2ecf20Sopenharmony_ci	if (page[l - 1] == '\n')
11538c2ecf20Sopenharmony_ci		--l;
11548c2ecf20Sopenharmony_ci	if (desc->opts_mutex)
11558c2ecf20Sopenharmony_ci		mutex_lock(desc->opts_mutex);
11568c2ecf20Sopenharmony_ci	memcpy(desc->ext_compat_id, page, l);
11578c2ecf20Sopenharmony_ci
11588c2ecf20Sopenharmony_ci	if (desc->opts_mutex)
11598c2ecf20Sopenharmony_ci		mutex_unlock(desc->opts_mutex);
11608c2ecf20Sopenharmony_ci
11618c2ecf20Sopenharmony_ci	return len;
11628c2ecf20Sopenharmony_ci}
11638c2ecf20Sopenharmony_ci
11648c2ecf20Sopenharmony_cistatic ssize_t interf_grp_sub_compatible_id_show(struct config_item *item,
11658c2ecf20Sopenharmony_ci						 char *page)
11668c2ecf20Sopenharmony_ci{
11678c2ecf20Sopenharmony_ci	memcpy(page, to_usb_os_desc(item)->ext_compat_id + 8, 8);
11688c2ecf20Sopenharmony_ci	return 8;
11698c2ecf20Sopenharmony_ci}
11708c2ecf20Sopenharmony_ci
11718c2ecf20Sopenharmony_cistatic ssize_t interf_grp_sub_compatible_id_store(struct config_item *item,
11728c2ecf20Sopenharmony_ci						  const char *page, size_t len)
11738c2ecf20Sopenharmony_ci{
11748c2ecf20Sopenharmony_ci	struct usb_os_desc *desc = to_usb_os_desc(item);
11758c2ecf20Sopenharmony_ci	int l;
11768c2ecf20Sopenharmony_ci
11778c2ecf20Sopenharmony_ci	l = min_t(int, 8, len);
11788c2ecf20Sopenharmony_ci	if (page[l - 1] == '\n')
11798c2ecf20Sopenharmony_ci		--l;
11808c2ecf20Sopenharmony_ci	if (desc->opts_mutex)
11818c2ecf20Sopenharmony_ci		mutex_lock(desc->opts_mutex);
11828c2ecf20Sopenharmony_ci	memcpy(desc->ext_compat_id + 8, page, l);
11838c2ecf20Sopenharmony_ci
11848c2ecf20Sopenharmony_ci	if (desc->opts_mutex)
11858c2ecf20Sopenharmony_ci		mutex_unlock(desc->opts_mutex);
11868c2ecf20Sopenharmony_ci
11878c2ecf20Sopenharmony_ci	return len;
11888c2ecf20Sopenharmony_ci}
11898c2ecf20Sopenharmony_ci
11908c2ecf20Sopenharmony_ciCONFIGFS_ATTR(interf_grp_, compatible_id);
11918c2ecf20Sopenharmony_ciCONFIGFS_ATTR(interf_grp_, sub_compatible_id);
11928c2ecf20Sopenharmony_ci
11938c2ecf20Sopenharmony_cistatic struct configfs_attribute *interf_grp_attrs[] = {
11948c2ecf20Sopenharmony_ci	&interf_grp_attr_compatible_id,
11958c2ecf20Sopenharmony_ci	&interf_grp_attr_sub_compatible_id,
11968c2ecf20Sopenharmony_ci	NULL
11978c2ecf20Sopenharmony_ci};
11988c2ecf20Sopenharmony_ci
11998c2ecf20Sopenharmony_cistruct config_group *usb_os_desc_prepare_interf_dir(
12008c2ecf20Sopenharmony_ci		struct config_group *parent,
12018c2ecf20Sopenharmony_ci		int n_interf,
12028c2ecf20Sopenharmony_ci		struct usb_os_desc **desc,
12038c2ecf20Sopenharmony_ci		char **names,
12048c2ecf20Sopenharmony_ci		struct module *owner)
12058c2ecf20Sopenharmony_ci{
12068c2ecf20Sopenharmony_ci	struct config_group *os_desc_group;
12078c2ecf20Sopenharmony_ci	struct config_item_type *os_desc_type, *interface_type;
12088c2ecf20Sopenharmony_ci
12098c2ecf20Sopenharmony_ci	vla_group(data_chunk);
12108c2ecf20Sopenharmony_ci	vla_item(data_chunk, struct config_group, os_desc_group, 1);
12118c2ecf20Sopenharmony_ci	vla_item(data_chunk, struct config_item_type, os_desc_type, 1);
12128c2ecf20Sopenharmony_ci	vla_item(data_chunk, struct config_item_type, interface_type, 1);
12138c2ecf20Sopenharmony_ci
12148c2ecf20Sopenharmony_ci	char *vlabuf = kzalloc(vla_group_size(data_chunk), GFP_KERNEL);
12158c2ecf20Sopenharmony_ci	if (!vlabuf)
12168c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
12178c2ecf20Sopenharmony_ci
12188c2ecf20Sopenharmony_ci	os_desc_group = vla_ptr(vlabuf, data_chunk, os_desc_group);
12198c2ecf20Sopenharmony_ci	os_desc_type = vla_ptr(vlabuf, data_chunk, os_desc_type);
12208c2ecf20Sopenharmony_ci	interface_type = vla_ptr(vlabuf, data_chunk, interface_type);
12218c2ecf20Sopenharmony_ci
12228c2ecf20Sopenharmony_ci	os_desc_type->ct_owner = owner;
12238c2ecf20Sopenharmony_ci	config_group_init_type_name(os_desc_group, "os_desc", os_desc_type);
12248c2ecf20Sopenharmony_ci	configfs_add_default_group(os_desc_group, parent);
12258c2ecf20Sopenharmony_ci
12268c2ecf20Sopenharmony_ci	interface_type->ct_group_ops = &interf_grp_ops;
12278c2ecf20Sopenharmony_ci	interface_type->ct_attrs = interf_grp_attrs;
12288c2ecf20Sopenharmony_ci	interface_type->ct_owner = owner;
12298c2ecf20Sopenharmony_ci
12308c2ecf20Sopenharmony_ci	while (n_interf--) {
12318c2ecf20Sopenharmony_ci		struct usb_os_desc *d;
12328c2ecf20Sopenharmony_ci
12338c2ecf20Sopenharmony_ci		d = desc[n_interf];
12348c2ecf20Sopenharmony_ci		d->owner = owner;
12358c2ecf20Sopenharmony_ci		config_group_init_type_name(&d->group, "", interface_type);
12368c2ecf20Sopenharmony_ci		config_item_set_name(&d->group.cg_item, "interface.%s",
12378c2ecf20Sopenharmony_ci				     names[n_interf]);
12388c2ecf20Sopenharmony_ci		configfs_add_default_group(&d->group, os_desc_group);
12398c2ecf20Sopenharmony_ci	}
12408c2ecf20Sopenharmony_ci
12418c2ecf20Sopenharmony_ci	return os_desc_group;
12428c2ecf20Sopenharmony_ci}
12438c2ecf20Sopenharmony_ciEXPORT_SYMBOL(usb_os_desc_prepare_interf_dir);
12448c2ecf20Sopenharmony_ci
12458c2ecf20Sopenharmony_cistatic int configfs_do_nothing(struct usb_composite_dev *cdev)
12468c2ecf20Sopenharmony_ci{
12478c2ecf20Sopenharmony_ci	WARN_ON(1);
12488c2ecf20Sopenharmony_ci	return -EINVAL;
12498c2ecf20Sopenharmony_ci}
12508c2ecf20Sopenharmony_ci
12518c2ecf20Sopenharmony_ciint composite_dev_prepare(struct usb_composite_driver *composite,
12528c2ecf20Sopenharmony_ci		struct usb_composite_dev *dev);
12538c2ecf20Sopenharmony_ci
12548c2ecf20Sopenharmony_ciint composite_os_desc_req_prepare(struct usb_composite_dev *cdev,
12558c2ecf20Sopenharmony_ci				  struct usb_ep *ep0);
12568c2ecf20Sopenharmony_ci
12578c2ecf20Sopenharmony_cistatic void purge_configs_funcs(struct gadget_info *gi)
12588c2ecf20Sopenharmony_ci{
12598c2ecf20Sopenharmony_ci	struct usb_configuration	*c;
12608c2ecf20Sopenharmony_ci
12618c2ecf20Sopenharmony_ci	list_for_each_entry(c, &gi->cdev.configs, list) {
12628c2ecf20Sopenharmony_ci		struct usb_function *f, *tmp;
12638c2ecf20Sopenharmony_ci		struct config_usb_cfg *cfg;
12648c2ecf20Sopenharmony_ci
12658c2ecf20Sopenharmony_ci		cfg = container_of(c, struct config_usb_cfg, c);
12668c2ecf20Sopenharmony_ci
12678c2ecf20Sopenharmony_ci		list_for_each_entry_safe_reverse(f, tmp, &c->functions, list) {
12688c2ecf20Sopenharmony_ci
12698c2ecf20Sopenharmony_ci			list_move(&f->list, &cfg->func_list);
12708c2ecf20Sopenharmony_ci			if (f->unbind) {
12718c2ecf20Sopenharmony_ci				dev_dbg(&gi->cdev.gadget->dev,
12728c2ecf20Sopenharmony_ci					"unbind function '%s'/%p\n",
12738c2ecf20Sopenharmony_ci					f->name, f);
12748c2ecf20Sopenharmony_ci				f->unbind(c, f);
12758c2ecf20Sopenharmony_ci			}
12768c2ecf20Sopenharmony_ci		}
12778c2ecf20Sopenharmony_ci		c->next_interface_id = 0;
12788c2ecf20Sopenharmony_ci		memset(c->interface, 0, sizeof(c->interface));
12798c2ecf20Sopenharmony_ci		c->superspeed_plus = 0;
12808c2ecf20Sopenharmony_ci		c->superspeed = 0;
12818c2ecf20Sopenharmony_ci		c->highspeed = 0;
12828c2ecf20Sopenharmony_ci		c->fullspeed = 0;
12838c2ecf20Sopenharmony_ci	}
12848c2ecf20Sopenharmony_ci}
12858c2ecf20Sopenharmony_ci
12868c2ecf20Sopenharmony_cistatic int configfs_composite_bind(struct usb_gadget *gadget,
12878c2ecf20Sopenharmony_ci		struct usb_gadget_driver *gdriver)
12888c2ecf20Sopenharmony_ci{
12898c2ecf20Sopenharmony_ci	struct usb_composite_driver     *composite = to_cdriver(gdriver);
12908c2ecf20Sopenharmony_ci	struct gadget_info		*gi = container_of(composite,
12918c2ecf20Sopenharmony_ci						struct gadget_info, composite);
12928c2ecf20Sopenharmony_ci	struct usb_composite_dev	*cdev = &gi->cdev;
12938c2ecf20Sopenharmony_ci	struct usb_configuration	*c;
12948c2ecf20Sopenharmony_ci	struct usb_string		*s;
12958c2ecf20Sopenharmony_ci	unsigned			i;
12968c2ecf20Sopenharmony_ci	int				ret;
12978c2ecf20Sopenharmony_ci
12988c2ecf20Sopenharmony_ci	/* the gi->lock is hold by the caller */
12998c2ecf20Sopenharmony_ci	gi->unbind = 0;
13008c2ecf20Sopenharmony_ci	cdev->gadget = gadget;
13018c2ecf20Sopenharmony_ci	set_gadget_data(gadget, cdev);
13028c2ecf20Sopenharmony_ci	ret = composite_dev_prepare(composite, cdev);
13038c2ecf20Sopenharmony_ci	if (ret)
13048c2ecf20Sopenharmony_ci		return ret;
13058c2ecf20Sopenharmony_ci	/* and now the gadget bind */
13068c2ecf20Sopenharmony_ci	ret = -EINVAL;
13078c2ecf20Sopenharmony_ci
13088c2ecf20Sopenharmony_ci	if (list_empty(&gi->cdev.configs)) {
13098c2ecf20Sopenharmony_ci		pr_err("Need at least one configuration in %s.\n",
13108c2ecf20Sopenharmony_ci				gi->composite.name);
13118c2ecf20Sopenharmony_ci		goto err_comp_cleanup;
13128c2ecf20Sopenharmony_ci	}
13138c2ecf20Sopenharmony_ci
13148c2ecf20Sopenharmony_ci
13158c2ecf20Sopenharmony_ci	list_for_each_entry(c, &gi->cdev.configs, list) {
13168c2ecf20Sopenharmony_ci		struct config_usb_cfg *cfg;
13178c2ecf20Sopenharmony_ci
13188c2ecf20Sopenharmony_ci		cfg = container_of(c, struct config_usb_cfg, c);
13198c2ecf20Sopenharmony_ci		if (list_empty(&cfg->func_list)) {
13208c2ecf20Sopenharmony_ci			pr_err("Config %s/%d of %s needs at least one function.\n",
13218c2ecf20Sopenharmony_ci			      c->label, c->bConfigurationValue,
13228c2ecf20Sopenharmony_ci			      gi->composite.name);
13238c2ecf20Sopenharmony_ci			goto err_comp_cleanup;
13248c2ecf20Sopenharmony_ci		}
13258c2ecf20Sopenharmony_ci	}
13268c2ecf20Sopenharmony_ci
13278c2ecf20Sopenharmony_ci	/* init all strings */
13288c2ecf20Sopenharmony_ci	if (!list_empty(&gi->string_list)) {
13298c2ecf20Sopenharmony_ci		struct gadget_strings *gs;
13308c2ecf20Sopenharmony_ci
13318c2ecf20Sopenharmony_ci		i = 0;
13328c2ecf20Sopenharmony_ci		list_for_each_entry(gs, &gi->string_list, list) {
13338c2ecf20Sopenharmony_ci
13348c2ecf20Sopenharmony_ci			gi->gstrings[i] = &gs->stringtab_dev;
13358c2ecf20Sopenharmony_ci			gs->stringtab_dev.strings = gs->strings;
13368c2ecf20Sopenharmony_ci			gs->strings[USB_GADGET_MANUFACTURER_IDX].s =
13378c2ecf20Sopenharmony_ci				gs->manufacturer;
13388c2ecf20Sopenharmony_ci			gs->strings[USB_GADGET_PRODUCT_IDX].s = gs->product;
13398c2ecf20Sopenharmony_ci			gs->strings[USB_GADGET_SERIAL_IDX].s = gs->serialnumber;
13408c2ecf20Sopenharmony_ci			i++;
13418c2ecf20Sopenharmony_ci		}
13428c2ecf20Sopenharmony_ci		gi->gstrings[i] = NULL;
13438c2ecf20Sopenharmony_ci		s = usb_gstrings_attach(&gi->cdev, gi->gstrings,
13448c2ecf20Sopenharmony_ci				USB_GADGET_FIRST_AVAIL_IDX);
13458c2ecf20Sopenharmony_ci		if (IS_ERR(s)) {
13468c2ecf20Sopenharmony_ci			ret = PTR_ERR(s);
13478c2ecf20Sopenharmony_ci			goto err_comp_cleanup;
13488c2ecf20Sopenharmony_ci		}
13498c2ecf20Sopenharmony_ci
13508c2ecf20Sopenharmony_ci		gi->cdev.desc.iManufacturer = s[USB_GADGET_MANUFACTURER_IDX].id;
13518c2ecf20Sopenharmony_ci		gi->cdev.desc.iProduct = s[USB_GADGET_PRODUCT_IDX].id;
13528c2ecf20Sopenharmony_ci		gi->cdev.desc.iSerialNumber = s[USB_GADGET_SERIAL_IDX].id;
13538c2ecf20Sopenharmony_ci	}
13548c2ecf20Sopenharmony_ci
13558c2ecf20Sopenharmony_ci	if (gi->use_os_desc) {
13568c2ecf20Sopenharmony_ci		cdev->use_os_string = true;
13578c2ecf20Sopenharmony_ci		cdev->b_vendor_code = gi->b_vendor_code;
13588c2ecf20Sopenharmony_ci		memcpy(cdev->qw_sign, gi->qw_sign, OS_STRING_QW_SIGN_LEN);
13598c2ecf20Sopenharmony_ci	}
13608c2ecf20Sopenharmony_ci
13618c2ecf20Sopenharmony_ci	if (gadget_is_otg(gadget) && !otg_desc[0]) {
13628c2ecf20Sopenharmony_ci		struct usb_descriptor_header *usb_desc;
13638c2ecf20Sopenharmony_ci
13648c2ecf20Sopenharmony_ci		usb_desc = usb_otg_descriptor_alloc(gadget);
13658c2ecf20Sopenharmony_ci		if (!usb_desc) {
13668c2ecf20Sopenharmony_ci			ret = -ENOMEM;
13678c2ecf20Sopenharmony_ci			goto err_comp_cleanup;
13688c2ecf20Sopenharmony_ci		}
13698c2ecf20Sopenharmony_ci		usb_otg_descriptor_init(gadget, usb_desc);
13708c2ecf20Sopenharmony_ci		otg_desc[0] = usb_desc;
13718c2ecf20Sopenharmony_ci		otg_desc[1] = NULL;
13728c2ecf20Sopenharmony_ci	}
13738c2ecf20Sopenharmony_ci
13748c2ecf20Sopenharmony_ci	/* Go through all configs, attach all functions */
13758c2ecf20Sopenharmony_ci	list_for_each_entry(c, &gi->cdev.configs, list) {
13768c2ecf20Sopenharmony_ci		struct config_usb_cfg *cfg;
13778c2ecf20Sopenharmony_ci		struct usb_function *f;
13788c2ecf20Sopenharmony_ci		struct usb_function *tmp;
13798c2ecf20Sopenharmony_ci		struct gadget_config_name *cn;
13808c2ecf20Sopenharmony_ci
13818c2ecf20Sopenharmony_ci		if (gadget_is_otg(gadget))
13828c2ecf20Sopenharmony_ci			c->descriptors = otg_desc;
13838c2ecf20Sopenharmony_ci
13848c2ecf20Sopenharmony_ci		cfg = container_of(c, struct config_usb_cfg, c);
13858c2ecf20Sopenharmony_ci		if (!list_empty(&cfg->string_list)) {
13868c2ecf20Sopenharmony_ci			i = 0;
13878c2ecf20Sopenharmony_ci			list_for_each_entry(cn, &cfg->string_list, list) {
13888c2ecf20Sopenharmony_ci				cfg->gstrings[i] = &cn->stringtab_dev;
13898c2ecf20Sopenharmony_ci				cn->stringtab_dev.strings = &cn->strings;
13908c2ecf20Sopenharmony_ci				cn->strings.s = cn->configuration;
13918c2ecf20Sopenharmony_ci				i++;
13928c2ecf20Sopenharmony_ci			}
13938c2ecf20Sopenharmony_ci			cfg->gstrings[i] = NULL;
13948c2ecf20Sopenharmony_ci			s = usb_gstrings_attach(&gi->cdev, cfg->gstrings, 1);
13958c2ecf20Sopenharmony_ci			if (IS_ERR(s)) {
13968c2ecf20Sopenharmony_ci				ret = PTR_ERR(s);
13978c2ecf20Sopenharmony_ci				goto err_comp_cleanup;
13988c2ecf20Sopenharmony_ci			}
13998c2ecf20Sopenharmony_ci			c->iConfiguration = s[0].id;
14008c2ecf20Sopenharmony_ci		}
14018c2ecf20Sopenharmony_ci
14028c2ecf20Sopenharmony_ci		list_for_each_entry_safe(f, tmp, &cfg->func_list, list) {
14038c2ecf20Sopenharmony_ci			list_del(&f->list);
14048c2ecf20Sopenharmony_ci			ret = usb_add_function(c, f);
14058c2ecf20Sopenharmony_ci			if (ret) {
14068c2ecf20Sopenharmony_ci				list_add(&f->list, &cfg->func_list);
14078c2ecf20Sopenharmony_ci				goto err_purge_funcs;
14088c2ecf20Sopenharmony_ci			}
14098c2ecf20Sopenharmony_ci		}
14108c2ecf20Sopenharmony_ci		usb_ep_autoconfig_reset(cdev->gadget);
14118c2ecf20Sopenharmony_ci	}
14128c2ecf20Sopenharmony_ci	if (cdev->use_os_string) {
14138c2ecf20Sopenharmony_ci		ret = composite_os_desc_req_prepare(cdev, gadget->ep0);
14148c2ecf20Sopenharmony_ci		if (ret)
14158c2ecf20Sopenharmony_ci			goto err_purge_funcs;
14168c2ecf20Sopenharmony_ci	}
14178c2ecf20Sopenharmony_ci
14188c2ecf20Sopenharmony_ci	usb_ep_autoconfig_reset(cdev->gadget);
14198c2ecf20Sopenharmony_ci	return 0;
14208c2ecf20Sopenharmony_ci
14218c2ecf20Sopenharmony_cierr_purge_funcs:
14228c2ecf20Sopenharmony_ci	purge_configs_funcs(gi);
14238c2ecf20Sopenharmony_cierr_comp_cleanup:
14248c2ecf20Sopenharmony_ci	composite_dev_cleanup(cdev);
14258c2ecf20Sopenharmony_ci	return ret;
14268c2ecf20Sopenharmony_ci}
14278c2ecf20Sopenharmony_ci
14288c2ecf20Sopenharmony_cistatic void configfs_composite_unbind(struct usb_gadget *gadget)
14298c2ecf20Sopenharmony_ci{
14308c2ecf20Sopenharmony_ci	struct usb_composite_dev	*cdev;
14318c2ecf20Sopenharmony_ci	struct gadget_info		*gi;
14328c2ecf20Sopenharmony_ci	unsigned long flags;
14338c2ecf20Sopenharmony_ci
14348c2ecf20Sopenharmony_ci	/* the gi->lock is hold by the caller */
14358c2ecf20Sopenharmony_ci
14368c2ecf20Sopenharmony_ci	cdev = get_gadget_data(gadget);
14378c2ecf20Sopenharmony_ci	gi = container_of(cdev, struct gadget_info, cdev);
14388c2ecf20Sopenharmony_ci	spin_lock_irqsave(&gi->spinlock, flags);
14398c2ecf20Sopenharmony_ci	gi->unbind = 1;
14408c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&gi->spinlock, flags);
14418c2ecf20Sopenharmony_ci
14428c2ecf20Sopenharmony_ci	kfree(otg_desc[0]);
14438c2ecf20Sopenharmony_ci	otg_desc[0] = NULL;
14448c2ecf20Sopenharmony_ci	purge_configs_funcs(gi);
14458c2ecf20Sopenharmony_ci	composite_dev_cleanup(cdev);
14468c2ecf20Sopenharmony_ci	usb_ep_autoconfig_reset(cdev->gadget);
14478c2ecf20Sopenharmony_ci	spin_lock_irqsave(&gi->spinlock, flags);
14488c2ecf20Sopenharmony_ci	cdev->gadget = NULL;
14498c2ecf20Sopenharmony_ci	cdev->deactivations = 0;
14508c2ecf20Sopenharmony_ci	gadget->deactivated = false;
14518c2ecf20Sopenharmony_ci	set_gadget_data(gadget, NULL);
14528c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&gi->spinlock, flags);
14538c2ecf20Sopenharmony_ci}
14548c2ecf20Sopenharmony_ci
14558c2ecf20Sopenharmony_cistatic int configfs_composite_setup(struct usb_gadget *gadget,
14568c2ecf20Sopenharmony_ci		const struct usb_ctrlrequest *ctrl)
14578c2ecf20Sopenharmony_ci{
14588c2ecf20Sopenharmony_ci	struct usb_composite_dev *cdev;
14598c2ecf20Sopenharmony_ci	struct gadget_info *gi;
14608c2ecf20Sopenharmony_ci	unsigned long flags;
14618c2ecf20Sopenharmony_ci	int ret;
14628c2ecf20Sopenharmony_ci
14638c2ecf20Sopenharmony_ci	cdev = get_gadget_data(gadget);
14648c2ecf20Sopenharmony_ci	if (!cdev)
14658c2ecf20Sopenharmony_ci		return 0;
14668c2ecf20Sopenharmony_ci
14678c2ecf20Sopenharmony_ci	gi = container_of(cdev, struct gadget_info, cdev);
14688c2ecf20Sopenharmony_ci	spin_lock_irqsave(&gi->spinlock, flags);
14698c2ecf20Sopenharmony_ci	cdev = get_gadget_data(gadget);
14708c2ecf20Sopenharmony_ci	if (!cdev || gi->unbind) {
14718c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&gi->spinlock, flags);
14728c2ecf20Sopenharmony_ci		return 0;
14738c2ecf20Sopenharmony_ci	}
14748c2ecf20Sopenharmony_ci
14758c2ecf20Sopenharmony_ci	ret = composite_setup(gadget, ctrl);
14768c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&gi->spinlock, flags);
14778c2ecf20Sopenharmony_ci	return ret;
14788c2ecf20Sopenharmony_ci}
14798c2ecf20Sopenharmony_ci
14808c2ecf20Sopenharmony_cistatic void configfs_composite_disconnect(struct usb_gadget *gadget)
14818c2ecf20Sopenharmony_ci{
14828c2ecf20Sopenharmony_ci	struct usb_composite_dev *cdev;
14838c2ecf20Sopenharmony_ci	struct gadget_info *gi;
14848c2ecf20Sopenharmony_ci	unsigned long flags;
14858c2ecf20Sopenharmony_ci
14868c2ecf20Sopenharmony_ci	cdev = get_gadget_data(gadget);
14878c2ecf20Sopenharmony_ci	if (!cdev)
14888c2ecf20Sopenharmony_ci		return;
14898c2ecf20Sopenharmony_ci
14908c2ecf20Sopenharmony_ci	gi = container_of(cdev, struct gadget_info, cdev);
14918c2ecf20Sopenharmony_ci	spin_lock_irqsave(&gi->spinlock, flags);
14928c2ecf20Sopenharmony_ci	cdev = get_gadget_data(gadget);
14938c2ecf20Sopenharmony_ci	if (!cdev || gi->unbind) {
14948c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&gi->spinlock, flags);
14958c2ecf20Sopenharmony_ci		return;
14968c2ecf20Sopenharmony_ci	}
14978c2ecf20Sopenharmony_ci
14988c2ecf20Sopenharmony_ci	composite_disconnect(gadget);
14998c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&gi->spinlock, flags);
15008c2ecf20Sopenharmony_ci}
15018c2ecf20Sopenharmony_ci
15028c2ecf20Sopenharmony_cistatic void configfs_composite_suspend(struct usb_gadget *gadget)
15038c2ecf20Sopenharmony_ci{
15048c2ecf20Sopenharmony_ci	struct usb_composite_dev *cdev;
15058c2ecf20Sopenharmony_ci	struct gadget_info *gi;
15068c2ecf20Sopenharmony_ci	unsigned long flags;
15078c2ecf20Sopenharmony_ci
15088c2ecf20Sopenharmony_ci	cdev = get_gadget_data(gadget);
15098c2ecf20Sopenharmony_ci	if (!cdev)
15108c2ecf20Sopenharmony_ci		return;
15118c2ecf20Sopenharmony_ci
15128c2ecf20Sopenharmony_ci	gi = container_of(cdev, struct gadget_info, cdev);
15138c2ecf20Sopenharmony_ci	spin_lock_irqsave(&gi->spinlock, flags);
15148c2ecf20Sopenharmony_ci	cdev = get_gadget_data(gadget);
15158c2ecf20Sopenharmony_ci	if (!cdev || gi->unbind) {
15168c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&gi->spinlock, flags);
15178c2ecf20Sopenharmony_ci		return;
15188c2ecf20Sopenharmony_ci	}
15198c2ecf20Sopenharmony_ci
15208c2ecf20Sopenharmony_ci	composite_suspend(gadget);
15218c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&gi->spinlock, flags);
15228c2ecf20Sopenharmony_ci}
15238c2ecf20Sopenharmony_ci
15248c2ecf20Sopenharmony_cistatic void configfs_composite_resume(struct usb_gadget *gadget)
15258c2ecf20Sopenharmony_ci{
15268c2ecf20Sopenharmony_ci	struct usb_composite_dev *cdev;
15278c2ecf20Sopenharmony_ci	struct gadget_info *gi;
15288c2ecf20Sopenharmony_ci	unsigned long flags;
15298c2ecf20Sopenharmony_ci
15308c2ecf20Sopenharmony_ci	cdev = get_gadget_data(gadget);
15318c2ecf20Sopenharmony_ci	if (!cdev)
15328c2ecf20Sopenharmony_ci		return;
15338c2ecf20Sopenharmony_ci
15348c2ecf20Sopenharmony_ci	gi = container_of(cdev, struct gadget_info, cdev);
15358c2ecf20Sopenharmony_ci	spin_lock_irqsave(&gi->spinlock, flags);
15368c2ecf20Sopenharmony_ci	cdev = get_gadget_data(gadget);
15378c2ecf20Sopenharmony_ci	if (!cdev || gi->unbind) {
15388c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&gi->spinlock, flags);
15398c2ecf20Sopenharmony_ci		return;
15408c2ecf20Sopenharmony_ci	}
15418c2ecf20Sopenharmony_ci
15428c2ecf20Sopenharmony_ci	composite_resume(gadget);
15438c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&gi->spinlock, flags);
15448c2ecf20Sopenharmony_ci}
15458c2ecf20Sopenharmony_ci
15468c2ecf20Sopenharmony_cistatic const struct usb_gadget_driver configfs_driver_template = {
15478c2ecf20Sopenharmony_ci	.bind           = configfs_composite_bind,
15488c2ecf20Sopenharmony_ci	.unbind         = configfs_composite_unbind,
15498c2ecf20Sopenharmony_ci
15508c2ecf20Sopenharmony_ci	.setup          = configfs_composite_setup,
15518c2ecf20Sopenharmony_ci	.reset          = configfs_composite_disconnect,
15528c2ecf20Sopenharmony_ci	.disconnect     = configfs_composite_disconnect,
15538c2ecf20Sopenharmony_ci
15548c2ecf20Sopenharmony_ci	.suspend	= configfs_composite_suspend,
15558c2ecf20Sopenharmony_ci	.resume		= configfs_composite_resume,
15568c2ecf20Sopenharmony_ci
15578c2ecf20Sopenharmony_ci	.max_speed	= USB_SPEED_SUPER_PLUS,
15588c2ecf20Sopenharmony_ci	.driver = {
15598c2ecf20Sopenharmony_ci		.owner          = THIS_MODULE,
15608c2ecf20Sopenharmony_ci		.name		= "configfs-gadget",
15618c2ecf20Sopenharmony_ci	},
15628c2ecf20Sopenharmony_ci	.match_existing_only = 1,
15638c2ecf20Sopenharmony_ci};
15648c2ecf20Sopenharmony_ci
15658c2ecf20Sopenharmony_cistatic struct config_group *gadgets_make(
15668c2ecf20Sopenharmony_ci		struct config_group *group,
15678c2ecf20Sopenharmony_ci		const char *name)
15688c2ecf20Sopenharmony_ci{
15698c2ecf20Sopenharmony_ci	struct gadget_info *gi;
15708c2ecf20Sopenharmony_ci
15718c2ecf20Sopenharmony_ci	gi = kzalloc(sizeof(*gi), GFP_KERNEL);
15728c2ecf20Sopenharmony_ci	if (!gi)
15738c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOMEM);
15748c2ecf20Sopenharmony_ci
15758c2ecf20Sopenharmony_ci	config_group_init_type_name(&gi->group, name, &gadget_root_type);
15768c2ecf20Sopenharmony_ci
15778c2ecf20Sopenharmony_ci	config_group_init_type_name(&gi->functions_group, "functions",
15788c2ecf20Sopenharmony_ci			&functions_type);
15798c2ecf20Sopenharmony_ci	configfs_add_default_group(&gi->functions_group, &gi->group);
15808c2ecf20Sopenharmony_ci
15818c2ecf20Sopenharmony_ci	config_group_init_type_name(&gi->configs_group, "configs",
15828c2ecf20Sopenharmony_ci			&config_desc_type);
15838c2ecf20Sopenharmony_ci	configfs_add_default_group(&gi->configs_group, &gi->group);
15848c2ecf20Sopenharmony_ci
15858c2ecf20Sopenharmony_ci	config_group_init_type_name(&gi->strings_group, "strings",
15868c2ecf20Sopenharmony_ci			&gadget_strings_strings_type);
15878c2ecf20Sopenharmony_ci	configfs_add_default_group(&gi->strings_group, &gi->group);
15888c2ecf20Sopenharmony_ci
15898c2ecf20Sopenharmony_ci	config_group_init_type_name(&gi->os_desc_group, "os_desc",
15908c2ecf20Sopenharmony_ci			&os_desc_type);
15918c2ecf20Sopenharmony_ci	configfs_add_default_group(&gi->os_desc_group, &gi->group);
15928c2ecf20Sopenharmony_ci
15938c2ecf20Sopenharmony_ci	gi->composite.bind = configfs_do_nothing;
15948c2ecf20Sopenharmony_ci	gi->composite.unbind = configfs_do_nothing;
15958c2ecf20Sopenharmony_ci	gi->composite.suspend = NULL;
15968c2ecf20Sopenharmony_ci	gi->composite.resume = NULL;
15978c2ecf20Sopenharmony_ci	gi->composite.max_speed = USB_SPEED_SUPER_PLUS;
15988c2ecf20Sopenharmony_ci
15998c2ecf20Sopenharmony_ci	spin_lock_init(&gi->spinlock);
16008c2ecf20Sopenharmony_ci	mutex_init(&gi->lock);
16018c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&gi->string_list);
16028c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&gi->available_func);
16038c2ecf20Sopenharmony_ci
16048c2ecf20Sopenharmony_ci	composite_init_dev(&gi->cdev);
16058c2ecf20Sopenharmony_ci	gi->cdev.desc.bLength = USB_DT_DEVICE_SIZE;
16068c2ecf20Sopenharmony_ci	gi->cdev.desc.bDescriptorType = USB_DT_DEVICE;
16078c2ecf20Sopenharmony_ci	gi->cdev.desc.bcdDevice = cpu_to_le16(get_default_bcdDevice());
16088c2ecf20Sopenharmony_ci
16098c2ecf20Sopenharmony_ci	gi->composite.gadget_driver = configfs_driver_template;
16108c2ecf20Sopenharmony_ci
16118c2ecf20Sopenharmony_ci	gi->composite.gadget_driver.function = kstrdup(name, GFP_KERNEL);
16128c2ecf20Sopenharmony_ci	gi->composite.name = gi->composite.gadget_driver.function;
16138c2ecf20Sopenharmony_ci
16148c2ecf20Sopenharmony_ci	if (!gi->composite.gadget_driver.function)
16158c2ecf20Sopenharmony_ci		goto err;
16168c2ecf20Sopenharmony_ci
16178c2ecf20Sopenharmony_ci	return &gi->group;
16188c2ecf20Sopenharmony_cierr:
16198c2ecf20Sopenharmony_ci	kfree(gi);
16208c2ecf20Sopenharmony_ci	return ERR_PTR(-ENOMEM);
16218c2ecf20Sopenharmony_ci}
16228c2ecf20Sopenharmony_ci
16238c2ecf20Sopenharmony_cistatic void gadgets_drop(struct config_group *group, struct config_item *item)
16248c2ecf20Sopenharmony_ci{
16258c2ecf20Sopenharmony_ci	config_item_put(item);
16268c2ecf20Sopenharmony_ci}
16278c2ecf20Sopenharmony_ci
16288c2ecf20Sopenharmony_cistatic struct configfs_group_operations gadgets_ops = {
16298c2ecf20Sopenharmony_ci	.make_group     = &gadgets_make,
16308c2ecf20Sopenharmony_ci	.drop_item      = &gadgets_drop,
16318c2ecf20Sopenharmony_ci};
16328c2ecf20Sopenharmony_ci
16338c2ecf20Sopenharmony_cistatic const struct config_item_type gadgets_type = {
16348c2ecf20Sopenharmony_ci	.ct_group_ops   = &gadgets_ops,
16358c2ecf20Sopenharmony_ci	.ct_owner       = THIS_MODULE,
16368c2ecf20Sopenharmony_ci};
16378c2ecf20Sopenharmony_ci
16388c2ecf20Sopenharmony_cistatic struct configfs_subsystem gadget_subsys = {
16398c2ecf20Sopenharmony_ci	.su_group = {
16408c2ecf20Sopenharmony_ci		.cg_item = {
16418c2ecf20Sopenharmony_ci			.ci_namebuf = "usb_gadget",
16428c2ecf20Sopenharmony_ci			.ci_type = &gadgets_type,
16438c2ecf20Sopenharmony_ci		},
16448c2ecf20Sopenharmony_ci	},
16458c2ecf20Sopenharmony_ci	.su_mutex = __MUTEX_INITIALIZER(gadget_subsys.su_mutex),
16468c2ecf20Sopenharmony_ci};
16478c2ecf20Sopenharmony_ci
16488c2ecf20Sopenharmony_civoid unregister_gadget_item(struct config_item *item)
16498c2ecf20Sopenharmony_ci{
16508c2ecf20Sopenharmony_ci	struct gadget_info *gi = to_gadget_info(item);
16518c2ecf20Sopenharmony_ci
16528c2ecf20Sopenharmony_ci	mutex_lock(&gi->lock);
16538c2ecf20Sopenharmony_ci	unregister_gadget(gi);
16548c2ecf20Sopenharmony_ci	mutex_unlock(&gi->lock);
16558c2ecf20Sopenharmony_ci}
16568c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(unregister_gadget_item);
16578c2ecf20Sopenharmony_ci
16588c2ecf20Sopenharmony_cistatic int __init gadget_cfs_init(void)
16598c2ecf20Sopenharmony_ci{
16608c2ecf20Sopenharmony_ci	int ret;
16618c2ecf20Sopenharmony_ci
16628c2ecf20Sopenharmony_ci	config_group_init(&gadget_subsys.su_group);
16638c2ecf20Sopenharmony_ci
16648c2ecf20Sopenharmony_ci	ret = configfs_register_subsystem(&gadget_subsys);
16658c2ecf20Sopenharmony_ci	return ret;
16668c2ecf20Sopenharmony_ci}
16678c2ecf20Sopenharmony_cimodule_init(gadget_cfs_init);
16688c2ecf20Sopenharmony_ci
16698c2ecf20Sopenharmony_cistatic void __exit gadget_cfs_exit(void)
16708c2ecf20Sopenharmony_ci{
16718c2ecf20Sopenharmony_ci	configfs_unregister_subsystem(&gadget_subsys);
16728c2ecf20Sopenharmony_ci}
16738c2ecf20Sopenharmony_cimodule_exit(gadget_cfs_exit);
1674