f_sdp: Add EP1_OUT as default data receive pipe in sdp

EP0 has been used to transfer file data in sdp before, but the max
packetsize of ep0 is 64 bytes. So in order to improve the file transfer
speed, here add the EP1_OUT interrupt endpoint which max packetsize is
set to 1024 byte.

After testing, it turns out that using ep1out is twice as fast as using
ep0 while receiving data in sdp.

Signed-off-by: Sherry Sun <sherry.sun@nxp.com>
Reviewed-by: Ye Li <ye.li@nxp.com>
Signed-off-by: Peng Fan <peng.fan@nxp.com>
diff --git a/drivers/usb/gadget/f_sdp.c b/drivers/usb/gadget/f_sdp.c
index 9b73728..c5b3594 100644
--- a/drivers/usb/gadget/f_sdp.c
+++ b/drivers/usb/gadget/f_sdp.c
@@ -71,6 +71,8 @@
 
 #define SDP_COMMAND_LEN		16
 
+#define SDP_HID_PACKET_SIZE_EP1 1024
+
 #define SDP_EXIT 1
 
 struct sdp_command {
@@ -84,8 +86,10 @@
 
 enum sdp_state {
 	SDP_STATE_IDLE,
+	SDP_STATE_RX_CMD,
 	SDP_STATE_RX_DCD_DATA,
 	SDP_STATE_RX_FILE_DATA,
+	SDP_STATE_RX_FILE_DATA_BUSY,
 	SDP_STATE_TX_SEC_CONF,
 	SDP_STATE_TX_SEC_CONF_BUSY,
 	SDP_STATE_TX_REGISTER,
@@ -116,8 +120,12 @@
 	/* EP1 IN */
 	struct usb_ep			*in_ep;
 	struct usb_request		*in_req;
+	/* EP1 OUT */
+	struct usb_ep			*out_ep;
+	struct usb_request		*out_req;
 
 	bool				configuration_done;
+	bool				ep_int_enable;
 };
 
 static struct f_sdp *sdp_func;
@@ -131,7 +139,7 @@
 	.bLength =		sizeof(sdp_intf_runtime),
 	.bDescriptorType =	USB_DT_INTERFACE,
 	.bAlternateSetting =	0,
-	.bNumEndpoints =	1,
+	.bNumEndpoints =	2,
 	.bInterfaceClass =	USB_CLASS_HID,
 	.bInterfaceSubClass =	0,
 	.bInterfaceProtocol =	0,
@@ -161,6 +169,16 @@
 	.bInterval =		1,
 };
 
+static struct usb_endpoint_descriptor out_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT, /*USB_DT_CS_ENDPOINT*/
+
+	.bEndpointAddress =	1 | USB_DIR_OUT,
+	.bmAttributes =		USB_ENDPOINT_XFER_INT,
+	.wMaxPacketSize =	64,
+	.bInterval =		1,
+};
+
 static struct usb_endpoint_descriptor in_hs_desc = {
 	.bLength =		USB_DT_ENDPOINT_SIZE,
 	.bDescriptorType =	USB_DT_ENDPOINT, /*USB_DT_CS_ENDPOINT*/
@@ -171,10 +189,21 @@
 	.bInterval =		1,
 };
 
+static struct usb_endpoint_descriptor out_hs_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT, /*USB_DT_CS_ENDPOINT*/
+
+	.bEndpointAddress =	1 | USB_DIR_OUT,
+	.bmAttributes =		USB_ENDPOINT_XFER_INT,
+	.wMaxPacketSize =	SDP_HID_PACKET_SIZE_EP1,
+	.bInterval =		1,
+};
+
 static struct usb_descriptor_header *sdp_runtime_descs[] = {
 	(struct usb_descriptor_header *)&sdp_intf_runtime,
 	(struct usb_descriptor_header *)&sdp_hid_desc,
 	(struct usb_descriptor_header *)&in_desc,
+	(struct usb_descriptor_header *)&out_desc,
 	NULL,
 };
 
@@ -182,6 +211,7 @@
 	(struct usb_descriptor_header *)&sdp_intf_runtime,
 	(struct usb_descriptor_header *)&sdp_hid_desc,
 	(struct usb_descriptor_header *)&in_hs_desc,
+	(struct usb_descriptor_header *)&out_hs_desc,
 	NULL,
 };
 
@@ -347,7 +377,7 @@
 	int status = req->status;
 	u8 *data = req->buf;
 	u8 report = data[0];
-	int datalen = req->length - 1;
+	int datalen = req->actual - 1;
 
 	if (status != 0) {
 		pr_err("Status: %d\n", status);
@@ -370,13 +400,15 @@
 		sdp->dnl_bytes_remaining -= datalen;
 	}
 
-	if (sdp->state == SDP_STATE_RX_FILE_DATA) {
+	if (sdp->state == SDP_STATE_RX_FILE_DATA_BUSY) {
 		memcpy(sdp_ptr(sdp->dnl_address), req->buf + 1, datalen);
 		sdp->dnl_address += datalen;
 	}
 
-	if (sdp->dnl_bytes_remaining)
+	if (sdp->dnl_bytes_remaining) {
+		sdp->state = SDP_STATE_RX_FILE_DATA;
 		return;
+	}
 
 #ifndef CONFIG_SPL_BUILD
 	env_set_hex("filesize", sdp->dnl_bytes);
@@ -384,7 +416,7 @@
 	printf("done\n");
 
 	switch (sdp->state) {
-	case SDP_STATE_RX_FILE_DATA:
+	case SDP_STATE_RX_FILE_DATA_BUSY:
 		sdp->state = SDP_STATE_TX_SEC_CONF;
 		break;
 	case SDP_STATE_RX_DCD_DATA:
@@ -465,10 +497,12 @@
 			case 1:
 				value = SDP_COMMAND_LEN + 1;
 				req->complete = sdp_rx_command_complete;
+				sdp_func->ep_int_enable = false;
 				break;
 			case 2:
 				value = len;
 				req->complete = sdp_rx_data_complete;
+				sdp_func->state = SDP_STATE_RX_FILE_DATA_BUSY;
 				break;
 			}
 		}
@@ -499,11 +533,17 @@
 		return id;
 	sdp_intf_runtime.bInterfaceNumber = id;
 
-	struct usb_ep *ep;
+	struct usb_ep *ep_in, *ep_out;
 
 	/* allocate instance-specific endpoints */
-	ep = usb_ep_autoconfig(gadget, &in_desc);
-	if (!ep) {
+	ep_in = usb_ep_autoconfig(gadget, &in_desc);
+	if (!ep_in) {
+		rv = -ENODEV;
+		goto error;
+	}
+
+	ep_out = usb_ep_autoconfig(gadget, &out_desc);
+	if (!ep_out) {
 		rv = -ENODEV;
 		goto error;
 	}
@@ -511,9 +551,11 @@
 	if (gadget_is_dualspeed(gadget)) {
 		/* Assume endpoint addresses are the same for both speeds */
 		in_hs_desc.bEndpointAddress = in_desc.bEndpointAddress;
+		out_hs_desc.bEndpointAddress = out_desc.bEndpointAddress;
 	}
 
-	sdp->in_ep = ep; /* Store IN EP for enabling @ setup */
+	sdp->in_ep = ep_in; /* Store IN EP for enabling @ setup */
+	sdp->out_ep = ep_out;
 
 	cdev->req->context = sdp;
 
@@ -546,18 +588,29 @@
 }
 
 
-static struct usb_request *sdp_start_ep(struct usb_ep *ep)
+static struct usb_request *sdp_start_ep(struct usb_ep *ep, bool in)
 {
 	struct usb_request *req;
 
-	req = alloc_ep_req(ep, 65);
+	if (in)
+		req = alloc_ep_req(ep, 65);
+	else
+		req = alloc_ep_req(ep, 2048);
+/*
+ * OUT endpoint request length should be an integral multiple of
+ * maxpacket size 1024, else we break on certain controllers like
+ * DWC3 that expect bulk OUT requests to be divisible by maxpacket size.
+ */
 	debug("%s: ep:%p req:%p\n", __func__, ep, req);
 
 	if (!req)
 		return NULL;
 
 	memset(req->buf, 0, req->length);
-	req->complete = sdp_tx_complete;
+	if (in)
+		req->complete = sdp_tx_complete;
+	else
+		req->complete = sdp_rx_command_complete;
 
 	return req;
 }
@@ -570,19 +623,27 @@
 
 	debug("%s: intf: %d alt: %d\n", __func__, intf, alt);
 
-	if (gadget_is_dualspeed(gadget) && gadget->speed == USB_SPEED_HIGH)
+	if (gadget_is_dualspeed(gadget) && gadget->speed == USB_SPEED_HIGH) {
 		result = usb_ep_enable(sdp->in_ep, &in_hs_desc);
-	else
+		result |= usb_ep_enable(sdp->out_ep, &out_hs_desc);
+	} else {
 		result = usb_ep_enable(sdp->in_ep, &in_desc);
+		result |= usb_ep_enable(sdp->out_ep, &out_desc);
+	}
 	if (result)
 		return result;
-	sdp->in_req = sdp_start_ep(sdp->in_ep);
+
+	sdp->in_req = sdp_start_ep(sdp->in_ep, true);
 	sdp->in_req->context = sdp;
+	sdp->out_req = sdp_start_ep(sdp->out_ep, false);
+	sdp->out_req->context = sdp;
 
 	sdp->in_ep->driver_data = cdev; /* claim */
+	sdp->out_ep->driver_data = cdev; /* claim */
 
 	sdp->altsetting = alt;
 	sdp->state = SDP_STATE_IDLE;
+	sdp->ep_int_enable = true;
 
 	return 0;
 }
@@ -599,11 +660,18 @@
 	struct f_sdp *sdp = func_to_sdp(f);
 
 	usb_ep_disable(sdp->in_ep);
+	usb_ep_disable(sdp->out_ep);
 
 	if (sdp->in_req) {
-		free(sdp->in_req);
+		free(sdp->in_req->buf);
+		usb_ep_free_request(sdp->in_ep, sdp->in_req);
 		sdp->in_req = NULL;
 	}
+	if (sdp->out_req) {
+		free(sdp->out_req->buf);
+		usb_ep_free_request(sdp->out_ep, sdp->out_req);
+		sdp->out_req = NULL;
+	}
 }
 
 static int sdp_bind_config(struct usb_configuration *c)
@@ -818,6 +886,27 @@
 	return 0;
 }
 
+static void sdp_handle_out_ep(void)
+{
+	int rc;
+
+	if (sdp_func->state == SDP_STATE_IDLE) {
+		sdp_func->out_req->complete = sdp_rx_command_complete;
+		rc = usb_ep_queue(sdp_func->out_ep, sdp_func->out_req, 0);
+		if (rc)
+			printf("error in submission: %s\n",
+			       sdp_func->out_ep->name);
+		sdp_func->state = SDP_STATE_RX_CMD;
+	} else if (sdp_func->state == SDP_STATE_RX_FILE_DATA) {
+		sdp_func->out_req->complete = sdp_rx_data_complete;
+		rc = usb_ep_queue(sdp_func->out_ep, sdp_func->out_req, 0);
+		if (rc)
+			printf("error in submission: %s\n",
+			       sdp_func->out_ep->name);
+		sdp_func->state = SDP_STATE_RX_FILE_DATA_BUSY;
+	}
+}
+
 #ifndef CONFIG_SPL_BUILD
 int sdp_handle(int controller_index)
 #else
@@ -843,6 +932,8 @@
 #else
 		flag = sdp_handle_in_ep(NULL);
 #endif
+		if (sdp_func->ep_int_enable)
+			sdp_handle_out_ep();
 	}
 }