usb: gadget: Accessory:Migrate to USB_FUNCTION API
authorBadhri Jagan Sridharan <Badhri@google.com>
Mon, 24 Nov 2014 01:21:22 +0000 (17:21 -0800)
committerJohn Stultz <john.stultz@linaro.org>
Tue, 16 Feb 2016 21:52:10 +0000 (13:52 -0800)
This patch adds support to use Android accessory
gadget function through the
DECLARE_USB_FUNCTION_INIT interface.

Signed-off-by: Badhri Jagan Sridharan <badhri@google.com>
Change-Id: Ib352752d5bc905fa1df9049b53eabf1294930db7

drivers/usb/gadget/Kconfig
drivers/usb/gadget/Makefile
drivers/usb/gadget/f_accessory.c

index f550989173bfc1d93bf22db6a7bd56a6b365d772..221f2c50d7e274050d82066972885d147a2e75b0 100644 (file)
@@ -208,6 +208,9 @@ config USB_F_PTP
 config USB_F_AUDIO_SRC
        tristate
 
+config USB_F_ACC
+       tristate
+
 choice
        tristate "USB Gadget Drivers"
        default USB_ETH
@@ -394,9 +397,16 @@ config USB_CONFIGFS_F_PTP
        help
          USB gadget PTP support
 
+config USB_CONFIGFS_F_ACC
+       boolean "Accessory gadget"
+       depends on USB_CONFIGFS
+       select USB_F_ACC
+       help
+         USB gadget Accessory support
+
 config USB_CONFIGFS_F_AUDIO_SRC
        boolean "Audio Source gadget"
-       depends on USB_CONFIGFS
+       depends on USB_CONFIGFS && USB_CONFIGFS_F_ACC
        select USB_F_AUDIO_SRC
        help
          USB gadget Audio Source support
index 598a67d6ba05fcc5c5ebd159f1384725acf25c8b..1b55d76ee049e8ba291ac0915942d0618f0a348e 100644 (file)
@@ -9,4 +9,7 @@ obj-$(CONFIG_USB_LIBCOMPOSITE)  += libcomposite.o
 libcomposite-y                 := usbstring.o config.o epautoconf.o
 libcomposite-y                 += composite.o functions.o configfs.o u_f.o
 
+usb_f_accessory-y               := f_accessory.o
+obj-$(CONFIG_USB_F_ACC)         += usb_f_accessory.o
+
 obj-$(CONFIG_USB_GADGET)       += udc/ function/ legacy/
index 9ffe017bf1cf3a67030235b61b70f83d6345e526..d9db5c595b9958c385c64693d2bc904a6528eb2d 100644 (file)
 #include <linux/usb/ch9.h>
 #include <linux/usb/f_accessory.h>
 
+#include <linux/configfs.h>
+#include <linux/usb/composite.h>
+
+#define MAX_INST_NAME_LEN        40
 #define BULK_BUFFER_SIZE    16384
 #define ACC_STRING_SIZE     256
 
@@ -194,6 +198,11 @@ static struct usb_gadget_strings *acc_strings[] = {
 /* temporary variable used between acc_open() and acc_gadget_bind() */
 static struct acc_dev *_acc_dev;
 
+struct acc_instance {
+       struct usb_function_instance func_inst;
+       const char *name;
+};
+
 static inline struct acc_dev *func_to_dev(struct usb_function *f)
 {
        return container_of(f, struct acc_dev, function);
@@ -775,7 +784,7 @@ static struct hid_driver acc_hid_driver = {
        .probe = acc_hid_probe,
 };
 
-static int acc_ctrlrequest(struct usb_composite_dev *cdev,
+int acc_ctrlrequest(struct usb_composite_dev *cdev,
                                const struct usb_ctrlrequest *ctrl)
 {
        struct acc_dev  *dev = _acc_dev;
@@ -879,9 +888,11 @@ err:
                        w_value, w_index, w_length);
        return value;
 }
+EXPORT_SYMBOL_GPL(acc_ctrlrequest);
 
 static int
-acc_function_bind(struct usb_configuration *c, struct usb_function *f)
+__acc_function_bind(struct usb_configuration *c,
+                       struct usb_function *f, bool configfs)
 {
        struct usb_composite_dev *cdev = c->cdev;
        struct acc_dev  *dev = func_to_dev(f);
@@ -890,6 +901,16 @@ acc_function_bind(struct usb_configuration *c, struct usb_function *f)
 
        DBG(cdev, "acc_function_bind dev: %p\n", dev);
 
+       if (configfs) {
+               if (acc_string_defs[INTERFACE_STRING_INDEX].id == 0) {
+                       ret = usb_string_id(c->cdev);
+                       if (ret < 0)
+                               return ret;
+                       acc_string_defs[INTERFACE_STRING_INDEX].id = ret;
+                       acc_interface_desc.iInterface = ret;
+               }
+               dev->cdev = c->cdev;
+       }
        ret = hid_register_driver(&acc_hid_driver);
        if (ret)
                return ret;
@@ -922,6 +943,17 @@ acc_function_bind(struct usb_configuration *c, struct usb_function *f)
        return 0;
 }
 
+static int
+acc_function_bind(struct usb_configuration *c, struct usb_function *f) {
+       return __acc_function_bind(c, f, false);
+}
+
+static int
+acc_function_bind_configfs(struct usb_configuration *c,
+                       struct usb_function *f) {
+       return __acc_function_bind(c, f, true);
+}
+
 static void
 kill_all_hid_devices(struct acc_dev *dev)
 {
@@ -1179,11 +1211,12 @@ err:
        return ret;
 }
 
-static void acc_disconnect(void)
+void acc_disconnect(void)
 {
        /* unregister all HID devices if USB is disconnected */
        kill_all_hid_devices(_acc_dev);
 }
+EXPORT_SYMBOL_GPL(acc_disconnect);
 
 static void acc_cleanup(void)
 {
@@ -1191,3 +1224,117 @@ static void acc_cleanup(void)
        kfree(_acc_dev);
        _acc_dev = NULL;
 }
+static struct acc_instance *to_acc_instance(struct config_item *item)
+{
+       return container_of(to_config_group(item), struct acc_instance,
+               func_inst.group);
+}
+
+static void acc_attr_release(struct config_item *item)
+{
+       struct acc_instance *fi_acc = to_acc_instance(item);
+
+       usb_put_function_instance(&fi_acc->func_inst);
+}
+
+static struct configfs_item_operations acc_item_ops = {
+       .release        = acc_attr_release,
+};
+
+static struct config_item_type acc_func_type = {
+       .ct_item_ops    = &acc_item_ops,
+       .ct_owner       = THIS_MODULE,
+};
+
+static struct acc_instance *to_fi_acc(struct usb_function_instance *fi)
+{
+       return container_of(fi, struct acc_instance, func_inst);
+}
+
+static int acc_set_inst_name(struct usb_function_instance *fi, const char *name)
+{
+       struct acc_instance *fi_acc;
+       char *ptr;
+       int name_len;
+
+       name_len = strlen(name) + 1;
+       if (name_len > MAX_INST_NAME_LEN)
+               return -ENAMETOOLONG;
+
+       ptr = kstrndup(name, name_len, GFP_KERNEL);
+       if (!ptr)
+               return -ENOMEM;
+
+       fi_acc = to_fi_acc(fi);
+       fi_acc->name = ptr;
+       return 0;
+}
+
+static void acc_free_inst(struct usb_function_instance *fi)
+{
+       struct acc_instance *fi_acc;
+
+       fi_acc = to_fi_acc(fi);
+       kfree(fi_acc->name);
+       acc_cleanup();
+}
+
+static struct usb_function_instance *acc_alloc_inst(void)
+{
+       struct acc_instance *fi_acc;
+       struct acc_dev *dev;
+       int err;
+
+       fi_acc = kzalloc(sizeof(*fi_acc), GFP_KERNEL);
+       if (!fi_acc)
+               return ERR_PTR(-ENOMEM);
+       fi_acc->func_inst.set_inst_name = acc_set_inst_name;
+       fi_acc->func_inst.free_func_inst = acc_free_inst;
+
+       err = acc_setup();
+       if (err) {
+               kfree(fi_acc);
+               pr_err("Error setting ACCESSORY\n");
+               return ERR_PTR(err);
+       }
+
+       config_group_init_type_name(&fi_acc->func_inst.group,
+                                       "", &acc_func_type);
+       dev = _acc_dev;
+       return  &fi_acc->func_inst;
+}
+
+static void acc_free(struct usb_function *f)
+{
+/*NO-OP: no function specific resource allocation in mtp_alloc*/
+}
+
+int acc_ctrlrequest_configfs(struct usb_function *f,
+                       const struct usb_ctrlrequest *ctrl) {
+       if (f->config != NULL && f->config->cdev != NULL)
+               return acc_ctrlrequest(f->config->cdev, ctrl);
+       else
+               return -1;
+}
+
+static struct usb_function *acc_alloc(struct usb_function_instance *fi)
+{
+       struct acc_dev *dev = _acc_dev;
+
+       pr_info("acc_alloc\n");
+
+       dev->function.name = "accessory";
+       dev->function.strings = acc_strings,
+       dev->function.fs_descriptors = fs_acc_descs;
+       dev->function.hs_descriptors = hs_acc_descs;
+       dev->function.bind = acc_function_bind_configfs;
+       dev->function.unbind = acc_function_unbind;
+       dev->function.set_alt = acc_function_set_alt;
+       dev->function.disable = acc_function_disable;
+       dev->function.free_func = acc_free;
+       dev->function.setup = acc_ctrlrequest_configfs;
+
+       return &dev->function;
+}
+DECLARE_USB_FUNCTION_INIT(accessory, acc_alloc_inst, acc_alloc);
+MODULE_LICENSE("GPL");