|
7 | 7 | */
|
8 | 8 |
|
9 | 9 | #include <linux/atomic.h>
|
| 10 | +#include <linux/gpio/consumer.h> |
10 | 11 | #include <linux/kernel.h>
|
11 | 12 | #include <linux/list.h>
|
12 | 13 | #include <linux/module.h>
|
@@ -1020,6 +1021,7 @@ static int uvc_parse_streaming(struct uvc_device *dev,
|
1020 | 1021 | }
|
1021 | 1022 |
|
1022 | 1023 | static const u8 uvc_camera_guid[16] = UVC_GUID_UVC_CAMERA;
|
| 1024 | +static const u8 uvc_gpio_guid[16] = UVC_GUID_EXT_GPIO_CONTROLLER; |
1023 | 1025 | static const u8 uvc_media_transport_input_guid[16] =
|
1024 | 1026 | UVC_GUID_UVC_MEDIA_TRANSPORT_INPUT;
|
1025 | 1027 | static const u8 uvc_processing_guid[16] = UVC_GUID_UVC_PROCESSING;
|
@@ -1051,6 +1053,9 @@ static struct uvc_entity *uvc_alloc_entity(u16 type, u16 id,
|
1051 | 1053 | * is initialized by the caller.
|
1052 | 1054 | */
|
1053 | 1055 | switch (type) {
|
| 1056 | + case UVC_EXT_GPIO_UNIT: |
| 1057 | + memcpy(entity->guid, uvc_gpio_guid, 16); |
| 1058 | + break; |
1054 | 1059 | case UVC_ITT_CAMERA:
|
1055 | 1060 | memcpy(entity->guid, uvc_camera_guid, 16);
|
1056 | 1061 | break;
|
@@ -1464,6 +1469,108 @@ static int uvc_parse_control(struct uvc_device *dev)
|
1464 | 1469 | return 0;
|
1465 | 1470 | }
|
1466 | 1471 |
|
| 1472 | +/* ----------------------------------------------------------------------------- |
| 1473 | + * Privacy GPIO |
| 1474 | + */ |
| 1475 | + |
| 1476 | +static void uvc_gpio_event(struct uvc_device *dev) |
| 1477 | +{ |
| 1478 | + struct uvc_entity *unit = dev->gpio_unit; |
| 1479 | + struct uvc_video_chain *chain; |
| 1480 | + u8 new_val; |
| 1481 | + |
| 1482 | + if (!unit) |
| 1483 | + return; |
| 1484 | + |
| 1485 | + new_val = gpiod_get_value_cansleep(unit->gpio.gpio_privacy); |
| 1486 | + |
| 1487 | + /* GPIO entities are always on the first chain. */ |
| 1488 | + chain = list_first_entry(&dev->chains, struct uvc_video_chain, list); |
| 1489 | + uvc_ctrl_status_event(chain, unit->controls, &new_val); |
| 1490 | +} |
| 1491 | + |
| 1492 | +static int uvc_gpio_get_cur(struct uvc_device *dev, struct uvc_entity *entity, |
| 1493 | + u8 cs, void *data, u16 size) |
| 1494 | +{ |
| 1495 | + if (cs != UVC_CT_PRIVACY_CONTROL || size < 1) |
| 1496 | + return -EINVAL; |
| 1497 | + |
| 1498 | + *(u8 *)data = gpiod_get_value_cansleep(entity->gpio.gpio_privacy); |
| 1499 | + |
| 1500 | + return 0; |
| 1501 | +} |
| 1502 | + |
| 1503 | +static int uvc_gpio_get_info(struct uvc_device *dev, struct uvc_entity *entity, |
| 1504 | + u8 cs, u8 *caps) |
| 1505 | +{ |
| 1506 | + if (cs != UVC_CT_PRIVACY_CONTROL) |
| 1507 | + return -EINVAL; |
| 1508 | + |
| 1509 | + *caps = UVC_CONTROL_CAP_GET | UVC_CONTROL_CAP_AUTOUPDATE; |
| 1510 | + return 0; |
| 1511 | +} |
| 1512 | + |
| 1513 | +static irqreturn_t uvc_gpio_irq(int irq, void *data) |
| 1514 | +{ |
| 1515 | + struct uvc_device *dev = data; |
| 1516 | + |
| 1517 | + uvc_gpio_event(dev); |
| 1518 | + return IRQ_HANDLED; |
| 1519 | +} |
| 1520 | + |
| 1521 | +static int uvc_gpio_parse(struct uvc_device *dev) |
| 1522 | +{ |
| 1523 | + struct uvc_entity *unit; |
| 1524 | + struct gpio_desc *gpio_privacy; |
| 1525 | + int irq; |
| 1526 | + |
| 1527 | + gpio_privacy = devm_gpiod_get_optional(&dev->udev->dev, "privacy", |
| 1528 | + GPIOD_IN); |
| 1529 | + if (IS_ERR_OR_NULL(gpio_privacy)) |
| 1530 | + return PTR_ERR_OR_ZERO(gpio_privacy); |
| 1531 | + |
| 1532 | + unit = uvc_alloc_entity(UVC_EXT_GPIO_UNIT, UVC_EXT_GPIO_UNIT_ID, 0, 1); |
| 1533 | + if (!unit) |
| 1534 | + return -ENOMEM; |
| 1535 | + |
| 1536 | + irq = gpiod_to_irq(gpio_privacy); |
| 1537 | + if (irq < 0) { |
| 1538 | + if (irq != EPROBE_DEFER) |
| 1539 | + dev_err(&dev->udev->dev, |
| 1540 | + "No IRQ for privacy GPIO (%d)\n", irq); |
| 1541 | + return irq; |
| 1542 | + } |
| 1543 | + |
| 1544 | + unit->gpio.gpio_privacy = gpio_privacy; |
| 1545 | + unit->gpio.irq = irq; |
| 1546 | + unit->gpio.bControlSize = 1; |
| 1547 | + unit->gpio.bmControls = (u8 *)unit + sizeof(*unit); |
| 1548 | + unit->gpio.bmControls[0] = 1; |
| 1549 | + unit->get_cur = uvc_gpio_get_cur; |
| 1550 | + unit->get_info = uvc_gpio_get_info; |
| 1551 | + strncpy(unit->name, "GPIO", sizeof(unit->name) - 1); |
| 1552 | + |
| 1553 | + list_add_tail(&unit->list, &dev->entities); |
| 1554 | + |
| 1555 | + dev->gpio_unit = unit; |
| 1556 | + |
| 1557 | + return 0; |
| 1558 | +} |
| 1559 | + |
| 1560 | +static int uvc_gpio_init_irq(struct uvc_device *dev) |
| 1561 | +{ |
| 1562 | + struct uvc_entity *unit = dev->gpio_unit; |
| 1563 | + |
| 1564 | + if (!unit || unit->gpio.irq < 0) |
| 1565 | + return 0; |
| 1566 | + |
| 1567 | + return devm_request_threaded_irq(&dev->udev->dev, unit->gpio.irq, NULL, |
| 1568 | + uvc_gpio_irq, |
| 1569 | + IRQF_ONESHOT | IRQF_TRIGGER_FALLING | |
| 1570 | + IRQF_TRIGGER_RISING, |
| 1571 | + "uvc_privacy_gpio", dev); |
| 1572 | +} |
| 1573 | + |
1467 | 1574 | /* ------------------------------------------------------------------------
|
1468 | 1575 | * UVC device scan
|
1469 | 1576 | */
|
@@ -1953,6 +2060,13 @@ static int uvc_scan_device(struct uvc_device *dev)
|
1953 | 2060 | return -1;
|
1954 | 2061 | }
|
1955 | 2062 |
|
| 2063 | + /* Add GPIO entity to the first chain. */ |
| 2064 | + if (dev->gpio_unit) { |
| 2065 | + chain = list_first_entry(&dev->chains, |
| 2066 | + struct uvc_video_chain, list); |
| 2067 | + list_add_tail(&dev->gpio_unit->chain, &chain->entities); |
| 2068 | + } |
| 2069 | + |
1956 | 2070 | return 0;
|
1957 | 2071 | }
|
1958 | 2072 |
|
@@ -2285,6 +2399,12 @@ static int uvc_probe(struct usb_interface *intf,
|
2285 | 2399 | goto error;
|
2286 | 2400 | }
|
2287 | 2401 |
|
| 2402 | + /* Parse the associated GPIOs. */ |
| 2403 | + if (uvc_gpio_parse(dev) < 0) { |
| 2404 | + uvc_trace(UVC_TRACE_PROBE, "Unable to parse UVC GPIOs\n"); |
| 2405 | + goto error; |
| 2406 | + } |
| 2407 | + |
2288 | 2408 | uvc_printk(KERN_INFO, "Found UVC %u.%02x device %s (%04x:%04x)\n",
|
2289 | 2409 | dev->uvc_version >> 8, dev->uvc_version & 0xff,
|
2290 | 2410 | udev->product ? udev->product : "<unnamed>",
|
@@ -2335,6 +2455,13 @@ static int uvc_probe(struct usb_interface *intf,
|
2335 | 2455 | "supported.\n", ret);
|
2336 | 2456 | }
|
2337 | 2457 |
|
| 2458 | + ret = uvc_gpio_init_irq(dev); |
| 2459 | + if (ret < 0) { |
| 2460 | + dev_err(&dev->udev->dev, |
| 2461 | + "Unable to request privacy GPIO IRQ (%d)\n", ret); |
| 2462 | + goto error; |
| 2463 | + } |
| 2464 | + |
2338 | 2465 | uvc_trace(UVC_TRACE_PROBE, "UVC device initialized.\n");
|
2339 | 2466 | usb_enable_autosuspend(udev);
|
2340 | 2467 | return 0;
|
|
0 commit comments