in gadget/udc/at91_udc.c [1045:1269]
static void handle_setup(struct at91_udc *udc, struct at91_ep *ep, u32 csr)
{
u32 __iomem *creg = ep->creg;
u8 __iomem *dreg = ep->creg + (AT91_UDP_FDR(0) - AT91_UDP_CSR(0));
unsigned rxcount, i = 0;
u32 tmp;
union setup pkt;
int status = 0;
/* read and ack SETUP; hard-fail for bogus packets */
rxcount = (csr & AT91_UDP_RXBYTECNT) >> 16;
if (likely(rxcount == 8)) {
while (rxcount--)
pkt.raw[i++] = __raw_readb(dreg);
if (pkt.r.bRequestType & USB_DIR_IN) {
csr |= AT91_UDP_DIR;
ep->is_in = 1;
} else {
csr &= ~AT91_UDP_DIR;
ep->is_in = 0;
}
} else {
/* REVISIT this happens sometimes under load; why?? */
ERR("SETUP len %d, csr %08x\n", rxcount, csr);
status = -EINVAL;
}
csr |= CLR_FX;
csr &= ~(SET_FX | AT91_UDP_RXSETUP);
__raw_writel(csr, creg);
udc->wait_for_addr_ack = 0;
udc->wait_for_config_ack = 0;
ep->stopped = 0;
if (unlikely(status != 0))
goto stall;
#define w_index le16_to_cpu(pkt.r.wIndex)
#define w_value le16_to_cpu(pkt.r.wValue)
#define w_length le16_to_cpu(pkt.r.wLength)
VDBG("SETUP %02x.%02x v%04x i%04x l%04x\n",
pkt.r.bRequestType, pkt.r.bRequest,
w_value, w_index, w_length);
/*
* A few standard requests get handled here, ones that touch
* hardware ... notably for device and endpoint features.
*/
udc->req_pending = 1;
csr = __raw_readl(creg);
csr |= CLR_FX;
csr &= ~SET_FX;
switch ((pkt.r.bRequestType << 8) | pkt.r.bRequest) {
case ((USB_TYPE_STANDARD|USB_RECIP_DEVICE) << 8)
| USB_REQ_SET_ADDRESS:
__raw_writel(csr | AT91_UDP_TXPKTRDY, creg);
udc->addr = w_value;
udc->wait_for_addr_ack = 1;
udc->req_pending = 0;
/* FADDR is set later, when we ack host STATUS */
return;
case ((USB_TYPE_STANDARD|USB_RECIP_DEVICE) << 8)
| USB_REQ_SET_CONFIGURATION:
tmp = at91_udp_read(udc, AT91_UDP_GLB_STAT) & AT91_UDP_CONFG;
if (pkt.r.wValue)
udc->wait_for_config_ack = (tmp == 0);
else
udc->wait_for_config_ack = (tmp != 0);
if (udc->wait_for_config_ack)
VDBG("wait for config\n");
/* CONFG is toggled later, if gadget driver succeeds */
break;
/*
* Hosts may set or clear remote wakeup status, and
* devices may report they're VBUS powered.
*/
case ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE) << 8)
| USB_REQ_GET_STATUS:
tmp = (udc->gadget.is_selfpowered << USB_DEVICE_SELF_POWERED);
if (at91_udp_read(udc, AT91_UDP_GLB_STAT) & AT91_UDP_ESR)
tmp |= (1 << USB_DEVICE_REMOTE_WAKEUP);
PACKET("get device status\n");
__raw_writeb(tmp, dreg);
__raw_writeb(0, dreg);
goto write_in;
/* then STATUS starts later, automatically */
case ((USB_TYPE_STANDARD|USB_RECIP_DEVICE) << 8)
| USB_REQ_SET_FEATURE:
if (w_value != USB_DEVICE_REMOTE_WAKEUP)
goto stall;
tmp = at91_udp_read(udc, AT91_UDP_GLB_STAT);
tmp |= AT91_UDP_ESR;
at91_udp_write(udc, AT91_UDP_GLB_STAT, tmp);
goto succeed;
case ((USB_TYPE_STANDARD|USB_RECIP_DEVICE) << 8)
| USB_REQ_CLEAR_FEATURE:
if (w_value != USB_DEVICE_REMOTE_WAKEUP)
goto stall;
tmp = at91_udp_read(udc, AT91_UDP_GLB_STAT);
tmp &= ~AT91_UDP_ESR;
at91_udp_write(udc, AT91_UDP_GLB_STAT, tmp);
goto succeed;
/*
* Interfaces have no feature settings; this is pretty useless.
* we won't even insist the interface exists...
*/
case ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_INTERFACE) << 8)
| USB_REQ_GET_STATUS:
PACKET("get interface status\n");
__raw_writeb(0, dreg);
__raw_writeb(0, dreg);
goto write_in;
/* then STATUS starts later, automatically */
case ((USB_TYPE_STANDARD|USB_RECIP_INTERFACE) << 8)
| USB_REQ_SET_FEATURE:
case ((USB_TYPE_STANDARD|USB_RECIP_INTERFACE) << 8)
| USB_REQ_CLEAR_FEATURE:
goto stall;
/*
* Hosts may clear bulk/intr endpoint halt after the gadget
* driver sets it (not widely used); or set it (for testing)
*/
case ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_ENDPOINT) << 8)
| USB_REQ_GET_STATUS:
tmp = w_index & USB_ENDPOINT_NUMBER_MASK;
ep = &udc->ep[tmp];
if (tmp >= NUM_ENDPOINTS || (tmp && !ep->ep.desc))
goto stall;
if (tmp) {
if ((w_index & USB_DIR_IN)) {
if (!ep->is_in)
goto stall;
} else if (ep->is_in)
goto stall;
}
PACKET("get %s status\n", ep->ep.name);
if (__raw_readl(ep->creg) & AT91_UDP_FORCESTALL)
tmp = (1 << USB_ENDPOINT_HALT);
else
tmp = 0;
__raw_writeb(tmp, dreg);
__raw_writeb(0, dreg);
goto write_in;
/* then STATUS starts later, automatically */
case ((USB_TYPE_STANDARD|USB_RECIP_ENDPOINT) << 8)
| USB_REQ_SET_FEATURE:
tmp = w_index & USB_ENDPOINT_NUMBER_MASK;
ep = &udc->ep[tmp];
if (w_value != USB_ENDPOINT_HALT || tmp >= NUM_ENDPOINTS)
goto stall;
if (!ep->ep.desc || ep->is_iso)
goto stall;
if ((w_index & USB_DIR_IN)) {
if (!ep->is_in)
goto stall;
} else if (ep->is_in)
goto stall;
tmp = __raw_readl(ep->creg);
tmp &= ~SET_FX;
tmp |= CLR_FX | AT91_UDP_FORCESTALL;
__raw_writel(tmp, ep->creg);
goto succeed;
case ((USB_TYPE_STANDARD|USB_RECIP_ENDPOINT) << 8)
| USB_REQ_CLEAR_FEATURE:
tmp = w_index & USB_ENDPOINT_NUMBER_MASK;
ep = &udc->ep[tmp];
if (w_value != USB_ENDPOINT_HALT || tmp >= NUM_ENDPOINTS)
goto stall;
if (tmp == 0)
goto succeed;
if (!ep->ep.desc || ep->is_iso)
goto stall;
if ((w_index & USB_DIR_IN)) {
if (!ep->is_in)
goto stall;
} else if (ep->is_in)
goto stall;
at91_udp_write(udc, AT91_UDP_RST_EP, ep->int_mask);
at91_udp_write(udc, AT91_UDP_RST_EP, 0);
tmp = __raw_readl(ep->creg);
tmp |= CLR_FX;
tmp &= ~(SET_FX | AT91_UDP_FORCESTALL);
__raw_writel(tmp, ep->creg);
if (!list_empty(&ep->queue))
handle_ep(ep);
goto succeed;
}
#undef w_value
#undef w_index
#undef w_length
/* pass request up to the gadget driver */
if (udc->driver) {
spin_unlock(&udc->lock);
status = udc->driver->setup(&udc->gadget, &pkt.r);
spin_lock(&udc->lock);
}
else
status = -ENODEV;
if (status < 0) {
stall:
VDBG("req %02x.%02x protocol STALL; stat %d\n",
pkt.r.bRequestType, pkt.r.bRequest, status);
csr |= AT91_UDP_FORCESTALL;
__raw_writel(csr, creg);
udc->req_pending = 0;
}
return;
succeed:
/* immediate successful (IN) STATUS after zero length DATA */
PACKET("ep0 in/status\n");
write_in:
csr |= AT91_UDP_TXPKTRDY;
__raw_writel(csr, creg);
udc->req_pending = 0;
}