📄 omap_udc.c
字号:
if (stat == 1) { done(ep0, req, 0); /* that may have STALLed ep0... */ UDC_EP_NUM_REG = UDC_EP_SEL|UDC_EP_DIR; UDC_CTRL_REG = UDC_CLR_EP; UDC_CTRL_REG = UDC_SET_FIFO_EN; UDC_EP_NUM_REG = UDC_EP_DIR; udc->ep0_pending = 0; } } else { /* ack status stage of IN transfer */ UDC_EP_NUM_REG = 0; if (req) done(ep0, req, 0); } } else if (stat & UDC_STALL) { UDC_CTRL_REG = UDC_CLR_HALT; UDC_EP_NUM_REG = 0; } else { UDC_EP_NUM_REG = 0; } } /* SETUP starts all control transfers */ if (irq_src & UDC_SETUP) { union u { u16 word[4]; struct usb_ctrlrequest r; } u; int status = -EINVAL; struct omap_ep *ep; /* read the (latest) SETUP message */ do { UDC_EP_NUM_REG = UDC_SETUP_SEL; /* two bytes at a time */ u.word[0] = UDC_DATA_REG; u.word[1] = UDC_DATA_REG; u.word[2] = UDC_DATA_REG; u.word[3] = UDC_DATA_REG; UDC_EP_NUM_REG = 0; } while (UDC_IRQ_SRC_REG & UDC_SETUP);#define w_value le16_to_cpup (&u.r.wValue)#define w_index le16_to_cpup (&u.r.wIndex)#define w_length le16_to_cpup (&u.r.wLength) /* Delegate almost all control requests to the gadget driver, * except for a handful of ch9 status/feature requests that * hardware doesn't autodecode _and_ the gadget API hides. */ udc->ep0_in = (u.r.bRequestType & USB_DIR_IN) != 0; udc->ep0_set_config = 0; udc->ep0_pending = 1; ep0->stopped = 0; ep0->ackwait = 0; switch (u.r.bRequest) { case USB_REQ_SET_CONFIGURATION: /* udc needs to know when ep != 0 is valid */ if (u.r.bRequestType != USB_RECIP_DEVICE) goto delegate; if (w_length != 0) goto do_stall; udc->ep0_set_config = 1; udc->ep0_reset_config = (w_value == 0); VDBG("set config %d\n", w_value); /* update udc NOW since gadget driver may start * queueing requests immediately; clear config * later if it fails the request. */ if (udc->ep0_reset_config) UDC_SYSCON2_REG = UDC_CLR_CFG; else UDC_SYSCON2_REG = UDC_DEV_CFG; update_otg(udc); goto delegate; case USB_REQ_CLEAR_FEATURE: /* clear endpoint halt */ if (u.r.bRequestType != USB_RECIP_ENDPOINT) goto delegate; if (w_value != USB_ENDPOINT_HALT || w_length != 0) goto do_stall; ep = &udc->ep[w_index & 0xf]; if (ep != ep0) { if (w_index & USB_DIR_IN) ep += 16; if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC || !ep->desc) goto do_stall; use_ep(ep, 0); UDC_CTRL_REG = udc->clr_halt; ep->ackwait = 0; if (!(ep->bEndpointAddress & USB_DIR_IN)) { UDC_CTRL_REG = UDC_SET_FIFO_EN; ep->ackwait = 1 + ep->double_buf; } /* NOTE: assumes the host behaves sanely, * only clearing real halts. Else we may * need to kill pending transfers and then * restart the queue... very messy for DMA! */ } VDBG("%s halt cleared by host\n", ep->name); goto ep0out_status_stage; case USB_REQ_SET_FEATURE: /* set endpoint halt */ if (u.r.bRequestType != USB_RECIP_ENDPOINT) goto delegate; if (w_value != USB_ENDPOINT_HALT || w_length != 0) goto do_stall; ep = &udc->ep[w_index & 0xf]; if (w_index & USB_DIR_IN) ep += 16; if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC || ep == ep0 || !ep->desc) goto do_stall; if (use_dma && ep->has_dma) { /* this has rude side-effects (aborts) and * can't really work if DMA-IN is active */ DBG("%s host set_halt, NYET \n", ep->name); goto do_stall; } use_ep(ep, 0); /* can't halt if fifo isn't empty... */ UDC_CTRL_REG = UDC_CLR_EP; UDC_CTRL_REG = UDC_SET_HALT; VDBG("%s halted by host\n", ep->name);ep0out_status_stage: status = 0; UDC_EP_NUM_REG = UDC_EP_SEL|UDC_EP_DIR; UDC_CTRL_REG = UDC_CLR_EP; UDC_CTRL_REG = UDC_SET_FIFO_EN; UDC_EP_NUM_REG = UDC_EP_DIR; udc->ep0_pending = 0; break; case USB_REQ_GET_STATUS: /* return interface status. if we were pedantic, * we'd detect non-existent interfaces, and stall. */ if (u.r.bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE)) goto delegate; /* return two zero bytes */ UDC_EP_NUM_REG = UDC_EP_SEL|UDC_EP_DIR; UDC_DATA_REG = 0; UDC_CTRL_REG = UDC_SET_FIFO_EN; UDC_EP_NUM_REG = UDC_EP_DIR; status = 0; VDBG("GET_STATUS, interface %d\n", w_index); /* next, status stage */ break; default:delegate: /* activate the ep0out fifo right away */ if (!udc->ep0_in && w_length) { UDC_EP_NUM_REG = 0; UDC_CTRL_REG = UDC_SET_FIFO_EN; } /* gadget drivers see class/vendor specific requests, * {SET,GET}_{INTERFACE,DESCRIPTOR,CONFIGURATION}, * and more */ VDBG("SETUP %02x.%02x v%04x i%04x l%04x\n", u.r.bRequestType, u.r.bRequest, w_value, w_index, w_length);#undef w_value#undef w_index#undef w_length /* The gadget driver may return an error here, * causing an immediate protocol stall. * * Else it must issue a response, either queueing a * response buffer for the DATA stage, or halting ep0 * (causing a protocol stall, not a real halt). A * zero length buffer means no DATA stage. * * It's fine to issue that response after the setup() * call returns, and this IRQ was handled. */ udc->ep0_setup = 1; spin_unlock(&udc->lock); status = udc->driver->setup (&udc->gadget, &u.r); spin_lock(&udc->lock); udc->ep0_setup = 0; } if (status < 0) {do_stall: VDBG("req %02x.%02x protocol STALL; stat %d\n", u.r.bRequestType, u.r.bRequest, status); if (udc->ep0_set_config) { if (udc->ep0_reset_config) WARN("error resetting config?\n"); else UDC_SYSCON2_REG = UDC_CLR_CFG; } UDC_SYSCON2_REG = UDC_STALL_CMD; udc->ep0_pending = 0; } }}/*-------------------------------------------------------------------------*/#define OTG_FLAGS (UDC_B_HNP_ENABLE|UDC_A_HNP_SUPPORT|UDC_A_ALT_HNP_SUPPORT)static void devstate_irq(struct omap_udc *udc, u16 irq_src){ u16 devstat, change; devstat = UDC_DEVSTAT_REG; change = devstat ^ udc->devstat; udc->devstat = devstat; if (change & (UDC_USB_RESET|UDC_ATT)) { udc_quiesce(udc); if (change & UDC_ATT) { /* driver for any external transceiver will * have called omap_vbus_session() already */ if (devstat & UDC_ATT) { udc->gadget.speed = USB_SPEED_FULL; VDBG("connect\n"); if (!udc->transceiver) pullup_enable(udc); // if (driver->connect) call it } else if (udc->gadget.speed != USB_SPEED_UNKNOWN) { udc->gadget.speed = USB_SPEED_UNKNOWN; if (!udc->transceiver) pullup_disable(udc); DBG("disconnect, gadget %s\n", udc->driver->driver.name); if (udc->driver->disconnect) { spin_unlock(&udc->lock); udc->driver->disconnect(&udc->gadget); spin_lock(&udc->lock); } } change &= ~UDC_ATT; } if (change & UDC_USB_RESET) { if (devstat & UDC_USB_RESET) { VDBG("RESET=1\n"); } else { udc->gadget.speed = USB_SPEED_FULL; INFO("USB reset done, gadget %s\n", udc->driver->driver.name); /* ep0 traffic is legal from now on */ UDC_IRQ_EN_REG = UDC_DS_CHG_IE | UDC_EP0_IE; } change &= ~UDC_USB_RESET; } } if (change & UDC_SUS) { if (udc->gadget.speed != USB_SPEED_UNKNOWN) { // FIXME tell isp1301 to suspend/resume (?) if (devstat & UDC_SUS) { VDBG("suspend\n"); update_otg(udc); /* HNP could be under way already */ if (udc->gadget.speed == USB_SPEED_FULL && udc->driver->suspend) { spin_unlock(&udc->lock); udc->driver->suspend(&udc->gadget); spin_lock(&udc->lock); } if (udc->transceiver) otg_set_suspend(udc->transceiver, 1); } else { VDBG("resume\n"); if (udc->transceiver) otg_set_suspend(udc->transceiver, 0); if (udc->gadget.speed == USB_SPEED_FULL && udc->driver->resume) { spin_unlock(&udc->lock); udc->driver->resume(&udc->gadget); spin_lock(&udc->lock); } } } change &= ~UDC_SUS; } if (!cpu_is_omap15xx() && (change & OTG_FLAGS)) { update_otg(udc); change &= ~OTG_FLAGS; } change &= ~(UDC_CFG|UDC_DEF|UDC_ADD); if (change) VDBG("devstat %03x, ignore change %03x\n", devstat, change); UDC_IRQ_SRC_REG = UDC_DS_CHG;}static irqreturn_tomap_udc_irq(int irq, void *_udc, struct pt_regs *r){ struct omap_udc *udc = _udc; u16 irq_src; irqreturn_t status = IRQ_NONE; unsigned long flags; spin_lock_irqsave(&udc->lock, flags); irq_src = UDC_IRQ_SRC_REG; /* Device state change (usb ch9 stuff) */ if (irq_src & UDC_DS_CHG) { devstate_irq(_udc, irq_src); status = IRQ_HANDLED; irq_src &= ~UDC_DS_CHG; } /* EP0 control transfers */ if (irq_src & (UDC_EP0_RX|UDC_SETUP|UDC_EP0_TX)) { ep0_irq(_udc, irq_src); status = IRQ_HANDLED; irq_src &= ~(UDC_EP0_RX|UDC_SETUP|UDC_EP0_TX); } /* DMA transfer completion */ if (use_dma && (irq_src & (UDC_TXN_DONE|UDC_RXN_CNT|UDC_RXN_EOT))) { dma_irq(_udc, irq_src); status = IRQ_HANDLED; irq_src &= ~(UDC_TXN_DONE|UDC_RXN_CNT|UDC_RXN_EOT); } irq_src &= ~(UDC_SOF|UDC_EPN_TX|UDC_EPN_RX); if (irq_src) DBG("udc_irq, unhandled %03x\n", irq_src); spin_unlock_irqrestore(&udc->lock, flags); return status;}/* workaround for seemingly-lost IRQs for RX ACKs... */#define PIO_OUT_TIMEOUT (jiffies + HZ/3)#define HALF_FULL(f) (!((f)&(UDC_NON_ISO_FIFO_FULL|UDC_NON_ISO_FIFO_EMPTY)))static void pio_out_timer(unsigned long _ep){ struct omap_ep *ep = (void *) _ep; unsigned long flags; u16 stat_flg; spin_lock_irqsave(&ep->udc->lock, flags); if (!list_empty(&ep->queue) && ep->ackwait) { use_ep(ep, 0); stat_flg = UDC_STAT_FLG_REG; if ((stat_flg & UDC_ACK) && (!(stat_flg & UDC_FIFO_EN) || (ep->double_buf && HALF_FULL(stat_flg)))) { struct omap_req *req; VDBG("%s: lose, %04x\n", ep->ep.name, stat_flg); req = container_of(ep->queue.next, struct omap_req, queue); UDC_EP_NUM_REG = ep->bEndpointAddress | UDC_EP_SEL; (void) read_fifo(ep, req); UDC_EP_NUM_REG = ep->bEndpointAddress; UDC_CTRL_REG = UDC_SET_FIFO_EN; ep->ackwait = 1 + ep->double_buf; } } mod_timer(&ep->timer, PIO_OUT_TIMEOUT); spin_unlock_irqrestore(&ep->udc->lock, flags);}static irqreturn_tomap_udc_pio_irq(int irq, void *_dev, struct pt_regs *r){ u16 epn_stat, irq_src; irqreturn_t status = IRQ_NONE; struct omap_ep *ep; int epnum; struct omap_udc *udc = _dev; struct omap_req *req; unsigned long flags; spin_lock_irqsave(&udc->lock, flags); epn_stat = UDC_EPN_STAT_REG; irq_src = UDC_IRQ_SRC_REG; /* handle OUT first, to avoid some wasteful NAKs */ if (irq_src & UDC_EPN_RX) { epnum = (epn_stat >> 8) & 0x0f; UDC_IRQ_SRC_REG = UDC_EPN_RX; status = IRQ_HANDLED; ep = &udc->ep[epnum]; ep->irqs++; UDC_EP_NUM_REG = epnum | UDC_EP_SEL; ep->fnf = 0; if ((UDC_STAT_FLG_REG & UDC_ACK)) { ep->ackwait--; if (!list_empty(&ep->queue)) { int stat; req = container_of(ep->queue.next, struct omap_req, queue); stat = read_fifo(ep, req); if (!ep->double_buf) ep->fnf = 1; } } /* min 6 clock delay before clearing EP_SEL ... */ epn_stat = UDC_EPN_STAT_REG; epn_stat = UDC_EPN_STAT_REG; UDC_EP_NUM_REG = epnum; /* enabling fifo _after_ clearing ACK, contrary to docs, * reduces lossage; timer still needed though (sigh). */ if (ep->fnf) { UDC_CTRL_REG = UDC_SET_FIFO_EN; ep->ackwait = 1 + ep->double_buf; } mod_timer(&ep->timer, PIO_OUT_TIMEOUT); } /* then IN transfers */ else if (irq_src & UDC_EPN_TX) { epnum = epn_stat & 0x0f; UDC_IRQ_SRC_REG = UDC_EPN_TX; status = IRQ_HANDLED; ep = &udc->ep[16 + epnum]; ep->irqs++; UDC_EP_NUM_REG = epnum | UDC_EP_DIR | UDC_EP_SEL; if ((UDC_STAT_FLG_REG & UDC_ACK)) { ep->ackwait = 0; if (!list_empty(&ep->queue)) { req = container_of(ep->queue.next, struct omap_req, queue); (void) write_fifo(ep, req); } } /* min 6 clock delay before clearing EP_SEL ... */ epn_stat = UDC_EPN_STAT_REG; epn_stat = UDC_EPN_STAT_REG; UDC_EP_NUM_REG = epnum | UDC_EP_DIR; /* then 6 clocks before it'd tx */ } spin_unlock_irqrestore(&udc->lock, flags); return status;}#ifdef USE_ISOstatic irqreturn_tomap_udc_iso_irq(int irq, void *_dev, struct pt_regs *r){ struct omap_udc *udc = _dev; struct omap_ep *ep; int pending = 0; unsigned long flags; spin_lock_irqsave(&udc->lock, flags); /* handle all non-DMA ISO transfers */ list_for_each_entry (ep, &udc->iso, iso) { u16 stat; struct omap_req *req; if (ep->has_dma || list_empty(&ep->queue)) continue; req = list_entry(ep->queue.next, struct omap_req, queue); use_ep(ep, UDC_EP_SEL); stat = UDC_STAT_FLG_REG; /* NOTE: like the other controller drivers, this isn't * currently reporting lost or damaged frames. */ if (ep->bEndpointAddress & USB_DIR_IN) { if (stat & UDC_MISS_IN) /* done(ep, req, -EPROTO) */; else write_fifo(ep, req); } else { int status = 0; if (stat & UDC_NO_RXPACKET) status = -EREMOTEIO; else if (stat & UDC_ISO_ERR) status = -EILSEQ; else if (stat & UDC_DATA_FLUSH) status = -ENOSR; if (status) /* done(ep, req, status) */; else read_fifo(ep, req); } deselect_ep(); /* 6 wait states before next EP */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -