Generate descriptors in new format and attach them to USB function in
prep_descs(). Implement prep_vendor_descs() to supply class specific
descriptors. Change set_alt() implementation and implement clear_alt()
operation. Move cdev initialization to hidg_alloc(). Remove boilerplate
code.

Signed-off-by: Robert Baldyga <r.bald...@samsung.com>
---
 drivers/usb/gadget/function/f_hid.c | 305 ++++++++++++++----------------------
 1 file changed, 119 insertions(+), 186 deletions(-)

diff --git a/drivers/usb/gadget/function/f_hid.c 
b/drivers/usb/gadget/function/f_hid.c
index 0456a53..8770289 100644
--- a/drivers/usb/gadget/function/f_hid.c
+++ b/drivers/usb/gadget/function/f_hid.c
@@ -125,14 +125,6 @@ static struct usb_endpoint_descriptor hidg_hs_out_ep_desc 
= {
                                      */
 };
 
-static struct usb_descriptor_header *hidg_hs_descriptors[] = {
-       (struct usb_descriptor_header *)&hidg_interface_desc,
-       (struct usb_descriptor_header *)&hidg_desc,
-       (struct usb_descriptor_header *)&hidg_hs_in_ep_desc,
-       (struct usb_descriptor_header *)&hidg_hs_out_ep_desc,
-       NULL,
-};
-
 /* Full-Speed Support */
 
 static struct usb_endpoint_descriptor hidg_fs_in_ep_desc = {
@@ -159,13 +151,16 @@ static struct usb_endpoint_descriptor hidg_fs_out_ep_desc 
= {
                                       */
 };
 
-static struct usb_descriptor_header *hidg_fs_descriptors[] = {
-       (struct usb_descriptor_header *)&hidg_interface_desc,
-       (struct usb_descriptor_header *)&hidg_desc,
-       (struct usb_descriptor_header *)&hidg_fs_in_ep_desc,
-       (struct usb_descriptor_header *)&hidg_fs_out_ep_desc,
-       NULL,
-};
+USB_COMPOSITE_ENDPOINT(ep_in, &hidg_fs_in_ep_desc,
+               &hidg_hs_in_ep_desc, NULL, NULL);
+USB_COMPOSITE_ENDPOINT(ep_out, &hidg_fs_out_ep_desc,
+               &hidg_hs_out_ep_desc, NULL, NULL);
+
+USB_COMPOSITE_ALTSETTING(intf0alt0, &hidg_interface_desc, &ep_in, &ep_out);
+
+USB_COMPOSITE_INTERFACE(intf0, &intf0alt0);
+
+USB_COMPOSITE_DESCRIPTORS(hidg_descs, &intf0);
 
 /*-------------------------------------------------------------------------*/
 /*                                 Strings                                 */
@@ -487,27 +482,6 @@ respond:
        return status;
 }
 
-static void hidg_disable(struct usb_function *f)
-{
-       struct f_hidg *hidg = func_to_hidg(f);
-       struct f_hidg_req_list *list, *next;
-       int i;
-
-       usb_ep_disable(hidg->in_ep);
-       usb_ep_disable(hidg->out_ep);
-
-       list_for_each_entry_safe(list, next, &hidg->completed_out_req, list) {
-               list_del(&list->list);
-               kfree(list);
-       }
-
-       for (i = 0; i < hidg->qlen; ++i) {
-               kfree(hidg->out_reqs[i]->buf);
-               kfree(hidg->out_reqs[i]);
-       }
-       kfree(hidg->out_reqs);
-}
-
 static int hidg_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 {
        struct usb_composite_dev                *cdev = f->config->cdev;
@@ -516,65 +490,46 @@ static int hidg_set_alt(struct usb_function *f, unsigned 
intf, unsigned alt)
 
        VDBG(cdev, "hidg_set_alt intf:%d alt:%d\n", intf, alt);
 
-       if (hidg->in_ep != NULL) {
-               /* restart endpoint */
-               usb_ep_disable(hidg->in_ep);
+       hidg->in_ep = usb_function_get_ep(f, intf, 0);
+       if (!hidg->in_ep)
+               return -ENODEV;
+       hidg->in_ep->driver_data = hidg;
 
-               status = config_ep_by_speed(f->config->cdev->gadget, f,
-                                           hidg->in_ep);
-               if (status) {
-                       ERROR(cdev, "config_ep_by_speed FAILED!\n");
-                       goto fail;
-               }
-               status = usb_ep_enable(hidg->in_ep);
-               if (status < 0) {
-                       ERROR(cdev, "Enable IN endpoint FAILED!\n");
-                       goto fail;
-               }
-               hidg->in_ep->driver_data = hidg;
-       }
+       hidg->out_ep = usb_function_get_ep(f, intf, 1);
+       if (!hidg->out_ep)
+               return -ENODEV;
+       hidg->out_ep->driver_data = hidg;
 
+       /* preallocate request and buffer */
+       hidg->req = usb_ep_alloc_request(hidg->in_ep, GFP_KERNEL);
+       if (!hidg->req)
+               return -ENOMEM;
 
-       if (hidg->out_ep != NULL) {
-               /* restart endpoint */
-               usb_ep_disable(hidg->out_ep);
+       hidg->req->buf = kmalloc(hidg->report_length, GFP_KERNEL);
+       if (!hidg->req->buf)
+               return -ENOMEM;
 
-               status = config_ep_by_speed(f->config->cdev->gadget, f,
-                                           hidg->out_ep);
-               if (status) {
-                       ERROR(cdev, "config_ep_by_speed FAILED!\n");
-                       goto fail;
-               }
-               status = usb_ep_enable(hidg->out_ep);
-               if (status < 0) {
-                       ERROR(cdev, "Enable IN endpoint FAILED!\n");
-                       goto fail;
-               }
-               hidg->out_ep->driver_data = hidg;
-
-               /*
-                * allocate a bunch of read buffers and queue them all at once.
-                */
-               hidg->out_reqs = kzalloc(hidg->qlen *
-                               sizeof(*hidg->out_reqs), GFP_KERNEL);
-               for (i = 0; i < hidg->qlen && status == 0; i++) {
-                       struct usb_request *req =
-                                       hidg_alloc_ep_req(hidg->out_ep,
-                                                         hidg->report_length);
-                       if (req) {
+       /*
+        * allocate a bunch of read buffers and queue them all at once.
+        */
+       hidg->out_reqs = kzalloc(hidg->qlen *
+                       sizeof(*hidg->out_reqs), GFP_KERNEL);
+       for (i = 0; i < hidg->qlen && status == 0; i++) {
+               struct usb_request *req =
+                       hidg_alloc_ep_req(hidg->out_ep,
+                                       hidg->report_length);
+               if (req) {
                                hidg->out_reqs[i] = req;
-                               req->complete = hidg_set_report_complete;
-                               req->context  = hidg;
-                               status = usb_ep_queue(hidg->out_ep, req,
-                                                     GFP_ATOMIC);
-                               if (status)
-                                       ERROR(cdev, "%s queue req --> %d\n",
+                       req->complete = hidg_set_report_complete;
+                       req->context  = hidg;
+                       status = usb_ep_queue(hidg->out_ep, req,
+                                       GFP_ATOMIC);
+                       if (status)
+                               ERROR(cdev, "%s queue req --> %d\n",
                                                hidg->out_ep->name, status);
-                       } else {
-                               usb_ep_disable(hidg->out_ep);
-                               status = -ENOMEM;
-                               goto free_req;
-                       }
+               } else {
+                       status = -ENOMEM;
+                       goto free_req;
                }
        }
 
@@ -587,10 +542,31 @@ free_req:
                kfree(hidg->out_reqs);
        }
 
-fail:
        return status;
 }
 
+static void hidg_clear_alt(struct usb_function *f, unsigned intf, unsigned alt)
+{
+       struct f_hidg *hidg = func_to_hidg(f);
+       struct f_hidg_req_list *list, *next;
+       int i;
+
+       list_for_each_entry_safe(list, next, &hidg->completed_out_req, list) {
+               list_del(&list->list);
+               kfree(list);
+       }
+
+       for (i = 0; i < hidg->qlen; ++i) {
+               kfree(hidg->out_reqs[i]->buf);
+               kfree(hidg->out_reqs[i]);
+       }
+       kfree(hidg->out_reqs);
+
+       /* disable/free request and end point */
+       kfree(hidg->req->buf);
+       usb_ep_free_request(hidg->in_ep, hidg->req);
+}
+
 static const struct file_operations f_hidg_fops = {
        .owner          = THIS_MODULE,
        .open           = f_hidg_open,
@@ -601,50 +577,19 @@ static const struct file_operations f_hidg_fops = {
        .llseek         = noop_llseek,
 };
 
-static int hidg_bind(struct usb_configuration *c, struct usb_function *f)
+static int hidg_prep_descs(struct usb_function *f)
 {
-       struct usb_ep           *ep;
+       struct usb_composite_dev *cdev = f->config->cdev;
        struct f_hidg           *hidg = func_to_hidg(f);
        struct usb_string       *us;
-       struct device           *device;
-       int                     status;
-       dev_t                   dev;
 
        /* maybe allocate device-global string IDs, and patch descriptors */
-       us = usb_gstrings_attach(c->cdev, ct_func_strings,
+       us = usb_gstrings_attach(cdev, ct_func_strings,
                                 ARRAY_SIZE(ct_func_string_defs));
        if (IS_ERR(us))
                return PTR_ERR(us);
        hidg_interface_desc.iInterface = us[CT_FUNC_HID_IDX].id;
 
-       /* allocate instance-specific interface IDs, and patch descriptors */
-       status = usb_interface_id(c, f);
-       if (status < 0)
-               goto fail;
-       hidg_interface_desc.bInterfaceNumber = status;
-
-       /* allocate instance-specific endpoints */
-       status = -ENODEV;
-       ep = usb_ep_autoconfig(c->cdev->gadget, &hidg_fs_in_ep_desc);
-       if (!ep)
-               goto fail;
-       hidg->in_ep = ep;
-
-       ep = usb_ep_autoconfig(c->cdev->gadget, &hidg_fs_out_ep_desc);
-       if (!ep)
-               goto fail;
-       hidg->out_ep = ep;
-
-       /* preallocate request and buffer */
-       status = -ENOMEM;
-       hidg->req = usb_ep_alloc_request(hidg->in_ep, GFP_KERNEL);
-       if (!hidg->req)
-               goto fail;
-
-       hidg->req->buf = kmalloc(hidg->report_length, GFP_KERNEL);
-       if (!hidg->req->buf)
-               goto fail;
-
        /* set descriptor dynamic values */
        hidg_interface_desc.bInterfaceSubClass = hidg->bInterfaceSubClass;
        hidg_interface_desc.bInterfaceProtocol = hidg->bInterfaceProtocol;
@@ -652,6 +597,14 @@ static int hidg_bind(struct usb_configuration *c, struct 
usb_function *f)
        hidg_fs_in_ep_desc.wMaxPacketSize = cpu_to_le16(hidg->report_length);
        hidg_hs_out_ep_desc.wMaxPacketSize = cpu_to_le16(hidg->report_length);
        hidg_fs_out_ep_desc.wMaxPacketSize = cpu_to_le16(hidg->report_length);
+
+       return usb_function_set_descs(f, &hidg_descs);
+}
+
+static int hidg_prep_vendor_descs(struct usb_function *f)
+{
+       struct f_hidg           *hidg = func_to_hidg(f);
+
        /*
         * We can use hidg_desc struct here but we should not relay
         * that its content won't change after returning from this function.
@@ -660,50 +613,10 @@ static int hidg_bind(struct usb_configuration *c, struct 
usb_function *f)
        hidg_desc.desc[0].wDescriptorLength =
                cpu_to_le16(hidg->report_desc_length);
 
-       hidg_hs_in_ep_desc.bEndpointAddress =
-               hidg_fs_in_ep_desc.bEndpointAddress;
-       hidg_hs_out_ep_desc.bEndpointAddress =
-               hidg_fs_out_ep_desc.bEndpointAddress;
-
-       status = usb_assign_descriptors(f, hidg_fs_descriptors,
-                       hidg_hs_descriptors, NULL);
-       if (status)
-               goto fail;
-
-       mutex_init(&hidg->lock);
-       spin_lock_init(&hidg->spinlock);
-       init_waitqueue_head(&hidg->write_queue);
-       init_waitqueue_head(&hidg->read_queue);
-       INIT_LIST_HEAD(&hidg->completed_out_req);
-
-       /* create char device */
-       cdev_init(&hidg->cdev, &f_hidg_fops);
-       dev = MKDEV(major, hidg->minor);
-       status = cdev_add(&hidg->cdev, dev, 1);
-       if (status)
-               goto fail_free_descs;
-
-       device = device_create(hidg_class, NULL, dev, NULL,
-                              "%s%d", "hidg", hidg->minor);
-       if (IS_ERR(device)) {
-               status = PTR_ERR(device);
-               goto del;
-       }
+       usb_altset_add_vendor_desc(f, 0, 0,
+                       (struct usb_descriptor_header *)&hidg_desc);
 
        return 0;
-del:
-       cdev_del(&hidg->cdev);
-fail_free_descs:
-       usb_free_all_descriptors(f);
-fail:
-       ERROR(f->config->cdev, "hidg_bind FAILED\n");
-       if (hidg->req != NULL) {
-               kfree(hidg->req->buf);
-               if (hidg->in_ep != NULL)
-                       usb_ep_free_request(hidg->in_ep, hidg->req);
-       }
-
-       return status;
 }
 
 static inline int hidg_get_minor(void)
@@ -914,6 +827,10 @@ static void hidg_free(struct usb_function *f)
 
        hidg = func_to_hidg(f);
        opts = container_of(f->fi, struct f_hid_opts, func_inst);
+
+       device_destroy(hidg_class, MKDEV(major, hidg->minor));
+       cdev_del(&hidg->cdev);
+
        kfree(hidg->report_desc);
        kfree(hidg);
        mutex_lock(&opts->lock);
@@ -921,31 +838,25 @@ static void hidg_free(struct usb_function *f)
        mutex_unlock(&opts->lock);
 }
 
-static void hidg_unbind(struct usb_configuration *c, struct usb_function *f)
-{
-       struct f_hidg *hidg = func_to_hidg(f);
-
-       device_destroy(hidg_class, MKDEV(major, hidg->minor));
-       cdev_del(&hidg->cdev);
-
-       /* disable/free request and end point */
-       usb_ep_disable(hidg->in_ep);
-       kfree(hidg->req->buf);
-       usb_ep_free_request(hidg->in_ep, hidg->req);
-
-       usb_free_all_descriptors(f);
-}
-
 static struct usb_function *hidg_alloc(struct usb_function_instance *fi)
 {
        struct f_hidg *hidg;
        struct f_hid_opts *opts;
+       struct device *device;
+       dev_t dev;
+       int ret;
 
        /* allocate and initialize one new instance */
        hidg = kzalloc(sizeof(*hidg), GFP_KERNEL);
        if (!hidg)
                return ERR_PTR(-ENOMEM);
 
+       mutex_init(&hidg->lock);
+       spin_lock_init(&hidg->spinlock);
+       init_waitqueue_head(&hidg->write_queue);
+       init_waitqueue_head(&hidg->read_queue);
+       INIT_LIST_HEAD(&hidg->completed_out_req);
+
        opts = container_of(fi, struct f_hid_opts, func_inst);
 
        mutex_lock(&opts->lock);
@@ -961,26 +872,48 @@ static struct usb_function *hidg_alloc(struct 
usb_function_instance *fi)
                                            opts->report_desc_length,
                                            GFP_KERNEL);
                if (!hidg->report_desc) {
-                       kfree(hidg);
                        mutex_unlock(&opts->lock);
-                       return ERR_PTR(-ENOMEM);
+                       ret = -ENOMEM;
+                       goto err_hidg;
                }
        }
 
        mutex_unlock(&opts->lock);
 
        hidg->func.name    = "hid";
-       hidg->func.bind    = hidg_bind;
-       hidg->func.unbind  = hidg_unbind;
+       hidg->func.prep_descs = hidg_prep_descs;
+       hidg->func.prep_vendor_descs = hidg_prep_vendor_descs;
        hidg->func.set_alt = hidg_set_alt;
-       hidg->func.disable = hidg_disable;
+       hidg->func.clear_alt = hidg_clear_alt;
        hidg->func.setup   = hidg_setup;
        hidg->func.free_func = hidg_free;
 
        /* this could me made configurable at some point */
        hidg->qlen         = 4;
 
+       /* create char device */
+       cdev_init(&hidg->cdev, &f_hidg_fops);
+       dev = MKDEV(major, hidg->minor);
+       ret = cdev_add(&hidg->cdev, dev, 1);
+       if (ret < 0)
+               goto err_report;
+
+       device = device_create(hidg_class, NULL, dev, NULL,
+                              "%s%d", "hidg", hidg->minor);
+       if (IS_ERR(device)) {
+               ret = PTR_ERR(device);
+               goto err_cdev;
+       }
+
        return &hidg->func;
+
+err_cdev:
+       cdev_del(&hidg->cdev);
+err_report:
+       kfree(hidg->report_desc);
+err_hidg:
+       kfree(hidg);
+       return ERR_PTR(ret);
 }
 
 DECLARE_USB_FUNCTION_INIT(hid, hidg_alloc_inst, hidg_alloc);
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to