[PATCH 30/35] USB: fsl_usb2_udc: fix bug in processing setup requests

Greg Kroah-Hartman <[email protected]>
Newsgroups gmane.linux.usb.devel
Message-ID <[email protected]>
From: Li Yang <[email protected]>

Kim Liu found that in the original code certain class setup requests
are wrongly recognized and processed as standard setup requests.
For that reason gadget ether can't work in RNDIS mode with Windows host.

The patch fixes the setup request processing code, and makes class
requests correctly passed to gadget layer.

Signed-off-by: Li Yang <[email protected]>
Signed-off-by: Kim Liu <[email protected]>
Signed-off-by: David Brownell <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>
---
 drivers/usb/gadget/fsl_usb2_udc.c |   77 +++++++++++++++++++-----------------
 1 files changed, 41 insertions(+), 36 deletions(-)

diff --git a/drivers/usb/gadget/fsl_usb2_udc.c b/drivers/usb/gadget/fsl_usb2_udc.c
index 10b2b33..d57bcfb 100644
--- a/drivers/usb/gadget/fsl_usb2_udc.c
+++ b/drivers/usb/gadget/fsl_usb2_udc.c
@@ -1277,31 +1277,32 @@ static void setup_received_irq(struct fsl_udc *udc,
 
 	udc_reset_ep_queue(udc, 0);
 
+	/* We process some stardard setup requests here */
 	switch (setup->bRequest) {
-		/* Request that need Data+Status phase from udc */
 	case USB_REQ_GET_STATUS:
-		if ((setup->bRequestType & (USB_DIR_IN | USB_TYPE_STANDARD))
+		/* Data+Status phase from udc */
+		if ((setup->bRequestType & (USB_DIR_IN | USB_TYPE_MASK))
 					!= (USB_DIR_IN | USB_TYPE_STANDARD))
 			break;
 		ch9getstatus(udc, setup->bRequestType, wValue, wIndex, wLength);
-		break;
+		return;
 
-		/* Requests that need Status phase from udc */
 	case USB_REQ_SET_ADDRESS:
+		/* Status phase from udc */
 		if (setup->bRequestType != (USB_DIR_OUT | USB_TYPE_STANDARD
 						| USB_RECIP_DEVICE))
 			break;
 		ch9setaddress(udc, wValue, wIndex, wLength);
-		break;
+		return;
 
-		/* Handled by udc, no data, status by udc */
 	case USB_REQ_CLEAR_FEATURE:
 	case USB_REQ_SET_FEATURE:
-	{	/* status transaction */
+		/* Status phase from udc */
+	{
 		int rc = -EOPNOTSUPP;
 
-		if ((setup->bRequestType & USB_RECIP_MASK)
-				== USB_RECIP_ENDPOINT) {
+		if ((setup->bRequestType & (USB_RECIP_MASK | USB_TYPE_MASK))
+				== (USB_RECIP_ENDPOINT | USB_TYPE_STANDARD)) {
 			int pipe = get_pipe_by_windex(wIndex);
 			struct fsl_ep *ep;
 
@@ -1315,8 +1316,9 @@ static void setup_received_irq(struct fsl_udc *udc,
 						? 1 : 0);
 			spin_lock(&udc->lock);
 
-		} else if ((setup->bRequestType & USB_RECIP_MASK)
-				== USB_RECIP_DEVICE) {
+		} else if ((setup->bRequestType & (USB_RECIP_MASK
+				| USB_TYPE_MASK)) == (USB_RECIP_DEVICE
+				| USB_TYPE_STANDARD)) {
 			/* Note: The driver has not include OTG support yet.
 			 * This will be set when OTG support is added */
 			if (!udc->gadget.is_otg)
@@ -1329,39 +1331,42 @@ static void setup_received_irq(struct fsl_udc *udc,
 					USB_DEVICE_A_ALT_HNP_SUPPORT)
 				udc->gadget.a_alt_hnp_support = 1;
 			rc = 0;
-		}
+		} else
+			break;
+
 		if (rc == 0) {
 			if (ep0_prime_status(udc, EP_DIR_IN))
 				ep0stall(udc);
 		}
-		break;
+		return;
 	}
-		/* Requests handled by gadget */
-	default:
-		if (wLength) {
-			/* Data phase from gadget, status phase from udc */
-			udc->ep0_dir = (setup->bRequestType & USB_DIR_IN)
-					?  USB_DIR_IN : USB_DIR_OUT;
-			spin_unlock(&udc->lock);
-			if (udc->driver->setup(&udc->gadget,
-					&udc->local_setup_buff) < 0)
-				ep0stall(udc);
-			spin_lock(&udc->lock);
-			udc->ep0_state = (setup->bRequestType & USB_DIR_IN)
-					?  DATA_STATE_XMIT : DATA_STATE_RECV;
 
-		} else {
-			/* No data phase, IN status from gadget */
-			udc->ep0_dir = USB_DIR_IN;
-			spin_unlock(&udc->lock);
-			if (udc->driver->setup(&udc->gadget,
-					&udc->local_setup_buff) < 0)
-				ep0stall(udc);
-			spin_lock(&udc->lock);
-			udc->ep0_state = WAIT_FOR_OUT_STATUS;
-		}
+	default:
 		break;
 	}
+
+	/* Requests handled by gadget */
+	if (wLength) {
+		/* Data phase from gadget, status phase from udc */
+		udc->ep0_dir = (setup->bRequestType & USB_DIR_IN)
+				?  USB_DIR_IN : USB_DIR_OUT;
+		spin_unlock(&udc->lock);
+		if (udc->driver->setup(&udc->gadget,
+				&udc->local_setup_buff) < 0)
+			ep0stall(udc);
+		spin_lock(&udc->lock);
+		udc->ep0_state = (setup->bRequestType & USB_DIR_IN)
+				?  DATA_STATE_XMIT : DATA_STATE_RECV;
+	} else {
+		/* No data phase, IN status from gadget */
+		udc->ep0_dir = USB_DIR_IN;
+		spin_unlock(&udc->lock);
+		if (udc->driver->setup(&udc->gadget,
+				&udc->local_setup_buff) < 0)
+			ep0stall(udc);
+		spin_lock(&udc->lock);
+		udc->ep0_state = WAIT_FOR_OUT_STATUS;
+	}
 }
 
 /* Process request for Data or Status phase of ep0
-- 
1.5.3.rc5


-------------------------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc.
Still grepping through log files to find problems?  Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >>  http://get.splunk.com/
_______________________________________________
[email protected]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.