uvc_driver.c

来自「trident tm5600的linux驱动」· C语言 代码 · 共 2,046 行 · 第 1/4 页

C
2,046
字号
{	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;	if (udev->product != NULL)		strncpy(dev->name, udev->product, sizeof dev->name);	else		snprintf(dev->name, sizeof dev->name,			"UVC Camera (%04x:%04x)",			le16_to_cpu(udev->descriptor.idVendor),			le16_to_cpu(udev->descriptor.idProduct));	/* 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).	 *	 * Note that the reference can't be released with the lock held,	 * otherwise a AB-BA deadlock can occur with videodev_lock that	 * videodev acquires in videodev_open() and video_unregister_device().	 */	mutex_lock(&uvc_driver.open_mutex);	dev->state |= UVC_DEV_DISCONNECTED;	mutex_unlock(&uvc_driver.open_mutex);	kref_put(&dev->kref, uvc_delete);}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, int reset){	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 (reset && (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);}static int uvc_resume(struct usb_interface *intf){	return __uvc_resume(intf, 0);}#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23)static int uvc_reset_resume(struct usb_interface *intf){	return __uvc_resume(intf, 1);}#endif/* ------------------------------------------------------------------------ * 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 },	/* Microsoft Lifecam VX-7000 */	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE				| USB_DEVICE_ID_MATCH_INT_INFO,	  .idVendor		= 0x045e,	  .idProduct		= 0x0723,	  .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 },	/* Asus F9SG */	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE				| USB_DEVICE_ID_MATCH_INT_INFO,	  .idVendor		= 0x174f,	  .idProduct		= 0x8a31,	  .bInterfaceClass	= USB_CLASS_VIDEO,	  .bInterfaceSubClass	= 1,	  .bInterfaceProtocol	= 0,	  .driver_info		= UVC_QUIRK_STREAM_NO_FID },	/* Syntek (Asus U3S) */	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE				| USB_DEVICE_ID_MATCH_INT_INFO,	  .idVendor		= 0x174f,	  .idProduct		= 0x8a33,	  .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_DEV_HI				| USB_DEVICE_ID_MATCH_INT_INFO,	  .idVendor		= 0x19ab,	  .idProduct		= 0x1000,	  .bcdDevice_hi		= 0x0126,	  .bInterfaceClass	= USB_CLASS_VIDEO,	  .bInterfaceSubClass	= 1,	  .bInterfaceProtocol	= 0,	  .driver_info		= UVC_QUIRK_STATUS_INTERVAL },	/* SiGma Micro USB Web Camera */	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE				| USB_DEVICE_ID_MATCH_INT_INFO,	  .idVendor		= 0x1c4f,	  .idProduct		= 0x3000,	  .bInterfaceClass	= USB_CLASS_VIDEO,	  .bInterfaceSubClass	= 1,	  .bInterfaceProtocol	= 0,	  .driver_info		= UVC_QUIRK_PROBE_MINMAX				| UVC_QUIRK_IGNORE_SELECTOR_UNIT},	/* 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 },	/* Packard Bell OEM Webcam - Bison Electronics */	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE				| USB_DEVICE_ID_MATCH_INT_INFO,	  .idVendor		= 0x5986,	  .idProduct		= 0x0101,	  .bInterfaceClass	= USB_CLASS_VIDEO,	  .bInterfaceSubClass	= 1,	  .bInterfaceProtocol	= 0,	  .driver_info		= UVC_QUIRK_PROBE_MINMAX },	/* Acer Crystal Eye webcam - Bison Electronics */	{ .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 },	/* Compaq Presario B1200 - Bison Electronics */	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE				| USB_DEVICE_ID_MATCH_INT_INFO,	  .idVendor		= 0x5986,	  .idProduct		= 0x0104,	  .bInterfaceClass	= USB_CLASS_VIDEO,	  .bInterfaceSubClass	= 1,	  .bInterfaceProtocol	= 0,	  .driver_info		= UVC_QUIRK_PROBE_MINMAX },	/* Acer Travelmate 7720 - Bison Electronics */	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE				| USB_DEVICE_ID_MATCH_INT_INFO,	  .idVendor		= 0x5986,	  .idProduct		= 0x0105,	  .bInterfaceClass	= USB_CLASS_VIDEO,	  .bInterfaceSubClass	= 1,	  .bInterfaceProtocol	= 0,	  .driver_info		= UVC_QUIRK_PROBE_MINMAX },	/* Medion Akoya Mini E1210 - Bison Electronics */	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE				| USB_DEVICE_ID_MATCH_INT_INFO,	  .idVendor		= 0x5986,	  .idProduct		= 0x0141,	  .bInterfaceClass	= USB_CLASS_VIDEO,	  .bInterfaceSubClass	= 1,	  .bInterfaceProtocol	= 0,	  .driver_info		= UVC_QUIRK_PROBE_MINMAX },	/* Acer OrbiCam - Bison Electronics */	{ .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 },	/*  Fujitsu Amilo SI2636 - Bison Electronics */	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE				| USB_DEVICE_ID_MATCH_INT_INFO,	  .idVendor		= 0x5986,	  .idProduct		= 0x0202,	  .bInterfaceClass	= USB_CLASS_VIDEO,	  .bInterfaceSubClass	= 1,	  .bInterfaceProtocol	= 0,	  .driver_info		= UVC_QUIRK_PROBE_MINMAX },	/*  Advent 4211 - Bison Electronics */	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE				| USB_DEVICE_ID_MATCH_INT_INFO,	  .idVendor		= 0x5986,	  .idProduct		= 0x0203,	  .bInterfaceClass	= USB_CLASS_VIDEO,	  .bInterfaceSubClass	= 1,	  .bInterfaceProtocol	= 0,	  .driver_info		= UVC_QUIRK_PROBE_MINMAX },	/* Bison Electronics */	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE				| USB_DEVICE_ID_MATCH_INT_INFO,	  .idVendor		= 0x5986,	  .idProduct		= 0x0300,	  .bInterfaceClass	= USB_CLASS_VIDEO,	  .bInterfaceSubClass	= 1,	  .bInterfaceProtocol	= 0,	  .driver_info		= UVC_QUIRK_PROBE_MINMAX },	/* Clevo M570TU - Bison Electronics */	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE				| USB_DEVICE_ID_MATCH_INT_INFO,	  .idVendor		= 0x5986,	  .idProduct		= 0x0303,	  .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 = {		.name		= "uvcvideo",		.probe		= uvc_probe,		.disconnect	= uvc_disconnect,		.suspend	= uvc_suspend,		.resume		= uvc_resume,#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 23)		.reset_resume	= uvc_reset_resume,#endif		.id_table	= uvc_ids,		.supports_autosuspend = 1,	},};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_PARM_DESC(quirks, "Forced device quirks");module_param_named(trace, uvc_trace_param, uint, S_IRUGO|S_IWUSR);MODULE_PARM_DESC(trace, "Trace level bitmask");MODULE_AUTHOR(DRIVER_AUTHOR);MODULE_DESCRIPTION(DRIVER_DESC);MODULE_LICENSE("GPL");MODULE_VERSION(DRIVER_VERSION);

⌨️ 快捷键说明

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