diff options
Diffstat (limited to 'drivers/media/usb/uvc/uvc_driver.c')
-rw-r--r-- | drivers/media/usb/uvc/uvc_driver.c | 552 |
1 files changed, 357 insertions, 195 deletions
diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c index ddb9eaa11be7..30ef2a3110f7 100644 --- a/drivers/media/usb/uvc/uvc_driver.c +++ b/drivers/media/usb/uvc/uvc_driver.c @@ -7,6 +7,7 @@ */ #include <linux/atomic.h> +#include <linux/gpio/consumer.h> #include <linux/kernel.h> #include <linux/list.h> #include <linux/module.h> @@ -31,7 +32,7 @@ unsigned int uvc_clock_param = CLOCK_MONOTONIC; unsigned int uvc_hw_timestamps_param; unsigned int uvc_no_drop_param; static unsigned int uvc_quirks_param = -1; -unsigned int uvc_trace_param; +unsigned int uvc_dbg_param; unsigned int uvc_timeout_param = UVC_CTRL_STREAMING_TIMEOUT; /* ------------------------------------------------------------------------ @@ -519,10 +520,10 @@ static int uvc_parse_format(struct uvc_device *dev, case UVC_VS_FORMAT_FRAME_BASED: n = buffer[2] == UVC_VS_FORMAT_UNCOMPRESSED ? 27 : 28; if (buflen < n) { - uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming " - "interface %d FORMAT error\n", - dev->udev->devnum, - alts->desc.bInterfaceNumber); + uvc_dbg(dev, DESCR, + "device %d videostreaming interface %d FORMAT error\n", + dev->udev->devnum, + alts->desc.bInterfaceNumber); return -EINVAL; } @@ -534,8 +535,8 @@ static int uvc_parse_format(struct uvc_device *dev, sizeof(format->name)); format->fcc = fmtdesc->fcc; } else { - uvc_printk(KERN_INFO, "Unknown video format %pUl\n", - &buffer[5]); + dev_info(&streaming->intf->dev, + "Unknown video format %pUl\n", &buffer[5]); snprintf(format->name, sizeof(format->name), "%pUl\n", &buffer[5]); format->fcc = 0; @@ -583,10 +584,10 @@ static int uvc_parse_format(struct uvc_device *dev, case UVC_VS_FORMAT_MJPEG: if (buflen < 11) { - uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming " - "interface %d FORMAT error\n", - dev->udev->devnum, - alts->desc.bInterfaceNumber); + uvc_dbg(dev, DESCR, + "device %d videostreaming interface %d FORMAT error\n", + dev->udev->devnum, + alts->desc.bInterfaceNumber); return -EINVAL; } @@ -599,10 +600,10 @@ static int uvc_parse_format(struct uvc_device *dev, case UVC_VS_FORMAT_DV: if (buflen < 9) { - uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming " - "interface %d FORMAT error\n", - dev->udev->devnum, - alts->desc.bInterfaceNumber); + uvc_dbg(dev, DESCR, + "device %d videostreaming interface %d FORMAT error\n", + dev->udev->devnum, + alts->desc.bInterfaceNumber); return -EINVAL; } @@ -617,10 +618,10 @@ static int uvc_parse_format(struct uvc_device *dev, strscpy(format->name, "HD-DV", sizeof(format->name)); break; default: - uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming " - "interface %d: unknown DV format %u\n", - dev->udev->devnum, - alts->desc.bInterfaceNumber, buffer[8]); + uvc_dbg(dev, DESCR, + "device %d videostreaming interface %d: unknown DV format %u\n", + dev->udev->devnum, + alts->desc.bInterfaceNumber, buffer[8]); return -EINVAL; } @@ -646,14 +647,14 @@ static int uvc_parse_format(struct uvc_device *dev, case UVC_VS_FORMAT_STREAM_BASED: /* Not supported yet. */ default: - uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming " - "interface %d unsupported format %u\n", - dev->udev->devnum, alts->desc.bInterfaceNumber, - buffer[2]); + uvc_dbg(dev, DESCR, + "device %d videostreaming interface %d unsupported format %u\n", + dev->udev->devnum, alts->desc.bInterfaceNumber, + buffer[2]); return -EINVAL; } - uvc_trace(UVC_TRACE_DESCR, "Found format %s.\n", format->name); + uvc_dbg(dev, DESCR, "Found format %s\n", format->name); buflen -= buffer[0]; buffer += buffer[0]; @@ -672,9 +673,10 @@ static int uvc_parse_format(struct uvc_device *dev, n = n ? n : 3; if (buflen < 26 + 4*n) { - uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming " - "interface %d FRAME error\n", dev->udev->devnum, - alts->desc.bInterfaceNumber); + uvc_dbg(dev, DESCR, + "device %d videostreaming interface %d FRAME error\n", + dev->udev->devnum, + alts->desc.bInterfaceNumber); return -EINVAL; } @@ -736,10 +738,10 @@ static int uvc_parse_format(struct uvc_device *dev, frame->dwDefaultFrameInterval; } - uvc_trace(UVC_TRACE_DESCR, "- %ux%u (%u.%u fps)\n", + uvc_dbg(dev, DESCR, "- %ux%u (%u.%u fps)\n", frame->wWidth, frame->wHeight, - 10000000/frame->dwDefaultFrameInterval, - (100000000/frame->dwDefaultFrameInterval)%10); + 10000000 / frame->dwDefaultFrameInterval, + (100000000 / frame->dwDefaultFrameInterval) % 10); format->nframes++; buflen -= buffer[0]; @@ -755,10 +757,10 @@ static int uvc_parse_format(struct uvc_device *dev, if (buflen > 2 && buffer[1] == USB_DT_CS_INTERFACE && buffer[2] == UVC_VS_COLORFORMAT) { if (buflen < 6) { - uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming " - "interface %d COLORFORMAT error\n", - dev->udev->devnum, - alts->desc.bInterfaceNumber); + uvc_dbg(dev, DESCR, + "device %d videostreaming interface %d COLORFORMAT error\n", + dev->udev->devnum, + alts->desc.bInterfaceNumber); return -EINVAL; } @@ -790,15 +792,17 @@ static int uvc_parse_streaming(struct uvc_device *dev, if (intf->cur_altsetting->desc.bInterfaceSubClass != UVC_SC_VIDEOSTREAMING) { - uvc_trace(UVC_TRACE_DESCR, "device %d interface %d isn't a " - "video streaming interface\n", dev->udev->devnum, + uvc_dbg(dev, DESCR, + "device %d interface %d isn't a video streaming interface\n", + dev->udev->devnum, intf->altsetting[0].desc.bInterfaceNumber); return -EINVAL; } if (usb_driver_claim_interface(&uvc_driver.driver, intf, dev)) { - uvc_trace(UVC_TRACE_DESCR, "device %d interface %d is already " - "claimed\n", dev->udev->devnum, + uvc_dbg(dev, DESCR, + "device %d interface %d is already claimed\n", + dev->udev->devnum, intf->altsetting[0].desc.bInterfaceNumber); return -EINVAL; } @@ -821,8 +825,9 @@ static int uvc_parse_streaming(struct uvc_device *dev, if (ep->extralen > 2 && ep->extra[1] == USB_DT_CS_INTERFACE) { - uvc_trace(UVC_TRACE_DESCR, "trying extra data " - "from endpoint %u.\n", i); + uvc_dbg(dev, DESCR, + "trying extra data from endpoint %u\n", + i); buffer = alts->endpoint[i].extra; buflen = alts->endpoint[i].extralen; break; @@ -837,8 +842,8 @@ static int uvc_parse_streaming(struct uvc_device *dev, } if (buflen <= 2) { - uvc_trace(UVC_TRACE_DESCR, "no class-specific streaming " - "interface descriptors found.\n"); + uvc_dbg(dev, DESCR, + "no class-specific streaming interface descriptors found\n"); goto error; } @@ -855,9 +860,9 @@ static int uvc_parse_streaming(struct uvc_device *dev, break; default: - uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming interface " - "%d HEADER descriptor not found.\n", dev->udev->devnum, - alts->desc.bInterfaceNumber); + uvc_dbg(dev, DESCR, + "device %d videostreaming interface %d HEADER descriptor not found\n", + dev->udev->devnum, alts->desc.bInterfaceNumber); goto error; } @@ -865,8 +870,8 @@ static int uvc_parse_streaming(struct uvc_device *dev, n = buflen >= size ? buffer[size-1] : 0; if (buflen < size + p*n) { - uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming " - "interface %d HEADER descriptor is invalid.\n", + uvc_dbg(dev, DESCR, + "device %d videostreaming interface %d HEADER descriptor is invalid\n", dev->udev->devnum, alts->desc.bInterfaceNumber); goto error; } @@ -917,8 +922,8 @@ static int uvc_parse_streaming(struct uvc_device *dev, case UVC_VS_FORMAT_MPEG2TS: case UVC_VS_FORMAT_STREAM_BASED: - uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming " - "interface %d FORMAT %u is not supported.\n", + uvc_dbg(dev, DESCR, + "device %d videostreaming interface %d FORMAT %u is not supported\n", dev->udev->devnum, alts->desc.bInterfaceNumber, _buffer[2]); break; @@ -942,8 +947,8 @@ static int uvc_parse_streaming(struct uvc_device *dev, } if (nformats == 0) { - uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming interface " - "%d has no supported formats defined.\n", + uvc_dbg(dev, DESCR, + "device %d videostreaming interface %d has no supported formats defined\n", dev->udev->devnum, alts->desc.bInterfaceNumber); goto error; } @@ -991,8 +996,8 @@ static int uvc_parse_streaming(struct uvc_device *dev, } if (buflen) - uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming interface " - "%d has %u bytes of trailing descriptor garbage.\n", + uvc_dbg(dev, DESCR, + "device %d videostreaming interface %d has %u bytes of trailing descriptor garbage\n", dev->udev->devnum, alts->desc.bInterfaceNumber, buflen); /* Parse the alternate settings to find the maximum bandwidth. */ @@ -1019,7 +1024,13 @@ error: return ret; } -static struct uvc_entity *uvc_alloc_entity(u16 type, u8 id, +static const u8 uvc_camera_guid[16] = UVC_GUID_UVC_CAMERA; +static const u8 uvc_gpio_guid[16] = UVC_GUID_EXT_GPIO_CONTROLLER; +static const u8 uvc_media_transport_input_guid[16] = + UVC_GUID_UVC_MEDIA_TRANSPORT_INPUT; +static const u8 uvc_processing_guid[16] = UVC_GUID_UVC_PROCESSING; + +static struct uvc_entity *uvc_alloc_entity(u16 type, u16 id, unsigned int num_pads, unsigned int extra_size) { struct uvc_entity *entity; @@ -1028,7 +1039,10 @@ static struct uvc_entity *uvc_alloc_entity(u16 type, u8 id, unsigned int i; extra_size = roundup(extra_size, sizeof(*entity->pads)); - num_inputs = (type & UVC_TERM_OUTPUT) ? num_pads : num_pads - 1; + if (num_pads) + num_inputs = type & UVC_TERM_OUTPUT ? num_pads : num_pads - 1; + else + num_inputs = 0; size = sizeof(*entity) + extra_size + sizeof(*entity->pads) * num_pads + num_inputs; entity = kzalloc(size, GFP_KERNEL); @@ -1038,13 +1052,32 @@ static struct uvc_entity *uvc_alloc_entity(u16 type, u8 id, entity->id = id; entity->type = type; + /* + * Set the GUID for standard entity types. For extension units, the GUID + * is initialized by the caller. + */ + switch (type) { + case UVC_EXT_GPIO_UNIT: + memcpy(entity->guid, uvc_gpio_guid, 16); + break; + case UVC_ITT_CAMERA: + memcpy(entity->guid, uvc_camera_guid, 16); + break; + case UVC_ITT_MEDIA_TRANSPORT_INPUT: + memcpy(entity->guid, uvc_media_transport_input_guid, 16); + break; + case UVC_VC_PROCESSING_UNIT: + memcpy(entity->guid, uvc_processing_guid, 16); + break; + } + entity->num_links = 0; entity->num_pads = num_pads; entity->pads = ((void *)(entity + 1)) + extra_size; for (i = 0; i < num_inputs; ++i) entity->pads[i].flags = MEDIA_PAD_FL_SINK; - if (!UVC_ENTITY_IS_OTERM(entity)) + if (!UVC_ENTITY_IS_OTERM(entity) && num_pads) entity->pads[num_pads-1].flags = MEDIA_PAD_FL_SOURCE; entity->bNrInPins = num_inputs; @@ -1098,8 +1131,8 @@ static int uvc_parse_vendor_control(struct uvc_device *dev, n = buflen >= 25 + p ? buffer[22+p] : 0; if (buflen < 25 + p + 2*n) { - uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol " - "interface %d EXTENSION_UNIT error\n", + uvc_dbg(dev, DESCR, + "device %d videocontrol interface %d EXTENSION_UNIT error\n", udev->devnum, alts->desc.bInterfaceNumber); break; } @@ -1109,7 +1142,7 @@ static int uvc_parse_vendor_control(struct uvc_device *dev, if (unit == NULL) return -ENOMEM; - memcpy(unit->extension.guidExtensionCode, &buffer[4], 16); + memcpy(unit->guid, &buffer[4], 16); unit->extension.bNumControls = buffer[20]; memcpy(unit->baSourceID, &buffer[22], p); unit->extension.bControlSize = buffer[22+p]; @@ -1147,9 +1180,9 @@ static int uvc_parse_standard_control(struct uvc_device *dev, n = buflen >= 12 ? buffer[11] : 0; if (buflen < 12 + n) { - uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol " - "interface %d HEADER error\n", udev->devnum, - alts->desc.bInterfaceNumber); + uvc_dbg(dev, DESCR, + "device %d videocontrol interface %d HEADER error\n", + udev->devnum, alts->desc.bInterfaceNumber); return -EINVAL; } @@ -1160,8 +1193,8 @@ static int uvc_parse_standard_control(struct uvc_device *dev, for (i = 0; i < n; ++i) { intf = usb_ifnum_to_if(udev, buffer[12+i]); if (intf == NULL) { - uvc_trace(UVC_TRACE_DESCR, "device %d " - "interface %d doesn't exists\n", + uvc_dbg(dev, DESCR, + "device %d interface %d doesn't exists\n", udev->devnum, i); continue; } @@ -1172,8 +1205,8 @@ static int uvc_parse_standard_control(struct uvc_device *dev, case UVC_VC_INPUT_TERMINAL: if (buflen < 8) { - uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol " - "interface %d INPUT_TERMINAL error\n", + uvc_dbg(dev, DESCR, + "device %d videocontrol interface %d INPUT_TERMINAL error\n", udev->devnum, alts->desc.bInterfaceNumber); return -EINVAL; } @@ -1191,10 +1224,9 @@ static int uvc_parse_standard_control(struct uvc_device *dev, */ 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, + uvc_dbg(dev, 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; } @@ -1214,8 +1246,8 @@ static int uvc_parse_standard_control(struct uvc_device *dev, } if (buflen < len + n + p) { - uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol " - "interface %d INPUT_TERMINAL error\n", + uvc_dbg(dev, DESCR, + "device %d videocontrol interface %d INPUT_TERMINAL error\n", udev->devnum, alts->desc.bInterfaceNumber); return -EINVAL; } @@ -1261,8 +1293,8 @@ static int uvc_parse_standard_control(struct uvc_device *dev, case UVC_VC_OUTPUT_TERMINAL: if (buflen < 9) { - uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol " - "interface %d OUTPUT_TERMINAL error\n", + uvc_dbg(dev, DESCR, + "device %d videocontrol interface %d OUTPUT_TERMINAL error\n", udev->devnum, alts->desc.bInterfaceNumber); return -EINVAL; } @@ -1272,10 +1304,10 @@ static int uvc_parse_standard_control(struct uvc_device *dev, */ type = get_unaligned_le16(&buffer[4]); if ((type & 0xff00) == 0) { - uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol " - "interface %d OUTPUT_TERMINAL %d has invalid " - "type 0x%04x, skipping\n", udev->devnum, - alts->desc.bInterfaceNumber, buffer[3], type); + uvc_dbg(dev, DESCR, + "device %d videocontrol interface %d OUTPUT_TERMINAL %d has invalid type 0x%04x, skipping\n", + udev->devnum, alts->desc.bInterfaceNumber, + buffer[3], type); return 0; } @@ -1299,8 +1331,8 @@ static int uvc_parse_standard_control(struct uvc_device *dev, p = buflen >= 5 ? buffer[4] : 0; if (buflen < 5 || buflen < 6 + p) { - uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol " - "interface %d SELECTOR_UNIT error\n", + uvc_dbg(dev, DESCR, + "device %d videocontrol interface %d SELECTOR_UNIT error\n", udev->devnum, alts->desc.bInterfaceNumber); return -EINVAL; } @@ -1325,8 +1357,8 @@ static int uvc_parse_standard_control(struct uvc_device *dev, p = dev->uvc_version >= 0x0110 ? 10 : 9; if (buflen < p + n) { - uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol " - "interface %d PROCESSING_UNIT error\n", + uvc_dbg(dev, DESCR, + "device %d videocontrol interface %d PROCESSING_UNIT error\n", udev->devnum, alts->desc.bInterfaceNumber); return -EINVAL; } @@ -1358,8 +1390,8 @@ static int uvc_parse_standard_control(struct uvc_device *dev, n = buflen >= 24 + p ? buffer[22+p] : 0; if (buflen < 24 + p + n) { - uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol " - "interface %d EXTENSION_UNIT error\n", + uvc_dbg(dev, DESCR, + "device %d videocontrol interface %d EXTENSION_UNIT error\n", udev->devnum, alts->desc.bInterfaceNumber); return -EINVAL; } @@ -1368,7 +1400,7 @@ static int uvc_parse_standard_control(struct uvc_device *dev, if (unit == NULL) return -ENOMEM; - memcpy(unit->extension.guidExtensionCode, &buffer[4], 16); + memcpy(unit->guid, &buffer[4], 16); unit->extension.bNumControls = buffer[20]; memcpy(unit->baSourceID, &buffer[22], p); unit->extension.bControlSize = buffer[22+p]; @@ -1385,8 +1417,9 @@ static int uvc_parse_standard_control(struct uvc_device *dev, break; default: - uvc_trace(UVC_TRACE_DESCR, "Found an unknown CS_INTERFACE " - "descriptor (%u)\n", buffer[2]); + uvc_dbg(dev, DESCR, + "Found an unknown CS_INTERFACE descriptor (%u)\n", + buffer[2]); break; } @@ -1431,8 +1464,9 @@ next_descriptor: if (usb_endpoint_is_int_in(desc) && le16_to_cpu(desc->wMaxPacketSize) >= 8 && desc->bInterval != 0) { - uvc_trace(UVC_TRACE_DESCR, "Found a Status endpoint " - "(addr %02x).\n", desc->bEndpointAddress); + uvc_dbg(dev, DESCR, + "Found a Status endpoint (addr %02x)\n", + desc->bEndpointAddress); dev->int_ep = ep; } } @@ -1440,6 +1474,108 @@ next_descriptor: return 0; } +/* ----------------------------------------------------------------------------- + * Privacy GPIO + */ + +static void uvc_gpio_event(struct uvc_device *dev) +{ + struct uvc_entity *unit = dev->gpio_unit; + struct uvc_video_chain *chain; + u8 new_val; + + if (!unit) + return; + + new_val = gpiod_get_value_cansleep(unit->gpio.gpio_privacy); + + /* GPIO entities are always on the first chain. */ + chain = list_first_entry(&dev->chains, struct uvc_video_chain, list); + uvc_ctrl_status_event(chain, unit->controls, &new_val); +} + +static int uvc_gpio_get_cur(struct uvc_device *dev, struct uvc_entity *entity, + u8 cs, void *data, u16 size) +{ + if (cs != UVC_CT_PRIVACY_CONTROL || size < 1) + return -EINVAL; + + *(u8 *)data = gpiod_get_value_cansleep(entity->gpio.gpio_privacy); + + return 0; +} + +static int uvc_gpio_get_info(struct uvc_device *dev, struct uvc_entity *entity, + u8 cs, u8 *caps) +{ + if (cs != UVC_CT_PRIVACY_CONTROL) + return -EINVAL; + + *caps = UVC_CONTROL_CAP_GET | UVC_CONTROL_CAP_AUTOUPDATE; + return 0; +} + +static irqreturn_t uvc_gpio_irq(int irq, void *data) +{ + struct uvc_device *dev = data; + + uvc_gpio_event(dev); + return IRQ_HANDLED; +} + +static int uvc_gpio_parse(struct uvc_device *dev) +{ + struct uvc_entity *unit; + struct gpio_desc *gpio_privacy; + int irq; + + gpio_privacy = devm_gpiod_get_optional(&dev->udev->dev, "privacy", + GPIOD_IN); + if (IS_ERR_OR_NULL(gpio_privacy)) + return PTR_ERR_OR_ZERO(gpio_privacy); + + unit = uvc_alloc_entity(UVC_EXT_GPIO_UNIT, UVC_EXT_GPIO_UNIT_ID, 0, 1); + if (!unit) + return -ENOMEM; + + irq = gpiod_to_irq(gpio_privacy); + if (irq < 0) { + if (irq != EPROBE_DEFER) + dev_err(&dev->udev->dev, + "No IRQ for privacy GPIO (%d)\n", irq); + return irq; + } + + unit->gpio.gpio_privacy = gpio_privacy; + unit->gpio.irq = irq; + unit->gpio.bControlSize = 1; + unit->gpio.bmControls = (u8 *)unit + sizeof(*unit); + unit->gpio.bmControls[0] = 1; + unit->get_cur = uvc_gpio_get_cur; + unit->get_info = uvc_gpio_get_info; + strscpy(unit->name, "GPIO", sizeof(unit->name)); + + list_add_tail(&unit->list, &dev->entities); + + dev->gpio_unit = unit; + + return 0; +} + +static int uvc_gpio_init_irq(struct uvc_device *dev) +{ + struct uvc_entity *unit = dev->gpio_unit; + + if (!unit || unit->gpio.irq < 0) + return 0; + + return devm_request_threaded_irq(&dev->udev->dev, unit->gpio.irq, NULL, + uvc_gpio_irq, + IRQF_ONESHOT | IRQF_TRIGGER_FALLING | + IRQF_TRIGGER_RISING, + "uvc_privacy_gpio", dev); +} + /* ------------------------------------------------------------------------ * UVC device scan */ @@ -1475,24 +1611,23 @@ 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(KERN_CONT " <- XU %d", entity->id); + uvc_dbg_cont(PROBE, " <- 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); + uvc_dbg(chain->dev, DESCR, + "Extension unit %d has more than 1 input pin\n", + entity->id); return -1; } break; case UVC_VC_PROCESSING_UNIT: - if (uvc_trace_param & UVC_TRACE_PROBE) - printk(KERN_CONT " <- PU %d", entity->id); + uvc_dbg_cont(PROBE, " <- PU %d", entity->id); if (chain->processing != NULL) { - uvc_trace(UVC_TRACE_DESCR, "Found multiple " - "Processing Units in chain.\n"); + uvc_dbg(chain->dev, DESCR, + "Found multiple Processing Units in chain\n"); return -1; } @@ -1500,16 +1635,15 @@ static int uvc_scan_chain_entity(struct uvc_video_chain *chain, break; case UVC_VC_SELECTOR_UNIT: - if (uvc_trace_param & UVC_TRACE_PROBE) - printk(KERN_CONT " <- SU %d", entity->id); + uvc_dbg_cont(PROBE, " <- 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"); + uvc_dbg(chain->dev, DESCR, + "Found multiple Selector Units in chain\n"); return -1; } @@ -1519,33 +1653,29 @@ static int uvc_scan_chain_entity(struct uvc_video_chain *chain, case UVC_ITT_VENDOR_SPECIFIC: case UVC_ITT_CAMERA: case UVC_ITT_MEDIA_TRANSPORT_INPUT: - if (uvc_trace_param & UVC_TRACE_PROBE) - printk(KERN_CONT " <- IT %d\n", entity->id); + uvc_dbg_cont(PROBE, " <- IT %d\n", entity->id); break; case UVC_OTT_VENDOR_SPECIFIC: case UVC_OTT_DISPLAY: case UVC_OTT_MEDIA_TRANSPORT_OUTPUT: - if (uvc_trace_param & UVC_TRACE_PROBE) - printk(KERN_CONT " OT %d", entity->id); + uvc_dbg_cont(PROBE, " OT %d", entity->id); break; case UVC_TT_STREAMING: - if (UVC_ENTITY_IS_ITERM(entity)) { - if (uvc_trace_param & UVC_TRACE_PROBE) - printk(KERN_CONT " <- IT %d\n", entity->id); - } else { - if (uvc_trace_param & UVC_TRACE_PROBE) - printk(KERN_CONT " OT %d", entity->id); - } + if (UVC_ENTITY_IS_ITERM(entity)) + uvc_dbg_cont(PROBE, " <- IT %d\n", entity->id); + else + uvc_dbg_cont(PROBE, " OT %d", entity->id); break; default: - uvc_trace(UVC_TRACE_DESCR, "Unsupported entity type " - "0x%04x found in chain.\n", UVC_ENTITY_TYPE(entity)); + uvc_dbg(chain->dev, DESCR, + "Unsupported entity type 0x%04x found in chain\n", + UVC_ENTITY_TYPE(entity)); return -1; } @@ -1571,28 +1701,27 @@ static int uvc_scan_chain_forward(struct uvc_video_chain *chain, if (forward == prev) continue; if (forward->chain.next || forward->chain.prev) { - uvc_trace(UVC_TRACE_DESCR, "Found reference to " - "entity %d already in chain.\n", forward->id); + uvc_dbg(chain->dev, DESCR, + "Found reference to entity %d already in chain\n", + forward->id); return -EINVAL; } switch (UVC_ENTITY_TYPE(forward)) { case UVC_VC_EXTENSION_UNIT: if (forward->bNrInPins != 1) { - uvc_trace(UVC_TRACE_DESCR, "Extension unit %d " - "has more than 1 input pin.\n", - entity->id); + uvc_dbg(chain->dev, DESCR, + "Extension unit %d has more than 1 input pin\n", + entity->id); return -EINVAL; } list_add_tail(&forward->chain, &chain->entities); - if (uvc_trace_param & UVC_TRACE_PROBE) { - if (!found) - printk(KERN_CONT " (->"); + if (!found) + uvc_dbg_cont(PROBE, " (->"); - printk(KERN_CONT " XU %d", forward->id); - found = 1; - } + uvc_dbg_cont(PROBE, " XU %d", forward->id); + found = 1; break; case UVC_OTT_VENDOR_SPECIFIC: @@ -1600,24 +1729,23 @@ static int uvc_scan_chain_forward(struct uvc_video_chain *chain, case UVC_OTT_MEDIA_TRANSPORT_OUTPUT: case UVC_TT_STREAMING: if (UVC_ENTITY_IS_ITERM(forward)) { - uvc_trace(UVC_TRACE_DESCR, "Unsupported input " - "terminal %u.\n", forward->id); + uvc_dbg(chain->dev, DESCR, + "Unsupported input terminal %u\n", + forward->id); return -EINVAL; } list_add_tail(&forward->chain, &chain->entities); - if (uvc_trace_param & UVC_TRACE_PROBE) { - if (!found) - printk(KERN_CONT " (->"); + if (!found) + uvc_dbg_cont(PROBE, " (->"); - printk(KERN_CONT " OT %d", forward->id); - found = 1; - } + uvc_dbg_cont(PROBE, " OT %d", forward->id); + found = 1; break; } } if (found) - printk(KERN_CONT ")"); + uvc_dbg_cont(PROBE, ")"); return 0; } @@ -1642,36 +1770,33 @@ static int uvc_scan_chain_backward(struct uvc_video_chain *chain, break; } - if (uvc_trace_param & UVC_TRACE_PROBE) - printk(KERN_CONT " <- IT"); + uvc_dbg_cont(PROBE, " <- IT"); chain->selector = entity; for (i = 0; i < entity->bNrInPins; ++i) { id = entity->baSourceID[i]; term = uvc_entity_by_id(chain->dev, id); 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); + uvc_dbg(chain->dev, DESCR, + "Selector unit %d input %d isn't connected to an input terminal\n", + entity->id, i); return -1; } if (term->chain.next || term->chain.prev) { - uvc_trace(UVC_TRACE_DESCR, "Found reference to " - "entity %d already in chain.\n", + uvc_dbg(chain->dev, DESCR, + "Found reference to entity %d already in chain\n", term->id); return -EINVAL; } - if (uvc_trace_param & UVC_TRACE_PROBE) - printk(KERN_CONT " %d", term->id); + uvc_dbg_cont(PROBE, " %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(KERN_CONT "\n"); + uvc_dbg_cont(PROBE, "\n"); id = 0; break; @@ -1694,8 +1819,8 @@ static int uvc_scan_chain_backward(struct uvc_video_chain *chain, entity = uvc_entity_by_id(chain->dev, id); if (entity == NULL) { - uvc_trace(UVC_TRACE_DESCR, "Found reference to " - "unknown entity %d.\n", id); + uvc_dbg(chain->dev, DESCR, + "Found reference to unknown entity %d\n", id); return -EINVAL; } @@ -1708,7 +1833,7 @@ static int uvc_scan_chain(struct uvc_video_chain *chain, { struct uvc_entity *entity, *prev; - uvc_trace(UVC_TRACE_PROBE, "Scanning UVC chain:"); + uvc_dbg(chain->dev, PROBE, "Scanning UVC chain:"); entity = term; prev = NULL; @@ -1716,8 +1841,9 @@ static int uvc_scan_chain(struct uvc_video_chain *chain, while (entity != NULL) { /* Entity must not be part of an existing chain */ if (entity->chain.next || entity->chain.prev) { - uvc_trace(UVC_TRACE_DESCR, "Found reference to " - "entity %d already in chain.\n", entity->id); + uvc_dbg(chain->dev, DESCR, + "Found reference to entity %d already in chain\n", + entity->id); return -EINVAL; } @@ -1871,9 +1997,8 @@ static int uvc_scan_fallback(struct uvc_device *dev) 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)); + uvc_dbg(dev, PROBE, "Found a video chain by fallback heuristic (%s)\n", + uvc_print_chain(chain)); return 0; @@ -1915,8 +2040,8 @@ static int uvc_scan_device(struct uvc_device *dev) continue; } - uvc_trace(UVC_TRACE_PROBE, "Found a valid video chain (%s).\n", - uvc_print_chain(chain)); + uvc_dbg(dev, PROBE, "Found a valid video chain (%s)\n", + uvc_print_chain(chain)); list_add_tail(&chain->list, &dev->chains); } @@ -1925,10 +2050,17 @@ static int uvc_scan_device(struct uvc_device *dev) uvc_scan_fallback(dev); if (list_empty(&dev->chains)) { - uvc_printk(KERN_INFO, "No valid video chain found.\n"); + dev_info(&dev->udev->dev, "No valid video chain found.\n"); return -1; } + /* Add GPIO entity to the first chain. */ + if (dev->gpio_unit) { + chain = list_first_entry(&dev->chains, + struct uvc_video_chain, list); + list_add_tail(&dev->gpio_unit->chain, &chain->entities); + } + return 0; } @@ -2077,8 +2209,9 @@ int uvc_register_video_device(struct uvc_device *dev, ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); if (ret < 0) { - uvc_printk(KERN_ERR, "Failed to register %s device (%d).\n", - v4l2_type_names[type], ret); + dev_err(&stream->intf->dev, + "Failed to register %s device (%d).\n", + v4l2_type_names[type], ret); return ret; } @@ -2094,8 +2227,8 @@ static int uvc_register_video(struct uvc_device *dev, /* Initialize the streaming interface with default parameters. */ ret = uvc_video_init(stream); if (ret < 0) { - uvc_printk(KERN_ERR, "Failed to initialize the device (%d).\n", - ret); + dev_err(&stream->intf->dev, + "Failed to initialize the device (%d).\n", ret); return ret; } @@ -2129,8 +2262,9 @@ static int uvc_register_terms(struct uvc_device *dev, stream = uvc_stream_by_id(dev, term->id); if (stream == NULL) { - uvc_printk(KERN_INFO, "No streaming interface found " - "for terminal %u.", term->id); + dev_info(&dev->udev->dev, + "No streaming interface found for terminal %u.", + term->id); continue; } @@ -2163,8 +2297,8 @@ static int uvc_register_chains(struct uvc_device *dev) #ifdef CONFIG_MEDIA_CONTROLLER ret = uvc_mc_register_entities(chain); if (ret < 0) - uvc_printk(KERN_INFO, - "Failed to register entities (%d).\n", ret); + dev_info(&dev->udev->dev, + "Failed to register entities (%d).\n", ret); #endif } @@ -2187,14 +2321,6 @@ static int uvc_probe(struct usb_interface *intf, int function; int ret; - if (id->idVendor && id->idProduct) - uvc_trace(UVC_TRACE_PROBE, "Probing known UVC device %s " - "(%04x:%04x)\n", udev->devpath, id->idVendor, - id->idProduct); - else - uvc_trace(UVC_TRACE_PROBE, "Probing generic UVC device %s\n", - udev->devpath); - /* Allocate memory for the device and initialize it. */ dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (dev == NULL) @@ -2214,6 +2340,13 @@ static int uvc_probe(struct usb_interface *intf, dev->quirks = uvc_quirks_param == -1 ? dev->info->quirks : uvc_quirks_param; + if (id->idVendor && id->idProduct) + uvc_dbg(dev, PROBE, "Probing known UVC device %s (%04x:%04x)\n", + udev->devpath, id->idVendor, id->idProduct); + else + uvc_dbg(dev, PROBE, "Probing generic UVC device %s\n", + udev->devpath); + if (udev->product != NULL) strscpy(dev->name, udev->product, sizeof(dev->name)); else @@ -2256,22 +2389,34 @@ static int uvc_probe(struct usb_interface *intf, /* Parse the Video Class control descriptor. */ if (uvc_parse_control(dev) < 0) { - uvc_trace(UVC_TRACE_PROBE, "Unable to parse UVC " - "descriptors.\n"); + uvc_dbg(dev, PROBE, "Unable to parse UVC descriptors\n"); + goto error; + } + + /* Parse the associated GPIOs. */ + if (uvc_gpio_parse(dev) < 0) { + uvc_dbg(dev, PROBE, "Unable to parse UVC GPIOs\n"); goto error; } - uvc_printk(KERN_INFO, "Found UVC %u.%02x device %s (%04x:%04x)\n", - dev->uvc_version >> 8, dev->uvc_version & 0xff, - udev->product ? udev->product : "<unnamed>", - le16_to_cpu(udev->descriptor.idVendor), - le16_to_cpu(udev->descriptor.idProduct)); + dev_info(&dev->udev->dev, "Found UVC %u.%02x device %s (%04x:%04x)\n", + dev->uvc_version >> 8, dev->uvc_version & 0xff, + udev->product ? udev->product : "<unnamed>", + le16_to_cpu(udev->descriptor.idVendor), + le16_to_cpu(udev->descriptor.idProduct)); if (dev->quirks != dev->info->quirks) { - uvc_printk(KERN_INFO, "Forcing device quirks to 0x%x by module " - "parameter for testing purpose.\n", dev->quirks); - uvc_printk(KERN_INFO, "Please report required quirks to the " - "linux-uvc-devel mailing list.\n"); + dev_info(&dev->udev->dev, + "Forcing device quirks to 0x%x by module parameter for testing purpose.\n", + dev->quirks); + dev_info(&dev->udev->dev, + "Please report required quirks to the linux-uvc-devel mailing list.\n"); + } + + if (dev->info->uvc_version) { + dev->uvc_version = dev->info->uvc_version; + dev_info(&dev->udev->dev, "Forcing UVC version to %u.%02x\n", + dev->uvc_version >> 8, dev->uvc_version & 0xff); } /* Register the V4L2 device. */ @@ -2300,12 +2445,19 @@ static int uvc_probe(struct usb_interface *intf, /* Initialize the interrupt URB. */ if ((ret = uvc_status_init(dev)) < 0) { - uvc_printk(KERN_INFO, "Unable to initialize the status " - "endpoint (%d), status interrupt will not be " - "supported.\n", ret); + dev_info(&dev->udev->dev, + "Unable to initialize the status endpoint (%d), status interrupt will not be supported.\n", + ret); } - uvc_trace(UVC_TRACE_PROBE, "UVC device initialized.\n"); + ret = uvc_gpio_init_irq(dev); + if (ret < 0) { + dev_err(&dev->udev->dev, + "Unable to request privacy GPIO IRQ (%d)\n", ret); + goto error; + } + + uvc_dbg(dev, PROBE, "UVC device initialized\n"); usb_enable_autosuspend(udev); return 0; @@ -2337,7 +2489,7 @@ static int uvc_suspend(struct usb_interface *intf, pm_message_t message) struct uvc_device *dev = usb_get_intfdata(intf); struct uvc_streaming *stream; - uvc_trace(UVC_TRACE_SUSPEND, "Suspending interface %u\n", + uvc_dbg(dev, SUSPEND, "Suspending interface %u\n", intf->cur_altsetting->desc.bInterfaceNumber); /* Controls are cached on the fly so they don't need to be saved. */ @@ -2355,8 +2507,8 @@ static int uvc_suspend(struct usb_interface *intf, pm_message_t message) return uvc_video_suspend(stream); } - uvc_trace(UVC_TRACE_SUSPEND, "Suspend: video streaming USB interface " - "mismatch.\n"); + uvc_dbg(dev, SUSPEND, + "Suspend: video streaming USB interface mismatch\n"); return -EINVAL; } @@ -2366,7 +2518,7 @@ static int __uvc_resume(struct usb_interface *intf, int reset) struct uvc_streaming *stream; int ret = 0; - uvc_trace(UVC_TRACE_SUSPEND, "Resuming interface %u\n", + uvc_dbg(dev, SUSPEND, "Resuming interface %u\n", intf->cur_altsetting->desc.bInterfaceNumber); if (intf->cur_altsetting->desc.bInterfaceSubClass == @@ -2395,8 +2547,8 @@ static int __uvc_resume(struct usb_interface *intf, int reset) } } - uvc_trace(UVC_TRACE_SUSPEND, "Resume: video streaming USB interface " - "mismatch.\n"); + uvc_dbg(dev, SUSPEND, + "Resume: video streaming USB interface mismatch\n"); return -EINVAL; } @@ -2446,7 +2598,7 @@ module_param_named(nodrop, uvc_no_drop_param, uint, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(nodrop, "Don't drop incomplete frames"); module_param_named(quirks, uvc_quirks_param, uint, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(quirks, "Forced device quirks"); -module_param_named(trace, uvc_trace_param, uint, S_IRUGO|S_IWUSR); +module_param_named(trace, uvc_dbg_param, uint, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(trace, "Trace level bitmask"); module_param_named(timeout, uvc_timeout_param, uint, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(timeout, "Streaming control requests timeout"); @@ -2923,6 +3075,17 @@ static const struct usb_device_id uvc_ids[] = { .bInterfaceSubClass = 1, .bInterfaceProtocol = 0, .driver_info = (kernel_ulong_t)&uvc_quirk_probe_minmax }, + /* Shenzhen Aoni Electronic Co.,Ltd 2K FHD camera */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x1bcf, + .idProduct = 0x0b40, + .bInterfaceClass = USB_CLASS_VIDEO, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = (kernel_ulong_t)&(const struct uvc_device_info){ + .uvc_version = 0x010a, + } }, /* SiGma Micro USB Web Camera */ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_INT_INFO, @@ -3002,7 +3165,6 @@ static int __init uvc_init(void) return ret; } - printk(KERN_INFO DRIVER_DESC " (" DRIVER_VERSION ")\n"); return 0; } |