Import of kernel-6.12.0-124.49.1.el10_1
This commit is contained in:
parent
e069747b16
commit
d3c36ff4dc
@ -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
|
||||
|
||||
@ -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
|
||||
@ -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
|
||||
|
||||
143
Documentation/userspace-api/media/v4l/pixfmt-rawnn-cru.rst
Normal file
143
Documentation/userspace-api/media/v4l/pixfmt-rawnn-cru.rst
Normal 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
|
||||
@ -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:
|
||||
|
||||
|
||||
@ -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/
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
};
|
||||
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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
|
||||
*
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
|
||||
@ -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 */
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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",
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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)
|
||||
{
|
||||
|
||||
@ -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, \
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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];
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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 */
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
4
uki.sbat
4
uki.sbat
@ -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
|
||||
|
||||
Loading…
Reference in New Issue
Block a user