Skip to content

Commit

Permalink
USB: fsl_usb2_udc: fix bug in processing setup requests
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Li Yang authored and Greg Kroah-Hartman committed Aug 22, 2007
1 parent d1a94f0 commit 39d1f8c
Showing 1 changed file with 41 additions and 36 deletions.
77 changes: 41 additions & 36 deletions drivers/usb/gadget/fsl_usb2_udc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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)
Expand All @@ -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
Expand Down

0 comments on commit 39d1f8c

Please sign in to comment.