Import of kernel-6.12.0-124.49.1.el10_1

This commit is contained in:
almalinux-bot-kernel 2026-04-16 05:06:49 +00:00
parent e069747b16
commit d3c36ff4dc
50 changed files with 1370 additions and 975 deletions

View File

@ -18,6 +18,7 @@ These formats are used for the :ref:`metadata` interface only.
metafmt-pisp-be
metafmt-rkisp1
metafmt-uvc
metafmt-uvc-msxu-1-5
metafmt-vivid
metafmt-vsp1-hgo
metafmt-vsp1-hgt

View File

@ -0,0 +1,23 @@
.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
.. _v4l2-meta-fmt-uvc-msxu-1-5:
***********************************
V4L2_META_FMT_UVC_MSXU_1_5 ('UVCM')
***********************************
Microsoft(R)'s UVC Payload Metadata.
Description
===========
V4L2_META_FMT_UVC_MSXU_1_5 buffers follow the metadata buffer layout of
V4L2_META_FMT_UVC with the only difference that it includes all the UVC
metadata in the `buffer[]` field, not just the first 2-12 bytes.
The metadata format follows the specification from Microsoft(R) [1].
.. _1:
[1] https://docs.microsoft.com/en-us/windows-hardware/drivers/stream/uvc-extensions-1-5

View File

@ -19,6 +19,7 @@ orders. See also `the Wikipedia article on Bayer filter
.. toctree::
:maxdepth: 1
pixfmt-rawnn-cru
pixfmt-srggb8
pixfmt-srggb8-pisp-comp
pixfmt-srggb10

View File

@ -0,0 +1,143 @@
.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
.. _v4l2-pix-fmt-raw-cru10:
.. _v4l2-pix-fmt-raw-cru12:
.. _v4l2-pix-fmt-raw-cru14:
.. _v4l2-pix-fmt-raw-cru20:
**********************************************************************************************************************************
V4L2_PIX_FMT_RAW_CRU10 ('CR10'), V4L2_PIX_FMT_RAW_CRU12 ('CR12'), V4L2_PIX_FMT_RAW_CRU14 ('CR14'), V4L2_PIX_FMT_RAW_CRU20 ('CR20')
**********************************************************************************************************************************
===============================================================
Renesas RZ/V2H Camera Receiver Unit 64-bit packed pixel formats
===============================================================
| V4L2_PIX_FMT_RAW_CRU10 (CR10)
| V4L2_PIX_FMT_RAW_CRU12 (CR12)
| V4L2_PIX_FMT_RAW_CRU14 (CR14)
| V4L2_PIX_FMT_RAW_CRU20 (CR20)
Description
===========
These pixel formats are some of the RAW outputs for the Camera Receiver Unit in
the Renesas RZ/V2H SoC. They are raw formats which pack pixels contiguously into
64-bit units, with the 4 or 8 most significant bits padded.
**Byte Order**
.. flat-table:: RAW formats
:header-rows: 2
:stub-columns: 0
:widths: 36 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
:fill-cells:
* - :rspan:`1` Pixel Format Code
- :cspan:`63` Data organization
* - 63
- 62
- 61
- 60
- 59
- 58
- 57
- 56
- 55
- 54
- 53
- 52
- 51
- 50
- 49
- 48
- 47
- 46
- 45
- 44
- 43
- 42
- 41
- 40
- 39
- 38
- 37
- 36
- 35
- 34
- 33
- 32
- 31
- 30
- 29
- 28
- 27
- 26
- 25
- 24
- 23
- 22
- 21
- 20
- 19
- 18
- 17
- 16
- 15
- 14
- 13
- 12
- 11
- 10
- 9
- 8
- 7
- 6
- 5
- 4
- 3
- 2
- 1
- 0
* - V4L2_PIX_FMT_RAW_CRU10
- 0
- 0
- 0
- 0
- :cspan:`9` P5
- :cspan:`9` P4
- :cspan:`9` P3
- :cspan:`9` P2
- :cspan:`9` P1
- :cspan:`9` P0
* - V4L2_PIX_FMT_RAW_CRU12
- 0
- 0
- 0
- 0
- :cspan:`11` P4
- :cspan:`11` P3
- :cspan:`11` P2
- :cspan:`11` P1
- :cspan:`11` P0
* - V4L2_PIX_FMT_RAW_CRU14
- 0
- 0
- 0
- 0
- 0
- 0
- 0
- 0
- :cspan:`13` P3
- :cspan:`13` P2
- :cspan:`13` P1
- :cspan:`13` P0
* - V4L2_PIX_FMT_RAW_CRU20
- 0
- 0
- 0
- 0
- :cspan:`19` P2
- :cspan:`19` P1
- :cspan:`19` P0

View File

@ -137,6 +137,13 @@ All components are stored with the same number of bits per component.
- Cb, Cr
- No
- Linear
* - V4L2_PIX_FMT_NV15
- 'NV15'
- 10
- 4:2:0
- Cb, Cr
- Yes
- Linear
* - V4L2_PIX_FMT_NV15_4L4
- 'VT15'
- 15
@ -186,6 +193,13 @@ All components are stored with the same number of bits per component.
- Cr, Cb
- No
- Linear
* - V4L2_PIX_FMT_NV20
- 'NV20'
- 10
- 4:2:2
- Cb, Cr
- Yes
- Linear
* - V4L2_PIX_FMT_NV24
- 'NV24'
- 8
@ -302,6 +316,57 @@ of the luma plane.
- Cr\ :sub:`11`
.. _V4L2-PIX-FMT-NV15:
NV15
----
Semi-planar 10-bit YUV 4:2:0 format similar to NV12, using 10-bit components
with no padding between each component. A group of 4 components are stored over
5 bytes in little endian order.
.. flat-table:: Sample 4x4 NV15 Image (1 byte per cell)
:header-rows: 0
:stub-columns: 0
* - start + 0:
- Y'\ :sub:`00[7:0]`
- Y'\ :sub:`01[5:0]`\ Y'\ :sub:`00[9:8]`
- Y'\ :sub:`02[3:0]`\ Y'\ :sub:`01[9:6]`
- Y'\ :sub:`03[1:0]`\ Y'\ :sub:`02[9:4]`
- Y'\ :sub:`03[9:2]`
* - start + 5:
- Y'\ :sub:`10[7:0]`
- Y'\ :sub:`11[5:0]`\ Y'\ :sub:`10[9:8]`
- Y'\ :sub:`12[3:0]`\ Y'\ :sub:`11[9:6]`
- Y'\ :sub:`13[1:0]`\ Y'\ :sub:`12[9:4]`
- Y'\ :sub:`13[9:2]`
* - start + 10:
- Y'\ :sub:`20[7:0]`
- Y'\ :sub:`21[5:0]`\ Y'\ :sub:`20[9:8]`
- Y'\ :sub:`22[3:0]`\ Y'\ :sub:`21[9:6]`
- Y'\ :sub:`23[1:0]`\ Y'\ :sub:`22[9:4]`
- Y'\ :sub:`23[9:2]`
* - start + 15:
- Y'\ :sub:`30[7:0]`
- Y'\ :sub:`31[5:0]`\ Y'\ :sub:`30[9:8]`
- Y'\ :sub:`32[3:0]`\ Y'\ :sub:`31[9:6]`
- Y'\ :sub:`33[1:0]`\ Y'\ :sub:`32[9:4]`
- Y'\ :sub:`33[9:2]`
* - start + 20:
- Cb\ :sub:`00[7:0]`
- Cr\ :sub:`00[5:0]`\ Cb\ :sub:`00[9:8]`
- Cb\ :sub:`01[3:0]`\ Cr\ :sub:`00[9:6]`
- Cr\ :sub:`01[1:0]`\ Cb\ :sub:`01[9:4]`
- Cr\ :sub:`01[9:2]`
* - start + 25:
- Cb\ :sub:`10[7:0]`
- Cr\ :sub:`10[5:0]`\ Cb\ :sub:`10[9:8]`
- Cb\ :sub:`11[3:0]`\ Cr\ :sub:`10[9:6]`
- Cr\ :sub:`11[1:0]`\ Cb\ :sub:`11[9:4]`
- Cr\ :sub:`11[9:2]`
.. _V4L2-PIX-FMT-NV12MT:
.. _V4L2-PIX-FMT-NV12MT-16X16:
.. _V4L2-PIX-FMT-NV12-4L4:
@ -631,6 +696,69 @@ number of lines as the luma plane.
- Cr\ :sub:`32`
.. _V4L2-PIX-FMT-NV20:
NV20
----
Semi-planar 10-bit YUV 4:2:2 format similar to NV16, using 10-bit components
with no padding between each component. A group of 4 components are stored over
5 bytes in little endian order.
.. flat-table:: Sample 4x4 NV20 Image (1 byte per cell)
:header-rows: 0
:stub-columns: 0
* - start + 0:
- Y'\ :sub:`00[7:0]`
- Y'\ :sub:`01[5:0]`\ Y'\ :sub:`00[9:8]`
- Y'\ :sub:`02[3:0]`\ Y'\ :sub:`01[9:6]`
- Y'\ :sub:`03[1:0]`\ Y'\ :sub:`02[9:4]`
- Y'\ :sub:`03[9:2]`
* - start + 5:
- Y'\ :sub:`10[7:0]`
- Y'\ :sub:`11[5:0]`\ Y'\ :sub:`10[9:8]`
- Y'\ :sub:`12[3:0]`\ Y'\ :sub:`11[9:6]`
- Y'\ :sub:`13[1:0]`\ Y'\ :sub:`12[9:4]`
- Y'\ :sub:`13[9:2]`
* - start + 10:
- Y'\ :sub:`20[7:0]`
- Y'\ :sub:`21[5:0]`\ Y'\ :sub:`20[9:8]`
- Y'\ :sub:`22[3:0]`\ Y'\ :sub:`21[9:6]`
- Y'\ :sub:`23[1:0]`\ Y'\ :sub:`22[9:4]`
- Y'\ :sub:`23[9:2]`
* - start + 15:
- Y'\ :sub:`30[7:0]`
- Y'\ :sub:`31[5:0]`\ Y'\ :sub:`30[9:8]`
- Y'\ :sub:`32[3:0]`\ Y'\ :sub:`31[9:6]`
- Y'\ :sub:`33[1:0]`\ Y'\ :sub:`32[9:4]`
- Y'\ :sub:`33[9:2]`
* - start + 20:
- Cb\ :sub:`00[7:0]`
- Cr\ :sub:`00[5:0]`\ Cb\ :sub:`00[9:8]`
- Cb\ :sub:`01[3:0]`\ Cr\ :sub:`00[9:6]`
- Cr\ :sub:`01[1:0]`\ Cb\ :sub:`01[9:4]`
- Cr\ :sub:`01[9:2]`
* - start + 25:
- Cb\ :sub:`10[7:0]`
- Cr\ :sub:`10[5:0]`\ Cb\ :sub:`10[9:8]`
- Cb\ :sub:`11[3:0]`\ Cr\ :sub:`10[9:6]`
- Cr\ :sub:`11[1:0]`\ Cb\ :sub:`11[9:4]`
- Cr\ :sub:`11[9:2]`
* - start + 30:
- Cb\ :sub:`20[7:0]`
- Cr\ :sub:`20[5:0]`\ Cb\ :sub:`20[9:8]`
- Cb\ :sub:`21[3:0]`\ Cr\ :sub:`20[9:6]`
- Cr\ :sub:`21[1:0]`\ Cb\ :sub:`21[9:4]`
- Cr\ :sub:`21[9:2]`
* - start + 35:
- Cb\ :sub:`30[7:0]`
- Cr\ :sub:`30[5:0]`\ Cb\ :sub:`30[9:8]`
- Cb\ :sub:`31[3:0]`\ Cr\ :sub:`30[9:6]`
- Cr\ :sub:`31[1:0]`\ Cb\ :sub:`31[9:4]`
- Cr\ :sub:`31[9:2]`
.. _V4L2-PIX-FMT-NV24:
.. _V4L2-PIX-FMT-NV42:

View File

@ -24235,6 +24235,7 @@ S: Maintained
W: http://www.ideasonboard.org/uvc/
T: git git://linuxtv.org/media.git
F: Documentation/userspace-api/media/drivers/uvcvideo.rst
F: Documentation/userspace-api/media/v4l/metafmt-uvc-msxu-1-5.rst
F: Documentation/userspace-api/media/v4l/metafmt-uvc.rst
F: drivers/media/common/uvc.c
F: drivers/media/usb/uvc/

View File

@ -12,7 +12,7 @@ RHEL_MINOR = 1
#
# Use this spot to avoid future merge conflicts.
# Do not trim this comment.
RHEL_RELEASE = 124.47.1
RHEL_RELEASE = 124.49.1
#
# RHEL_REBASE_NUM

View File

@ -498,9 +498,6 @@ CONFIG_PPC_TRANSACTIONAL_MEM=y
CONFIG_PPC_UV=y
# CONFIG_LD_HEAD_STUB_CATCH is not set
CONFIG_MPROFILE_KERNEL=y
CONFIG_ARCH_USING_PATCHABLE_FUNCTION_ENTRY=y
CONFIG_PPC_FTRACE_OUT_OF_LINE=y
CONFIG_PPC_FTRACE_OUT_OF_LINE_NUM_RESERVE=32768
CONFIG_HOTPLUG_CPU=y
CONFIG_INTERRUPT_SANITIZE_REGISTERS=y
CONFIG_PPC_QUEUED_SPINLOCKS=y
@ -724,7 +721,6 @@ CONFIG_FUNCTION_ALIGNMENT_4B=y
CONFIG_FUNCTION_ALIGNMENT=4
CONFIG_CC_HAS_MIN_FUNCTION_ALIGNMENT=y
CONFIG_CC_HAS_SANE_FUNCTION_ALIGNMENT=y
CONFIG_ARCH_WANTS_PRE_LINK_VMLINUX=y
# end of General architecture-dependent options
CONFIG_RT_MUTEXES=y
@ -5030,7 +5026,6 @@ CONFIG_HID_KUNIT_TEST=m
#
# HID-BPF support
#
CONFIG_HID_BPF=y
# end of HID-BPF support
CONFIG_I2C_HID=y
@ -7100,8 +7095,6 @@ CONFIG_HAVE_FUNCTION_TRACER=y
CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
CONFIG_HAVE_DYNAMIC_FTRACE=y
CONFIG_HAVE_DYNAMIC_FTRACE_WITH_REGS=y
CONFIG_HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS=y
CONFIG_HAVE_DYNAMIC_FTRACE_WITH_CALL_OPS=y
CONFIG_HAVE_DYNAMIC_FTRACE_WITH_ARGS=y
CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
@ -7121,8 +7114,6 @@ CONFIG_FUNCTION_TRACER=y
CONFIG_FUNCTION_GRAPH_TRACER=y
CONFIG_DYNAMIC_FTRACE=y
CONFIG_DYNAMIC_FTRACE_WITH_REGS=y
CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS=y
CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS=y
CONFIG_DYNAMIC_FTRACE_WITH_ARGS=y
CONFIG_FPROBE=y
CONFIG_FUNCTION_PROFILER=y
@ -7147,7 +7138,7 @@ CONFIG_BPF_EVENTS=y
CONFIG_DYNAMIC_EVENTS=y
CONFIG_PROBE_EVENTS=y
CONFIG_FTRACE_MCOUNT_RECORD=y
CONFIG_FTRACE_MCOUNT_USE_PATCHABLE_FUNCTION_ENTRY=y
CONFIG_FTRACE_MCOUNT_USE_CC=y
CONFIG_TRACING_MAP=y
CONFIG_SYNTH_EVENTS=y
# CONFIG_USER_EVENTS is not set
@ -7173,8 +7164,6 @@ CONFIG_RV_REACTORS=y
CONFIG_RV_REACT_PRINTK=y
CONFIG_RV_REACT_PANIC=y
# CONFIG_SAMPLES is not set
CONFIG_HAVE_SAMPLE_FTRACE_DIRECT=y
CONFIG_HAVE_SAMPLE_FTRACE_DIRECT_MULTI=y
CONFIG_ARCH_HAS_DEVMEM_IS_ALLOWED=y
CONFIG_STRICT_DEVMEM=y
# CONFIG_IO_STRICT_DEVMEM is not set

View File

@ -3882,7 +3882,7 @@ static int btusb_probe(struct usb_interface *intf,
return -ENODEV;
}
data = devm_kzalloc(&intf->dev, sizeof(*data), GFP_KERNEL);
data = kzalloc(sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
@ -3905,8 +3905,10 @@ static int btusb_probe(struct usb_interface *intf,
}
}
if (!data->intr_ep || !data->bulk_tx_ep || !data->bulk_rx_ep)
if (!data->intr_ep || !data->bulk_tx_ep || !data->bulk_rx_ep) {
kfree(data);
return -ENODEV;
}
if (id->driver_info & BTUSB_AMP) {
data->cmdreq_type = USB_TYPE_CLASS | 0x01;
@ -3961,8 +3963,10 @@ static int btusb_probe(struct usb_interface *intf,
data->recv_acl = hci_recv_frame;
hdev = hci_alloc_dev_priv(priv_size);
if (!hdev)
if (!hdev) {
kfree(data);
return -ENOMEM;
}
hdev->bus = HCI_USB;
hci_set_drvdata(hdev, data);
@ -4235,6 +4239,7 @@ out_free_dev:
if (data->reset_gpio)
gpiod_put(data->reset_gpio);
hci_free_dev(hdev);
kfree(data);
return err;
}
@ -4262,6 +4267,11 @@ static void btusb_disconnect(struct usb_interface *intf)
hci_unregister_dev(hdev);
if (data->oob_wake_irq)
device_init_wakeup(&data->udev->dev, false);
if (data->reset_gpio)
gpiod_put(data->reset_gpio);
if (intf == data->intf) {
if (data->isoc)
usb_driver_release_interface(&btusb_driver, data->isoc);
@ -4272,18 +4282,13 @@ static void btusb_disconnect(struct usb_interface *intf)
usb_driver_release_interface(&btusb_driver, data->diag);
usb_driver_release_interface(&btusb_driver, data->intf);
} else if (intf == data->diag) {
usb_driver_release_interface(&btusb_driver, data->intf);
if (data->isoc)
usb_driver_release_interface(&btusb_driver, data->isoc);
usb_driver_release_interface(&btusb_driver, data->intf);
}
if (data->oob_wake_irq)
device_init_wakeup(&data->udev->dev, false);
if (data->reset_gpio)
gpiod_put(data->reset_gpio);
hci_free_dev(hdev);
kfree(data);
}
#ifdef CONFIG_PM

View File

@ -685,6 +685,8 @@ static int hci_uart_register_dev(struct hci_uart *hu)
return err;
}
set_bit(HCI_UART_PROTO_INIT, &hu->flags);
if (test_bit(HCI_UART_INIT_PENDING, &hu->hdev_flags))
return 0;
@ -712,8 +714,6 @@ static int hci_uart_set_proto(struct hci_uart *hu, int id)
hu->proto = p;
set_bit(HCI_UART_PROTO_INIT, &hu->flags);
err = hci_uart_register_dev(hu);
if (err) {
return err;

View File

@ -1483,14 +1483,28 @@ static u32 uvc_get_ctrl_bitmap(struct uvc_control *ctrl,
return ~0;
}
/*
* Maximum retry count to avoid spurious errors with controls. Increasing this
* value does no seem to produce better results in the tested hardware.
*/
#define MAX_QUERY_RETRIES 2
static int __uvc_queryctrl_boundaries(struct uvc_video_chain *chain,
struct uvc_control *ctrl,
struct uvc_control_mapping *mapping,
struct v4l2_query_ext_ctrl *v4l2_ctrl)
{
if (!ctrl->cached) {
int ret = uvc_ctrl_populate_cache(chain, ctrl);
if (ret < 0)
unsigned int retries;
int ret;
for (retries = 0; retries < MAX_QUERY_RETRIES; retries++) {
ret = uvc_ctrl_populate_cache(chain, ctrl);
if (ret != -EIO)
break;
}
if (ret)
return ret;
}
@ -1567,6 +1581,7 @@ static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
{
struct uvc_control_mapping *master_map = NULL;
struct uvc_control *master_ctrl = NULL;
int ret;
memset(v4l2_ctrl, 0, sizeof(*v4l2_ctrl));
v4l2_ctrl->id = mapping->id;
@ -1587,18 +1602,31 @@ static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
__uvc_find_control(ctrl->entity, mapping->master_id,
&master_map, &master_ctrl, 0, 0);
if (master_ctrl && (master_ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR)) {
unsigned int retries;
s32 val;
int ret;
if (WARN_ON(uvc_ctrl_mapping_is_compound(master_map)))
return -EIO;
ret = __uvc_ctrl_get(chain, master_ctrl, master_map, &val);
if (ret < 0)
return ret;
for (retries = 0; retries < MAX_QUERY_RETRIES; retries++) {
ret = __uvc_ctrl_get(chain, master_ctrl, master_map,
&val);
if (!ret)
break;
if (ret < 0 && ret != -EIO)
return ret;
}
if (val != mapping->master_manual)
v4l2_ctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
if (ret == -EIO) {
dev_warn_ratelimited(&chain->dev->udev->dev,
"UVC non compliance: Error %d querying master control %x (%s)\n",
ret, master_map->id,
uvc_map_get_name(master_map));
} else {
if (val != mapping->master_manual)
v4l2_ctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
}
}
v4l2_ctrl->elem_size = uvc_mapping_v4l2_size(mapping);
@ -1613,7 +1641,18 @@ static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
return 0;
}
return __uvc_queryctrl_boundaries(chain, ctrl, mapping, v4l2_ctrl);
ret = __uvc_queryctrl_boundaries(chain, ctrl, mapping, v4l2_ctrl);
if (ret && !mapping->disabled) {
dev_warn(&chain->dev->udev->dev,
"UVC non compliance: permanently disabling control %x (%s), due to error %d\n",
mapping->id, uvc_map_get_name(mapping), ret);
mapping->disabled = true;
}
if (mapping->disabled)
v4l2_ctrl->flags |= V4L2_CTRL_FLAG_DISABLED;
return 0;
}
int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
@ -1812,38 +1851,49 @@ static void uvc_ctrl_send_slave_event(struct uvc_video_chain *chain,
uvc_ctrl_send_event(chain, handle, ctrl, mapping, val, changes);
}
static void uvc_ctrl_set_handle(struct uvc_fh *handle, struct uvc_control *ctrl,
struct uvc_fh *new_handle)
static int uvc_ctrl_set_handle(struct uvc_control *ctrl, struct uvc_fh *handle)
{
int ret;
lockdep_assert_held(&handle->chain->ctrl_mutex);
if (new_handle) {
if (ctrl->handle)
dev_warn_ratelimited(&handle->stream->dev->udev->dev,
"UVC non compliance: Setting an async control with a pending operation.");
if (ctrl->handle) {
dev_warn_ratelimited(&handle->stream->dev->udev->dev,
"UVC non compliance: Setting an async control with a pending operation.");
if (new_handle == ctrl->handle)
return;
if (ctrl->handle == handle)
return 0;
if (ctrl->handle) {
WARN_ON(!ctrl->handle->pending_async_ctrls);
if (ctrl->handle->pending_async_ctrls)
ctrl->handle->pending_async_ctrls--;
}
ctrl->handle = new_handle;
handle->pending_async_ctrls++;
return;
WARN_ON(!ctrl->handle->pending_async_ctrls);
if (ctrl->handle->pending_async_ctrls)
ctrl->handle->pending_async_ctrls--;
ctrl->handle = handle;
ctrl->handle->pending_async_ctrls++;
return 0;
}
/* Cannot clear the handle for a control not owned by us.*/
if (WARN_ON(ctrl->handle != handle))
return;
ret = uvc_pm_get(handle->chain->dev);
if (ret)
return ret;
ctrl->handle = handle;
ctrl->handle->pending_async_ctrls++;
return 0;
}
static int uvc_ctrl_clear_handle(struct uvc_control *ctrl)
{
lockdep_assert_held(&ctrl->handle->chain->ctrl_mutex);
if (WARN_ON(!ctrl->handle->pending_async_ctrls)) {
ctrl->handle = NULL;
return -EINVAL;
}
ctrl->handle->pending_async_ctrls--;
uvc_pm_put(ctrl->handle->chain->dev);
ctrl->handle = NULL;
if (WARN_ON(!handle->pending_async_ctrls))
return;
handle->pending_async_ctrls--;
return 0;
}
void uvc_ctrl_status_event(struct uvc_video_chain *chain,
@ -1860,7 +1910,7 @@ void uvc_ctrl_status_event(struct uvc_video_chain *chain,
handle = ctrl->handle;
if (handle)
uvc_ctrl_set_handle(handle, ctrl, NULL);
uvc_ctrl_clear_handle(ctrl);
list_for_each_entry(mapping, &ctrl->info.mappings, list) {
s32 value;
@ -1943,7 +1993,9 @@ static bool uvc_ctrl_xctrls_has_control(const struct v4l2_ext_control *xctrls,
}
static void uvc_ctrl_send_events(struct uvc_fh *handle,
const struct v4l2_ext_control *xctrls, unsigned int xctrls_count)
struct uvc_entity *entity,
const struct v4l2_ext_control *xctrls,
unsigned int xctrls_count)
{
struct uvc_control_mapping *mapping;
struct uvc_control *ctrl;
@ -1955,6 +2007,9 @@ static void uvc_ctrl_send_events(struct uvc_fh *handle,
s32 value;
ctrl = uvc_find_control(handle->chain, xctrls[i].id, &mapping);
if (ctrl->entity != entity)
continue;
if (ctrl->info.flags & UVC_CTRL_FLAG_ASYNCHRONOUS)
/* Notification will be sent from an Interrupt event. */
continue;
@ -2017,18 +2072,24 @@ static int uvc_ctrl_add_event(struct v4l2_subscribed_event *sev, unsigned elems)
goto done;
}
list_add_tail(&sev->node, &mapping->ev_subs);
if (sev->flags & V4L2_EVENT_SUB_FL_SEND_INITIAL) {
struct v4l2_event ev;
u32 changes = V4L2_EVENT_CTRL_CH_FLAGS;
s32 val = 0;
ret = uvc_pm_get(handle->chain->dev);
if (ret)
goto done;
if (uvc_ctrl_mapping_is_compound(mapping) ||
__uvc_ctrl_get(handle->chain, ctrl, mapping, &val) == 0)
changes |= V4L2_EVENT_CTRL_CH_VALUE;
uvc_ctrl_fill_event(handle->chain, &ev, ctrl, mapping, val,
changes);
uvc_pm_put(handle->chain->dev);
/*
* Mark the queue as active, allowing this initial event to be
* accepted.
@ -2037,6 +2098,8 @@ static int uvc_ctrl_add_event(struct v4l2_subscribed_event *sev, unsigned elems)
v4l2_event_queue_fh(sev->fh, &ev);
}
list_add_tail(&sev->node, &mapping->ev_subs);
done:
mutex_unlock(&handle->chain->ctrl_mutex);
return ret;
@ -2090,15 +2153,20 @@ int uvc_ctrl_begin(struct uvc_video_chain *chain)
return mutex_lock_interruptible(&chain->ctrl_mutex) ? -ERESTARTSYS : 0;
}
/*
* Returns the number of uvc controls that have been correctly set, or a
* negative number if there has been an error.
*/
static int uvc_ctrl_commit_entity(struct uvc_device *dev,
struct uvc_fh *handle,
struct uvc_entity *entity,
int rollback,
struct uvc_control **err_ctrl)
{
unsigned int processed_ctrls = 0;
struct uvc_control *ctrl;
unsigned int i;
int ret;
int ret = 0;
if (entity == NULL)
return 0;
@ -2127,8 +2195,9 @@ static int uvc_ctrl_commit_entity(struct uvc_device *dev,
dev->intfnum, ctrl->info.selector,
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
ctrl->info.size);
else
ret = 0;
if (!ret)
processed_ctrls++;
if (rollback || ret < 0)
memcpy(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
@ -2137,18 +2206,25 @@ static int uvc_ctrl_commit_entity(struct uvc_device *dev,
ctrl->dirty = 0;
if (ret < 0) {
if (!rollback && handle && !ret &&
ctrl->info.flags & UVC_CTRL_FLAG_ASYNCHRONOUS)
ret = uvc_ctrl_set_handle(ctrl, handle);
if (ret < 0 && !rollback) {
if (err_ctrl)
*err_ctrl = ctrl;
return ret;
/*
* If we fail to set a control, we need to rollback
* the next ones.
*/
rollback = 1;
}
if (!rollback && handle &&
ctrl->info.flags & UVC_CTRL_FLAG_ASYNCHRONOUS)
uvc_ctrl_set_handle(handle, ctrl, handle);
}
return 0;
if (ret)
return ret;
return processed_ctrls;
}
static int uvc_ctrl_find_ctrl_idx(struct uvc_entity *entity,
@ -2178,7 +2254,8 @@ int __uvc_ctrl_commit(struct uvc_fh *handle, int rollback,
struct uvc_video_chain *chain = handle->chain;
struct uvc_control *err_ctrl;
struct uvc_entity *entity;
int ret = 0;
int ret_out = 0;
int ret;
/* Find the control. */
list_for_each_entry(entity, &chain->entities, chain) {
@ -2189,15 +2266,23 @@ int __uvc_ctrl_commit(struct uvc_fh *handle, int rollback,
ctrls->error_idx =
uvc_ctrl_find_ctrl_idx(entity, ctrls,
err_ctrl);
goto done;
/*
* When we fail to commit an entity, we need to
* restore the UVC_CTRL_DATA_BACKUP for all the
* controls in the other entities, otherwise our cache
* and the hardware will be out of sync.
*/
rollback = 1;
ret_out = ret;
} else if (ret > 0 && !rollback) {
uvc_ctrl_send_events(handle, entity,
ctrls->controls, ctrls->count);
}
}
if (!rollback)
uvc_ctrl_send_events(handle, ctrls->controls, ctrls->count);
done:
mutex_unlock(&chain->ctrl_mutex);
return ret;
return ret_out;
}
static int uvc_mapping_get_xctrl_compound(struct uvc_video_chain *chain,
@ -3232,11 +3317,15 @@ void uvc_ctrl_cleanup_fh(struct uvc_fh *handle)
for (unsigned int i = 0; i < entity->ncontrols; ++i) {
if (entity->controls[i].handle != handle)
continue;
uvc_ctrl_set_handle(handle, &entity->controls[i], NULL);
uvc_ctrl_clear_handle(&entity->controls[i]);
}
}
WARN_ON(handle->pending_async_ctrls);
if (!WARN_ON(handle->pending_async_ctrls))
return;
for (unsigned int i = 0; i < handle->pending_async_ctrls; i++)
uvc_pm_put(handle->stream->dev);
}
/*

View File

@ -183,8 +183,6 @@ static void uvc_stream_delete(struct uvc_streaming *stream)
if (stream->async_wq)
destroy_workqueue(stream->async_wq);
mutex_destroy(&stream->mutex);
usb_put_intf(stream->intf);
kfree(stream->formats);
@ -201,8 +199,6 @@ static struct uvc_streaming *uvc_stream_new(struct uvc_device *dev,
if (stream == NULL)
return NULL;
mutex_init(&stream->mutex);
stream->dev = dev;
stream->intf = usb_get_intf(intf);
stream->intfnum = intf->cur_altsetting->desc.bInterfaceNumber;
@ -344,6 +340,9 @@ static int uvc_parse_format(struct uvc_device *dev,
u8 ftype;
int ret;
if (buflen < 4)
return -EINVAL;
format->type = buffer[2];
format->index = buffer[3];
format->frames = frames;
@ -1299,8 +1298,13 @@ static int uvc_gpio_parse(struct uvc_device *dev)
gpio_privacy = devm_gpiod_get_optional(&dev->intf->dev, "privacy",
GPIOD_IN);
if (IS_ERR_OR_NULL(gpio_privacy))
return PTR_ERR_OR_ZERO(gpio_privacy);
if (!gpio_privacy)
return 0;
if (IS_ERR(gpio_privacy))
return dev_err_probe(&dev->intf->dev,
PTR_ERR(gpio_privacy),
"Can't get privacy GPIO\n");
irq = gpiod_to_irq(gpio_privacy);
if (irq < 0)
@ -1861,7 +1865,7 @@ static int uvc_scan_device(struct uvc_device *dev)
if (list_empty(&dev->chains)) {
dev_info(&dev->udev->dev, "No valid video chain found.\n");
return -1;
return -ENODEV;
}
/* Add GPIO entity to the first chain. */
@ -1953,31 +1957,7 @@ static void uvc_unregister_video(struct uvc_device *dev)
if (!video_is_registered(&stream->vdev))
continue;
/*
* For stream->vdev we follow the same logic as:
* vb2_video_unregister_device().
*/
/* 1. Take a reference to vdev */
get_device(&stream->vdev.dev);
/* 2. Ensure that no new ioctls can be called. */
video_unregister_device(&stream->vdev);
/* 3. Wait for old ioctls to finish. */
mutex_lock(&stream->mutex);
/* 4. Stop streaming. */
uvc_queue_release(&stream->queue);
mutex_unlock(&stream->mutex);
put_device(&stream->vdev.dev);
/*
* For stream->meta.vdev we can directly call:
* vb2_video_unregister_device().
*/
vb2_video_unregister_device(&stream->vdev);
vb2_video_unregister_device(&stream->meta.vdev);
/*
@ -2025,6 +2005,8 @@ int uvc_register_video_device(struct uvc_device *dev,
vdev->ioctl_ops = ioctl_ops;
vdev->release = uvc_release;
vdev->prio = &stream->chain->prio;
vdev->queue = &queue->queue;
vdev->lock = &queue->mutex;
if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
vdev->vfl_dir = VFL_DIR_TX;
else
@ -2232,16 +2214,16 @@ static int uvc_probe(struct usb_interface *intf,
#endif
/* Parse the Video Class control descriptor. */
if (uvc_parse_control(dev) < 0) {
ret = uvc_parse_control(dev);
if (ret < 0) {
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");
ret = uvc_gpio_parse(dev);
if (ret < 0)
goto error;
}
dev_info(&dev->udev->dev, "Found UVC %u.%02x device %s (%04x:%04x)\n",
dev->uvc_version >> 8, dev->uvc_version & 0xff,
@ -2264,24 +2246,29 @@ static int uvc_probe(struct usb_interface *intf,
}
/* Register the V4L2 device. */
if (v4l2_device_register(&intf->dev, &dev->vdev) < 0)
ret = v4l2_device_register(&intf->dev, &dev->vdev);
if (ret < 0)
goto error;
/* Scan the device for video chains. */
if (uvc_scan_device(dev) < 0)
ret = uvc_scan_device(dev);
if (ret < 0)
goto error;
/* Initialize controls. */
if (uvc_ctrl_init_device(dev) < 0)
ret = uvc_ctrl_init_device(dev);
if (ret < 0)
goto error;
/* Register video device nodes. */
if (uvc_register_chains(dev) < 0)
ret = uvc_register_chains(dev);
if (ret < 0)
goto error;
#ifdef CONFIG_MEDIA_CONTROLLER
/* Register the media device node */
if (media_device_register(&dev->mdev) < 0)
ret = media_device_register(&dev->mdev);
if (ret < 0)
goto error;
#endif
/* Save our data pointer in the interface data. */
@ -2302,6 +2289,13 @@ static int uvc_probe(struct usb_interface *intf,
goto error;
}
ret = uvc_meta_init(dev);
if (ret < 0) {
dev_err(&dev->udev->dev,
"Error initializing the metadata formats (%d)\n", ret);
goto error;
}
if (dev->quirks & UVC_QUIRK_NO_RESET_RESUME)
udev->quirks &= ~USB_QUIRK_RESET_RESUME;
@ -2315,7 +2309,7 @@ static int uvc_probe(struct usb_interface *intf,
error:
uvc_unregister_video(dev);
kref_put(&dev->ref, uvc_delete);
return -ENODEV;
return ret;
}
static void uvc_disconnect(struct usb_interface *intf)
@ -2384,9 +2378,12 @@ static int __uvc_resume(struct usb_interface *intf, int reset)
list_for_each_entry(stream, &dev->streams, list) {
if (stream->intf == intf) {
ret = uvc_video_resume(stream, reset);
if (ret < 0)
uvc_queue_streamoff(&stream->queue,
stream->queue.queue.type);
if (ret < 0) {
mutex_lock(&stream->queue.mutex);
vb2_streamoff(&stream->queue.queue,
stream->queue.queue.type);
mutex_unlock(&stream->queue.mutex);
}
return ret;
}
}
@ -2500,6 +2497,15 @@ static const struct uvc_device_info uvc_quirk_force_y8 = {
* Sort these by vendor/product ID.
*/
static const struct usb_device_id uvc_ids[] = {
/* HP Webcam HD 2300 */
{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE
| USB_DEVICE_ID_MATCH_INT_INFO,
.idVendor = 0x03f0,
.idProduct = 0xe207,
.bInterfaceClass = USB_CLASS_VIDEO,
.bInterfaceSubClass = 1,
.bInterfaceProtocol = 0,
.driver_info = (kernel_ulong_t)&uvc_quirk_stream_no_fid },
/* Quanta ACER HD User Facing */
{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE
| USB_DEVICE_ID_MATCH_INT_INFO,

View File

@ -10,6 +10,7 @@
#include <linux/list.h>
#include <linux/module.h>
#include <linux/usb.h>
#include <linux/usb/uvc.h>
#include <linux/videodev2.h>
#include <media/v4l2-ioctl.h>
@ -63,15 +64,20 @@ static int uvc_meta_v4l2_try_format(struct file *file, void *fh,
struct uvc_streaming *stream = video_get_drvdata(vfh->vdev);
struct uvc_device *dev = stream->dev;
struct v4l2_meta_format *fmt = &format->fmt.meta;
u32 fmeta = fmt->dataformat;
u32 fmeta = V4L2_META_FMT_UVC;
if (format->type != vfh->vdev->queue->type)
return -EINVAL;
for (unsigned int i = 0; i < dev->nmeta_formats; i++)
if (dev->meta_formats[i] == fmt->dataformat) {
fmeta = fmt->dataformat;
break;
}
memset(fmt, 0, sizeof(*fmt));
fmt->dataformat = fmeta == dev->info->meta_format
? fmeta : V4L2_META_FMT_UVC;
fmt->dataformat = fmeta;
fmt->buffersize = UVC_METADATA_BUF_SIZE;
return 0;
@ -94,16 +100,12 @@ static int uvc_meta_v4l2_set_format(struct file *file, void *fh,
* Metadata buffers would still be perfectly parseable, but it's more
* consistent and cleaner to disallow that.
*/
mutex_lock(&stream->mutex);
if (vb2_is_busy(&stream->meta.queue.queue))
return -EBUSY;
if (uvc_queue_allocated(&stream->queue))
ret = -EBUSY;
else
stream->meta.format = fmt->dataformat;
stream->meta.format = fmt->dataformat;
mutex_unlock(&stream->mutex);
return ret;
return 0;
}
static int uvc_meta_v4l2_enum_formats(struct file *file, void *fh,
@ -112,17 +114,19 @@ static int uvc_meta_v4l2_enum_formats(struct file *file, void *fh,
struct v4l2_fh *vfh = file->private_data;
struct uvc_streaming *stream = video_get_drvdata(vfh->vdev);
struct uvc_device *dev = stream->dev;
u32 index = fdesc->index;
u32 i = fdesc->index;
if (fdesc->type != vfh->vdev->queue->type ||
index > 1U || (index && !dev->info->meta_format))
if (fdesc->type != vfh->vdev->queue->type)
return -EINVAL;
if (i >= dev->nmeta_formats)
return -EINVAL;
memset(fdesc, 0, sizeof(*fdesc));
fdesc->type = vfh->vdev->queue->type;
fdesc->index = index;
fdesc->pixelformat = index ? dev->info->meta_format : V4L2_META_FMT_UVC;
fdesc->index = i;
fdesc->pixelformat = dev->meta_formats[i];
return 0;
}
@ -156,6 +160,76 @@ static const struct v4l2_file_operations uvc_meta_fops = {
.mmap = vb2_fop_mmap,
};
static struct uvc_entity *uvc_meta_find_msxu(struct uvc_device *dev)
{
static const u8 uvc_msxu_guid[16] = UVC_GUID_MSXU_1_5;
struct uvc_entity *entity;
list_for_each_entry(entity, &dev->entities, list) {
if (!memcmp(entity->guid, uvc_msxu_guid, sizeof(entity->guid)))
return entity;
}
return NULL;
}
#define MSXU_CONTROL_METADATA 0x9
static int uvc_meta_detect_msxu(struct uvc_device *dev)
{
u32 *data __free(kfree) = NULL;
struct uvc_entity *entity;
int ret;
entity = uvc_meta_find_msxu(dev);
if (!entity)
return 0;
/*
* USB requires buffers aligned in a special way, simplest way is to
* make sure that query_ctrl will work is to kmalloc() them.
*/
data = kmalloc(sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
/*
* Check if the metadata is already enabled, or if the device always
* returns metadata.
*/
ret = uvc_query_ctrl(dev, UVC_GET_CUR, entity->id, dev->intfnum,
MSXU_CONTROL_METADATA, data, sizeof(*data));
if (ret)
return 0;
if (*data) {
dev->quirks |= UVC_QUIRK_MSXU_META;
return 0;
}
/*
* Set the value of MSXU_CONTROL_METADATA to the value reported by
* GET_MAX to enable production of MSXU metadata. The GET_MAX request
* reports the maximum size of the metadata, if its value is 0 then MSXU
* metadata is not supported. For more information, see
* https://learn.microsoft.com/en-us/windows-hardware/drivers/stream/uvc-extensions-1-5#2229-metadata-control
*/
ret = uvc_query_ctrl(dev, UVC_GET_MAX, entity->id, dev->intfnum,
MSXU_CONTROL_METADATA, data, sizeof(*data));
if (ret || !*data)
return 0;
/*
* If we can set MSXU_CONTROL_METADATA, the device will report
* metadata.
*/
ret = uvc_query_ctrl(dev, UVC_SET_CUR, entity->id, dev->intfnum,
MSXU_CONTROL_METADATA, data, sizeof(*data));
if (!ret)
dev->quirks |= UVC_QUIRK_MSXU_META;
return 0;
}
int uvc_meta_register(struct uvc_streaming *stream)
{
struct uvc_device *dev = stream->dev;
@ -164,13 +238,32 @@ int uvc_meta_register(struct uvc_streaming *stream)
stream->meta.format = V4L2_META_FMT_UVC;
/*
* The video interface queue uses manual locking and thus does not set
* the queue pointer. Set it manually here.
*/
vdev->queue = &queue->queue;
return uvc_register_video_device(dev, stream, vdev, queue,
V4L2_BUF_TYPE_META_CAPTURE,
&uvc_meta_fops, &uvc_meta_ioctl_ops);
}
int uvc_meta_init(struct uvc_device *dev)
{
unsigned int i = 0;
int ret;
ret = uvc_meta_detect_msxu(dev);
if (ret)
return ret;
dev->meta_formats[i++] = V4L2_META_FMT_UVC;
if (dev->info->meta_format &&
!WARN_ON(dev->info->meta_format == V4L2_META_FMT_UVC))
dev->meta_formats[i++] = dev->info->meta_format;
if (dev->quirks & UVC_QUIRK_MSXU_META &&
!WARN_ON(dev->info->meta_format == V4L2_META_FMT_UVC_MSXU_1_5))
dev->meta_formats[i++] = V4L2_META_FMT_UVC_MSXU_1_5;
/* IMPORTANT: for new meta-formats update UVC_MAX_META_DATA_FORMATS. */
dev->nmeta_formats = i;
return 0;
}

View File

@ -42,13 +42,15 @@ static inline struct uvc_buffer *uvc_vbuf_to_buffer(struct vb2_v4l2_buffer *buf)
*
* This function must be called with the queue spinlock held.
*/
static void uvc_queue_return_buffers(struct uvc_video_queue *queue,
enum uvc_buffer_state state)
static void __uvc_queue_return_buffers(struct uvc_video_queue *queue,
enum uvc_buffer_state state)
{
enum vb2_buffer_state vb2_state = state == UVC_BUF_STATE_ERROR
? VB2_BUF_STATE_ERROR
: VB2_BUF_STATE_QUEUED;
lockdep_assert_held(&queue->irqlock);
while (!list_empty(&queue->irqqueue)) {
struct uvc_buffer *buf = list_first_entry(&queue->irqqueue,
struct uvc_buffer,
@ -59,6 +61,14 @@ static void uvc_queue_return_buffers(struct uvc_video_queue *queue,
}
}
static void uvc_queue_return_buffers(struct uvc_video_queue *queue,
enum uvc_buffer_state state)
{
spin_lock_irq(&queue->irqlock);
__uvc_queue_return_buffers(queue, state);
spin_unlock_irq(&queue->irqlock);
}
/* -----------------------------------------------------------------------------
* videobuf2 queue operations
*/
@ -157,7 +167,7 @@ static void uvc_buffer_finish(struct vb2_buffer *vb)
uvc_video_clock_update(stream, vbuf, buf);
}
static int uvc_start_streaming(struct vb2_queue *vq, unsigned int count)
static int uvc_start_streaming_video(struct vb2_queue *vq, unsigned int count)
{
struct uvc_video_queue *queue = vb2_get_drv_priv(vq);
struct uvc_streaming *stream = uvc_queue_to_stream(queue);
@ -165,31 +175,44 @@ static int uvc_start_streaming(struct vb2_queue *vq, unsigned int count)
lockdep_assert_irqs_enabled();
ret = uvc_pm_get(stream->dev);
if (ret)
return ret;
queue->buf_used = 0;
ret = uvc_video_start_streaming(stream);
if (ret == 0)
return 0;
spin_lock_irq(&queue->irqlock);
uvc_pm_put(stream->dev);
uvc_queue_return_buffers(queue, UVC_BUF_STATE_QUEUED);
spin_unlock_irq(&queue->irqlock);
return ret;
}
static void uvc_stop_streaming(struct vb2_queue *vq)
static void uvc_stop_streaming_video(struct vb2_queue *vq)
{
struct uvc_video_queue *queue = vb2_get_drv_priv(vq);
struct uvc_streaming *stream = uvc_queue_to_stream(queue);
lockdep_assert_irqs_enabled();
uvc_video_stop_streaming(uvc_queue_to_stream(queue));
uvc_pm_put(stream->dev);
uvc_queue_return_buffers(queue, UVC_BUF_STATE_ERROR);
}
static void uvc_stop_streaming_meta(struct vb2_queue *vq)
{
struct uvc_video_queue *queue = vb2_get_drv_priv(vq);
lockdep_assert_irqs_enabled();
if (vq->type != V4L2_BUF_TYPE_META_CAPTURE)
uvc_video_stop_streaming(uvc_queue_to_stream(queue));
spin_lock_irq(&queue->irqlock);
uvc_queue_return_buffers(queue, UVC_BUF_STATE_ERROR);
spin_unlock_irq(&queue->irqlock);
}
static const struct vb2_ops uvc_queue_qops = {
@ -197,15 +220,20 @@ static const struct vb2_ops uvc_queue_qops = {
.buf_prepare = uvc_buffer_prepare,
.buf_queue = uvc_buffer_queue,
.buf_finish = uvc_buffer_finish,
.start_streaming = uvc_start_streaming,
.stop_streaming = uvc_stop_streaming,
.start_streaming = uvc_start_streaming_video,
.stop_streaming = uvc_stop_streaming_video,
};
static const struct vb2_ops uvc_meta_queue_qops = {
.queue_setup = uvc_queue_setup,
.buf_prepare = uvc_buffer_prepare,
.buf_queue = uvc_buffer_queue,
.stop_streaming = uvc_stop_streaming,
/*
* .start_streaming is not provided here. Metadata relies on video
* streaming being active. If video isn't streaming, then no metadata
* will arrive either.
*/
.stop_streaming = uvc_stop_streaming_meta,
};
int uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type)
@ -242,153 +270,10 @@ int uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type)
return 0;
}
void uvc_queue_release(struct uvc_video_queue *queue)
{
mutex_lock(&queue->mutex);
vb2_queue_release(&queue->queue);
mutex_unlock(&queue->mutex);
}
/* -----------------------------------------------------------------------------
* V4L2 queue operations
*/
int uvc_request_buffers(struct uvc_video_queue *queue,
struct v4l2_requestbuffers *rb)
{
int ret;
mutex_lock(&queue->mutex);
ret = vb2_reqbufs(&queue->queue, rb);
mutex_unlock(&queue->mutex);
return ret ? ret : rb->count;
}
int uvc_query_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *buf)
{
int ret;
mutex_lock(&queue->mutex);
ret = vb2_querybuf(&queue->queue, buf);
mutex_unlock(&queue->mutex);
return ret;
}
int uvc_create_buffers(struct uvc_video_queue *queue,
struct v4l2_create_buffers *cb)
{
int ret;
mutex_lock(&queue->mutex);
ret = vb2_create_bufs(&queue->queue, cb);
mutex_unlock(&queue->mutex);
return ret;
}
int uvc_queue_buffer(struct uvc_video_queue *queue,
struct media_device *mdev, struct v4l2_buffer *buf)
{
int ret;
mutex_lock(&queue->mutex);
ret = vb2_qbuf(&queue->queue, mdev, buf);
mutex_unlock(&queue->mutex);
return ret;
}
int uvc_export_buffer(struct uvc_video_queue *queue,
struct v4l2_exportbuffer *exp)
{
int ret;
mutex_lock(&queue->mutex);
ret = vb2_expbuf(&queue->queue, exp);
mutex_unlock(&queue->mutex);
return ret;
}
int uvc_dequeue_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *buf,
int nonblocking)
{
int ret;
mutex_lock(&queue->mutex);
ret = vb2_dqbuf(&queue->queue, buf, nonblocking);
mutex_unlock(&queue->mutex);
return ret;
}
int uvc_queue_streamon(struct uvc_video_queue *queue, enum v4l2_buf_type type)
{
int ret;
mutex_lock(&queue->mutex);
ret = vb2_streamon(&queue->queue, type);
mutex_unlock(&queue->mutex);
return ret;
}
int uvc_queue_streamoff(struct uvc_video_queue *queue, enum v4l2_buf_type type)
{
int ret;
mutex_lock(&queue->mutex);
ret = vb2_streamoff(&queue->queue, type);
mutex_unlock(&queue->mutex);
return ret;
}
int uvc_queue_mmap(struct uvc_video_queue *queue, struct vm_area_struct *vma)
{
return vb2_mmap(&queue->queue, vma);
}
#ifndef CONFIG_MMU
unsigned long uvc_queue_get_unmapped_area(struct uvc_video_queue *queue,
unsigned long pgoff)
{
return vb2_get_unmapped_area(&queue->queue, 0, 0, pgoff, 0);
}
#endif
__poll_t uvc_queue_poll(struct uvc_video_queue *queue, struct file *file,
poll_table *wait)
{
__poll_t ret;
mutex_lock(&queue->mutex);
ret = vb2_poll(&queue->queue, file, wait);
mutex_unlock(&queue->mutex);
return ret;
}
/* -----------------------------------------------------------------------------
*
*/
/*
* Check if buffers have been allocated.
*/
int uvc_queue_allocated(struct uvc_video_queue *queue)
{
int allocated;
mutex_lock(&queue->mutex);
allocated = vb2_is_busy(&queue->queue);
mutex_unlock(&queue->mutex);
return allocated;
}
/*
* Cancel the video buffers queue.
*
@ -406,7 +291,7 @@ void uvc_queue_cancel(struct uvc_video_queue *queue, int disconnect)
unsigned long flags;
spin_lock_irqsave(&queue->irqlock, flags);
uvc_queue_return_buffers(queue, UVC_BUF_STATE_ERROR);
__uvc_queue_return_buffers(queue, UVC_BUF_STATE_ERROR);
/*
* This must be protected by the irqlock spinlock to avoid race
* conditions between uvc_buffer_queue and the disconnection event that

View File

@ -26,7 +26,26 @@
#include "uvcvideo.h"
static int uvc_acquire_privileges(struct uvc_fh *handle);
int uvc_pm_get(struct uvc_device *dev)
{
int ret;
ret = usb_autopm_get_interface(dev->intf);
if (ret)
return ret;
ret = uvc_status_get(dev);
if (ret)
usb_autopm_put_interface(dev->intf);
return ret;
}
void uvc_pm_put(struct uvc_device *dev)
{
uvc_status_put(dev);
usb_autopm_put_interface(dev->intf);
}
static int uvc_control_add_xu_mapping(struct uvc_video_chain *chain,
struct uvc_control_mapping *map,
@ -310,14 +329,12 @@ static int uvc_v4l2_try_format(struct uvc_streaming *stream,
* developers test their webcams with the Linux driver as well as with
* the Windows driver).
*/
mutex_lock(&stream->mutex);
if (stream->dev->quirks & UVC_QUIRK_PROBE_EXTRAFIELDS)
probe->dwMaxVideoFrameSize =
stream->ctrl.dwMaxVideoFrameSize;
/* Probe the device. */
ret = uvc_probe_video(stream, probe);
mutex_unlock(&stream->mutex);
if (ret < 0)
return ret;
@ -376,19 +393,15 @@ static int uvc_ioctl_g_fmt(struct file *file, void *fh,
struct uvc_streaming *stream = handle->stream;
const struct uvc_format *format;
const struct uvc_frame *frame;
int ret = 0;
if (fmt->type != stream->type)
return -EINVAL;
mutex_lock(&stream->mutex);
format = stream->cur_format;
frame = stream->cur_frame;
if (format == NULL || frame == NULL) {
ret = -EINVAL;
goto done;
}
if (!format || !frame)
return -EINVAL;
fmt->fmt.pix.pixelformat = format->fcc;
fmt->fmt.pix.width = frame->wWidth;
@ -400,9 +413,7 @@ static int uvc_ioctl_g_fmt(struct file *file, void *fh,
fmt->fmt.pix.xfer_func = format->xfer_func;
fmt->fmt.pix.ycbcr_enc = format->ycbcr_enc;
done:
mutex_unlock(&stream->mutex);
return ret;
return 0;
}
static int uvc_ioctl_s_fmt(struct file *file, void *fh,
@ -415,10 +426,6 @@ static int uvc_ioctl_s_fmt(struct file *file, void *fh,
const struct uvc_frame *frame;
int ret;
ret = uvc_acquire_privileges(handle);
if (ret < 0)
return ret;
if (fmt->type != stream->type)
return -EINVAL;
@ -426,20 +433,14 @@ static int uvc_ioctl_s_fmt(struct file *file, void *fh,
if (ret < 0)
return ret;
mutex_lock(&stream->mutex);
if (uvc_queue_allocated(&stream->queue)) {
ret = -EBUSY;
goto done;
}
if (vb2_is_busy(&stream->queue.queue))
return -EBUSY;
stream->ctrl = probe;
stream->cur_format = format;
stream->cur_frame = frame;
done:
mutex_unlock(&stream->mutex);
return ret;
return 0;
}
static int uvc_ioctl_g_parm(struct file *file, void *fh,
@ -452,10 +453,7 @@ static int uvc_ioctl_g_parm(struct file *file, void *fh,
if (parm->type != stream->type)
return -EINVAL;
mutex_lock(&stream->mutex);
numerator = stream->ctrl.dwFrameInterval;
mutex_unlock(&stream->mutex);
denominator = 10000000;
v4l2_simplify_fraction(&numerator, &denominator, 8, 333);
@ -492,10 +490,6 @@ static int uvc_ioctl_s_parm(struct file *file, void *fh,
unsigned int i;
int ret;
ret = uvc_acquire_privileges(handle);
if (ret < 0)
return ret;
if (parm->type != stream->type)
return -EINVAL;
@ -509,12 +503,8 @@ static int uvc_ioctl_s_parm(struct file *file, void *fh,
uvc_dbg(stream->dev, FORMAT, "Setting frame interval to %u/%u (%u)\n",
timeperframe.numerator, timeperframe.denominator, interval);
mutex_lock(&stream->mutex);
if (uvc_queue_streaming(&stream->queue)) {
mutex_unlock(&stream->mutex);
if (uvc_queue_streaming(&stream->queue))
return -EBUSY;
}
format = stream->cur_format;
frame = stream->cur_frame;
@ -546,14 +536,11 @@ static int uvc_ioctl_s_parm(struct file *file, void *fh,
/* Probe the device with the new settings. */
ret = uvc_probe_video(stream, &probe);
if (ret < 0) {
mutex_unlock(&stream->mutex);
if (ret < 0)
return ret;
}
stream->ctrl = probe;
stream->cur_frame = frame;
mutex_unlock(&stream->mutex);
/* Return the actual frame period. */
timeperframe.numerator = probe.dwFrameInterval;
@ -572,63 +559,6 @@ static int uvc_ioctl_s_parm(struct file *file, void *fh,
return 0;
}
/* ------------------------------------------------------------------------
* Privilege management
*/
/*
* Privilege management is the multiple-open implementation basis. The current
* implementation is completely transparent for the end-user and doesn't
* require explicit use of the VIDIOC_G_PRIORITY and VIDIOC_S_PRIORITY ioctls.
* Those ioctls enable finer control on the device (by making possible for a
* user to request exclusive access to a device), but are not mature yet.
* Switching to the V4L2 priority mechanism might be considered in the future
* if this situation changes.
*
* Each open instance of a UVC device can either be in a privileged or
* unprivileged state. Only a single instance can be in a privileged state at
* a given time. Trying to perform an operation that requires privileges will
* automatically acquire the required privileges if possible, or return -EBUSY
* otherwise. Privileges are dismissed when closing the instance or when
* freeing the video buffers using VIDIOC_REQBUFS.
*
* Operations that require privileges are:
*
* - VIDIOC_S_INPUT
* - VIDIOC_S_PARM
* - VIDIOC_S_FMT
* - VIDIOC_CREATE_BUFS
* - VIDIOC_REQBUFS
*/
static int uvc_acquire_privileges(struct uvc_fh *handle)
{
/* Always succeed if the handle is already privileged. */
if (handle->state == UVC_HANDLE_ACTIVE)
return 0;
/* Check if the device already has a privileged handle. */
if (atomic_inc_return(&handle->stream->active) != 1) {
atomic_dec(&handle->stream->active);
return -EBUSY;
}
handle->state = UVC_HANDLE_ACTIVE;
return 0;
}
static void uvc_dismiss_privileges(struct uvc_fh *handle)
{
if (handle->state == UVC_HANDLE_ACTIVE)
atomic_dec(&handle->stream->active);
handle->state = UVC_HANDLE_PASSIVE;
}
static int uvc_has_privileges(struct uvc_fh *handle)
{
return handle->state == UVC_HANDLE_ACTIVE;
}
/* ------------------------------------------------------------------------
* V4L2 file operations
*/
@ -637,69 +567,43 @@ static int uvc_v4l2_open(struct file *file)
{
struct uvc_streaming *stream;
struct uvc_fh *handle;
int ret = 0;
stream = video_drvdata(file);
uvc_dbg(stream->dev, CALLS, "%s\n", __func__);
ret = usb_autopm_get_interface(stream->dev->intf);
if (ret < 0)
return ret;
/* Create the device handle. */
handle = kzalloc(sizeof(*handle), GFP_KERNEL);
if (handle == NULL) {
usb_autopm_put_interface(stream->dev->intf);
if (!handle)
return -ENOMEM;
}
ret = uvc_status_get(stream->dev);
if (ret) {
usb_autopm_put_interface(stream->dev->intf);
kfree(handle);
return ret;
}
v4l2_fh_init(&handle->vfh, &stream->vdev);
v4l2_fh_add(&handle->vfh);
handle->chain = stream->chain;
handle->stream = stream;
handle->state = UVC_HANDLE_PASSIVE;
file->private_data = handle;
file->private_data = &handle->vfh;
return 0;
}
static int uvc_v4l2_release(struct file *file)
{
struct uvc_fh *handle = file->private_data;
struct uvc_fh *handle = to_uvc_fh(file);
struct uvc_streaming *stream = handle->stream;
uvc_dbg(stream->dev, CALLS, "%s\n", __func__);
uvc_ctrl_cleanup_fh(handle);
/* Only free resources if this is a privileged handle. */
if (uvc_has_privileges(handle))
uvc_queue_release(&stream->queue);
/* Release the file handle. */
uvc_dismiss_privileges(handle);
v4l2_fh_del(&handle->vfh);
v4l2_fh_exit(&handle->vfh);
kfree(handle);
file->private_data = NULL;
vb2_fop_release(file);
uvc_status_put(stream->dev);
usb_autopm_put_interface(stream->dev->intf);
return 0;
}
static int uvc_ioctl_querycap(struct file *file, void *fh,
struct v4l2_capability *cap)
{
struct uvc_fh *handle = file->private_data;
struct uvc_fh *handle = to_uvc_fh(file);
struct uvc_video_chain *chain = handle->chain;
struct uvc_streaming *stream = handle->stream;
@ -746,124 +650,6 @@ static int uvc_ioctl_try_fmt(struct file *file, void *fh,
return uvc_v4l2_try_format(stream, fmt, &probe, NULL, NULL);
}
static int uvc_ioctl_reqbufs(struct file *file, void *fh,
struct v4l2_requestbuffers *rb)
{
struct uvc_fh *handle = fh;
struct uvc_streaming *stream = handle->stream;
int ret;
ret = uvc_acquire_privileges(handle);
if (ret < 0)
return ret;
mutex_lock(&stream->mutex);
ret = uvc_request_buffers(&stream->queue, rb);
mutex_unlock(&stream->mutex);
if (ret < 0)
return ret;
if (ret == 0)
uvc_dismiss_privileges(handle);
return 0;
}
static int uvc_ioctl_querybuf(struct file *file, void *fh,
struct v4l2_buffer *buf)
{
struct uvc_fh *handle = fh;
struct uvc_streaming *stream = handle->stream;
if (!uvc_has_privileges(handle))
return -EBUSY;
return uvc_query_buffer(&stream->queue, buf);
}
static int uvc_ioctl_qbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
{
struct uvc_fh *handle = fh;
struct uvc_streaming *stream = handle->stream;
if (!uvc_has_privileges(handle))
return -EBUSY;
return uvc_queue_buffer(&stream->queue,
stream->vdev.v4l2_dev->mdev, buf);
}
static int uvc_ioctl_expbuf(struct file *file, void *fh,
struct v4l2_exportbuffer *exp)
{
struct uvc_fh *handle = fh;
struct uvc_streaming *stream = handle->stream;
if (!uvc_has_privileges(handle))
return -EBUSY;
return uvc_export_buffer(&stream->queue, exp);
}
static int uvc_ioctl_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
{
struct uvc_fh *handle = fh;
struct uvc_streaming *stream = handle->stream;
if (!uvc_has_privileges(handle))
return -EBUSY;
return uvc_dequeue_buffer(&stream->queue, buf,
file->f_flags & O_NONBLOCK);
}
static int uvc_ioctl_create_bufs(struct file *file, void *fh,
struct v4l2_create_buffers *cb)
{
struct uvc_fh *handle = fh;
struct uvc_streaming *stream = handle->stream;
int ret;
ret = uvc_acquire_privileges(handle);
if (ret < 0)
return ret;
return uvc_create_buffers(&stream->queue, cb);
}
static int uvc_ioctl_streamon(struct file *file, void *fh,
enum v4l2_buf_type type)
{
struct uvc_fh *handle = fh;
struct uvc_streaming *stream = handle->stream;
int ret;
if (!uvc_has_privileges(handle))
return -EBUSY;
mutex_lock(&stream->mutex);
ret = uvc_queue_streamon(&stream->queue, type);
mutex_unlock(&stream->mutex);
return ret;
}
static int uvc_ioctl_streamoff(struct file *file, void *fh,
enum v4l2_buf_type type)
{
struct uvc_fh *handle = fh;
struct uvc_streaming *stream = handle->stream;
if (!uvc_has_privileges(handle))
return -EBUSY;
mutex_lock(&stream->mutex);
uvc_queue_streamoff(&stream->queue, type);
mutex_unlock(&stream->mutex);
return 0;
}
static int uvc_ioctl_enum_input(struct file *file, void *fh,
struct v4l2_input *input)
{
@ -938,13 +724,13 @@ static int uvc_ioctl_g_input(struct file *file, void *fh, unsigned int *input)
static int uvc_ioctl_s_input(struct file *file, void *fh, unsigned int input)
{
struct uvc_fh *handle = fh;
struct uvc_streaming *stream = handle->stream;
struct uvc_video_chain *chain = handle->chain;
u8 *buf;
int ret;
ret = uvc_acquire_privileges(handle);
if (ret < 0)
return ret;
if (vb2_is_busy(&stream->queue.queue))
return -EBUSY;
if (chain->selector == NULL ||
(chain->dev->quirks & UVC_QUIRK_IGNORE_SELECTOR_UNIT)) {
@ -1132,10 +918,8 @@ static int uvc_ioctl_g_selection(struct file *file, void *fh,
sel->r.left = 0;
sel->r.top = 0;
mutex_lock(&stream->mutex);
sel->r.width = stream->cur_frame->wWidth;
sel->r.height = stream->cur_frame->wHeight;
mutex_unlock(&stream->mutex);
return 0;
}
@ -1361,7 +1145,7 @@ static int uvc_v4l2_put_xu_query(const struct uvc_xu_control_query *kp,
static long uvc_v4l2_compat_ioctl32(struct file *file,
unsigned int cmd, unsigned long arg)
{
struct uvc_fh *handle = file->private_data;
struct uvc_fh *handle = to_uvc_fh(file);
union {
struct uvc_xu_control_mapping xmap;
struct uvc_xu_control_query xqry;
@ -1369,84 +1153,82 @@ static long uvc_v4l2_compat_ioctl32(struct file *file,
void __user *up = compat_ptr(arg);
long ret;
ret = uvc_pm_get(handle->stream->dev);
if (ret)
return ret;
switch (cmd) {
case UVCIOC_CTRL_MAP32:
ret = uvc_v4l2_get_xu_mapping(&karg.xmap, up);
if (ret)
return ret;
break;
ret = uvc_ioctl_xu_ctrl_map(handle->chain, &karg.xmap);
if (ret)
return ret;
break;
ret = uvc_v4l2_put_xu_mapping(&karg.xmap, up);
if (ret)
return ret;
break;
break;
case UVCIOC_CTRL_QUERY32:
ret = uvc_v4l2_get_xu_query(&karg.xqry, up);
if (ret)
return ret;
break;
ret = uvc_xu_ctrl_query(handle->chain, &karg.xqry);
if (ret)
return ret;
break;
ret = uvc_v4l2_put_xu_query(&karg.xqry, up);
if (ret)
return ret;
break;
break;
default:
return -ENOIOCTLCMD;
ret = -ENOIOCTLCMD;
break;
}
uvc_pm_put(handle->stream->dev);
return ret;
}
#endif
static ssize_t uvc_v4l2_read(struct file *file, char __user *data,
size_t count, loff_t *ppos)
static long uvc_v4l2_unlocked_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
struct uvc_fh *handle = file->private_data;
struct uvc_streaming *stream = handle->stream;
struct uvc_fh *handle = to_uvc_fh(file);
unsigned int converted_cmd = v4l2_translate_cmd(cmd);
int ret;
uvc_dbg(stream->dev, CALLS, "%s: not implemented\n", __func__);
return -EINVAL;
/* The following IOCTLs need to turn on the camera. */
switch (converted_cmd) {
case UVCIOC_CTRL_MAP:
case UVCIOC_CTRL_QUERY:
case VIDIOC_G_CTRL:
case VIDIOC_G_EXT_CTRLS:
case VIDIOC_G_INPUT:
case VIDIOC_QUERYCTRL:
case VIDIOC_QUERYMENU:
case VIDIOC_QUERY_EXT_CTRL:
case VIDIOC_S_CTRL:
case VIDIOC_S_EXT_CTRLS:
case VIDIOC_S_FMT:
case VIDIOC_S_INPUT:
case VIDIOC_S_PARM:
case VIDIOC_TRY_EXT_CTRLS:
case VIDIOC_TRY_FMT:
ret = uvc_pm_get(handle->stream->dev);
if (ret)
return ret;
ret = video_ioctl2(file, cmd, arg);
uvc_pm_put(handle->stream->dev);
return ret;
}
/* The other IOCTLs can run with the camera off. */
return video_ioctl2(file, cmd, arg);
}
static int uvc_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
{
struct uvc_fh *handle = file->private_data;
struct uvc_streaming *stream = handle->stream;
uvc_dbg(stream->dev, CALLS, "%s\n", __func__);
return uvc_queue_mmap(&stream->queue, vma);
}
static __poll_t uvc_v4l2_poll(struct file *file, poll_table *wait)
{
struct uvc_fh *handle = file->private_data;
struct uvc_streaming *stream = handle->stream;
uvc_dbg(stream->dev, CALLS, "%s\n", __func__);
return uvc_queue_poll(&stream->queue, file, wait);
}
#ifndef CONFIG_MMU
static unsigned long uvc_v4l2_get_unmapped_area(struct file *file,
unsigned long addr, unsigned long len, unsigned long pgoff,
unsigned long flags)
{
struct uvc_fh *handle = file->private_data;
struct uvc_streaming *stream = handle->stream;
uvc_dbg(stream->dev, CALLS, "%s\n", __func__);
return uvc_queue_get_unmapped_area(&stream->queue, pgoff);
}
#endif
const struct v4l2_ioctl_ops uvc_ioctl_ops = {
.vidioc_g_fmt_vid_cap = uvc_ioctl_g_fmt,
.vidioc_g_fmt_vid_out = uvc_ioctl_g_fmt,
@ -1459,14 +1241,15 @@ const struct v4l2_ioctl_ops uvc_ioctl_ops = {
.vidioc_enum_fmt_vid_out = uvc_ioctl_enum_fmt,
.vidioc_try_fmt_vid_cap = uvc_ioctl_try_fmt,
.vidioc_try_fmt_vid_out = uvc_ioctl_try_fmt,
.vidioc_reqbufs = uvc_ioctl_reqbufs,
.vidioc_querybuf = uvc_ioctl_querybuf,
.vidioc_qbuf = uvc_ioctl_qbuf,
.vidioc_expbuf = uvc_ioctl_expbuf,
.vidioc_dqbuf = uvc_ioctl_dqbuf,
.vidioc_create_bufs = uvc_ioctl_create_bufs,
.vidioc_streamon = uvc_ioctl_streamon,
.vidioc_streamoff = uvc_ioctl_streamoff,
.vidioc_reqbufs = vb2_ioctl_reqbufs,
.vidioc_querybuf = vb2_ioctl_querybuf,
.vidioc_prepare_buf = vb2_ioctl_prepare_buf,
.vidioc_qbuf = vb2_ioctl_qbuf,
.vidioc_expbuf = vb2_ioctl_expbuf,
.vidioc_dqbuf = vb2_ioctl_dqbuf,
.vidioc_create_bufs = vb2_ioctl_create_bufs,
.vidioc_streamon = vb2_ioctl_streamon,
.vidioc_streamoff = vb2_ioctl_streamoff,
.vidioc_enum_input = uvc_ioctl_enum_input,
.vidioc_g_input = uvc_ioctl_g_input,
.vidioc_s_input = uvc_ioctl_s_input,
@ -1487,15 +1270,14 @@ const struct v4l2_file_operations uvc_fops = {
.owner = THIS_MODULE,
.open = uvc_v4l2_open,
.release = uvc_v4l2_release,
.unlocked_ioctl = video_ioctl2,
.unlocked_ioctl = uvc_v4l2_unlocked_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl32 = uvc_v4l2_compat_ioctl32,
#endif
.read = uvc_v4l2_read,
.mmap = uvc_v4l2_mmap,
.poll = uvc_v4l2_poll,
.mmap = vb2_fop_mmap,
.poll = vb2_fop_poll,
#ifndef CONFIG_MMU
.get_unmapped_area = uvc_v4l2_get_unmapped_area,
.get_unmapped_area = vb2_fop_get_unmapped_area,
#endif
};

View File

@ -262,6 +262,15 @@ static void uvc_fixup_video_ctrl(struct uvc_streaming *stream,
ctrl->dwMaxPayloadTransferSize = bandwidth;
}
if (stream->intf->num_altsetting > 1 &&
ctrl->dwMaxPayloadTransferSize > stream->maxpsize) {
dev_warn_ratelimited(&stream->intf->dev,
"UVC non compliance: the max payload transmission size (%u) exceeds the size of the ep max packet (%u). Using the max size.\n",
ctrl->dwMaxPayloadTransferSize,
stream->maxpsize);
ctrl->dwMaxPayloadTransferSize = stream->maxpsize;
}
}
static size_t uvc_video_ctrl_size(struct uvc_streaming *stream)
@ -1433,12 +1442,6 @@ static void uvc_video_decode_meta(struct uvc_streaming *stream,
if (!meta_buf || length == 2)
return;
if (meta_buf->length - meta_buf->bytesused <
length + sizeof(meta->ns) + sizeof(meta->sof)) {
meta_buf->error = 1;
return;
}
has_pts = mem[1] & UVC_STREAM_PTS;
has_scr = mem[1] & UVC_STREAM_SCR;
@ -1459,6 +1462,12 @@ static void uvc_video_decode_meta(struct uvc_streaming *stream,
!memcmp(scr, stream->clock.last_scr, 6)))
return;
if (meta_buf->length - meta_buf->bytesused <
length + sizeof(meta->ns) + sizeof(meta->sof)) {
meta_buf->error = 1;
return;
}
meta = (struct uvc_meta_buf *)((u8 *)meta_buf->mem + meta_buf->bytesused);
local_irq_save(flags);
time = uvc_video_get_time();

View File

@ -77,6 +77,7 @@
#define UVC_QUIRK_DISABLE_AUTOSUSPEND 0x00008000
#define UVC_QUIRK_INVALID_DEVICE_SOF 0x00010000
#define UVC_QUIRK_MJPEG_NO_EOF 0x00020000
#define UVC_QUIRK_MSXU_META 0x00040000
/* Format flags */
#define UVC_FMT_FLAG_COMPRESSED 0x00000001
@ -134,6 +135,8 @@ struct uvc_control_mapping {
s32 master_manual;
u32 slave_ids[2];
bool disabled;
const struct uvc_control_mapping *(*filter_mapping)
(struct uvc_video_chain *chain,
struct uvc_control *ctrl);
@ -326,7 +329,10 @@ struct uvc_buffer {
struct uvc_video_queue {
struct vb2_queue queue;
struct mutex mutex; /* Protects queue */
struct mutex mutex; /*
* Serializes vb2_queue and
* fops
*/
unsigned int flags;
unsigned int buf_used;
@ -463,12 +469,6 @@ struct uvc_streaming {
const struct uvc_format *cur_format;
const struct uvc_frame *cur_frame;
/*
* Protect access to ctrl, cur_format, cur_frame and hardware video
* probe control.
*/
struct mutex mutex;
/* Buffers queue. */
unsigned int frozen : 1;
struct uvc_video_queue queue;
@ -570,6 +570,8 @@ struct uvc_status {
};
} __packed;
#define UVC_MAX_META_DATA_FORMATS 3
struct uvc_device {
struct usb_device *udev;
struct usb_interface *intf;
@ -580,6 +582,9 @@ struct uvc_device {
const struct uvc_device_info *info;
u32 meta_formats[UVC_MAX_META_DATA_FORMATS];
unsigned int nmeta_formats;
atomic_t nmappings;
/* Video control interface */
@ -619,19 +624,18 @@ struct uvc_device {
struct uvc_entity *gpio_unit;
};
enum uvc_handle_state {
UVC_HANDLE_PASSIVE = 0,
UVC_HANDLE_ACTIVE = 1,
};
struct uvc_fh {
struct v4l2_fh vfh;
struct uvc_video_chain *chain;
struct uvc_streaming *stream;
enum uvc_handle_state state;
unsigned int pending_async_ctrls;
};
static inline struct uvc_fh *to_uvc_fh(struct file *filp)
{
return container_of(filp->private_data, struct uvc_fh, vfh);
}
/* ------------------------------------------------------------------------
* Debugging, printing and logging
*/
@ -686,36 +690,11 @@ struct uvc_entity *uvc_entity_by_id(struct uvc_device *dev, int id);
/* Video buffers queue management. */
int uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type);
void uvc_queue_release(struct uvc_video_queue *queue);
int uvc_request_buffers(struct uvc_video_queue *queue,
struct v4l2_requestbuffers *rb);
int uvc_query_buffer(struct uvc_video_queue *queue,
struct v4l2_buffer *v4l2_buf);
int uvc_create_buffers(struct uvc_video_queue *queue,
struct v4l2_create_buffers *v4l2_cb);
int uvc_queue_buffer(struct uvc_video_queue *queue,
struct media_device *mdev,
struct v4l2_buffer *v4l2_buf);
int uvc_export_buffer(struct uvc_video_queue *queue,
struct v4l2_exportbuffer *exp);
int uvc_dequeue_buffer(struct uvc_video_queue *queue,
struct v4l2_buffer *v4l2_buf, int nonblocking);
int uvc_queue_streamon(struct uvc_video_queue *queue, enum v4l2_buf_type type);
int uvc_queue_streamoff(struct uvc_video_queue *queue, enum v4l2_buf_type type);
void uvc_queue_cancel(struct uvc_video_queue *queue, int disconnect);
struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue,
struct uvc_buffer *buf);
struct uvc_buffer *uvc_queue_get_current_buffer(struct uvc_video_queue *queue);
void uvc_queue_buffer_release(struct uvc_buffer *buf);
int uvc_queue_mmap(struct uvc_video_queue *queue,
struct vm_area_struct *vma);
__poll_t uvc_queue_poll(struct uvc_video_queue *queue, struct file *file,
poll_table *wait);
#ifndef CONFIG_MMU
unsigned long uvc_queue_get_unmapped_area(struct uvc_video_queue *queue,
unsigned long pgoff);
#endif
int uvc_queue_allocated(struct uvc_video_queue *queue);
static inline int uvc_queue_streaming(struct uvc_video_queue *queue)
{
return vb2_is_streaming(&queue->queue);
@ -748,6 +727,7 @@ int uvc_query_ctrl(struct uvc_device *dev, u8 query, u8 unit,
void uvc_video_clock_update(struct uvc_streaming *stream,
struct vb2_v4l2_buffer *vbuf,
struct uvc_buffer *buf);
int uvc_meta_init(struct uvc_device *dev);
int uvc_meta_register(struct uvc_streaming *stream);
int uvc_register_video_device(struct uvc_device *dev,
@ -767,6 +747,10 @@ void uvc_status_suspend(struct uvc_device *dev);
int uvc_status_get(struct uvc_device *dev);
void uvc_status_put(struct uvc_device *dev);
/* PM */
int uvc_pm_get(struct uvc_device *dev);
void uvc_pm_put(struct uvc_device *dev);
/* Controls */
extern const struct v4l2_subscribed_event_ops uvc_ctrl_sub_ev_ops;

View File

@ -154,13 +154,18 @@ void v4l_bound_align_image(u32 *w, unsigned int wmin, unsigned int wmax,
EXPORT_SYMBOL_GPL(v4l_bound_align_image);
const void *
__v4l2_find_nearest_size(const void *array, size_t array_size,
size_t entry_size, size_t width_offset,
size_t height_offset, s32 width, s32 height)
__v4l2_find_nearest_size_conditional(const void *array, size_t array_size,
size_t entry_size, size_t width_offset,
size_t height_offset, s32 width,
s32 height,
bool (*func)(const void *array,
size_t index,
const void *context),
const void *context)
{
u32 error, min_error = U32_MAX;
const void *best = NULL;
unsigned int i;
size_t i;
if (!array)
return NULL;
@ -169,6 +174,9 @@ __v4l2_find_nearest_size(const void *array, size_t array_size,
const u32 *entry_width = array + width_offset;
const u32 *entry_height = array + height_offset;
if (func && !func(array, i, context))
continue;
error = abs(*entry_width - width) + abs(*entry_height - height);
if (error > min_error)
continue;
@ -181,7 +189,7 @@ __v4l2_find_nearest_size(const void *array, size_t array_size,
return best;
}
EXPORT_SYMBOL_GPL(__v4l2_find_nearest_size);
EXPORT_SYMBOL_GPL(__v4l2_find_nearest_size_conditional);
int v4l2_g_parm_cap(struct video_device *vdev,
struct v4l2_subdev *sd, struct v4l2_streamparm *a)
@ -250,6 +258,7 @@ const struct v4l2_format_info *v4l2_format_info(u32 format)
{ .format = V4L2_PIX_FMT_ABGR32, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_BGRA32, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_RGB565, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_RGB565X, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_RGB555, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_BGR666, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_BGR48_12, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 6, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
@ -277,8 +286,10 @@ const struct v4l2_format_info *v4l2_format_info(u32 format)
/* YUV planar formats */
{ .format = V4L2_PIX_FMT_NV12, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 2, .vdiv = 2 },
{ .format = V4L2_PIX_FMT_NV21, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 2, .vdiv = 2 },
{ .format = V4L2_PIX_FMT_NV15, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 5, 10, 0, 0 }, .bpp_div = { 4, 4, 1, 1 }, .hdiv = 2, .vdiv = 2 },
{ .format = V4L2_PIX_FMT_NV16, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 2, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_NV61, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 2, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_NV20, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 5, 10, 0, 0 }, .bpp_div = { 4, 4, 1, 1 }, .hdiv = 2, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_NV24, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_NV42, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_P010, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 1, .comp_planes = 2, .bpp = { 2, 2, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 2, .vdiv = 1 },
@ -312,6 +323,12 @@ const struct v4l2_format_info *v4l2_format_info(u32 format)
{ .format = V4L2_PIX_FMT_NV61M, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 2, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 2, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_P012M, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 2, .comp_planes = 2, .bpp = { 2, 4, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 2, .vdiv = 2 },
/* Tiled YUV formats, non contiguous variant */
{ .format = V4L2_PIX_FMT_NV12MT, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 2, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 2, .vdiv = 2,
.block_w = { 64, 32, 0, 0 }, .block_h = { 32, 16, 0, 0 }},
{ .format = V4L2_PIX_FMT_NV12MT_16X16, .pixel_enc = V4L2_PIXEL_ENC_YUV, .mem_planes = 2, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 2, .vdiv = 2,
.block_w = { 16, 8, 0, 0 }, .block_h = { 16, 8, 0, 0 }},
/* Bayer RGB formats */
{ .format = V4L2_PIX_FMT_SBGGR8, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_SGBRG8, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
@ -321,6 +338,10 @@ const struct v4l2_format_info *v4l2_format_info(u32 format)
{ .format = V4L2_PIX_FMT_SGBRG10, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_SGRBG10, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_SRGGB10, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_SBGGR10P, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 5, 0, 0, 0 }, .bpp_div = { 4, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_SGBRG10P, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 5, 0, 0, 0 }, .bpp_div = { 4, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_SGRBG10P, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 5, 0, 0, 0 }, .bpp_div = { 4, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_SRGGB10P, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 5, 0, 0, 0 }, .bpp_div = { 4, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_SBGGR10ALAW8, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_SGBRG10ALAW8, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_SGRBG10ALAW8, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
@ -333,6 +354,28 @@ const struct v4l2_format_info *v4l2_format_info(u32 format)
{ .format = V4L2_PIX_FMT_SGBRG12, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_SGRBG12, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_SRGGB12, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_SBGGR12P, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 3, 0, 0, 0 }, .bpp_div = { 2, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_SGBRG12P, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 3, 0, 0, 0 }, .bpp_div = { 2, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_SGRBG12P, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 3, 0, 0, 0 }, .bpp_div = { 2, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_SRGGB12P, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 3, 0, 0, 0 }, .bpp_div = { 2, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_SBGGR14, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_SGBRG14, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_SGRBG14, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_SRGGB14, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_SBGGR14P, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 7, 0, 0, 0 }, .bpp_div = { 4, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_SGBRG14P, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 7, 0, 0, 0 }, .bpp_div = { 4, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_SGRBG14P, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 7, 0, 0, 0 }, .bpp_div = { 4, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_SRGGB14P, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 7, 0, 0, 0 }, .bpp_div = { 4, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_SBGGR16, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_SGBRG16, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_SGRBG16, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_SRGGB16, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
/* Renesas Camera Data Receiver Unit formats, bayer order agnostic */
{ .format = V4L2_PIX_FMT_RAW_CRU10, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 8, 0, 0, 0 }, .bpp_div = { 6, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_RAW_CRU12, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 8, 0, 0, 0 }, .bpp_div = { 5, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_RAW_CRU14, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 8, 0, 0, 0 }, .bpp_div = { 4, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_RAW_CRU20, .pixel_enc = V4L2_PIXEL_ENC_BAYER, .mem_planes = 1, .comp_planes = 1, .bpp = { 8, 0, 0, 0 }, .bpp_div = { 3, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
};
unsigned int i;
@ -357,6 +400,34 @@ static inline unsigned int v4l2_format_block_height(const struct v4l2_format_inf
return info->block_h[plane];
}
static inline unsigned int v4l2_format_plane_stride(const struct v4l2_format_info *info, int plane,
unsigned int width)
{
unsigned int hdiv = plane ? info->hdiv : 1;
unsigned int aligned_width =
ALIGN(width, v4l2_format_block_width(info, plane));
return DIV_ROUND_UP(aligned_width, hdiv) *
info->bpp[plane] / info->bpp_div[plane];
}
static inline unsigned int v4l2_format_plane_height(const struct v4l2_format_info *info, int plane,
unsigned int height)
{
unsigned int vdiv = plane ? info->vdiv : 1;
unsigned int aligned_height =
ALIGN(height, v4l2_format_block_height(info, plane));
return DIV_ROUND_UP(aligned_height, vdiv);
}
static inline unsigned int v4l2_format_plane_size(const struct v4l2_format_info *info, int plane,
unsigned int width, unsigned int height)
{
return v4l2_format_plane_stride(info, plane, width) *
v4l2_format_plane_height(info, plane, height);
}
void v4l2_apply_frmsize_constraints(u32 *width, u32 *height,
const struct v4l2_frmsize_stepwise *frmsize)
{
@ -392,37 +463,19 @@ int v4l2_fill_pixfmt_mp(struct v4l2_pix_format_mplane *pixfmt,
if (info->mem_planes == 1) {
plane = &pixfmt->plane_fmt[0];
plane->bytesperline = ALIGN(width, v4l2_format_block_width(info, 0)) * info->bpp[0] / info->bpp_div[0];
plane->bytesperline = v4l2_format_plane_stride(info, 0, width);
plane->sizeimage = 0;
for (i = 0; i < info->comp_planes; i++) {
unsigned int hdiv = (i == 0) ? 1 : info->hdiv;
unsigned int vdiv = (i == 0) ? 1 : info->vdiv;
unsigned int aligned_width;
unsigned int aligned_height;
aligned_width = ALIGN(width, v4l2_format_block_width(info, i));
aligned_height = ALIGN(height, v4l2_format_block_height(info, i));
plane->sizeimage += info->bpp[i] *
DIV_ROUND_UP(aligned_width, hdiv) *
DIV_ROUND_UP(aligned_height, vdiv) / info->bpp_div[i];
}
for (i = 0; i < info->comp_planes; i++)
plane->sizeimage +=
v4l2_format_plane_size(info, i, width, height);
} else {
for (i = 0; i < info->comp_planes; i++) {
unsigned int hdiv = (i == 0) ? 1 : info->hdiv;
unsigned int vdiv = (i == 0) ? 1 : info->vdiv;
unsigned int aligned_width;
unsigned int aligned_height;
aligned_width = ALIGN(width, v4l2_format_block_width(info, i));
aligned_height = ALIGN(height, v4l2_format_block_height(info, i));
plane = &pixfmt->plane_fmt[i];
plane->bytesperline =
info->bpp[i] * DIV_ROUND_UP(aligned_width, hdiv) / info->bpp_div[i];
plane->sizeimage =
plane->bytesperline * DIV_ROUND_UP(aligned_height, vdiv);
v4l2_format_plane_stride(info, i, width);
plane->sizeimage = plane->bytesperline *
v4l2_format_plane_height(info, i, height);
}
}
return 0;
@ -446,28 +499,18 @@ int v4l2_fill_pixfmt(struct v4l2_pix_format *pixfmt, u32 pixelformat,
pixfmt->width = width;
pixfmt->height = height;
pixfmt->pixelformat = pixelformat;
pixfmt->bytesperline = ALIGN(width, v4l2_format_block_width(info, 0)) * info->bpp[0] / info->bpp_div[0];
pixfmt->bytesperline = v4l2_format_plane_stride(info, 0, width);
pixfmt->sizeimage = 0;
for (i = 0; i < info->comp_planes; i++) {
unsigned int hdiv = (i == 0) ? 1 : info->hdiv;
unsigned int vdiv = (i == 0) ? 1 : info->vdiv;
unsigned int aligned_width;
unsigned int aligned_height;
aligned_width = ALIGN(width, v4l2_format_block_width(info, i));
aligned_height = ALIGN(height, v4l2_format_block_height(info, i));
pixfmt->sizeimage += info->bpp[i] *
DIV_ROUND_UP(aligned_width, hdiv) *
DIV_ROUND_UP(aligned_height, vdiv) / info->bpp_div[i];
}
for (i = 0; i < info->comp_planes; i++)
pixfmt->sizeimage +=
v4l2_format_plane_size(info, i, width, height);
return 0;
}
EXPORT_SYMBOL_GPL(v4l2_fill_pixfmt);
s64 v4l2_get_link_freq(struct v4l2_ctrl_handler *handler, unsigned int mul,
unsigned int div)
s64 __v4l2_get_link_freq_ctrl(struct v4l2_ctrl_handler *handler,
unsigned int mul, unsigned int div)
{
struct v4l2_ctrl *ctrl;
s64 freq;
@ -494,15 +537,41 @@ s64 v4l2_get_link_freq(struct v4l2_ctrl_handler *handler, unsigned int mul,
freq = div_u64(v4l2_ctrl_g_ctrl_int64(ctrl) * mul, div);
pr_warn("%s: Link frequency estimated using pixel rate: result might be inaccurate\n",
__func__);
pr_warn("%s: Consider implementing support for V4L2_CID_LINK_FREQ in the transmitter driver\n",
__func__);
pr_warn_once("%s: Link frequency estimated using pixel rate: result might be inaccurate\n",
__func__);
pr_warn_once("%s: Consider implementing support for V4L2_CID_LINK_FREQ in the transmitter driver\n",
__func__);
}
return freq > 0 ? freq : -EINVAL;
}
EXPORT_SYMBOL_GPL(v4l2_get_link_freq);
EXPORT_SYMBOL_GPL(__v4l2_get_link_freq_ctrl);
#ifdef CONFIG_MEDIA_CONTROLLER
s64 __v4l2_get_link_freq_pad(struct media_pad *pad, unsigned int mul,
unsigned int div)
{
struct v4l2_mbus_config mbus_config = {};
struct v4l2_subdev *sd;
int ret;
sd = media_entity_to_v4l2_subdev(pad->entity);
ret = v4l2_subdev_call(sd, pad, get_mbus_config, pad->index,
&mbus_config);
if (ret < 0 && ret != -ENOIOCTLCMD)
return ret;
if (mbus_config.link_freq)
return mbus_config.link_freq;
/*
* Fall back to using the link frequency control if the media bus config
* doesn't provide a link frequency.
*/
return __v4l2_get_link_freq_ctrl(sd->ctrl_handler, mul, div);
}
EXPORT_SYMBOL_GPL(__v4l2_get_link_freq_pad);
#endif /* CONFIG_MEDIA_CONTROLLER */
/*
* Simplify a fraction using a simple continued fraction decomposition. The

View File

@ -1157,6 +1157,36 @@ int v4l2_query_ext_ctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_query_ext_ctr
}
EXPORT_SYMBOL(v4l2_query_ext_ctrl);
void v4l2_query_ext_ctrl_to_v4l2_queryctrl(struct v4l2_queryctrl *to,
const struct v4l2_query_ext_ctrl *from)
{
to->id = from->id;
to->type = from->type;
to->flags = from->flags;
strscpy(to->name, from->name, sizeof(to->name));
switch (from->type) {
case V4L2_CTRL_TYPE_INTEGER:
case V4L2_CTRL_TYPE_BOOLEAN:
case V4L2_CTRL_TYPE_MENU:
case V4L2_CTRL_TYPE_INTEGER_MENU:
case V4L2_CTRL_TYPE_STRING:
case V4L2_CTRL_TYPE_BITMASK:
to->minimum = from->minimum;
to->maximum = from->maximum;
to->step = from->step;
to->default_value = from->default_value;
break;
default:
to->minimum = 0;
to->maximum = 0;
to->step = 0;
to->default_value = 0;
break;
}
}
EXPORT_SYMBOL(v4l2_query_ext_ctrl_to_v4l2_queryctrl);
/* Implement VIDIOC_QUERYCTRL */
int v4l2_queryctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_queryctrl *qc)
{
@ -1167,29 +1197,8 @@ int v4l2_queryctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_queryctrl *qc)
if (rc)
return rc;
qc->id = qec.id;
qc->type = qec.type;
qc->flags = qec.flags;
strscpy(qc->name, qec.name, sizeof(qc->name));
switch (qc->type) {
case V4L2_CTRL_TYPE_INTEGER:
case V4L2_CTRL_TYPE_BOOLEAN:
case V4L2_CTRL_TYPE_MENU:
case V4L2_CTRL_TYPE_INTEGER_MENU:
case V4L2_CTRL_TYPE_STRING:
case V4L2_CTRL_TYPE_BITMASK:
qc->minimum = qec.minimum;
qc->maximum = qec.maximum;
qc->step = qec.step;
qc->default_value = qec.default_value;
break;
default:
qc->minimum = 0;
qc->maximum = 0;
qc->step = 0;
qc->default_value = 0;
break;
}
v4l2_query_ext_ctrl_to_v4l2_queryctrl(qc, &qec);
return 0;
}
EXPORT_SYMBOL(v4l2_queryctrl);

View File

@ -437,9 +437,9 @@ void v4l2_ctrl_type_op_log(const struct v4l2_ctrl *ctrl)
pr_cont("AV1_FILM_GRAIN");
break;
case V4L2_CTRL_TYPE_RECT:
pr_cont("%ux%u@%dx%d",
ptr.p_rect->width, ptr.p_rect->height,
ptr.p_rect->left, ptr.p_rect->top);
pr_cont("(%d,%d)/%ux%u",
ptr.p_rect->left, ptr.p_rect->top,
ptr.p_rect->width, ptr.p_rect->height);
break;
default:
pr_cont("unknown type %d", ctrl->type);
@ -968,12 +968,12 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx,
p_h264_sps->flags &=
~V4L2_H264_SPS_FLAG_QPPRIME_Y_ZERO_TRANSFORM_BYPASS;
if (p_h264_sps->chroma_format_idc < 3)
p_h264_sps->flags &=
~V4L2_H264_SPS_FLAG_SEPARATE_COLOUR_PLANE;
}
if (p_h264_sps->chroma_format_idc < 3)
p_h264_sps->flags &=
~V4L2_H264_SPS_FLAG_SEPARATE_COLOUR_PLANE;
if (p_h264_sps->flags & V4L2_H264_SPS_FLAG_FRAME_MBS_ONLY)
p_h264_sps->flags &=
~V4L2_H264_SPS_FLAG_MB_ADAPTIVE_FRAME_FIELD;
@ -1631,14 +1631,17 @@ int v4l2_ctrl_handler_init_class(struct v4l2_ctrl_handler *hdl,
EXPORT_SYMBOL(v4l2_ctrl_handler_init_class);
/* Free all controls and control refs */
void v4l2_ctrl_handler_free(struct v4l2_ctrl_handler *hdl)
int v4l2_ctrl_handler_free(struct v4l2_ctrl_handler *hdl)
{
struct v4l2_ctrl_ref *ref, *next_ref;
struct v4l2_ctrl *ctrl, *next_ctrl;
struct v4l2_subscribed_event *sev, *next_sev;
if (hdl == NULL || hdl->buckets == NULL)
return;
if (!hdl)
return 0;
if (!hdl->buckets)
return hdl->error;
v4l2_ctrl_handler_free_request(hdl);
@ -1661,9 +1664,10 @@ void v4l2_ctrl_handler_free(struct v4l2_ctrl_handler *hdl)
kvfree(hdl->buckets);
hdl->buckets = NULL;
hdl->cached = NULL;
hdl->error = 0;
mutex_unlock(hdl->lock);
mutex_destroy(&hdl->_lock);
return hdl->error;
}
EXPORT_SYMBOL(v4l2_ctrl_handler_free);

View File

@ -572,13 +572,13 @@ static void determine_valid_ioctls(struct video_device *vdev)
and that can't be tested here. If the bit for these control ioctls
is set, then the ioctl is valid. But if it is 0, then it can still
be valid if the filehandle passed the control handler. */
if (vdev->ctrl_handler || ops->vidioc_queryctrl)
if (vdev->ctrl_handler || ops->vidioc_query_ext_ctrl)
__set_bit(_IOC_NR(VIDIOC_QUERYCTRL), valid_ioctls);
if (vdev->ctrl_handler || ops->vidioc_query_ext_ctrl)
__set_bit(_IOC_NR(VIDIOC_QUERY_EXT_CTRL), valid_ioctls);
if (vdev->ctrl_handler || ops->vidioc_g_ctrl || ops->vidioc_g_ext_ctrls)
if (vdev->ctrl_handler || ops->vidioc_g_ext_ctrls)
__set_bit(_IOC_NR(VIDIOC_G_CTRL), valid_ioctls);
if (vdev->ctrl_handler || ops->vidioc_s_ctrl || ops->vidioc_s_ext_ctrls)
if (vdev->ctrl_handler || ops->vidioc_s_ext_ctrls)
__set_bit(_IOC_NR(VIDIOC_S_CTRL), valid_ioctls);
if (vdev->ctrl_handler || ops->vidioc_g_ext_ctrls)
__set_bit(_IOC_NR(VIDIOC_G_EXT_CTRLS), valid_ioctls);
@ -1054,25 +1054,25 @@ int __video_register_device(struct video_device *vdev,
vdev->dev.class = &video_class;
vdev->dev.devt = MKDEV(VIDEO_MAJOR, vdev->minor);
vdev->dev.parent = vdev->dev_parent;
vdev->dev.release = v4l2_device_release;
dev_set_name(&vdev->dev, "%s%d", name_base, vdev->num);
/* Increase v4l2_device refcount */
v4l2_device_get(vdev->v4l2_dev);
mutex_lock(&videodev_lock);
ret = device_register(&vdev->dev);
if (ret < 0) {
mutex_unlock(&videodev_lock);
pr_err("%s: device_register failed\n", __func__);
goto cleanup;
put_device(&vdev->dev);
return ret;
}
/* Register the release callback that will be called when the last
reference to the device goes away. */
vdev->dev.release = v4l2_device_release;
if (nr != -1 && nr != vdev->num && warn_if_nr_in_use)
pr_warn("%s: requested %s%d, got %s\n", __func__,
name_base, nr, video_device_node_name(vdev));
/* Increase v4l2_device refcount */
v4l2_device_get(vdev->v4l2_dev);
/* Part 5: Register the entity. */
ret = video_register_media_controller(vdev);

View File

@ -764,7 +764,7 @@ bool v4l2_detect_gtf(unsigned int frame_height,
u64 num;
u32 den;
num = ((image_width * GTF_D_C_PRIME * (u64)hfreq) -
num = (((u64)image_width * GTF_D_C_PRIME * hfreq) -
((u64)image_width * GTF_D_M_PRIME * 1000));
den = (hfreq * (100 - GTF_D_C_PRIME) + GTF_D_M_PRIME * 1000) *
(2 * GTF_CELL_GRAN);
@ -774,7 +774,7 @@ bool v4l2_detect_gtf(unsigned int frame_height,
u64 num;
u32 den;
num = ((image_width * GTF_S_C_PRIME * (u64)hfreq) -
num = (((u64)image_width * GTF_S_C_PRIME * hfreq) -
((u64)image_width * GTF_S_M_PRIME * 1000));
den = (hfreq * (100 - GTF_S_C_PRIME) + GTF_S_M_PRIME * 1000) *
(2 * GTF_CELL_GRAN);
@ -1017,6 +1017,42 @@ v4l2_hdmi_rx_colorimetry(const struct hdmi_avi_infoframe *avi,
}
EXPORT_SYMBOL_GPL(v4l2_hdmi_rx_colorimetry);
/**
* v4l2_num_edid_blocks() - return the number of EDID blocks
*
* @edid: pointer to the EDID data
* @max_blocks: maximum number of supported EDID blocks
*
* Return: the number of EDID blocks based on the contents of the EDID.
* This supports the HDMI Forum EDID Extension Override Data Block.
*/
unsigned int v4l2_num_edid_blocks(const u8 *edid, unsigned int max_blocks)
{
unsigned int blocks;
if (!edid || !max_blocks)
return 0;
// The number of extension blocks is recorded at byte 126 of the
// first 128-byte block in the EDID.
//
// If there is an HDMI Forum EDID Extension Override Data Block
// present, then it is in bytes 4-6 of the first CTA-861 extension
// block of the EDID.
blocks = edid[126] + 1;
// Check for HDMI Forum EDID Extension Override Data Block
if (blocks >= 2 && // The EDID must be at least 2 blocks
max_blocks >= 3 && // The caller supports at least 3 blocks
edid[128] == 2 && // The first extension block is type CTA-861
edid[133] == 0x78 && // Identifier for the EEODB
(edid[132] & 0xe0) == 0xe0 && // Tag Code == 7
(edid[132] & 0x1f) >= 2 && // Length >= 2
edid[134] > 1) // Number of extension blocks is sane
blocks = edid[134] + 1;
return blocks > max_blocks ? max_blocks : blocks;
}
EXPORT_SYMBOL_GPL(v4l2_num_edid_blocks);
/**
* v4l2_get_edid_phys_addr() - find and return the physical address
*

View File

@ -5,6 +5,7 @@
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/property.h>
#include <media/v4l2-common.h>
#include <media/v4l2-device.h>
@ -24,7 +25,7 @@ void v4l2_i2c_subdev_unregister(struct v4l2_subdev *sd)
* registered by us, and would not be
* re-created by just probing the V4L2 driver.
*/
if (client && !client->dev.of_node && !client->dev.fwnode)
if (client && !dev_fwnode(&client->dev))
i2c_unregister_device(client);
}

View File

@ -310,8 +310,8 @@ static void v4l_print_format(const void *arg, bool write_only)
case V4L2_BUF_TYPE_VIDEO_OVERLAY:
case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
win = &p->fmt.win;
pr_cont(", wxh=%dx%d, x,y=%d,%d, field=%s, chromakey=0x%08x, global_alpha=0x%02x\n",
win->w.width, win->w.height, win->w.left, win->w.top,
pr_cont(", (%d,%d)/%ux%u, field=%s, chromakey=0x%08x, global_alpha=0x%02x\n",
win->w.left, win->w.top, win->w.width, win->w.height,
prt_names(win->field, v4l2_field_names),
win->chromakey, win->global_alpha);
break;
@ -589,12 +589,12 @@ static void v4l_print_cropcap(const void *arg, bool write_only)
{
const struct v4l2_cropcap *p = arg;
pr_cont("type=%s, bounds wxh=%dx%d, x,y=%d,%d, defrect wxh=%dx%d, x,y=%d,%d, pixelaspect %d/%d\n",
pr_cont("type=%s, bounds (%d,%d)/%ux%u, defrect (%d,%d)/%ux%u, pixelaspect %d/%d\n",
prt_names(p->type, v4l2_type_names),
p->bounds.width, p->bounds.height,
p->bounds.left, p->bounds.top,
p->defrect.width, p->defrect.height,
p->bounds.width, p->bounds.height,
p->defrect.left, p->defrect.top,
p->defrect.width, p->defrect.height,
p->pixelaspect.numerator, p->pixelaspect.denominator);
}
@ -602,20 +602,20 @@ static void v4l_print_crop(const void *arg, bool write_only)
{
const struct v4l2_crop *p = arg;
pr_cont("type=%s, wxh=%dx%d, x,y=%d,%d\n",
pr_cont("type=%s, crop=(%d,%d)/%ux%u\n",
prt_names(p->type, v4l2_type_names),
p->c.width, p->c.height,
p->c.left, p->c.top);
p->c.left, p->c.top,
p->c.width, p->c.height);
}
static void v4l_print_selection(const void *arg, bool write_only)
{
const struct v4l2_selection *p = arg;
pr_cont("type=%s, target=%d, flags=0x%x, wxh=%dx%d, x,y=%d,%d\n",
pr_cont("type=%s, target=%d, flags=0x%x, rect=(%d,%d)/%ux%u\n",
prt_names(p->type, v4l2_type_names),
p->target, p->flags,
p->r.width, p->r.height, p->r.left, p->r.top);
p->r.left, p->r.top, p->r.width, p->r.height);
}
static void v4l_print_jpegcompression(const void *arg, bool write_only)
@ -1363,8 +1363,10 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt)
case V4L2_PIX_FMT_YUV48_12: descr = "12-bit YUV 4:4:4 Packed"; break;
case V4L2_PIX_FMT_NV12: descr = "Y/UV 4:2:0"; break;
case V4L2_PIX_FMT_NV21: descr = "Y/VU 4:2:0"; break;
case V4L2_PIX_FMT_NV15: descr = "10-bit Y/UV 4:2:0 (Packed)"; break;
case V4L2_PIX_FMT_NV16: descr = "Y/UV 4:2:2"; break;
case V4L2_PIX_FMT_NV61: descr = "Y/VU 4:2:2"; break;
case V4L2_PIX_FMT_NV20: descr = "10-bit Y/UV 4:2:2 (Packed)"; break;
case V4L2_PIX_FMT_NV24: descr = "Y/UV 4:4:4"; break;
case V4L2_PIX_FMT_NV42: descr = "Y/VU 4:4:4"; break;
case V4L2_PIX_FMT_P010: descr = "10-bit Y/UV 4:2:0"; break;
@ -1411,6 +1413,7 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt)
case V4L2_PIX_FMT_SGBRG10DPCM8: descr = "8-bit Bayer GBGB/RGRG (DPCM)"; break;
case V4L2_PIX_FMT_SGRBG10DPCM8: descr = "8-bit Bayer GRGR/BGBG (DPCM)"; break;
case V4L2_PIX_FMT_SRGGB10DPCM8: descr = "8-bit Bayer RGRG/GBGB (DPCM)"; break;
case V4L2_PIX_FMT_RAW_CRU10: descr = "10-bit Raw CRU Packed"; break;
case V4L2_PIX_FMT_SBGGR12: descr = "12-bit Bayer BGBG/GRGR"; break;
case V4L2_PIX_FMT_SGBRG12: descr = "12-bit Bayer GBGB/RGRG"; break;
case V4L2_PIX_FMT_SGRBG12: descr = "12-bit Bayer GRGR/BGBG"; break;
@ -1419,6 +1422,7 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt)
case V4L2_PIX_FMT_SGBRG12P: descr = "12-bit Bayer GBGB/RGRG Packed"; break;
case V4L2_PIX_FMT_SGRBG12P: descr = "12-bit Bayer GRGR/BGBG Packed"; break;
case V4L2_PIX_FMT_SRGGB12P: descr = "12-bit Bayer RGRG/GBGB Packed"; break;
case V4L2_PIX_FMT_RAW_CRU12: descr = "12-bit Raw CRU Packed"; break;
case V4L2_PIX_FMT_SBGGR14: descr = "14-bit Bayer BGBG/GRGR"; break;
case V4L2_PIX_FMT_SGBRG14: descr = "14-bit Bayer GBGB/RGRG"; break;
case V4L2_PIX_FMT_SGRBG14: descr = "14-bit Bayer GRGR/BGBG"; break;
@ -1427,10 +1431,12 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt)
case V4L2_PIX_FMT_SGBRG14P: descr = "14-bit Bayer GBGB/RGRG Packed"; break;
case V4L2_PIX_FMT_SGRBG14P: descr = "14-bit Bayer GRGR/BGBG Packed"; break;
case V4L2_PIX_FMT_SRGGB14P: descr = "14-bit Bayer RGRG/GBGB Packed"; break;
case V4L2_PIX_FMT_RAW_CRU14: descr = "14-bit Raw CRU Packed"; break;
case V4L2_PIX_FMT_SBGGR16: descr = "16-bit Bayer BGBG/GRGR"; break;
case V4L2_PIX_FMT_SGBRG16: descr = "16-bit Bayer GBGB/RGRG"; break;
case V4L2_PIX_FMT_SGRBG16: descr = "16-bit Bayer GRGR/BGBG"; break;
case V4L2_PIX_FMT_SRGGB16: descr = "16-bit Bayer RGRG/GBGB"; break;
case V4L2_PIX_FMT_RAW_CRU20: descr = "14-bit Raw CRU Packed"; break;
case V4L2_PIX_FMT_SN9C20X_I420: descr = "GSPCA SN9C20X I420"; break;
case V4L2_PIX_FMT_SPCA501: descr = "GSPCA SPCA501"; break;
case V4L2_PIX_FMT_SPCA505: descr = "GSPCA SPCA505"; break;
@ -1457,11 +1463,14 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt)
case V4L2_META_FMT_VSP1_HGO: descr = "R-Car VSP1 1-D Histogram"; break;
case V4L2_META_FMT_VSP1_HGT: descr = "R-Car VSP1 2-D Histogram"; break;
case V4L2_META_FMT_UVC: descr = "UVC Payload Header Metadata"; break;
case V4L2_META_FMT_UVC_MSXU_1_5: descr = "UVC MSXU Metadata"; break;
case V4L2_META_FMT_D4XX: descr = "Intel D4xx UVC Metadata"; break;
case V4L2_META_FMT_VIVID: descr = "Vivid Metadata"; break;
case V4L2_META_FMT_RK_ISP1_PARAMS: descr = "Rockchip ISP1 3A Parameters"; break;
case V4L2_META_FMT_RK_ISP1_STAT_3A: descr = "Rockchip ISP1 3A Statistics"; break;
case V4L2_META_FMT_RK_ISP1_EXT_PARAMS: descr = "Rockchip ISP1 Ext 3A Params"; break;
case V4L2_META_FMT_C3ISP_PARAMS: descr = "Amlogic C3 ISP Parameters"; break;
case V4L2_META_FMT_C3ISP_STATS: descr = "Amlogic C3 ISP Statistics"; break;
case V4L2_PIX_FMT_NV12_8L128: descr = "NV12 (8x128 Linear)"; break;
case V4L2_PIX_FMT_NV12M_8L128: descr = "NV12M (8x128 Linear)"; break;
case V4L2_PIX_FMT_NV12_10BE_8L128: descr = "10-bit NV12 (8x128 Linear, BE)"; break;
@ -2284,17 +2293,26 @@ static int v4l_queryctrl(const struct v4l2_ioctl_ops *ops,
struct file *file, void *fh, void *arg)
{
struct video_device *vfd = video_devdata(file);
struct v4l2_query_ext_ctrl qec = {};
struct v4l2_queryctrl *p = arg;
struct v4l2_fh *vfh =
test_bit(V4L2_FL_USES_V4L2_FH, &vfd->flags) ? fh : NULL;
int ret;
if (vfh && vfh->ctrl_handler)
return v4l2_queryctrl(vfh->ctrl_handler, p);
if (vfd->ctrl_handler)
return v4l2_queryctrl(vfd->ctrl_handler, p);
if (ops->vidioc_queryctrl)
return ops->vidioc_queryctrl(file, fh, p);
return -ENOTTY;
if (!ops->vidioc_query_ext_ctrl)
return -ENOTTY;
/* Simulate query_ext_ctr using query_ctrl. */
qec.id = p->id;
ret = ops->vidioc_query_ext_ctrl(file, fh, &qec);
if (ret)
return ret;
v4l2_query_ext_ctrl_to_v4l2_queryctrl(p, &qec);
return ret;
}
static int v4l_query_ext_ctrl(const struct v4l2_ioctl_ops *ops,
@ -2345,8 +2363,6 @@ static int v4l_g_ctrl(const struct v4l2_ioctl_ops *ops,
return v4l2_g_ctrl(vfh->ctrl_handler, p);
if (vfd->ctrl_handler)
return v4l2_g_ctrl(vfd->ctrl_handler, p);
if (ops->vidioc_g_ctrl)
return ops->vidioc_g_ctrl(file, fh, p);
if (ops->vidioc_g_ext_ctrls == NULL)
return -ENOTTY;
@ -2380,8 +2396,6 @@ static int v4l_s_ctrl(const struct v4l2_ioctl_ops *ops,
return v4l2_s_ctrl(vfh, vfh->ctrl_handler, p);
if (vfd->ctrl_handler)
return v4l2_s_ctrl(NULL, vfd->ctrl_handler, p);
if (ops->vidioc_s_ctrl)
return ops->vidioc_s_ctrl(file, fh, p);
if (ops->vidioc_s_ext_ctrls == NULL)
return -ENOTTY;
@ -2826,8 +2840,7 @@ static int v4l_enum_freq_bands(const struct v4l2_ioctl_ops *ops,
p->capability = m.capability | V4L2_TUNER_CAP_FREQ_BANDS;
p->rangelow = m.rangelow;
p->rangehigh = m.rangehigh;
p->modulation = (type == V4L2_TUNER_RADIO) ?
V4L2_BAND_MODULATION_FM : V4L2_BAND_MODULATION_VSB;
p->modulation = V4L2_BAND_MODULATION_FM;
return 0;
}
return -ENOTTY;
@ -3235,7 +3248,7 @@ static int check_array_args(unsigned int cmd, void *parg, size_t *array_size,
return ret;
}
static unsigned int video_translate_cmd(unsigned int cmd)
unsigned int v4l2_translate_cmd(unsigned int cmd)
{
#if !defined(CONFIG_64BIT) && defined(CONFIG_COMPAT_32BIT_TIME)
switch (cmd) {
@ -3256,6 +3269,7 @@ static unsigned int video_translate_cmd(unsigned int cmd)
return cmd;
}
EXPORT_SYMBOL_GPL(v4l2_translate_cmd);
static int video_get_user(void __user *arg, void *parg,
unsigned int real_cmd, unsigned int cmd,
@ -3416,7 +3430,7 @@ video_usercopy(struct file *file, unsigned int orig_cmd, unsigned long arg,
size_t array_size = 0;
void __user *user_ptr = NULL;
void **kernel_ptr = NULL;
unsigned int cmd = video_translate_cmd(orig_cmd);
unsigned int cmd = v4l2_translate_cmd(orig_cmd);
const size_t ioc_size = _IOC_SIZE(cmd);
/* Copy arguments into temp kernel buffer */

View File

@ -711,83 +711,3 @@ int v4l2_jpeg_parse_header(void *buf, size_t len, struct v4l2_jpeg_header *out)
return marker;
}
EXPORT_SYMBOL_GPL(v4l2_jpeg_parse_header);
/**
* v4l2_jpeg_parse_frame_header - parse frame header
* @buf: address of the frame header, after the SOF0 marker
* @len: length of the frame header
* @frame_header: returns the parsed frame header
*
* Returns 0 or negative error if parsing failed.
*/
int v4l2_jpeg_parse_frame_header(void *buf, size_t len,
struct v4l2_jpeg_frame_header *frame_header)
{
struct jpeg_stream stream;
stream.curr = buf;
stream.end = stream.curr + len;
return jpeg_parse_frame_header(&stream, SOF0, frame_header);
}
EXPORT_SYMBOL_GPL(v4l2_jpeg_parse_frame_header);
/**
* v4l2_jpeg_parse_scan_header - parse scan header
* @buf: address of the scan header, after the SOS marker
* @len: length of the scan header
* @scan_header: returns the parsed scan header
*
* Returns 0 or negative error if parsing failed.
*/
int v4l2_jpeg_parse_scan_header(void *buf, size_t len,
struct v4l2_jpeg_scan_header *scan_header)
{
struct jpeg_stream stream;
stream.curr = buf;
stream.end = stream.curr + len;
return jpeg_parse_scan_header(&stream, scan_header);
}
EXPORT_SYMBOL_GPL(v4l2_jpeg_parse_scan_header);
/**
* v4l2_jpeg_parse_quantization_tables - parse quantization tables segment
* @buf: address of the quantization table segment, after the DQT marker
* @len: length of the quantization table segment
* @precision: sample precision (P) in bits per component
* @q_tables: returns four references into the buffer for the
* four possible quantization table destinations
*
* Returns 0 or negative error if parsing failed.
*/
int v4l2_jpeg_parse_quantization_tables(void *buf, size_t len, u8 precision,
struct v4l2_jpeg_reference *q_tables)
{
struct jpeg_stream stream;
stream.curr = buf;
stream.end = stream.curr + len;
return jpeg_parse_quantization_tables(&stream, precision, q_tables);
}
EXPORT_SYMBOL_GPL(v4l2_jpeg_parse_quantization_tables);
/**
* v4l2_jpeg_parse_huffman_tables - parse huffman tables segment
* @buf: address of the Huffman table segment, after the DHT marker
* @len: length of the Huffman table segment
* @huffman_tables: returns four references into the buffer for the
* four possible Huffman table destinations, in
* the order DC0, DC1, AC0, AC1
*
* Returns 0 or negative error if parsing failed.
*/
int v4l2_jpeg_parse_huffman_tables(void *buf, size_t len,
struct v4l2_jpeg_reference *huffman_tables)
{
struct jpeg_stream stream;
stream.curr = buf;
stream.end = stream.curr + len;
return jpeg_parse_huffman_tables(&stream, huffman_tables);
}
EXPORT_SYMBOL_GPL(v4l2_jpeg_parse_huffman_tables);

View File

@ -444,6 +444,8 @@ static int call_enum_dv_timings(struct v4l2_subdev *sd,
static int call_get_mbus_config(struct v4l2_subdev *sd, unsigned int pad,
struct v4l2_mbus_config *config)
{
memset(config, 0, sizeof(*config));
return check_pad(sd, pad) ? :
sd->ops->pad->get_mbus_config(sd, pad, config);
}
@ -1002,6 +1004,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg,
struct v4l2_subdev_route *routes =
(struct v4l2_subdev_route *)(uintptr_t)routing->routes;
struct v4l2_subdev_krouting krouting = {};
unsigned int num_active_routes = 0;
unsigned int i;
if (!v4l2_subdev_enable_streams_api)
@ -1039,8 +1042,21 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg,
if (!(pads[route->source_pad].flags &
MEDIA_PAD_FL_SOURCE))
return -EINVAL;
if (route->flags & V4L2_SUBDEV_ROUTE_FL_ACTIVE)
num_active_routes++;
}
/*
* Drivers that implement routing need to report a frame
* descriptor accordingly, with up to one entry per route. Until
* the frame descriptors entries get allocated dynamically,
* limit the number of active routes to
* V4L2_FRAME_DESC_ENTRY_MAX.
*/
if (num_active_routes > V4L2_FRAME_DESC_ENTRY_MAX)
return -E2BIG;
/*
* If the driver doesn't support setting routing, just return
* the routing table.
@ -2217,6 +2233,9 @@ static void v4l2_subdev_collect_streams(struct v4l2_subdev *sd,
*found_streams = BIT_ULL(0);
*enabled_streams =
(sd->enabled_pads & BIT_ULL(pad)) ? BIT_ULL(0) : 0;
dev_dbg(sd->dev,
"collect_streams: sub-device \"%s\" does not support streams\n",
sd->entity.name);
return;
}
@ -2234,6 +2253,10 @@ static void v4l2_subdev_collect_streams(struct v4l2_subdev *sd,
if (cfg->enabled)
*enabled_streams |= BIT_ULL(cfg->stream);
}
dev_dbg(sd->dev,
"collect_streams: \"%s\":%u: found %#llx enabled %#llx\n",
sd->entity.name, pad, *found_streams, *enabled_streams);
}
static void v4l2_subdev_set_streams_enabled(struct v4l2_subdev *sd,
@ -2269,6 +2292,9 @@ int v4l2_subdev_enable_streams(struct v4l2_subdev *sd, u32 pad,
bool use_s_stream;
int ret;
dev_dbg(dev, "enable streams \"%s\":%u/%#llx\n", sd->entity.name, pad,
streams_mask);
/* A few basic sanity checks first. */
if (pad >= sd->entity.num_pads)
return -EINVAL;
@ -2316,8 +2342,6 @@ int v4l2_subdev_enable_streams(struct v4l2_subdev *sd, u32 pad,
goto done;
}
dev_dbg(dev, "enable streams %u:%#llx\n", pad, streams_mask);
already_streaming = v4l2_subdev_is_streaming(sd);
if (!use_s_stream) {
@ -2369,6 +2393,9 @@ int v4l2_subdev_disable_streams(struct v4l2_subdev *sd, u32 pad,
bool use_s_stream;
int ret;
dev_dbg(dev, "disable streams \"%s\":%u/%#llx\n", sd->entity.name, pad,
streams_mask);
/* A few basic sanity checks first. */
if (pad >= sd->entity.num_pads)
return -EINVAL;
@ -2416,8 +2443,6 @@ int v4l2_subdev_disable_streams(struct v4l2_subdev *sd, u32 pad,
goto done;
}
dev_dbg(dev, "disable streams %u:%#llx\n", pad, streams_mask);
if (!use_s_stream) {
/* Call the .disable_streams() operation. */
ret = v4l2_subdev_call(sd, pad, disable_streams, state, pad,

View File

@ -2366,11 +2366,6 @@ skip_mac_set:
unblock_netpoll_tx();
}
/* broadcast mode uses the all_slaves to loop through slaves. */
if (bond_mode_can_use_xmit_hash(bond) ||
BOND_MODE(bond) == BOND_MODE_BROADCAST)
bond_update_slave_arr(bond, NULL);
if (!slave_dev->netdev_ops->ndo_bpf ||
!slave_dev->netdev_ops->ndo_xdp_xmit) {
if (bond->xdp_prog) {
@ -2404,6 +2399,11 @@ skip_mac_set:
bpf_prog_inc(bond->xdp_prog);
}
/* broadcast mode uses the all_slaves to loop through slaves. */
if (bond_mode_can_use_xmit_hash(bond) ||
BOND_MODE(bond) == BOND_MODE_BROADCAST)
bond_update_slave_arr(bond, NULL);
bond_xdp_set_features(bond_dev);
slave_info(bond_dev, slave_dev, "Enslaving as %s interface with %s link\n",

View File

@ -921,6 +921,7 @@ ice_get_rx_buf(struct ice_rx_ring *rx_ring, const unsigned int size,
if (!size) {
rx_buf->pagecnt_bias--;
rx_buf->has_data = false;
return rx_buf;
}
/* we are reusing so sync this buffer for CPU use */
@ -930,6 +931,7 @@ ice_get_rx_buf(struct ice_rx_ring *rx_ring, const unsigned int size,
/* We have pulled a buffer for use, so decrement pagecnt_bias */
rx_buf->pagecnt_bias--;
rx_buf->has_data = true;
return rx_buf;
}
@ -1142,25 +1144,15 @@ static void ice_put_rx_mbuf(struct ice_rx_ring *rx_ring, struct xdp_buff *xdp,
u32 idx = rx_ring->first_desc;
u32 cnt = rx_ring->count;
struct ice_rx_buf *buf;
u32 xdp_frags = 0;
int i = 0;
if (unlikely(xdp_buff_has_frags(xdp)))
xdp_frags = xdp_get_shared_info_from_buff(xdp)->nr_frags;
while (idx != ntc) {
buf = &rx_ring->rx_buf[idx];
if (++idx == cnt)
idx = 0;
/* An XDP program could release fragments from the end of the
* buffer. For these, we need to keep the pagecnt_bias as-is.
* To do this, only adjust pagecnt_bias for fragments up to
* the total remaining after the XDP program has run.
*/
if (verdict != ICE_XDP_CONSUMED)
if (verdict != ICE_XDP_CONSUMED && buf->has_data)
ice_rx_buf_adjust_pg_offset(buf, xdp->frame_sz);
else if (i++ <= xdp_frags)
else
buf->pagecnt_bias++;
ice_put_rx_buf(rx_ring, buf);

View File

@ -203,6 +203,7 @@ struct ice_rx_buf {
unsigned int page_offset;
unsigned int pgcnt;
unsigned int pagecnt_bias;
bool has_data;
};
struct ice_q_stats {

View File

@ -1295,12 +1295,15 @@ mlx5_eswitch_enable_pf_vf_vports(struct mlx5_eswitch *esw,
ret = mlx5_eswitch_load_pf_vf_vport(esw, MLX5_VPORT_ECPF, enabled_events);
if (ret)
goto ecpf_err;
if (mlx5_core_ec_sriov_enabled(esw->dev)) {
ret = mlx5_eswitch_load_ec_vf_vports(esw, esw->esw_funcs.num_ec_vfs,
enabled_events);
if (ret)
goto ec_vf_err;
}
}
/* Enable ECVF vports */
if (mlx5_core_ec_sriov_enabled(esw->dev)) {
ret = mlx5_eswitch_load_ec_vf_vports(esw,
esw->esw_funcs.num_ec_vfs,
enabled_events);
if (ret)
goto ec_vf_err;
}
/* Enable VF vports */
@ -1331,9 +1334,11 @@ void mlx5_eswitch_disable_pf_vf_vports(struct mlx5_eswitch *esw)
{
mlx5_eswitch_unload_vf_vports(esw, esw->esw_funcs.num_vfs);
if (mlx5_core_ec_sriov_enabled(esw->dev))
mlx5_eswitch_unload_ec_vf_vports(esw,
esw->esw_funcs.num_ec_vfs);
if (mlx5_ecpf_vport_exists(esw->dev)) {
if (mlx5_core_ec_sriov_enabled(esw->dev))
mlx5_eswitch_unload_ec_vf_vports(esw, esw->esw_funcs.num_vfs);
mlx5_eswitch_unload_pf_vf_vport(esw, MLX5_VPORT_ECPF);
}

View File

@ -1563,10 +1563,16 @@ destroy_macvlan_port:
/* the macvlan port may be freed by macvlan_uninit when fail to register.
* so we destroy the macvlan port only when it's valid.
*/
if (create && macvlan_port_get_rtnl(lowerdev)) {
if (macvlan_port_get_rtnl(lowerdev)) {
macvlan_flush_sources(port, vlan);
macvlan_port_destroy(port->dev);
if (create)
macvlan_port_destroy(port->dev);
}
/* @dev might have been made visible before an error was detected.
* Make sure to observe an RCU grace period before our caller
* (rtnl_newlink()) frees it.
*/
synchronize_net();
return err;
}
EXPORT_SYMBOL_GPL(macvlan_common_newlink);

View File

@ -785,8 +785,11 @@ void iscsit_dec_session_usage_count(struct iscsit_session *sess)
spin_lock_bh(&sess->session_usage_lock);
sess->session_usage_count--;
if (!sess->session_usage_count && sess->session_waiting_on_uc)
if (!sess->session_usage_count && sess->session_waiting_on_uc) {
spin_unlock_bh(&sess->session_usage_lock);
complete(&sess->session_waiting_on_uc_comp);
return;
}
spin_unlock_bh(&sess->session_usage_lock);
}

View File

@ -4203,6 +4203,18 @@ skb_header_pointer(const struct sk_buff *skb, int offset, int len, void *buffer)
skb_headlen(skb), buffer);
}
/* Variant of skb_header_pointer() where @offset is user-controlled
* and potentially negative.
*/
static inline void * __must_check
skb_header_pointer_careful(const struct sk_buff *skb, int offset,
int len, void *buffer)
{
if (unlikely(offset < 0 && -offset > skb_headroom(skb)))
return NULL;
return skb_header_pointer(skb, offset, len, buffer);
}
static inline void * __must_check
skb_pointer_if_linear(const struct sk_buff *skb, int offset, int len)
{

View File

@ -29,6 +29,9 @@
#define UVC_GUID_EXT_GPIO_CONTROLLER \
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03}
#define UVC_GUID_MSXU_1_5 \
{0xdc, 0x95, 0x3f, 0x0f, 0x32, 0x26, 0x4e, 0x4c, \
0x92, 0xc9, 0xa0, 0x47, 0x82, 0xf4, 0x3b, 0xc8}
#define UVC_GUID_FORMAT_MJPEG \
{ 'M', 'J', 'P', 'G', 0x00, 0x00, 0x10, 0x00, \

View File

@ -390,15 +390,59 @@ void v4l_bound_align_image(unsigned int *width, unsigned int wmin,
unsigned int salign);
/**
* v4l2_find_nearest_size - Find the nearest size among a discrete
* set of resolutions contained in an array of a driver specific struct.
* v4l2_find_nearest_size_conditional - Find the nearest size among a discrete
* set of resolutions contained in an array of a driver specific struct,
* with conditionally exlusion of certain modes
*
* @array: a driver specific array of image sizes
* @array_size: the length of the driver specific array of image sizes
* @width_field: the name of the width field in the driver specific struct
* @height_field: the name of the height field in the driver specific struct
* @width: desired width.
* @height: desired height.
* @width: desired width
* @height: desired height
* @func: ignores mode if returns false
* @context: context for the function
*
* Finds the closest resolution to minimize the width and height differences
* between what requested and the supported resolutions. The size of the width
* and height fields in the driver specific must equal to that of u32, i.e. four
* bytes. @func is called for each mode considered, a mode is ignored if @func
* returns false for it.
*
* Returns the best match or NULL if the length of the array is zero.
*/
#define v4l2_find_nearest_size_conditional(array, array_size, width_field, \
height_field, width, height, \
func, context) \
({ \
BUILD_BUG_ON(sizeof((array)->width_field) != sizeof(u32) || \
sizeof((array)->height_field) != sizeof(u32)); \
(typeof(&(array)[0]))__v4l2_find_nearest_size_conditional( \
(array), array_size, sizeof(*(array)), \
offsetof(typeof(*(array)), width_field), \
offsetof(typeof(*(array)), height_field), \
width, height, func, context); \
})
const void *
__v4l2_find_nearest_size_conditional(const void *array, size_t array_size,
size_t entry_size, size_t width_offset,
size_t height_offset, s32 width,
s32 height,
bool (*func)(const void *array,
size_t index,
const void *context),
const void *context);
/**
* v4l2_find_nearest_size - Find the nearest size among a discrete set of
* resolutions contained in an array of a driver specific struct
*
* @array: a driver specific array of image sizes
* @array_size: the length of the driver specific array of image sizes
* @width_field: the name of the width field in the driver specific struct
* @height_field: the name of the height field in the driver specific struct
* @width: desired width
* @height: desired height
*
* Finds the closest resolution to minimize the width and height differences
* between what requested and the supported resolutions. The size of the width
@ -407,21 +451,11 @@ void v4l_bound_align_image(unsigned int *width, unsigned int wmin,
*
* Returns the best match or NULL if the length of the array is zero.
*/
#define v4l2_find_nearest_size(array, array_size, width_field, height_field, \
width, height) \
({ \
BUILD_BUG_ON(sizeof((array)->width_field) != sizeof(u32) || \
sizeof((array)->height_field) != sizeof(u32)); \
(typeof(&(array)[0]))__v4l2_find_nearest_size( \
(array), array_size, sizeof(*(array)), \
offsetof(typeof(*(array)), width_field), \
offsetof(typeof(*(array)), height_field), \
width, height); \
})
const void *
__v4l2_find_nearest_size(const void *array, size_t array_size,
size_t entry_size, size_t width_offset,
size_t height_offset, s32 width, s32 height);
#define v4l2_find_nearest_size(array, array_size, width_field, \
height_field, width, height) \
v4l2_find_nearest_size_conditional(array, array_size, width_field, \
height_field, width, height, NULL, \
NULL)
/**
* v4l2_g_parm_cap - helper routine for vidioc_g_parm to fill this in by
@ -525,7 +559,8 @@ int v4l2_fill_pixfmt_mp(struct v4l2_pix_format_mplane *pixfmt, u32 pixelformat,
/**
* v4l2_get_link_freq - Get link rate from transmitter
*
* @handler: The transmitter's control handler
* @pad: The transmitter's media pad (or control handler for non-MC users or
* compatibility reasons, don't use in new code)
* @mul: The multiplier between pixel rate and link frequency. Bits per pixel on
* D-PHY, samples per clock on parallel. 0 otherwise.
* @div: The divisor between pixel rate and link frequency. Number of data lanes
@ -541,8 +576,20 @@ int v4l2_fill_pixfmt_mp(struct v4l2_pix_format_mplane *pixfmt, u32 pixelformat,
* * %-ENOENT: Link frequency or pixel rate control not found
* * %-EINVAL: Invalid link frequency value
*/
s64 v4l2_get_link_freq(struct v4l2_ctrl_handler *handler, unsigned int mul,
unsigned int div);
#ifdef CONFIG_MEDIA_CONTROLLER
#define v4l2_get_link_freq(pad, mul, div) \
_Generic(pad, \
struct media_pad *: __v4l2_get_link_freq_pad, \
struct v4l2_ctrl_handler *: __v4l2_get_link_freq_ctrl) \
(pad, mul, div)
s64 __v4l2_get_link_freq_pad(struct media_pad *pad, unsigned int mul,
unsigned int div);
#else
#define v4l2_get_link_freq(handler, mul, div) \
__v4l2_get_link_freq_ctrl(handler, mul, div)
#endif
s64 __v4l2_get_link_freq_ctrl(struct v4l2_ctrl_handler *handler,
unsigned int mul, unsigned int div);
void v4l2_simplify_fraction(u32 *numerator, u32 *denominator,
unsigned int n_terms, unsigned int threshold);

View File

@ -579,8 +579,10 @@ int v4l2_ctrl_handler_init_class(struct v4l2_ctrl_handler *hdl,
* @hdl: The control handler.
*
* Does nothing if @hdl == NULL.
*
* Return: @hdl's error field or 0 if @hdl is NULL.
*/
void v4l2_ctrl_handler_free(struct v4l2_ctrl_handler *hdl);
int v4l2_ctrl_handler_free(struct v4l2_ctrl_handler *hdl);
/**
* v4l2_ctrl_lock() - Helper function to lock the handler
@ -1432,6 +1434,18 @@ v4l2_ctrl_request_hdl_ctrl_find(struct v4l2_ctrl_handler *hdl, u32 id);
*/
int v4l2_queryctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_queryctrl *qc);
/**
* v4l2_query_ext_ctrl_to_v4l2_queryctrl - Convert a qec to qe.
*
* @to: The v4l2_queryctrl to write to.
* @from: The v4l2_query_ext_ctrl to read from.
*
* This function is a helper to convert a v4l2_query_ext_ctrl into a
* v4l2_queryctrl.
*/
void v4l2_query_ext_ctrl_to_v4l2_queryctrl(struct v4l2_queryctrl *to,
const struct v4l2_query_ext_ctrl *from);
/**
* v4l2_query_ext_ctrl - Helper function to implement
* :ref:`VIDIOC_QUERY_EXT_CTRL <vidioc_queryctrl>` ioctl

View File

@ -252,6 +252,7 @@ v4l2_hdmi_rx_colorimetry(const struct hdmi_avi_infoframe *avi,
const struct hdmi_vendor_infoframe *hdmi,
unsigned int height);
unsigned int v4l2_num_edid_blocks(const u8 *edid, unsigned int max_blocks);
u16 v4l2_get_edid_phys_addr(const u8 *edid, unsigned int size,
unsigned int *offset);
void v4l2_set_edid_phys_addr(u8 *edid, unsigned int size, u16 phys_addr);

View File

@ -193,14 +193,8 @@ struct v4l2_fh;
* :ref:`VIDIOC_G_OUTPUT <vidioc_g_output>` ioctl
* @vidioc_s_output: pointer to the function that implements
* :ref:`VIDIOC_S_OUTPUT <vidioc_g_output>` ioctl
* @vidioc_queryctrl: pointer to the function that implements
* :ref:`VIDIOC_QUERYCTRL <vidioc_queryctrl>` ioctl
* @vidioc_query_ext_ctrl: pointer to the function that implements
* :ref:`VIDIOC_QUERY_EXT_CTRL <vidioc_queryctrl>` ioctl
* @vidioc_g_ctrl: pointer to the function that implements
* :ref:`VIDIOC_G_CTRL <vidioc_g_ctrl>` ioctl
* @vidioc_s_ctrl: pointer to the function that implements
* :ref:`VIDIOC_S_CTRL <vidioc_g_ctrl>` ioctl
* @vidioc_g_ext_ctrls: pointer to the function that implements
* :ref:`VIDIOC_G_EXT_CTRLS <vidioc_g_ext_ctrls>` ioctl
* @vidioc_s_ext_ctrls: pointer to the function that implements
@ -461,14 +455,8 @@ struct v4l2_ioctl_ops {
int (*vidioc_s_output)(struct file *file, void *fh, unsigned int i);
/* Control handling */
int (*vidioc_queryctrl)(struct file *file, void *fh,
struct v4l2_queryctrl *a);
int (*vidioc_query_ext_ctrl)(struct file *file, void *fh,
struct v4l2_query_ext_ctrl *a);
int (*vidioc_g_ctrl)(struct file *file, void *fh,
struct v4l2_control *a);
int (*vidioc_s_ctrl)(struct file *file, void *fh,
struct v4l2_control *a);
int (*vidioc_g_ext_ctrls)(struct file *file, void *fh,
struct v4l2_ext_controls *a);
int (*vidioc_s_ext_ctrls)(struct file *file, void *fh,
@ -691,6 +679,7 @@ long int v4l2_compat_ioctl32(struct file *file, unsigned int cmd,
#endif
unsigned int v4l2_compat_translate_cmd(unsigned int cmd);
unsigned int v4l2_translate_cmd(unsigned int cmd);
int v4l2_compat_get_user(void __user *arg, void *parg, unsigned int cmd);
int v4l2_compat_put_user(void __user *arg, void *parg, unsigned int cmd);
int v4l2_compat_get_array_args(struct file *file, void *mbuf,

View File

@ -169,15 +169,6 @@ struct v4l2_jpeg_header {
int v4l2_jpeg_parse_header(void *buf, size_t len, struct v4l2_jpeg_header *out);
int v4l2_jpeg_parse_frame_header(void *buf, size_t len,
struct v4l2_jpeg_frame_header *frame_header);
int v4l2_jpeg_parse_scan_header(void *buf, size_t len,
struct v4l2_jpeg_scan_header *scan_header);
int v4l2_jpeg_parse_quantization_tables(void *buf, size_t len, u8 precision,
struct v4l2_jpeg_reference *q_tables);
int v4l2_jpeg_parse_huffman_tables(void *buf, size_t len,
struct v4l2_jpeg_reference *huffman_tables);
extern const u8 v4l2_jpeg_zigzag_scan_index[V4L2_JPEG_PIXELS_IN_BLOCK];
extern const u8 v4l2_jpeg_ref_table_luma_qt[V4L2_JPEG_PIXELS_IN_BLOCK];
extern const u8 v4l2_jpeg_ref_table_chroma_qt[V4L2_JPEG_PIXELS_IN_BLOCK];

View File

@ -169,6 +169,7 @@ enum v4l2_mbus_type {
/**
* struct v4l2_mbus_config - media bus configuration
* @type: interface type
* @link_freq: The link frequency. See also V4L2_CID_LINK_FREQ control.
* @bus: bus configuration data structure
* @bus.parallel: embedded &struct v4l2_mbus_config_parallel.
* Used if the bus is parallel or BT.656.
@ -183,6 +184,7 @@ enum v4l2_mbus_type {
*/
struct v4l2_mbus_config {
enum v4l2_mbus_type type;
u64 link_freq;
union {
struct v4l2_mbus_config_parallel parallel;
struct v4l2_mbus_config_mipi_csi1 mipi_csi1;

View File

@ -822,7 +822,9 @@ struct v4l2_subdev_state {
* possible configuration from the remote end, likely calling
* this operation as close as possible to stream on time. The
* operation shall fail if the pad index it has been called on
* is not valid or in case of unrecoverable failures.
* is not valid or in case of unrecoverable failures. The
* config argument has been memset to 0 just before calling
* the op.
*
* @set_routing: Enable or disable data connection routes described in the
* subdevice routing table. Subdevs that implement this operation

View File

@ -643,8 +643,10 @@ struct v4l2_pix_format {
/* two planes -- one Y, one Cr + Cb interleaved */
#define V4L2_PIX_FMT_NV12 v4l2_fourcc('N', 'V', '1', '2') /* 12 Y/CbCr 4:2:0 */
#define V4L2_PIX_FMT_NV21 v4l2_fourcc('N', 'V', '2', '1') /* 12 Y/CrCb 4:2:0 */
#define V4L2_PIX_FMT_NV15 v4l2_fourcc('N', 'V', '1', '5') /* 15 Y/CbCr 4:2:0 10-bit packed */
#define V4L2_PIX_FMT_NV16 v4l2_fourcc('N', 'V', '1', '6') /* 16 Y/CbCr 4:2:2 */
#define V4L2_PIX_FMT_NV61 v4l2_fourcc('N', 'V', '6', '1') /* 16 Y/CrCb 4:2:2 */
#define V4L2_PIX_FMT_NV20 v4l2_fourcc('N', 'V', '2', '0') /* 20 Y/CbCr 4:2:2 10-bit packed */
#define V4L2_PIX_FMT_NV24 v4l2_fourcc('N', 'V', '2', '4') /* 24 Y/CbCr 4:4:4 */
#define V4L2_PIX_FMT_NV42 v4l2_fourcc('N', 'V', '4', '2') /* 24 Y/CrCb 4:4:4 */
#define V4L2_PIX_FMT_P010 v4l2_fourcc('P', '0', '1', '0') /* 24 Y/CbCr 4:2:0 10-bit per component */
@ -830,6 +832,12 @@ struct v4l2_pix_format {
#define V4L2_PIX_FMT_PISP_COMP2_BGGR v4l2_fourcc('P', 'C', '2', 'B') /* PiSP 8-bit mode 2 compressed BGGR bayer */
#define V4L2_PIX_FMT_PISP_COMP2_MONO v4l2_fourcc('P', 'C', '2', 'M') /* PiSP 8-bit mode 2 compressed monochrome */
/* Renesas RZ/V2H CRU packed formats. 64-bit units with contiguous pixels */
#define V4L2_PIX_FMT_RAW_CRU10 v4l2_fourcc('C', 'R', '1', '0')
#define V4L2_PIX_FMT_RAW_CRU12 v4l2_fourcc('C', 'R', '1', '2')
#define V4L2_PIX_FMT_RAW_CRU14 v4l2_fourcc('C', 'R', '1', '4')
#define V4L2_PIX_FMT_RAW_CRU20 v4l2_fourcc('C', 'R', '2', '0')
/* SDR formats - used only for Software Defined Radio devices */
#define V4L2_SDR_FMT_CU8 v4l2_fourcc('C', 'U', '0', '8') /* IQ u8 */
#define V4L2_SDR_FMT_CU16LE v4l2_fourcc('C', 'U', '1', '6') /* IQ u16le */
@ -851,6 +859,7 @@ struct v4l2_pix_format {
#define V4L2_META_FMT_VSP1_HGT v4l2_fourcc('V', 'S', 'P', 'T') /* R-Car VSP1 2-D Histogram */
#define V4L2_META_FMT_UVC v4l2_fourcc('U', 'V', 'C', 'H') /* UVC Payload Header metadata */
#define V4L2_META_FMT_D4XX v4l2_fourcc('D', '4', 'X', 'X') /* D4XX Payload Header metadata */
#define V4L2_META_FMT_UVC_MSXU_1_5 v4l2_fourcc('U', 'V', 'C', 'M') /* UVC MSXU metadata */
#define V4L2_META_FMT_VIVID v4l2_fourcc('V', 'I', 'V', 'D') /* Vivid Metadata */
/* Vendor specific - used for RK_ISP1 camera sub-system */
@ -858,6 +867,10 @@ struct v4l2_pix_format {
#define V4L2_META_FMT_RK_ISP1_STAT_3A v4l2_fourcc('R', 'K', '1', 'S') /* Rockchip ISP1 3A Statistics */
#define V4L2_META_FMT_RK_ISP1_EXT_PARAMS v4l2_fourcc('R', 'K', '1', 'E') /* Rockchip ISP1 3a Extensible Parameters */
/* Vendor specific - used for C3_ISP */
#define V4L2_META_FMT_C3ISP_PARAMS v4l2_fourcc('C', '3', 'P', 'M') /* Amlogic C3 ISP Parameters */
#define V4L2_META_FMT_C3ISP_STATS v4l2_fourcc('C', '3', 'S', 'T') /* Amlogic C3 ISP Statistics */
/* Vendor specific - used for RaspberryPi PiSP */
#define V4L2_META_FMT_RPI_BE_CFG v4l2_fourcc('R', 'P', 'B', 'C') /* PiSP BE configuration */

View File

@ -716,7 +716,7 @@ static int damon_sysfs_context_add_dirs(struct damon_sysfs_context *context)
err = damon_sysfs_context_set_targets(context);
if (err)
goto put_attrs_out;
goto rmdir_put_attrs_out;
err = damon_sysfs_context_set_schemes(context);
if (err)
@ -726,7 +726,8 @@ static int damon_sysfs_context_add_dirs(struct damon_sysfs_context *context)
put_targets_attrs_out:
kobject_put(&context->targets->kobj);
context->targets = NULL;
put_attrs_out:
rmdir_put_attrs_out:
damon_sysfs_attrs_rm_dirs(context->attrs);
kobject_put(&context->attrs->kobj);
context->attrs = NULL;
return err;

View File

@ -1949,6 +1949,7 @@ static void set_ssp_complete(struct hci_dev *hdev, void *data, int err)
}
mgmt_cmd_status(cmd->sk, cmd->hdev->id, cmd->opcode, mgmt_err);
mgmt_pending_free(cmd);
return;
}
@ -1967,6 +1968,7 @@ static void set_ssp_complete(struct hci_dev *hdev, void *data, int err)
sock_put(match.sk);
hci_update_eir_sync(hdev);
mgmt_pending_free(cmd);
}
static int set_ssp_sync(struct hci_dev *hdev, void *data)
@ -6350,6 +6352,7 @@ static void set_advertising_complete(struct hci_dev *hdev, void *data, int err)
hci_dev_clear_flag(hdev, HCI_ADVERTISING);
settings_rsp(cmd, &match);
mgmt_pending_free(cmd);
new_settings(hdev, match.sk);

View File

@ -161,10 +161,8 @@ next_knode:
int toff = off + key->off + (off2 & key->offmask);
__be32 *data, hdata;
if (skb_headroom(skb) + toff > INT_MAX)
goto out;
data = skb_header_pointer(skb, toff, 4, &hdata);
data = skb_header_pointer_careful(skb, toff, 4,
&hdata);
if (!data)
goto out;
if ((*data ^ key->val) & key->mask) {
@ -214,8 +212,9 @@ check_terminal:
if (ht->divisor) {
__be32 *data, hdata;
data = skb_header_pointer(skb, off + n->sel.hoff, 4,
&hdata);
data = skb_header_pointer_careful(skb,
off + n->sel.hoff,
4, &hdata);
if (!data)
goto out;
sel = ht->divisor & u32_hash_fold(*data, &n->sel,
@ -229,7 +228,7 @@ check_terminal:
if (n->sel.flags & TC_U32_VAROFFSET) {
__be16 *data, hdata;
data = skb_header_pointer(skb,
data = skb_header_pointer_careful(skb,
off + n->sel.offoff,
2, &hdata);
if (!data)

View File

@ -1,3 +1,87 @@
* Tue Mar 31 2026 CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> [6.12.0-124.49.1.el10_1]
- net/mlx5: Fix ECVF vports unload on shutdown flow (CKI Backport Bot) [RHEL-154540] {CVE-2025-38109}
- mm/damon/sysfs: cleanup attrs subdirs on context dir setup failure (Rafael Aquini) [RHEL-150480] {CVE-2026-23144}
- ALSA: aloop: Fix racy access at PCM trigger (CKI Backport Bot) [RHEL-150132] {CVE-2026-23191}
Resolves: RHEL-150132, RHEL-150480, RHEL-154540
* Thu Mar 26 2026 CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> [6.12.0-124.48.1.el10_1]
- ice: fix page leak for zero-size Rx descriptors (CKI Backport Bot) [RHEL-154232]
- Bluetooth: MGMT: Fix memory leak in set_ssp_complete (David Marlin) [RHEL-151786]
- Bluetooth: hci_uart: fix null-ptr-deref in hci_uart_write_work (David Marlin) [RHEL-151786]
- Bluetooth: btusb: revert use of devm_kzalloc in btusb (David Marlin) [RHEL-151786]
- Bluetooth: btusb: reorder cleanup in btusb_disconnect to avoid UAF (David Marlin) [RHEL-151786]
- net/sched: cls_u32: use skb_header_pointer_careful() (Paolo Abeni) [RHEL-150406] {CVE-2026-23204}
- net: add skb_header_pointer_careful() helper (Paolo Abeni) [RHEL-150406]
- bonding: fix use-after-free due to enslave fail after slave array update (CKI Backport Bot) [RHEL-152391] {CVE-2026-23171}
- scsi: target: iscsi: Fix use-after-free in iscsit_dec_session_usage_count() (CKI Backport Bot) [RHEL-150426] {CVE-2026-23193}
- macvlan: observe an RCU grace period in macvlan_common_newlink() error path (Hangbin Liu) [RHEL-150229]
- macvlan: fix error recovery in macvlan_common_newlink() (CKI Backport Bot) [RHEL-150229] {CVE-2026-23209}
- media: uvcvideo: Drop stream->mutex (Kate Hsuan) [RHEL-128622]
- media: uvcvideo: Fix comments in uvc_meta_detect_msxu (Kate Hsuan) [RHEL-128622]
- media: usb: uvcvideo: Store v4l2_fh pointer in file->private_data (Kate Hsuan) [RHEL-128622]
- media: v4l2: Add support for NV12M tiled variants to v4l2_format_info() (Kate Hsuan) [RHEL-128622]
- media: uvcvideo: Use a count variable for meta_formats instead of 0 terminating (Kate Hsuan) [RHEL-128622]
- media: uvcvideo: Auto-set UVC_QUIRK_MSXU_META (Kate Hsuan) [RHEL-128622]
- media: uvcvideo: Introduce V4L2_META_FMT_UVC_MSXU_1_5 (Kate Hsuan) [RHEL-128622]
- media: uvcvideo: Introduce dev->meta_formats (Kate Hsuan) [RHEL-128622]
- media: uvcvideo: Do not mark valid metadata as invalid (Kate Hsuan) [RHEL-128622]
- media: uvcvideo: uvc_v4l2_unlocked_ioctl: Invert PM logic (Kate Hsuan) [RHEL-128622]
- media: core: export v4l2_translate_cmd (Kate Hsuan) [RHEL-128622]
- media: uvcvideo: Turn on the camera if V4L2_EVENT_SUB_FL_SEND_INITIAL (Kate Hsuan) [RHEL-128622]
- media: uvcvideo: Remove stream->is_streaming field (Kate Hsuan) [RHEL-128622]
- media: uvcvideo: Split uvc_stop_streaming() (Kate Hsuan) [RHEL-128622]
- media: uvcvideo: Handle locks in uvc_queue_return_buffers (Kate Hsuan) [RHEL-128622]
- media: uvcvideo: Use vb2 ioctl and fop helpers (Kate Hsuan) [RHEL-128622]
- media: v4l2-common: Add the missing Raw Bayer pixel formats (Kate Hsuan) [RHEL-128622]
- media: v4l2-subdev: Add debug prints to v4l2_subdev_collect_streams() (Kate Hsuan) [RHEL-128622]
- media: v4l2-subdev: Print early in v4l2_subdev_{enable,disable}_streams() (Kate Hsuan) [RHEL-128622]
- media: v4l2: Add Renesas Camera Receiver Unit pixel formats (Kate Hsuan) [RHEL-128622]
- media: v4l2-subdev: Limit the number of active routes to V4L2_FRAME_DESC_ENTRY_MAX (Kate Hsuan) [RHEL-128622]
- media: v4l2-ctrls: Return the handler's error in v4l2_ctrl_handler_free() (Kate Hsuan) [RHEL-128622]
- media: v4l2-ctrls: Don't reset handler's error in v4l2_ctrl_handler_free() (Kate Hsuan) [RHEL-128622]
- media: v4l2-common: Reduce warnings about missing V4L2_CID_LINK_FREQ control (Kate Hsuan) [RHEL-128622]
- media: v4l2-ctrls: Fix H264 SEPARATE_COLOUR_PLANE check (Kate Hsuan) [RHEL-128622]
- media: v4l2-jpeg: Remove unused v4l2_jpeg_parse_* wrappers (Kate Hsuan) [RHEL-128622]
- media: v4l2-core: Replace the check for firmware registered I2C devices (Kate Hsuan) [RHEL-128622]
- media: uvcvideo: Fix 1-byte out-of-bounds read in uvc_parse_format() (Kate Hsuan) [RHEL-128622] {CVE-2025-38680}
- media: uvcvideo: Add quirk for HP Webcam HD 2300 (Kate Hsuan) [RHEL-128622]
- media: uvcvideo: Refactor uvc_v4l2_compat_ioctl32 (Kate Hsuan) [RHEL-128622]
- media: uvcvideo: Refactor uvc_queue_streamon (Kate Hsuan) [RHEL-128622]
- media: uvcvideo: Refactor uvc_ctrl_set_handle() (Kate Hsuan) [RHEL-128622]
- media: uvcvideo: Populate all errors in uvc_probe() (Kate Hsuan) [RHEL-128622]
- media: uvcvideo: Set V4L2_CTRL_FLAG_DISABLED during queryctrl errors (Kate Hsuan) [RHEL-128622]
- media: uvcvideo: Fix bandwidth issue for Alcor camera (Kate Hsuan) [RHEL-128622]
- media: uvcvideo: Use dev_err_probe for devm_gpiod_get_optional (Kate Hsuan) [RHEL-128622]
- media: uvcvideo: Fix deferred probing error (Kate Hsuan) [RHEL-128622]
- media: uvcvideo: Rollback non processed entities on error (Kate Hsuan) [RHEL-128622]
- media: uvcvideo: Send control events for partial succeeds (Kate Hsuan) [RHEL-128622]
- media: uvcvideo: Return the number of processed controls (Kate Hsuan) [RHEL-128622]
- media: uvcvideo: Do not turn on the camera for some ioctls (Kate Hsuan) [RHEL-128622]
- media: uvcvideo: Make power management granular (Kate Hsuan) [RHEL-128622]
- media: uvcvideo: Avoid variable shadowing in uvc_ctrl_cleanup_fh (Kate Hsuan) [RHEL-128622]
- media: uvcvideo: Increase/decrease the PM counter per IOCTL (Kate Hsuan) [RHEL-128622]
- media: uvcvideo: Create uvc_pm_(get|put) functions (Kate Hsuan) [RHEL-128622]
- media: uvcvideo: Keep streaming state in the file handle (Kate Hsuan) [RHEL-128622]
- media: Add C3ISP_PARAMS and C3ISP_STATS meta formats (Kate Hsuan) [RHEL-128622]
- media: v4l: subdev: Fix coverity issue: Logically dead code (Kate Hsuan) [RHEL-128622]
- media: v4l2-dev: fix error handling in __video_register_device() (Kate Hsuan) [RHEL-128622]
- media: common: Add v4l2_find_nearest_size_conditional() (Kate Hsuan) [RHEL-128622]
- media: v4l2-common: Add RGBR format info (Kate Hsuan) [RHEL-128622]
- media: v4l2: Add NV15 and NV20 pixel formats (Kate Hsuan) [RHEL-128622]
- media: v4l2-common: Add helpers to calculate bytesperline and sizeimage (Kate Hsuan) [RHEL-128622]
- media: v4l2-dv-timings: prevent possible overflow in v4l2_detect_gtf() (Kate Hsuan) [RHEL-128622]
- media: v4l2-core: use (t,l)/wxh format for rectangle (Kate Hsuan) [RHEL-128622]
- media: v4l2-core: Introduce v4l2_query_ext_ctrl_to_v4l2_queryctrl (Kate Hsuan) [RHEL-128622]
- media: v4l2: Remove vidioc_s_ctrl callback (Kate Hsuan) [RHEL-128622]
- media: v4l2: Remove vidioc_g_ctrl callback (Kate Hsuan) [RHEL-128622]
- media: v4l2: Remove vidioc_queryctrl callback (Kate Hsuan) [RHEL-128622]
- media: ioctl: Simulate v4l2_queryctrl with v4l2_query_ext_ctrl (Kate Hsuan) [RHEL-128622]
- media: v4l2-dv-timings: add v4l2_num_edid_blocks() helper (Kate Hsuan) [RHEL-128622]
- media: v4l: Memset argument to 0 before calling get_mbus_config pad op (Kate Hsuan) [RHEL-128622]
- media: v4l: Support obtaining link frequency via get_mbus_config (Kate Hsuan) [RHEL-128622]
- media: v4l: Support passing media pad argument to v4l2_get_link_freq() (Kate Hsuan) [RHEL-128622]
Resolves: RHEL-128622, RHEL-150229, RHEL-150406, RHEL-150426, RHEL-151786, RHEL-152391, RHEL-154232
* Sat Mar 21 2026 CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> [6.12.0-124.47.1.el10_1]
- dpll: zl3073x: Fix output pin phase adjustment sign (Ivan Vecera) [RHEL-149766]
- redhat: genlog: add new JIRA cloud server hostname (Jan Stancek)

View File

@ -335,37 +335,43 @@ static bool is_access_interleaved(snd_pcm_access_t access)
static int loopback_check_format(struct loopback_cable *cable, int stream)
{
struct loopback_pcm *dpcm_play, *dpcm_capt;
struct snd_pcm_runtime *runtime, *cruntime;
struct loopback_setup *setup;
struct snd_card *card;
bool stop_capture = false;
int check;
if (cable->valid != CABLE_VALID_BOTH) {
if (stream == SNDRV_PCM_STREAM_PLAYBACK)
goto __notify;
return 0;
}
runtime = cable->streams[SNDRV_PCM_STREAM_PLAYBACK]->
substream->runtime;
cruntime = cable->streams[SNDRV_PCM_STREAM_CAPTURE]->
substream->runtime;
check = runtime->format != cruntime->format ||
runtime->rate != cruntime->rate ||
runtime->channels != cruntime->channels ||
is_access_interleaved(runtime->access) !=
is_access_interleaved(cruntime->access);
if (!check)
return 0;
if (stream == SNDRV_PCM_STREAM_CAPTURE) {
return -EIO;
} else {
snd_pcm_stop(cable->streams[SNDRV_PCM_STREAM_CAPTURE]->
substream, SNDRV_PCM_STATE_DRAINING);
__notify:
runtime = cable->streams[SNDRV_PCM_STREAM_PLAYBACK]->
substream->runtime;
setup = get_setup(cable->streams[SNDRV_PCM_STREAM_PLAYBACK]);
card = cable->streams[SNDRV_PCM_STREAM_PLAYBACK]->loopback->card;
scoped_guard(spinlock_irqsave, &cable->lock) {
dpcm_play = cable->streams[SNDRV_PCM_STREAM_PLAYBACK];
dpcm_capt = cable->streams[SNDRV_PCM_STREAM_CAPTURE];
if (cable->valid != CABLE_VALID_BOTH) {
if (stream == SNDRV_PCM_STREAM_CAPTURE || !dpcm_play)
return 0;
} else {
if (!dpcm_play || !dpcm_capt)
return -EIO;
runtime = dpcm_play->substream->runtime;
cruntime = dpcm_capt->substream->runtime;
if (!runtime || !cruntime)
return -EIO;
check = runtime->format != cruntime->format ||
runtime->rate != cruntime->rate ||
runtime->channels != cruntime->channels ||
is_access_interleaved(runtime->access) !=
is_access_interleaved(cruntime->access);
if (!check)
return 0;
if (stream == SNDRV_PCM_STREAM_CAPTURE)
return -EIO;
else if (cruntime->state == SNDRV_PCM_STATE_RUNNING)
stop_capture = true;
}
setup = get_setup(dpcm_play);
card = dpcm_play->loopback->card;
runtime = dpcm_play->substream->runtime;
if (setup->format != runtime->format) {
snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
&setup->format_id);
@ -388,6 +394,10 @@ static int loopback_check_format(struct loopback_cable *cable, int stream)
setup->access = runtime->access;
}
}
if (stop_capture)
snd_pcm_stop(dpcm_capt->substream, SNDRV_PCM_STATE_DRAINING);
return 0;
}

View File

@ -1,3 +1,3 @@
sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md
kernel-uki-virt-addons.centos,1,Red Hat,kernel-uki-virt-addons,6.12.0-124.47.1.el10.x86_64,mailto:secalert@redhat.com
kernel-uki-virt-addons.almalinux,1,AlmaLinux,kernel-uki-virt-addons,6.12.0-124.47.1.el10.x86_64,mailto:security@almalinux.org
kernel-uki-virt-addons.centos,1,Red Hat,kernel-uki-virt-addons,6.12.0-124.49.1.el10.x86_64,mailto:secalert@redhat.com
kernel-uki-virt-addons.almalinux,1,AlmaLinux,kernel-uki-virt-addons,6.12.0-124.49.1.el10.x86_64,mailto:security@almalinux.org

View File

@ -1,3 +1,3 @@
sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md
kernel-uki-virt.centos,1,Red Hat,kernel-uki-virt,6.12.0-124.47.1.el10.x86_64,mailto:secalert@redhat.com
kernel-uki-virt.almalinux,1,AlmaLinux,kernel-uki-virt,6.12.0-124.47.1.el10.x86_64,mailto:security@almalinux.org
kernel-uki-virt.centos,1,Red Hat,kernel-uki-virt,6.12.0-124.49.1.el10.x86_64,mailto:secalert@redhat.com
kernel-uki-virt.almalinux,1,AlmaLinux,kernel-uki-virt,6.12.0-124.49.1.el10.x86_64,mailto:security@almalinux.org