usb: device: fix control endpoint handling with MPS of 8 bytes

The possible control endpoint MPS for USB 2.0 FS devices is
8, 16, 32, or 64 bytes. Typically, USB2.0 compliant devices support MPS
up to 64 bytes, and we have not had the need to support other MPS.

This patch implements a mechanism to fall back to the minimum allowed
MPS when a controller is likely a USB 1.1 compliant device and does
not support control endpoint MPS of 64 bytes.

Signed-off-by: Johann Fischer <johann.fischer@nordicsemi.no>
diff --git a/subsys/usb/device/usb_descriptor.c b/subsys/usb/device/usb_descriptor.c
index 0ca9b89..5533828 100644
--- a/subsys/usb/device/usb_descriptor.c
+++ b/subsys/usb/device/usb_descriptor.c
@@ -355,6 +355,31 @@
 	memcpy(sn->bString, runtime_sn, runtime_sn_len);
 }
 
+static void usb_desc_update_mps0(struct usb_device_descriptor *const desc)
+{
+	struct usb_dc_ep_cfg_data ep_cfg = {
+		.ep_addr = 0,
+		.ep_mps = USB_MAX_CTRL_MPS,
+		.ep_type = USB_DC_EP_CONTROL,
+	};
+	int ret;
+
+	ret = usb_dc_ep_check_cap(&ep_cfg);
+	if (ret) {
+		/* Try the minimum bMaxPacketSize0 that must be supported. */
+		ep_cfg.ep_mps = 8;
+		ret = usb_dc_ep_check_cap(&ep_cfg);
+		if (ret) {
+			ep_cfg.ep_mps = 0;
+		}
+
+		__ASSERT(ret == 0, "Failed to find valid bMaxPacketSize0");
+	}
+
+	desc->bMaxPacketSize0 = ep_cfg.ep_mps;
+	LOG_DBG("Set bMaxPacketSize0 %u", desc->bMaxPacketSize0);
+}
+
 /*
  * The entire descriptor, placed in the .usb.descriptor section,
  * needs to be fixed before use. Currently, only the length of the
@@ -377,6 +402,10 @@
 
 	while (head->bLength != 0U) {
 		switch (head->bDescriptorType) {
+		case USB_DESC_DEVICE:
+			LOG_DBG("Device descriptor %p", head);
+			usb_desc_update_mps0((void *)head);
+			break;
 		case USB_DESC_CONFIGURATION:
 			cfg_descr = (struct usb_cfg_descriptor *)head;
 			LOG_DBG("Configuration descriptor %p", head);
diff --git a/subsys/usb/device/usb_device.c b/subsys/usb/device/usb_device.c
index dfed9eb..41bcb85 100644
--- a/subsys/usb/device/usb_device.c
+++ b/subsys/usb/device/usb_device.c
@@ -136,6 +136,8 @@
 	bool remote_wakeup;
 	/** Tracks whether set_endpoint() had been called on an EP */
 	uint32_t ep_bm;
+	/** Maximum Packet Size (MPS) of control endpoint */
+	uint8_t mps0;
 } usb_dev;
 
 /* Setup packet definition used to read raw data from USB line */
@@ -255,7 +257,7 @@
 		if (!usb_dev.data_buf_residue && chunk &&
 		    usb_dev.setup.wLength > usb_dev.data_buf_len) {
 			/* Send less data as requested during the Setup stage */
-			if (!(usb_dev.data_buf_len % USB_MAX_CTRL_MPS)) {
+			if (!(usb_dev.data_buf_len % usb_dev.mps0)) {
 				/* Transfers a zero-length packet */
 				LOG_DBG("ZLP, requested %u , length %u ",
 					usb_dev.setup.wLength,
@@ -1593,6 +1595,7 @@
 {
 	int ret;
 	struct usb_dc_ep_cfg_data ep0_cfg;
+	struct usb_device_descriptor *dev_desc = (void *)usb_dev.descriptors;
 
 	/* Prevent from calling usb_enable form different context.
 	 * This should only be called once.
@@ -1626,8 +1629,16 @@
 		goto out;
 	}
 
+	if (dev_desc->bDescriptorType != USB_DESC_DEVICE ||
+	    dev_desc->bMaxPacketSize0 == 0) {
+		LOG_ERR("Erroneous device descriptor or bMaxPacketSize0");
+		ret = -EINVAL;
+		goto out;
+	}
+
 	/* Configure control EP */
-	ep0_cfg.ep_mps = USB_MAX_CTRL_MPS;
+	usb_dev.mps0 = dev_desc->bMaxPacketSize0;
+	ep0_cfg.ep_mps = usb_dev.mps0;
 	ep0_cfg.ep_type = USB_DC_EP_CONTROL;
 
 	ep0_cfg.ep_addr = USB_CONTROL_EP_OUT;