USB: fsl_usb2_udc: fix bug in processing setup requests
authorLi Yang <leoli@freescale.com>
Fri, 17 Aug 2007 15:36:44 +0000 (08:36 -0700)
committerGreg Kroah-Hartman <gregkh@suse.de>
Wed, 22 Aug 2007 21:28:00 +0000 (14:28 -0700)
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 <leoli@freescale.com>
Signed-off-by: Kim Liu <KLiu@vixs.com>
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/usb/gadget/fsl_usb2_udc.c

index 10b2b33..d57bcfb 100644 (file)
@@ -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