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

📄 uvc_driver.c

📁 linux camera下的uvc driver驱动源码
💻 C
📖 第 1 页 / 共 4 页
字号:
	 */	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;	if (dev->udev->product != NULL)		strncpy(vdev->name, dev->udev->product, sizeof vdev->name);	else		snprintf(vdev->name, sizeof vdev->name,			"UVC Camera (%04x:%04x)",			le16_to_cpu(dev->udev->descriptor.idVendor),			le16_to_cpu(dev->udev->descriptor.idProduct));	/* 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->intf->dev;	vdev->type = 0;	vdev->type2 = 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);	usb_put_dev(dev->udev);	uvc_status_cleanup(dev);	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);		kfree(streaming->format);		kfree(streaming->header.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;	if (id->idVendor && id->idProduct)		uvc_trace(UVC_TRACE_PROBE, "Probing known UVC device %s "				"(%04x:%04x)\n", udev->devpath, id->idVendor,				id->idProduct);	else		uvc_trace(UVC_TRACE_PROBE, "Probing generic UVC device %s\n",				udev->devpath);	/* 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 = usb_get_intf(intf);	dev->intfnum = intf->cur_altsetting->desc.bInterfaceNumber;	dev->quirks = id->driver_info | uvc_quirks_param;	/* 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;	}	uvc_printk(KERN_INFO, "Found UVC %u.%02u device %s (%04x:%04x)\n",		dev->uvc_version >> 8, dev->uvc_version & 0xff,		udev->product ? udev->product : "<unnamed>",		le16_to_cpu(udev->descriptor.idVendor),		le16_to_cpu(udev->descriptor.idProduct));	if (uvc_quirks_param != 0) {		uvc_printk(KERN_INFO, "Forcing device quirks 0x%x by module "			"parameter for testing purpose.\n", uvc_quirks_param);		uvc_printk(KERN_INFO, "Please report required quirks to the "			"linux-uvc-devel mailing list.\n");	}	/* 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 ((ret = uvc_status_init(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);	/* 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);	if (intf->cur_altsetting->desc.bInterfaceSubClass == SC_VIDEOSTREAMING)		return;	/* 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);}static int uvc_suspend(struct usb_interface *intf, pm_message_t message){	struct uvc_device *dev = usb_get_intfdata(intf);	uvc_trace(UVC_TRACE_SUSPEND, "Suspending interface %u\n",		intf->cur_altsetting->desc.bInterfaceNumber);	/* Controls are cached on the fly so they don't need to be saved. */	if (intf->cur_altsetting->desc.bInterfaceSubClass == SC_VIDEOCONTROL)		return uvc_status_suspend(dev);	if (dev->video.streaming->intf != intf) {		uvc_trace(UVC_TRACE_SUSPEND, "Suspend: video streaming USB "				"interface mismatch.\n");		return -EINVAL;	}	return uvc_video_suspend(&dev->video);}static int uvc_resume(struct usb_interface *intf){	struct uvc_device *dev = usb_get_intfdata(intf);	int ret;	uvc_trace(UVC_TRACE_SUSPEND, "Resuming interface %u\n",		intf->cur_altsetting->desc.bInterfaceNumber);	if (intf->cur_altsetting->desc.bInterfaceSubClass == SC_VIDEOCONTROL) {		if ((ret = uvc_ctrl_resume_device(dev)) < 0)			return ret;		return uvc_status_resume(dev);	}	if (dev->video.streaming->intf != intf) {		uvc_trace(UVC_TRACE_SUSPEND, "Resume: video streaming USB "				"interface mismatch.\n");		return -EINVAL;	}	return uvc_video_resume(&dev->video);}/* ------------------------------------------------------------------------ * 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[] = {	/* ALi M5606 (Clevo M540SR) */	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE				| USB_DEVICE_ID_MATCH_INT_INFO,	  .idVendor		= 0x0402,	  .idProduct		= 0x5606,	  .bInterfaceClass	= USB_CLASS_VIDEO,	  .bInterfaceSubClass	= 1,	  .bInterfaceProtocol	= 0,	  .driver_info		= UVC_QUIRK_PROBE_MINMAX },	/* Creative Live! Optia */	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE				| USB_DEVICE_ID_MATCH_INT_INFO,	  .idVendor		= 0x041e,	  .idProduct		= 0x4057,	  .bInterfaceClass	= USB_CLASS_VIDEO,	  .bInterfaceSubClass	= 1,	  .bInterfaceProtocol	= 0,	  .driver_info		= UVC_QUIRK_PROBE_MINMAX },	/* Microsoft Lifecam NX-6000 */	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE				| USB_DEVICE_ID_MATCH_INT_INFO,	  .idVendor		= 0x045e,	  .idProduct		= 0x00f8,	  .bInterfaceClass	= USB_CLASS_VIDEO,	  .bInterfaceSubClass	= 1,	  .bInterfaceProtocol	= 0,	  .driver_info		= UVC_QUIRK_PROBE_MINMAX },	/* Logitech Quickcam Fusion */	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE				| USB_DEVICE_ID_MATCH_INT_INFO,	  .idVendor		= 0x046d,	  .idProduct		= 0x08c1,	  .bInterfaceClass	= USB_CLASS_VENDOR_SPEC,	  .bInterfaceSubClass	= 1,	  .bInterfaceProtocol	= 0 },	/* Logitech Quickcam Orbit MP */	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE				| USB_DEVICE_ID_MATCH_INT_INFO,	  .idVendor		= 0x046d,	  .idProduct		= 0x08c2,	  .bInterfaceClass	= USB_CLASS_VENDOR_SPEC,	  .bInterfaceSubClass	= 1,	  .bInterfaceProtocol	= 0 },	/* Logitech Quickcam Pro for Notebook */	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE				| USB_DEVICE_ID_MATCH_INT_INFO,	  .idVendor		= 0x046d,	  .idProduct		= 0x08c3,	  .bInterfaceClass	= USB_CLASS_VENDOR_SPEC,	  .bInterfaceSubClass	= 1,	  .bInterfaceProtocol	= 0 },	/* Logitech Quickcam Pro 5000 */	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE				| USB_DEVICE_ID_MATCH_INT_INFO,	  .idVendor		= 0x046d,	  .idProduct		= 0x08c5,	  .bInterfaceClass	= USB_CLASS_VENDOR_SPEC,	  .bInterfaceSubClass	= 1,	  .bInterfaceProtocol	= 0 },	/* Logitech Quickcam OEM Dell Notebook */	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE				| USB_DEVICE_ID_MATCH_INT_INFO,	  .idVendor		= 0x046d,	  .idProduct		= 0x08c6,	  .bInterfaceClass	= USB_CLASS_VENDOR_SPEC,	  .bInterfaceSubClass	= 1,	  .bInterfaceProtocol	= 0 },	/* Logitech Quickcam OEM Cisco VT Camera II */	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE				| USB_DEVICE_ID_MATCH_INT_INFO,	  .idVendor		= 0x046d,	  .idProduct		= 0x08c7,	  .bInterfaceClass	= USB_CLASS_VENDOR_SPEC,	  .bInterfaceSubClass	= 1,	  .bInterfaceProtocol	= 0 },	/* Apple Built-In iSight */	{ .match_flags          = USB_DEVICE_ID_MATCH_DEVICE				| USB_DEVICE_ID_MATCH_INT_INFO,	  .idVendor		= 0x05ac,	  .idProduct		= 0x8501,	  .bInterfaceClass      = USB_CLASS_VIDEO,	  .bInterfaceSubClass   = 1,	  .bInterfaceProtocol   = 0,	  .driver_info 		= UVC_QUIRK_PROBE_MINMAX	                        | UVC_QUIRK_BUILTIN_ISIGHT },	/* Genesys Logic USB 2.0 PC Camera */	{ .match_flags          = USB_DEVICE_ID_MATCH_DEVICE				| USB_DEVICE_ID_MATCH_INT_INFO,	  .idVendor             = 0x05e3,	  .idProduct            = 0x0505,	  .bInterfaceClass      = USB_CLASS_VIDEO,	  .bInterfaceSubClass   = 1,	  .bInterfaceProtocol   = 0,	  .driver_info          = UVC_QUIRK_STREAM_NO_FID },	/* Silicon Motion SM371 */	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE				| USB_DEVICE_ID_MATCH_INT_INFO,	  .idVendor		= 0x090c,	  .idProduct		= 0xb371,	  .bInterfaceClass	= USB_CLASS_VIDEO,	  .bInterfaceSubClass	= 1,	  .bInterfaceProtocol	= 0,	  .driver_info		= UVC_QUIRK_PROBE_MINMAX }, 	/* MT6227 */ 	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE 				| USB_DEVICE_ID_MATCH_INT_INFO, 	  .idVendor		= 0x0e8d, 	  .idProduct		= 0x0004, 	  .bInterfaceClass	= USB_CLASS_VIDEO, 	  .bInterfaceSubClass	= 1, 	  .bInterfaceProtocol	= 0, 	  .driver_info		= UVC_QUIRK_PROBE_MINMAX },	/* Syntek (HP Spartan) */	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE				| USB_DEVICE_ID_MATCH_INT_INFO,	  .idVendor		= 0x174f,	  .idProduct		= 0x5212,	  .bInterfaceClass	= USB_CLASS_VIDEO,	  .bInterfaceSubClass	= 1,	  .bInterfaceProtocol	= 0,	  .driver_info		= UVC_QUIRK_STREAM_NO_FID },	/* Ecamm Pico iMage */	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE				| USB_DEVICE_ID_MATCH_INT_INFO,	  .idVendor		= 0x18cd,	  .idProduct		= 0xcafe,	  .bInterfaceClass	= USB_CLASS_VIDEO,	  .bInterfaceSubClass	= 1,	  .bInterfaceProtocol	= 0,	  .driver_info		= UVC_QUIRK_PROBE_EXTRAFIELDS },	/* Bodelin ProScopeHR */	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE				| USB_DEVICE_ID_MATCH_INT_INFO,	  .idVendor		= 0x19ab,	  .idProduct		= 0x1000,	  .bInterfaceClass	= USB_CLASS_VIDEO,	  .bInterfaceSubClass	= 1,	  .bInterfaceProtocol	= 0,	  .driver_info		= UVC_QUIRK_STATUS_INTERVAL },	/* Acer OEM Webcam - Unknown vendor */	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE				| USB_DEVICE_ID_MATCH_INT_INFO,	  .idVendor		= 0x5986,	  .idProduct		= 0x0100,	  .bInterfaceClass	= USB_CLASS_VIDEO,	  .bInterfaceSubClass	= 1,	  .bInterfaceProtocol	= 0,	  .driver_info		= UVC_QUIRK_PROBE_MINMAX },	/* Acer Crystal Eye webcam */	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE				| USB_DEVICE_ID_MATCH_INT_INFO,	  .idVendor		= 0x5986,	  .idProduct		= 0x0102,	  .bInterfaceClass	= USB_CLASS_VIDEO,	  .bInterfaceSubClass	= 1,	  .bInterfaceProtocol	= 0,	  .driver_info		= UVC_QUIRK_PROBE_MINMAX },	/* Acer OrbiCam - Unknown vendor */	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE				| USB_DEVICE_ID_MATCH_INT_INFO,	  .idVendor		= 0x5986,	  .idProduct		= 0x0200,	  .bInterfaceClass	= USB_CLASS_VIDEO,	  .bInterfaceSubClass	= 1,	  .bInterfaceProtocol	= 0,	  .driver_info		= UVC_QUIRK_PROBE_MINMAX },	/* 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,		.suspend	= uvc_suspend,		.resume		= uvc_resume,		.id_table	= uvc_ids,#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19)		.supports_autosuspend = 1,#endif	},};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);	uvc_ctrl_init();	result = usb_register(&uvc_driver.driver);	if (result == 0)		printk(KERN_INFO DRIVER_DESC " (" DRIVER_VERSION ")\n");	return result;}static void __exit uvc_cleanup(void){	usb_deregister(&uvc_driver.driver);}module_init(uvc_init);module_exit(uvc_cleanup);module_param_named(quirks, uvc_quirks_param, uint, S_IRUGO|S_IWUSR);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 + -