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

Commit f6acfff9 authored by Jerome Brunet's avatar Jerome Brunet Committed by Greg Kroah-Hartman
Browse files

usb: gadget: f_uac2: reset wMaxPacketSize



commit 9389044f27081d6ec77730c36d5bf9a1288bcda2 upstream.

With commit 913e4a90 ("usb: gadget: f_uac2: finalize wMaxPacketSize according to bandwidth")
wMaxPacketSize is computed dynamically but the value is never reset.

Because of this, the actual maximum packet size can only decrease each time
the audio gadget is instantiated.

Reset the endpoint maximum packet size and mark wMaxPacketSize as dynamic
to solve the problem.

Fixes: 913e4a90 ("usb: gadget: f_uac2: finalize wMaxPacketSize according to bandwidth")
Signed-off-by: default avatarJerome Brunet <jbrunet@baylibre.com>
Cc: stable <stable@vger.kernel.org>
Link: https://lore.kernel.org/r/20201221173531.215169-2-jbrunet@baylibre.com


Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 50681437
Loading
Loading
Loading
Loading
+55 −14
Original line number Diff line number Diff line
@@ -766,7 +766,7 @@ static struct usb_endpoint_descriptor fs_epout_desc = {

	.bEndpointAddress = USB_DIR_OUT,
	.bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC,
	.wMaxPacketSize = cpu_to_le16(1023),
	/* .wMaxPacketSize = DYNAMIC */
	.bInterval = 1,
};

@@ -775,7 +775,7 @@ static struct usb_endpoint_descriptor hs_epout_desc = {
	.bDescriptorType = USB_DT_ENDPOINT,

	.bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC,
	.wMaxPacketSize = cpu_to_le16(1024),
	/* .wMaxPacketSize = DYNAMIC */
	.bInterval = 4,
};

@@ -843,7 +843,7 @@ static struct usb_endpoint_descriptor fs_epin_desc = {

	.bEndpointAddress = USB_DIR_IN,
	.bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC,
	.wMaxPacketSize = cpu_to_le16(1023),
	/* .wMaxPacketSize = DYNAMIC */
	.bInterval = 1,
};

@@ -852,7 +852,7 @@ static struct usb_endpoint_descriptor hs_epin_desc = {
	.bDescriptorType = USB_DT_ENDPOINT,

	.bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC,
	.wMaxPacketSize = cpu_to_le16(1024),
	/* .wMaxPacketSize = DYNAMIC */
	.bInterval = 4,
};

@@ -963,12 +963,28 @@ free_ep(struct uac2_rtd_params *prm, struct usb_ep *ep)
			"%s:%d Error!\n", __func__, __LINE__);
}

static void set_ep_max_packet_size(const struct f_uac2_opts *uac2_opts,
static int set_ep_max_packet_size(const struct f_uac2_opts *uac2_opts,
	struct usb_endpoint_descriptor *ep_desc,
	unsigned int factor, bool is_playback)
	enum usb_device_speed speed, bool is_playback)
{
	int chmask, srate, ssize;
	u16 max_packet_size;
	u16 max_size_bw, max_size_ep;
	unsigned int factor;

	switch (speed) {
	case USB_SPEED_FULL:
		max_size_ep = 1023;
		factor = 1000;
		break;

	case USB_SPEED_HIGH:
		max_size_ep = 1024;
		factor = 8000;
		break;

	default:
		return -EINVAL;
	}

	if (is_playback) {
		chmask = uac2_opts->p_chmask;
@@ -980,10 +996,12 @@ static void set_ep_max_packet_size(const struct f_uac2_opts *uac2_opts,
		ssize = uac2_opts->c_ssize;
	}

	max_packet_size = num_channels(chmask) * ssize *
	max_size_bw = num_channels(chmask) * ssize *
		DIV_ROUND_UP(srate, factor / (1 << (ep_desc->bInterval - 1)));
	ep_desc->wMaxPacketSize = cpu_to_le16(min_t(u16, max_packet_size,
				le16_to_cpu(ep_desc->wMaxPacketSize)));
	ep_desc->wMaxPacketSize = cpu_to_le16(min_t(u16, max_size_bw,
						    max_size_ep));

	return 0;
}

static int
@@ -1082,10 +1100,33 @@ afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)
	uac2->c_prm.uac2 = uac2;

	/* Calculate wMaxPacketSize according to audio bandwidth */
	set_ep_max_packet_size(uac2_opts, &fs_epin_desc, 1000, true);
	set_ep_max_packet_size(uac2_opts, &fs_epout_desc, 1000, false);
	set_ep_max_packet_size(uac2_opts, &hs_epin_desc, 8000, true);
	set_ep_max_packet_size(uac2_opts, &hs_epout_desc, 8000, false);
	ret = set_ep_max_packet_size(uac2_opts, &fs_epin_desc, USB_SPEED_FULL,
				     true);
	if (ret < 0) {
		dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
		return ret;
	}

	ret = set_ep_max_packet_size(uac2_opts, &fs_epout_desc, USB_SPEED_FULL,
				     false);
	if (ret < 0) {
		dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
		return ret;
	}

	ret = set_ep_max_packet_size(uac2_opts, &hs_epin_desc, USB_SPEED_HIGH,
				     true);
	if (ret < 0) {
		dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
		return ret;
	}

	ret = set_ep_max_packet_size(uac2_opts, &hs_epout_desc, USB_SPEED_HIGH,
				     false);
	if (ret < 0) {
		dev_err(dev, "%s:%d Error!\n", __func__, __LINE__);
		return ret;
	}

	hs_epout_desc.bEndpointAddress = fs_epout_desc.bEndpointAddress;
	hs_epin_desc.bEndpointAddress = fs_epin_desc.bEndpointAddress;