musb_gadget.c
来自「omap3 linux 2.6 用nocc去除了冗余代码」· C语言 代码 · 共 1,834 行 · 第 1/4 页
C
1,834 行
* to the rest of the driver state. */static inline void __init musb_g_init_endpoints(struct musb *musb){ u8 bEnd; struct musb_hw_ep *hw_ep; unsigned count = 0; /* intialize endpoint list just once */ INIT_LIST_HEAD(&(musb->g.ep_list)); for (bEnd = 0, hw_ep = musb->aLocalEnd; bEnd < musb->bEndCount; bEnd++, hw_ep++) { if (hw_ep->bIsSharedFifo /* || !bEnd */) { init_peripheral_ep(musb, &hw_ep->ep_in, bEnd, 0); count++; } else { if (hw_ep->wMaxPacketSizeTx) { init_peripheral_ep(musb, &hw_ep->ep_in, bEnd, 1); count++; } if (hw_ep->wMaxPacketSizeRx) { init_peripheral_ep(musb, &hw_ep->ep_out, bEnd, 0); count++; } } }}/* called once during driver setup to initialize and link into * the driver model; memory is zeroed. */int __init musb_gadget_setup(struct musb *musb){ int status; /* REVISIT minor race: if (erroneously) setting up two * musb peripherals at the same time, only the bus lock * is probably held. */ if (the_gadget) return -EBUSY; the_gadget = musb; musb->g.ops = &musb_gadget_operations; musb->g.is_dualspeed = 1; musb->g.speed = USB_SPEED_UNKNOWN; /* this "gadget" abstracts/virtualizes the controller */ strcpy(musb->g.dev.bus_id, "gadget"); musb->g.dev.parent = musb->controller; musb->g.dev.dma_mask = musb->controller->dma_mask; musb->g.dev.release = musb_gadget_release; musb->g.name = musb_driver_name; if (is_otg_enabled(musb)) musb->g.is_otg = 1; musb_g_init_endpoints(musb); musb->is_active = 0; musb_platform_try_idle(musb, 0); status = device_register(&musb->g.dev); if (status != 0) the_gadget = NULL; return status;}void musb_gadget_cleanup(struct musb *musb){ if (musb != the_gadget) return; device_unregister(&musb->g.dev); the_gadget = NULL;}/* * Register the gadget driver. Used by gadget drivers when * registering themselves with the controller. * * -EINVAL something went wrong (not driver) * -EBUSY another gadget is already using the controller * -ENOMEM no memeory to perform the operation * * @param driver the gadget driver * @return <0 if error, 0 if everything is fine */int usb_gadget_register_driver(struct usb_gadget_driver *driver){ int retval; unsigned long flags; struct musb *musb = the_gadget; if (!driver || driver->speed != USB_SPEED_HIGH || !driver->bind || !driver->setup) return -EINVAL; /* driver must be initialized to support peripheral mode */ if (!musb || !(musb->board_mode == MUSB_OTG || musb->board_mode != MUSB_OTG)) { DBG(1,"%s, no dev??\n", __FUNCTION__); return -ENODEV; } DBG(3, "registering driver %s\n", driver->function); spin_lock_irqsave(&musb->Lock, flags); if (musb->pGadgetDriver) { DBG(1, "%s is already bound to %s\n", musb_driver_name, musb->pGadgetDriver->driver.name); retval = -EBUSY; } else { musb->pGadgetDriver = driver; musb->g.dev.driver = &driver->driver; driver->driver.bus = NULL; musb->softconnect = 1; retval = 0; } spin_unlock_irqrestore(&musb->Lock, flags); if (retval == 0) retval = driver->bind(&musb->g); if (retval != 0) { DBG(3, "bind to driver %s failed --> %d\n", driver->driver.name, retval); musb->pGadgetDriver = NULL; musb->g.dev.driver = NULL; } /* start peripheral and/or OTG engines */ if (retval == 0) { spin_lock_irqsave(&musb->Lock, flags); /* REVISIT always use otg_set_peripheral(), handling * issues including the root hub one below ... */ musb->xceiv.gadget = &musb->g; musb->xceiv.state = OTG_STATE_B_IDLE; musb->is_active = 1; /* FIXME this ignores the softconnect flag. Drivers are * allowed hold the peripheral inactive until for example * userspace hooks up printer hardware or DSP codecs, so * hosts only see fully functional devices. */ if (!is_otg_enabled(musb)) musb_start(musb); spin_unlock_irqrestore(&musb->Lock, flags); if (is_otg_enabled(musb)) { DBG(3, "OTG startup...\n"); /* REVISIT: funcall to other code, which also * handles power budgeting ... this way also * ensures HdrcStart is indirectly called. */ retval = usb_add_hcd(musb_to_hcd(musb), -1, 0); if (retval < 0) { DBG(1, "add_hcd failed, %d\n", retval); spin_lock_irqsave(&musb->Lock, flags); musb->xceiv.gadget = NULL; musb->xceiv.state = OTG_STATE_UNDEFINED; musb->pGadgetDriver = NULL; musb->g.dev.driver = NULL; spin_unlock_irqrestore(&musb->Lock, flags); } } } return retval;}EXPORT_SYMBOL(usb_gadget_register_driver);static voidstop_activity(struct musb *musb, struct usb_gadget_driver *driver){ int i; struct musb_hw_ep *hw_ep; /* don't disconnect if it's not connected */ if (musb->g.speed == USB_SPEED_UNKNOWN) driver = NULL; else musb->g.speed = USB_SPEED_UNKNOWN; /* deactivate the hardware */ if (musb->softconnect) { musb->softconnect = 0; musb_pullup(musb, 0); } musb_stop(musb); /* killing any outstanding requests will quiesce the driver; * then report disconnect */ if (driver) { for (i = 0, hw_ep = musb->aLocalEnd; i < musb->bEndCount; i++, hw_ep++) { MGC_SelectEnd(musb->pRegs, i); if (hw_ep->bIsSharedFifo /* || !bEnd */) { nuke(&hw_ep->ep_in, -ESHUTDOWN); } else { if (hw_ep->wMaxPacketSizeTx) nuke(&hw_ep->ep_in, -ESHUTDOWN); if (hw_ep->wMaxPacketSizeRx) nuke(&hw_ep->ep_out, -ESHUTDOWN); } } spin_unlock(&musb->Lock); driver->disconnect (&musb->g); spin_lock(&musb->Lock); }}void musb_g_stop_activity(struct musb *musb, struct usb_gadget_driver *driver){ stop_activity(musb, driver);}/* * Unregister the gadget driver. Used by gadget drivers when * unregistering themselves from the controller. * * @param driver the gadget driver to unregister */int usb_gadget_unregister_driver(struct usb_gadget_driver *driver){ unsigned long flags; int retval = 0; struct musb *musb = the_gadget; if (!driver || !driver->unbind || !musb) return -EINVAL; /* REVISIT always use otg_set_peripheral() here too; * this needs to shut down the OTG engine. */ spin_lock_irqsave(&musb->Lock, flags); musb_hnp_stop(musb); if (musb->pGadgetDriver == driver) { musb->xceiv.state = OTG_STATE_UNDEFINED; stop_activity(musb, driver); DBG(3, "unregistering driver %s\n", driver->function); spin_unlock_irqrestore(&musb->Lock, flags); driver->unbind(&musb->g); spin_lock_irqsave(&musb->Lock, flags); musb->pGadgetDriver = NULL; musb->g.dev.driver = NULL; musb->is_active = 0; musb_platform_try_idle(musb, 0); } else retval = -EINVAL; spin_unlock_irqrestore(&musb->Lock, flags); if (is_otg_enabled(musb) && retval == 0) { usb_remove_hcd(musb_to_hcd(musb)); /* FIXME we need to be able to register another * gadget driver here and have everything work; * that currently misbehaves. */ } return retval;}EXPORT_SYMBOL(usb_gadget_unregister_driver);/***********************************************************************//* lifecycle operations called through plat_uds.c */void musb_g_resume(struct musb *musb){ musb->is_suspended = 0; switch (musb->xceiv.state) { case OTG_STATE_B_IDLE: break; case OTG_STATE_B_WAIT_ACON: case OTG_STATE_B_PERIPHERAL: musb->is_active = 1; if (musb->pGadgetDriver && musb->pGadgetDriver->resume) { spin_unlock(&musb->Lock); musb->pGadgetDriver->resume(&musb->g); spin_lock(&musb->Lock); } break; default: WARN("unhandled RESUME transition (%s)\n", otg_state_string(musb)); }}/* called when SOF packets stop for 3+ msec */void musb_g_suspend(struct musb *musb){ u8 devctl; devctl = musb_readb(musb->pRegs, MGC_O_HDRC_DEVCTL); DBG(3, "devctl %02x\n", devctl); switch (musb->xceiv.state) { case OTG_STATE_B_IDLE: if ((devctl & MGC_M_DEVCTL_VBUS) == MGC_M_DEVCTL_VBUS) musb->xceiv.state = OTG_STATE_B_PERIPHERAL; break; case OTG_STATE_B_PERIPHERAL: musb->is_suspended = 1; if (musb->pGadgetDriver && musb->pGadgetDriver->suspend) { spin_unlock(&musb->Lock); musb->pGadgetDriver->suspend(&musb->g); spin_lock(&musb->Lock); } break; case OTG_STATE_A_PERIPHERAL: if (musb->pGadgetDriver && musb->pGadgetDriver->suspend) { spin_unlock(&musb->Lock); musb->pGadgetDriver->suspend(&musb->g); spin_lock(&musb->Lock); } break; default: /* REVISIT if B_HOST, clear DEVCTL.HOSTREQ; * A_PERIPHERAL may need care too */ WARN("unhandled SUSPEND transition (%s)\n", otg_state_string(musb)); }}/* Called during SRP. Caller must hold lock */void musb_g_wakeup(struct musb *musb){ musb_gadget_wakeup(&musb->g);}/* called when VBUS drops below session threshold, and in other cases */void musb_g_disconnect(struct musb *musb){ void __iomem *mregs = musb->pRegs; u8 devctl = musb_readb(mregs, MGC_O_HDRC_DEVCTL); DBG(3, "devctl %02x\n", devctl); /* clear HR */ musb_writeb(mregs, MGC_O_HDRC_DEVCTL, devctl & MGC_M_DEVCTL_SESSION); /* don't draw vbus until new b-default session */ (void) musb_gadget_vbus_draw(&musb->g, 0); musb->g.speed = USB_SPEED_UNKNOWN; if (musb->pGadgetDriver && musb->pGadgetDriver->disconnect) { spin_unlock(&musb->Lock); musb->pGadgetDriver->disconnect(&musb->g); spin_lock(&musb->Lock); } switch (musb->xceiv.state) { default: musb->xceiv.state = OTG_STATE_A_IDLE; break; case OTG_STATE_A_PERIPHERAL: musb->xceiv.state = OTG_STATE_A_WAIT_VFALL; break; case OTG_STATE_B_WAIT_ACON: case OTG_STATE_B_HOST: case OTG_STATE_B_PERIPHERAL: musb->xceiv.state = OTG_STATE_B_IDLE; break; case OTG_STATE_B_SRP_INIT: break; } musb->is_active = 0;}void musb_g_reset(struct musb *musb)__releases(musb->Lock)__acquires(musb->Lock){ void __iomem *pBase = musb->pRegs; u8 devctl = musb_readb(pBase, MGC_O_HDRC_DEVCTL); u8 power; DBG(3, "<== %s addr=%x driver '%s'\n", (devctl & MGC_M_DEVCTL_BDEVICE) ? "B-Device" : "A-Device", musb_readb(pBase, MGC_O_HDRC_FADDR), musb->pGadgetDriver ? musb->pGadgetDriver->driver.name : NULL ); /* report disconnect, if we didn't already (flushing EP state) */ if (musb->g.speed != USB_SPEED_UNKNOWN) musb_g_disconnect(musb); /* clear HR */ else if (devctl & MGC_M_DEVCTL_HR) musb_writeb(pBase, MGC_O_HDRC_DEVCTL, MGC_M_DEVCTL_SESSION); /* what speed did we negotiate? */ power = musb_readb(pBase, MGC_O_HDRC_POWER); musb->g.speed = (power & MGC_M_POWER_HSMODE) ? USB_SPEED_HIGH : USB_SPEED_FULL; /* start in USB_STATE_DEFAULT */ musb->is_active = 1; musb->is_suspended = 0; MUSB_DEV_MODE(musb); musb->bAddress = 0; musb->ep0_state = MGC_END0_STAGE_SETUP; musb->may_wakeup = 0; musb->g.b_hnp_enable = 0; musb->g.a_alt_hnp_support = 0; musb->g.a_hnp_support = 0; /* Normal reset, as B-Device; * or else after HNP, as A-Device */ if (devctl & MGC_M_DEVCTL_BDEVICE) { musb->xceiv.state = OTG_STATE_B_PERIPHERAL; musb->g.is_a_peripheral = 0; } else if (is_otg_enabled(musb)) { musb->xceiv.state = OTG_STATE_A_PERIPHERAL; musb->g.is_a_peripheral = 1; } else WARN_ON(1); /* start with default limits on VBUS power draw */ (void) musb_gadget_vbus_draw(&musb->g, is_otg_enabled(musb) ? 8 : 100);}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?