aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrzej Pietrasiewicz <andrzej.p@samsung.com>2014-05-08 08:06:28 -0400
committerFelipe Balbi <balbi@ti.com>2014-05-14 10:39:51 -0400
commit7419485f197c436d41535df78ddea1085042d271 (patch)
treebbf52fde27c3b5be352a3c98ea58da7eea8389d9
parenta747b0958b5ead2d4ba46dc1f77d46e693a06efa (diff)
usb: gadget: configfs: OS Extended Properties descriptors support
Add handling of OS Extended Properties descriptors from configfs interface. One kind of "OS Descriptors" are "Extended Properties" descriptors, which need to be specified per interface or per group of interfaces described by an IAD. This patch adds support for creating subdirectories in interface.<n> directory located in the function's directory. Names of subdirectories created become names of properties. Each property contains two attributes: "type" and "data". The type can be a numeric value 1..7 while data is a blob interpreted depending on the type specified. The types are: 1 - unicode string 2 - unicode string with environment variables 3 - binary 4 - little-endian 32-bit 5 - big-endian 32-bit 6 - unicode string with a symbolic link 7 - multiple unicode strings Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@samsung.com> Signed-off-by: Felipe Balbi <balbi@ti.com>
-rw-r--r--Documentation/ABI/testing/configfs-usb-gadget21
-rw-r--r--drivers/usb/gadget/configfs.c201
-rw-r--r--include/linux/usb/composite.h4
3 files changed, 226 insertions, 0 deletions
diff --git a/Documentation/ABI/testing/configfs-usb-gadget b/Documentation/ABI/testing/configfs-usb-gadget
index 5c0b3e6eb981..95a36589a66b 100644
--- a/Documentation/ABI/testing/configfs-usb-gadget
+++ b/Documentation/ABI/testing/configfs-usb-gadget
@@ -75,6 +75,27 @@ Description:
75 compatible_id - 8-byte string for "Compatible ID" 75 compatible_id - 8-byte string for "Compatible ID"
76 sub_compatible_id - 8-byte string for "Sub Compatible ID" 76 sub_compatible_id - 8-byte string for "Sub Compatible ID"
77 77
78What: /config/usb-gadget/gadget/functions/<func>.<inst>/interface.<n>/<property>
79Date: May 2014
80KernelVersion: 3.16
81Description:
82 This group contains "Extended Property Descriptors" specific for one
83 gadget's USB interface or one interface group described
84 by an IAD.
85
86 The attributes:
87
88 type - value 1..7 for interpreting the data
89 1: unicode string
90 2: unicode string with environment variable
91 3: binary
92 4: little-endian 32-bit
93 5: big-endian 32-bit
94 6: unicode string with a symbolic link
95 7: multiple unicode strings
96 data - blob of data to be interpreted depending on
97 type
98
78What: /config/usb-gadget/gadget/strings 99What: /config/usb-gadget/gadget/strings
79Date: Jun 2013 100Date: Jun 2013
80KernelVersion: 3.11 101KernelVersion: 3.11
diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c
index fa6cb06cca09..2ddcd635ca2a 100644
--- a/drivers/usb/gadget/configfs.c
+++ b/drivers/usb/gadget/configfs.c
@@ -7,6 +7,7 @@
7#include <linux/usb/gadget_configfs.h> 7#include <linux/usb/gadget_configfs.h>
8#include "configfs.h" 8#include "configfs.h"
9#include "u_f.h" 9#include "u_f.h"
10#include "u_os_desc.h"
10 11
11int check_user_usb_string(const char *name, 12int check_user_usb_string(const char *name,
12 struct usb_gadget_strings *stringtab_dev) 13 struct usb_gadget_strings *stringtab_dev)
@@ -941,6 +942,204 @@ static struct config_item_type os_desc_type = {
941CONFIGFS_ATTR_STRUCT(usb_os_desc); 942CONFIGFS_ATTR_STRUCT(usb_os_desc);
942CONFIGFS_ATTR_OPS(usb_os_desc); 943CONFIGFS_ATTR_OPS(usb_os_desc);
943 944
945
946static inline struct usb_os_desc_ext_prop
947*to_usb_os_desc_ext_prop(struct config_item *item)
948{
949 return container_of(item, struct usb_os_desc_ext_prop, item);
950}
951
952CONFIGFS_ATTR_STRUCT(usb_os_desc_ext_prop);
953CONFIGFS_ATTR_OPS(usb_os_desc_ext_prop);
954
955static ssize_t ext_prop_type_show(struct usb_os_desc_ext_prop *ext_prop,
956 char *page)
957{
958 return sprintf(page, "%d", ext_prop->type);
959}
960
961static ssize_t ext_prop_type_store(struct usb_os_desc_ext_prop *ext_prop,
962 const char *page, size_t len)
963{
964 struct usb_os_desc *desc = to_usb_os_desc(ext_prop->item.ci_parent);
965 u8 type;
966 int ret;
967
968 if (desc->opts_mutex)
969 mutex_lock(desc->opts_mutex);
970 ret = kstrtou8(page, 0, &type);
971 if (ret)
972 goto end;
973 if (type < USB_EXT_PROP_UNICODE || type > USB_EXT_PROP_UNICODE_MULTI) {
974 ret = -EINVAL;
975 goto end;
976 }
977
978 if ((ext_prop->type == USB_EXT_PROP_BINARY ||
979 ext_prop->type == USB_EXT_PROP_LE32 ||
980 ext_prop->type == USB_EXT_PROP_BE32) &&
981 (type == USB_EXT_PROP_UNICODE ||
982 type == USB_EXT_PROP_UNICODE_ENV ||
983 type == USB_EXT_PROP_UNICODE_LINK))
984 ext_prop->data_len <<= 1;
985 else if ((ext_prop->type == USB_EXT_PROP_UNICODE ||
986 ext_prop->type == USB_EXT_PROP_UNICODE_ENV ||
987 ext_prop->type == USB_EXT_PROP_UNICODE_LINK) &&
988 (type == USB_EXT_PROP_BINARY ||
989 type == USB_EXT_PROP_LE32 ||
990 type == USB_EXT_PROP_BE32))
991 ext_prop->data_len >>= 1;
992 ext_prop->type = type;
993 ret = len;
994
995end:
996 if (desc->opts_mutex)
997 mutex_unlock(desc->opts_mutex);
998 return ret;
999}
1000
1001static ssize_t ext_prop_data_show(struct usb_os_desc_ext_prop *ext_prop,
1002 char *page)
1003{
1004 int len = ext_prop->data_len;
1005
1006 if (ext_prop->type == USB_EXT_PROP_UNICODE ||
1007 ext_prop->type == USB_EXT_PROP_UNICODE_ENV ||
1008 ext_prop->type == USB_EXT_PROP_UNICODE_LINK)
1009 len >>= 1;
1010 memcpy(page, ext_prop->data, len);
1011
1012 return len;
1013}
1014
1015static ssize_t ext_prop_data_store(struct usb_os_desc_ext_prop *ext_prop,
1016 const char *page, size_t len)
1017{
1018 struct usb_os_desc *desc = to_usb_os_desc(ext_prop->item.ci_parent);
1019 char *new_data;
1020 size_t ret_len = len;
1021
1022 if (page[len - 1] == '\n' || page[len - 1] == '\0')
1023 --len;
1024 new_data = kzalloc(len, GFP_KERNEL);
1025 if (!new_data)
1026 return -ENOMEM;
1027
1028 memcpy(new_data, page, len);
1029
1030 if (desc->opts_mutex)
1031 mutex_lock(desc->opts_mutex);
1032 kfree(ext_prop->data);
1033 ext_prop->data = new_data;
1034 desc->ext_prop_len -= ext_prop->data_len;
1035 ext_prop->data_len = len;
1036 desc->ext_prop_len += ext_prop->data_len;
1037 if (ext_prop->type == USB_EXT_PROP_UNICODE ||
1038 ext_prop->type == USB_EXT_PROP_UNICODE_ENV ||
1039 ext_prop->type == USB_EXT_PROP_UNICODE_LINK) {
1040 desc->ext_prop_len -= ext_prop->data_len;
1041 ext_prop->data_len <<= 1;
1042 ext_prop->data_len += 2;
1043 desc->ext_prop_len += ext_prop->data_len;
1044 }
1045 if (desc->opts_mutex)
1046 mutex_unlock(desc->opts_mutex);
1047 return ret_len;
1048}
1049
1050static struct usb_os_desc_ext_prop_attribute ext_prop_type =
1051 __CONFIGFS_ATTR(type, S_IRUGO | S_IWUSR,
1052 ext_prop_type_show, ext_prop_type_store);
1053
1054static struct usb_os_desc_ext_prop_attribute ext_prop_data =
1055 __CONFIGFS_ATTR(data, S_IRUGO | S_IWUSR,
1056 ext_prop_data_show, ext_prop_data_store);
1057
1058static struct configfs_attribute *ext_prop_attrs[] = {
1059 &ext_prop_type.attr,
1060 &ext_prop_data.attr,
1061 NULL,
1062};
1063
1064static void usb_os_desc_ext_prop_release(struct config_item *item)
1065{
1066 struct usb_os_desc_ext_prop *ext_prop = to_usb_os_desc_ext_prop(item);
1067
1068 kfree(ext_prop); /* frees a whole chunk */
1069}
1070
1071static struct configfs_item_operations ext_prop_ops = {
1072 .release = usb_os_desc_ext_prop_release,
1073 .show_attribute = usb_os_desc_ext_prop_attr_show,
1074 .store_attribute = usb_os_desc_ext_prop_attr_store,
1075};
1076
1077static struct config_item *ext_prop_make(
1078 struct config_group *group,
1079 const char *name)
1080{
1081 struct usb_os_desc_ext_prop *ext_prop;
1082 struct config_item_type *ext_prop_type;
1083 struct usb_os_desc *desc;
1084 char *vlabuf;
1085
1086 vla_group(data_chunk);
1087 vla_item(data_chunk, struct usb_os_desc_ext_prop, ext_prop, 1);
1088 vla_item(data_chunk, struct config_item_type, ext_prop_type, 1);
1089
1090 vlabuf = kzalloc(vla_group_size(data_chunk), GFP_KERNEL);
1091 if (!vlabuf)
1092 return ERR_PTR(-ENOMEM);
1093
1094 ext_prop = vla_ptr(vlabuf, data_chunk, ext_prop);
1095 ext_prop_type = vla_ptr(vlabuf, data_chunk, ext_prop_type);
1096
1097 desc = container_of(group, struct usb_os_desc, group);
1098 ext_prop_type->ct_item_ops = &ext_prop_ops;
1099 ext_prop_type->ct_attrs = ext_prop_attrs;
1100 ext_prop_type->ct_owner = desc->owner;
1101
1102 config_item_init_type_name(&ext_prop->item, name, ext_prop_type);
1103
1104 ext_prop->name = kstrdup(name, GFP_KERNEL);
1105 if (!ext_prop->name) {
1106 kfree(vlabuf);
1107 return ERR_PTR(-ENOMEM);
1108 }
1109 desc->ext_prop_len += 14;
1110 ext_prop->name_len = 2 * strlen(ext_prop->name) + 2;
1111 if (desc->opts_mutex)
1112 mutex_lock(desc->opts_mutex);
1113 desc->ext_prop_len += ext_prop->name_len;
1114 list_add_tail(&ext_prop->entry, &desc->ext_prop);
1115 ++desc->ext_prop_count;
1116 if (desc->opts_mutex)
1117 mutex_unlock(desc->opts_mutex);
1118
1119 return &ext_prop->item;
1120}
1121
1122static void ext_prop_drop(struct config_group *group, struct config_item *item)
1123{
1124 struct usb_os_desc_ext_prop *ext_prop = to_usb_os_desc_ext_prop(item);
1125 struct usb_os_desc *desc = to_usb_os_desc(&group->cg_item);
1126
1127 if (desc->opts_mutex)
1128 mutex_lock(desc->opts_mutex);
1129 list_del(&ext_prop->entry);
1130 --desc->ext_prop_count;
1131 kfree(ext_prop->name);
1132 desc->ext_prop_len -= (ext_prop->name_len + ext_prop->data_len + 14);
1133 if (desc->opts_mutex)
1134 mutex_unlock(desc->opts_mutex);
1135 config_item_put(item);
1136}
1137
1138static struct configfs_group_operations interf_grp_ops = {
1139 .make_item = &ext_prop_make,
1140 .drop_item = &ext_prop_drop,
1141};
1142
944static struct configfs_item_operations interf_item_ops = { 1143static struct configfs_item_operations interf_item_ops = {
945 .show_attribute = usb_os_desc_attr_show, 1144 .show_attribute = usb_os_desc_attr_show,
946 .store_attribute = usb_os_desc_attr_store, 1145 .store_attribute = usb_os_desc_attr_store,
@@ -1048,6 +1247,7 @@ int usb_os_desc_prepare_interf_dir(struct config_group *parent,
1048 1247
1049 os_desc_group->default_groups = interface_groups; 1248 os_desc_group->default_groups = interface_groups;
1050 interface_type->ct_item_ops = &interf_item_ops; 1249 interface_type->ct_item_ops = &interf_item_ops;
1250 interface_type->ct_group_ops = &interf_grp_ops;
1051 interface_type->ct_attrs = interf_grp_attrs; 1251 interface_type->ct_attrs = interf_grp_attrs;
1052 interface_type->ct_owner = owner; 1252 interface_type->ct_owner = owner;
1053 1253
@@ -1055,6 +1255,7 @@ int usb_os_desc_prepare_interf_dir(struct config_group *parent,
1055 struct usb_os_desc *d; 1255 struct usb_os_desc *d;
1056 1256
1057 d = desc[n_interf]; 1257 d = desc[n_interf];
1258 d->owner = owner;
1058 config_group_init_type_name(&d->group, "", interface_type); 1259 config_group_init_type_name(&d->group, "", interface_type);
1059 config_item_set_name(&d->group.cg_item, "interface.%d", 1260 config_item_set_name(&d->group.cg_item, "interface.%d",
1060 n_interf); 1261 n_interf);
diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h
index 9c3903d76781..7373203140e7 100644
--- a/include/linux/usb/composite.h
+++ b/include/linux/usb/composite.h
@@ -64,6 +64,7 @@ struct usb_configuration;
64 * @name: Extended Property name 64 * @name: Extended Property name
65 * @data_len: Length of Extended Property blob (for unicode store double len) 65 * @data_len: Length of Extended Property blob (for unicode store double len)
66 * @data: Extended Property blob 66 * @data: Extended Property blob
67 * @item: Represents this Extended Property in configfs
67 */ 68 */
68struct usb_os_desc_ext_prop { 69struct usb_os_desc_ext_prop {
69 struct list_head entry; 70 struct list_head entry;
@@ -72,6 +73,7 @@ struct usb_os_desc_ext_prop {
72 char *name; 73 char *name;
73 int data_len; 74 int data_len;
74 char *data; 75 char *data;
76 struct config_item item;
75}; 77};
76 78
77/** 79/**
@@ -82,6 +84,7 @@ struct usb_os_desc_ext_prop {
82 * @ext_prop_count: Number of Extended Properties 84 * @ext_prop_count: Number of Extended Properties
83 * @opts_mutex: Optional mutex protecting config data of a usb_function_instance 85 * @opts_mutex: Optional mutex protecting config data of a usb_function_instance
84 * @group: Represents OS descriptors associated with an interface in configfs 86 * @group: Represents OS descriptors associated with an interface in configfs
87 * @owner: Module associated with this OS descriptor
85 */ 88 */
86struct usb_os_desc { 89struct usb_os_desc {
87 char *ext_compat_id; 90 char *ext_compat_id;
@@ -90,6 +93,7 @@ struct usb_os_desc {
90 int ext_prop_count; 93 int ext_prop_count;
91 struct mutex *opts_mutex; 94 struct mutex *opts_mutex;
92 struct config_group group; 95 struct config_group group;
96 struct module *owner;
93}; 97};
94 98
95/** 99/**