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 + -
显示快捷键?