LINUX&UVC输入终端描述符解析
2024-03-19
92
0
UVC输入终端是UVC设备拓扑结构中数据流的起始节点。UVC输入终端使用UVC输入终端描述符来描述.
关于该描述符详细的字段描述详见:https://www.usbzh.com/article/detail-95.html
关于相机终端描述符详见:https://www.usbzh.com/article/detail-47.html
根据前文可知,输入终端按其类型可分为:
wTerminalType | 值 | 描述 |
---|---|---|
ITT_VENDOR_SPECIFIC | 0x200 | 厂商用自定义 |
ITT_CAMERA | 0x201 | 相机 |
ITT_MEDIA_TRANSPORT_INPUT | 0x202 | 序列媒介 |
一般最常见的UVC相机就是ITT_CAMERA类型,值为0x201。
uvc_parse_standard_control函数中关于输入终端的代码解析如下:
case UVC_VC_INPUT_TERMINAL:
if (buflen < 8) {
uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
"interface %d INPUT_TERMINAL error\n",
udev->devnum, alts->desc.bInterfaceNumber);
return -EINVAL;
}
/*
* Reject invalid terminal types that would cause issues:
*
* - The high byte must be non-zero, otherwise it would be
* confused with a unit.
*
* - Bit 15 must be 0, as we use it internally as a terminal
* direction flag.
*
* Other unknown types are accepted.
*/
type = get_unaligned_le16(&buffer[4]);
if ((type & 0x7f00) == 0 || (type & 0x8000) != 0) {
uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
"interface %d INPUT_TERMINAL %d has invalid "
"type 0x%04x, skipping\n", udev->devnum,
alts->desc.bInterfaceNumber,
buffer[3], type);
return 0;
}
n = 0;
p = 0;
len = 8;
if (type == UVC_ITT_CAMERA) {
n = buflen >= 15 ? buffer[14] : 0;
len = 15;
} else if (type == UVC_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, alts->desc.bInterfaceNumber);
return -EINVAL;
}
term = uvc_alloc_entity(type | UVC_TERM_INPUT, buffer[3],
1, n + p);
if (term == NULL)
return -ENOMEM;
if (UVC_ENTITY_TYPE(term) == UVC_ITT_CAMERA) {
term->camera.bControlSize = n;
term->camera.bmControls = (u8 *)term + sizeof(*term);
term->camera.wObjectiveFocalLengthMin = get_unaligned_le16(&buffer[8]);
term->camera.wObjectiveFocalLengthMax = get_unaligned_le16(&buffer[10]);
term->camera.wOcularFocalLength = get_unaligned_le16(&buffer[12]);
memcpy(term->camera.bmControls, &buffer[15], n);
} else if (UVC_ENTITY_TYPE(term) == UVC_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) == UVC_ITT_CAMERA)
sprintf(term->name, "Camera %u", buffer[3]);
else if (UVC_ENTITY_TYPE(term) == UVC_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;
代码看着其实挺乱的,不过如果对代码整理,我相信大部分都会很看地很清楚的:
先定义3个结构体,分别为输入终端描述符,相机终端描述符和序列媒体描述符。
// Input Terminal Descriptor
typedef struct _USB_IT_DESCRIPTOR
{
UINT8 bLength;
UINT8 bDescriptorType;
UINT8 bDescriptorSubtype;
UINT8 bTerminalID;
UINT16 wTerminalType;
UINT8 bAssocTerminal;
UINT8 iTerminal;
UINT8 reserved[0];
} USB_IT_DESCRIPTOR;
typedef struct _CAMERA_TERMINAL_DESCRIPTOR
UINT8 bLength;
UINT8 bDescriptorType;
UINT8 bDescriptorSubtype;
UINT8 bTerminalID;
UINT16 wTerminalType;
UINT8 bAssocTerminal;
UINT8 iTerminal;
UINT16 wObjectiveFocalLengthMin;
UIN16 wObjectiveFocalLengthMax;
UIN16 wOcularFocalLength;
UINT8 bControlSize;
UINT8 bmControls[3];
}CAMERA_TERMINAL_DESCRIPTOR;
然后根据不同的bTerminalID,使用不同的结构体处理:
if (UVC_ENTITY_TYPE(term) == UVC_TERM_INPUT) {
...
}
else if (UVC_ENTITY_TYPE(term) == UVC_ITT_CAMERA){
...
}
else if (UVC_ENTITY_TYPE(term) == UVC_ITT_MEDIA_TRANSPORT_INPUT){
...
}
至于申请的通用结构体uvc_entity,内部根据类型的不同,其用不同的结构体而已。这种情况在windows内核中太常见了,Linux中我也是第一次见。
struct uvc_entity {
...
u8 id;
u16 type;
...
union {
struct {
u16 wObjectiveFocalLengthMin;
u16 wObjectiveFocalLengthMax;
u16 wOcularFocalLength;
u8 bControlSize;
u8 *bmControls;
} camera;
struct {
u8 bControlSize;
u8 *bmControls;
u8 bTransportModeSize;
u8 *bmTransportModes;
} media;
struct {
} output;
struct {
u16 wMaxMultiplier;
u8 bControlSize;
u8 *bmControls;
u8 bmVideoStandards;
} processing;
struct {
} selector;
struct {
u8 guidExtensionCode[16];
u8 bNumControls;
u8 bControlSize;
u8 *bmControls;
u8 *bmControlsType;
} extension;
};
}