aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorAndrzej Pietrasiewicz <andrzej.p@samsung.com>2014-05-08 08:06:26 -0400
committerFelipe Balbi <balbi@ti.com>2014-05-14 10:39:25 -0400
commitda4243145fb197622425d4c2feff5d6422f2391e (patch)
tree83405fcd69a4ae077c3364f584ab90b1314449a3 /drivers
parent87213d388e927aaa88b21d5ff7e1f75ca2288da1 (diff)
usb: gadget: configfs: OS Extended Compatibility descriptors support
Add handling of OS Extended Compatibility descriptors from configfs interface. Hosts which expect the "OS Descriptors" ask only for configurations @ index 0, but linux-based USB devices can provide more than one configuration. This patch adds marking one of gadget's configurations the configuration to be reported at index 0, regardless of the actual sequence of usb_add_config invocations used for adding the configurations. The configuration is selected by creating a symbolic link pointing to it from the "os_desc" directory located at the top of a gadget's directory hierarchy. One kind of "OS Descriptors" are "Extended Compatibility Descriptors", which need to be specified per interface. This patch adds interface.<n> directory in function's configfs directory to represent each interface defined by the function. Each interface's directory contains two attributes: "compatible_id" and "sub_compatible_id", which represent 8-byte strings to be reported to the host as the "Compatible ID" and "Sub Compatible ID". Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@samsung.com> Signed-off-by: Felipe Balbi <balbi@ti.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/usb/gadget/configfs.c190
-rw-r--r--drivers/usb/gadget/configfs.h12
2 files changed, 202 insertions, 0 deletions
diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c
index 8b9e038ac22b..fa6cb06cca09 100644
--- a/drivers/usb/gadget/configfs.c
+++ b/drivers/usb/gadget/configfs.c
@@ -6,6 +6,7 @@
6#include <linux/usb/composite.h> 6#include <linux/usb/composite.h>
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 10
10int check_user_usb_string(const char *name, 11int check_user_usb_string(const char *name,
11 struct usb_gadget_strings *stringtab_dev) 12 struct usb_gadget_strings *stringtab_dev)
@@ -872,10 +873,63 @@ static void os_desc_attr_release(struct config_item *item)
872 kfree(os_desc); 873 kfree(os_desc);
873} 874}
874 875
876static int os_desc_link(struct config_item *os_desc_ci,
877 struct config_item *usb_cfg_ci)
878{
879 struct gadget_info *gi = container_of(to_config_group(os_desc_ci),
880 struct gadget_info, os_desc_group);
881 struct usb_composite_dev *cdev = &gi->cdev;
882 struct config_usb_cfg *c_target =
883 container_of(to_config_group(usb_cfg_ci),
884 struct config_usb_cfg, group);
885 struct usb_configuration *c;
886 int ret;
887
888 mutex_lock(&gi->lock);
889 list_for_each_entry(c, &cdev->configs, list) {
890 if (c == &c_target->c)
891 break;
892 }
893 if (c != &c_target->c) {
894 ret = -EINVAL;
895 goto out;
896 }
897
898 if (cdev->os_desc_config) {
899 ret = -EBUSY;
900 goto out;
901 }
902
903 cdev->os_desc_config = &c_target->c;
904 ret = 0;
905
906out:
907 mutex_unlock(&gi->lock);
908 return ret;
909}
910
911static int os_desc_unlink(struct config_item *os_desc_ci,
912 struct config_item *usb_cfg_ci)
913{
914 struct gadget_info *gi = container_of(to_config_group(os_desc_ci),
915 struct gadget_info, os_desc_group);
916 struct usb_composite_dev *cdev = &gi->cdev;
917
918 mutex_lock(&gi->lock);
919 if (gi->udc_name)
920 unregister_gadget(gi);
921 cdev->os_desc_config = NULL;
922 WARN_ON(gi->udc_name);
923 mutex_unlock(&gi->lock);
924 return 0;
925}
926
875static struct configfs_item_operations os_desc_ops = { 927static struct configfs_item_operations os_desc_ops = {
876 .release = os_desc_attr_release, 928 .release = os_desc_attr_release,
877 .show_attribute = os_desc_attr_show, 929 .show_attribute = os_desc_attr_show,
878 .store_attribute = os_desc_attr_store, 930 .store_attribute = os_desc_attr_store,
931 .allow_link = os_desc_link,
932 .drop_link = os_desc_unlink,
879}; 933};
880 934
881static struct config_item_type os_desc_type = { 935static struct config_item_type os_desc_type = {
@@ -884,6 +938,133 @@ static struct config_item_type os_desc_type = {
884 .ct_owner = THIS_MODULE, 938 .ct_owner = THIS_MODULE,
885}; 939};
886 940
941CONFIGFS_ATTR_STRUCT(usb_os_desc);
942CONFIGFS_ATTR_OPS(usb_os_desc);
943
944static struct configfs_item_operations interf_item_ops = {
945 .show_attribute = usb_os_desc_attr_show,
946 .store_attribute = usb_os_desc_attr_store,
947};
948
949static ssize_t rndis_grp_compatible_id_show(struct usb_os_desc *desc,
950 char *page)
951{
952 memcpy(page, desc->ext_compat_id, 8);
953 return 8;
954}
955
956static ssize_t rndis_grp_compatible_id_store(struct usb_os_desc *desc,
957 const char *page, size_t len)
958{
959 int l;
960
961 l = min_t(int, 8, len);
962 if (page[l - 1] == '\n')
963 --l;
964 if (desc->opts_mutex)
965 mutex_lock(desc->opts_mutex);
966 memcpy(desc->ext_compat_id, page, l);
967 desc->ext_compat_id[l] = '\0';
968
969 if (desc->opts_mutex)
970 mutex_unlock(desc->opts_mutex);
971
972 return len;
973}
974
975static struct usb_os_desc_attribute rndis_grp_attr_compatible_id =
976 __CONFIGFS_ATTR(compatible_id, S_IRUGO | S_IWUSR,
977 rndis_grp_compatible_id_show,
978 rndis_grp_compatible_id_store);
979
980static ssize_t rndis_grp_sub_compatible_id_show(struct usb_os_desc *desc,
981 char *page)
982{
983 memcpy(page, desc->ext_compat_id + 8, 8);
984 return 8;
985}
986
987static ssize_t rndis_grp_sub_compatible_id_store(struct usb_os_desc *desc,
988 const char *page, size_t len)
989{
990 int l;
991
992 l = min_t(int, 8, len);
993 if (page[l - 1] == '\n')
994 --l;
995 if (desc->opts_mutex)
996 mutex_lock(desc->opts_mutex);
997 memcpy(desc->ext_compat_id + 8, page, l);
998 desc->ext_compat_id[l + 8] = '\0';
999
1000 if (desc->opts_mutex)
1001 mutex_unlock(desc->opts_mutex);
1002
1003 return len;
1004}
1005
1006static struct usb_os_desc_attribute rndis_grp_attr_sub_compatible_id =
1007 __CONFIGFS_ATTR(sub_compatible_id, S_IRUGO | S_IWUSR,
1008 rndis_grp_sub_compatible_id_show,
1009 rndis_grp_sub_compatible_id_store);
1010
1011static struct configfs_attribute *interf_grp_attrs[] = {
1012 &rndis_grp_attr_compatible_id.attr,
1013 &rndis_grp_attr_sub_compatible_id.attr,
1014 NULL
1015};
1016
1017int usb_os_desc_prepare_interf_dir(struct config_group *parent,
1018 int n_interf,
1019 struct usb_os_desc **desc,
1020 struct module *owner)
1021{
1022 struct config_group **f_default_groups, *os_desc_group,
1023 **interface_groups;
1024 struct config_item_type *os_desc_type, *interface_type;
1025
1026 vla_group(data_chunk);
1027 vla_item(data_chunk, struct config_group *, f_default_groups, 2);
1028 vla_item(data_chunk, struct config_group, os_desc_group, 1);
1029 vla_item(data_chunk, struct config_group *, interface_groups,
1030 n_interf + 1);
1031 vla_item(data_chunk, struct config_item_type, os_desc_type, 1);
1032 vla_item(data_chunk, struct config_item_type, interface_type, 1);
1033
1034 char *vlabuf = kzalloc(vla_group_size(data_chunk), GFP_KERNEL);
1035 if (!vlabuf)
1036 return -ENOMEM;
1037
1038 f_default_groups = vla_ptr(vlabuf, data_chunk, f_default_groups);
1039 os_desc_group = vla_ptr(vlabuf, data_chunk, os_desc_group);
1040 os_desc_type = vla_ptr(vlabuf, data_chunk, os_desc_type);
1041 interface_groups = vla_ptr(vlabuf, data_chunk, interface_groups);
1042 interface_type = vla_ptr(vlabuf, data_chunk, interface_type);
1043
1044 parent->default_groups = f_default_groups;
1045 os_desc_type->ct_owner = owner;
1046 config_group_init_type_name(os_desc_group, "os_desc", os_desc_type);
1047 f_default_groups[0] = os_desc_group;
1048
1049 os_desc_group->default_groups = interface_groups;
1050 interface_type->ct_item_ops = &interf_item_ops;
1051 interface_type->ct_attrs = interf_grp_attrs;
1052 interface_type->ct_owner = owner;
1053
1054 while (n_interf--) {
1055 struct usb_os_desc *d;
1056
1057 d = desc[n_interf];
1058 config_group_init_type_name(&d->group, "", interface_type);
1059 config_item_set_name(&d->group.cg_item, "interface.%d",
1060 n_interf);
1061 interface_groups[n_interf] = &d->group;
1062 }
1063
1064 return 0;
1065}
1066EXPORT_SYMBOL(usb_os_desc_prepare_interf_dir);
1067
887static int configfs_do_nothing(struct usb_composite_dev *cdev) 1068static int configfs_do_nothing(struct usb_composite_dev *cdev)
888{ 1069{
889 WARN_ON(1); 1070 WARN_ON(1);
@@ -893,6 +1074,9 @@ static int configfs_do_nothing(struct usb_composite_dev *cdev)
893int composite_dev_prepare(struct usb_composite_driver *composite, 1074int composite_dev_prepare(struct usb_composite_driver *composite,
894 struct usb_composite_dev *dev); 1075 struct usb_composite_dev *dev);
895 1076
1077int composite_os_desc_req_prepare(struct usb_composite_dev *cdev,
1078 struct usb_ep *ep0);
1079
896static void purge_configs_funcs(struct gadget_info *gi) 1080static void purge_configs_funcs(struct gadget_info *gi)
897{ 1081{
898 struct usb_configuration *c; 1082 struct usb_configuration *c;
@@ -1028,6 +1212,12 @@ static int configfs_composite_bind(struct usb_gadget *gadget,
1028 } 1212 }
1029 usb_ep_autoconfig_reset(cdev->gadget); 1213 usb_ep_autoconfig_reset(cdev->gadget);
1030 } 1214 }
1215 if (cdev->use_os_string) {
1216 ret = composite_os_desc_req_prepare(cdev, gadget->ep0);
1217 if (ret)
1218 goto err_purge_funcs;
1219 }
1220
1031 usb_ep_autoconfig_reset(cdev->gadget); 1221 usb_ep_autoconfig_reset(cdev->gadget);
1032 return 0; 1222 return 0;
1033 1223
diff --git a/drivers/usb/gadget/configfs.h b/drivers/usb/gadget/configfs.h
index a7b564a913d1..a14ac792c698 100644
--- a/drivers/usb/gadget/configfs.h
+++ b/drivers/usb/gadget/configfs.h
@@ -1,6 +1,18 @@
1#ifndef USB__GADGET__CONFIGFS__H 1#ifndef USB__GADGET__CONFIGFS__H
2#define USB__GADGET__CONFIGFS__H 2#define USB__GADGET__CONFIGFS__H
3 3
4#include <linux/configfs.h>
5
4void unregister_gadget_item(struct config_item *item); 6void unregister_gadget_item(struct config_item *item);
5 7
8int usb_os_desc_prepare_interf_dir(struct config_group *parent,
9 int n_interf,
10 struct usb_os_desc **desc,
11 struct module *owner);
12
13static inline struct usb_os_desc *to_usb_os_desc(struct config_item *item)
14{
15 return container_of(to_config_group(item), struct usb_os_desc, group);
16}
17
6#endif /* USB__GADGET__CONFIGFS__H */ 18#endif /* USB__GADGET__CONFIGFS__H */