diff options
Diffstat (limited to 'drivers/media/usb/uvc/uvc_driver.c')
-rw-r--r-- | drivers/media/usb/uvc/uvc_driver.c | 177 |
1 files changed, 156 insertions, 21 deletions
diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c index 302e284a95eb..04bf35063c4c 100644 --- a/drivers/media/usb/uvc/uvc_driver.c +++ b/drivers/media/usb/uvc/uvc_driver.c @@ -168,6 +168,26 @@ static struct uvc_format_desc uvc_fmts[] = { .guid = UVC_GUID_FORMAT_RW10, .fcc = V4L2_PIX_FMT_SRGGB10P, }, + { + .name = "Bayer 16-bit (SBGGR16)", + .guid = UVC_GUID_FORMAT_BG16, + .fcc = V4L2_PIX_FMT_SBGGR16, + }, + { + .name = "Bayer 16-bit (SGBRG16)", + .guid = UVC_GUID_FORMAT_GB16, + .fcc = V4L2_PIX_FMT_SGBRG16, + }, + { + .name = "Bayer 16-bit (SRGGB16)", + .guid = UVC_GUID_FORMAT_RG16, + .fcc = V4L2_PIX_FMT_SRGGB16, + }, + { + .name = "Bayer 16-bit (SGRBG16)", + .guid = UVC_GUID_FORMAT_GR16, + .fcc = V4L2_PIX_FMT_SGRBG16, + }, }; /* ------------------------------------------------------------------------ @@ -1309,7 +1329,7 @@ static int uvc_scan_chain_entity(struct uvc_video_chain *chain, switch (UVC_ENTITY_TYPE(entity)) { case UVC_VC_EXTENSION_UNIT: if (uvc_trace_param & UVC_TRACE_PROBE) - printk(" <- XU %d", entity->id); + printk(KERN_CONT " <- XU %d", entity->id); if (entity->bNrInPins != 1) { uvc_trace(UVC_TRACE_DESCR, "Extension unit %d has more " @@ -1321,7 +1341,7 @@ static int uvc_scan_chain_entity(struct uvc_video_chain *chain, case UVC_VC_PROCESSING_UNIT: if (uvc_trace_param & UVC_TRACE_PROBE) - printk(" <- PU %d", entity->id); + printk(KERN_CONT " <- PU %d", entity->id); if (chain->processing != NULL) { uvc_trace(UVC_TRACE_DESCR, "Found multiple " @@ -1334,7 +1354,7 @@ static int uvc_scan_chain_entity(struct uvc_video_chain *chain, case UVC_VC_SELECTOR_UNIT: if (uvc_trace_param & UVC_TRACE_PROBE) - printk(" <- SU %d", entity->id); + printk(KERN_CONT " <- SU %d", entity->id); /* Single-input selector units are ignored. */ if (entity->bNrInPins == 1) @@ -1353,7 +1373,7 @@ static int uvc_scan_chain_entity(struct uvc_video_chain *chain, case UVC_ITT_CAMERA: case UVC_ITT_MEDIA_TRANSPORT_INPUT: if (uvc_trace_param & UVC_TRACE_PROBE) - printk(" <- IT %d\n", entity->id); + printk(KERN_CONT " <- IT %d\n", entity->id); break; @@ -1361,17 +1381,17 @@ static int uvc_scan_chain_entity(struct uvc_video_chain *chain, case UVC_OTT_DISPLAY: case UVC_OTT_MEDIA_TRANSPORT_OUTPUT: if (uvc_trace_param & UVC_TRACE_PROBE) - printk(" OT %d", entity->id); + printk(KERN_CONT " OT %d", entity->id); break; case UVC_TT_STREAMING: if (UVC_ENTITY_IS_ITERM(entity)) { if (uvc_trace_param & UVC_TRACE_PROBE) - printk(" <- IT %d\n", entity->id); + printk(KERN_CONT " <- IT %d\n", entity->id); } else { if (uvc_trace_param & UVC_TRACE_PROBE) - printk(" OT %d", entity->id); + printk(KERN_CONT " OT %d", entity->id); } break; @@ -1416,9 +1436,9 @@ static int uvc_scan_chain_forward(struct uvc_video_chain *chain, list_add_tail(&forward->chain, &chain->entities); if (uvc_trace_param & UVC_TRACE_PROBE) { if (!found) - printk(" (->"); + printk(KERN_CONT " (->"); - printk(" XU %d", forward->id); + printk(KERN_CONT " XU %d", forward->id); found = 1; } break; @@ -1436,16 +1456,16 @@ static int uvc_scan_chain_forward(struct uvc_video_chain *chain, list_add_tail(&forward->chain, &chain->entities); if (uvc_trace_param & UVC_TRACE_PROBE) { if (!found) - printk(" (->"); + printk(KERN_CONT " (->"); - printk(" OT %d", forward->id); + printk(KERN_CONT " OT %d", forward->id); found = 1; } break; } } if (found) - printk(")"); + printk(KERN_CONT ")"); return 0; } @@ -1471,7 +1491,7 @@ static int uvc_scan_chain_backward(struct uvc_video_chain *chain, } if (uvc_trace_param & UVC_TRACE_PROBE) - printk(" <- IT"); + printk(KERN_CONT " <- IT"); chain->selector = entity; for (i = 0; i < entity->bNrInPins; ++i) { @@ -1485,14 +1505,14 @@ static int uvc_scan_chain_backward(struct uvc_video_chain *chain, } if (uvc_trace_param & UVC_TRACE_PROBE) - printk(" %d", term->id); + printk(KERN_CONT " %d", term->id); list_add_tail(&term->chain, &chain->entities); uvc_scan_chain_forward(chain, term, entity); } if (uvc_trace_param & UVC_TRACE_PROBE) - printk("\n"); + printk(KERN_CONT "\n"); id = 0; break; @@ -1595,6 +1615,114 @@ static const char *uvc_print_chain(struct uvc_video_chain *chain) return buffer; } +static struct uvc_video_chain *uvc_alloc_chain(struct uvc_device *dev) +{ + struct uvc_video_chain *chain; + + chain = kzalloc(sizeof(*chain), GFP_KERNEL); + if (chain == NULL) + return NULL; + + INIT_LIST_HEAD(&chain->entities); + mutex_init(&chain->ctrl_mutex); + chain->dev = dev; + v4l2_prio_init(&chain->prio); + + return chain; +} + +/* + * Fallback heuristic for devices that don't connect units and terminals in a + * valid chain. + * + * Some devices have invalid baSourceID references, causing uvc_scan_chain() + * to fail, but if we just take the entities we can find and put them together + * in the most sensible chain we can think of, turns out they do work anyway. + * Note: This heuristic assumes there is a single chain. + * + * At the time of writing, devices known to have such a broken chain are + * - Acer Integrated Camera (5986:055a) + * - Realtek rtl157a7 (0bda:57a7) + */ +static int uvc_scan_fallback(struct uvc_device *dev) +{ + struct uvc_video_chain *chain; + struct uvc_entity *iterm = NULL; + struct uvc_entity *oterm = NULL; + struct uvc_entity *entity; + struct uvc_entity *prev; + + /* + * Start by locating the input and output terminals. We only support + * devices with exactly one of each for now. + */ + list_for_each_entry(entity, &dev->entities, list) { + if (UVC_ENTITY_IS_ITERM(entity)) { + if (iterm) + return -EINVAL; + iterm = entity; + } + + if (UVC_ENTITY_IS_OTERM(entity)) { + if (oterm) + return -EINVAL; + oterm = entity; + } + } + + if (iterm == NULL || oterm == NULL) + return -EINVAL; + + /* Allocate the chain and fill it. */ + chain = uvc_alloc_chain(dev); + if (chain == NULL) + return -ENOMEM; + + if (uvc_scan_chain_entity(chain, oterm) < 0) + goto error; + + prev = oterm; + + /* + * Add all Processing and Extension Units with two pads. The order + * doesn't matter much, use reverse list traversal to connect units in + * UVC descriptor order as we build the chain from output to input. This + * leads to units appearing in the order meant by the manufacturer for + * the cameras known to require this heuristic. + */ + list_for_each_entry_reverse(entity, &dev->entities, list) { + if (entity->type != UVC_VC_PROCESSING_UNIT && + entity->type != UVC_VC_EXTENSION_UNIT) + continue; + + if (entity->num_pads != 2) + continue; + + if (uvc_scan_chain_entity(chain, entity) < 0) + goto error; + + prev->baSourceID[0] = entity->id; + prev = entity; + } + + if (uvc_scan_chain_entity(chain, iterm) < 0) + goto error; + + prev->baSourceID[0] = iterm->id; + + list_add_tail(&chain->list, &dev->chains); + + uvc_trace(UVC_TRACE_PROBE, + "Found a video chain by fallback heuristic (%s).\n", + uvc_print_chain(chain)); + + return 0; + +error: + kfree(chain); + return -EINVAL; +} + /* * Scan the device for video chains and register video devices. * @@ -1617,15 +1745,10 @@ static int uvc_scan_device(struct uvc_device *dev) if (term->chain.next || term->chain.prev) continue; - chain = kzalloc(sizeof(*chain), GFP_KERNEL); + chain = uvc_alloc_chain(dev); if (chain == NULL) return -ENOMEM; - INIT_LIST_HEAD(&chain->entities); - mutex_init(&chain->ctrl_mutex); - chain->dev = dev; - v4l2_prio_init(&chain->prio); - term->flags |= UVC_ENTITY_FLAG_DEFAULT; if (uvc_scan_chain(chain, term) < 0) { @@ -1639,6 +1762,9 @@ static int uvc_scan_device(struct uvc_device *dev) list_add_tail(&chain->list, &dev->chains); } + if (list_empty(&dev->chains)) + uvc_scan_fallback(dev); + if (list_empty(&dev->chains)) { uvc_printk(KERN_INFO, "No valid video chain found.\n"); return -1; @@ -2564,6 +2690,15 @@ static struct usb_device_id uvc_ids[] = { .bInterfaceSubClass = 1, .bInterfaceProtocol = 0, .driver_info = UVC_QUIRK_FORCE_Y8 }, + /* Oculus VR Rift Sensor */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x2833, + .idProduct = 0x0211, + .bInterfaceClass = USB_CLASS_VENDOR_SPEC, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = UVC_QUIRK_FORCE_Y8 }, /* Generic USB Video Class */ { USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, UVC_PC_PROTOCOL_UNDEFINED) }, { USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, UVC_PC_PROTOCOL_15) }, |