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是如何組建起來的