Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 10287bae authored by Sebastian Andrzej Siewior's avatar Sebastian Andrzej Siewior Committed by Felipe Balbi
Browse files

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: default avatarSebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: default avatarFelipe Balbi <balbi@ti.com>
parent 0f9df939
Loading
Loading
Loading
Loading
+4 −4
Original line number Original line Diff line number Diff line
@@ -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
Original line number Original line Diff line number Diff line
@@ -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
Original line number Original line Diff line number Diff line
@@ -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_in_desc.bEndpointAddress =
	acm_hs_out_desc.bEndpointAddress = acm_fs_out_desc.bEndpointAddress;
				acm_fs_in_desc.bEndpointAddress;
		acm_hs_out_desc.bEndpointAddress =
				acm_fs_out_desc.bEndpointAddress;
	acm_hs_notify_desc.bEndpointAddress =
	acm_hs_notify_desc.bEndpointAddress =
		acm_fs_notify_desc.bEndpointAddress;
		acm_fs_notify_desc.bEndpointAddress;


		/* copy descriptors */
	acm_ss_in_desc.bEndpointAddress = acm_fs_in_desc.bEndpointAddress;
		f->hs_descriptors = usb_copy_descriptors(acm_hs_function);
	acm_ss_out_desc.bEndpointAddress = acm_fs_out_desc.bEndpointAddress;
	}

	if (gadget_is_superspeed(c->cdev->gadget)) {
	status = usb_assign_descriptors(f, acm_fs_function, acm_hs_function,
		acm_ss_in_desc.bEndpointAddress =
			acm_ss_function);
			acm_fs_in_desc.bEndpointAddress;
	if (status)
		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;
		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_all_descriptors(f);
		usb_free_descriptors(f->hs_descriptors);
	if (gadget_is_superspeed(c->cdev->gadget))
		usb_free_descriptors(f->ss_descriptors);
	usb_free_descriptors(f->descriptors);
	gs_free_req(acm->notify, acm->notify_req);
	gs_free_req(acm->notify, acm->notify_req);
	kfree(acm);
	kfree(acm);
}
}
+15 −42
Original line number Original line Diff line number Diff line
@@ -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_in_desc.bEndpointAddress =
	hs_ecm_out_desc.bEndpointAddress = fs_ecm_out_desc.bEndpointAddress;
				fs_ecm_in_desc.bEndpointAddress;
		hs_ecm_out_desc.bEndpointAddress =
				fs_ecm_out_desc.bEndpointAddress;
	hs_ecm_notify_desc.bEndpointAddress =
	hs_ecm_notify_desc.bEndpointAddress =
		fs_ecm_notify_desc.bEndpointAddress;
		fs_ecm_notify_desc.bEndpointAddress;


		/* copy descriptors, and track endpoint copies */
	ss_ecm_in_desc.bEndpointAddress = fs_ecm_in_desc.bEndpointAddress;
		f->hs_descriptors = usb_copy_descriptors(ecm_hs_function);
	ss_ecm_out_desc.bEndpointAddress = fs_ecm_out_desc.bEndpointAddress;
		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 =
	ss_ecm_notify_desc.bEndpointAddress =
		fs_ecm_notify_desc.bEndpointAddress;
		fs_ecm_notify_desc.bEndpointAddress;


		/* copy descriptors, and track endpoint copies */
	status = usb_assign_descriptors(f, ecm_fs_function, ecm_hs_function,
		f->ss_descriptors = usb_copy_descriptors(ecm_ss_function);
			ecm_ss_function);
		if (!f->ss_descriptors)
	if (status)
		goto fail;
		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_all_descriptors(f);
		usb_free_descriptors(f->ss_descriptors);
	if (gadget_is_dualspeed(c->cdev->gadget))
		usb_free_descriptors(f->hs_descriptors);
	usb_free_descriptors(f->descriptors);


	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
Original line number Original line Diff line number Diff line
@@ -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_in_desc.bEndpointAddress =
	eem_hs_out_desc.bEndpointAddress = eem_fs_out_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;
	}


	if (gadget_is_superspeed(c->cdev->gadget)) {
	eem_ss_in_desc.bEndpointAddress = eem_fs_in_desc.bEndpointAddress;
		eem_ss_in_desc.bEndpointAddress =
	eem_ss_out_desc.bEndpointAddress = eem_fs_out_desc.bEndpointAddress;
				eem_fs_in_desc.bEndpointAddress;
		eem_ss_out_desc.bEndpointAddress =
				eem_fs_out_desc.bEndpointAddress;


		/* copy descriptors, and track endpoint copies */
	status = usb_assign_descriptors(f, eem_fs_function, eem_hs_function,
		f->ss_descriptors = usb_copy_descriptors(eem_ss_function);
			eem_ss_function);
		if (!f->ss_descriptors)
	if (status)
		goto fail;
		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_all_descriptors(f);
		usb_free_descriptors(f->descriptors);
	if (f->hs_descriptors)
		usb_free_descriptors(f->hs_descriptors);

	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_all_descriptors(f);
		usb_free_descriptors(f->ss_descriptors);
	if (gadget_is_dualspeed(c->cdev->gadget))
		usb_free_descriptors(f->hs_descriptors);
	usb_free_descriptors(f->descriptors);
	kfree(eem);
	kfree(eem);
}
}


Loading