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

📄 dummy_hcd.c

📁 h内核
💻 C
📖 第 1 页 / 共 3 页
字号:
				} else if (setup.bRequestType == Ep_Request) {					// endpoint halt					ep2 = find_endpoint (dum,							setup.wIndex);					if (!ep2) {						value = -EOPNOTSUPP;						break;					}					ep2->halted = 1;					value = 0;					maybe_set_status (urb, 0);				}				break;			case USB_REQ_CLEAR_FEATURE:				if (setup.bRequestType == Dev_Request) {					switch (setup.wValue) {					case USB_DEVICE_REMOTE_WAKEUP:						dum->devstatus &= ~(1 <<							USB_DEVICE_REMOTE_WAKEUP);						value = 0;						maybe_set_status (urb, 0);						break;					default:						value = -EOPNOTSUPP;						break;					}				} else if (setup.bRequestType == Ep_Request) {					// endpoint halt					ep2 = find_endpoint (dum,							setup.wIndex);					if (!ep2) {						value = -EOPNOTSUPP;						break;					}					ep2->halted = 0;					value = 0;					maybe_set_status (urb, 0);				}				break;			case USB_REQ_GET_STATUS:				if (setup.bRequestType == Dev_InRequest						|| setup.bRequestType							== Intf_InRequest						|| setup.bRequestType							== Ep_InRequest						) {					char *buf;					// device: remote wakeup, selfpowered					// interface: nothing					// endpoint: halt					buf = (char *)urb->transfer_buffer;					if (urb->transfer_buffer_length > 0) {						if (setup.bRequestType ==								Ep_InRequest) {	ep2 = find_endpoint (dum, setup.wIndex);	if (!ep2) {		value = -EOPNOTSUPP;		break;	}	buf [0] = ep2->halted;						} else if (setup.bRequestType ==								Dev_InRequest) {							buf [0] = (u8)								dum->devstatus;						} else							buf [0] = 0;					}					if (urb->transfer_buffer_length > 1)						buf [1] = 0;					urb->actual_length = min (2,						urb->transfer_buffer_length);					value = 0;					maybe_set_status (urb, 0);				}				break;			}			/* gadget driver handles all other requests.  block			 * until setup() returns; no reentrancy issues etc.			 */			if (value > 0) {				spin_unlock (&dum->lock);				value = dum->driver->setup (&dum->gadget,						&setup);				spin_lock (&dum->lock);				if (value >= 0) {					/* no delays (max 64KB data stage) */					limit = 64*1024;					goto treat_control_like_bulk;				}				/* error, see below */			}			if (value < 0) {				if (value != -EOPNOTSUPP)					dev_dbg (dummy_dev(dum),						"setup --> %d\n",						value);				maybe_set_status (urb, -EPIPE);				urb->actual_length = 0;			}			goto return_urb;		}		/* non-control requests */		limit = total;		switch (usb_pipetype (urb->pipe)) {		case PIPE_ISOCHRONOUS:			/* FIXME is it urb->interval since the last xfer?			 * use urb->iso_frame_desc[i].			 * complete whether or not ep has requests queued.			 * report random errors, to debug drivers.			 */			limit = max (limit, periodic_bytes (dum, ep));			maybe_set_status (urb, -ENOSYS);			break;		case PIPE_INTERRUPT:			/* FIXME is it urb->interval since the last xfer?			 * this almost certainly polls too fast.			 */			limit = max (limit, periodic_bytes (dum, ep));			/* FALLTHROUGH */		// case PIPE_BULK:  case PIPE_CONTROL:		default:		treat_control_like_bulk:			ep->last_io = jiffies;			total = transfer (dum, urb, ep, limit);			break;		}		/* incomplete transfer? */		if (urb->status == -EINPROGRESS)			continue;return_urb:		urb->hcpriv = NULL;		list_del (&urbp->urbp_list);		kfree (urbp);		if (ep)			ep->already_seen = ep->setup_stage = 0;		spin_unlock (&dum->lock);		usb_hcd_giveback_urb (dummy_to_hcd(dum), urb, NULL);		spin_lock (&dum->lock);		goto restart;	}	/* want a 1 msec delay here */	if (!list_empty (&dum->urbp_list))		mod_timer (&dum->timer, jiffies + msecs_to_jiffies(1));	else {		usb_put_dev (dum->udev);		dum->udev = NULL;	}	spin_unlock_irqrestore (&dum->lock, flags);}/*-------------------------------------------------------------------------*/#define PORT_C_MASK \	 ((1 << USB_PORT_FEAT_C_CONNECTION) \	| (1 << USB_PORT_FEAT_C_ENABLE) \	| (1 << USB_PORT_FEAT_C_SUSPEND) \	| (1 << USB_PORT_FEAT_C_OVER_CURRENT) \	| (1 << USB_PORT_FEAT_C_RESET))static int dummy_hub_status (struct usb_hcd *hcd, char *buf){	struct dummy		*dum;	unsigned long		flags;	int			retval;	dum = hcd_to_dummy (hcd);	spin_lock_irqsave (&dum->lock, flags);	if (!(dum->port_status & PORT_C_MASK))		retval = 0;	else {		*buf = (1 << 1);		dev_dbg (dummy_dev(dum), "port status 0x%08x has changes\n",			dum->port_status);		retval = 1;	}	spin_unlock_irqrestore (&dum->lock, flags);	return retval;}static inline voidhub_descriptor (struct usb_hub_descriptor *desc){	memset (desc, 0, sizeof *desc);	desc->bDescriptorType = 0x29;	desc->bDescLength = 9;	desc->wHubCharacteristics = __constant_cpu_to_le16 (0x0001);	desc->bNbrPorts = 1;	desc->bitmap [0] = 0xff;	desc->bitmap [1] = 0xff;}static int dummy_hub_control (	struct usb_hcd	*hcd,	u16		typeReq,	u16		wValue,	u16		wIndex,	char		*buf,	u16		wLength) {	struct dummy	*dum;	int		retval = 0;	unsigned long	flags;	dum = hcd_to_dummy (hcd);	spin_lock_irqsave (&dum->lock, flags);	switch (typeReq) {	case ClearHubFeature:		break;	case ClearPortFeature:		switch (wValue) {		case USB_PORT_FEAT_SUSPEND:			if (dum->port_status & (1 << USB_PORT_FEAT_SUSPEND)) {				/* 20msec resume signaling */				dum->resuming = 1;				dum->re_timeout = jiffies +							msecs_to_jiffies(20);			}			break;		case USB_PORT_FEAT_POWER:			dum->port_status = 0;			dum->resuming = 0;			stop_activity(dum, dum->driver);			break;		default:			dum->port_status &= ~(1 << wValue);		}		break;	case GetHubDescriptor:		hub_descriptor ((struct usb_hub_descriptor *) buf);		break;	case GetHubStatus:		*(u32 *) buf = __constant_cpu_to_le32 (0);		break;	case GetPortStatus:		if (wIndex != 1)			retval = -EPIPE;		/* whoever resets or resumes must GetPortStatus to		 * complete it!!		 */		if (dum->resuming && time_after (jiffies, dum->re_timeout)) {			dum->port_status |= (1 << USB_PORT_FEAT_C_SUSPEND);			dum->port_status &= ~(1 << USB_PORT_FEAT_SUSPEND);			dum->resuming = 0;			dum->re_timeout = 0;			if (dum->driver && dum->driver->resume) {				spin_unlock (&dum->lock);				dum->driver->resume (&dum->gadget);				spin_lock (&dum->lock);			}		}		if ((dum->port_status & (1 << USB_PORT_FEAT_RESET)) != 0				&& time_after (jiffies, dum->re_timeout)) {			dum->port_status |= (1 << USB_PORT_FEAT_C_RESET);			dum->port_status &= ~(1 << USB_PORT_FEAT_RESET);			dum->re_timeout = 0;			if (dum->driver) {				dum->port_status |= USB_PORT_STAT_ENABLE;				/* give it the best speed we agree on */				dum->gadget.speed = dum->driver->speed;				dum->gadget.ep0->maxpacket = 64;				switch (dum->gadget.speed) {				case USB_SPEED_HIGH:					dum->port_status |=						USB_PORT_STAT_HIGH_SPEED;					break;				case USB_SPEED_LOW:					dum->gadget.ep0->maxpacket = 8;					dum->port_status |=						USB_PORT_STAT_LOW_SPEED;					break;				default:					dum->gadget.speed = USB_SPEED_FULL;					break;				}			}		}		((u16 *) buf)[0] = cpu_to_le16 (dum->port_status);		((u16 *) buf)[1] = cpu_to_le16 (dum->port_status >> 16);		break;	case SetHubFeature:		retval = -EPIPE;		break;	case SetPortFeature:		switch (wValue) {		case USB_PORT_FEAT_SUSPEND:			if ((dum->port_status & (1 << USB_PORT_FEAT_SUSPEND))					== 0) {				dum->port_status |=						(1 << USB_PORT_FEAT_SUSPEND);				if (dum->driver && dum->driver->suspend) {					spin_unlock (&dum->lock);					dum->driver->suspend (&dum->gadget);					spin_lock (&dum->lock);				}			}			break;		case USB_PORT_FEAT_RESET:			/* if it's already running, disconnect first */			if (dum->port_status & USB_PORT_STAT_ENABLE) {				dum->port_status &= ~(USB_PORT_STAT_ENABLE						| USB_PORT_STAT_LOW_SPEED						| USB_PORT_STAT_HIGH_SPEED);				if (dum->driver) {					dev_dbg (dummy_dev(dum),							"disconnect\n");					stop_activity (dum, dum->driver);				}				/* FIXME test that code path! */			}			/* 50msec reset signaling */			dum->re_timeout = jiffies + msecs_to_jiffies(50);			/* FALLTHROUGH */		default:			dum->port_status |= (1 << wValue);		}		break;	default:		dev_dbg (dummy_dev(dum),			"hub control req%04x v%04x i%04x l%d\n",			typeReq, wValue, wIndex, wLength);		/* "protocol stall" on error */		retval = -EPIPE;	}	spin_unlock_irqrestore (&dum->lock, flags);	return retval;}/*-------------------------------------------------------------------------*/static inline ssize_tshow_urb (char *buf, size_t size, struct urb *urb){	int ep = usb_pipeendpoint (urb->pipe);	return snprintf (buf, size,		"urb/%p %s ep%d%s%s len %d/%d\n",		urb,		({ char *s;		 switch (urb->dev->speed) {		 case USB_SPEED_LOW:	s = "ls"; break;		 case USB_SPEED_FULL:	s = "fs"; break;		 case USB_SPEED_HIGH:	s = "hs"; break;		 default:		s = "?"; break;		 }; s; }),		ep, ep ? (usb_pipein (urb->pipe) ? "in" : "out") : "",		({ char *s; \		 switch (usb_pipetype (urb->pipe)) { \		 case PIPE_CONTROL:	s = ""; break; \		 case PIPE_BULK:	s = "-bulk"; break; \		 case PIPE_INTERRUPT:	s = "-int"; break; \		 default: 		s = "-iso"; break; \		}; s;}),		urb->actual_length, urb->transfer_buffer_length);}static ssize_tshow_urbs (struct device *dev, char *buf){	struct usb_hcd		*hcd = dev_get_drvdata (dev);	struct dummy		*dum = hcd_to_dummy (hcd);	struct urbp		*urbp;	size_t			size = 0;	unsigned long		flags;	spin_lock_irqsave (&dum->lock, flags);	list_for_each_entry (urbp, &dum->urbp_list, urbp_list) {		size_t		temp;		temp = show_urb (buf, PAGE_SIZE - size, urbp->urb);		buf += temp;		size += temp;	}	spin_unlock_irqrestore (&dum->lock, flags);	return size;}static DEVICE_ATTR (urbs, S_IRUGO, show_urbs, NULL);static int dummy_start (struct usb_hcd *hcd){	struct dummy		*dum;	struct usb_device	*root;	int			retval;	dum = hcd_to_dummy (hcd);	/*	 * MASTER side init ... we emulate a root hub that'll only ever	 * talk to one device (the slave side).  Also appears in sysfs,	 * just like more familiar pci-based HCDs.	 */	spin_lock_init (&dum->lock);	init_timer (&dum->timer);	dum->timer.function = dummy_timer;	dum->timer.data = (unsigned long) dum;	INIT_LIST_HEAD (&dum->urbp_list);	root = usb_alloc_dev (NULL, &hcd->self, 0);	if (!root)		return -ENOMEM;	/* root hub enters addressed state... */	hcd->state = USB_STATE_RUNNING;	root->speed = USB_SPEED_HIGH;	/* ...then configured, so khubd sees us. */	if ((retval = hcd_register_root (root, hcd)) != 0) {		usb_put_dev (root);clean:		hcd->state = USB_STATE_QUIESCING;		return retval;	}	/* only show a low-power port: just 8mA */	hub_set_power_budget (root, 8);	if ((retval = dummy_register_udc (dum)) != 0) {		usb_disconnect (&hcd->self.root_hub);		goto clean;	}	/* FIXME 'urbs' should be a per-device thing, maybe in usbcore */	device_create_file (dummy_dev(dum), &dev_attr_urbs);	dum->started = 1;	return 0;}static void dummy_stop (struct usb_hcd *hcd){	struct dummy		*dum;	dum = hcd_to_dummy (hcd);	if (!dum->started)		return;	dum->started = 0;	device_remove_file (dummy_dev(dum), &dev_attr_urbs);	usb_gadget_unregister_driver (dum->driver);	dummy_unregister_udc (dum);	dev_info (dummy_dev(dum), "stopped\n");}/*-------------------------------------------------------------------------*/static int dummy_h_get_frame (struct usb_hcd *hcd){	return dummy_g_get_frame (NULL);}static const struct hc_driver dummy_hcd = {	.description =		(char *) driver_name,	.product_desc =		"Dummy host controller",	.hcd_priv_size =	sizeof(struct dummy),	.flags =		HCD_USB2,	.start =		dummy_start,	.stop =			dummy_stop,	.urb_enqueue = 		dummy_urb_enqueue,	.urb_dequeue = 		dummy_urb_dequeue,	.get_frame_number = 	dummy_h_get_frame,	.hub_status_data = 	dummy_hub_status,	.hub_control = 		dummy_hub_control,};static void dummy_remove (struct device *dev);static int dummy_probe (struct device *dev){	struct usb_hcd		*hcd;	struct dummy		*dum;	int			retval;	dev_info (dev, "%s, driver " DRIVER_VERSION "\n", driver_desc);	hcd = usb_create_hcd (&dummy_hcd);	if (hcd == NULL) {		dev_dbg (dev, "hcd_alloc failed\n");		return -ENOMEM;	}	dev_set_drvdata (dev, hcd);	dum = hcd_to_dummy (hcd);	the_controller = dum;	hcd->self.controller = dev;	/* FIXME don't require the pci-based buffer/alloc impls;	 * the "generic dma" implementation still requires them,	 * it's not very generic yet.	 */	retval = hcd_buffer_create (hcd);	if (retval != 0) {		dev_dbg (dev, "pool alloc failed\n");		goto err1;	}	hcd->self.bus_name = dev->bus_id;	usb_register_bus (&hcd->self);	if ((retval = dummy_start (hcd)) < 0) 		dummy_remove (dev);	return retval;err1:	usb_put_hcd (hcd);	dev_set_drvdata (dev, NULL);	return retval;}static void dummy_remove (struct device *dev){	struct usb_hcd		*hcd;	struct dummy		*dum;	hcd = dev_get_drvdata (dev);	dum = hcd_to_dummy (hcd);	hcd->state = USB_STATE_QUIESCING;	dev_dbg (dev, "roothub graceful disconnect\n");	usb_disconnect (&hcd->self.root_hub);	hcd->driver->stop (hcd);	hcd->state = USB_STATE_HALT;	hcd_buffer_destroy (hcd);	dev_set_drvdata (dev, NULL);	usb_deregister_bus (&hcd->self);	the_controller = NULL;}/*-------------------------------------------------------------------------*/static int dummy_pdev_detect (void){	int			retval;	retval = driver_register (&dummy_driver);	if (retval < 0)		return retval;	the_pdev.name = "hc";	the_pdev.dev.driver = &dummy_driver;	the_pdev.dev.release = dummy_pdev_release;	retval = platform_device_register (&the_pdev);	if (retval < 0)		driver_unregister (&dummy_driver);	return retval;}static void dummy_pdev_remove (void){	platform_device_unregister (&the_pdev);	driver_unregister (&dummy_driver);}/*-------------------------------------------------------------------------*/static int __init init (void){	int	retval;	if (usb_disabled ())		return -ENODEV;	if ((retval = dummy_pdev_detect ()) != 0)		return retval;	if ((retval = dummy_probe (&the_pdev.dev)) != 0)		dummy_pdev_remove ();	return retval;}module_init (init);static void __exit cleanup (void){	dummy_remove (&the_pdev.dev);	dummy_pdev_remove ();}module_exit (cleanup);

⌨️ 快捷键说明

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