📄 omap_udc.c
字号:
} } else { if (can_pullup(udc)) pullup_enable (udc); else pullup_disable (udc); } if (machine_is_omap_innovator()) 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()) omap_vbus_session(&udc->gadget, 0); if (udc->transceiver) (void) otg_set_peripheral(udc->transceiver, 0); 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 = 0; udc->driver = 0; 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){ switch (m) { case 3: case 0: return "6wire"; case 1: return "4wire"; case 2: return "3wire"; default: return "unknown"; }}static int proc_otg_show(struct seq_file *s){ u32 tmp; tmp = OTG_REV_REG; seq_printf(s, "OTG rev %d.%d, transceiver_ctrl %08x\n", tmp >> 4, tmp & 0xf, USB_TRANSCEIVER_CTRL_REG); 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)), trx_mode(USB1_TRX_MODE(tmp)), trx_mode(USB0_TRX_MODE(tmp)), (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);}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, 0);}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, 0);}#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. */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) epn_rxtx |= UDC_EPN_RX_DB; init_timer(&ep->timer); ep->timer.function = pio_out_timer; ep->timer.data = (unsigned long) ep; } if (addr) epn_rxtx |= UDC_EPN_RX_VALID; BUG_ON(buf & 0x07); epn_rxtx |= buf >> 3; DBG("%s addr %02x rxtx %04x maxp %d%s buf %d\n", name, addr, epn_rxtx, maxp, dbuf ? "x2" : "", buf); if (addr & USB_DIR_IN) UDC_EP_TX_REG(addr & 0xf) = epn_rxtx; else UDC_EP_RX_REG(addr) = epn_rxtx; /* next endpoint's buffer starts after this one's */ buf += maxp; if (dbuf) buf += maxp; BUG_ON(buf > 2048); /* set up driver data structures */ BUG_ON(strlen(name) >= sizeof ep->name); strlcpy(ep->name, name, sizeof ep->name); INIT_LIST_HEAD(&ep->queue); INIT_LIST_HEAD(&ep->iso); ep->bEndpointAddress = addr; ep->bmAttributes = type; ep->double_buf = dbuf; ep->udc = udc; ep->ep.name = ep->name; ep->ep.ops = &omap_ep_ops; ep->ep.maxpacket = ep->maxpacket = maxp; list_add_tail (&ep->ep.ep_list, &udc->gadget.ep_list); return buf;}static void omap_udc_release(struct device *dev){ complete(udc->done); kfree (udc); udc = 0;}static int __initomap_udc_setup(struct platform_device *odev, struct otg_transceiver *xceiv){ unsigned tmp, buf; /* abolish any previous hardware state */ UDC_SYSCON1_REG = 0; UDC_IRQ_EN_REG = 0; UDC_IRQ_SRC_REG = UDC_IRQ_SRC_MASK; UDC_DMA_IRQ_EN_REG = 0; UDC_RXDMA_CFG_REG = 0; UDC_TXDMA_CFG_REG = 0; /* UDC_PULLUP_EN gates the chip clock */ // OTG_SYSCON_1_REG |= DEV_IDLE_EN; udc = kmalloc (sizeof *udc, SLAB_KERNEL); if (!udc) return -ENOMEM; memset(udc, 0, sizeof *udc); spin_lock_init (&udc->lock); udc->gadget.ops = &omap_gadget_ops; udc->gadget.ep0 = &udc->ep[0].ep; INIT_LIST_HEAD(&udc->gadget.ep_list); INIT_LIST_HEAD(&udc->iso); udc->gadget.speed = USB_SPEED_UNKNOWN; udc->gadget.name = driver_name; device_initialize(&udc->gadget.dev); strcpy (udc->gadget.dev.bus_id, "gadget"); udc->gadget.dev.release = omap_udc_release; udc->gadget.dev.parent = &odev->dev; if (use_dma) udc->gadget.dev.dma_mask = odev->dev.dma_mask; udc->transceiver = xceiv; /* ep0 is special; put it right after the SETUP buffer */ buf = omap_ep_setup("ep0", 0, USB_ENDPOINT_XFER_CONTROL, 8 /* after SETUP */, 64 /* maxpacket */, 0); list_del_init(&udc->ep[0].ep.ep_list); /* initially disable all non-e
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -