diff options
Diffstat (limited to 'drivers/media/usb/uvc/uvc_driver.c')
| -rw-r--r-- | drivers/media/usb/uvc/uvc_driver.c | 34 | 
1 files changed, 33 insertions, 1 deletions
| diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c index 30ef2a3110f7..9a791d8ef200 100644 --- a/drivers/media/usb/uvc/uvc_driver.c +++ b/drivers/media/usb/uvc/uvc_driver.c @@ -1712,10 +1712,35 @@ static int uvc_scan_chain_forward(struct uvc_video_chain *chain,  			if (forward->bNrInPins != 1) {  				uvc_dbg(chain->dev, DESCR,  					"Extension unit %d has more than 1 input pin\n", -					entity->id); +					forward->id);  				return -EINVAL;  			} +			/* +			 * Some devices reference an output terminal as the +			 * source of extension units. This is incorrect, as +			 * output terminals only have an input pin, and thus +			 * can't be connected to any entity in the forward +			 * direction. The resulting topology would cause issues +			 * when registering the media controller graph. To +			 * avoid this problem, connect the extension unit to +			 * the source of the output terminal instead. +			 */ +			if (UVC_ENTITY_IS_OTERM(entity)) { +				struct uvc_entity *source; + +				source = uvc_entity_by_id(chain->dev, +							  entity->baSourceID[0]); +				if (!source) { +					uvc_dbg(chain->dev, DESCR, +						"Can't connect extension unit %u in chain\n", +						forward->id); +					break; +				} + +				forward->baSourceID[0] = source->id; +			} +  			list_add_tail(&forward->chain, &chain->entities);  			if (!found)  				uvc_dbg_cont(PROBE, " (->"); @@ -1735,6 +1760,13 @@ static int uvc_scan_chain_forward(struct uvc_video_chain *chain,  				return -EINVAL;  			} +			if (UVC_ENTITY_IS_OTERM(entity)) { +				uvc_dbg(chain->dev, DESCR, +					"Unsupported connection between output terminals %u and %u\n", +					entity->id, forward->id); +				break; +			} +  			list_add_tail(&forward->chain, &chain->entities);  			if (!found)  				uvc_dbg_cont(PROBE, " (->"); | 
