📄 omap_udc.c
字号:
ep->irqs++; if (!list_empty(&ep->queue)) pending = 1; } if (!pending) UDC_IRQ_EN_REG &= ~UDC_SOF_IE; UDC_IRQ_SRC_REG = UDC_SOF; spin_unlock_irqrestore(&udc->lock, flags); return IRQ_HANDLED;}#endif/*-------------------------------------------------------------------------*/static struct omap_udc *udc;int usb_gadget_register_driver (struct usb_gadget_driver *driver){ int status = -ENODEV; struct omap_ep *ep; unsigned long flags; /* basic sanity tests */ if (!udc) return -ENODEV; if (!driver // FIXME if otg, check: driver->is_otg || driver->speed < USB_SPEED_FULL || !driver->bind || !driver->unbind || !driver->setup) return -EINVAL; spin_lock_irqsave(&udc->lock, flags); if (udc->driver) { spin_unlock_irqrestore(&udc->lock, flags); return -EBUSY; } /* reset state */ list_for_each_entry (ep, &udc->gadget.ep_list, ep.ep_list) { ep->irqs = 0; if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC) continue; use_ep(ep, 0); UDC_CTRL_REG = UDC_SET_HALT; } udc->ep0_pending = 0; udc->ep[0].irqs = 0; udc->softconnect = 1; /* hook up the driver */ driver->driver.bus = NULL; udc->driver = driver; udc->gadget.dev.driver = &driver->driver; spin_unlock_irqrestore(&udc->lock, flags); status = driver->bind (&udc->gadget); if (status) { DBG("bind to %s --> %d\n", driver->driver.name, status); udc->gadget.dev.driver = NULL; udc->driver = NULL; goto done; } DBG("bound to driver %s\n", driver->driver.name); UDC_IRQ_SRC_REG = UDC_IRQ_SRC_MASK; /* connect to bus through transceiver */ if (udc->transceiver) { status = otg_set_peripheral(udc->transceiver, &udc->gadget); if (status < 0) { ERR("can't bind to transceiver\n"); driver->unbind (&udc->gadget); udc->gadget.dev.driver = NULL; udc->driver = NULL; goto done; } } else { if (can_pullup(udc)) pullup_enable (udc); else pullup_disable (udc); } /* boards that don't have VBUS sensing can't autogate 48MHz; * can't enter deep sleep while a gadget driver is active. */ if (machine_is_omap_innovator() || machine_is_omap_osk()) omap_vbus_session(&udc->gadget, 1);done: return status;}EXPORT_SYMBOL(usb_gadget_register_driver);int usb_gadget_unregister_driver (struct usb_gadget_driver *driver){ unsigned long flags; int status = -ENODEV; if (!udc) return -ENODEV; if (!driver || driver != udc->driver) return -EINVAL; if (machine_is_omap_innovator() || machine_is_omap_osk()) omap_vbus_session(&udc->gadget, 0); if (udc->transceiver) (void) otg_set_peripheral(udc->transceiver, NULL); else pullup_disable(udc); spin_lock_irqsave(&udc->lock, flags); udc_quiesce(udc); spin_unlock_irqrestore(&udc->lock, flags); driver->unbind(&udc->gadget); udc->gadget.dev.driver = NULL; udc->driver = NULL; DBG("unregistered driver '%s'\n", driver->driver.name); return status;}EXPORT_SYMBOL(usb_gadget_unregister_driver);/*-------------------------------------------------------------------------*/#ifdef CONFIG_USB_GADGET_DEBUG_FILES#include <linux/seq_file.h>static const char proc_filename[] = "driver/udc";#define FOURBITS "%s%s%s%s"#define EIGHTBITS FOURBITS FOURBITSstatic void proc_ep_show(struct seq_file *s, struct omap_ep *ep){ u16 stat_flg; struct omap_req *req; char buf[20]; use_ep(ep, 0); if (use_dma && ep->has_dma) snprintf(buf, sizeof buf, "(%cxdma%d lch%d) ", (ep->bEndpointAddress & USB_DIR_IN) ? 't' : 'r', ep->dma_channel - 1, ep->lch); else buf[0] = 0; stat_flg = UDC_STAT_FLG_REG; seq_printf(s, "\n%s %s%s%sirqs %ld stat %04x " EIGHTBITS FOURBITS "%s\n", ep->name, buf, ep->double_buf ? "dbuf " : "", ({char *s; switch(ep->ackwait){ case 0: s = ""; break; case 1: s = "(ackw) "; break; case 2: s = "(ackw2) "; break; default: s = "(?) "; break; } s;}), ep->irqs, stat_flg, (stat_flg & UDC_NO_RXPACKET) ? "no_rxpacket " : "", (stat_flg & UDC_MISS_IN) ? "miss_in " : "", (stat_flg & UDC_DATA_FLUSH) ? "data_flush " : "", (stat_flg & UDC_ISO_ERR) ? "iso_err " : "", (stat_flg & UDC_ISO_FIFO_EMPTY) ? "iso_fifo_empty " : "", (stat_flg & UDC_ISO_FIFO_FULL) ? "iso_fifo_full " : "", (stat_flg & UDC_EP_HALTED) ? "HALT " : "", (stat_flg & UDC_STALL) ? "STALL " : "", (stat_flg & UDC_NAK) ? "NAK " : "", (stat_flg & UDC_ACK) ? "ACK " : "", (stat_flg & UDC_FIFO_EN) ? "fifo_en " : "", (stat_flg & UDC_NON_ISO_FIFO_EMPTY) ? "fifo_empty " : "", (stat_flg & UDC_NON_ISO_FIFO_FULL) ? "fifo_full " : ""); if (list_empty (&ep->queue)) seq_printf(s, "\t(queue empty)\n"); else list_for_each_entry (req, &ep->queue, queue) { unsigned length = req->req.actual; if (use_dma && buf[0]) { length += ((ep->bEndpointAddress & USB_DIR_IN) ? dma_src_len : dma_dest_len) (ep, req->req.dma + length); buf[0] = 0; } seq_printf(s, "\treq %p len %d/%d buf %p\n", &req->req, length, req->req.length, req->req.buf); }}static char *trx_mode(unsigned m, int enabled){ switch (m) { case 0: return enabled ? "*6wire" : "unused"; case 1: return "4wire"; case 2: return "3wire"; case 3: return "6wire"; default: return "unknown"; }}static int proc_otg_show(struct seq_file *s){ u32 tmp; u32 trans; tmp = OTG_REV_REG; trans = USB_TRANSCEIVER_CTRL_REG; seq_printf(s, "\nOTG rev %d.%d, transceiver_ctrl %05x\n", tmp >> 4, tmp & 0xf, trans); tmp = OTG_SYSCON_1_REG; seq_printf(s, "otg_syscon1 %08x usb2 %s, usb1 %s, usb0 %s," FOURBITS "\n", tmp, trx_mode(USB2_TRX_MODE(tmp), trans & CONF_USB2_UNI_R), trx_mode(USB1_TRX_MODE(tmp), trans & CONF_USB1_UNI_R), (USB0_TRX_MODE(tmp) == 0 && !cpu_is_omap1710()) ? "internal" : trx_mode(USB0_TRX_MODE(tmp), 1), (tmp & OTG_IDLE_EN) ? " !otg" : "", (tmp & HST_IDLE_EN) ? " !host" : "", (tmp & DEV_IDLE_EN) ? " !dev" : "", (tmp & OTG_RESET_DONE) ? " reset_done" : " reset_active"); tmp = OTG_SYSCON_2_REG; seq_printf(s, "otg_syscon2 %08x%s" EIGHTBITS " b_ase_brst=%d hmc=%d\n", tmp, (tmp & OTG_EN) ? " otg_en" : "", (tmp & USBX_SYNCHRO) ? " synchro" : "", // much more SRP stuff (tmp & SRP_DATA) ? " srp_data" : "", (tmp & SRP_VBUS) ? " srp_vbus" : "", (tmp & OTG_PADEN) ? " otg_paden" : "", (tmp & HMC_PADEN) ? " hmc_paden" : "", (tmp & UHOST_EN) ? " uhost_en" : "", (tmp & HMC_TLLSPEED) ? " tllspeed" : "", (tmp & HMC_TLLATTACH) ? " tllattach" : "", B_ASE_BRST(tmp), OTG_HMC(tmp)); tmp = OTG_CTRL_REG; seq_printf(s, "otg_ctrl %06x" EIGHTBITS EIGHTBITS "%s\n", tmp, (tmp & OTG_ASESSVLD) ? " asess" : "", (tmp & OTG_BSESSEND) ? " bsess_end" : "", (tmp & OTG_BSESSVLD) ? " bsess" : "", (tmp & OTG_VBUSVLD) ? " vbus" : "", (tmp & OTG_ID) ? " id" : "", (tmp & OTG_DRIVER_SEL) ? " DEVICE" : " HOST", (tmp & OTG_A_SETB_HNPEN) ? " a_setb_hnpen" : "", (tmp & OTG_A_BUSREQ) ? " a_bus" : "", (tmp & OTG_B_HNPEN) ? " b_hnpen" : "", (tmp & OTG_B_BUSREQ) ? " b_bus" : "", (tmp & OTG_BUSDROP) ? " busdrop" : "", (tmp & OTG_PULLDOWN) ? " down" : "", (tmp & OTG_PULLUP) ? " up" : "", (tmp & OTG_DRV_VBUS) ? " drv" : "", (tmp & OTG_PD_VBUS) ? " pd_vb" : "", (tmp & OTG_PU_VBUS) ? " pu_vb" : "", (tmp & OTG_PU_ID) ? " pu_id" : "" ); tmp = OTG_IRQ_EN_REG; seq_printf(s, "otg_irq_en %04x" "\n", tmp); tmp = OTG_IRQ_SRC_REG; seq_printf(s, "otg_irq_src %04x" "\n", tmp); tmp = OTG_OUTCTRL_REG; seq_printf(s, "otg_outctrl %04x" "\n", tmp); tmp = OTG_TEST_REG; seq_printf(s, "otg_test %04x" "\n", tmp); return 0;}static int proc_udc_show(struct seq_file *s, void *_){ u32 tmp; struct omap_ep *ep; unsigned long flags; spin_lock_irqsave(&udc->lock, flags); seq_printf(s, "%s, version: " DRIVER_VERSION#ifdef USE_ISO " (iso)"#endif "%s\n", driver_desc, use_dma ? " (dma)" : ""); tmp = UDC_REV_REG & 0xff; seq_printf(s, "UDC rev %d.%d, fifo mode %d, gadget %s\n" "hmc %d, transceiver %s\n", tmp >> 4, tmp & 0xf, fifo_mode, udc->driver ? udc->driver->driver.name : "(none)", HMC, udc->transceiver ? udc->transceiver->label : "(none)"); seq_printf(s, "ULPD control %04x req %04x status %04x\n", __REG16(ULPD_CLOCK_CTRL), __REG16(ULPD_SOFT_REQ), __REG16(ULPD_STATUS_REQ)); /* OTG controller registers */ if (!cpu_is_omap15xx()) proc_otg_show(s); tmp = UDC_SYSCON1_REG; seq_printf(s, "\nsyscon1 %04x" EIGHTBITS "\n", tmp, (tmp & UDC_CFG_LOCK) ? " cfg_lock" : "", (tmp & UDC_DATA_ENDIAN) ? " data_endian" : "", (tmp & UDC_DMA_ENDIAN) ? " dma_endian" : "", (tmp & UDC_NAK_EN) ? " nak" : "", (tmp & UDC_AUTODECODE_DIS) ? " autodecode_dis" : "", (tmp & UDC_SELF_PWR) ? " self_pwr" : "", (tmp & UDC_SOFF_DIS) ? " soff_dis" : "", (tmp & UDC_PULLUP_EN) ? " PULLUP" : ""); // syscon2 is write-only /* UDC controller registers */ if (!(tmp & UDC_PULLUP_EN)) { seq_printf(s, "(suspended)\n"); spin_unlock_irqrestore(&udc->lock, flags); return 0; } tmp = UDC_DEVSTAT_REG; seq_printf(s, "devstat %04x" EIGHTBITS "%s%s\n", tmp, (tmp & UDC_B_HNP_ENABLE) ? " b_hnp" : "", (tmp & UDC_A_HNP_SUPPORT) ? " a_hnp" : "", (tmp & UDC_A_ALT_HNP_SUPPORT) ? " a_alt_hnp" : "", (tmp & UDC_R_WK_OK) ? " r_wk_ok" : "", (tmp & UDC_USB_RESET) ? " usb_reset" : "", (tmp & UDC_SUS) ? " SUS" : "", (tmp & UDC_CFG) ? " CFG" : "", (tmp & UDC_ADD) ? " ADD" : "", (tmp & UDC_DEF) ? " DEF" : "", (tmp & UDC_ATT) ? " ATT" : ""); seq_printf(s, "sof %04x\n", UDC_SOF_REG); tmp = UDC_IRQ_EN_REG; seq_printf(s, "irq_en %04x" FOURBITS "%s\n", tmp, (tmp & UDC_SOF_IE) ? " sof" : "", (tmp & UDC_EPN_RX_IE) ? " epn_rx" : "", (tmp & UDC_EPN_TX_IE) ? " epn_tx" : "", (tmp & UDC_DS_CHG_IE) ? " ds_chg" : "", (tmp & UDC_EP0_IE) ? " ep0" : ""); tmp = UDC_IRQ_SRC_REG; seq_printf(s, "irq_src %04x" EIGHTBITS "%s%s\n", tmp, (tmp & UDC_TXN_DONE) ? " txn_done" : "", (tmp & UDC_RXN_CNT) ? " rxn_cnt" : "", (tmp & UDC_RXN_EOT) ? " rxn_eot" : "", (tmp & UDC_SOF) ? " sof" : "", (tmp & UDC_EPN_RX) ? " epn_rx" : "", (tmp & UDC_EPN_TX) ? " epn_tx" : "", (tmp & UDC_DS_CHG) ? " ds_chg" : "", (tmp & UDC_SETUP) ? " setup" : "", (tmp & UDC_EP0_RX) ? " ep0out" : "", (tmp & UDC_EP0_TX) ? " ep0in" : ""); if (use_dma) { unsigned i; tmp = UDC_DMA_IRQ_EN_REG; seq_printf(s, "dma_irq_en %04x%s" EIGHTBITS "\n", tmp, (tmp & UDC_TX_DONE_IE(3)) ? " tx2_done" : "", (tmp & UDC_RX_CNT_IE(3)) ? " rx2_cnt" : "", (tmp & UDC_RX_EOT_IE(3)) ? " rx2_eot" : "", (tmp & UDC_TX_DONE_IE(2)) ? " tx1_done" : "", (tmp & UDC_RX_CNT_IE(2)) ? " rx1_cnt" : "", (tmp & UDC_RX_EOT_IE(2)) ? " rx1_eot" : "", (tmp & UDC_TX_DONE_IE(1)) ? " tx0_done" : "", (tmp & UDC_RX_CNT_IE(1)) ? " rx0_cnt" : "", (tmp & UDC_RX_EOT_IE(1)) ? " rx0_eot" : ""); tmp = UDC_RXDMA_CFG_REG; seq_printf(s, "rxdma_cfg %04x\n", tmp); if (tmp) { for (i = 0; i < 3; i++) { if ((tmp & (0x0f << (i * 4))) == 0) continue; seq_printf(s, "rxdma[%d] %04x\n", i, UDC_RXDMA_REG(i + 1)); } } tmp = UDC_TXDMA_CFG_REG; seq_printf(s, "txdma_cfg %04x\n", tmp); if (tmp) { for (i = 0; i < 3; i++) { if (!(tmp & (0x0f << (i * 4)))) continue; seq_printf(s, "txdma[%d] %04x\n", i, UDC_TXDMA_REG(i + 1)); } } } tmp = UDC_DEVSTAT_REG; if (tmp & UDC_ATT) { proc_ep_show(s, &udc->ep[0]); if (tmp & UDC_ADD) { list_for_each_entry (ep, &udc->gadget.ep_list, ep.ep_list) { if (ep->desc) proc_ep_show(s, ep); } } } spin_unlock_irqrestore(&udc->lock, flags); return 0;}static int proc_udc_open(struct inode *inode, struct file *file){ return single_open(file, proc_udc_show, NULL);}static struct file_operations proc_ops = { .open = proc_udc_open, .read = seq_read, .llseek = seq_lseek, .release = single_release,};static void create_proc_file(void){ struct proc_dir_entry *pde; pde = create_proc_entry (proc_filename, 0, NULL); if (pde) pde->proc_fops = &proc_ops;}static void remove_proc_file(void){ remove_proc_entry(proc_filename, NULL);}#elsestatic inline void create_proc_file(void) {}static inline void remove_proc_file(void) {}#endif/*-------------------------------------------------------------------------*//* Before this controller can enumerate, we need to pick an endpoint * configuration, or "fifo_mode" That involves allocating 2KB of packet * buffer space among the endpoints we'll be operating. * * NOTE: as of OMAP 1710 ES2.0, writing a new endpoint config when * UDC_SYSCON_1_REG.CFG_LOCK is set can now work. We won't use that * capability yet though. */static unsigned __initomap_ep_setup(char *name, u8 addr, u8 type, unsigned buf, unsigned maxp, int dbuf){ struct omap_ep *ep; u16 epn_rxtx = 0; /* OUT endpoints first, then IN */ ep = &udc->ep[addr & 0xf]; if (addr & USB_DIR_IN) ep += 16; /* in case of ep init table bugs */ BUG_ON(ep->name[0]); /* chip setup ... bit values are same for IN, OUT */ if (type == USB_ENDPOINT_XFER_ISOC) { switch (maxp) { case 8: epn_rxtx = 0 << 12; break; case 16: epn_rxtx = 1 << 12; break; case 32: epn_rxtx = 2 << 12; break; case 64: epn_rxtx = 3 << 12; break; case 128: epn_rxtx = 4 << 12; break; case 256: epn_rxtx = 5 << 12; break; case 512: epn_rxtx = 6 << 12; break; default: BUG(); } epn_rxtx |= UDC_EPN_RX_ISO; dbuf = 1; } else { /* double-buffering "not supported" on 15xx, * and ignored for PIO-IN on 16xx */ if (!use_dma || cpu_is_omap15xx()) dbuf = 0; switch (maxp) { case 8: epn_rxtx = 0 << 12; break; case 16: epn_rxtx = 1 << 12; break; case 32: epn_rxtx = 2 << 12; break; case 64: epn_rxtx = 3 << 12; break; default: BUG(); } if (dbuf && addr) e
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -