浏览代码

usb: gadget: always update HS/SS descriptors and create a copy of them

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>
Sebastian Andrzej Siewior 12 年之前
父节点
当前提交
10287baec7

+ 4 - 4
drivers/usb/gadget/composite.c

@@ -107,7 +107,7 @@ int config_ep_by_speed(struct usb_gadget *g,
 		}
 		}
 		/* else: fall through */
 		/* else: fall through */
 	default:
 	default:
-		speed_desc = f->descriptors;
+		speed_desc = f->fs_descriptors;
 	}
 	}
 	/* find descriptors */
 	/* find descriptors */
 	for_each_ep_desc(speed_desc, d_spd) {
 	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
 	 * as full speed ... it's the function drivers that will need
 	 * to avoid bulk and ISO transfers.
 	 * to avoid bulk and ISO transfers.
 	 */
 	 */
-	if (!config->fullspeed && function->descriptors)
+	if (!config->fullspeed && function->fs_descriptors)
 		config->fullspeed = true;
 		config->fullspeed = true;
 	if (!config->highspeed && function->hs_descriptors)
 	if (!config->highspeed && function->hs_descriptors)
 		config->highspeed = true;
 		config->highspeed = true;
@@ -363,7 +363,7 @@ static int config_buf(struct usb_configuration *config,
 			descriptors = f->hs_descriptors;
 			descriptors = f->hs_descriptors;
 			break;
 			break;
 		default:
 		default:
-			descriptors = f->descriptors;
+			descriptors = f->fs_descriptors;
 		}
 		}
 
 
 		if (!descriptors)
 		if (!descriptors)
@@ -620,7 +620,7 @@ static int set_config(struct usb_composite_dev *cdev,
 			descriptors = f->hs_descriptors;
 			descriptors = f->hs_descriptors;
 			break;
 			break;
 		default:
 		default:
-			descriptors = f->descriptors;
+			descriptors = f->fs_descriptors;
 		}
 		}
 
 
 		for (; *descriptors; ++descriptors) {
 		for (; *descriptors; ++descriptors) {

+ 38 - 1
drivers/usb/gadget/config.c

@@ -19,7 +19,7 @@
 
 
 #include <linux/usb/ch9.h>
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
 #include <linux/usb/gadget.h>
-
+#include <linux/usb/composite.h>
 
 
 /**
 /**
  * usb_descriptor_fillbuf - fill buffer with descriptors
  * usb_descriptor_fillbuf - fill buffer with descriptors
@@ -158,3 +158,40 @@ usb_copy_descriptors(struct usb_descriptor_header **src)
 	return ret;
 	return ret;
 }
 }
 EXPORT_SYMBOL_GPL(usb_copy_descriptors);
 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);

+ 13 - 32
drivers/usb/gadget/f_acm.c

@@ -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->complete = acm_cdc_notify_complete;
 	acm->notify_req->context = acm;
 	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
 	/* support all relevant hardware speeds... we expect that when
 	 * hardware is dual speed, all bulk-capable endpoints work at
 	 * hardware is dual speed, all bulk-capable endpoints work at
 	 * both speeds
 	 * 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",
 	DBG(cdev, "acm ttyGS%d: %s speed IN/%s OUT/%s NOTIFY/%s\n",
 			acm->port_num,
 			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);
 	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);
 	gs_free_req(acm->notify, acm->notify_req);
 	kfree(acm);
 	kfree(acm);
 }
 }

+ 15 - 42
drivers/usb/gadget/f_ecm.c

@@ -743,42 +743,24 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f)
 	ecm->notify_req->context = ecm;
 	ecm->notify_req->context = ecm;
 	ecm->notify_req->complete = ecm_notify_complete;
 	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
 	/* support all relevant hardware speeds... we expect that when
 	 * hardware is dual speed, all bulk-capable endpoints work at
 	 * hardware is dual speed, all bulk-capable endpoints work at
 	 * both speeds
 	 * 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
 	/* NOTE:  all that is done without knowing or caring about
 	 * the network link ... which is unavailable to this code
 	 * 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;
 	return 0;
 
 
 fail:
 fail:
-	if (f->descriptors)
-		usb_free_descriptors(f->descriptors);
-	if (f->hs_descriptors)
-		usb_free_descriptors(f->hs_descriptors);
-
 	if (ecm->notify_req) {
 	if (ecm->notify_req) {
 		kfree(ecm->notify_req->buf);
 		kfree(ecm->notify_req->buf);
 		usb_ep_free_request(ecm->notify, ecm->notify_req);
 		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");
 	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);
 	kfree(ecm->notify_req->buf);
 	usb_ep_free_request(ecm->notify, ecm->notify_req);
 	usb_ep_free_request(ecm->notify, ecm->notify_req);

+ 10 - 36
drivers/usb/gadget/f_eem.c

@@ -274,38 +274,20 @@ eem_bind(struct usb_configuration *c, struct usb_function *f)
 
 
 	status = -ENOMEM;
 	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
 	/* support all relevant hardware speeds... we expect that when
 	 * hardware is dual speed, all bulk-capable endpoints work at
 	 * hardware is dual speed, all bulk-capable endpoints work at
 	 * both speeds
 	 * 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",
 	DBG(cdev, "CDC Ethernet (EEM): %s speed IN/%s OUT/%s\n",
 			gadget_is_superspeed(c->cdev->gadget) ? "super" :
 			gadget_is_superspeed(c->cdev->gadget) ? "super" :
@@ -314,11 +296,7 @@ eem_bind(struct usb_configuration *c, struct usb_function *f)
 	return 0;
 	return 0;
 
 
 fail:
 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)
 	if (eem->port.out_ep)
 		eem->port.out_ep->driver_data = NULL;
 		eem->port.out_ep->driver_data = NULL;
 	if (eem->port.in_ep)
 	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");
 	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);
 	kfree(eem);
 }
 }
 
 

+ 2 - 2
drivers/usb/gadget/f_fs.c

@@ -2097,7 +2097,7 @@ static int __ffs_func_bind_do_descs(enum ffs_entity_type type, u8 *valuep,
 	if (isHS)
 	if (isHS)
 		func->function.hs_descriptors[(long)valuep] = desc;
 		func->function.hs_descriptors[(long)valuep] = desc;
 	else
 	else
-		func->function.descriptors[(long)valuep]    = desc;
+		func->function.fs_descriptors[(long)valuep]    = desc;
 
 
 	if (!desc || desc->bDescriptorType != USB_DT_ENDPOINT)
 	if (!desc || desc->bDescriptorType != USB_DT_ENDPOINT)
 		return 0;
 		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.
 	 * numbers without worrying that it may be described later on.
 	 */
 	 */
 	if (likely(full)) {
 	if (likely(full)) {
-		func->function.descriptors = data->fs_descs;
+		func->function.fs_descriptors = data->fs_descs;
 		ret = ffs_do_descs(ffs->fs_descs_count,
 		ret = ffs_do_descs(ffs->fs_descs_count,
 				   data->raw_descs,
 				   data->raw_descs,
 				   sizeof data->raw_descs,
 				   sizeof data->raw_descs,

+ 10 - 20
drivers/usb/gadget/f_hid.c

@@ -573,7 +573,6 @@ static int __init hidg_bind(struct usb_configuration *c, struct usb_function *f)
 		goto fail;
 		goto fail;
 	hidg_interface_desc.bInterfaceNumber = status;
 	hidg_interface_desc.bInterfaceNumber = status;
 
 
-
 	/* allocate instance-specific endpoints */
 	/* allocate instance-specific endpoints */
 	status = -ENODEV;
 	status = -ENODEV;
 	ep = usb_ep_autoconfig(c->cdev->gadget, &hidg_fs_in_ep_desc);
 	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 =
 	hidg_desc.desc[0].wDescriptorLength =
 		cpu_to_le16(hidg->report_desc_length);
 		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);
 	mutex_init(&hidg->lock);
 	spin_lock_init(&hidg->spinlock);
 	spin_lock_init(&hidg->spinlock);
@@ -649,9 +643,7 @@ fail:
 			usb_ep_free_request(hidg->in_ep, hidg->req);
 			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;
 	return status;
 }
 }
 
 
@@ -668,9 +660,7 @@ static void hidg_unbind(struct usb_configuration *c, struct usb_function *f)
 	kfree(hidg->req->buf);
 	kfree(hidg->req->buf);
 	usb_ep_free_request(hidg->in_ep, hidg->req);
 	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->report_desc);
 	kfree(hidg);
 	kfree(hidg);

+ 13 - 15
drivers/usb/gadget/f_loopback.c

@@ -177,6 +177,7 @@ loopback_bind(struct usb_configuration *c, struct usb_function *f)
 	struct usb_composite_dev *cdev = c->cdev;
 	struct usb_composite_dev *cdev = c->cdev;
 	struct f_loopback	*loop = func_to_loop(f);
 	struct f_loopback	*loop = func_to_loop(f);
 	int			id;
 	int			id;
+	int ret;
 
 
 	/* allocate interface ID(s) */
 	/* allocate interface ID(s) */
 	id = usb_interface_id(c, f);
 	id = usb_interface_id(c, f);
@@ -201,22 +202,19 @@ autoconf_fail:
 	loop->out_ep->driver_data = cdev;	/* claim */
 	loop->out_ep->driver_data = cdev;	/* claim */
 
 
 	/* support high speed hardware */
 	/* 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 */
 	/* 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",
 	DBG(cdev, "%s speed %s: IN/%s, OUT/%s\n",
 	    (gadget_is_superspeed(c->cdev->gadget) ? "super" :
 	    (gadget_is_superspeed(c->cdev->gadget) ? "super" :
@@ -228,6 +226,7 @@ autoconf_fail:
 static void
 static void
 loopback_unbind(struct usb_configuration *c, struct usb_function *f)
 loopback_unbind(struct usb_configuration *c, struct usb_function *f)
 {
 {
+	usb_free_all_descriptors(f);
 	kfree(func_to_loop(f));
 	kfree(func_to_loop(f));
 }
 }
 
 
@@ -379,7 +378,6 @@ static int __init loopback_bind_config(struct usb_configuration *c)
 		return -ENOMEM;
 		return -ENOMEM;
 
 
 	loop->function.name = "loopback";
 	loop->function.name = "loopback";
-	loop->function.descriptors = fs_loopback_descs;
 	loop->function.bind = loopback_bind;
 	loop->function.bind = loopback_bind;
 	loop->function.unbind = loopback_unbind;
 	loop->function.unbind = loopback_unbind;
 	loop->function.set_alt = loopback_set_alt;
 	loop->function.set_alt = loopback_set_alt;

+ 20 - 39
drivers/usb/gadget/f_mass_storage.c

@@ -2904,9 +2904,7 @@ static void fsg_unbind(struct usb_configuration *c, struct usb_function *f)
 	}
 	}
 
 
 	fsg_common_put(common);
 	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);
 	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;
 	struct usb_gadget	*gadget = c->cdev->gadget;
 	int			i;
 	int			i;
 	struct usb_ep		*ep;
 	struct usb_ep		*ep;
+	unsigned		max_burst;
+	int			ret;
 
 
 	fsg->gadget = gadget;
 	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 */
 	ep->driver_data = fsg->common;	/* claim the endpoint */
 	fsg->bulk_out = ep;
 	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;
 	return 0;
 
 
@@ -2986,7 +2968,6 @@ autoconf_fail:
 	return -ENOTSUPP;
 	return -ENOTSUPP;
 }
 }
 
 
-
 /****************************** ADD FUNCTION ******************************/
 /****************************** ADD FUNCTION ******************************/
 
 
 static struct usb_gadget_strings *fsg_strings_array[] = {
 static struct usb_gadget_strings *fsg_strings_array[] = {

+ 4 - 4
drivers/usb/gadget/f_midi.c

@@ -414,8 +414,7 @@ static void f_midi_unbind(struct usb_configuration *c, struct usb_function *f)
 	kfree(midi->id);
 	kfree(midi->id);
 	midi->id = NULL;
 	midi->id = NULL;
 
 
-	usb_free_descriptors(f->descriptors);
-	usb_free_descriptors(f->hs_descriptors);
+	usb_free_all_descriptors(f);
 	kfree(midi);
 	kfree(midi);
 }
 }
 
 
@@ -882,9 +881,10 @@ f_midi_bind(struct usb_configuration *c, struct usb_function *f)
 	 * both speeds
 	 * both speeds
 	 */
 	 */
 	/* copy descriptors, and track endpoint copies */
 	/* 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;
 		goto fail_f_midi;
+
 	if (gadget_is_dualspeed(c->cdev->gadget)) {
 	if (gadget_is_dualspeed(c->cdev->gadget)) {
 		bulk_in_desc.wMaxPacketSize = cpu_to_le16(512);
 		bulk_in_desc.wMaxPacketSize = cpu_to_le16(512);
 		bulk_out_desc.wMaxPacketSize = cpu_to_le16(512);
 		bulk_out_desc.wMaxPacketSize = cpu_to_le16(512);

+ 8 - 24
drivers/usb/gadget/f_ncm.c

@@ -1208,30 +1208,18 @@ ncm_bind(struct usb_configuration *c, struct usb_function *f)
 	ncm->notify_req->context = ncm;
 	ncm->notify_req->context = ncm;
 	ncm->notify_req->complete = ncm_notify_complete;
 	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
 	 * support all relevant hardware speeds... we expect that when
 	 * hardware is dual speed, all bulk-capable endpoints work at
 	 * hardware is dual speed, all bulk-capable endpoints work at
 	 * both speeds
 	 * 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
 	 * NOTE:  all that is done without knowing or caring about
 	 * the network link ... which is unavailable to this code
 	 * 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;
 	return 0;
 
 
 fail:
 fail:
-	if (f->descriptors)
-		usb_free_descriptors(f->descriptors);
-
+	usb_free_all_descriptors(f);
 	if (ncm->notify_req) {
 	if (ncm->notify_req) {
 		kfree(ncm->notify_req->buf);
 		kfree(ncm->notify_req->buf);
 		usb_ep_free_request(ncm->notify, ncm->notify_req);
 		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");
 	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);
 	kfree(ncm->notify_req->buf);
 	usb_ep_free_request(ncm->notify, ncm->notify_req);
 	usb_ep_free_request(ncm->notify, ncm->notify_req);

+ 9 - 14
drivers/usb/gadget/f_obex.c

@@ -331,23 +331,19 @@ obex_bind(struct usb_configuration *c, struct usb_function *f)
 	obex->port.out = ep;
 	obex->port.out = ep;
 	ep->driver_data = cdev;	/* claim */
 	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
 	/* support all relevant hardware speeds... we expect that when
 	 * hardware is dual speed, all bulk-capable endpoints work at
 	 * hardware is dual speed, all bulk-capable endpoints work at
 	 * both speeds
 	 * 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
 	/* Avoid letting this gadget enumerate until the userspace
 	 * OBEX server is active.
 	 * OBEX server is active.
@@ -368,6 +364,7 @@ obex_bind(struct usb_configuration *c, struct usb_function *f)
 	return 0;
 	return 0;
 
 
 fail:
 fail:
+	usb_free_all_descriptors(f);
 	/* we might as well release our claims on endpoints */
 	/* we might as well release our claims on endpoints */
 	if (obex->port.out)
 	if (obex->port.out)
 		obex->port.out->driver_data = NULL;
 		obex->port.out->driver_data = NULL;
@@ -382,9 +379,7 @@ fail:
 static void
 static void
 obex_unbind(struct usb_configuration *c, struct usb_function *f)
 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));
 	kfree(func_to_obex(f));
 }
 }
 
 

+ 8 - 7
drivers/usb/gadget/f_phonet.c

@@ -515,14 +515,14 @@ int pn_bind(struct usb_configuration *c, struct usb_function *f)
 	fp->in_ep = ep;
 	fp->in_ep = ep;
 	ep->driver_data = fp; /* Claim */
 	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... */
 	/* 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 */
 	/* Incoming USB requests */
 	status = -ENOMEM;
 	status = -ENOMEM;
@@ -551,7 +551,7 @@ err_req:
 	for (i = 0; i < phonet_rxq_size && fp->out_reqv[i]; i++)
 	for (i = 0; i < phonet_rxq_size && fp->out_reqv[i]; i++)
 		usb_ep_free_request(fp->out_ep, fp->out_reqv[i]);
 		usb_ep_free_request(fp->out_ep, fp->out_reqv[i]);
 err:
 err:
-
+	usb_free_all_descriptors(f);
 	if (fp->out_ep)
 	if (fp->out_ep)
 		fp->out_ep->driver_data = NULL;
 		fp->out_ep->driver_data = NULL;
 	if (fp->in_ep)
 	if (fp->in_ep)
@@ -573,6 +573,7 @@ pn_unbind(struct usb_configuration *c, struct usb_function *f)
 		if (fp->out_reqv[i])
 		if (fp->out_reqv[i])
 			usb_ep_free_request(fp->out_ep, fp->out_reqv[i]);
 			usb_ep_free_request(fp->out_ep, fp->out_reqv[i]);
 
 
+	usb_free_all_descriptors(f);
 	kfree(fp);
 	kfree(fp);
 }
 }
 
 

+ 13 - 42
drivers/usb/gadget/f_rndis.c

@@ -722,42 +722,22 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)
 	rndis->notify_req->context = rndis;
 	rndis->notify_req->context = rndis;
 	rndis->notify_req->complete = rndis_response_complete;
 	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
 	/* support all relevant hardware speeds... we expect that when
 	 * hardware is dual speed, all bulk-capable endpoints work at
 	 * hardware is dual speed, all bulk-capable endpoints work at
 	 * both speeds
 	 * 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.open = rndis_open;
 	rndis->port.close = rndis_close;
 	rndis->port.close = rndis_close;
@@ -788,12 +768,7 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)
 	return 0;
 	return 0;
 
 
 fail:
 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) {
 	if (rndis->notify_req) {
 		kfree(rndis->notify_req->buf);
 		kfree(rndis->notify_req->buf);
@@ -822,11 +797,7 @@ rndis_unbind(struct usb_configuration *c, struct usb_function *f)
 	rndis_exit();
 	rndis_exit();
 	rndis_string_defs[0].id = 0;
 	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);
 	kfree(rndis->notify_req->buf);
 	usb_ep_free_request(rndis->notify, rndis->notify_req);
 	usb_ep_free_request(rndis->notify, rndis->notify_req);

+ 10 - 28
drivers/usb/gadget/f_serial.c

@@ -213,34 +213,20 @@ gser_bind(struct usb_configuration *c, struct usb_function *f)
 	gser->port.out = ep;
 	gser->port.out = ep;
 	ep->driver_data = cdev;	/* claim */
 	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
 	/* support all relevant hardware speeds... we expect that when
 	 * hardware is dual speed, all bulk-capable endpoints work at
 	 * hardware is dual speed, all bulk-capable endpoints work at
 	 * both speeds
 	 * 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",
 	DBG(cdev, "generic ttyGS%d: %s speed IN/%s OUT/%s\n",
 			gser->port_num,
 			gser->port_num,
 			gadget_is_superspeed(c->cdev->gadget) ? "super" :
 			gadget_is_superspeed(c->cdev->gadget) ? "super" :
@@ -263,11 +249,7 @@ fail:
 static void
 static void
 gser_unbind(struct usb_configuration *c, struct usb_function *f)
 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));
 	kfree(func_to_gser(f));
 }
 }
 
 

+ 49 - 55
drivers/usb/gadget/f_sourcesink.c

@@ -319,6 +319,7 @@ sourcesink_bind(struct usb_configuration *c, struct usb_function *f)
 	struct usb_composite_dev *cdev = c->cdev;
 	struct usb_composite_dev *cdev = c->cdev;
 	struct f_sourcesink	*ss = func_to_ss(f);
 	struct f_sourcesink	*ss = func_to_ss(f);
 	int	id;
 	int	id;
+	int ret;
 
 
 	/* allocate interface ID(s) */
 	/* allocate interface ID(s) */
 	id = usb_interface_id(c, f);
 	id = usb_interface_id(c, f);
@@ -387,64 +388,57 @@ no_iso:
 		isoc_maxpacket = 1024;
 		isoc_maxpacket = 1024;
 
 
 	/* support high speed hardware */
 	/* 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 */
 	/* 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",
 	DBG(cdev, "%s speed %s: IN/%s, OUT/%s, ISO-IN/%s, ISO-OUT/%s\n",
 	    (gadget_is_superspeed(c->cdev->gadget) ? "super" :
 	    (gadget_is_superspeed(c->cdev->gadget) ? "super" :
@@ -458,6 +452,7 @@ no_iso:
 static void
 static void
 sourcesink_unbind(struct usb_configuration *c, struct usb_function *f)
 sourcesink_unbind(struct usb_configuration *c, struct usb_function *f)
 {
 {
+	usb_free_all_descriptors(f);
 	kfree(func_to_ss(f));
 	kfree(func_to_ss(f));
 }
 }
 
 
@@ -773,7 +768,6 @@ static int __init sourcesink_bind_config(struct usb_configuration *c)
 		return -ENOMEM;
 		return -ENOMEM;
 
 
 	ss->function.name = "source/sink";
 	ss->function.name = "source/sink";
-	ss->function.descriptors = fs_source_sink_descs;
 	ss->function.bind = sourcesink_bind;
 	ss->function.bind = sourcesink_bind;
 	ss->function.unbind = sourcesink_unbind;
 	ss->function.unbind = sourcesink_unbind;
 	ss->function.set_alt = sourcesink_set_alt;
 	ss->function.set_alt = sourcesink_set_alt;

+ 12 - 36
drivers/usb/gadget/f_subset.c

@@ -319,38 +319,22 @@ geth_bind(struct usb_configuration *c, struct usb_function *f)
 	geth->port.out_ep = ep;
 	geth->port.out_ep = ep;
 	ep->driver_data = cdev;	/* claim */
 	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
 	/* support all relevant hardware speeds... we expect that when
 	 * hardware is dual speed, all bulk-capable endpoints work at
 	 * hardware is dual speed, all bulk-capable endpoints work at
 	 * both speeds
 	 * 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
 	/* NOTE:  all that is done without knowing or caring about
 	 * the network link ... which is unavailable to this code
 	 * 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;
 	return 0;
 
 
 fail:
 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 */
 	/* we might as well release our claims on endpoints */
 	if (geth->port.out_ep)
 	if (geth->port.out_ep)
 		geth->port.out_ep->driver_data = NULL;
 		geth->port.out_ep->driver_data = NULL;
@@ -383,11 +363,7 @@ fail:
 static void
 static void
 geth_unbind(struct usb_configuration *c, struct usb_function *f)
 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;
 	geth_string_defs[1].s = NULL;
 	kfree(func_to_geth(f));
 	kfree(func_to_geth(f));
 }
 }

+ 7 - 15
drivers/usb/gadget/f_uac1.c

@@ -630,7 +630,7 @@ f_audio_bind(struct usb_configuration *c, struct usb_function *f)
 	struct usb_composite_dev *cdev = c->cdev;
 	struct usb_composite_dev *cdev = c->cdev;
 	struct f_audio		*audio = func_to_audio(f);
 	struct f_audio		*audio = func_to_audio(f);
 	int			status;
 	int			status;
-	struct usb_ep		*ep;
+	struct usb_ep		*ep = NULL;
 
 
 	f_audio_build_desc(audio);
 	f_audio_build_desc(audio);
 
 
@@ -659,21 +659,14 @@ f_audio_bind(struct usb_configuration *c, struct usb_function *f)
 	status = -ENOMEM;
 	status = -ENOMEM;
 
 
 	/* copy descriptors, and track endpoint copies */
 	/* 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;
 	return 0;
 
 
 fail:
 fail:
-
+	if (ep)
+		ep->driver_data = NULL;
 	return status;
 	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);
 	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);
 	kfree(audio);
 }
 }
 
 

+ 5 - 11
drivers/usb/gadget/f_uac2.c

@@ -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.bEndpointAddress = fs_epin_desc.bEndpointAddress;
 	hs_epin_desc.wMaxPacketSize = fs_epin_desc.wMaxPacketSize;
 	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 = &agdev->uac2.c_prm;
 	prm->max_psize = hs_epout_desc.wMaxPacketSize;
 	prm->max_psize = hs_epout_desc.wMaxPacketSize;
@@ -1029,8 +1029,7 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)
 err:
 err:
 	kfree(agdev->uac2.p_prm.rbuf);
 	kfree(agdev->uac2.p_prm.rbuf);
 	kfree(agdev->uac2.c_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)
 	if (agdev->in_ep)
 		agdev->in_ep->driver_data = NULL;
 		agdev->in_ep->driver_data = NULL;
 	if (agdev->out_ep)
 	if (agdev->out_ep)
@@ -1042,8 +1041,6 @@ static void
 afunc_unbind(struct usb_configuration *cfg, struct usb_function *fn)
 afunc_unbind(struct usb_configuration *cfg, struct usb_function *fn)
 {
 {
 	struct audio_dev *agdev = func_to_agdev(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;
 	struct uac2_rtd_params *prm;
 
 
 	alsa_uac2_exit(agdev);
 	alsa_uac2_exit(agdev);
@@ -1053,10 +1050,7 @@ afunc_unbind(struct usb_configuration *cfg, struct usb_function *fn)
 
 
 	prm = &agdev->uac2.c_prm;
 	prm = &agdev->uac2.c_prm;
 	kfree(prm->rbuf);
 	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)
 	if (agdev->in_ep)
 		agdev->in_ep->driver_data = NULL;
 		agdev->in_ep->driver_data = NULL;

+ 33 - 46
drivers/usb/gadget/f_uvc.c

@@ -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);
 	usb_ep_free_request(cdev->gadget->ep0, uvc->control_req);
 	kfree(uvc->control_buf);
 	kfree(uvc->control_buf);
 
 
-	kfree(f->descriptors);
-	kfree(f->hs_descriptors);
-	kfree(f->ss_descriptors);
+	usb_free_all_descriptors(f);
 
 
 	kfree(uvc);
 	kfree(uvc);
 }
 }
@@ -651,49 +649,40 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
 	/* sanity check the streaming endpoint module parameters */
 	/* sanity check the streaming endpoint module parameters */
 	if (streaming_maxpacket > 1024)
 	if (streaming_maxpacket > 1024)
 		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);
 		f->ss_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_SUPER);
-	}
 
 
 	/* Preallocate control endpoint request. */
 	/* Preallocate control endpoint request. */
 	uvc->control_req = usb_ep_alloc_request(cdev->gadget->ep0, GFP_KERNEL);
 	uvc->control_req = usb_ep_alloc_request(cdev->gadget->ep0, GFP_KERNEL);
@@ -741,9 +730,7 @@ error:
 		kfree(uvc->control_buf);
 		kfree(uvc->control_buf);
 	}
 	}
 
 
-	kfree(f->descriptors);
-	kfree(f->hs_descriptors);
-	kfree(f->ss_descriptors);
+	usb_free_all_descriptors(f);
 	return ret;
 	return ret;
 }
 }
 
 

+ 9 - 3
drivers/usb/gadget/printer.c

@@ -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 printer_dev *dev = container_of(f, struct printer_dev, function);
 	struct usb_composite_dev *cdev = c->cdev;
 	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 id;
+	int ret;
 
 
 	id = usb_interface_id(c, f);
 	id = usb_interface_id(c, f);
 	if (id < 0)
 	if (id < 0)
@@ -1010,6 +1012,11 @@ autoconf_fail:
 	hs_ep_in_desc.bEndpointAddress = fs_ep_in_desc.bEndpointAddress;
 	hs_ep_in_desc.bEndpointAddress = fs_ep_in_desc.bEndpointAddress;
 	hs_ep_out_desc.bEndpointAddress = fs_ep_out_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->in_ep = in_ep;
 	dev->out_ep = out_ep;
 	dev->out_ep = out_ep;
 	return 0;
 	return 0;
@@ -1018,6 +1025,7 @@ autoconf_fail:
 static void printer_func_unbind(struct usb_configuration *c,
 static void printer_func_unbind(struct usb_configuration *c,
 		struct usb_function *f)
 		struct usb_function *f)
 {
 {
+	usb_free_all_descriptors(f);
 }
 }
 
 
 static int printer_func_set_alt(struct usb_function *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 = &usb_printer_gadget;
 
 
 	dev->function.name = shortname;
 	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.bind = printer_func_bind;
 	dev->function.setup = printer_func_setup;
 	dev->function.setup = printer_func_setup;
 	dev->function.unbind = printer_func_unbind;
 	dev->function.unbind = printer_func_unbind;

+ 7 - 3
drivers/usb/gadget/tcm_usb_gadget.c

@@ -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_gadget	*gadget = c->cdev->gadget;
 	struct usb_ep		*ep;
 	struct usb_ep		*ep;
 	int			iface;
 	int			iface;
+	int			ret;
 
 
 	iface = usb_interface_id(c, f);
 	iface = usb_interface_id(c, f);
 	if (iface < 0)
 	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_ss_status_desc.bEndpointAddress;
 	uasp_fs_cmd_desc.bEndpointAddress = uasp_ss_cmd_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;
 	return 0;
 ep_fail:
 ep_fail:
 	pr_err("Can't claim all required eps\n");
 	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);
 	struct f_uas *fu = to_f_uas(f);
 
 
+	usb_free_all_descriptors(f);
 	kfree(fu);
 	kfree(fu);
 }
 }
 
 
@@ -2385,9 +2392,6 @@ static int usbg_cfg_bind(struct usb_configuration *c)
 	if (!fu)
 	if (!fu)
 		return -ENOMEM;
 		return -ENOMEM;
 	fu->function.name = "Target Function";
 	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.bind = usbg_bind;
 	fu->function.unbind = usbg_unbind;
 	fu->function.unbind = usbg_unbind;
 	fu->function.set_alt = usbg_set_alt;
 	fu->function.set_alt = usbg_set_alt;

+ 1 - 1
include/linux/usb/composite.h

@@ -119,7 +119,7 @@ struct usb_configuration;
 struct usb_function {
 struct usb_function {
 	const char			*name;
 	const char			*name;
 	struct usb_gadget_strings	**strings;
 	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	**hs_descriptors;
 	struct usb_descriptor_header	**ss_descriptors;
 	struct usb_descriptor_header	**ss_descriptors;
 
 

+ 7 - 0
include/linux/usb/gadget.h

@@ -939,6 +939,13 @@ static inline void usb_free_descriptors(struct usb_descriptor_header **v)
 	kfree(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 */
 /* utility to simplify map/unmap of usb_requests to/from DMA */