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

📄 uvc_driver.c

📁 linux camera下的uvc driver驱动源码
💻 C
📖 第 1 页 / 共 4 页
字号:
			} else if (UVC_ENTITY_TYPE(term) == ITT_MEDIA_TRANSPORT_INPUT) {				term->media.bControlSize = n;				term->media.bmControls = (__u8*)term + sizeof *term;				term->media.bTransportModeSize = p;				term->media.bmTransportModes = (__u8*)term + sizeof *term + n;				memcpy(term->media.bmControls, &buffer[9], n);				memcpy(term->media.bmTransportModes, &buffer[10+n], p);			}			if (buffer[7] != 0)				usb_string(udev, buffer[7], term->name, sizeof term->name);			else if (UVC_ENTITY_TYPE(term) == ITT_CAMERA)				sprintf(term->name, "Camera %u", buffer[3]);			else if (UVC_ENTITY_TYPE(term) == ITT_MEDIA_TRANSPORT_INPUT)				sprintf(term->name, "Media %u", buffer[3]);			else				sprintf(term->name, "Input %u", buffer[3]);			list_add_tail(&term->list, &dev->entities);			break;		case VC_OUTPUT_TERMINAL:			if (buflen < 9) {				uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "				       "interface %d OUTPUT_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 OUTPUT_TERMINAL %d has invalid "				       "type 0x%04x, skipping\n", udev->devnum,				       dev->intf->cur_altsetting->desc.bInterfaceNumber,				       buffer[3], type);				continue;			}			term = kzalloc(sizeof *term, GFP_KERNEL);			if (term == NULL)				return -ENOMEM;			term->id = buffer[3];			term->type = type | UVC_TERM_OUTPUT;			term->output.bSourceID = buffer[7];			if (buffer[8] != 0)				usb_string(udev, buffer[8], term->name, sizeof term->name);			else				sprintf(term->name, "Output %u", buffer[3]);			list_add_tail(&term->list, &dev->entities);			break;		case VC_SELECTOR_UNIT:			p = buflen >= 5 ? buffer[4] : 0;			if (buflen < 5 || buflen < 6 + p) {				uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "				       "interface %d SELECTOR_UNIT error\n", udev->devnum,				       dev->intf->cur_altsetting->desc.bInterfaceNumber);				return -EINVAL;			}			unit = kzalloc(sizeof *unit + p, GFP_KERNEL);			if (unit == NULL)				return -ENOMEM;			unit->id = buffer[3];			unit->type = buffer[2];			unit->selector.bNrInPins = buffer[4];			unit->selector.baSourceID = (__u8*)unit + sizeof *unit;			memcpy(unit->selector.baSourceID, &buffer[5], p);			if (buffer[5+p] != 0)				usb_string(udev, buffer[5+p], unit->name, sizeof unit->name);			else				sprintf(unit->name, "Selector %u", buffer[3]);			list_add_tail(&unit->list, &dev->entities);			break;		case VC_PROCESSING_UNIT:			n = buflen >= 8 ? buffer[7] : 0;			p = dev->uvc_version >= 0x0110 ? 10 : 9;			if (buflen < p + n) {				uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "				       "interface %d PROCESSING_UNIT error\n", udev->devnum,				       dev->intf->cur_altsetting->desc.bInterfaceNumber);				return -EINVAL;			}			unit = kzalloc(sizeof *unit + n, GFP_KERNEL);			if (unit == NULL)				return -ENOMEM;			unit->id = buffer[3];			unit->type = buffer[2];			unit->processing.bSourceID = buffer[4];			unit->processing.wMaxMultiplier = le16_to_cpup((__le16*)&buffer[5]);			unit->processing.bControlSize = buffer[7];			unit->processing.bmControls = (__u8*)unit + sizeof *unit;			memcpy(unit->processing.bmControls, &buffer[8], n);			if (dev->uvc_version >= 0x0110)				unit->processing.bmVideoStandards = buffer[9+n];			if (buffer[8+n] != 0)				usb_string(udev, buffer[8+n], unit->name, sizeof unit->name);			else				sprintf(unit->name, "Processing %u", buffer[3]);			list_add_tail(&unit->list, &dev->entities);			break;		case VC_EXTENSION_UNIT:			p = buflen >= 22 ? buffer[21] : 0;			n = buflen >= 24 + p ? buffer[22+p] : 0;			if (buflen < 24 + p + n) {				uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "				       "interface %d EXTENSION_UNIT error\n", udev->devnum,				       dev->intf->cur_altsetting->desc.bInterfaceNumber);				return -EINVAL;			}			unit = kzalloc(sizeof *unit + p + n, GFP_KERNEL);			if (unit == NULL)				return -ENOMEM;			unit->id = buffer[3];			unit->type = buffer[2];			memcpy(unit->extension.guidExtensionCode, &buffer[4], 16);			unit->extension.bNumControls = buffer[20];			unit->extension.bNrInPins = le16_to_cpup((__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;			memcpy(unit->extension.bmControls, &buffer[23+p], n);			if (buffer[23+p+n] != 0)				usb_string(udev, buffer[23+p+n], unit->name, sizeof unit->name);			else				sprintf(unit->name, "Extension %u", buffer[3]);			list_add_tail(&unit->list, &dev->entities);			break;		default:			uvc_trace(UVC_TRACE_DESCR, "Found an unknown CS_INTERFACE "				"descriptor (%u)\n", buffer[2]);			break;		}next_descriptor:		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 the following units: * * - a USB Streaming Output Terminal * - zero or one Processing Unit * - zero, one or mode single-input Selector Units * - zero or one multiple-input Selector Units, provided all inputs are *   connected to input terminals * - zero, one or mode single-input Extension Units * - one Camera Input Terminal, or one or more External terminals. * * A side forward scan is made on each detected entity to check for additional * extension units. */static int uvc_scan_chain_entity(struct uvc_video_device *video,	struct uvc_entity *entity){	switch (UVC_ENTITY_TYPE(entity)) {	case VC_EXTENSION_UNIT:		if (uvc_trace_param & UVC_TRACE_PROBE)			printk(" <- XU %d", entity->id);		if (entity->extension.bNrInPins != 1) {			uvc_trace(UVC_TRACE_DESCR, "Extension unit %d has more "				"than 1 input pin.\n", entity->id);			return -1;		}		list_add_tail(&entity->chain, &video->extensions);		break;	case VC_PROCESSING_UNIT:		if (uvc_trace_param & UVC_TRACE_PROBE)			printk(" <- PU %d", entity->id);		if (video->processing != NULL) {			uvc_trace(UVC_TRACE_DESCR, "Found multiple "				"Processing Units in chain.\n");			return -1;		}		video->processing = entity;		break;	case VC_SELECTOR_UNIT:		if (uvc_trace_param & UVC_TRACE_PROBE)			printk(" <- SU %d", entity->id);		/* Single-input selector units are ignored. */		if (entity->selector.bNrInPins == 1)			break;		if (video->selector != NULL) {			uvc_trace(UVC_TRACE_DESCR, "Found multiple Selector "				"Units in chain.\n");			return -1;		}		video->selector = entity;		break;	case ITT_VENDOR_SPECIFIC:	case ITT_CAMERA:	case ITT_MEDIA_TRANSPORT_INPUT:		if (uvc_trace_param & UVC_TRACE_PROBE)			printk(" <- IT %d\n", entity->id);		list_add_tail(&entity->chain, &video->iterms);		break;	default:		uvc_trace(UVC_TRACE_DESCR, "Unsupported entity type "			"0x%04x found in chain.\n", UVC_ENTITY_TYPE(entity));		return -1;	}	return 0;}static int uvc_scan_chain_forward(struct uvc_video_device *video,	struct uvc_entity *entity, struct uvc_entity *prev){	struct uvc_entity *forward;	int found;	/* Forward scan */	forward = NULL;	found = 0;	while (1) {		forward = uvc_entity_by_reference(video->dev, entity->id,			forward);		if (forward == NULL)			break;		if (forward == prev || UVC_ENTITY_TYPE(forward) != VC_EXTENSION_UNIT)			continue;		if (forward->extension.bNrInPins != 1) {			uvc_trace(UVC_TRACE_DESCR, "Extension unit %d has"				"more than 1 input pin.\n", entity->id);			return -1;		}		list_add_tail(&forward->chain, &video->extensions);		if (uvc_trace_param & UVC_TRACE_PROBE) {			if (!found)				printk(" (-> XU");			printk(" %d", forward->id);			found = 1;		}	}	if (found)		printk(")");	return 0;}static int uvc_scan_chain_backward(struct uvc_video_device *video,	struct uvc_entity *entity){	struct uvc_entity *term;	int id = -1, i;	switch (UVC_ENTITY_TYPE(entity)) {	case VC_EXTENSION_UNIT:		id = entity->extension.baSourceID[0];		break;	case VC_PROCESSING_UNIT:		id = entity->processing.bSourceID;		break;	case VC_SELECTOR_UNIT:		/* Single-input selector units are ignored. */		if (entity->selector.bNrInPins == 1) {			id = entity->selector.baSourceID[0];			break;		}		if (uvc_trace_param & UVC_TRACE_PROBE)			printk(" <- IT");		video->selector = entity;		for (i = 0; i < entity->selector.bNrInPins; ++i) {			id = entity->selector.baSourceID[i];			term = uvc_entity_by_id(video->dev, id);			if (term == NULL || !UVC_ENTITY_IS_ITERM(term)) {				uvc_trace(UVC_TRACE_DESCR, "Selector unit %d "					"input %d isn't connected to an "					"input terminal\n", entity->id, i);				return -1;			}			if (uvc_trace_param & UVC_TRACE_PROBE)				printk(" %d", term->id);			list_add_tail(&term->chain, &video->iterms);			uvc_scan_chain_forward(video, term, entity);		}		if (uvc_trace_param & UVC_TRACE_PROBE)			printk("\n");		id = 0;		break;	}	return id;}static int uvc_scan_chain(struct uvc_video_device *video){	struct uvc_entity *entity, *prev;	int id;	entity = video->oterm;	uvc_trace(UVC_TRACE_PROBE, "Scanning UVC chain: OT %d", entity->id);	id = entity->output.bSourceID;	while (id != 0) {		prev = entity;		entity = uvc_entity_by_id(video->dev, id);		if (entity == NULL) {			uvc_trace(UVC_TRACE_DESCR, "Found reference to "				"unknown entity %d.\n", id);			return -1;		}		/* Process entity */		if (uvc_scan_chain_entity(video, entity) < 0)			return -1;		/* Forward scan */		if (uvc_scan_chain_forward(video, entity, prev) < 0)			return -1;		/* Stop when a terminal is found. */		if (!UVC_ENTITY_IS_UNIT(entity))			break;		/* Backward scan */		id = uvc_scan_chain_backward(video, entity);		if (id < 0)			return id;	}	/* 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 uvc_streaming *streaming;		if (UVC_ENTITY_TYPE(term) != TT_STREAMING)			continue;		memset(&dev->video, 0, sizeof dev->video);		mutex_init(&dev->video.ctrl_mutex);		INIT_LIST_HEAD(&dev->video.iterms);		INIT_LIST_HEAD(&dev->video.extensions);		dev->video.oterm = term;		dev->video.dev = dev;		if (uvc_scan_chain(&dev->video) < 0)			continue;		list_for_each_entry(streaming, &dev->streaming, list) {			if (streaming->header.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;	}	if (uvc_trace_param & UVC_TRACE_PROBE) {		uvc_printk(KERN_INFO, "Found a valid video chain (");		list_for_each_entry(term, &dev->video.iterms, chain) {			printk("%d", term->id);			if (term->chain.next != &dev->video.iterms)				printk(",");		}		printk(" -> %d).\n", dev->video.oterm->id);	}	/* Initialize the streaming interface with default streaming	 * parameters.

⌨️ 快捷键说明

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