📄 omap_udc.c
字号:
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_ISO
static irqreturn_t
omap_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 */
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 FOURBITS
static 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_unl
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -