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

📄 uvc_driver.c

📁 linux camera下的uvc driver驱动源码
💻 C
📖 第 1 页 / 共 4 页
字号:
		}		frame->dwFrameInterval = *intervals;		/* Some bogus devices report dwMinFrameInterval equal to		 * dwMaxFrameInterval and have dwFrameIntervalStep set to		 * zero. Setting all null intervals to 1 fixes the problem and		 * some other divisions by zero which could happen.		 */		for (i = 0; i < n; ++i) {			interval = le32_to_cpup((__le32*)&buffer[26+4*i]);			*(*intervals)++ = interval ? interval : 1;		}		/* Make sure that the default frame interval stays between		 * the boundaries.		 */		n -= frame->bFrameIntervalType ? 1 : 2;		frame->dwDefaultFrameInterval =			min(frame->dwFrameInterval[n],			    max(frame->dwFrameInterval[0],				frame->dwDefaultFrameInterval));		uvc_trace(UVC_TRACE_DESCR, "- %ux%u (%u.%u fps)\n",			frame->wWidth, frame->wHeight,			10000000/frame->dwDefaultFrameInterval,			(100000000/frame->dwDefaultFrameInterval)%10);		format->nframes++;		buflen -= buffer[0];		buffer += buffer[0];	}	if (buflen > 2 && buffer[2] == VS_STILL_IMAGE_FRAME) {		buflen -= buffer[0];		buffer += buffer[0];	}	if (buflen > 2 && buffer[2] == VS_COLORFORMAT) {		if (buflen < 6) {			uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming"			       "interface %d COLORFORMAT error\n",			       dev->udev->devnum,			       alts->desc.bInterfaceNumber);			return -EINVAL;		}		format->colorspace = uvc_colorspace(buffer[3]);		buflen -= buffer[0];		buffer += buffer[0];	}	return buffer - start;}static int uvc_parse_streaming(struct uvc_device *dev,	struct uvc_streaming *streaming){	struct uvc_format *format;	struct uvc_frame *frame;	struct usb_interface *intf = streaming->intf;	struct usb_host_interface *alts = &intf->altsetting[0];	unsigned char *_buffer, *buffer = alts->extra;	int _buflen, buflen = alts->extralen;	unsigned int nformats = 0, nframes = 0, nintervals = 0;	unsigned int size, i, n, p;	__u32 *interval;	__u16 psize;	int ret;	/* The Pico iMage webcam has its class-specific interface descriptors	 * after the endpoint descriptors.	 */	if (buflen == 0) {		for (i = 0; i < alts->desc.bNumEndpoints; ++i) {			struct usb_host_endpoint *ep = &alts->endpoint[i];			if (ep->extralen == 0)				continue;			if (ep->extralen > 2 && ep->extra[1] == USB_DT_CS_INTERFACE) {				uvc_trace(UVC_TRACE_DESCR, "trying extra data "					"from endpoint %u.\n", i);				buffer = alts->endpoint[i].extra;				buflen = alts->endpoint[i].extralen;				break;			}		}	}	/* Skip the standard interface descriptors. */	while (buflen > 2 && buffer[1] != USB_DT_CS_INTERFACE) {		buflen -= buffer[0];		buffer += buffer[0];	}	if (buflen <= 2) {		uvc_trace(UVC_TRACE_DESCR, "no class-specific streaming "			"interface descriptors found.\n");		return -EINVAL;	}	/* Parse the header descriptor. */	if (buffer[2] == VS_OUTPUT_HEADER) {		uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming interface "			"%d OUTPUT HEADER descriptor is not supported.\n",			dev->udev->devnum, alts->desc.bInterfaceNumber);		return -EINVAL;	}	else if (buffer[2] == VS_INPUT_HEADER) {		p = buflen >= 5 ? buffer[3] : 0;		n = buflen >= 12 ? buffer[12] : 0;		if (buflen < 13 + p*n || buffer[2] != VS_INPUT_HEADER) {			uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "				"interface %d INPUT HEADER descriptor is "				"invalid.\n", dev->udev->devnum,				alts->desc.bInterfaceNumber);			return -EINVAL;		}		streaming->header.bNumFormats = p;		streaming->header.bEndpointAddress = buffer[6];		streaming->header.bmInfo = buffer[7];		streaming->header.bTerminalLink = buffer[8];		streaming->header.bStillCaptureMethod = buffer[9];		streaming->header.bTriggerSupport = buffer[10];		streaming->header.bTriggerUsage = buffer[11];		streaming->header.bControlSize = n;		streaming->header.bmaControls = kmalloc(p*n, GFP_KERNEL);		if (streaming->header.bmaControls == NULL)			return -ENOMEM;		memcpy(streaming->header.bmaControls, &buffer[13], p*n);	}	else {		uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming interface "			"%d HEADER descriptor not found.\n", dev->udev->devnum,			alts->desc.bInterfaceNumber);		return -EINVAL;	}	buflen -= buffer[0];	buffer += buffer[0];	_buffer = buffer;	_buflen = buflen;	/* Count the format and frame descriptors. */	while (_buflen > 2) {		switch (_buffer[2]) {		case VS_FORMAT_UNCOMPRESSED:		case VS_FORMAT_MJPEG:		case VS_FORMAT_FRAME_BASED:			nformats++;			break;		case VS_FORMAT_DV:			/* DV format has no frame descriptor. We will create a			 * dummy frame descriptor with a dummy frame interval.			 */			nformats++;			nframes++;			nintervals++;			break;		case VS_FORMAT_MPEG2TS:		case VS_FORMAT_STREAM_BASED:			uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "				"interface %d FORMAT %u is not supported.\n",				dev->udev->devnum,				alts->desc.bInterfaceNumber, _buffer[2]);			break;		case VS_FRAME_UNCOMPRESSED:		case VS_FRAME_MJPEG:			nframes++;			if (_buflen > 25)				nintervals += _buffer[25] ? _buffer[25] : 3;			break;		case VS_FRAME_FRAME_BASED:			nframes++;			if (_buflen > 21)				nintervals += _buffer[21] ? _buffer[21] : 3;			break;		}		_buflen -= _buffer[0];		_buffer += _buffer[0];	}	if (nformats == 0) {		uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming interface "			"%d has no supported formats defined.\n",			dev->udev->devnum, alts->desc.bInterfaceNumber);		return -EINVAL;	}	size = nformats * sizeof *format + nframes * sizeof *frame	     + nintervals * sizeof *interval;	format = kzalloc(size, GFP_KERNEL);	if (format == NULL)		return -ENOMEM;	frame = (struct uvc_frame*)&format[nformats];	interval = (__u32*)&frame[nframes];	streaming->format = format;	streaming->nformats = nformats;	/* Parse the format descriptors. */	while (buflen > 2) {		switch (buffer[2]) {		case VS_FORMAT_UNCOMPRESSED:		case VS_FORMAT_MJPEG:		case VS_FORMAT_DV:		case VS_FORMAT_FRAME_BASED:			format->frame = frame;			ret = uvc_parse_format(dev, streaming, format,				&interval, buffer, buflen);			if (ret < 0)				return ret;			frame += format->nframes;			format++;			buflen -= ret;			buffer += ret;			continue;		default:			break;		}		buflen -= buffer[0];		buffer += buffer[0];	}	/* Parse the alternate settings to find the maximum bandwidth. */	for (i = 0; i < intf->num_altsetting; ++i) {		struct usb_host_endpoint *ep;		alts = &intf->altsetting[i];		ep = uvc_find_endpoint(alts,				streaming->header.bEndpointAddress);		if (ep == NULL)			continue;		psize = le16_to_cpu(ep->desc.wMaxPacketSize);		psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3));		if (psize > streaming->maxpsize)			streaming->maxpsize = psize;	}	return 0;}/* Parse vendor-specific extensions. */static int uvc_parse_vendor_control(struct uvc_device *dev,	const unsigned char *buffer, int buflen){	struct usb_device *udev = dev->udev;	struct uvc_entity *unit;	unsigned int n, p;	int handled = 0;	switch (le16_to_cpu(dev->udev->descriptor.idVendor)) {	case 0x046d:		/* Logitech */		if (buffer[1] != 0x41 || buffer[2] != 0x01)			break;		/* Logitech implements several vendor specific functions		 * through vendor specific extension units (LXU).		 *		 * The LXU descriptors are similar to XU descriptors		 * (see "USB Device Video Class for Video Devices", section		 * 3.7.2.6 "Extension Unit Descriptor") with the following		 * differences:		 *		 * ----------------------------------------------------------		 * 0		bLength		1	 Number		 *	Size of this descriptor, in bytes: 24+p+n*2		 * ----------------------------------------------------------		 * 23+p+n	bmControlsType	N	Bitmap		 * 	Individual bits in the set are defined:		 * 	0: Absolute		 * 	1: Relative		 *		 * 	This bitset is mapped exactly the same as bmControls.		 * ----------------------------------------------------------		 * 23+p+n*2	bReserved	1	Boolean		 * ----------------------------------------------------------		 * 24+p+n*2	iExtension	1	Index		 *	Index of a string descriptor that describes this		 *	extension unit.		 * ----------------------------------------------------------		 */		p = buflen >= 22 ? buffer[21] : 0;		n = buflen >= 25 + p ? buffer[22+p] : 0;		if (buflen < 25 + p + 2*n) {			uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "			       "interface %d EXTENSION_UNIT error\n", udev->devnum,			       dev->intf->cur_altsetting->desc.bInterfaceNumber);			break;		}		unit = kzalloc(sizeof *unit + p + 2*n, GFP_KERNEL);		if (unit == NULL)			return -ENOMEM;		unit->id = buffer[3];		unit->type = VC_EXTENSION_UNIT;		memcpy(unit->extension.guidExtensionCode, &buffer[4], 16);		unit->extension.bNumControls = buffer[20];		unit->extension.bNrInPins = le16_to_cpup((const __le16*)&buffer[21]);		unit->extension.baSourceID = (__u8*)unit + sizeof *unit;		memcpy(unit->extension.baSourceID, &buffer[22], p);		unit->extension.bControlSize = buffer[22+p];		unit->extension.bmControls = (__u8*)unit + sizeof *unit + p;		unit->extension.bmControlsType = (__u8*)unit + sizeof *unit + p + n;		memcpy(unit->extension.bmControls, &buffer[23+p], 2*n);		if (buffer[24+p+2*n] != 0)			usb_string(udev, buffer[24+p+2*n], unit->name, sizeof unit->name);		else			sprintf(unit->name, "Extension %u", buffer[3]);		list_add_tail(&unit->list, &dev->entities);		handled = 1;		break;	}	return handled;}static int uvc_parse_control(struct uvc_device *dev){	struct usb_device *udev = dev->udev;	struct uvc_streaming *streaming;	struct uvc_entity *unit, *term;	struct usb_interface *intf;	struct usb_host_interface *alts = dev->intf->cur_altsetting;	unsigned char *buffer = alts->extra;	int buflen = alts->extralen;	unsigned int i, n, p, len;	__u16 type;	/* Parse the default alternate setting only, as the UVC specification	 * defines a single alternate setting, the default alternate setting	 * zero.	 */	while (buflen > 2) {		if (uvc_parse_vendor_control(dev, buffer, buflen) ||		    buffer[1] != USB_DT_CS_INTERFACE)			goto next_descriptor;		switch (buffer[2]) {		case VC_HEADER:			n = buflen >= 12 ? buffer[11] : 0;			if (buflen < 12 || buflen < 12 + n) {				uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "				       "interface %d HEADER error\n", udev->devnum,				       dev->intf->cur_altsetting->desc.bInterfaceNumber);				return -EINVAL;			}			dev->uvc_version = le16_to_cpup((__le16*)&buffer[3]);			dev->clock_frequency = le32_to_cpup((__le32*)&buffer[7]);			/* Parse all USB Video Streaming interfaces. */			for (i = 0; i < n; ++i) {				intf = usb_ifnum_to_if(udev, buffer[12+i]);				if (intf == NULL) {					uvc_trace(UVC_TRACE_DESCR, "device %d "						"interface %d doesn't exists\n",						udev->devnum, i);					continue;				}				if (intf->cur_altsetting->desc.bInterfaceSubClass					!= SC_VIDEOSTREAMING) {					uvc_trace(UVC_TRACE_DESCR, "device %d "						"interface %d isn't a video "						"streaming interface\n",						udev->devnum, i);					continue;				}				if (usb_interface_claimed(intf)) {					uvc_trace(UVC_TRACE_DESCR, "device %d "						"interface %d is already claimed\n",						udev->devnum, i);					continue;				}				usb_driver_claim_interface(&uvc_driver.driver, intf, dev);				streaming = kzalloc(sizeof *streaming, GFP_KERNEL);				if (streaming == NULL)					continue;				mutex_init(&streaming->mutex);				streaming->intf = usb_get_intf(intf);				streaming->intfnum =					intf->cur_altsetting->desc.bInterfaceNumber;				if (uvc_parse_streaming(dev, streaming) < 0) {					usb_put_intf(intf);					kfree(streaming->format);					kfree(streaming->header.bmaControls);					kfree(streaming);					continue;				}				list_add_tail(&streaming->list, &dev->streaming);			}			break;		case VC_INPUT_TERMINAL:			if (buflen < 8) {				uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "				       "interface %d INPUT_TERMINAL error\n", udev->devnum,				       dev->intf->cur_altsetting->desc.bInterfaceNumber);				return -EINVAL;			}			/* Make sure the terminal type MSB is not null, otherwise it could be			 * confused with a unit.			 */			type = le16_to_cpup((__le16*)&buffer[4]);			if ((type & 0xff00) == 0) {				uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "				       "interface %d INPUT_TERMINAL %d has invalid "				       "type 0x%04x, skipping\n", udev->devnum,				       dev->intf->cur_altsetting->desc.bInterfaceNumber,				       buffer[3], type);				continue;			}			n = 0;			p = 0;			len = 8;			if (type == ITT_CAMERA) {				n = buflen >= 15 ? buffer[14] : 0;				len = 15;			} else if (type == ITT_MEDIA_TRANSPORT_INPUT) {				n = buflen >= 9 ? buffer[8] : 0;				p = buflen >= 10 + n ? buffer[9+n] : 0;				len = 10;			}			if (buflen < len + n + p) {				uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "				       "interface %d INPUT_TERMINAL error\n", udev->devnum,				       dev->intf->cur_altsetting->desc.bInterfaceNumber);				return -EINVAL;			}			term = kzalloc(sizeof *term + n + p, GFP_KERNEL);			if (term == NULL)				return -ENOMEM;			term->id = buffer[3];			term->type = type | UVC_TERM_INPUT;			if (UVC_ENTITY_TYPE(term) == ITT_CAMERA) {				term->camera.bControlSize = n;				term->camera.bmControls = (__u8*)term + sizeof *term;				term->camera.wObjectiveFocalLengthMin = le16_to_cpup((__le16*)&buffer[8]);				term->camera.wObjectiveFocalLengthMax = le16_to_cpup((__le16*)&buffer[10]);				term->camera.wOcularFocalLength = le16_to_cpup((__le16*)&buffer[12]);				memcpy(term->camera.bmControls, &buffer[15], n);

⌨️ 快捷键说明

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