uvc摄像头代码解析6
2017-09-14 17:48
567 查看
10.扫描视频设备链和注册视频设备
10.1 uvc视频链
[cpp]
struct uvc_video_chain { //uvc视频链
struct uvc_device *dev; //uvc设备
struct list_head list; //uvc视频链链表头
struct list_head entities; //uvc实体链表头
struct uvc_entity *processing; //处理Unit实体
struct uvc_entity *selector; //选择器Unit实体
struct mutex ctrl_mutex; /* Protects ctrl.info */
};
10.2 uvc扫描设备
[cpp]
static int uvc_scan_device(struct uvc_device *dev)
{
struct uvc_video_chain *chain; //uvc视频链
struct uvc_entity *term; //uvc实体
list_for_each_entry(term, &dev->entities, list) { //遍历全局实体链表
if (!UVC_ENTITY_IS_OTERM(term)) //获取实体链表中的输出Terminal实体
continue;
if (term->chain.next || term->chain.prev) //已经添加到uvc视频链中了
continue;
chain = kzalloc(sizeof(*chain), GFP_KERNEL); //分配uvc视频链内存(有多少个输入Terminal就有多少个uvc_video_chain)
if (chain == NULL)
return -ENOMEM;
INIT_LIST_HEAD(&chain->entities); //初始化视频链entities(实体)链表
mutex_init(&chain->ctrl_mutex);
chain->dev = dev; //捆绑uvc视频链和uvc设备
if (uvc_scan_chain(chain, term) < 0) { //扫描uvc视频链(处理所有相关的输入pin)
kfree(chain);
continue;
}
uvc_trace(UVC_TRACE_PROBE, "Found a valid video chain (%s).\n",uvc_print_chain(chain));
list_add_tail(&chain->list, &dev->chains); //添加到uvc设备的uvc视频链链表
}
if (list_empty(&dev->chains)) {
uvc_printk(KERN_INFO, "No valid video chain found.\n");
return -1;
}
return 0;
}
10.3 uvc扫描视频链
[cpp]
static int uvc_scan_chain(struct uvc_video_chain *chain,struct uvc_entity *term)
{
struct uvc_entity *entity, *prev;
uvc_trace(UVC_TRACE_PROBE, "Scanning UVC chain:");
entity = term; //获取实体
prev = NULL; //前一个实体
while (entity != NULL) {
/* Entity must not be part of an existing chain */
if (entity->chain.next || entity->chain.prev) { //已经添加到uvc视频链中了
uvc_trace(UVC_TRACE_DESCR, "Found reference to entity %d already in chain.\n", entity->id);
return -EINVAL;
}
/* Process entity */
if (uvc_scan_chain_entity(chain, entity) < 0) //扫描当前实体
return -EINVAL;
/* Forward scan */
if (uvc_scan_chain_forward(chain, entity, prev) < 0) //向前扫描实体
return -EINVAL;
/* Backward scan */
prev = entity; //当前实体作为下一次while循环的前一个实体
if (uvc_scan_chain_backward(chain, &entity) < 0) //向后扫描实体
return -EINVAL;
}
return 0;
}
将uvc视频链的输入实体添加到uvc视频链的entities链表中
将uvc视频链添加到uvc设备的chains链表中
10.3.1 扫描当前实体
[cpp]
static int uvc_scan_chain_entity(struct uvc_video_chain *chain,struct uvc_entity *entity)
{
switch (UVC_ENTITY_TYPE(entity)) {
case UVC_VC_EXTENSION_UNIT: //扩展Unit
if (uvc_trace_param & UVC_TRACE_PROBE)
printk(" <- XU %d", entity->id);
if (entity->bNrInPins != 1) {
uvc_trace(UVC_TRACE_DESCR, "Extension unit %d has more than 1 input pin.\n", entity->id);
return -1;
}
break;
case UVC_VC_PROCESSING_UNIT: //处理Unit
if (uvc_trace_param & UVC_TRACE_PROBE)
printk(" <- PU %d", entity->id);
if (chain->processing != NULL) {
uvc_trace(UVC_TRACE_DESCR, "Found multiple Processing Units in chain.\n");
return -1;
}
chain->processing = entity; //如果是处理Unit则设置其为uvc视频链的processing对象
break;
case UVC_VC_SELECTOR_UNIT: //选择器Unit
if (uvc_trace_param & UVC_TRACE_PROBE)
printk(" <- SU %d", entity->id);
/* Single-input selector units are ignored. */
if (entity->bNrInPins == 1)
break;
if (chain->selector != NULL) {
uvc_trace(UVC_TRACE_DESCR, "Found multiple Selector Units in chain.\n");
return -1;
}
chain->selector = entity; //如果是选择器Unit则设置其为uvc视频链的selector对象
break;
case UVC_ITT_VENDOR_SPECIFIC: //厂商特殊
case UVC_ITT_CAMERA: //输入Terminal camera
case UVC_ITT_MEDIA_TRANSPORT_INPUT: //输入Terminal Media transport
if (uvc_trace_param & UVC_TRACE_PROBE)
printk(" <- IT %d\n", entity->id);
break;
case UVC_TT_STREAMING: //输入Terminal stream
if (UVC_ENTITY_IS_ITERM(entity)) {
if (uvc_trace_param & UVC_TRACE_PROBE)
printk(" <- IT %d\n", entity->id);
}
else {
if (uvc_trace_param & UVC_TRACE_PROBE)
printk(" OT %d", entity->id);
}
break;
default:
uvc_trace(UVC_TRACE_DESCR, "Unsupported entity type 0x%04x found in chain.\n", UVC_ENTITY_TYPE(entity));
return -1;
}
list_add_tail(&entity->chain, &chain->entities); //添加到uvc视频链的实体链表
return 0;
}
10.3.2 向前扫描实体
[cpp]
static int uvc_scan_chain_forward(struct uvc_video_chain *chain,struct uvc_entity *entity, struct uvc_entity *prev)
{
struct uvc_entity *forward;
int found;
/* Forward scan */
forward = NULL;
found = 0;
while (1) { //获取实体前面的所以实体处理直到前面的实体forward=NULL为止跳出死循环
forward = uvc_entity_by_reference(chain->dev, entity->id,forward); //获取前一个实体
if (forward == NULL)
break;
if (forward == prev)
continue;
switch (UVC_ENTITY_TYPE(forward)) {
case UVC_VC_EXTENSION_UNIT: //扩展Unit
if (forward->bNrInPins != 1) {
uvc_trace(UVC_TRACE_DESCR, "Extension unit %d has more than 1 input pin.\n",entity->id);
return -EINVAL;
}
list_add_tail(&forward->chain, &chain->entities); //添加uvc实体到uvc视频链的entities中
if (uvc_trace_param & UVC_TRACE_PROBE) {
if (!found)
printk(" (->");
printk(" XU %d", forward->id);
found = 1;
}
break;
case UVC_OTT_VENDOR_SPECIFIC: //厂商特殊
case UVC_OTT_DISPLAY: //输出Termianl display
case UVC_OTT_MEDIA_TRANSPORT_OUTPUT: //输出Terminal media transport
case UVC_TT_STREAMING: //输出Terminal stream
if (UVC_ENTITY_IS_ITERM(forward)) {
uvc_trace(UVC_TRACE_DESCR, "Unsupported input terminal %u.\n", forward->id);
return -EINVAL;
}
list_add_tail(&forward->chain, &chain->entities); //添加uvc实体到uvc视频链的entities中
if (uvc_trace_param & UVC_TRACE_PROBE) {
if (!found)
printk(" (->");
printk(" OT %d", forward->id);
found = 1;
}
break;
}
}
if (found)
printk(")");
return 0;
}
10.3.3 向后扫描实体
[cpp]
static int uvc_scan_chain_backward(struct uvc_video_chain *chain,struct uvc_entity **_entity)
{
struct uvc_entity *entity = *_entity;
struct uvc_entity *term;
int id = -EINVAL, i;
switch (UVC_ENTITY_TYPE(entity)) {
case UVC_VC_EXTENSION_UNIT: //扩展Unit
case UVC_VC_PROCESSING_UNIT: //处理Unit处理Unit的输入Terminal个数只能为1
id = entity->baSourceID[0]; //获取输入pin(Unit/Terminal)的ID
break;
case UVC_VC_SELECTOR_UNIT: //选择器实体
/* Single-input selector units are ignored. */
if (entity->bNrInPins == 1) { //若输入pin个数为1
id = entity->baSourceID[0]; //获取输入in(Unit/Terminal)的ID
break;
}
if (uvc_trace_param & UVC_TRACE_PROBE)
printk(" <- IT");
chain->selector = entity; //uvc视频链的selector对象指向uvc实体
for (i = 0; i < entity->bNrInPins; ++i) { //总共有多少个输入pin
id = entity->baSourceID[i]; //获取输入in(Unit/Terminal)的ID
term = uvc_entity_by_id(chain->dev, id); //获取对应的输入pin实体
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, &chain->entities); //添加uvc实体到uvc视频链的entities链表
uvc_scan_chain_forward(chain, term, entity); //向前扫描实体
}
if (uvc_trace_param & UVC_TRACE_PROBE)
printk("\n");
id = 0;
break;
case UVC_ITT_VENDOR_SPECIFIC:
case UVC_ITT_CAMERA:
case UVC_ITT_MEDIA_TRANSPORT_INPUT:
case UVC_OTT_VENDOR_SPECIFIC:
case UVC_OTT_DISPLAY:
case UVC_OTT_MEDIA_TRANSPORT_OUTPUT:
case UVC_TT_STREAMING:
id = UVC_ENTITY_IS_OTERM(entity) ? entity->baSourceID[0] : 0;
break;
}
if (id <= 0) {
*_entity = NULL;
return id;
}
entity = uvc_entity_by_id(chain->dev, id);
if (entity == NULL) {
uvc_trace(UVC_TRACE_DESCR, "Found reference to unknown entity %d.\n", id);
return -EINVAL;
}
*_entity = entity;
return 0;
}
注意到trace打印的语句会发现有一条
[cpp]
uvcvideo: Scanning UVC chain: OT 2 <- XU 5 <- XU 4 <- PU 3 <- IT 1
可以看到这些Unit和Terminal是如何组建起来的
10.1 uvc视频链
[cpp]
struct uvc_video_chain { //uvc视频链
struct uvc_device *dev; //uvc设备
struct list_head list; //uvc视频链链表头
struct list_head entities; //uvc实体链表头
struct uvc_entity *processing; //处理Unit实体
struct uvc_entity *selector; //选择器Unit实体
struct mutex ctrl_mutex; /* Protects ctrl.info */
};
10.2 uvc扫描设备
[cpp]
static int uvc_scan_device(struct uvc_device *dev)
{
struct uvc_video_chain *chain; //uvc视频链
struct uvc_entity *term; //uvc实体
list_for_each_entry(term, &dev->entities, list) { //遍历全局实体链表
if (!UVC_ENTITY_IS_OTERM(term)) //获取实体链表中的输出Terminal实体
continue;
if (term->chain.next || term->chain.prev) //已经添加到uvc视频链中了
continue;
chain = kzalloc(sizeof(*chain), GFP_KERNEL); //分配uvc视频链内存(有多少个输入Terminal就有多少个uvc_video_chain)
if (chain == NULL)
return -ENOMEM;
INIT_LIST_HEAD(&chain->entities); //初始化视频链entities(实体)链表
mutex_init(&chain->ctrl_mutex);
chain->dev = dev; //捆绑uvc视频链和uvc设备
if (uvc_scan_chain(chain, term) < 0) { //扫描uvc视频链(处理所有相关的输入pin)
kfree(chain);
continue;
}
uvc_trace(UVC_TRACE_PROBE, "Found a valid video chain (%s).\n",uvc_print_chain(chain));
list_add_tail(&chain->list, &dev->chains); //添加到uvc设备的uvc视频链链表
}
if (list_empty(&dev->chains)) {
uvc_printk(KERN_INFO, "No valid video chain found.\n");
return -1;
}
return 0;
}
10.3 uvc扫描视频链
[cpp]
static int uvc_scan_chain(struct uvc_video_chain *chain,struct uvc_entity *term)
{
struct uvc_entity *entity, *prev;
uvc_trace(UVC_TRACE_PROBE, "Scanning UVC chain:");
entity = term; //获取实体
prev = NULL; //前一个实体
while (entity != NULL) {
/* Entity must not be part of an existing chain */
if (entity->chain.next || entity->chain.prev) { //已经添加到uvc视频链中了
uvc_trace(UVC_TRACE_DESCR, "Found reference to entity %d already in chain.\n", entity->id);
return -EINVAL;
}
/* Process entity */
if (uvc_scan_chain_entity(chain, entity) < 0) //扫描当前实体
return -EINVAL;
/* Forward scan */
if (uvc_scan_chain_forward(chain, entity, prev) < 0) //向前扫描实体
return -EINVAL;
/* Backward scan */
prev = entity; //当前实体作为下一次while循环的前一个实体
if (uvc_scan_chain_backward(chain, &entity) < 0) //向后扫描实体
return -EINVAL;
}
return 0;
}
将uvc视频链的输入实体添加到uvc视频链的entities链表中
将uvc视频链添加到uvc设备的chains链表中
10.3.1 扫描当前实体
[cpp]
static int uvc_scan_chain_entity(struct uvc_video_chain *chain,struct uvc_entity *entity)
{
switch (UVC_ENTITY_TYPE(entity)) {
case UVC_VC_EXTENSION_UNIT: //扩展Unit
if (uvc_trace_param & UVC_TRACE_PROBE)
printk(" <- XU %d", entity->id);
if (entity->bNrInPins != 1) {
uvc_trace(UVC_TRACE_DESCR, "Extension unit %d has more than 1 input pin.\n", entity->id);
return -1;
}
break;
case UVC_VC_PROCESSING_UNIT: //处理Unit
if (uvc_trace_param & UVC_TRACE_PROBE)
printk(" <- PU %d", entity->id);
if (chain->processing != NULL) {
uvc_trace(UVC_TRACE_DESCR, "Found multiple Processing Units in chain.\n");
return -1;
}
chain->processing = entity; //如果是处理Unit则设置其为uvc视频链的processing对象
break;
case UVC_VC_SELECTOR_UNIT: //选择器Unit
if (uvc_trace_param & UVC_TRACE_PROBE)
printk(" <- SU %d", entity->id);
/* Single-input selector units are ignored. */
if (entity->bNrInPins == 1)
break;
if (chain->selector != NULL) {
uvc_trace(UVC_TRACE_DESCR, "Found multiple Selector Units in chain.\n");
return -1;
}
chain->selector = entity; //如果是选择器Unit则设置其为uvc视频链的selector对象
break;
case UVC_ITT_VENDOR_SPECIFIC: //厂商特殊
case UVC_ITT_CAMERA: //输入Terminal camera
case UVC_ITT_MEDIA_TRANSPORT_INPUT: //输入Terminal Media transport
if (uvc_trace_param & UVC_TRACE_PROBE)
printk(" <- IT %d\n", entity->id);
break;
case UVC_TT_STREAMING: //输入Terminal stream
if (UVC_ENTITY_IS_ITERM(entity)) {
if (uvc_trace_param & UVC_TRACE_PROBE)
printk(" <- IT %d\n", entity->id);
}
else {
if (uvc_trace_param & UVC_TRACE_PROBE)
printk(" OT %d", entity->id);
}
break;
default:
uvc_trace(UVC_TRACE_DESCR, "Unsupported entity type 0x%04x found in chain.\n", UVC_ENTITY_TYPE(entity));
return -1;
}
list_add_tail(&entity->chain, &chain->entities); //添加到uvc视频链的实体链表
return 0;
}
10.3.2 向前扫描实体
[cpp]
static int uvc_scan_chain_forward(struct uvc_video_chain *chain,struct uvc_entity *entity, struct uvc_entity *prev)
{
struct uvc_entity *forward;
int found;
/* Forward scan */
forward = NULL;
found = 0;
while (1) { //获取实体前面的所以实体处理直到前面的实体forward=NULL为止跳出死循环
forward = uvc_entity_by_reference(chain->dev, entity->id,forward); //获取前一个实体
if (forward == NULL)
break;
if (forward == prev)
continue;
switch (UVC_ENTITY_TYPE(forward)) {
case UVC_VC_EXTENSION_UNIT: //扩展Unit
if (forward->bNrInPins != 1) {
uvc_trace(UVC_TRACE_DESCR, "Extension unit %d has more than 1 input pin.\n",entity->id);
return -EINVAL;
}
list_add_tail(&forward->chain, &chain->entities); //添加uvc实体到uvc视频链的entities中
if (uvc_trace_param & UVC_TRACE_PROBE) {
if (!found)
printk(" (->");
printk(" XU %d", forward->id);
found = 1;
}
break;
case UVC_OTT_VENDOR_SPECIFIC: //厂商特殊
case UVC_OTT_DISPLAY: //输出Termianl display
case UVC_OTT_MEDIA_TRANSPORT_OUTPUT: //输出Terminal media transport
case UVC_TT_STREAMING: //输出Terminal stream
if (UVC_ENTITY_IS_ITERM(forward)) {
uvc_trace(UVC_TRACE_DESCR, "Unsupported input terminal %u.\n", forward->id);
return -EINVAL;
}
list_add_tail(&forward->chain, &chain->entities); //添加uvc实体到uvc视频链的entities中
if (uvc_trace_param & UVC_TRACE_PROBE) {
if (!found)
printk(" (->");
printk(" OT %d", forward->id);
found = 1;
}
break;
}
}
if (found)
printk(")");
return 0;
}
10.3.3 向后扫描实体
[cpp]
static int uvc_scan_chain_backward(struct uvc_video_chain *chain,struct uvc_entity **_entity)
{
struct uvc_entity *entity = *_entity;
struct uvc_entity *term;
int id = -EINVAL, i;
switch (UVC_ENTITY_TYPE(entity)) {
case UVC_VC_EXTENSION_UNIT: //扩展Unit
case UVC_VC_PROCESSING_UNIT: //处理Unit处理Unit的输入Terminal个数只能为1
id = entity->baSourceID[0]; //获取输入pin(Unit/Terminal)的ID
break;
case UVC_VC_SELECTOR_UNIT: //选择器实体
/* Single-input selector units are ignored. */
if (entity->bNrInPins == 1) { //若输入pin个数为1
id = entity->baSourceID[0]; //获取输入in(Unit/Terminal)的ID
break;
}
if (uvc_trace_param & UVC_TRACE_PROBE)
printk(" <- IT");
chain->selector = entity; //uvc视频链的selector对象指向uvc实体
for (i = 0; i < entity->bNrInPins; ++i) { //总共有多少个输入pin
id = entity->baSourceID[i]; //获取输入in(Unit/Terminal)的ID
term = uvc_entity_by_id(chain->dev, id); //获取对应的输入pin实体
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, &chain->entities); //添加uvc实体到uvc视频链的entities链表
uvc_scan_chain_forward(chain, term, entity); //向前扫描实体
}
if (uvc_trace_param & UVC_TRACE_PROBE)
printk("\n");
id = 0;
break;
case UVC_ITT_VENDOR_SPECIFIC:
case UVC_ITT_CAMERA:
case UVC_ITT_MEDIA_TRANSPORT_INPUT:
case UVC_OTT_VENDOR_SPECIFIC:
case UVC_OTT_DISPLAY:
case UVC_OTT_MEDIA_TRANSPORT_OUTPUT:
case UVC_TT_STREAMING:
id = UVC_ENTITY_IS_OTERM(entity) ? entity->baSourceID[0] : 0;
break;
}
if (id <= 0) {
*_entity = NULL;
return id;
}
entity = uvc_entity_by_id(chain->dev, id);
if (entity == NULL) {
uvc_trace(UVC_TRACE_DESCR, "Found reference to unknown entity %d.\n", id);
return -EINVAL;
}
*_entity = entity;
return 0;
}
注意到trace打印的语句会发现有一条
[cpp]
uvcvideo: Scanning UVC chain: OT 2 <- XU 5 <- XU 4 <- PU 3 <- IT 1
可以看到这些Unit和Terminal是如何组建起来的