⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dummy_hcd.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 4 页
字号:
) {	char			*retval;	struct dummy_ep		*ep;	struct dummy		*dum;	ep = usb_ep_to_dummy_ep (_ep);	dum = ep_to_dummy (ep);	if (!dum->driver)		return NULL;	retval = kmalloc (bytes, mem_flags);	*dma = (dma_addr_t) retval;	return retval;}static voiddummy_free_buffer (	struct usb_ep *_ep,	void *buf,	dma_addr_t dma,	unsigned bytes) {	if (bytes)		kfree (buf);}static voidfifo_complete (struct usb_ep *ep, struct usb_request *req){}static intdummy_queue (struct usb_ep *_ep, struct usb_request *_req,		gfp_t mem_flags){	struct dummy_ep		*ep;	struct dummy_request	*req;	struct dummy		*dum;	unsigned long		flags;	req = usb_request_to_dummy_request (_req);	if (!_req || !list_empty (&req->queue) || !_req->complete)		return -EINVAL;	ep = usb_ep_to_dummy_ep (_ep);	if (!_ep || (!ep->desc && _ep->name != ep0name))		return -EINVAL;	dum = ep_to_dummy (ep);	if (!dum->driver || !is_enabled (dum))		return -ESHUTDOWN;#if 0	dev_dbg (udc_dev(dum), "ep %p queue req %p to %s, len %d buf %p\n",			ep, _req, _ep->name, _req->length, _req->buf);#endif	_req->status = -EINPROGRESS;	_req->actual = 0;	spin_lock_irqsave (&dum->lock, flags);	/* implement an emulated single-request FIFO */	if (ep->desc && (ep->desc->bEndpointAddress & USB_DIR_IN) &&			list_empty (&dum->fifo_req.queue) &&			list_empty (&ep->queue) &&			_req->length <= FIFO_SIZE) {		req = &dum->fifo_req;		req->req = *_req;		req->req.buf = dum->fifo_buf;		memcpy (dum->fifo_buf, _req->buf, _req->length);		req->req.context = dum;		req->req.complete = fifo_complete;		spin_unlock (&dum->lock);		_req->actual = _req->length;		_req->status = 0;		_req->complete (_ep, _req);		spin_lock (&dum->lock);	}	list_add_tail (&req->queue, &ep->queue);	spin_unlock_irqrestore (&dum->lock, flags);	/* real hardware would likely enable transfers here, in case	 * it'd been left NAKing.	 */	return 0;}static int dummy_dequeue (struct usb_ep *_ep, struct usb_request *_req){	struct dummy_ep		*ep;	struct dummy		*dum;	int			retval = -EINVAL;	unsigned long		flags;	struct dummy_request	*req = NULL;	if (!_ep || !_req)		return retval;	ep = usb_ep_to_dummy_ep (_ep);	dum = ep_to_dummy (ep);	if (!dum->driver)		return -ESHUTDOWN;	spin_lock_irqsave (&dum->lock, flags);	list_for_each_entry (req, &ep->queue, queue) {		if (&req->req == _req) {			list_del_init (&req->queue);			_req->status = -ECONNRESET;			retval = 0;			break;		}	}	spin_unlock_irqrestore (&dum->lock, flags);	if (retval == 0) {		dev_dbg (udc_dev(dum),				"dequeued req %p from %s, len %d buf %p\n",				req, _ep->name, _req->length, _req->buf);		_req->complete (_ep, _req);	}	return retval;}static intdummy_set_halt (struct usb_ep *_ep, int value){	struct dummy_ep		*ep;	struct dummy		*dum;	if (!_ep)		return -EINVAL;	ep = usb_ep_to_dummy_ep (_ep);	dum = ep_to_dummy (ep);	if (!dum->driver)		return -ESHUTDOWN;	if (!value)		ep->halted = 0;	else if (ep->desc && (ep->desc->bEndpointAddress & USB_DIR_IN) &&			!list_empty (&ep->queue))		return -EAGAIN;	else		ep->halted = 1;	/* FIXME clear emulated data toggle too */	return 0;}static const struct usb_ep_ops dummy_ep_ops = {	.enable		= dummy_enable,	.disable	= dummy_disable,	.alloc_request	= dummy_alloc_request,	.free_request	= dummy_free_request,	.alloc_buffer	= dummy_alloc_buffer,	.free_buffer	= dummy_free_buffer,	/* map, unmap, ... eventually hook the "generic" dma calls */	.queue		= dummy_queue,	.dequeue	= dummy_dequeue,	.set_halt	= dummy_set_halt,};/*-------------------------------------------------------------------------*//* there are both host and device side versions of this call ... */static int dummy_g_get_frame (struct usb_gadget *_gadget){	struct timeval	tv;	do_gettimeofday (&tv);	return tv.tv_usec / 1000;}static int dummy_wakeup (struct usb_gadget *_gadget){	struct dummy	*dum;	dum = gadget_to_dummy (_gadget);	if (!(dum->devstatus &	( (1 << USB_DEVICE_B_HNP_ENABLE)				| (1 << USB_DEVICE_REMOTE_WAKEUP))))		return -EINVAL;	if ((dum->port_status & USB_PORT_STAT_CONNECTION) == 0)		return -ENOLINK;	if ((dum->port_status & USB_PORT_STAT_SUSPEND) == 0 &&			 dum->rh_state != DUMMY_RH_SUSPENDED)		return -EIO;	/* FIXME: What if the root hub is suspended but the port isn't? */	/* hub notices our request, issues downstream resume, etc */	dum->resuming = 1;	dum->re_timeout = jiffies + msecs_to_jiffies(20);	mod_timer (&dummy_to_hcd (dum)->rh_timer, dum->re_timeout);	return 0;}static int dummy_set_selfpowered (struct usb_gadget *_gadget, int value){	struct dummy	*dum;	dum = gadget_to_dummy (_gadget);	if (value)		dum->devstatus |= (1 << USB_DEVICE_SELF_POWERED);	else		dum->devstatus &= ~(1 << USB_DEVICE_SELF_POWERED);	return 0;}static int dummy_pullup (struct usb_gadget *_gadget, int value){	struct dummy	*dum;	unsigned long	flags;	dum = gadget_to_dummy (_gadget);	spin_lock_irqsave (&dum->lock, flags);	dum->pullup = (value != 0);	set_link_state (dum);	spin_unlock_irqrestore (&dum->lock, flags);	usb_hcd_poll_rh_status (dummy_to_hcd (dum));	return 0;}static const struct usb_gadget_ops dummy_ops = {	.get_frame	= dummy_g_get_frame,	.wakeup		= dummy_wakeup,	.set_selfpowered = dummy_set_selfpowered,	.pullup		= dummy_pullup,};/*-------------------------------------------------------------------------*//* "function" sysfs attribute */static ssize_tshow_function (struct device *dev, struct device_attribute *attr, char *buf){	struct dummy	*dum = gadget_dev_to_dummy (dev);	if (!dum->driver || !dum->driver->function)		return 0;	return scnprintf (buf, PAGE_SIZE, "%s\n", dum->driver->function);}static DEVICE_ATTR (function, S_IRUGO, show_function, NULL);/*-------------------------------------------------------------------------*//* * Driver registration/unregistration. * * This is basically hardware-specific; there's usually only one real USB * device (not host) controller since that's how USB devices are intended * to work.  So most implementations of these api calls will rely on the * fact that only one driver will ever bind to the hardware.  But curious * hardware can be built with discrete components, so the gadget API doesn't * require that assumption. * * For this emulator, it might be convenient to create a usb slave device * for each driver that registers:  just add to a big root hub. */intusb_gadget_register_driver (struct usb_gadget_driver *driver){	struct dummy	*dum = the_controller;	int		retval, i;	if (!dum)		return -EINVAL;	if (dum->driver)		return -EBUSY;	if (!driver->bind || !driver->unbind || !driver->setup			|| driver->speed == USB_SPEED_UNKNOWN)		return -EINVAL;	/*	 * SLAVE side init ... the layer above hardware, which	 * can't enumerate without help from the driver we're binding.	 */	dum->devstatus = 0;	INIT_LIST_HEAD (&dum->gadget.ep_list);	for (i = 0; i < DUMMY_ENDPOINTS; i++) {		struct dummy_ep	*ep = &dum->ep [i];		if (!ep_name [i])			break;		ep->ep.name = ep_name [i];		ep->ep.ops = &dummy_ep_ops;		list_add_tail (&ep->ep.ep_list, &dum->gadget.ep_list);		ep->halted = ep->already_seen = ep->setup_stage = 0;		ep->ep.maxpacket = ~0;		ep->last_io = jiffies;		ep->gadget = &dum->gadget;		ep->desc = NULL;		INIT_LIST_HEAD (&ep->queue);	}	dum->gadget.ep0 = &dum->ep [0].ep;	dum->ep [0].ep.maxpacket = 64;	list_del_init (&dum->ep [0].ep.ep_list);	INIT_LIST_HEAD(&dum->fifo_req.queue);	dum->driver = driver;	dum->gadget.dev.driver = &driver->driver;	dev_dbg (udc_dev(dum), "binding gadget driver '%s'\n",			driver->driver.name);	if ((retval = driver->bind (&dum->gadget)) != 0) {		dum->driver = NULL;		dum->gadget.dev.driver = NULL;		return retval;	}	driver->driver.bus = dum->gadget.dev.parent->bus;	driver_register (&driver->driver);	device_bind_driver (&dum->gadget.dev);	/* khubd will enumerate this in a while */	spin_lock_irq (&dum->lock);	dum->pullup = 1;	set_link_state (dum);	spin_unlock_irq (&dum->lock);	usb_hcd_poll_rh_status (dummy_to_hcd (dum));	return 0;}EXPORT_SYMBOL (usb_gadget_register_driver);intusb_gadget_unregister_driver (struct usb_gadget_driver *driver){	struct dummy	*dum = the_controller;	unsigned long	flags;	if (!dum)		return -ENODEV;	if (!driver || driver != dum->driver)		return -EINVAL;	dev_dbg (udc_dev(dum), "unregister gadget driver '%s'\n",			driver->driver.name);	spin_lock_irqsave (&dum->lock, flags);	dum->pullup = 0;	set_link_state (dum);	spin_unlock_irqrestore (&dum->lock, flags);	driver->unbind (&dum->gadget);	dum->driver = NULL;	device_release_driver (&dum->gadget.dev);	driver_unregister (&driver->driver);	spin_lock_irqsave (&dum->lock, flags);	dum->pullup = 0;	set_link_state (dum);	spin_unlock_irqrestore (&dum->lock, flags);	usb_hcd_poll_rh_status (dummy_to_hcd (dum));	return 0;}EXPORT_SYMBOL (usb_gadget_unregister_driver);#undef is_enabled/* just declare this in any driver that really need it */extern int net2280_set_fifo_mode (struct usb_gadget *gadget, int mode);int net2280_set_fifo_mode (struct usb_gadget *gadget, int mode){	return -ENOSYS;}EXPORT_SYMBOL (net2280_set_fifo_mode);/* The gadget structure is stored inside the hcd structure and will be * released along with it. */static voiddummy_gadget_release (struct device *dev){#if 0		/* usb_bus_put isn't EXPORTed! */	struct dummy	*dum = gadget_dev_to_dummy (dev);	usb_bus_put (&dummy_to_hcd (dum)->self);#endif}static int dummy_udc_probe (struct platform_device *dev){	struct dummy	*dum = the_controller;	int		rc;	dum->gadget.name = gadget_name;	dum->gadget.ops = &dummy_ops;	dum->gadget.is_dualspeed = 1;	/* maybe claim OTG support, though we won't complete HNP */	dum->gadget.is_otg = (dummy_to_hcd(dum)->self.otg_port != 0);	strcpy (dum->gadget.dev.bus_id, "gadget");	dum->gadget.dev.parent = &dev->dev;	dum->gadget.dev.release = dummy_gadget_release;	rc = device_register (&dum->gadget.dev);	if (rc < 0)		return rc;#if 0		/* usb_bus_get isn't EXPORTed! */	usb_bus_get (&dummy_to_hcd (dum)->self);#endif	platform_set_drvdata (dev, dum);	device_create_file (&dum->gadget.dev, &dev_attr_function);	return rc;}static int dummy_udc_remove (struct platform_device *dev){	struct dummy	*dum = platform_get_drvdata (dev);	platform_set_drvdata (dev, NULL);	device_remove_file (&dum->gadget.dev, &dev_attr_function);	device_unregister (&dum->gadget.dev);	return 0;}static int dummy_udc_suspend (struct platform_device *dev, pm_message_t state){	struct dummy	*dum = platform_get_drvdata(dev);	dev_dbg (&dev->dev, "%s\n", __FUNCTION__);	spin_lock_irq (&dum->lock);	dum->udc_suspended = 1;	set_link_state (dum);	spin_unlock_irq (&dum->lock);	dev->dev.power.power_state = state;	usb_hcd_poll_rh_status (dummy_to_hcd (dum));	return 0;}static int dummy_udc_resume (struct platform_device *dev){	struct dummy	*dum = platform_get_drvdata(dev);	dev_dbg (&dev->dev, "%s\n", __FUNCTION__);	spin_lock_irq (&dum->lock);	dum->udc_suspended = 0;	set_link_state (dum);	spin_unlock_irq (&dum->lock);	dev->dev.power.power_state = PMSG_ON;	usb_hcd_poll_rh_status (dummy_to_hcd (dum));	return 0;}static struct platform_driver dummy_udc_driver = {	.probe		= dummy_udc_probe,	.remove		= dummy_udc_remove,	.suspend	= dummy_udc_suspend,	.resume		= dummy_udc_resume,	.driver		= {		.name	= (char *) gadget_name,		.owner	= THIS_MODULE,	},};/*-------------------------------------------------------------------------*//* MASTER/HOST SIDE DRIVER * * this uses the hcd framework to hook up to host side drivers. * its root hub will only have one device, otherwise it acts like * a normal host controller. * * when urbs are queued, they're just stuck on a list that we * scan in a timer callback.  that callback connects writes from * the host with reads from the device, and so on, based on the * usb 2.0 rules. */static int dummy_urb_enqueue (	struct usb_hcd			*hcd,	struct usb_host_endpoint	*ep,	struct urb			*urb,	gfp_t				mem_flags) {	struct dummy	*dum;	struct urbp	*urbp;	unsigned long	flags;	if (!urb->transfer_buffer && urb->transfer_buffer_length)		return -EINVAL;	urbp = kmalloc (sizeof *urbp, mem_flags);	if (!urbp)		return -ENOMEM;	urbp->urb = urb;	dum = hcd_to_dummy (hcd);	spin_lock_irqsave (&dum->lock, flags);	if (!dum->udev) {		dum->udev = urb->dev;		usb_get_dev (dum->udev);	} else if (unlikely (dum->udev != urb->dev))		dev_err (dummy_dev(dum), "usb_device address has changed!\n");

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -