usb: gadget: always update HS/SS descriptors and create a copy of them
authorSebastian Andrzej Siewior <bigeasy@linutronix.de>
Mon, 22 Oct 2012 20:15:06 +0000 (22:15 +0200)
committerFelipe Balbi <balbi@ti.com>
Wed, 31 Oct 2012 13:09:44 +0000 (15:09 +0200)
HS and SS descriptors are staticaly created. They are updated during the
bind process with the endpoint address, string id or interface numbers.

After that, the descriptor chain is linked to struct usb_function which
is used by composite in order to serve the GET_DESCRIPTOR requests,
number of available configs and so on.

There is no need to assign the HS descriptor only if the UDC supports
HS speed because composite won't report those to the host if HS support
has not been reached. The same reasoning is valid for SS.

This patch makes sure each function updates HS/SS descriptors
unconditionally and uses the newly introduced helper function to create a
copy the descriptors for the speed which is supported by the UDC.

While at that, also rename f->descriptors to f->fs_descriptors in order
to make it more explicit what that means.

Cc: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: Felipe Balbi <balbi@ti.com>
24 files changed:
drivers/usb/gadget/composite.c
drivers/usb/gadget/config.c
drivers/usb/gadget/f_acm.c
drivers/usb/gadget/f_ecm.c
drivers/usb/gadget/f_eem.c
drivers/usb/gadget/f_fs.c
drivers/usb/gadget/f_hid.c
drivers/usb/gadget/f_loopback.c
drivers/usb/gadget/f_mass_storage.c
drivers/usb/gadget/f_midi.c
drivers/usb/gadget/f_ncm.c
drivers/usb/gadget/f_obex.c
drivers/usb/gadget/f_phonet.c
drivers/usb/gadget/f_rndis.c
drivers/usb/gadget/f_serial.c
drivers/usb/gadget/f_sourcesink.c
drivers/usb/gadget/f_subset.c
drivers/usb/gadget/f_uac1.c
drivers/usb/gadget/f_uac2.c
drivers/usb/gadget/f_uvc.c
drivers/usb/gadget/printer.c
drivers/usb/gadget/tcm_usb_gadget.c
include/linux/usb/composite.h
include/linux/usb/gadget.h

index 957f973dd96ad6f069a8eddf084d448c7a34ff0f..2a6bfe759c2971435a3fbb10203e5e3f0a3ee3c1 100644 (file)
@@ -107,7 +107,7 @@ int config_ep_by_speed(struct usb_gadget *g,
                }
                /* else: fall through */
        default:
-               speed_desc = f->descriptors;
+               speed_desc = f->fs_descriptors;
        }
        /* find descriptors */
        for_each_ep_desc(speed_desc, d_spd) {
@@ -200,7 +200,7 @@ int usb_add_function(struct usb_configuration *config,
         * as full speed ... it's the function drivers that will need
         * to avoid bulk and ISO transfers.
         */
-       if (!config->fullspeed && function->descriptors)
+       if (!config->fullspeed && function->fs_descriptors)
                config->fullspeed = true;
        if (!config->highspeed && function->hs_descriptors)
                config->highspeed = true;
@@ -363,7 +363,7 @@ static int config_buf(struct usb_configuration *config,
                        descriptors = f->hs_descriptors;
                        break;
                default:
-                       descriptors = f->descriptors;
+                       descriptors = f->fs_descriptors;
                }
 
                if (!descriptors)
@@ -620,7 +620,7 @@ static int set_config(struct usb_composite_dev *cdev,
                        descriptors = f->hs_descriptors;
                        break;
                default:
-                       descriptors = f->descriptors;
+                       descriptors = f->fs_descriptors;
                }
 
                for (; *descriptors; ++descriptors) {
index e3a98929d3463d50ad395be7bf7fe08c92dfc983..34e12fc52c23d45fa2148212938242bb05b777f3 100644 (file)
@@ -19,7 +19,7 @@
 
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
-
+#include <linux/usb/composite.h>
 
 /**
  * usb_descriptor_fillbuf - fill buffer with descriptors
@@ -158,3 +158,40 @@ usb_copy_descriptors(struct usb_descriptor_header **src)
        return ret;
 }
 EXPORT_SYMBOL_GPL(usb_copy_descriptors);
+
+int usb_assign_descriptors(struct usb_function *f,
+               struct usb_descriptor_header **fs,
+               struct usb_descriptor_header **hs,
+               struct usb_descriptor_header **ss)
+{
+       struct usb_gadget *g = f->config->cdev->gadget;
+
+       if (fs) {
+               f->fs_descriptors = usb_copy_descriptors(fs);
+               if (!f->fs_descriptors)
+                       goto err;
+       }
+       if (hs && gadget_is_dualspeed(g)) {
+               f->hs_descriptors = usb_copy_descriptors(hs);
+               if (!f->hs_descriptors)
+                       goto err;
+       }
+       if (ss && gadget_is_superspeed(g)) {
+               f->ss_descriptors = usb_copy_descriptors(ss);
+               if (!f->ss_descriptors)
+                       goto err;
+       }
+       return 0;
+err:
+       usb_free_all_descriptors(f);
+       return -ENOMEM;
+}
+EXPORT_SYMBOL_GPL(usb_assign_descriptors);
+
+void usb_free_all_descriptors(struct usb_function *f)
+{
+       usb_free_descriptors(f->fs_descriptors);
+       usb_free_descriptors(f->hs_descriptors);
+       usb_free_descriptors(f->ss_descriptors);
+}
+EXPORT_SYMBOL_GPL(usb_free_all_descriptors);
index 7c30bb49850b074303c9e23d7f146afbfab0cdc2..308242b5d6e0ab4a9c02ea00798f2edada1421a1 100644 (file)
@@ -658,37 +658,22 @@ acm_bind(struct usb_configuration *c, struct usb_function *f)
        acm->notify_req->complete = acm_cdc_notify_complete;
        acm->notify_req->context = acm;
 
-       /* copy descriptors */
-       f->descriptors = usb_copy_descriptors(acm_fs_function);
-       if (!f->descriptors)
-               goto fail;
-
        /* support all relevant hardware speeds... we expect that when
         * hardware is dual speed, all bulk-capable endpoints work at
         * both speeds
         */
-       if (gadget_is_dualspeed(c->cdev->gadget)) {
-               acm_hs_in_desc.bEndpointAddress =
-                               acm_fs_in_desc.bEndpointAddress;
-               acm_hs_out_desc.bEndpointAddress =
-                               acm_fs_out_desc.bEndpointAddress;
-               acm_hs_notify_desc.bEndpointAddress =
-                               acm_fs_notify_desc.bEndpointAddress;
-
-               /* copy descriptors */
-               f->hs_descriptors = usb_copy_descriptors(acm_hs_function);
-       }
-       if (gadget_is_superspeed(c->cdev->gadget)) {
-               acm_ss_in_desc.bEndpointAddress =
-                       acm_fs_in_desc.bEndpointAddress;
-               acm_ss_out_desc.bEndpointAddress =
-                       acm_fs_out_desc.bEndpointAddress;
-
-               /* copy descriptors, and track endpoint copies */
-               f->ss_descriptors = usb_copy_descriptors(acm_ss_function);
-               if (!f->ss_descriptors)
-                       goto fail;
-       }
+       acm_hs_in_desc.bEndpointAddress = acm_fs_in_desc.bEndpointAddress;
+       acm_hs_out_desc.bEndpointAddress = acm_fs_out_desc.bEndpointAddress;
+       acm_hs_notify_desc.bEndpointAddress =
+               acm_fs_notify_desc.bEndpointAddress;
+
+       acm_ss_in_desc.bEndpointAddress = acm_fs_in_desc.bEndpointAddress;
+       acm_ss_out_desc.bEndpointAddress = acm_fs_out_desc.bEndpointAddress;
+
+       status = usb_assign_descriptors(f, acm_fs_function, acm_hs_function,
+                       acm_ss_function);
+       if (status)
+               goto fail;
 
        DBG(cdev, "acm ttyGS%d: %s speed IN/%s OUT/%s NOTIFY/%s\n",
                        acm->port_num,
@@ -720,11 +705,7 @@ acm_unbind(struct usb_configuration *c, struct usb_function *f)
 {
        struct f_acm            *acm = func_to_acm(f);
 
-       if (gadget_is_dualspeed(c->cdev->gadget))
-               usb_free_descriptors(f->hs_descriptors);
-       if (gadget_is_superspeed(c->cdev->gadget))
-               usb_free_descriptors(f->ss_descriptors);
-       usb_free_descriptors(f->descriptors);
+       usb_free_all_descriptors(f);
        gs_free_req(acm->notify, acm->notify_req);
        kfree(acm);
 }
index a158740255ced5a83abbb884a441eee53ab92d35..2d3c5a46de8e71d08094f83a8f774397c8c10c7f 100644 (file)
@@ -743,42 +743,24 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f)
        ecm->notify_req->context = ecm;
        ecm->notify_req->complete = ecm_notify_complete;
 
-       /* copy descriptors, and track endpoint copies */
-       f->descriptors = usb_copy_descriptors(ecm_fs_function);
-       if (!f->descriptors)
-               goto fail;
-
        /* support all relevant hardware speeds... we expect that when
         * hardware is dual speed, all bulk-capable endpoints work at
         * both speeds
         */
-       if (gadget_is_dualspeed(c->cdev->gadget)) {
-               hs_ecm_in_desc.bEndpointAddress =
-                               fs_ecm_in_desc.bEndpointAddress;
-               hs_ecm_out_desc.bEndpointAddress =
-                               fs_ecm_out_desc.bEndpointAddress;
-               hs_ecm_notify_desc.bEndpointAddress =
-                               fs_ecm_notify_desc.bEndpointAddress;
-
-               /* copy descriptors, and track endpoint copies */
-               f->hs_descriptors = usb_copy_descriptors(ecm_hs_function);
-               if (!f->hs_descriptors)
-                       goto fail;
-       }
-
-       if (gadget_is_superspeed(c->cdev->gadget)) {
-               ss_ecm_in_desc.bEndpointAddress =
-                               fs_ecm_in_desc.bEndpointAddress;
-               ss_ecm_out_desc.bEndpointAddress =
-                               fs_ecm_out_desc.bEndpointAddress;
-               ss_ecm_notify_desc.bEndpointAddress =
-                               fs_ecm_notify_desc.bEndpointAddress;
-
-               /* copy descriptors, and track endpoint copies */
-               f->ss_descriptors = usb_copy_descriptors(ecm_ss_function);
-               if (!f->ss_descriptors)
-                       goto fail;
-       }
+       hs_ecm_in_desc.bEndpointAddress = fs_ecm_in_desc.bEndpointAddress;
+       hs_ecm_out_desc.bEndpointAddress = fs_ecm_out_desc.bEndpointAddress;
+       hs_ecm_notify_desc.bEndpointAddress =
+               fs_ecm_notify_desc.bEndpointAddress;
+
+       ss_ecm_in_desc.bEndpointAddress = fs_ecm_in_desc.bEndpointAddress;
+       ss_ecm_out_desc.bEndpointAddress = fs_ecm_out_desc.bEndpointAddress;
+       ss_ecm_notify_desc.bEndpointAddress =
+               fs_ecm_notify_desc.bEndpointAddress;
+
+       status = usb_assign_descriptors(f, ecm_fs_function, ecm_hs_function,
+                       ecm_ss_function);
+       if (status)
+               goto fail;
 
        /* NOTE:  all that is done without knowing or caring about
         * the network link ... which is unavailable to this code
@@ -796,11 +778,6 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f)
        return 0;
 
 fail:
-       if (f->descriptors)
-               usb_free_descriptors(f->descriptors);
-       if (f->hs_descriptors)
-               usb_free_descriptors(f->hs_descriptors);
-
        if (ecm->notify_req) {
                kfree(ecm->notify_req->buf);
                usb_ep_free_request(ecm->notify, ecm->notify_req);
@@ -826,11 +803,7 @@ ecm_unbind(struct usb_configuration *c, struct usb_function *f)
 
        DBG(c->cdev, "ecm unbind\n");
 
-       if (gadget_is_superspeed(c->cdev->gadget))
-               usb_free_descriptors(f->ss_descriptors);
-       if (gadget_is_dualspeed(c->cdev->gadget))
-               usb_free_descriptors(f->hs_descriptors);
-       usb_free_descriptors(f->descriptors);
+       usb_free_all_descriptors(f);
 
        kfree(ecm->notify_req->buf);
        usb_ep_free_request(ecm->notify, ecm->notify_req);
index a9cf20522ffa7b43f779dfe9caab5bacadd5a024..cf0ebee855636c9412b76f17d484c3f1b86bd3e8 100644 (file)
@@ -274,38 +274,20 @@ eem_bind(struct usb_configuration *c, struct usb_function *f)
 
        status = -ENOMEM;
 
-       /* copy descriptors, and track endpoint copies */
-       f->descriptors = usb_copy_descriptors(eem_fs_function);
-       if (!f->descriptors)
-               goto fail;
-
        /* support all relevant hardware speeds... we expect that when
         * hardware is dual speed, all bulk-capable endpoints work at
         * both speeds
         */
-       if (gadget_is_dualspeed(c->cdev->gadget)) {
-               eem_hs_in_desc.bEndpointAddress =
-                               eem_fs_in_desc.bEndpointAddress;
-               eem_hs_out_desc.bEndpointAddress =
-                               eem_fs_out_desc.bEndpointAddress;
-
-               /* copy descriptors, and track endpoint copies */
-               f->hs_descriptors = usb_copy_descriptors(eem_hs_function);
-               if (!f->hs_descriptors)
-                       goto fail;
-       }
+       eem_hs_in_desc.bEndpointAddress = eem_fs_in_desc.bEndpointAddress;
+       eem_hs_out_desc.bEndpointAddress = eem_fs_out_desc.bEndpointAddress;
 
-       if (gadget_is_superspeed(c->cdev->gadget)) {
-               eem_ss_in_desc.bEndpointAddress =
-                               eem_fs_in_desc.bEndpointAddress;
-               eem_ss_out_desc.bEndpointAddress =
-                               eem_fs_out_desc.bEndpointAddress;
+       eem_ss_in_desc.bEndpointAddress = eem_fs_in_desc.bEndpointAddress;
+       eem_ss_out_desc.bEndpointAddress = eem_fs_out_desc.bEndpointAddress;
 
-               /* copy descriptors, and track endpoint copies */
-               f->ss_descriptors = usb_copy_descriptors(eem_ss_function);
-               if (!f->ss_descriptors)
-                       goto fail;
-       }
+       status = usb_assign_descriptors(f, eem_fs_function, eem_hs_function,
+                       eem_ss_function);
+       if (status)
+               goto fail;
 
        DBG(cdev, "CDC Ethernet (EEM): %s speed IN/%s OUT/%s\n",
                        gadget_is_superspeed(c->cdev->gadget) ? "super" :
@@ -314,11 +296,7 @@ eem_bind(struct usb_configuration *c, struct usb_function *f)
        return 0;
 
 fail:
-       if (f->descriptors)
-               usb_free_descriptors(f->descriptors);
-       if (f->hs_descriptors)
-               usb_free_descriptors(f->hs_descriptors);
-
+       usb_free_all_descriptors(f);
        if (eem->port.out_ep)
                eem->port.out_ep->driver_data = NULL;
        if (eem->port.in_ep)
@@ -336,11 +314,7 @@ eem_unbind(struct usb_configuration *c, struct usb_function *f)
 
        DBG(c->cdev, "eem unbind\n");
 
-       if (gadget_is_superspeed(c->cdev->gadget))
-               usb_free_descriptors(f->ss_descriptors);
-       if (gadget_is_dualspeed(c->cdev->gadget))
-               usb_free_descriptors(f->hs_descriptors);
-       usb_free_descriptors(f->descriptors);
+       usb_free_all_descriptors(f);
        kfree(eem);
 }
 
index 64c4ec10d1fcbe9db29220c5e79e33c9116de17c..4a6961c517f261103f006259bab366265dde7e4c 100644 (file)
@@ -2097,7 +2097,7 @@ static int __ffs_func_bind_do_descs(enum ffs_entity_type type, u8 *valuep,
        if (isHS)
                func->function.hs_descriptors[(long)valuep] = desc;
        else
-               func->function.descriptors[(long)valuep]    = desc;
+               func->function.fs_descriptors[(long)valuep]    = desc;
 
        if (!desc || desc->bDescriptorType != USB_DT_ENDPOINT)
                return 0;
@@ -2249,7 +2249,7 @@ static int ffs_func_bind(struct usb_configuration *c,
         * numbers without worrying that it may be described later on.
         */
        if (likely(full)) {
-               func->function.descriptors = data->fs_descs;
+               func->function.fs_descriptors = data->fs_descs;
                ret = ffs_do_descs(ffs->fs_descs_count,
                                   data->raw_descs,
                                   sizeof data->raw_descs,
index 511e527178e23d0e3cb3787700b5f7cc4f3baa32..6e69a8e8d22a7c7468994fd40eab738bddb52d1c 100644 (file)
@@ -573,7 +573,6 @@ static int __init hidg_bind(struct usb_configuration *c, struct usb_function *f)
                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);
@@ -609,20 +608,15 @@ static int __init hidg_bind(struct usb_configuration *c, struct usb_function *f)
        hidg_desc.desc[0].wDescriptorLength =
                cpu_to_le16(hidg->report_desc_length);
 
-       /* copy descriptors */
-       f->descriptors = usb_copy_descriptors(hidg_fs_descriptors);
-       if (!f->descriptors)
-               goto fail;
+       hidg_hs_in_ep_desc.bEndpointAddress =
+               hidg_fs_in_ep_desc.bEndpointAddress;
+       hidg_hs_out_ep_desc.bEndpointAddress =
+               hidg_fs_out_ep_desc.bEndpointAddress;
 
-       if (gadget_is_dualspeed(c->cdev->gadget)) {
-               hidg_hs_in_ep_desc.bEndpointAddress =
-                       hidg_fs_in_ep_desc.bEndpointAddress;
-               hidg_hs_out_ep_desc.bEndpointAddress =
-                       hidg_fs_out_ep_desc.bEndpointAddress;
-               f->hs_descriptors = usb_copy_descriptors(hidg_hs_descriptors);
-               if (!f->hs_descriptors)
-                       goto fail;
-       }
+       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);
@@ -649,9 +643,7 @@ fail:
                        usb_ep_free_request(hidg->in_ep, hidg->req);
        }
 
-       usb_free_descriptors(f->hs_descriptors);
-       usb_free_descriptors(f->descriptors);
-
+       usb_free_all_descriptors(f);
        return status;
 }
 
@@ -668,9 +660,7 @@ static void hidg_unbind(struct usb_configuration *c, struct usb_function *f)
        kfree(hidg->req->buf);
        usb_ep_free_request(hidg->in_ep, hidg->req);
 
-       /* free descriptors copies */
-       usb_free_descriptors(f->hs_descriptors);
-       usb_free_descriptors(f->descriptors);
+       usb_free_all_descriptors(f);
 
        kfree(hidg->report_desc);
        kfree(hidg);
index 7275706caeb0534301354976c177e2123de908a9..bb39cb2bb3a3f9f1ece4879f8e3a4e48c110ba0a 100644 (file)
@@ -177,6 +177,7 @@ loopback_bind(struct usb_configuration *c, struct usb_function *f)
        struct usb_composite_dev *cdev = c->cdev;
        struct f_loopback       *loop = func_to_loop(f);
        int                     id;
+       int ret;
 
        /* allocate interface ID(s) */
        id = usb_interface_id(c, f);
@@ -201,22 +202,19 @@ autoconf_fail:
        loop->out_ep->driver_data = cdev;       /* claim */
 
        /* support high speed hardware */
-       if (gadget_is_dualspeed(c->cdev->gadget)) {
-               hs_loop_source_desc.bEndpointAddress =
-                               fs_loop_source_desc.bEndpointAddress;
-               hs_loop_sink_desc.bEndpointAddress =
-                               fs_loop_sink_desc.bEndpointAddress;
-               f->hs_descriptors = hs_loopback_descs;
-       }
+       hs_loop_source_desc.bEndpointAddress =
+               fs_loop_source_desc.bEndpointAddress;
+       hs_loop_sink_desc.bEndpointAddress = fs_loop_sink_desc.bEndpointAddress;
 
        /* support super speed hardware */
-       if (gadget_is_superspeed(c->cdev->gadget)) {
-               ss_loop_source_desc.bEndpointAddress =
-                               fs_loop_source_desc.bEndpointAddress;
-               ss_loop_sink_desc.bEndpointAddress =
-                               fs_loop_sink_desc.bEndpointAddress;
-               f->ss_descriptors = ss_loopback_descs;
-       }
+       ss_loop_source_desc.bEndpointAddress =
+               fs_loop_source_desc.bEndpointAddress;
+       ss_loop_sink_desc.bEndpointAddress = fs_loop_sink_desc.bEndpointAddress;
+
+       ret = usb_assign_descriptors(f, fs_loopback_descs, hs_loopback_descs,
+                       ss_loopback_descs);
+       if (ret)
+               return ret;
 
        DBG(cdev, "%s speed %s: IN/%s, OUT/%s\n",
            (gadget_is_superspeed(c->cdev->gadget) ? "super" :
@@ -228,6 +226,7 @@ autoconf_fail:
 static void
 loopback_unbind(struct usb_configuration *c, struct usb_function *f)
 {
+       usb_free_all_descriptors(f);
        kfree(func_to_loop(f));
 }
 
@@ -379,7 +378,6 @@ static int __init loopback_bind_config(struct usb_configuration *c)
                return -ENOMEM;
 
        loop->function.name = "loopback";
-       loop->function.descriptors = fs_loopback_descs;
        loop->function.bind = loopback_bind;
        loop->function.unbind = loopback_unbind;
        loop->function.set_alt = loopback_set_alt;
index 3a7668bde3ef44bfc752f98ef1ebce7da531e885..3433e432a4ae03a3657633da0fcba56f91709adb 100644 (file)
@@ -2904,9 +2904,7 @@ static void fsg_unbind(struct usb_configuration *c, struct usb_function *f)
        }
 
        fsg_common_put(common);
-       usb_free_descriptors(fsg->function.descriptors);
-       usb_free_descriptors(fsg->function.hs_descriptors);
-       usb_free_descriptors(fsg->function.ss_descriptors);
+       usb_free_all_descriptors(&fsg->function);
        kfree(fsg);
 }
 
@@ -2916,6 +2914,8 @@ static int fsg_bind(struct usb_configuration *c, struct usb_function *f)
        struct usb_gadget       *gadget = c->cdev->gadget;
        int                     i;
        struct usb_ep           *ep;
+       unsigned                max_burst;
+       int                     ret;
 
        fsg->gadget = gadget;
 
@@ -2939,45 +2939,27 @@ static int fsg_bind(struct usb_configuration *c, struct usb_function *f)
        ep->driver_data = fsg->common;  /* claim the endpoint */
        fsg->bulk_out = ep;
 
-       /* Copy descriptors */
-       f->descriptors = usb_copy_descriptors(fsg_fs_function);
-       if (unlikely(!f->descriptors))
-               return -ENOMEM;
-
-       if (gadget_is_dualspeed(gadget)) {
-               /* Assume endpoint addresses are the same for both speeds */
-               fsg_hs_bulk_in_desc.bEndpointAddress =
-                       fsg_fs_bulk_in_desc.bEndpointAddress;
-               fsg_hs_bulk_out_desc.bEndpointAddress =
-                       fsg_fs_bulk_out_desc.bEndpointAddress;
-               f->hs_descriptors = usb_copy_descriptors(fsg_hs_function);
-               if (unlikely(!f->hs_descriptors)) {
-                       usb_free_descriptors(f->descriptors);
-                       return -ENOMEM;
-               }
-       }
-
-       if (gadget_is_superspeed(gadget)) {
-               unsigned        max_burst;
+       /* Assume endpoint addresses are the same for both speeds */
+       fsg_hs_bulk_in_desc.bEndpointAddress =
+               fsg_fs_bulk_in_desc.bEndpointAddress;
+       fsg_hs_bulk_out_desc.bEndpointAddress =
+               fsg_fs_bulk_out_desc.bEndpointAddress;
 
-               /* Calculate bMaxBurst, we know packet size is 1024 */
-               max_burst = min_t(unsigned, FSG_BUFLEN / 1024, 15);
+       /* Calculate bMaxBurst, we know packet size is 1024 */
+       max_burst = min_t(unsigned, FSG_BUFLEN / 1024, 15);
 
-               fsg_ss_bulk_in_desc.bEndpointAddress =
-                       fsg_fs_bulk_in_desc.bEndpointAddress;
-               fsg_ss_bulk_in_comp_desc.bMaxBurst = max_burst;
+       fsg_ss_bulk_in_desc.bEndpointAddress =
+               fsg_fs_bulk_in_desc.bEndpointAddress;
+       fsg_ss_bulk_in_comp_desc.bMaxBurst = max_burst;
 
-               fsg_ss_bulk_out_desc.bEndpointAddress =
-                       fsg_fs_bulk_out_desc.bEndpointAddress;
-               fsg_ss_bulk_out_comp_desc.bMaxBurst = max_burst;
+       fsg_ss_bulk_out_desc.bEndpointAddress =
+               fsg_fs_bulk_out_desc.bEndpointAddress;
+       fsg_ss_bulk_out_comp_desc.bMaxBurst = max_burst;
 
-               f->ss_descriptors = usb_copy_descriptors(fsg_ss_function);
-               if (unlikely(!f->ss_descriptors)) {
-                       usb_free_descriptors(f->hs_descriptors);
-                       usb_free_descriptors(f->descriptors);
-                       return -ENOMEM;
-               }
-       }
+       ret = usb_assign_descriptors(f, fsg_fs_function, fsg_hs_function,
+                       fsg_ss_function);
+       if (ret)
+               goto autoconf_fail;
 
        return 0;
 
@@ -2986,7 +2968,6 @@ autoconf_fail:
        return -ENOTSUPP;
 }
 
-
 /****************************** ADD FUNCTION ******************************/
 
 static struct usb_gadget_strings *fsg_strings_array[] = {
index b265ee8fa5aabc4faeddb6a00ad82cf603aa1f95..263e721c2694cdcdc9968d0a7c8f1c5957e16e75 100644 (file)
@@ -414,8 +414,7 @@ static void f_midi_unbind(struct usb_configuration *c, struct usb_function *f)
        kfree(midi->id);
        midi->id = NULL;
 
-       usb_free_descriptors(f->descriptors);
-       usb_free_descriptors(f->hs_descriptors);
+       usb_free_all_descriptors(f);
        kfree(midi);
 }
 
@@ -882,9 +881,10 @@ f_midi_bind(struct usb_configuration *c, struct usb_function *f)
         * both speeds
         */
        /* copy descriptors, and track endpoint copies */
-       f->descriptors = usb_copy_descriptors(midi_function);
-       if (!f->descriptors)
+       f->fs_descriptors = usb_copy_descriptors(midi_function);
+       if (!f->fs_descriptors)
                goto fail_f_midi;
+
        if (gadget_is_dualspeed(c->cdev->gadget)) {
                bulk_in_desc.wMaxPacketSize = cpu_to_le16(512);
                bulk_out_desc.wMaxPacketSize = cpu_to_le16(512);
index 424fc3d1cc36fc0ec2df6cd4300c6d5277254e34..326d7e6c297c6939f06db85ddd64a7bdd25daf30 100644 (file)
@@ -1208,30 +1208,18 @@ ncm_bind(struct usb_configuration *c, struct usb_function *f)
        ncm->notify_req->context = ncm;
        ncm->notify_req->complete = ncm_notify_complete;
 
-       /* copy descriptors, and track endpoint copies */
-       f->descriptors = usb_copy_descriptors(ncm_fs_function);
-       if (!f->descriptors)
-               goto fail;
-
        /*
         * support all relevant hardware speeds... we expect that when
         * hardware is dual speed, all bulk-capable endpoints work at
         * both speeds
         */
-       if (gadget_is_dualspeed(c->cdev->gadget)) {
-               hs_ncm_in_desc.bEndpointAddress =
-                               fs_ncm_in_desc.bEndpointAddress;
-               hs_ncm_out_desc.bEndpointAddress =
-                               fs_ncm_out_desc.bEndpointAddress;
-               hs_ncm_notify_desc.bEndpointAddress =
-                               fs_ncm_notify_desc.bEndpointAddress;
-
-               /* copy descriptors, and track endpoint copies */
-               f->hs_descriptors = usb_copy_descriptors(ncm_hs_function);
-               if (!f->hs_descriptors)
-                       goto fail;
-       }
+       hs_ncm_in_desc.bEndpointAddress = fs_ncm_in_desc.bEndpointAddress;
+       hs_ncm_out_desc.bEndpointAddress = fs_ncm_out_desc.bEndpointAddress;
+       hs_ncm_notify_desc.bEndpointAddress =
+               fs_ncm_notify_desc.bEndpointAddress;
 
+       status = usb_assign_descriptors(f, ncm_fs_function, ncm_hs_function,
+                       NULL);
        /*
         * NOTE:  all that is done without knowing or caring about
         * the network link ... which is unavailable to this code
@@ -1248,9 +1236,7 @@ ncm_bind(struct usb_configuration *c, struct usb_function *f)
        return 0;
 
 fail:
-       if (f->descriptors)
-               usb_free_descriptors(f->descriptors);
-
+       usb_free_all_descriptors(f);
        if (ncm->notify_req) {
                kfree(ncm->notify_req->buf);
                usb_ep_free_request(ncm->notify, ncm->notify_req);
@@ -1276,9 +1262,7 @@ ncm_unbind(struct usb_configuration *c, struct usb_function *f)
 
        DBG(c->cdev, "ncm unbind\n");
 
-       if (gadget_is_dualspeed(c->cdev->gadget))
-               usb_free_descriptors(f->hs_descriptors);
-       usb_free_descriptors(f->descriptors);
+       usb_free_all_descriptors(f);
 
        kfree(ncm->notify_req->buf);
        usb_ep_free_request(ncm->notify, ncm->notify_req);
index 5f400f66aa9b5dfa3c4844639d62ad23ad11608b..d74491ad82cb1e43c613801bfd74901ecdaf6635 100644 (file)
@@ -331,23 +331,19 @@ obex_bind(struct usb_configuration *c, struct usb_function *f)
        obex->port.out = ep;
        ep->driver_data = cdev; /* claim */
 
-       /* copy descriptors, and track endpoint copies */
-       f->descriptors = usb_copy_descriptors(fs_function);
-
        /* support all relevant hardware speeds... we expect that when
         * hardware is dual speed, all bulk-capable endpoints work at
         * both speeds
         */
-       if (gadget_is_dualspeed(c->cdev->gadget)) {
 
-               obex_hs_ep_in_desc.bEndpointAddress =
-                               obex_fs_ep_in_desc.bEndpointAddress;
-               obex_hs_ep_out_desc.bEndpointAddress =
-                               obex_fs_ep_out_desc.bEndpointAddress;
+       obex_hs_ep_in_desc.bEndpointAddress =
+               obex_fs_ep_in_desc.bEndpointAddress;
+       obex_hs_ep_out_desc.bEndpointAddress =
+               obex_fs_ep_out_desc.bEndpointAddress;
 
-               /* copy descriptors, and track endpoint copies */
-               f->hs_descriptors = usb_copy_descriptors(hs_function);
-       }
+       status = usb_assign_descriptors(f, fs_function, hs_function, NULL);
+       if (status)
+               goto fail;
 
        /* Avoid letting this gadget enumerate until the userspace
         * OBEX server is active.
@@ -368,6 +364,7 @@ obex_bind(struct usb_configuration *c, struct usb_function *f)
        return 0;
 
 fail:
+       usb_free_all_descriptors(f);
        /* we might as well release our claims on endpoints */
        if (obex->port.out)
                obex->port.out->driver_data = NULL;
@@ -382,9 +379,7 @@ fail:
 static void
 obex_unbind(struct usb_configuration *c, struct usb_function *f)
 {
-       if (gadget_is_dualspeed(c->cdev->gadget))
-               usb_free_descriptors(f->hs_descriptors);
-       usb_free_descriptors(f->descriptors);
+       usb_free_all_descriptors(f);
        kfree(func_to_obex(f));
 }
 
index a6c19a486d5324e99c35cc711748b7c69e86bd57..b21ab558b6c01ada7fbca98bf63ec2949090a17d 100644 (file)
@@ -515,14 +515,14 @@ int pn_bind(struct usb_configuration *c, struct usb_function *f)
        fp->in_ep = ep;
        ep->driver_data = fp; /* Claim */
 
-       pn_hs_sink_desc.bEndpointAddress =
-               pn_fs_sink_desc.bEndpointAddress;
-       pn_hs_source_desc.bEndpointAddress =
-               pn_fs_source_desc.bEndpointAddress;
+       pn_hs_sink_desc.bEndpointAddress = pn_fs_sink_desc.bEndpointAddress;
+       pn_hs_source_desc.bEndpointAddress = pn_fs_source_desc.bEndpointAddress;
 
        /* Do not try to bind Phonet twice... */
-       fp->function.descriptors = fs_pn_function;
-       fp->function.hs_descriptors = hs_pn_function;
+       status = usb_assign_descriptors(f, fs_pn_function, hs_pn_function,
+                       NULL);
+       if (status)
+               goto err;
 
        /* Incoming USB requests */
        status = -ENOMEM;
@@ -551,7 +551,7 @@ err_req:
        for (i = 0; i < phonet_rxq_size && fp->out_reqv[i]; i++)
                usb_ep_free_request(fp->out_ep, fp->out_reqv[i]);
 err:
-
+       usb_free_all_descriptors(f);
        if (fp->out_ep)
                fp->out_ep->driver_data = NULL;
        if (fp->in_ep)
@@ -573,6 +573,7 @@ pn_unbind(struct usb_configuration *c, struct usb_function *f)
                if (fp->out_reqv[i])
                        usb_ep_free_request(fp->out_ep, fp->out_reqv[i]);
 
+       usb_free_all_descriptors(f);
        kfree(fp);
 }
 
index 7c27626f0235506ec1d6d7b20c87b68ec35c9643..e7c25105bd8ed8529a121b8fa0fa0814544a92b7 100644 (file)
@@ -722,42 +722,22 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)
        rndis->notify_req->context = rndis;
        rndis->notify_req->complete = rndis_response_complete;
 
-       /* copy descriptors, and track endpoint copies */
-       f->descriptors = usb_copy_descriptors(eth_fs_function);
-       if (!f->descriptors)
-               goto fail;
-
        /* support all relevant hardware speeds... we expect that when
         * hardware is dual speed, all bulk-capable endpoints work at
         * both speeds
         */
-       if (gadget_is_dualspeed(c->cdev->gadget)) {
-               hs_in_desc.bEndpointAddress =
-                               fs_in_desc.bEndpointAddress;
-               hs_out_desc.bEndpointAddress =
-                               fs_out_desc.bEndpointAddress;
-               hs_notify_desc.bEndpointAddress =
-                               fs_notify_desc.bEndpointAddress;
-
-               /* copy descriptors, and track endpoint copies */
-               f->hs_descriptors = usb_copy_descriptors(eth_hs_function);
-               if (!f->hs_descriptors)
-                       goto fail;
-       }
+       hs_in_desc.bEndpointAddress = fs_in_desc.bEndpointAddress;
+       hs_out_desc.bEndpointAddress = fs_out_desc.bEndpointAddress;
+       hs_notify_desc.bEndpointAddress = fs_notify_desc.bEndpointAddress;
 
-       if (gadget_is_superspeed(c->cdev->gadget)) {
-               ss_in_desc.bEndpointAddress =
-                               fs_in_desc.bEndpointAddress;
-               ss_out_desc.bEndpointAddress =
-                               fs_out_desc.bEndpointAddress;
-               ss_notify_desc.bEndpointAddress =
-                               fs_notify_desc.bEndpointAddress;
-
-               /* copy descriptors, and track endpoint copies */
-               f->ss_descriptors = usb_copy_descriptors(eth_ss_function);
-               if (!f->ss_descriptors)
-                       goto fail;
-       }
+       ss_in_desc.bEndpointAddress = fs_in_desc.bEndpointAddress;
+       ss_out_desc.bEndpointAddress = fs_out_desc.bEndpointAddress;
+       ss_notify_desc.bEndpointAddress = fs_notify_desc.bEndpointAddress;
+
+       status = usb_assign_descriptors(f, eth_fs_function, eth_hs_function,
+                       eth_ss_function);
+       if (status)
+               goto fail;
 
        rndis->port.open = rndis_open;
        rndis->port.close = rndis_close;
@@ -788,12 +768,7 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)
        return 0;
 
 fail:
-       if (gadget_is_superspeed(c->cdev->gadget) && f->ss_descriptors)
-               usb_free_descriptors(f->ss_descriptors);
-       if (gadget_is_dualspeed(c->cdev->gadget) && f->hs_descriptors)
-               usb_free_descriptors(f->hs_descriptors);
-       if (f->descriptors)
-               usb_free_descriptors(f->descriptors);
+       usb_free_all_descriptors(f);
 
        if (rndis->notify_req) {
                kfree(rndis->notify_req->buf);
@@ -822,11 +797,7 @@ rndis_unbind(struct usb_configuration *c, struct usb_function *f)
        rndis_exit();
        rndis_string_defs[0].id = 0;
 
-       if (gadget_is_superspeed(c->cdev->gadget))
-               usb_free_descriptors(f->ss_descriptors);
-       if (gadget_is_dualspeed(c->cdev->gadget))
-               usb_free_descriptors(f->hs_descriptors);
-       usb_free_descriptors(f->descriptors);
+       usb_free_all_descriptors(f);
 
        kfree(rndis->notify_req->buf);
        usb_ep_free_request(rndis->notify, rndis->notify_req);
index 07197d63d9b1d056e75c79cd85261059279715fa..98fa7795df5f8bccc9b03a89bb43e78c0392865f 100644 (file)
@@ -213,34 +213,20 @@ gser_bind(struct usb_configuration *c, struct usb_function *f)
        gser->port.out = ep;
        ep->driver_data = cdev; /* claim */
 
-       /* copy descriptors, and track endpoint copies */
-       f->descriptors = usb_copy_descriptors(gser_fs_function);
-
        /* support all relevant hardware speeds... we expect that when
         * hardware is dual speed, all bulk-capable endpoints work at
         * both speeds
         */
-       if (gadget_is_dualspeed(c->cdev->gadget)) {
-               gser_hs_in_desc.bEndpointAddress =
-                               gser_fs_in_desc.bEndpointAddress;
-               gser_hs_out_desc.bEndpointAddress =
-                               gser_fs_out_desc.bEndpointAddress;
-
-               /* copy descriptors, and track endpoint copies */
-               f->hs_descriptors = usb_copy_descriptors(gser_hs_function);
-       }
-       if (gadget_is_superspeed(c->cdev->gadget)) {
-               gser_ss_in_desc.bEndpointAddress =
-                       gser_fs_in_desc.bEndpointAddress;
-               gser_ss_out_desc.bEndpointAddress =
-                       gser_fs_out_desc.bEndpointAddress;
-
-               /* copy descriptors, and track endpoint copies */
-               f->ss_descriptors = usb_copy_descriptors(gser_ss_function);
-               if (!f->ss_descriptors)
-                       goto fail;
-       }
+       gser_hs_in_desc.bEndpointAddress = gser_fs_in_desc.bEndpointAddress;
+       gser_hs_out_desc.bEndpointAddress = gser_fs_out_desc.bEndpointAddress;
 
+       gser_ss_in_desc.bEndpointAddress = gser_fs_in_desc.bEndpointAddress;
+       gser_ss_out_desc.bEndpointAddress = gser_fs_out_desc.bEndpointAddress;
+
+       status = usb_assign_descriptors(f, gser_fs_function, gser_hs_function,
+                       gser_ss_function);
+       if (status)
+               goto fail;
        DBG(cdev, "generic ttyGS%d: %s speed IN/%s OUT/%s\n",
                        gser->port_num,
                        gadget_is_superspeed(c->cdev->gadget) ? "super" :
@@ -263,11 +249,7 @@ fail:
 static void
 gser_unbind(struct usb_configuration *c, struct usb_function *f)
 {
-       if (gadget_is_dualspeed(c->cdev->gadget))
-               usb_free_descriptors(f->hs_descriptors);
-       if (gadget_is_superspeed(c->cdev->gadget))
-               usb_free_descriptors(f->ss_descriptors);
-       usb_free_descriptors(f->descriptors);
+       usb_free_all_descriptors(f);
        kfree(func_to_gser(f));
 }
 
index 3c126fde6e7e7131168c47805a32f94379b68fcc..102d49beb9dfe833f3bf00a07b3bba8685aa0a35 100644 (file)
@@ -319,6 +319,7 @@ sourcesink_bind(struct usb_configuration *c, struct usb_function *f)
        struct usb_composite_dev *cdev = c->cdev;
        struct f_sourcesink     *ss = func_to_ss(f);
        int     id;
+       int ret;
 
        /* allocate interface ID(s) */
        id = usb_interface_id(c, f);
@@ -387,64 +388,57 @@ no_iso:
                isoc_maxpacket = 1024;
 
        /* support high speed hardware */
-       if (gadget_is_dualspeed(c->cdev->gadget)) {
-               hs_source_desc.bEndpointAddress =
-                               fs_source_desc.bEndpointAddress;
-               hs_sink_desc.bEndpointAddress =
-                               fs_sink_desc.bEndpointAddress;
+       hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress;
+       hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress;
 
-               /*
-                * Fill in the HS isoc descriptors from the module parameters.
-                * We assume that the user knows what they are doing and won't
-                * give parameters that their UDC doesn't support.
-                */
-               hs_iso_source_desc.wMaxPacketSize = isoc_maxpacket;
-               hs_iso_source_desc.wMaxPacketSize |= isoc_mult << 11;
-               hs_iso_source_desc.bInterval = isoc_interval;
-               hs_iso_source_desc.bEndpointAddress =
-                               fs_iso_source_desc.bEndpointAddress;
-
-               hs_iso_sink_desc.wMaxPacketSize = isoc_maxpacket;
-               hs_iso_sink_desc.wMaxPacketSize |= isoc_mult << 11;
-               hs_iso_sink_desc.bInterval = isoc_interval;
-               hs_iso_sink_desc.bEndpointAddress =
-                               fs_iso_sink_desc.bEndpointAddress;
-
-               f->hs_descriptors = hs_source_sink_descs;
-       }
+       /*
+        * Fill in the HS isoc descriptors from the module parameters.
+        * We assume that the user knows what they are doing and won't
+        * give parameters that their UDC doesn't support.
+        */
+       hs_iso_source_desc.wMaxPacketSize = isoc_maxpacket;
+       hs_iso_source_desc.wMaxPacketSize |= isoc_mult << 11;
+       hs_iso_source_desc.bInterval = isoc_interval;
+       hs_iso_source_desc.bEndpointAddress =
+               fs_iso_source_desc.bEndpointAddress;
+
+       hs_iso_sink_desc.wMaxPacketSize = isoc_maxpacket;
+       hs_iso_sink_desc.wMaxPacketSize |= isoc_mult << 11;
+       hs_iso_sink_desc.bInterval = isoc_interval;
+       hs_iso_sink_desc.bEndpointAddress = fs_iso_sink_desc.bEndpointAddress;
 
        /* support super speed hardware */
-       if (gadget_is_superspeed(c->cdev->gadget)) {
-               ss_source_desc.bEndpointAddress =
-                               fs_source_desc.bEndpointAddress;
-               ss_sink_desc.bEndpointAddress =
-                               fs_sink_desc.bEndpointAddress;
+       ss_source_desc.bEndpointAddress =
+               fs_source_desc.bEndpointAddress;
+       ss_sink_desc.bEndpointAddress =
+               fs_sink_desc.bEndpointAddress;
 
-               /*
-                * Fill in the SS isoc descriptors from the module parameters.
-                * We assume that the user knows what they are doing and won't
-                * give parameters that their UDC doesn't support.
-                */
-               ss_iso_source_desc.wMaxPacketSize = isoc_maxpacket;
-               ss_iso_source_desc.bInterval = isoc_interval;
-               ss_iso_source_comp_desc.bmAttributes = isoc_mult;
-               ss_iso_source_comp_desc.bMaxBurst = isoc_maxburst;
-               ss_iso_source_comp_desc.wBytesPerInterval =
-                       isoc_maxpacket * (isoc_mult + 1) * (isoc_maxburst + 1);
-               ss_iso_source_desc.bEndpointAddress =
-                               fs_iso_source_desc.bEndpointAddress;
-
-               ss_iso_sink_desc.wMaxPacketSize = isoc_maxpacket;
-               ss_iso_sink_desc.bInterval = isoc_interval;
-               ss_iso_sink_comp_desc.bmAttributes = isoc_mult;
-               ss_iso_sink_comp_desc.bMaxBurst = isoc_maxburst;
-               ss_iso_sink_comp_desc.wBytesPerInterval =
-                       isoc_maxpacket * (isoc_mult + 1) * (isoc_maxburst + 1);
-               ss_iso_sink_desc.bEndpointAddress =
-                               fs_iso_sink_desc.bEndpointAddress;
-
-               f->ss_descriptors = ss_source_sink_descs;
-       }
+       /*
+        * Fill in the SS isoc descriptors from the module parameters.
+        * We assume that the user knows what they are doing and won't
+        * give parameters that their UDC doesn't support.
+        */
+       ss_iso_source_desc.wMaxPacketSize = isoc_maxpacket;
+       ss_iso_source_desc.bInterval = isoc_interval;
+       ss_iso_source_comp_desc.bmAttributes = isoc_mult;
+       ss_iso_source_comp_desc.bMaxBurst = isoc_maxburst;
+       ss_iso_source_comp_desc.wBytesPerInterval =
+               isoc_maxpacket * (isoc_mult + 1) * (isoc_maxburst + 1);
+       ss_iso_source_desc.bEndpointAddress =
+               fs_iso_source_desc.bEndpointAddress;
+
+       ss_iso_sink_desc.wMaxPacketSize = isoc_maxpacket;
+       ss_iso_sink_desc.bInterval = isoc_interval;
+       ss_iso_sink_comp_desc.bmAttributes = isoc_mult;
+       ss_iso_sink_comp_desc.bMaxBurst = isoc_maxburst;
+       ss_iso_sink_comp_desc.wBytesPerInterval =
+               isoc_maxpacket * (isoc_mult + 1) * (isoc_maxburst + 1);
+       ss_iso_sink_desc.bEndpointAddress = fs_iso_sink_desc.bEndpointAddress;
+
+       ret = usb_assign_descriptors(f, fs_source_sink_descs,
+                       hs_source_sink_descs, ss_source_sink_descs);
+       if (ret)
+               return ret;
 
        DBG(cdev, "%s speed %s: IN/%s, OUT/%s, ISO-IN/%s, ISO-OUT/%s\n",
            (gadget_is_superspeed(c->cdev->gadget) ? "super" :
@@ -458,6 +452,7 @@ no_iso:
 static void
 sourcesink_unbind(struct usb_configuration *c, struct usb_function *f)
 {
+       usb_free_all_descriptors(f);
        kfree(func_to_ss(f));
 }
 
@@ -773,7 +768,6 @@ static int __init sourcesink_bind_config(struct usb_configuration *c)
                return -ENOMEM;
 
        ss->function.name = "source/sink";
-       ss->function.descriptors = fs_source_sink_descs;
        ss->function.bind = sourcesink_bind;
        ss->function.unbind = sourcesink_unbind;
        ss->function.set_alt = sourcesink_set_alt;
index deb437c3b53edaf1620a2136ec83a1a7e8a7a920..856dbae586f14dbd8be61bb1c1c64eea600a1bb6 100644 (file)
@@ -319,38 +319,22 @@ geth_bind(struct usb_configuration *c, struct usb_function *f)
        geth->port.out_ep = ep;
        ep->driver_data = cdev; /* claim */
 
-       /* copy descriptors, and track endpoint copies */
-       f->descriptors = usb_copy_descriptors(fs_eth_function);
-       if (!f->descriptors)
-               goto fail;
-
        /* support all relevant hardware speeds... we expect that when
         * hardware is dual speed, all bulk-capable endpoints work at
         * both speeds
         */
-       if (gadget_is_dualspeed(c->cdev->gadget)) {
-               hs_subset_in_desc.bEndpointAddress =
-                               fs_subset_in_desc.bEndpointAddress;
-               hs_subset_out_desc.bEndpointAddress =
-                               fs_subset_out_desc.bEndpointAddress;
-
-               /* copy descriptors, and track endpoint copies */
-               f->hs_descriptors = usb_copy_descriptors(hs_eth_function);
-               if (!f->hs_descriptors)
-                       goto fail;
-       }
+       hs_subset_in_desc.bEndpointAddress = fs_subset_in_desc.bEndpointAddress;
+       hs_subset_out_desc.bEndpointAddress =
+               fs_subset_out_desc.bEndpointAddress;
 
-       if (gadget_is_superspeed(c->cdev->gadget)) {
-               ss_subset_in_desc.bEndpointAddress =
-                               fs_subset_in_desc.bEndpointAddress;
-               ss_subset_out_desc.bEndpointAddress =
-                               fs_subset_out_desc.bEndpointAddress;
+       ss_subset_in_desc.bEndpointAddress = fs_subset_in_desc.bEndpointAddress;
+       ss_subset_out_desc.bEndpointAddress =
+               fs_subset_out_desc.bEndpointAddress;
 
-               /* copy descriptors, and track endpoint copies */
-               f->ss_descriptors = usb_copy_descriptors(ss_eth_function);
-               if (!f->ss_descriptors)
-                       goto fail;
-       }
+       status = usb_assign_descriptors(f, fs_eth_function, hs_eth_function,
+                       ss_eth_function);
+       if (status)
+               goto fail;
 
        /* NOTE:  all that is done without knowing or caring about
         * the network link ... which is unavailable to this code
@@ -364,11 +348,7 @@ geth_bind(struct usb_configuration *c, struct usb_function *f)
        return 0;
 
 fail:
-       if (f->descriptors)
-               usb_free_descriptors(f->descriptors);
-       if (f->hs_descriptors)
-               usb_free_descriptors(f->hs_descriptors);
-
+       usb_free_all_descriptors(f);
        /* we might as well release our claims on endpoints */
        if (geth->port.out_ep)
                geth->port.out_ep->driver_data = NULL;
@@ -383,11 +363,7 @@ fail:
 static void
 geth_unbind(struct usb_configuration *c, struct usb_function *f)
 {
-       if (gadget_is_superspeed(c->cdev->gadget))
-               usb_free_descriptors(f->ss_descriptors);
-       if (gadget_is_dualspeed(c->cdev->gadget))
-               usb_free_descriptors(f->hs_descriptors);
-       usb_free_descriptors(f->descriptors);
+       usb_free_all_descriptors(f);
        geth_string_defs[1].s = NULL;
        kfree(func_to_geth(f));
 }
index c8ed41ba1042b7a900917216ba0b3b8a1b8a8e48..f570e667a640d0619cd6abaffaf9705738fcab24 100644 (file)
@@ -630,7 +630,7 @@ f_audio_bind(struct usb_configuration *c, struct usb_function *f)
        struct usb_composite_dev *cdev = c->cdev;
        struct f_audio          *audio = func_to_audio(f);
        int                     status;
-       struct usb_ep           *ep;
+       struct usb_ep           *ep = NULL;
 
        f_audio_build_desc(audio);
 
@@ -659,21 +659,14 @@ f_audio_bind(struct usb_configuration *c, struct usb_function *f)
        status = -ENOMEM;
 
        /* copy descriptors, and track endpoint copies */
-       f->descriptors = usb_copy_descriptors(f_audio_desc);
-
-       /*
-        * support all relevant hardware speeds... we expect that when
-        * hardware is dual speed, all bulk-capable endpoints work at
-        * both speeds
-        */
-       if (gadget_is_dualspeed(c->cdev->gadget)) {
-               f->hs_descriptors = usb_copy_descriptors(f_audio_desc);
-       }
-
+       status = usb_assign_descriptors(f, f_audio_desc, f_audio_desc, NULL);
+       if (status)
+               goto fail;
        return 0;
 
 fail:
-
+       if (ep)
+               ep->driver_data = NULL;
        return status;
 }
 
@@ -682,8 +675,7 @@ f_audio_unbind(struct usb_configuration *c, struct usb_function *f)
 {
        struct f_audio          *audio = func_to_audio(f);
 
-       usb_free_descriptors(f->descriptors);
-       usb_free_descriptors(f->hs_descriptors);
+       usb_free_all_descriptors(f);
        kfree(audio);
 }
 
index f02b8ece5287b9a447998868fba3671c5dc9aa46..730a260e1841c1b65e941046f7fc15a224b565c6 100644 (file)
@@ -998,9 +998,9 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)
        hs_epin_desc.bEndpointAddress = fs_epin_desc.bEndpointAddress;
        hs_epin_desc.wMaxPacketSize = fs_epin_desc.wMaxPacketSize;
 
-       fn->descriptors = usb_copy_descriptors(fs_audio_desc);
-       if (gadget_is_dualspeed(gadget))
-               fn->hs_descriptors = usb_copy_descriptors(hs_audio_desc);
+       ret = usb_assign_descriptors(fn, fs_audio_desc, hs_audio_desc, NULL);
+       if (ret)
+               goto err;
 
        prm = &agdev->uac2.c_prm;
        prm->max_psize = hs_epout_desc.wMaxPacketSize;
@@ -1029,8 +1029,7 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)
 err:
        kfree(agdev->uac2.p_prm.rbuf);
        kfree(agdev->uac2.c_prm.rbuf);
-       usb_free_descriptors(fn->hs_descriptors);
-       usb_free_descriptors(fn->descriptors);
+       usb_free_all_descriptors(fn);
        if (agdev->in_ep)
                agdev->in_ep->driver_data = NULL;
        if (agdev->out_ep)
@@ -1042,8 +1041,6 @@ static void
 afunc_unbind(struct usb_configuration *cfg, struct usb_function *fn)
 {
        struct audio_dev *agdev = func_to_agdev(fn);
-       struct usb_composite_dev *cdev = cfg->cdev;
-       struct usb_gadget *gadget = cdev->gadget;
        struct uac2_rtd_params *prm;
 
        alsa_uac2_exit(agdev);
@@ -1053,10 +1050,7 @@ afunc_unbind(struct usb_configuration *cfg, struct usb_function *fn)
 
        prm = &agdev->uac2.c_prm;
        kfree(prm->rbuf);
-
-       if (gadget_is_dualspeed(gadget))
-               usb_free_descriptors(fn->hs_descriptors);
-       usb_free_descriptors(fn->descriptors);
+       usb_free_all_descriptors(fn);
 
        if (agdev->in_ep)
                agdev->in_ep->driver_data = NULL;
index 10f13c1213c71f2a6b338c128d56571a6989f6bc..28ff2546a5b3dcd5770365de2b191304468203ff 100644 (file)
@@ -583,9 +583,7 @@ uvc_function_unbind(struct usb_configuration *c, struct usb_function *f)
        usb_ep_free_request(cdev->gadget->ep0, uvc->control_req);
        kfree(uvc->control_buf);
 
-       kfree(f->descriptors);
-       kfree(f->hs_descriptors);
-       kfree(f->ss_descriptors);
+       usb_free_all_descriptors(f);
 
        kfree(uvc);
 }
@@ -651,49 +649,40 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
        /* sanity check the streaming endpoint module parameters */
        if (streaming_maxpacket > 1024)
                streaming_maxpacket = 1024;
+       /*
+        * Fill in the HS descriptors from the module parameters for the Video
+        * Streaming endpoint.
+        * NOTE: We assume that the user knows what they are doing and won't
+        * give parameters that their UDC doesn't support.
+        */
+       uvc_hs_streaming_ep.wMaxPacketSize = streaming_maxpacket;
+       uvc_hs_streaming_ep.wMaxPacketSize |= streaming_mult << 11;
+       uvc_hs_streaming_ep.bInterval = streaming_interval;
+       uvc_hs_streaming_ep.bEndpointAddress =
+               uvc_fs_streaming_ep.bEndpointAddress;
 
-       /* Copy descriptors for FS. */
-       f->descriptors = uvc_copy_descriptors(uvc, USB_SPEED_FULL);
-
-       /* support high speed hardware */
-       if (gadget_is_dualspeed(cdev->gadget)) {
-               /*
-                * Fill in the HS descriptors from the module parameters for the
-                * Video Streaming endpoint.
-                * NOTE: We assume that the user knows what they are doing and
-                * won't give parameters that their UDC doesn't support.
-                */
-               uvc_hs_streaming_ep.wMaxPacketSize = streaming_maxpacket;
-               uvc_hs_streaming_ep.wMaxPacketSize |= streaming_mult << 11;
-               uvc_hs_streaming_ep.bInterval = streaming_interval;
-               uvc_hs_streaming_ep.bEndpointAddress =
-                               uvc_fs_streaming_ep.bEndpointAddress;
-
-               /* Copy descriptors. */
-               f->hs_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_HIGH);
-       }
+       /*
+        * Fill in the SS descriptors from the module parameters for the Video
+        * Streaming endpoint.
+        * NOTE: We assume that the user knows what they are doing and won't
+        * give parameters that their UDC doesn't support.
+        */
+       uvc_ss_streaming_ep.wMaxPacketSize = streaming_maxpacket;
+       uvc_ss_streaming_ep.bInterval = streaming_interval;
+       uvc_ss_streaming_comp.bmAttributes = streaming_mult;
+       uvc_ss_streaming_comp.bMaxBurst = streaming_maxburst;
+       uvc_ss_streaming_comp.wBytesPerInterval =
+               streaming_maxpacket * (streaming_mult + 1) *
+               (streaming_maxburst + 1);
+       uvc_ss_streaming_ep.bEndpointAddress =
+               uvc_fs_streaming_ep.bEndpointAddress;
 
-       /* support super speed hardware */
-       if (gadget_is_superspeed(c->cdev->gadget)) {
-               /*
-                * Fill in the SS descriptors from the module parameters for the
-                * Video Streaming endpoint.
-                * NOTE: We assume that the user knows what they are doing and
-                * won't give parameters that their UDC doesn't support.
-                */
-               uvc_ss_streaming_ep.wMaxPacketSize = streaming_maxpacket;
-               uvc_ss_streaming_ep.bInterval = streaming_interval;
-               uvc_ss_streaming_comp.bmAttributes = streaming_mult;
-               uvc_ss_streaming_comp.bMaxBurst = streaming_maxburst;
-               uvc_ss_streaming_comp.wBytesPerInterval =
-                       streaming_maxpacket * (streaming_mult + 1) *
-                       (streaming_maxburst + 1);
-               uvc_ss_streaming_ep.bEndpointAddress =
-                               uvc_fs_streaming_ep.bEndpointAddress;
-
-               /* Copy descriptors. */
+       /* Copy descriptors */
+       f->fs_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_FULL);
+       if (gadget_is_dualspeed(cdev->gadget))
+               f->hs_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_HIGH);
+       if (gadget_is_superspeed(c->cdev->gadget))
                f->ss_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_SUPER);
-       }
 
        /* Preallocate control endpoint request. */
        uvc->control_req = usb_ep_alloc_request(cdev->gadget->ep0, GFP_KERNEL);
@@ -741,9 +730,7 @@ error:
                kfree(uvc->control_buf);
        }
 
-       kfree(f->descriptors);
-       kfree(f->hs_descriptors);
-       kfree(f->ss_descriptors);
+       usb_free_all_descriptors(f);
        return ret;
 }
 
index e156e3f267273c3a8b45b0a06025fcbd7e1541a1..35bcc83d1e0428388a30632c8f9b1c2e7f8212e8 100644 (file)
@@ -983,8 +983,10 @@ static int __init printer_func_bind(struct usb_configuration *c,
 {
        struct printer_dev *dev = container_of(f, struct printer_dev, function);
        struct usb_composite_dev *cdev = c->cdev;
-       struct usb_ep           *in_ep, *out_ep;
+       struct usb_ep *in_ep;
+       struct usb_ep *out_ep = NULL;
        int id;
+       int ret;
 
        id = usb_interface_id(c, f);
        if (id < 0)
@@ -1010,6 +1012,11 @@ autoconf_fail:
        hs_ep_in_desc.bEndpointAddress = fs_ep_in_desc.bEndpointAddress;
        hs_ep_out_desc.bEndpointAddress = fs_ep_out_desc.bEndpointAddress;
 
+       ret = usb_assign_descriptors(f, fs_printer_function,
+                       hs_printer_function, NULL);
+       if (ret)
+               return ret;
+
        dev->in_ep = in_ep;
        dev->out_ep = out_ep;
        return 0;
@@ -1018,6 +1025,7 @@ autoconf_fail:
 static void printer_func_unbind(struct usb_configuration *c,
                struct usb_function *f)
 {
+       usb_free_all_descriptors(f);
 }
 
 static int printer_func_set_alt(struct usb_function *f,
@@ -1110,8 +1118,6 @@ static int __init printer_bind_config(struct usb_configuration *c)
        dev = &usb_printer_gadget;
 
        dev->function.name = shortname;
-       dev->function.descriptors = fs_printer_function;
-       dev->function.hs_descriptors = hs_printer_function;
        dev->function.bind = printer_func_bind;
        dev->function.setup = printer_func_setup;
        dev->function.unbind = printer_func_unbind;
index 49596096b43588e56d6132d6b5aec00ab33df057..27a2337f986844901e90a08707d659fa363bc37b 100644 (file)
@@ -2240,6 +2240,7 @@ static int usbg_bind(struct usb_configuration *c, struct usb_function *f)
        struct usb_gadget       *gadget = c->cdev->gadget;
        struct usb_ep           *ep;
        int                     iface;
+       int                     ret;
 
        iface = usb_interface_id(c, f);
        if (iface < 0)
@@ -2290,6 +2291,11 @@ static int usbg_bind(struct usb_configuration *c, struct usb_function *f)
                uasp_ss_status_desc.bEndpointAddress;
        uasp_fs_cmd_desc.bEndpointAddress = uasp_ss_cmd_desc.bEndpointAddress;
 
+       ret = usb_assign_descriptors(f, uasp_fs_function_desc,
+                       uasp_hs_function_desc, uasp_ss_function_desc);
+       if (ret)
+               goto ep_fail;
+
        return 0;
 ep_fail:
        pr_err("Can't claim all required eps\n");
@@ -2305,6 +2311,7 @@ static void usbg_unbind(struct usb_configuration *c, struct usb_function *f)
 {
        struct f_uas *fu = to_f_uas(f);
 
+       usb_free_all_descriptors(f);
        kfree(fu);
 }
 
@@ -2385,9 +2392,6 @@ static int usbg_cfg_bind(struct usb_configuration *c)
        if (!fu)
                return -ENOMEM;
        fu->function.name = "Target Function";
-       fu->function.descriptors = uasp_fs_function_desc;
-       fu->function.hs_descriptors = uasp_hs_function_desc;
-       fu->function.ss_descriptors = uasp_ss_function_desc;
        fu->function.bind = usbg_bind;
        fu->function.unbind = usbg_unbind;
        fu->function.set_alt = usbg_set_alt;
index 8634a127bdd3a14a5808875534318104c1d00e50..b09c37e04a91f64f007a0699cf89d3adc1b97483 100644 (file)
@@ -119,7 +119,7 @@ struct usb_configuration;
 struct usb_function {
        const char                      *name;
        struct usb_gadget_strings       **strings;
-       struct usb_descriptor_header    **descriptors;
+       struct usb_descriptor_header    **fs_descriptors;
        struct usb_descriptor_header    **hs_descriptors;
        struct usb_descriptor_header    **ss_descriptors;
 
index 5b6e50888248d044c4f9f277165cc5ad7b9a7ad6..0af6569b8cc60778c619f3a059d4b78ff49f07f4 100644 (file)
@@ -939,6 +939,13 @@ static inline void usb_free_descriptors(struct usb_descriptor_header **v)
        kfree(v);
 }
 
+struct usb_function;
+int usb_assign_descriptors(struct usb_function *f,
+               struct usb_descriptor_header **fs,
+               struct usb_descriptor_header **hs,
+               struct usb_descriptor_header **ss);
+void usb_free_all_descriptors(struct usb_function *f);
+
 /*-------------------------------------------------------------------------*/
 
 /* utility to simplify map/unmap of usb_requests to/from DMA */