if (dir == USB_DIR_IN)
isp1760_udc_set(udc, DC_EPDIR); else
isp1760_udc_clear(udc, DC_EPDIR);
}
/** * isp1760_udc_select_ep - Select an endpoint for register access * @ep: The endpoint * @udc: Reference to the device controller * * The ISP1761 endpoint registers are banked. This function selects the target * endpoint for banked register access. The selection remains valid until the * next call to this function, the next direct access to the EPINDEX register * or the next reset, whichever comes first. * * Called with the UDC spinlock held.
*/ staticvoid isp1760_udc_select_ep(struct isp1760_udc *udc, struct isp1760_ep *ep)
{
__isp1760_udc_select_ep(udc, ep, ep->addr & USB_ENDPOINT_DIR_MASK);
}
/* Called with the UDC spinlock held. */ staticvoid isp1760_udc_ctrl_send_status(struct isp1760_ep *ep, int dir)
{ struct isp1760_udc *udc = ep->udc;
/* * Proceed to the status stage. The status stage data packet flows in * the direction opposite to the data stage data packets, we thus need * to select the OUT/IN endpoint for IN/OUT transfers.
*/ if (dir == USB_DIR_IN)
isp1760_udc_clear(udc, DC_EPDIR); else
isp1760_udc_set(udc, DC_EPDIR);
/* * The hardware will terminate the request automatically and go back to * the setup stage without notifying us.
*/
udc->ep0_state = ISP1760_CTRL_SETUP;
}
/* Called without the UDC spinlock held. */ staticvoid isp1760_udc_request_complete(struct isp1760_ep *ep, struct isp1760_request *req, int status)
{ struct isp1760_udc *udc = ep->udc; unsignedlong flags;
dev_dbg(ep->udc->isp->dev, "completing request %p with status %d\n",
req, status);
/* * When completing control OUT requests, move to the status stage after * calling the request complete callback. This gives the gadget an * opportunity to stall the control transfer if needed.
*/ if (status == 0 && ep->addr == 0 && udc->ep0_dir == USB_DIR_OUT)
isp1760_udc_ctrl_send_status(ep, USB_DIR_OUT);
/* Stall both the IN and OUT endpoints. */
__isp1760_udc_select_ep(udc, ep, USB_DIR_OUT);
isp1760_udc_set(udc, DC_STALL);
__isp1760_udc_select_ep(udc, ep, USB_DIR_IN);
isp1760_udc_set(udc, DC_STALL);
/* A protocol stall completes the control transaction. */
udc->ep0_state = ISP1760_CTRL_SETUP;
spin_unlock_irqrestore(&udc->lock, flags);
}
/* ----------------------------------------------------------------------------- * Data Endpoints
*/
/* Called with the UDC spinlock held. */ staticbool isp1760_udc_receive(struct isp1760_ep *ep, struct isp1760_request *req)
{ struct isp1760_udc *udc = ep->udc; unsignedint len;
u32 *buf; int i;
isp1760_udc_select_ep(udc, ep);
len = isp1760_udc_read(udc, DC_BUFLEN);
len = min(len, req->req.length - req->req.actual);
if (!len) { /* * There's no data to be read from the FIFO, acknowledge the RX * interrupt by clearing the buffer. * * TODO: What if another packet arrives in the meantime ? The * datasheet doesn't clearly document how this should be * handled.
*/
isp1760_udc_set(udc, DC_CLBUF); returnfalse;
}
buf = req->req.buf + req->req.actual;
/* * Make sure not to read more than one extra byte, otherwise data from * the next packet might be removed from the FIFO.
*/ for (i = len; i > 2; i -= 4, ++buf)
*buf = isp1760_udc_read_raw(udc, ISP176x_DC_DATAPORT); if (i > 0)
*(u16 *)buf = isp1760_udc_read_raw16(udc, ISP176x_DC_DATAPORT);
req->req.actual += len;
/* * TODO: The short_not_ok flag isn't supported yet, but isn't used by * any gadget driver either.
*/
/* * Complete the request if all data has been received or if a short * packet has been received.
*/ if (req->req.actual == req->req.length || len < ep->maxpacket) {
list_del(&req->queue); returntrue;
}
if (req->packet_size)
isp1760_udc_write(udc, DC_BUFLEN, req->packet_size);
/* * Make sure not to write more than one extra byte, otherwise extra data * will stay in the FIFO and will be transmitted during the next control * request. The endpoint control CLBUF bit is supposed to allow flushing * the FIFO for this kind of conditions, but doesn't seem to work.
*/ for (i = req->packet_size; i > 2; i -= 4, ++buf)
isp1760_udc_write_raw(udc, ISP176x_DC_DATAPORT, *buf); if (i > 0)
isp1760_udc_write_raw16(udc, ISP176x_DC_DATAPORT, *(u16 *)buf);
if (ep->addr == 0)
isp1760_udc_set(udc, DC_DSEN); if (!req->packet_size)
isp1760_udc_set(udc, DC_VENDP);
}
if (ep->addr == 0 && udc->ep0_state != ISP1760_CTRL_DATA_IN) {
spin_unlock(&udc->lock);
dev_dbg(udc->isp->dev, "TX IRQ: invalid endpoint state %u\n",
udc->ep0_state); return;
}
if (list_empty(&ep->queue)) { /* * This can happen for the control endpoint when the reply to * the GET_STATUS IN control request is sent directly by the * setup IRQ handler. Just proceed to the status stage.
*/ if (ep->addr == 0) {
isp1760_udc_ctrl_send_status(ep, USB_DIR_IN);
spin_unlock(&udc->lock); return;
}
spin_unlock(&udc->lock);
dev_dbg(udc->isp->dev, "%s: ep%02x has no request queued\n",
__func__, ep->addr); return;
}
/* * Complete the request if all data has been sent and we don't need to * transmit a zero length packet.
*/ if (req->req.actual == req->req.length && !need_zlp) {
complete = req;
list_del(&req->queue);
if (ep->addr == 0)
isp1760_udc_ctrl_send_status(ep, USB_DIR_IN);
/* * Transmit the next packet or start the next request, if any. * * TODO: If the endpoint is stalled the next request shouldn't be * started, but what about the next packet ?
*/ if (req)
isp1760_udc_transmit(ep, req);
spin_unlock(&udc->lock);
if (complete)
isp1760_udc_request_complete(ep, complete, 0);
}
dev_dbg(udc->isp->dev, "%s: %s halt on ep%02x\n", __func__,
halt ? "set" : "clear", ep->addr);
if (ep->desc && usb_endpoint_xfer_isoc(ep->desc)) {
dev_dbg(udc->isp->dev, "%s: ep%02x is isochronous\n", __func__,
ep->addr); return -EINVAL;
}
isp1760_udc_select_ep(udc, ep);
if (halt)
isp1760_udc_set(udc, DC_STALL); else
isp1760_udc_clear(udc, DC_STALL);
if (ep->addr == 0) { /* When halting the control endpoint, stall both IN and OUT. */
__isp1760_udc_select_ep(udc, ep, USB_DIR_IN); if (halt)
isp1760_udc_set(udc, DC_STALL); else
isp1760_udc_clear(udc, DC_STALL);
} elseif (!halt) { /* Reset the data PID by cycling the endpoint enable bit. */
isp1760_udc_clear(udc, DC_EPENABLE);
isp1760_udc_set(udc, DC_EPENABLE);
/* * Disabling the endpoint emptied the transmit FIFO, fill it * again if a request is pending. * * TODO: Does the gadget framework require synchronizatino with * the TX IRQ handler ?
*/ if ((ep->addr & USB_DIR_IN) && !list_empty(&ep->queue)) { struct isp1760_request *req;
if (udc->gadget.state != USB_STATE_DEFAULT &&
udc->gadget.state != USB_STATE_ADDRESS) {
dev_dbg(udc->isp->dev, "can't set address in state %u\n",
udc->gadget.state); return -EINVAL;
}
switch (req->bRequest) { case USB_REQ_GET_STATUS: return isp1760_udc_get_status(udc, req);
case USB_REQ_CLEAR_FEATURE: switch (req->bRequestType) { case USB_DIR_OUT | USB_RECIP_DEVICE: { /* TODO: Handle remote wakeup feature. */ returntrue;
}
case USB_DIR_OUT | USB_RECIP_ENDPOINT: {
u16 index = le16_to_cpu(req->wIndex); struct isp1760_ep *ep;
if (req->wLength != cpu_to_le16(0) ||
req->wValue != cpu_to_le16(USB_ENDPOINT_HALT)) returntrue;
ep = isp1760_udc_find_ep(udc, index); if (!ep) returntrue;
spin_lock(&udc->lock);
/* * If the endpoint is wedged only the gadget can clear * the halt feature. Pretend success in that case, but * keep the endpoint halted.
*/ if (!ep->wedged)
stall = __isp1760_udc_set_halt(ep, false); else
stall = false;
if (!stall)
isp1760_udc_ctrl_send_status(&udc->ep[0],
USB_DIR_OUT);
spin_unlock(&udc->lock); return stall;
}
default: returntrue;
} break;
case USB_REQ_SET_FEATURE: switch (req->bRequestType) { case USB_DIR_OUT | USB_RECIP_DEVICE: { /* TODO: Handle remote wakeup and test mode features */ returntrue;
}
case USB_DIR_OUT | USB_RECIP_ENDPOINT: {
u16 index = le16_to_cpu(req->wIndex); struct isp1760_ep *ep;
if (req->wLength != cpu_to_le16(0) ||
req->wValue != cpu_to_le16(USB_ENDPOINT_HALT)) returntrue;
ep = isp1760_udc_find_ep(udc, index); if (!ep) returntrue;
spin_lock(&udc->lock);
stall = __isp1760_udc_set_halt(ep, true); if (!stall)
isp1760_udc_ctrl_send_status(&udc->ep[0],
USB_DIR_OUT);
spin_unlock(&udc->lock); return stall;
}
default: returntrue;
} break;
case USB_REQ_SET_ADDRESS: if (req->bRequestType != (USB_DIR_OUT | USB_RECIP_DEVICE)) returntrue;
/* * SET_CONFIGURATION (and SET_INTERFACE) must reset the halt * feature on all endpoints. There is however no need to do so * explicitly here as the gadget driver will disable and * reenable endpoints, clearing the halt feature.
*/ returnfalse;
/* * Validate the descriptor. The control endpoint can't be enabled * manually.
*/ if (desc->bDescriptorType != USB_DT_ENDPOINT ||
desc->bEndpointAddress == 0 ||
desc->bEndpointAddress != uep->addr ||
le16_to_cpu(desc->wMaxPacketSize) > ep->maxpacket) {
dev_dbg(udc->isp->dev, "%s: invalid descriptor type %u addr %02x ep addr %02x max packet size %u/%u\n",
__func__, desc->bDescriptorType,
desc->bEndpointAddress, uep->addr,
le16_to_cpu(desc->wMaxPacketSize), ep->maxpacket); return -EINVAL;
}
switch (usb_endpoint_type(desc)) { case USB_ENDPOINT_XFER_ISOC:
type = ISP176x_DC_ENDPTYP_ISOC; break; case USB_ENDPOINT_XFER_BULK:
type = ISP176x_DC_ENDPTYP_BULK; break; case USB_ENDPOINT_XFER_INT:
type = ISP176x_DC_ENDPTYP_INTERRUPT; break; case USB_ENDPOINT_XFER_CONTROL: default:
dev_dbg(udc->isp->dev, "%s: control endpoints unsupported\n",
__func__); return -EINVAL;
}
if (!uep->addr) { /* * Halting the control endpoint is only valid as a delayed error * response to a SETUP packet. Make sure EP0 is in the right * stage and that the gadget isn't trying to clear the halt * condition.
*/ if (WARN_ON(udc->ep0_state == ISP1760_CTRL_SETUP || !stall ||
wedge)) { return -EINVAL;
}
}
if (uep->addr && !uep->desc) {
dev_dbg(udc->isp->dev, "%s: ep%02x is disabled\n", __func__,
uep->addr); return -EINVAL;
}
if (uep->addr & USB_DIR_IN) { /* Refuse to halt IN endpoints with active transfers. */ if (!list_empty(&uep->queue)) {
dev_dbg(udc->isp->dev, "%s: ep%02x has request pending\n", __func__,
uep->addr); return -EAGAIN;
}
}
ret = __isp1760_udc_set_halt(uep, stall); if (ret < 0) return ret;
if (!uep->addr) { /* * Stalling EP0 completes the control transaction, move back to * the SETUP state.
*/
udc->ep0_state = ISP1760_CTRL_SETUP; return 0;
}
if (wedge)
uep->wedged = true; elseif (!stall)
uep->wedged = false;
return 0;
}
staticint isp1760_ep_set_halt(struct usb_ep *ep, int value)
{ struct isp1760_ep *uep = ep_to_udc_ep(ep); unsignedlong flags; int ret;
dev_dbg(uep->udc->isp->dev, "%s: %s halt on ep%02x\n", __func__,
value ? "set" : "clear", uep->addr);
spin_lock_irqsave(&uep->udc->lock, flags);
ret = __isp1760_ep_set_halt(uep, value, false);
spin_unlock_irqrestore(&uep->udc->lock, flags);
/* * Set the CLBUF bit twice to flush both buffers in case double * buffering is enabled.
*/
isp1760_udc_set(udc, DC_CLBUF);
isp1760_udc_set(udc, DC_CLBUF);
/* ----------------------------------------------------------------------------- * Device States
*/
/* Called with the UDC spinlock held. */ staticvoid isp1760_udc_connect(struct isp1760_udc *udc)
{
usb_gadget_set_state(&udc->gadget, USB_STATE_POWERED);
mod_timer(&udc->vbus_timer, jiffies + ISP1760_VBUS_POLL_INTERVAL);
}
/* Called with the UDC spinlock held. */ staticvoid isp1760_udc_disconnect(struct isp1760_udc *udc)
{ if (udc->gadget.state < USB_STATE_POWERED) return;
dev_dbg(udc->isp->dev, "Device disconnected in state %u\n",
udc->gadget.state);
/* * The device controller currently shares its interrupt with the host * controller, the DC_IRQ polarity and signaling mode are ignored. Set * the to active-low level-triggered. * * Configure the control, in and out pipes to generate interrupts on * ACK tokens only (and NYET for the out pipe). The default * configuration also generates an interrupt on the first NACK token.
*/
isp1760_reg_write(udc->regs, intconf,
ISP176x_DC_CDBGMOD_ACK | ISP176x_DC_DDBGMODIN_ACK |
ISP176x_DC_DDBGMODOUT_ACK);
if (status & ISP176x_DC_IEVBUS) {
dev_dbg(udc->isp->dev, "%s(VBUS)\n", __func__); /* The VBUS interrupt is only triggered when VBUS appears. */
spin_lock(&udc->lock);
isp1760_udc_connect(udc);
spin_unlock(&udc->lock);
}
if (status & ISP176x_DC_IEBRST) {
dev_dbg(udc->isp->dev, "%s(BRST)\n", __func__);
isp1760_udc_reset(udc);
}
for (i = 0; i <= 7; ++i) { struct isp1760_ep *ep = &udc->ep[i*2];
/* * Hardcode the maximum packet sizes for now, to 64 bytes for * the control endpoint and 512 bytes for all other endpoints. * This fits in the 8kB FIFO without double-buffering.
*/ if (ep_num == 0) {
usb_ep_set_maxpacket_limit(&ep->ep, 64);
ep->ep.caps.type_control = true;
ep->ep.caps.dir_in = true;
ep->ep.caps.dir_out = true;
ep->maxpacket = 64;
udc->gadget.ep0 = &ep->ep;
} else {
usb_ep_set_maxpacket_limit(&ep->ep, 512);
ep->ep.caps.type_iso = true;
ep->ep.caps.type_bulk = true;
ep->ep.caps.type_int = true;
ep->maxpacket = 0;
list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list);
}
/* * Check that the controller is present by writing to the scratch * register, modifying the bus pattern by reading from the chip ID * register, and reading the scratch register value back. The chip ID * and scratch register contents must match the expected values.
*/
isp1760_udc_write(udc, DC_SCRATCH, 0xbabe);
chipid = isp1760_udc_read(udc, DC_CHIP_ID_HIGH) << 16;
chipid |= isp1760_udc_read(udc, DC_CHIP_ID_LOW);
scratch = isp1760_udc_read(udc, DC_SCRATCH);
if (scratch != 0xbabe) {
dev_err(udc->isp->dev, "udc: scratch test failed (0x%04x/0x%08x)\n",
scratch, chipid); return -ENODEV;
}
ret = isp1760_udc_init(udc); if (ret < 0) return ret;
udc->irqname = kasprintf(GFP_KERNEL, "%s (udc)", dev_name(isp->dev)); if (!udc->irqname) return -ENOMEM;
ret = request_irq(irq, isp1760_udc_irq, IRQF_SHARED | irqflags,
udc->irqname, udc); if (ret < 0) goto error;
udc->irq = irq;
/* * Initialize the gadget static fields and register its device. Gadget * fields that vary during the life time of the gadget are initialized * by the UDC core.
*/
udc->gadget.ops = &isp1760_udc_ops;
udc->gadget.speed = USB_SPEED_UNKNOWN;
udc->gadget.max_speed = USB_SPEED_HIGH;
udc->gadget.name = "isp1761_udc";
isp1760_udc_init_eps(udc);
ret = usb_add_gadget_udc(isp->dev, &udc->gadget); if (ret < 0) goto error;
return 0;
error: if (udc->irq >= 0)
free_irq(udc->irq, udc);
kfree(udc->irqname);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.