Personal Homepage: Chengang. plus/

The article will be synchronized to personal wechat official account: Android blog

UVC document website: www.usb.org/documents?s…

Download USB Video Class 1_5, pay attention to download the UVC 1.5 Class specification. PDF file in the zip package, which has the explanation of interface.

The Android Box control camera project has been going on for almost four years now, and a lot of things have already been forgotten. The following two articles will help you review them.

My.oschina.net/u/2007478/b…

Blog.csdn.net/go_str/arti…

An explanation of the various constructs in the code can be found at the following two sites:

www.kernel.org/doc/html/v4…

www.linuxtv.org/downloads/l…

1. UVC in Linux Kernel

Git clone kernel git clone

Android.googlesource.com/kernel/gold…

Git clone android.googlesource.com/kernel/gold…

Clone to local, you can use Source Insight to view the Source code. Before viewing the source code, first project -> rebuild project, so that the code between objects can be clicked jump.

1.1 the initialization

goldfish\drivers\media\usb\uvc\uvc_driver.c

static int __init uvc_init(void)
{
	int ret;
	ret = usb_register(&uvc_driver.driver);
	return 0;
}

struct uvc_driver uvc_driver = {
	.driver = {
		.name		= "uvcvideo",
		.probe		= uvc_probe,
		.disconnect	= uvc_disconnect,
		.suspend	= uvc_suspend,
		.resume		= uvc_resume,
		.reset_resume	= uvc_reset_resume,
		.id_table	= uvc_ids,
		.supports_autosuspend = 1,}};Copy the code

In the entry function uvc_init, the core line is usb_register, which is to register a USB device, and the uvc_probe function is called after the registration is complete.

goldfish\include\linux\usb.h

struct usb_driver {
	const char *name;

	int (*probe) (struct usb_interface *intf,
		      const struct usb_device_id *id);
Copy the code

Take a look at the uvc_probe function:

goldfish\drivers\media\usb\uvc\uvc_driver.c

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);
    
    uvc_parse_control(dev);/ / 1
    v4l2_device_register(&intf->dev, &dev->vdev);/ / 2
    uvc_ctrl_init_device(dev);/ / 3
    uvc_scan_device(dev);
    uvc_register_chains(dev);
    usb_set_intfdata(intf, dev);
    ret = uvc_status_init(dev);
    usb_enable_autosuspend(udev);
}
Copy the code
  • Each camera device has a vendorId and productId after low-level initialization.
  • uvc_parse_controlThe vendorId and productId of the device can be used to adapt the camera of a specific manufacturer.
  • v4l2_device_register, this method registers the device with V4L2, which is short for Video for Linux2, a Linux kernel driver for Video devices. The method ingoldfish\drivers\media\v4l2-core\v4l2-device.cIn the.
  • uvc_ctrl_init_deviceInitializes device control.

1.2 Initializing device Control

Here’s what we need to focus on. You can start by tracing the call stack.

goldfish\drivers\media\usb\uvc\uvc_ctrl.c

int uvc_ctrl_init_device(struct uvc_device *dev)
{
    list_for_each_entry(entity, &dev->entities, list) {
		struct uvc_control *ctrl;
		unsigned int bControlSize = 0, ncontrols;
		__u8 *bmControls = NULL;
		// The first part
		if (UVC_ENTITY_TYPE(entity) == UVC_VC_EXTENSION_UNIT) {
			bmControls = entity->extension.bmControls;
			bControlSize = entity->extension.bControlSize;
		} else if (UVC_ENTITY_TYPE(entity) == UVC_VC_PROCESSING_UNIT) {
			bmControls = entity->processing.bmControls;
			bControlSize = entity->processing.bControlSize;
		} else if (UVC_ENTITY_TYPE(entity) == UVC_ITT_CAMERA) {
			bmControls = entity->camera.bmControls;
			bControlSize = entity->camera.bControlSize;
		}
		// Part 2
		/* Initialize all supported controls */
		ctrl = entity->controls;
		for (i = 0; i < bControlSize * 8; ++i) {
			if (uvc_test_bit(bmControls, i) == 0)
				continue; ctrl->entity = entity; ctrl->index = i; uvc_ctrl_init_ctrl(dev, ctrl); ctrl++; }}}Copy the code

1.2.1 ENTITY Type Filtering

The UVC_ITT_CAMERA type is used to distinguish between terminal types, focusing on the UVC_ITT_CAMERA type, which is defined in the UVC protocol documentation:

The camera sensor is used to describe the camera terminal only. The description in the code is:

goldfish\include\uapi\linux\usb\video.h

/* B.2. Input Terminal Types */
#define UVC_ITT_VENDOR_SPECIFIC				0x0200
#define UVC_ITT_CAMERA					0x0201
#define UVC_ITT_MEDIA_TRANSPORT_INPUT			0x0202
Copy the code

1.2.2 Initializing uvc_Control

Camera. BmControls and Camera. BControlSize are both camera.bmControls and Camera. bControlSize.

BControlSize is the bit size corresponding to bmControls; BmControls corresponds to the control parameters supported by the camera. If the control parameter is set to 1, the control parameter is supported.

1.2.2.1 method uvc_ctrl_init_ctrl

Next call the uvc_CTRl_init_ctrl method:

goldfish\drivers\media\usb\uvc\uvc_ctrl.c

static void uvc_ctrl_init_ctrl(struct uvc_device *dev, struct uvc_control *ctrl)
{
	const struct uvc_control_info *info = uvc_ctrls;
	const struct uvc_control_info *iend = info + ARRAY_SIZE(uvc_ctrls);
	const struct uvc_control_mapping *mapping = uvc_ctrl_mappings;
	const struct uvc_control_mapping *mend = mapping + ARRAY_SIZE(uvc_ctrl_mappings);
	
	for (; info < iend; ++info) {
		if (uvc_entity_match_guid(ctrl->entity, info->entity) &&
		    ctrl->index == info->index) {
			uvc_ctrl_add_info(dev, ctrl, info);
			break; }}if(! ctrl->initialized)return;

	for (; mapping < mend; ++mapping) {
		if(uvc_entity_match_guid(ctrl->entity, mapping->entity) && ctrl->info.selector == mapping->selector) __uvc_ctrl_add_mapping(dev, ctrl, mapping); }}Copy the code
1.2.2.2 Structure uvc_control_info
  • uvc_ctrlsThe type of this structure isuvc_control_infoIs a static array. It can be understood that there are multiple control functions corresponding to one entity category, and each function has a different operation mode. Take the functions needed in the current project as examples:
static struct uvc_control_info uvc_ctrls[] = {
	{
		.entity		= UVC_GUID_UVC_CAMERA,
		.selector	= UVC_CT_PANTILT_ABSOLUTE_CONTROL,
		.index		= 11,
		.size		= 8,
		.flags		= UVC_CTRL_FLAG_SET_CUR
				| UVC_CTRL_FLAG_GET_RANGE
				| UVC_CTRL_FLAG_RESTORE
				| UVC_CTRL_FLAG_AUTO_UPDATE,
	},
	{
		.entity		= UVC_GUID_UVC_CAMERA,
		.selector	= UVC_CT_PANTILT_RELATIVE_CONTROL,
		.index		= 12,
		.size		= 4. .flags = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_MIN | UVC_CTRL_FLAG_GET_MAX | UVC_CTRL_FLAG_GET_RES | UVC_CTRL_FLAG_GET_DEF | UVC_CTRL_FLAG_AUTO_UPDATE, }, }Copy the code
  • Entity entity is one type. UVC_GUID_UVC_CAMERA is only one type. UVC_GUID_UVC_PROCESSING is another type.

  • Selector corresponds to a function under the entity, like relative absolute rotation.

  • Index corresponds to the sequence number in uvc_CTRls.

/* Bit index in bmControls */

  • sizeCorresponding to the length of the specific operation bits, as listed aboveUVC_CT_PANTILT_ABSOLUTE_CONTROLandUVC_CT_PANTILT_RELATIVE_CONTROLControl, see the definition in the protocol documentation:

For PanTilt Absolute, the high four digits represent the left and right angles, while the low four digits represent the up and down angles. Both are signed integers with a total of eight digits, so the size is 8.

For PanTilt Relative, there are four digits in total, each representing a different control attribute, the first representing left and right Relative; The second indicates the speed of left and right control; The third digit means up and down; The fourth is the speed up and down. So size is 4.

  • flagsMeans that for theseselectorSupported operations: Detailed explanations are as follows:
1.2.2.3 UvC_control_MAPPING Structure

Uvc_ctrl_mappings is uvc_control_mapping type structure variables, as well as a static structure, a brief look at the inside what defines:

static struct uvc_control_mapping uvc_ctrl_mappings[] = {
    {
		.id		= V4L2_CID_PAN_ABSOLUTE,
		.name		= "Pan (Absolute)",
		.entity		= UVC_GUID_UVC_CAMERA,
		.selector	= UVC_CT_PANTILT_ABSOLUTE_CONTROL,
		.size		= 32,
		.offset		= 0,
		.v4l2_type	= V4L2_CTRL_TYPE_INTEGER,
		.data_type	= UVC_CTRL_DATA_TYPE_UNSIGNED,
	},
	{
		.id		= V4L2_CID_TILT_ABSOLUTE,
		.name		= "Tilt (Absolute)",
		.entity		= UVC_GUID_UVC_CAMERA,
		.selector	= UVC_CT_PANTILT_ABSOLUTE_CONTROL,
		.size		= 32,
		.offset		= 32,
		.v4l2_type	= V4L2_CTRL_TYPE_INTEGER,
		.data_type	= UVC_CTRL_DATA_TYPE_UNSIGNED,
	},
}
Copy the code

You can see that the iD starts with V4L2, and the entity and selector correspond to the entity and selector defined in uvc_control_info.

In addition, v4L2_type corresponds to the set data type, and data_type defines whether the data is signed or unsigned.

This structure, as I understand it, maps the controls defined by UVC to V4L2 and establishes the relationship between the two.

1.2.2.4 method uvc_ctrl_add_info

The core of this method is one line of code:

goldfish\drivers\media\usb\uvc\uvc_ctrl.c

static int uvc_ctrl_add_info(struct uvc_device *dev, struct uvc_control *ctrl,
	const struct uvc_control_info *info)
{
    ctrl->info = *info;
}
Copy the code

Pass the previous variable uvc_control_info to the info of uvc_control. Uvc_control is defined as follows:

goldfish\drivers\media\usb\uvc\uvcvideo.h

struct uvc_control {
	struct uvc_entity *entity;
	struct uvc_control_info info;

	__u8 index;	/* Used to match the uvc_control entry with a uvc_control_info. */
	__u8 dirty:1,
	     loaded:1,
	     modified:1,
	     cached:1,
	     initialized:1;

	__u8 *uvc_data;
};
Copy the code
1.2.2.5 method __uvc_ctrl_add_mapping

Similarly, assign the uvc_control_mapping data to the uvc_control object:

goldfish\drivers\media\usb\uvc\uvc_ctrl.c

static int __uvc_ctrl_add_mapping(struct uvc_device *dev,
	struct uvc_control *ctrl, const struct uvc_control_mapping *mapping)
{
	struct uvc_control_mapping *map;
	map = kmemdup(mapping, sizeof(*mapping), GFP_KERNEL);
	map->menu_info = kmemdup(mapping->menu_info, size, GFP_KERNEL);
	list_add_tail(&map->list, &ctrl->info.mappings);
}
Copy the code

Uvc_control_info as the list header, add map->list to the end.

1.3 summarize

During initialization, the UVC document can be associated with the code to help understand the logic of the code. After understanding the principle and flow of various data type definitions, it is found that the connection between UVC and V4L2 is realized, so that the next step is easier to carry out.

This concludes the UVC initialization, and it’s time to do some customization based on your specific needs.