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

📄 uvc_driver.c

📁 LINUXvideopPREVIEW, LINUX下面打开图像的工具源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
		buflen -= buffer[0];		buffer += buffer[0];	}	/* Check if the optional status endpoint is present. */	if (alts->desc.bNumEndpoints == 1) {		struct usb_host_endpoint *ep = &alts->endpoint[0];		struct usb_endpoint_descriptor *desc = &ep->desc;		if (usb_endpoint_is_int_in(desc) &&		    le16_to_cpu(desc->wMaxPacketSize) >= 8 &&		    desc->bInterval != 0) {			uvc_trace(UVC_TRACE_DESCR, "Found a Status endpoint "				"(addr %02x).\n", desc->bEndpointAddress);			dev->int_ep = ep;		}	}	return 0;}/* ------------------------------------------------------------------------ * USB probe and disconnect *//* * Unregister the video devices. */static void uvc_unregister_video(struct uvc_device *dev){	if (dev->video.vdev) {		if (dev->video.vdev->minor == -1)			video_device_release(dev->video.vdev);		else			video_unregister_device(dev->video.vdev);		dev->video.vdev = NULL;	}}/* * Scan the UVC descriptors to locate a chain starting at an Output Terminal * and containing only a Processing Unit, optional Extension Units and an * Input Terminal. A side forward scan is made on each detected entity to * check for additional extension units. */static int uvc_scan_chain(struct uvc_video_device *video){	struct uvc_entity *entity, *forward;	unsigned int ext = 0;	int id, found;	entity = video->oterm;	uvc_trace(UVC_TRACE_PROBE, "Scanning UVC chain: OT %d", entity->id);	id = entity->output.bSourceID;	while (1) {		/* Forward scan */		forward = NULL;		found = 0;		while (1) {			forward = uvc_entity_by_reference(video->dev, id, forward);			if (forward == NULL)				break;			if (forward == entity || forward->type != VC_EXTENSION_UNIT)				continue;			if (forward->extension.bNrInPins != 1) {				uvc_trace(UVC_TRACE_DESCR, "Extension unit %d has"					"more than 1 input pin.\n", id);				return -1;			}			video->extension[ext++] = forward;			if (uvc_trace_param & UVC_TRACE_PROBE) {				if (!found)					printk(" (->");				printk(" %d", forward->id);				found = 1;			}		}		if (found)			printk(")");		/* Backward scan */		entity = uvc_entity_by_id(video->dev, id);		if (entity == NULL || !UVC_ENTITY_IS_UNIT(entity))			break;		if (uvc_trace_param & UVC_TRACE_PROBE)			printk(" <- Unit %d", entity->id);		switch (entity->type) {		case VC_EXTENSION_UNIT:			if (entity->extension.bNrInPins != 1) {				uvc_trace(UVC_TRACE_DESCR, "Extension unit %d has"					"more than 1 input pin.\n", id);				return -1;			}			video->extension[ext++] = entity;			id = entity->extension.baSourceID[0];			break;		case VC_PROCESSING_UNIT:			if (video->processing != NULL) {				uvc_trace(UVC_TRACE_DESCR, "Found multiple "					"Processing Units in chain.\n");				return -1;			}			video->processing = entity;			id = entity->processing.bSourceID;			break;		case VC_SELECTOR_UNIT:			uvc_trace(UVC_TRACE_DESCR, "Selector units are not "				"supported yet.\n");			return -1;		default:			uvc_trace(UVC_TRACE_DESCR, "Unsupported unit type "				"0x%04x found in chain.n", entity->type);			return -1;		}	}	if (entity == NULL || !UVC_ENTITY_IS_ITERM(entity)) {		uvc_trace(UVC_TRACE_DESCR, "Input terminal %d not found.\n", id);		return -1;	}	if (uvc_trace_param & UVC_TRACE_PROBE)		printk(" <- IT %d\n", entity->id);	video->iterm = entity;	/* Initialize the video buffers queue. */	uvc_queue_init(&video->queue);	return 0;}/* * Register the video devices. * * The driver currently supports a single video device per control interface * only. The terminal and units must match the following structure: * * ITT_CAMERA -> VC_PROCESSING_UNIT -> VC_EXTENSION_UNIT{0,n} -> TT_STREAMING * * The Extension Units, if present, must have a single input pin. The * Processing Unit and Extension Units can be in any order. Additional * Extension Units connected to the main chain as single-unit branches are * also supported. */static int uvc_register_video(struct uvc_device *dev){	struct video_device *vdev;	struct uvc_entity *term;	int found = 0, ret;	/* Check if the control interface matches the structure we expect. */	list_for_each_entry(term, &dev->entities, list) {		struct list_head *ps;		if (term->type != TT_STREAMING)			continue;		memset(&dev->video, 0, sizeof dev->video);		mutex_init(&dev->video.ctrl_mutex);		dev->video.oterm = term;		dev->video.dev = dev;		if (uvc_scan_chain(&dev->video) < 0)			continue;		list_for_each(ps, &dev->streaming) {			struct uvc_streaming *streaming;			streaming = list_entry(ps, struct uvc_streaming, list);			if (streaming->input.bTerminalLink == term->id) {				dev->video.streaming = streaming;				found = 1;				break;			}		}		if (found)			break;	}	if (!found) {		uvc_printk(KERN_INFO, "No valid video chain found.\n");		return -1;	}	uvc_trace(UVC_TRACE_PROBE, "Found a valid video chain (%d -> %d).\n",		dev->video.iterm->id, dev->video.oterm->id);	/* Initialize the streaming interface with default streaming	 * parameters.	 */	if ((ret = uvc_video_init(&dev->video)) < 0) {		uvc_printk(KERN_ERR, "Failed to initialize the device "			"(%d).\n", ret);		return ret;	}	/* Register the device with V4L. */	vdev = video_device_alloc();	if (vdev == NULL)		return -1;	sprintf(vdev->name, "USB Video Class");	/* We already hold a reference to dev->udev. The video device will be	 * unregistered before the reference is released, so we don't need to	 * get another one.	 */	vdev->dev = &dev->udev->dev;	vdev->type = 0;	vdev->type2 = 0;	vdev->hardware = 0;	vdev->minor = -1;	vdev->fops = &uvc_fops;	vdev->release = video_device_release;	/* Set the driver data before calling video_register_device, otherwise	 * uvc_v4l2_open might race us.	 *	 * FIXME: usb_set_intfdata hasn't been called so far. Is that a	 * 	  problem ? Does any function which could be called here get	 * 	  a pointer to the usb_interface ?	 */	dev->video.vdev = vdev;	video_set_drvdata(vdev, &dev->video);	if (video_register_device(vdev, VFL_TYPE_GRABBER, -1) < 0) {		dev->video.vdev = NULL;		video_device_release(vdev);		return -1;	}	return 0;}/* * Delete the UVC device. * * Called by the kernel when the last reference to the uvc_device structure * is released. * * Unregistering the video devices is done here because every opened instance * must be closed before the device can be unregistered. An alternative would * have been to use another reference count for uvc_v4l2_open/uvc_release, and * unregister the video devices on disconnect when that reference count drops * to zero. * * As this function is called after or during disconnect(), all URBs have * already been canceled by the USB core. There is no need to kill the * interrupt URB manually. */void uvc_delete(struct kref *kref){	struct uvc_device *dev = container_of(kref, struct uvc_device, kref);	struct list_head *p, *n;	/* Unregister the video device */	uvc_unregister_video(dev);//	usb_put_intf(dev->intf); // [wlq]	usb_put_dev(dev->udev);	uvc_ctrl_cleanup_device(dev);	list_for_each_safe(p, n, &dev->entities) {		struct uvc_entity *entity;		entity = list_entry(p, struct uvc_entity, list);		kfree(entity);	}	list_for_each_safe(p, n, &dev->streaming) {		struct uvc_streaming *streaming;		streaming = list_entry(p, struct uvc_streaming, list);//		usb_put_intf(streaming->intf); // [wlq]		kfree(streaming->format);		kfree(streaming->input.bmaControls);		kfree(streaming);	}	kfree(dev);}static int uvc_probe(struct usb_interface *intf,		     const struct usb_device_id *id){	struct usb_device *udev = interface_to_usbdev(intf);	struct uvc_device *dev;	int ret;	printk(KERN_INFO "Probing known UVC device (%04x, %04x)\n", udev->descriptor.idVendor, udev->descriptor.idProduct);	/* Allocate memory for the device and initialize it */	if ((dev = kzalloc(sizeof *dev, GFP_KERNEL)) == NULL)		return -ENOMEM;	INIT_LIST_HEAD(&dev->entities);	INIT_LIST_HEAD(&dev->streaming);	kref_init(&dev->kref);	dev->udev = usb_get_dev(udev);	dev->intf = intf; //usb_get_intf(intf); // [wlq]	dev->intfnum = intf->cur_altsetting->desc.bInterfaceNumber;	dev->quirks = id->driver_info;	/* Parse the Video Class control descriptor */	if (uvc_parse_control(dev) < 0) {		uvc_trace(UVC_TRACE_PROBE, "Unable to parse UVC descriptors.\n");		goto error;	}	/* Initialize controls */	if (uvc_ctrl_init_device(dev) < 0)		goto error;	/* Register the video devices */	if (uvc_register_video(dev) < 0)		goto error;	/* Save our data pointer in the interface data */	usb_set_intfdata(intf, dev);	/* Initialize the interrupt URB */	if (dev->int_ep != NULL && (ret = uvc_init_status(dev)) < 0) {		uvc_printk(KERN_INFO, "Unable to initialize the status "			"endpoint (%d), status interrupt will not be "			"supported.\n", ret);	}	uvc_trace(UVC_TRACE_PROBE, "UVC device initialized.\n");	return 0;error:	kref_put(&dev->kref, uvc_delete);	return -ENODEV;}static void uvc_disconnect(struct usb_interface *intf){	struct uvc_device *dev = usb_get_intfdata(intf);	if (dev == (void*)-1)		return;	/* Set the USB interface data to NULL. This can be done outside the	 * lock, as there's no other reader.	 */	usb_set_intfdata(intf, NULL);	/* uvc_v4l2_open() might race uvc_disconnect(). A static driver-wide	 * lock is needed to prevent uvc_disconnect from releasing its	 * reference to the uvc_device instance after uvc_v4l2_open() received	 * the pointer to the device (video_devdata) but before it got the	 * chance to increase the reference count (kref_get). An alternative	 * (used by the usb-skeleton driver) would have been to use the big	 * kernel lock instead of a driver-specific mutex (open calls on	 * char devices are protected by the BKL), but that approach is not	 * recommended for new code.	 */	mutex_lock(&uvc_driver.open_mutex);	dev->state |= UVC_DEV_DISCONNECTED;	kref_put(&dev->kref, uvc_delete);	mutex_unlock(&uvc_driver.open_mutex);}/* ------------------------------------------------------------------------ * Driver initialization and cleanup *//* * The Logitech cameras listed below have their interface class set to * VENDOR_SPEC because they don't announce themselves as UVC devices, even * though they are compliant. */static struct usb_device_id uvc_ids[] = {	/* Generic USB Video Class */	{ USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, 0) },	{}};MODULE_DEVICE_TABLE(usb, uvc_ids);struct uvc_driver uvc_driver = {	.driver = {#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16)		.owner		= THIS_MODULE,#endif		.name		= "uvcvideo",		.probe		= uvc_probe,		.disconnect	= uvc_disconnect,		.id_table	= uvc_ids,	},};static int __init uvc_init(void){	int result;	INIT_LIST_HEAD(&uvc_driver.devices);	INIT_LIST_HEAD(&uvc_driver.controls);	mutex_init(&uvc_driver.open_mutex);	mutex_init(&uvc_driver.ctrl_mutex);	printk(KERN_INFO "trace = %d\n", uvc_trace_param);	uvc_ctrl_init();	result = usb_register(&uvc_driver.driver);	if (result == 0)		printk(KERN_INFO DRIVER_DESC " (v" DRIVER_VERSION ")\n");	return result;}static void __exit uvc_cleanup(void){	usb_deregister(&uvc_driver.driver);}module_init(uvc_init);module_exit(uvc_cleanup);unsigned int uvc_trace_param = 0;module_param_named(trace, uvc_trace_param, uint, S_IRUGO|S_IWUSR);MODULE_AUTHOR(DRIVER_AUTHOR);MODULE_DESCRIPTION(DRIVER_DESC);MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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