From 50733b5b9102da5b2415e3497aa89588396e4f20 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Wed, 18 Mar 2020 19:35:32 +0100 Subject: media: add v4l2 JPEG helpers Add helpers for JPEG header parsing. They allow both scanning for marker segment positions and later parsing the segments individually, as required by s5p-jpeg, as well as parsing all headers in one go, as required by coda-vpu. The frame header is always parsed, as basically all decoders are interested in width, height, and number of components. For convenience, the JPEG chroma subsampling factors are decoded into a v4l2_jpeg_chroma_subsampling enum. Only baseline and extended sequential DCT encoded JPEGs with 8-bit or 12-bit precision with up to four components are supported. Signed-off-by: Philipp Zabel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- include/media/v4l2-jpeg.h | 135 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 135 insertions(+) create mode 100644 include/media/v4l2-jpeg.h (limited to 'include/media') diff --git a/include/media/v4l2-jpeg.h b/include/media/v4l2-jpeg.h new file mode 100644 index 000000000000..ddba2a56c321 --- /dev/null +++ b/include/media/v4l2-jpeg.h @@ -0,0 +1,135 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * V4L2 JPEG helpers header + * + * Copyright (C) 2019 Pengutronix, Philipp Zabel + * + * For reference, see JPEG ITU-T.81 (ISO/IEC 10918-1) + */ + +#ifndef _V4L2_JPEG_H +#define _V4L2_JPEG_H + +#include + +#define V4L2_JPEG_MAX_COMPONENTS 4 +#define V4L2_JPEG_MAX_TABLES 4 + +/** + * struct v4l2_jpeg_reference - reference into the JPEG buffer + * @start: pointer to the start of the referenced segment or table + * @length: size of the referenced segment or table + * + * Wnen referencing marker segments, start points right after the marker code, + * and length is the size of the segment parameters, excluding the marker code. + */ +struct v4l2_jpeg_reference { + u8 *start; + size_t length; +}; + +/* B.2.2 Frame header syntax */ + +/** + * struct v4l2_jpeg_frame_component_spec - frame component-specification + * @component_identifier: C[i] + * @horizontal_sampling_factor: H[i] + * @vertical_sampling_factor: V[i] + * @quantization_table_selector: quantization table destination selector Tq[i] + */ +struct v4l2_jpeg_frame_component_spec { + u8 component_identifier; + u8 horizontal_sampling_factor; + u8 vertical_sampling_factor; + u8 quantization_table_selector; +}; + +/** + * struct v4l2_jpeg_frame_header - JPEG frame header + * @height: Y + * @width: X + * @precision: P + * @num_components: Nf + * @component: component-specification, see v4l2_jpeg_frame_component_spec + * @subsampling: decoded subsampling from component-specification + */ +struct v4l2_jpeg_frame_header { + u16 height; + u16 width; + u8 precision; + u8 num_components; + struct v4l2_jpeg_frame_component_spec component[V4L2_JPEG_MAX_COMPONENTS]; + enum v4l2_jpeg_chroma_subsampling subsampling; +}; + +/* B.2.3 Scan header syntax */ + +/** + * struct v4l2_jpeg_scan_component_spec - scan component-specification + * @component_selector: Cs[j] + * @dc_entropy_coding_table_selector: Td[j] + * @ac_entropy_coding_table_selector: Ta[j] + */ +struct v4l2_jpeg_scan_component_spec { + u8 component_selector; + u8 dc_entropy_coding_table_selector; + u8 ac_entropy_coding_table_selector; +}; + +/** + * struct v4l2_jpeg_scan_header - JPEG scan header + * @num_components: Ns + * @component: component-specification, see v4l2_jpeg_scan_component_spec + */ +struct v4l2_jpeg_scan_header { + u8 num_components; /* Ns */ + struct v4l2_jpeg_scan_component_spec component[V4L2_JPEG_MAX_COMPONENTS]; + /* Ss, Se, Ah, and Al are not used by any driver */ +}; + +/** + * struct v4l2_jpeg_header - parsed JPEG header + * @sof: pointer to frame header and size + * @sos: pointer to scan header and size + * @dht: pointers to huffman tables and sizes + * @dqt: pointers to quantization tables and sizes + * @frame: parsed frame header + * @scan: pointer to parsed scan header, optional + * @quantization_tables: references to four quantization tables, optional + * @huffman_tables: references to four Huffman tables in DC0, DC1, AC0, AC1 + * order, optional + * @restart_interval: number of MCU per restart interval, Ri + * @ecs_offset: buffer offset in bytes to the entropy coded segment + * + * When this structure is passed to v4l2_jpeg_parse_header, the optional scan, + * quantization_tables, and huffman_tables pointers must be initialized to NULL + * or point at valid memory. + */ +struct v4l2_jpeg_header { + struct v4l2_jpeg_reference sof; + struct v4l2_jpeg_reference sos; + unsigned int num_dht; + struct v4l2_jpeg_reference dht[V4L2_JPEG_MAX_TABLES]; + unsigned int num_dqt; + struct v4l2_jpeg_reference dqt[V4L2_JPEG_MAX_TABLES]; + + struct v4l2_jpeg_frame_header frame; + struct v4l2_jpeg_scan_header *scan; + struct v4l2_jpeg_reference *quantization_tables; + struct v4l2_jpeg_reference *huffman_tables; + u16 restart_interval; + size_t ecs_offset; +}; + +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); + +#endif -- cgit v1.2.3-59-g8ed1b From a8648098948d9b04627408b0c51877720412dc9f Mon Sep 17 00:00:00 2001 From: Sean Young Date: Tue, 31 Mar 2020 14:39:52 +0200 Subject: media: rc: if kernel is built without an IR codec, don't advertise it If the kernel is built without e.g. the imon IR decoder, the protocols sysfs file still show the protocol as available. If user-space tries to enable this decoder, the kernel will report an error: $ echo +imon > /sys/class/rc/rc0/protocols [ 57.693033] rc_core: Loaded IR protocol module ir-imon-decoder, but protocol imon still not available Ensuring that unavailable protocols are not advertised, ensures that users space knows it is not available, and a BPF based IR decoder can be loaded instead. This supports the case when no kernel-based codec needs to be compiled in, and every IR decoder can be BPF based. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- include/media/rc-map.h | 103 ++++++++++++++++++++++++++++++++++++------------- 1 file changed, 76 insertions(+), 27 deletions(-) (limited to 'include/media') diff --git a/include/media/rc-map.h b/include/media/rc-map.h index 0ce896f10202..7dbb91c601a7 100644 --- a/include/media/rc-map.h +++ b/include/media/rc-map.h @@ -41,36 +41,85 @@ #define RC_PROTO_BIT_RCMM32 BIT_ULL(RC_PROTO_RCMM32) #define RC_PROTO_BIT_XBOX_DVD BIT_ULL(RC_PROTO_XBOX_DVD) -/* All rc protocols for which we have decoders */ +#if IS_ENABLED(CONFIG_IR_RC5_DECODER) +#define __RC_PROTO_RC5_CODEC \ + (RC_PROTO_BIT_RC5 | RC_PROTO_BIT_RC5X_20 | RC_PROTO_BIT_RC5_SZ) +#else +#define __RC_PROTO_RC5_CODEC 0 +#endif + +#if IS_ENABLED(CONFIG_IR_JVC_DECODER) +#define __RC_PROTO_JVC_CODEC RC_PROTO_BIT_JVC +#else +#define __RC_PROTO_JVC_CODEC 0 +#endif +#if IS_ENABLED(CONFIG_IR_SONY_DECODER) +#define __RC_PROTO_SONY_CODEC \ + (RC_PROTO_BIT_SONY12 | RC_PROTO_BIT_SONY15 | RC_PROTO_BIT_SONY20) +#else +#define __RC_PROTO_SONY_CODEC 0 +#endif +#if IS_ENABLED(CONFIG_IR_NEC_DECODER) +#define __RC_PROTO_NEC_CODEC \ + (RC_PROTO_BIT_NEC | RC_PROTO_BIT_NECX | RC_PROTO_BIT_NEC32) +#else +#define __RC_PROTO_NEC_CODEC 0 +#endif +#if IS_ENABLED(CONFIG_IR_SANYO_DECODER) +#define __RC_PROTO_SANYO_CODEC RC_PROTO_BIT_SANYO +#else +#define __RC_PROTO_SANYO_CODEC 0 +#endif +#if IS_ENABLED(CONFIG_IR_MCE_KBD_DECODER) +#define __RC_PROTO_MCE_KBD_CODEC \ + (RC_PROTO_BIT_MCIR2_KBD | RC_PROTO_BIT_MCIR2_MSE) +#else +#define __RC_PROTO_MCE_KBD_CODEC 0 +#endif +#if IS_ENABLED(CONFIG_IR_RC6_DECODER) +#define __RC_PROTO_RC6_CODEC \ + (RC_PROTO_BIT_RC6_0 | RC_PROTO_BIT_RC6_6A_20 | \ + RC_PROTO_BIT_RC6_6A_24 | RC_PROTO_BIT_RC6_6A_32 | \ + RC_PROTO_BIT_RC6_MCE) +#else +#define __RC_PROTO_RC6_CODEC 0 +#endif +#if IS_ENABLED(CONFIG_IR_SHARP_DECODER) +#define __RC_PROTO_SHARP_CODEC RC_PROTO_BIT_SHARP +#else +#define __RC_PROTO_SHARP_CODEC 0 +#endif +#if IS_ENABLED(CONFIG_IR_XMP_DECODER) +#define __RC_PROTO_XMP_CODEC RC_PROTO_BIT_XMP +#else +#define __RC_PROTO_XMP_CODEC 0 +#endif +#if IS_ENABLED(CONFIG_IR_IMON_DECODER) +#define __RC_PROTO_IMON_CODEC RC_PROTO_BIT_IMON +#else +#define __RC_PROTO_IMON_CODEC 0 +#endif +#if IS_ENABLED(CONFIG_IR_RCMM_DECODER) +#define __RC_PROTO_RCMM_CODEC \ + (RC_PROTO_BIT_RCMM12 | RC_PROTO_BIT_RCMM24 | RC_PROTO_BIT_RCMM32) +#else +#define __RC_PROTO_RCMM_CODEC 0 +#endif + +/* All kernel-based codecs have encoders and decoders */ #define RC_PROTO_BIT_ALL_IR_DECODER \ - (RC_PROTO_BIT_RC5 | RC_PROTO_BIT_RC5X_20 | \ - RC_PROTO_BIT_RC5_SZ | RC_PROTO_BIT_JVC | \ - RC_PROTO_BIT_SONY12 | RC_PROTO_BIT_SONY15 | \ - RC_PROTO_BIT_SONY20 | RC_PROTO_BIT_NEC | \ - RC_PROTO_BIT_NECX | RC_PROTO_BIT_NEC32 | \ - RC_PROTO_BIT_SANYO | RC_PROTO_BIT_MCIR2_KBD | \ - RC_PROTO_BIT_MCIR2_MSE | \ - RC_PROTO_BIT_RC6_0 | RC_PROTO_BIT_RC6_6A_20 | \ - RC_PROTO_BIT_RC6_6A_24 | RC_PROTO_BIT_RC6_6A_32 | \ - RC_PROTO_BIT_RC6_MCE | RC_PROTO_BIT_SHARP | \ - RC_PROTO_BIT_XMP | RC_PROTO_BIT_IMON | \ - RC_PROTO_BIT_RCMM12 | RC_PROTO_BIT_RCMM24 | \ - RC_PROTO_BIT_RCMM32) + (__RC_PROTO_RC5_CODEC | __RC_PROTO_JVC_CODEC | __RC_PROTO_SONY_CODEC | \ + __RC_PROTO_NEC_CODEC | __RC_PROTO_SANYO_CODEC | \ + __RC_PROTO_MCE_KBD_CODEC | __RC_PROTO_RC6_CODEC | \ + __RC_PROTO_SHARP_CODEC | __RC_PROTO_XMP_CODEC | \ + __RC_PROTO_IMON_CODEC | __RC_PROTO_RCMM_CODEC) #define RC_PROTO_BIT_ALL_IR_ENCODER \ - (RC_PROTO_BIT_RC5 | RC_PROTO_BIT_RC5X_20 | \ - RC_PROTO_BIT_RC5_SZ | RC_PROTO_BIT_JVC | \ - RC_PROTO_BIT_SONY12 | RC_PROTO_BIT_SONY15 | \ - RC_PROTO_BIT_SONY20 | RC_PROTO_BIT_NEC | \ - RC_PROTO_BIT_NECX | RC_PROTO_BIT_NEC32 | \ - RC_PROTO_BIT_SANYO | RC_PROTO_BIT_MCIR2_KBD | \ - RC_PROTO_BIT_MCIR2_MSE | \ - RC_PROTO_BIT_RC6_0 | RC_PROTO_BIT_RC6_6A_20 | \ - RC_PROTO_BIT_RC6_6A_24 | \ - RC_PROTO_BIT_RC6_6A_32 | RC_PROTO_BIT_RC6_MCE | \ - RC_PROTO_BIT_SHARP | RC_PROTO_BIT_IMON | \ - RC_PROTO_BIT_RCMM12 | RC_PROTO_BIT_RCMM24 | \ - RC_PROTO_BIT_RCMM32) + (__RC_PROTO_RC5_CODEC | __RC_PROTO_JVC_CODEC | __RC_PROTO_SONY_CODEC | \ + __RC_PROTO_NEC_CODEC | __RC_PROTO_SANYO_CODEC | \ + __RC_PROTO_MCE_KBD_CODEC | __RC_PROTO_RC6_CODEC | \ + __RC_PROTO_SHARP_CODEC | __RC_PROTO_XMP_CODEC | \ + __RC_PROTO_IMON_CODEC | __RC_PROTO_RCMM_CODEC) #define RC_SCANCODE_UNKNOWN(x) (x) #define RC_SCANCODE_OTHER(x) (x) -- cgit v1.2.3-59-g8ed1b From d6ef0719fa90da52a555ff6de5f13e6bea601d33 Mon Sep 17 00:00:00 2001 From: Seungchul Kim Date: Thu, 26 Mar 2020 10:09:46 +0100 Subject: media: v4l2-fh: define v4l2_fh struct regardless of condition v4l2_fh struct define differently by CONFIG_V4L2_MEM2MEM_DEV. If some vendors use CONFIG_V4L2_MEM2MEM_DEV by module, it can make the mismatch of v4l2_fh sturct. By the mismatch, the following error occurs. =============================== [ 7.533506] v4l2_mem2mem: disagrees about version of symbol video_devdata [ 7.533594] v4l2_mem2mem: Unknown symbol video_devdata (err -22) [ 7.535319] v4l2_mem2mem: disagrees about version of symbol v4l2_event_pending [ 7.542532] v4l2_mem2mem: Unknown symbol v4l2_event_pending (err -22) =============================== So v4l2_fh struct is modified to does not have dependency for CONFIG_V4L2_MEM2MEM_DEV. Signed-off-by: Seungchul Kim Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-ioctl.c | 2 -- include/media/v4l2-fh.h | 2 -- 2 files changed, 4 deletions(-) (limited to 'include/media') diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index b2ef8e60ea7d..833e79a2cb98 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -2805,13 +2805,11 @@ static struct mutex *v4l2_ioctl_get_lock(struct video_device *vdev, { if (_IOC_NR(cmd) >= V4L2_IOCTLS) return vdev->lock; -#if IS_ENABLED(CONFIG_V4L2_MEM2MEM_DEV) if (vfh && vfh->m2m_ctx && (v4l2_ioctls[_IOC_NR(cmd)].flags & INFO_FL_QUEUE)) { if (vfh->m2m_ctx->q_lock) return vfh->m2m_ctx->q_lock; } -#endif if (vdev->queue && vdev->queue->lock && (v4l2_ioctls[_IOC_NR(cmd)].flags & INFO_FL_QUEUE)) return vdev->queue->lock; diff --git a/include/media/v4l2-fh.h b/include/media/v4l2-fh.h index 53b4dbb4ae8e..b5b3e00c8e6a 100644 --- a/include/media/v4l2-fh.h +++ b/include/media/v4l2-fh.h @@ -53,9 +53,7 @@ struct v4l2_fh { unsigned int navailable; u32 sequence; -#if IS_ENABLED(CONFIG_V4L2_MEM2MEM_DEV) struct v4l2_m2m_ctx *m2m_ctx; -#endif }; /** -- cgit v1.2.3-59-g8ed1b From 624922a2739b96b83aaf1655d0519b41d30140f7 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Sat, 4 Apr 2020 00:13:41 +0200 Subject: media: v4l2-core: Add helpers to build the H264 P/B0/B1 reflists Building those list is a standard procedure described in section '8.2.4 Decoding process for reference picture lists construction' of the H264 specification. We already have 2 drivers needing the same logic (hantro and rkvdec) and I suspect we will soon have more. Let's provide generic helpers to create those lists. Signed-off-by: Boris Brezillon Signed-off-by: Ezequiel Garcia Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/Kconfig | 4 + drivers/media/v4l2-core/Makefile | 1 + drivers/media/v4l2-core/v4l2-h264.c | 270 ++++++++++++++++++++++++++++++++++++ include/media/h264-ctrls.h | 8 +- include/media/v4l2-h264.h | 85 ++++++++++++ 5 files changed, 367 insertions(+), 1 deletion(-) create mode 100644 drivers/media/v4l2-core/v4l2-h264.c create mode 100644 include/media/v4l2-h264.h (limited to 'include/media') diff --git a/drivers/media/v4l2-core/Kconfig b/drivers/media/v4l2-core/Kconfig index 3fa75352d04c..bf49f83cb86f 100644 --- a/drivers/media/v4l2-core/Kconfig +++ b/drivers/media/v4l2-core/Kconfig @@ -48,6 +48,10 @@ config VIDEO_TUNER config V4L2_JPEG_HELPER tristate +# Used by drivers that need v4l2-h264.ko +config V4L2_H264 + tristate + # Used by drivers that need v4l2-mem2mem.ko config V4L2_MEM2MEM_DEV tristate diff --git a/drivers/media/v4l2-core/Makefile b/drivers/media/v4l2-core/Makefile index 144564656d22..2ef0c7c958a2 100644 --- a/drivers/media/v4l2-core/Makefile +++ b/drivers/media/v4l2-core/Makefile @@ -21,6 +21,7 @@ obj-$(CONFIG_VIDEO_V4L2) += v4l2-dv-timings.o obj-$(CONFIG_VIDEO_TUNER) += tuner.o obj-$(CONFIG_V4L2_MEM2MEM_DEV) += v4l2-mem2mem.o +obj-$(CONFIG_V4L2_H264) += v4l2-h264.o obj-$(CONFIG_V4L2_FLASH_LED_CLASS) += v4l2-flash-led-class.o diff --git a/drivers/media/v4l2-core/v4l2-h264.c b/drivers/media/v4l2-core/v4l2-h264.c new file mode 100644 index 000000000000..edf6225f0522 --- /dev/null +++ b/drivers/media/v4l2-core/v4l2-h264.c @@ -0,0 +1,270 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * V4L2 H264 helpers. + * + * Copyright (C) 2019 Collabora, Ltd. + * + * Author: Boris Brezillon + */ + +#include +#include + +#include + +/** + * v4l2_h264_init_reflist_builder() - Initialize a P/B0/B1 reference list + * builder + * + * @b: the builder context to initialize + * @dec_params: decode parameters control + * @slice_params: first slice parameters control + * @sps: SPS control + * @dpb: DPB to use when creating the reference list + */ +void +v4l2_h264_init_reflist_builder(struct v4l2_h264_reflist_builder *b, + const struct v4l2_ctrl_h264_decode_params *dec_params, + const struct v4l2_ctrl_h264_slice_params *slice_params, + const struct v4l2_ctrl_h264_sps *sps, + const struct v4l2_h264_dpb_entry dpb[V4L2_H264_NUM_DPB_ENTRIES]) +{ + int cur_frame_num, max_frame_num; + unsigned int i; + + max_frame_num = 1 << (sps->log2_max_frame_num_minus4 + 4); + cur_frame_num = slice_params->frame_num; + + memset(b, 0, sizeof(*b)); + if (!(slice_params->flags & V4L2_H264_SLICE_FLAG_FIELD_PIC)) + b->cur_pic_order_count = min(dec_params->bottom_field_order_cnt, + dec_params->top_field_order_cnt); + else if (slice_params->flags & V4L2_H264_SLICE_FLAG_BOTTOM_FIELD) + b->cur_pic_order_count = dec_params->bottom_field_order_cnt; + else + b->cur_pic_order_count = dec_params->top_field_order_cnt; + + for (i = 0; i < V4L2_H264_NUM_DPB_ENTRIES; i++) { + u32 pic_order_count; + + if (!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE)) + continue; + + b->refs[i].pic_num = dpb[i].pic_num; + if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_LONG_TERM) + b->refs[i].longterm = true; + + /* + * Handle frame_num wraparound as described in section + * '8.2.4.1 Decoding process for picture numbers' of the spec. + * TODO: This logic will have to be adjusted when we start + * supporting interlaced content. + */ + if (dpb[i].frame_num > cur_frame_num) + b->refs[i].frame_num = (int)dpb[i].frame_num - + max_frame_num; + else + b->refs[i].frame_num = dpb[i].frame_num; + + if (!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_FIELD)) + pic_order_count = min(dpb[i].top_field_order_cnt, + dpb[i].bottom_field_order_cnt); + else if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_BOTTOM_FIELD) + pic_order_count = dpb[i].bottom_field_order_cnt; + else + pic_order_count = dpb[i].top_field_order_cnt; + + b->refs[i].pic_order_count = pic_order_count; + b->unordered_reflist[b->num_valid] = i; + b->num_valid++; + } + + for (i = b->num_valid; i < ARRAY_SIZE(b->unordered_reflist); i++) + b->unordered_reflist[i] = i; +} +EXPORT_SYMBOL_GPL(v4l2_h264_init_reflist_builder); + +static int v4l2_h264_p_ref_list_cmp(const void *ptra, const void *ptrb, + const void *data) +{ + const struct v4l2_h264_reflist_builder *builder = data; + u8 idxa, idxb; + + idxa = *((u8 *)ptra); + idxb = *((u8 *)ptrb); + + if (WARN_ON(idxa >= V4L2_H264_NUM_DPB_ENTRIES || + idxb >= V4L2_H264_NUM_DPB_ENTRIES)) + return 1; + + if (builder->refs[idxa].longterm != builder->refs[idxb].longterm) { + /* Short term pics first. */ + if (!builder->refs[idxa].longterm) + return -1; + else + return 1; + } + + /* + * Short term pics in descending pic num order, long term ones in + * ascending order. + */ + if (!builder->refs[idxa].longterm) + return builder->refs[idxb].frame_num < + builder->refs[idxa].frame_num ? + -1 : 1; + + return builder->refs[idxa].pic_num < builder->refs[idxb].pic_num ? + -1 : 1; +} + +static int v4l2_h264_b0_ref_list_cmp(const void *ptra, const void *ptrb, + const void *data) +{ + const struct v4l2_h264_reflist_builder *builder = data; + s32 poca, pocb; + u8 idxa, idxb; + + idxa = *((u8 *)ptra); + idxb = *((u8 *)ptrb); + + if (WARN_ON(idxa >= V4L2_H264_NUM_DPB_ENTRIES || + idxb >= V4L2_H264_NUM_DPB_ENTRIES)) + return 1; + + if (builder->refs[idxa].longterm != builder->refs[idxb].longterm) { + /* Short term pics first. */ + if (!builder->refs[idxa].longterm) + return -1; + else + return 1; + } + + /* Long term pics in ascending pic num order. */ + if (builder->refs[idxa].longterm) + return builder->refs[idxa].pic_num < + builder->refs[idxb].pic_num ? + -1 : 1; + + poca = builder->refs[idxa].pic_order_count; + pocb = builder->refs[idxb].pic_order_count; + + /* + * Short term pics with POC < cur POC first in POC descending order + * followed by short term pics with POC > cur POC in POC ascending + * order. + */ + if ((poca < builder->cur_pic_order_count) != + (pocb < builder->cur_pic_order_count)) + return poca < pocb ? -1 : 1; + else if (poca < builder->cur_pic_order_count) + return pocb < poca ? -1 : 1; + + return poca < pocb ? -1 : 1; +} + +static int v4l2_h264_b1_ref_list_cmp(const void *ptra, const void *ptrb, + const void *data) +{ + const struct v4l2_h264_reflist_builder *builder = data; + s32 poca, pocb; + u8 idxa, idxb; + + idxa = *((u8 *)ptra); + idxb = *((u8 *)ptrb); + + if (WARN_ON(idxa >= V4L2_H264_NUM_DPB_ENTRIES || + idxb >= V4L2_H264_NUM_DPB_ENTRIES)) + return 1; + + if (builder->refs[idxa].longterm != builder->refs[idxb].longterm) { + /* Short term pics first. */ + if (!builder->refs[idxa].longterm) + return -1; + else + return 1; + } + + /* Long term pics in ascending pic num order. */ + if (builder->refs[idxa].longterm) + return builder->refs[idxa].pic_num < + builder->refs[idxb].pic_num ? + -1 : 1; + + poca = builder->refs[idxa].pic_order_count; + pocb = builder->refs[idxb].pic_order_count; + + /* + * Short term pics with POC > cur POC first in POC ascending order + * followed by short term pics with POC < cur POC in POC descending + * order. + */ + if ((poca < builder->cur_pic_order_count) != + (pocb < builder->cur_pic_order_count)) + return pocb < poca ? -1 : 1; + else if (poca < builder->cur_pic_order_count) + return pocb < poca ? -1 : 1; + + return poca < pocb ? -1 : 1; +} + +/** + * v4l2_h264_build_p_ref_list() - Build the P reference list + * + * @builder: reference list builder context + * @reflist: 16-bytes array used to store the P reference list. Each entry + * is an index in the DPB + * + * This functions builds the P reference lists. This procedure is describe in + * section '8.2.4 Decoding process for reference picture lists construction' + * of the H264 spec. This function can be used by H264 decoder drivers that + * need to pass a P reference list to the hardware. + */ +void +v4l2_h264_build_p_ref_list(const struct v4l2_h264_reflist_builder *builder, + u8 *reflist) +{ + memcpy(reflist, builder->unordered_reflist, + sizeof(builder->unordered_reflist[0]) * builder->num_valid); + sort_r(reflist, builder->num_valid, sizeof(*reflist), + v4l2_h264_p_ref_list_cmp, NULL, builder); +} +EXPORT_SYMBOL_GPL(v4l2_h264_build_p_ref_list); + +/** + * v4l2_h264_build_b_ref_lists() - Build the B0/B1 reference lists + * + * @builder: reference list builder context + * @b0_reflist: 16-bytes array used to store the B0 reference list. Each entry + * is an index in the DPB + * @b1_reflist: 16-bytes array used to store the B1 reference list. Each entry + * is an index in the DPB + * + * This functions builds the B0/B1 reference lists. This procedure is described + * in section '8.2.4 Decoding process for reference picture lists construction' + * of the H264 spec. This function can be used by H264 decoder drivers that + * need to pass B0/B1 reference lists to the hardware. + */ +void +v4l2_h264_build_b_ref_lists(const struct v4l2_h264_reflist_builder *builder, + u8 *b0_reflist, u8 *b1_reflist) +{ + memcpy(b0_reflist, builder->unordered_reflist, + sizeof(builder->unordered_reflist[0]) * builder->num_valid); + sort_r(b0_reflist, builder->num_valid, sizeof(*b0_reflist), + v4l2_h264_b0_ref_list_cmp, NULL, builder); + + memcpy(b1_reflist, builder->unordered_reflist, + sizeof(builder->unordered_reflist[0]) * builder->num_valid); + sort_r(b1_reflist, builder->num_valid, sizeof(*b1_reflist), + v4l2_h264_b1_ref_list_cmp, NULL, builder); + + if (builder->num_valid > 1 && + !memcmp(b1_reflist, b0_reflist, builder->num_valid)) + swap(b1_reflist[0], b1_reflist[1]); +} +EXPORT_SYMBOL_GPL(v4l2_h264_build_b_ref_lists); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("V4L2 H264 Helpers"); +MODULE_AUTHOR("Boris Brezillon "); diff --git a/include/media/h264-ctrls.h b/include/media/h264-ctrls.h index 1c6ff7d63bca..080fd1293c42 100644 --- a/include/media/h264-ctrls.h +++ b/include/media/h264-ctrls.h @@ -13,6 +13,12 @@ #include +/* + * Maximum DPB size, as specified by section 'A.3.1 Level limits + * common to the Baseline, Main, and Extended profiles'. + */ +#define V4L2_H264_NUM_DPB_ENTRIES 16 + /* Our pixel format isn't stable at the moment */ #define V4L2_PIX_FMT_H264_SLICE v4l2_fourcc('S', '2', '6', '4') /* H264 parsed slices */ @@ -201,7 +207,7 @@ struct v4l2_h264_dpb_entry { #define V4L2_H264_DECODE_PARAM_FLAG_IDR_PIC 0x01 struct v4l2_ctrl_h264_decode_params { - struct v4l2_h264_dpb_entry dpb[16]; + struct v4l2_h264_dpb_entry dpb[V4L2_H264_NUM_DPB_ENTRIES]; __u16 num_slices; __u16 nal_ref_idc; __s32 top_field_order_cnt; diff --git a/include/media/v4l2-h264.h b/include/media/v4l2-h264.h new file mode 100644 index 000000000000..bc9ebb560ccf --- /dev/null +++ b/include/media/v4l2-h264.h @@ -0,0 +1,85 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Helper functions for H264 codecs. + * + * Copyright (c) 2019 Collabora, Ltd. + * + * Author: Boris Brezillon + */ + +#ifndef _MEDIA_V4L2_H264_H +#define _MEDIA_V4L2_H264_H + +#include + +/** + * struct v4l2_h264_reflist_builder - Reference list builder object + * + * @refs.pic_order_count: reference picture order count + * @refs.frame_num: reference frame number + * @refs.pic_num: reference picture number + * @refs.longterm: set to true for a long term reference + * @refs: array of references + * @cur_pic_order_count: picture order count of the frame being decoded + * @unordered_reflist: unordered list of references. Will be used to generate + * ordered P/B0/B1 lists + * @num_valid: number of valid references in the refs array + * + * This object stores the context of the P/B0/B1 reference list builder. + * This procedure is described in section '8.2.4 Decoding process for reference + * picture lists construction' of the H264 spec. + */ +struct v4l2_h264_reflist_builder { + struct { + s32 pic_order_count; + int frame_num; + u16 pic_num; + u16 longterm : 1; + } refs[V4L2_H264_NUM_DPB_ENTRIES]; + s32 cur_pic_order_count; + u8 unordered_reflist[V4L2_H264_NUM_DPB_ENTRIES]; + u8 num_valid; +}; + +void +v4l2_h264_init_reflist_builder(struct v4l2_h264_reflist_builder *b, + const struct v4l2_ctrl_h264_decode_params *dec_params, + const struct v4l2_ctrl_h264_slice_params *slice_params, + const struct v4l2_ctrl_h264_sps *sps, + const struct v4l2_h264_dpb_entry dpb[V4L2_H264_NUM_DPB_ENTRIES]); + +/** + * v4l2_h264_build_b_ref_lists() - Build the B0/B1 reference lists + * + * @builder: reference list builder context + * @b0_reflist: 16-bytes array used to store the B0 reference list. Each entry + * is an index in the DPB + * @b1_reflist: 16-bytes array used to store the B1 reference list. Each entry + * is an index in the DPB + * + * This functions builds the B0/B1 reference lists. This procedure is described + * in section '8.2.4 Decoding process for reference picture lists construction' + * of the H264 spec. This function can be used by H264 decoder drivers that + * need to pass B0/B1 reference lists to the hardware. + */ +void +v4l2_h264_build_b_ref_lists(const struct v4l2_h264_reflist_builder *builder, + u8 *b0_reflist, u8 *b1_reflist); + +/** + * v4l2_h264_build_b_ref_lists() - Build the P reference list + * + * @builder: reference list builder context + * @p_reflist: 16-bytes array used to store the P reference list. Each entry + * is an index in the DPB + * + * This functions builds the P reference lists. This procedure is describe in + * section '8.2.4 Decoding process for reference picture lists construction' + * of the H264 spec. This function can be used by H264 decoder drivers that + * need to pass a P reference list to the hardware. + */ +void +v4l2_h264_build_p_ref_list(const struct v4l2_h264_reflist_builder *builder, + u8 *reflist); + +#endif /* _MEDIA_V4L2_H264_H */ -- cgit v1.2.3-59-g8ed1b From b2b1046f1de6263e6281d46fd376ee048f09d013 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 3 Mar 2020 12:02:00 +0100 Subject: media: v4l2-ctrls: add __v4l2_ctrl_s_ctrl_compound() Rather than creating new compound control helpers for each new type, create one generic function and just create defines on top. Signed-off-by: Hans Verkuil Tested-by: Paul Kocialkowski Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-ctrls.c | 10 ++++---- include/media/v4l2-ctrls.h | 49 +++++++++++++++++++++--------------- 2 files changed, 34 insertions(+), 25 deletions(-) (limited to 'include/media') diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index 77b0132d9f6f..1c617b42a944 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c @@ -4253,18 +4253,18 @@ int __v4l2_ctrl_s_ctrl_string(struct v4l2_ctrl *ctrl, const char *s) } EXPORT_SYMBOL(__v4l2_ctrl_s_ctrl_string); -int __v4l2_ctrl_s_ctrl_area(struct v4l2_ctrl *ctrl, - const struct v4l2_area *area) +int __v4l2_ctrl_s_ctrl_compound(struct v4l2_ctrl *ctrl, + enum v4l2_ctrl_type type, const void *p) { lockdep_assert_held(ctrl->handler->lock); /* It's a driver bug if this happens. */ - if (WARN_ON(ctrl->type != V4L2_CTRL_TYPE_AREA)) + if (WARN_ON(ctrl->type != type)) return -EINVAL; - *ctrl->p_new.p_area = *area; + memcpy(ctrl->p_new.p, p, ctrl->elems * ctrl->elem_size); return set_ctrl(NULL, ctrl, 0); } -EXPORT_SYMBOL(__v4l2_ctrl_s_ctrl_area); +EXPORT_SYMBOL(__v4l2_ctrl_s_ctrl_compound); void v4l2_ctrl_request_complete(struct media_request *req, struct v4l2_ctrl_handler *main_hdl) diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h index 7db9e719a583..75a8daacb4c4 100644 --- a/include/media/v4l2-ctrls.h +++ b/include/media/v4l2-ctrls.h @@ -1113,45 +1113,54 @@ static inline int v4l2_ctrl_s_ctrl_string(struct v4l2_ctrl *ctrl, const char *s) } /** - * __v4l2_ctrl_s_ctrl_area() - Unlocked variant of v4l2_ctrl_s_ctrl_area(). + * __v4l2_ctrl_s_ctrl_compound() - Unlocked variant to set a compound control * - * @ctrl: The control. - * @area: The new area. + * @ctrl: The control. + * @type: The type of the data. + * @p: The new compound payload. * - * This sets the control's new area safely by going through the control - * framework. This function assumes the control's handler is already locked, - * allowing it to be used from within the &v4l2_ctrl_ops functions. + * This sets the control's new compound payload safely by going through the + * control framework. This function assumes the control's handler is already + * locked, allowing it to be used from within the &v4l2_ctrl_ops functions. * - * This function is for area type controls only. + * This function is for compound type controls only. */ -int __v4l2_ctrl_s_ctrl_area(struct v4l2_ctrl *ctrl, - const struct v4l2_area *area); +int __v4l2_ctrl_s_ctrl_compound(struct v4l2_ctrl *ctrl, + enum v4l2_ctrl_type type, const void *p); /** - * v4l2_ctrl_s_ctrl_area() - Helper function to set a control's area value - * from within a driver. + * v4l2_ctrl_s_ctrl_compound() - Helper function to set a compound control + * from within a driver. * - * @ctrl: The control. - * @area: The new area. + * @ctrl: The control. + * @type: The type of the data. + * @p: The new compound payload. * - * This sets the control's new area safely by going through the control - * framework. This function will lock the control's handler, so it cannot be - * used from within the &v4l2_ctrl_ops functions. + * This sets the control's new compound payload safely by going through the + * control framework. This function will lock the control's handler, so it + * cannot be used from within the &v4l2_ctrl_ops functions. * - * This function is for area type controls only. + * This function is for compound type controls only. */ -static inline int v4l2_ctrl_s_ctrl_area(struct v4l2_ctrl *ctrl, - const struct v4l2_area *area) +static inline int v4l2_ctrl_s_ctrl_compound(struct v4l2_ctrl *ctrl, + enum v4l2_ctrl_type type, + const void *p) { int rval; v4l2_ctrl_lock(ctrl); - rval = __v4l2_ctrl_s_ctrl_area(ctrl, area); + rval = __v4l2_ctrl_s_ctrl_compound(ctrl, type, p); v4l2_ctrl_unlock(ctrl); return rval; } +/* Helper defines for area type controls */ +#define __v4l2_ctrl_s_ctrl_area(ctrl, area) \ + __v4l2_ctrl_s_ctrl_compound((ctrl), V4L2_CTRL_TYPE_AREA, (area)) +#define v4l2_ctrl_s_ctrl_area(ctrl, area) \ + v4l2_ctrl_s_ctrl_compound((ctrl), V4L2_CTRL_TYPE_AREA, (area)) + /* Internal helper functions that deal with control events. */ extern const struct v4l2_subscribed_event_ops v4l2_ctrl_sub_ev_ops; -- cgit v1.2.3-59-g8ed1b From ba99522b2bd08bf3ec7126bd363cf18ade74ed2f Mon Sep 17 00:00:00 2001 From: Marco Felsch Date: Thu, 2 Apr 2020 10:49:57 +0200 Subject: media: v4l2-image-sizes: add HD and Full-HD definitions Add common (Full-)HD definitions also known as 720p and 1080p. Signed-off-by: Marco Felsch Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- include/media/v4l2-image-sizes.h | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'include/media') diff --git a/include/media/v4l2-image-sizes.h b/include/media/v4l2-image-sizes.h index 450f4f5d3d6a..24a7a0bb59ab 100644 --- a/include/media/v4l2-image-sizes.h +++ b/include/media/v4l2-image-sizes.h @@ -10,6 +10,12 @@ #define CIF_WIDTH 352 #define CIF_HEIGHT 288 +#define HD_720_WIDTH 1280 +#define HD_720_HEIGHT 720 + +#define HD_1080_WIDTH 1920 +#define HD_1080_HEIGHT 1080 + #define QCIF_WIDTH 176 #define QCIF_HEIGHT 144 -- cgit v1.2.3-59-g8ed1b From 49c6644eb6acc71a76a46bedb17dd204b105161b Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 16 Apr 2020 15:58:55 +0200 Subject: media: dvb-usb-ids.h: fix an USB PID name The USB_PID_ALINK_DTU is a Product ID, not a vendor ID. Fix that. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/gl861.c | 2 +- include/media/dvb-usb-ids.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'include/media') diff --git a/drivers/media/usb/dvb-usb-v2/gl861.c b/drivers/media/usb/dvb-usb-v2/gl861.c index 42c3b8af0774..b7ca236174f3 100644 --- a/drivers/media/usb/dvb-usb-v2/gl861.c +++ b/drivers/media/usb/dvb-usb-v2/gl861.c @@ -550,7 +550,7 @@ static struct dvb_usb_device_properties friio_props = { static const struct usb_device_id gl861_id_table[] = { { DVB_USB_DEVICE(USB_VID_MSI, USB_PID_MSI_MEGASKY580_55801, &gl861_props, "MSI Mega Sky 55801 DVB-T USB2.0", NULL) }, - { DVB_USB_DEVICE(USB_VID_ALINK, USB_VID_ALINK_DTU, + { DVB_USB_DEVICE(USB_VID_ALINK, USB_PID_ALINK_DTU, &gl861_props, "A-LINK DTU DVB-T USB2.0", NULL) }, { DVB_USB_DEVICE(USB_VID_774, USB_PID_FRIIO_WHITE, &friio_props, "774 Friio White ISDB-T USB2.0", NULL) }, diff --git a/include/media/dvb-usb-ids.h b/include/media/dvb-usb-ids.h index 800d473b03c4..41f0bf122f53 100644 --- a/include/media/dvb-usb-ids.h +++ b/include/media/dvb-usb-ids.h @@ -96,7 +96,7 @@ #define USB_PID_AFATECH_AF9035_9035 0x9035 #define USB_PID_TREKSTOR_DVBT 0x901b #define USB_PID_TREKSTOR_TERRES_2_0 0xC803 -#define USB_VID_ALINK_DTU 0xf170 +#define USB_PID_ALINK_DTU 0xf170 #define USB_PID_ANSONIC_DVBT_USB 0x6000 #define USB_PID_ANYSEE 0x861f #define USB_PID_AZUREWAVE_AD_TU700 0x3237 -- cgit v1.2.3-59-g8ed1b From e5ad7db4b2f35aaed796669b47e24c6d79cab3d0 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 21 Apr 2020 11:23:41 +0200 Subject: media: cec-gpio: handle gpiod_get_value errors correctly gpiod_get_value() can return negative values if an error occurs. In several places this error code was ignored. Ensure that errors codes are handled correctly throughout the CEC pin framework and CEC pin drivers. The return code of the cec_pin_ops read() callback had to be changed from 'bool' to 'int', which mean the prototype of that callback in the sun4i drm driver also had to be changed. Signed-off-by: Hans Verkuil Reported-by: Dan Carpenter Signed-off-by: Mauro Carvalho Chehab --- drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c | 2 +- drivers/media/cec/platform/cec-gpio/cec-gpio.c | 18 +++++++++++------- include/media/cec-pin.h | 16 +++++++--------- 3 files changed, 19 insertions(+), 17 deletions(-) (limited to 'include/media') diff --git a/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c b/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c index 68d4644ac2dc..126e1517ade2 100644 --- a/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c +++ b/drivers/gpu/drm/sun4i/sun4i_hdmi_enc.c @@ -282,7 +282,7 @@ static const struct drm_connector_funcs sun4i_hdmi_connector_funcs = { }; #ifdef CONFIG_DRM_SUN4I_HDMI_CEC -static bool sun4i_hdmi_cec_pin_read(struct cec_adapter *adap) +static int sun4i_hdmi_cec_pin_read(struct cec_adapter *adap) { struct sun4i_hdmi *hdmi = cec_get_drvdata(adap); diff --git a/drivers/media/cec/platform/cec-gpio/cec-gpio.c b/drivers/media/cec/platform/cec-gpio/cec-gpio.c index 42d2c2cd9a78..c8c4efc83f5f 100644 --- a/drivers/media/cec/platform/cec-gpio/cec-gpio.c +++ b/drivers/media/cec/platform/cec-gpio/cec-gpio.c @@ -31,12 +31,12 @@ struct cec_gpio { ktime_t v5_ts; }; -static bool cec_gpio_read(struct cec_adapter *adap) +static int cec_gpio_read(struct cec_adapter *adap) { struct cec_gpio *cec = cec_get_drvdata(adap); if (cec->cec_is_low) - return false; + return 0; return gpiod_get_value(cec->cec_gpio); } @@ -71,9 +71,10 @@ static irqreturn_t cec_hpd_gpio_irq_handler_thread(int irq, void *priv) static irqreturn_t cec_5v_gpio_irq_handler(int irq, void *priv) { struct cec_gpio *cec = priv; - bool is_high = gpiod_get_value(cec->v5_gpio); + int val = gpiod_get_value(cec->v5_gpio); + bool is_high = val > 0; - if (is_high == cec->v5_is_high) + if (val < 0 || is_high == cec->v5_is_high) return IRQ_HANDLED; cec->v5_ts = ktime_get(); cec->v5_is_high = is_high; @@ -91,9 +92,10 @@ static irqreturn_t cec_5v_gpio_irq_handler_thread(int irq, void *priv) static irqreturn_t cec_hpd_gpio_irq_handler(int irq, void *priv) { struct cec_gpio *cec = priv; - bool is_high = gpiod_get_value(cec->hpd_gpio); + int val = gpiod_get_value(cec->hpd_gpio); + bool is_high = val > 0; - if (is_high == cec->hpd_is_high) + if (val < 0 || is_high == cec->hpd_is_high) return IRQ_HANDLED; cec->hpd_ts = ktime_get(); cec->hpd_is_high = is_high; @@ -103,8 +105,10 @@ static irqreturn_t cec_hpd_gpio_irq_handler(int irq, void *priv) static irqreturn_t cec_gpio_irq_handler(int irq, void *priv) { struct cec_gpio *cec = priv; + int val = gpiod_get_value(cec->cec_gpio); - cec_pin_changed(cec->adap, gpiod_get_value(cec->cec_gpio)); + if (val >= 0) + cec_pin_changed(cec->adap, val > 0); return IRQ_HANDLED; } diff --git a/include/media/cec-pin.h b/include/media/cec-pin.h index 88c8b016eb09..483bc4769fe9 100644 --- a/include/media/cec-pin.h +++ b/include/media/cec-pin.h @@ -13,7 +13,8 @@ /** * struct cec_pin_ops - low-level CEC pin operations - * @read: read the CEC pin. Return true if high, false if low. + * @read: read the CEC pin. Returns > 0 if high, 0 if low, or an error + * if negative. * @low: drive the CEC pin low. * @high: stop driving the CEC pin. The pull-up will drive the pin * high, unless someone else is driving the pin low. @@ -22,13 +23,10 @@ * @free: optional. Free any allocated resources. Called when the * adapter is deleted. * @status: optional, log status information. - * @read_hpd: read the HPD pin. Return true if high, false if low or - * an error if negative. If NULL or -ENOTTY is returned, - * then this is not supported. - * @read_5v: read the 5V pin. Return true if high, false if low or - * an error if negative. If NULL or -ENOTTY is returned, - * then this is not supported. - * + * @read_hpd: optional. Read the HPD pin. Returns > 0 if high, 0 if low or + * an error if negative. + * @read_5v: optional. Read the 5V pin. Returns > 0 if high, 0 if low or + * an error if negative. * @received: optional. High-level CEC message callback. Allows the driver * to process CEC messages. * @@ -36,7 +34,7 @@ * cec pin framework to manipulate the CEC pin. */ struct cec_pin_ops { - bool (*read)(struct cec_adapter *adap); + int (*read)(struct cec_adapter *adap); void (*low)(struct cec_adapter *adap); void (*high)(struct cec_adapter *adap); bool (*enable_irq)(struct cec_adapter *adap); -- cgit v1.2.3-59-g8ed1b From e51759f56d314d28c25be7606b03791f048e44c7 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 23 Apr 2020 13:42:32 +0200 Subject: media: v4l2-ctrls.h: clarify the p_def argument of v4l2_ctrl_new_std_compound It was not sufficiently clear how to create and use p_def. Improve the documentation. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- include/media/v4l2-ctrls.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'include/media') diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h index 75a8daacb4c4..757a713bad41 100644 --- a/include/media/v4l2-ctrls.h +++ b/include/media/v4l2-ctrls.h @@ -685,7 +685,9 @@ struct v4l2_ctrl *v4l2_ctrl_new_std_menu_items(struct v4l2_ctrl_handler *hdl, * @p_def: The control's default value. * * Sames as v4l2_ctrl_new_std(), but with support to compound controls, thanks - * to the @p_def field. + * to the @p_def field. Use v4l2_ctrl_ptr_create() to create @p_def from a + * pointer. Use v4l2_ctrl_ptr_create(NULL) if the default value of the + * compound control should be all zeroes. * */ struct v4l2_ctrl *v4l2_ctrl_new_std_compound(struct v4l2_ctrl_handler *hdl, -- cgit v1.2.3-59-g8ed1b From f75c431e54e2e43c91fe267097b974ff2e5dc668 Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Thu, 7 May 2020 17:12:50 +0200 Subject: media: v4l2-dev: Add v4l2_device_register_ro_subdev_node() Add to the V4L2 core a function to register device nodes for video subdevices in read-only mode. Registering a device node in read-only mode is useful to expose to userspace the current sub-device configuration, without allowing application to change it by using the V4L2 subdevice ioctls. Acked-by: Sakari Ailus Signed-off-by: Jacopo Mondi Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-device.c | 7 +++-- drivers/media/v4l2-core/v4l2-subdev.c | 19 +++++++++++++ include/media/v4l2-dev.h | 7 +++++ include/media/v4l2-device.h | 50 ++++++++++++++++++++++++++++++++--- 4 files changed, 77 insertions(+), 6 deletions(-) (limited to 'include/media') diff --git a/drivers/media/v4l2-core/v4l2-device.c b/drivers/media/v4l2-core/v4l2-device.c index c69941214bb2..de4287251a89 100644 --- a/drivers/media/v4l2-core/v4l2-device.c +++ b/drivers/media/v4l2-core/v4l2-device.c @@ -186,7 +186,8 @@ static void v4l2_device_release_subdev_node(struct video_device *vdev) kfree(vdev); } -int v4l2_device_register_subdev_nodes(struct v4l2_device *v4l2_dev) +int __v4l2_device_register_subdev_nodes(struct v4l2_device *v4l2_dev, + bool read_only) { struct video_device *vdev; struct v4l2_subdev *sd; @@ -215,6 +216,8 @@ int v4l2_device_register_subdev_nodes(struct v4l2_device *v4l2_dev) vdev->fops = &v4l2_subdev_fops; vdev->release = v4l2_device_release_subdev_node; vdev->ctrl_handler = sd->ctrl_handler; + if (read_only) + set_bit(V4L2_FL_SUBDEV_RO_DEVNODE, &vdev->flags); err = __video_register_device(vdev, VFL_TYPE_SUBDEV, -1, 1, sd->owner); if (err < 0) { @@ -252,7 +255,7 @@ clean_up: return err; } -EXPORT_SYMBOL_GPL(v4l2_device_register_subdev_nodes); +EXPORT_SYMBOL_GPL(__v4l2_device_register_subdev_nodes); void v4l2_device_unregister_subdev(struct v4l2_subdev *sd) { diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c index a376b351135f..1dc263c2ca0a 100644 --- a/drivers/media/v4l2-core/v4l2-subdev.c +++ b/drivers/media/v4l2-core/v4l2-subdev.c @@ -331,6 +331,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) struct v4l2_fh *vfh = file->private_data; #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API) struct v4l2_subdev_fh *subdev_fh = to_v4l2_subdev_fh(vfh); + bool ro_subdev = test_bit(V4L2_FL_SUBDEV_RO_DEVNODE, &vdev->flags); #endif int rval; @@ -477,6 +478,9 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) case VIDIOC_SUBDEV_S_FMT: { struct v4l2_subdev_format *format = arg; + if (format->which != V4L2_SUBDEV_FORMAT_TRY && ro_subdev) + return -EPERM; + memset(format->reserved, 0, sizeof(format->reserved)); memset(format->format.reserved, 0, sizeof(format->format.reserved)); return v4l2_subdev_call(sd, pad, set_fmt, subdev_fh->pad, format); @@ -504,6 +508,9 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) struct v4l2_subdev_crop *crop = arg; struct v4l2_subdev_selection sel; + if (crop->which != V4L2_SUBDEV_FORMAT_TRY && ro_subdev) + return -EPERM; + memset(crop->reserved, 0, sizeof(crop->reserved)); memset(&sel, 0, sizeof(sel)); sel.which = crop->which; @@ -545,6 +552,9 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) case VIDIOC_SUBDEV_S_FRAME_INTERVAL: { struct v4l2_subdev_frame_interval *fi = arg; + if (ro_subdev) + return -EPERM; + memset(fi->reserved, 0, sizeof(fi->reserved)); return v4l2_subdev_call(sd, video, s_frame_interval, arg); } @@ -568,6 +578,9 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) case VIDIOC_SUBDEV_S_SELECTION: { struct v4l2_subdev_selection *sel = arg; + if (sel->which != V4L2_SUBDEV_FORMAT_TRY && ro_subdev) + return -EPERM; + memset(sel->reserved, 0, sizeof(sel->reserved)); return v4l2_subdev_call( sd, pad, set_selection, subdev_fh->pad, sel); @@ -604,6 +617,9 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) return v4l2_subdev_call(sd, video, g_dv_timings, arg); case VIDIOC_SUBDEV_S_DV_TIMINGS: + if (ro_subdev) + return -EPERM; + return v4l2_subdev_call(sd, video, s_dv_timings, arg); case VIDIOC_SUBDEV_G_STD: @@ -612,6 +628,9 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg) case VIDIOC_SUBDEV_S_STD: { v4l2_std_id *std = arg; + if (ro_subdev) + return -EPERM; + return v4l2_subdev_call(sd, video, s_std, *std); } diff --git a/include/media/v4l2-dev.h b/include/media/v4l2-dev.h index 4602c15ff878..ad2d41952442 100644 --- a/include/media/v4l2-dev.h +++ b/include/media/v4l2-dev.h @@ -82,11 +82,18 @@ struct v4l2_ctrl_handler; * but the old crop API will still work as expected in order to preserve * backwards compatibility. * Never set this flag for new drivers. + * @V4L2_FL_SUBDEV_RO_DEVNODE: + * indicates that the video device node is registered in read-only mode. + * The flag only applies to device nodes registered for sub-devices, it is + * set by the core when the sub-devices device nodes are registered with + * v4l2_device_register_ro_subdev_nodes() and used by the sub-device ioctl + * handler to restrict access to some ioctl calls. */ enum v4l2_video_device_flags { V4L2_FL_REGISTERED = 0, V4L2_FL_USES_V4L2_FH = 1, V4L2_FL_QUIRK_INVERTED_CROP = 2, + V4L2_FL_SUBDEV_RO_DEVNODE = 3, }; /* Priority helper functions */ diff --git a/include/media/v4l2-device.h b/include/media/v4l2-device.h index 7c912b7d2870..64ec4de948e9 100644 --- a/include/media/v4l2-device.h +++ b/include/media/v4l2-device.h @@ -174,14 +174,56 @@ int __must_check v4l2_device_register_subdev(struct v4l2_device *v4l2_dev, void v4l2_device_unregister_subdev(struct v4l2_subdev *sd); /** - * v4l2_device_register_subdev_nodes - Registers device nodes for all subdevs - * of the v4l2 device that are marked with - * the %V4L2_SUBDEV_FL_HAS_DEVNODE flag. + * __v4l2_device_register_ro_subdev_nodes - Registers device nodes for + * all subdevs of the v4l2 device that are marked with the + * %V4L2_SUBDEV_FL_HAS_DEVNODE flag. * * @v4l2_dev: pointer to struct v4l2_device + * @read_only: subdevices read-only flag. True to register the subdevices + * device nodes in read-only mode, false to allow full access to the + * subdevice userspace API. */ int __must_check -v4l2_device_register_subdev_nodes(struct v4l2_device *v4l2_dev); +__v4l2_device_register_subdev_nodes(struct v4l2_device *v4l2_dev, + bool read_only); + +/** + * v4l2_device_register_subdev_nodes - Registers subdevices device nodes with + * unrestricted access to the subdevice userspace operations + * + * Internally calls __v4l2_device_register_subdev_nodes(). See its documentation + * for more details. + * + * @v4l2_dev: pointer to struct v4l2_device + */ +static inline int __must_check +v4l2_device_register_subdev_nodes(struct v4l2_device *v4l2_dev) +{ +#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API) + return __v4l2_device_register_subdev_nodes(v4l2_dev, false); +#else + return 0; +#endif +} + +/** + * v4l2_device_register_ro_subdev_nodes - Registers subdevices device nodes + * in read-only mode + * + * Internally calls __v4l2_device_register_subdev_nodes(). See its documentation + * for more details. + * + * @v4l2_dev: pointer to struct v4l2_device + */ +static inline int __must_check +v4l2_device_register_ro_subdev_nodes(struct v4l2_device *v4l2_dev) +{ +#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API) + return __v4l2_device_register_subdev_nodes(v4l2_dev, true); +#else + return 0; +#endif +} /** * v4l2_subdev_notify - Sends a notification to v4l2_device. -- cgit v1.2.3-59-g8ed1b From 70d4a9efee9cdd580207473379e3ee64b331ae75 Mon Sep 17 00:00:00 2001 From: Steve Longerbeam Date: Fri, 1 May 2020 19:15:35 +0200 Subject: media: entity: Pass entity to get_fwnode_pad operation Add a missing pointer to the entity in the media_entity operation get_fwnode_pad. There are no implementers of this op yet, but a future entity that does so will almost certainly need a reference to itself to carry out the work. operation") Fixes: ae45cd5efc120 ("[media] media: entity: Add get_fwnode_pad entity Signed-off-by: Steve Longerbeam Reviewed-by: Laurent Pinchart Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/mc/mc-entity.c | 2 +- include/media/media-entity.h | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'include/media') diff --git a/drivers/media/mc/mc-entity.c b/drivers/media/mc/mc-entity.c index 211279c5fd77..12b45e669bcc 100644 --- a/drivers/media/mc/mc-entity.c +++ b/drivers/media/mc/mc-entity.c @@ -386,7 +386,7 @@ int media_entity_get_fwnode_pad(struct media_entity *entity, if (ret) return ret; - ret = entity->ops->get_fwnode_pad(&endpoint); + ret = entity->ops->get_fwnode_pad(entity, &endpoint); if (ret < 0) return ret; diff --git a/include/media/media-entity.h b/include/media/media-entity.h index 8cb2c504a05c..cde80ad029b7 100644 --- a/include/media/media-entity.h +++ b/include/media/media-entity.h @@ -212,7 +212,8 @@ struct media_pad { * mutex held. */ struct media_entity_operations { - int (*get_fwnode_pad)(struct fwnode_endpoint *endpoint); + int (*get_fwnode_pad)(struct media_entity *entity, + struct fwnode_endpoint *endpoint); int (*link_setup)(struct media_entity *entity, const struct media_pad *local, const struct media_pad *remote, u32 flags); -- cgit v1.2.3-59-g8ed1b From 8fe784b9abb296124d0182eac35b96dbc29d049a Mon Sep 17 00:00:00 2001 From: Steve Longerbeam Date: Fri, 1 May 2020 19:15:36 +0200 Subject: media: v4l2-subdev: add v4l2_subdev_get_fwnode_pad_1_to_1 Add a convenience function that can be used as the .get_fwnode_pad operation for subdevices that map port numbers and pad indexes 1:1. The function verifies the endpoint is owned by the subdevice, and if so returns the endpoint port number. Signed-off-by: Steve Longerbeam Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-subdev.c | 22 ++++++++++++++++++++++ include/media/v4l2-subdev.h | 17 +++++++++++++++++ 2 files changed, 39 insertions(+) (limited to 'include/media') diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c index 665b0c0f74cf..6b989fe5a0a9 100644 --- a/drivers/media/v4l2-core/v4l2-subdev.c +++ b/drivers/media/v4l2-core/v4l2-subdev.c @@ -749,6 +749,28 @@ const struct v4l2_file_operations v4l2_subdev_fops = { }; #ifdef CONFIG_MEDIA_CONTROLLER + +int v4l2_subdev_get_fwnode_pad_1_to_1(struct media_entity *entity, + struct fwnode_endpoint *endpoint) +{ + struct fwnode_handle *fwnode; + struct v4l2_subdev *sd; + + if (!is_media_entity_v4l2_subdev(entity)) + return -EINVAL; + + sd = media_entity_to_v4l2_subdev(entity); + + fwnode = fwnode_graph_get_port_parent(endpoint->local_fwnode); + fwnode_handle_put(fwnode); + + if (dev_fwnode(sd->dev) == fwnode) + return endpoint->port; + + return -ENXIO; +} +EXPORT_SYMBOL_GPL(v4l2_subdev_get_fwnode_pad_1_to_1); + int v4l2_subdev_link_validate_default(struct v4l2_subdev *sd, struct media_link *link, struct v4l2_subdev_format *source_fmt, diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h index a4848de59852..f7fe78a6f65a 100644 --- a/include/media/v4l2-subdev.h +++ b/include/media/v4l2-subdev.h @@ -1027,6 +1027,23 @@ static inline void *v4l2_get_subdev_hostdata(const struct v4l2_subdev *sd) #ifdef CONFIG_MEDIA_CONTROLLER +/** + * v4l2_subdev_get_fwnode_pad_1_to_1 - Get pad number from a subdev fwnode + * endpoint, assuming 1:1 port:pad + * + * @entity - Pointer to the subdev entity + * @endpoint - Pointer to a parsed fwnode endpoint + * + * This function can be used as the .get_fwnode_pad operation for + * subdevices that map port numbers and pad indexes 1:1. If the endpoint + * is owned by the subdevice, the function returns the endpoint port + * number. + * + * Returns the endpoint port number on success or a negative error code. + */ +int v4l2_subdev_get_fwnode_pad_1_to_1(struct media_entity *entity, + struct fwnode_endpoint *endpoint); + /** * v4l2_subdev_link_validate_default - validates a media link * -- cgit v1.2.3-59-g8ed1b From 0d3c81e82da90f0752a09c38ffae7e7ffec01b33 Mon Sep 17 00:00:00 2001 From: Steve Longerbeam Date: Fri, 1 May 2020 19:15:37 +0200 Subject: media: v4l2-mc: add v4l2_create_fwnode_links helpers Add functions to create media links between source and sink subdevices, based on the fwnode endpoint connections between them: v4l2_create_fwnode_links_to_pad() - create links from a source subdev to a single sink pad based on fwnode endpoint connections. v4l2_create_fwnode_links() - create all links from a source to sink subdev based on fwnode endpoint connections. These functions can be used in a sink's v4l2-async notifier subdev bound callback to make the links from the bound subdev. Signed-off-by: Steve Longerbeam Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-mc.c | 95 +++++++++++++++++++++++++++++++++++++++ include/media/v4l2-mc.h | 48 ++++++++++++++++++++ 2 files changed, 143 insertions(+) (limited to 'include/media') diff --git a/drivers/media/v4l2-core/v4l2-mc.c b/drivers/media/v4l2-core/v4l2-mc.c index 0fffdd3ce6a4..ba2f2b8dcc8c 100644 --- a/drivers/media/v4l2-core/v4l2-mc.c +++ b/drivers/media/v4l2-core/v4l2-mc.c @@ -309,6 +309,101 @@ int v4l_vb2q_enable_media_source(struct vb2_queue *q) } EXPORT_SYMBOL_GPL(v4l_vb2q_enable_media_source); +int v4l2_create_fwnode_links_to_pad(struct v4l2_subdev *src_sd, + struct media_pad *sink) +{ + struct fwnode_handle *endpoint; + struct v4l2_subdev *sink_sd; + + if (!(sink->flags & MEDIA_PAD_FL_SINK) || + !is_media_entity_v4l2_subdev(sink->entity)) + return -EINVAL; + + sink_sd = media_entity_to_v4l2_subdev(sink->entity); + + fwnode_graph_for_each_endpoint(dev_fwnode(src_sd->dev), endpoint) { + struct fwnode_handle *remote_ep; + int src_idx, sink_idx, ret; + struct media_pad *src; + + src_idx = media_entity_get_fwnode_pad(&src_sd->entity, + endpoint, + MEDIA_PAD_FL_SOURCE); + if (src_idx < 0) + continue; + + remote_ep = fwnode_graph_get_remote_endpoint(endpoint); + if (!remote_ep) + continue; + + /* + * ask the sink to verify it owns the remote endpoint, + * and translate to a sink pad. + */ + sink_idx = media_entity_get_fwnode_pad(&sink_sd->entity, + remote_ep, + MEDIA_PAD_FL_SINK); + fwnode_handle_put(remote_ep); + + if (sink_idx < 0 || sink_idx != sink->index) + continue; + + /* + * the source endpoint corresponds to one of its source pads, + * the source endpoint connects to an endpoint at the sink + * entity, and the sink endpoint corresponds to the sink + * pad requested, so we have found an endpoint connection + * that works, create the media link for it. + */ + + src = &src_sd->entity.pads[src_idx]; + + /* skip if link already exists */ + if (media_entity_find_link(src, sink)) + continue; + + dev_dbg(sink_sd->dev, "creating link %s:%d -> %s:%d\n", + src_sd->entity.name, src_idx, + sink_sd->entity.name, sink_idx); + + ret = media_create_pad_link(&src_sd->entity, src_idx, + &sink_sd->entity, sink_idx, 0); + if (ret) { + dev_err(sink_sd->dev, + "link %s:%d -> %s:%d failed with %d\n", + src_sd->entity.name, src_idx, + sink_sd->entity.name, sink_idx, ret); + + fwnode_handle_put(endpoint); + return ret; + } + } + + return 0; +} +EXPORT_SYMBOL_GPL(v4l2_create_fwnode_links_to_pad); + +int v4l2_create_fwnode_links(struct v4l2_subdev *src_sd, + struct v4l2_subdev *sink_sd) +{ + unsigned int i; + + for (i = 0; i < sink_sd->entity.num_pads; i++) { + struct media_pad *pad = &sink_sd->entity.pads[i]; + int ret; + + if (!(pad->flags & MEDIA_PAD_FL_SINK)) + continue; + + ret = v4l2_create_fwnode_links_to_pad(src_sd, pad); + if (ret) + return ret; + } + + return 0; +} +EXPORT_SYMBOL_GPL(v4l2_create_fwnode_links); + /* ----------------------------------------------------------------------------- * Pipeline power management * diff --git a/include/media/v4l2-mc.h b/include/media/v4l2-mc.h index 5e73eb8e28f6..246eed398648 100644 --- a/include/media/v4l2-mc.h +++ b/include/media/v4l2-mc.h @@ -12,6 +12,7 @@ #include #include +#include #include /* We don't need to include pci.h or usb.h here */ @@ -84,6 +85,53 @@ void v4l_disable_media_source(struct video_device *vdev); */ int v4l_vb2q_enable_media_source(struct vb2_queue *q); +/** + * v4l2_create_fwnode_links_to_pad - Create fwnode-based links from a + * source subdev to a sink subdev pad. + * + * @src_sd - pointer to a source subdev + * @sink - pointer to a subdev sink pad + * + * This function searches for fwnode endpoint connections from a source + * subdevice to a single sink pad, and if suitable connections are found, + * translates them into media links to that pad. The function can be + * called by the sink subdevice, in its v4l2-async notifier subdev bound + * callback, to create links from a bound source subdevice. + * + * .. note:: + * + * Any sink subdevice that calls this function must implement the + * .get_fwnode_pad media operation in order to verify endpoints passed + * to the sink are owned by the sink. + * + * Return 0 on success or a negative error code on failure. + */ +int v4l2_create_fwnode_links_to_pad(struct v4l2_subdev *src_sd, + struct media_pad *sink); + +/** + * v4l2_create_fwnode_links - Create fwnode-based links from a source + * subdev to a sink subdev. + * + * @src_sd - pointer to a source subdevice + * @sink_sd - pointer to a sink subdevice + * + * This function searches for any and all fwnode endpoint connections + * between source and sink subdevices, and translates them into media + * links. The function can be called by the sink subdevice, in its + * v4l2-async notifier subdev bound callback, to create all links from + * a bound source subdevice. + * + * .. note:: + * + * Any sink subdevice that calls this function must implement the + * .get_fwnode_pad media operation in order to verify endpoints passed + * to the sink are owned by the sink. + * + * Return 0 on success or a negative error code on failure. + */ +int v4l2_create_fwnode_links(struct v4l2_subdev *src_sd, + struct v4l2_subdev *sink_sd); /** * v4l2_pipeline_pm_get - Increase the use count of a pipeline -- cgit v1.2.3-59-g8ed1b From acee6033c5c5b7758b521ea63bb9f989578aa9fd Mon Sep 17 00:00:00 2001 From: Steve Longerbeam Date: Fri, 1 May 2020 19:15:40 +0200 Subject: media: Revert "media: v4l2-fwnode: Add a convenience function for registering subdevs with notifiers" The users of v4l2_async_register_fwnode_subdev() have switched to parsing their endpoints and setting up async sub-device lists in their notifiers locally, without using the endpoint parsing callbacks. There are no more users of v4l2_async_register_fwnode_subdev() so this convenience function can be removed. This reverts commit 1634f0eded87d1f150e823fa56cd782ea0775eb2. Signed-off-by: Steve Longerbeam Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-fwnode.c | 62 ----------------------------------- include/media/v4l2-fwnode.h | 38 --------------------- 2 files changed, 100 deletions(-) (limited to 'include/media') diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c index 97f0f8b23b5d..e1f273ae8522 100644 --- a/drivers/media/v4l2-core/v4l2-fwnode.c +++ b/drivers/media/v4l2-core/v4l2-fwnode.c @@ -1323,68 +1323,6 @@ out_cleanup: } EXPORT_SYMBOL_GPL(v4l2_async_register_subdev_sensor_common); -int v4l2_async_register_fwnode_subdev(struct v4l2_subdev *sd, - size_t asd_struct_size, - unsigned int *ports, - unsigned int num_ports, - parse_endpoint_func parse_endpoint) -{ - struct v4l2_async_notifier *notifier; - struct device *dev = sd->dev; - struct fwnode_handle *fwnode; - int ret; - - if (WARN_ON(!dev)) - return -ENODEV; - - fwnode = dev_fwnode(dev); - if (!fwnode_device_is_available(fwnode)) - return -ENODEV; - - notifier = kzalloc(sizeof(*notifier), GFP_KERNEL); - if (!notifier) - return -ENOMEM; - - v4l2_async_notifier_init(notifier); - - if (!ports) { - ret = v4l2_async_notifier_parse_fwnode_endpoints(dev, notifier, - asd_struct_size, - parse_endpoint); - if (ret < 0) - goto out_cleanup; - } else { - unsigned int i; - - for (i = 0; i < num_ports; i++) { - ret = v4l2_async_notifier_parse_fwnode_endpoints_by_port(dev, notifier, asd_struct_size, ports[i], parse_endpoint); - if (ret < 0) - goto out_cleanup; - } - } - - ret = v4l2_async_subdev_notifier_register(sd, notifier); - if (ret < 0) - goto out_cleanup; - - ret = v4l2_async_register_subdev(sd); - if (ret < 0) - goto out_unregister; - - sd->subdev_notifier = notifier; - - return 0; - -out_unregister: - v4l2_async_notifier_unregister(notifier); -out_cleanup: - v4l2_async_notifier_cleanup(notifier); - kfree(notifier); - - return ret; -} -EXPORT_SYMBOL_GPL(v4l2_async_register_fwnode_subdev); - MODULE_LICENSE("GPL"); MODULE_AUTHOR("Sakari Ailus "); MODULE_AUTHOR("Sylwester Nawrocki "); diff --git a/include/media/v4l2-fwnode.h b/include/media/v4l2-fwnode.h index dd82d6d9764e..fad7a6480bf9 100644 --- a/include/media/v4l2-fwnode.h +++ b/include/media/v4l2-fwnode.h @@ -20,7 +20,6 @@ #include #include -#include struct fwnode_handle; struct v4l2_async_notifier; @@ -490,43 +489,6 @@ v4l2_async_notifier_parse_fwnode_endpoints_by_port(struct device *dev, int v4l2_async_notifier_parse_fwnode_sensor_common(struct device *dev, struct v4l2_async_notifier *notifier); -/** - * v4l2_async_register_fwnode_subdev - registers a sub-device to the - * asynchronous sub-device framework - * and parses fwnode endpoints - * - * @sd: pointer to struct &v4l2_subdev - * @asd_struct_size: size of the driver's async sub-device struct, including - * sizeof(struct v4l2_async_subdev). The &struct - * v4l2_async_subdev shall be the first member of - * the driver's async sub-device struct, i.e. both - * begin at the same memory address. - * @ports: array of port id's to parse for fwnode endpoints. If NULL, will - * parse all ports owned by the sub-device. - * @num_ports: number of ports in @ports array. Ignored if @ports is NULL. - * @parse_endpoint: Driver's callback function called on each V4L2 fwnode - * endpoint. Optional. - * - * This function is just like v4l2_async_register_subdev() with the - * exception that calling it will also allocate a notifier for the - * sub-device, parse the sub-device's firmware node endpoints using - * v4l2_async_notifier_parse_fwnode_endpoints() or - * v4l2_async_notifier_parse_fwnode_endpoints_by_port(), and - * registers the sub-device notifier. The sub-device is similarly - * unregistered by calling v4l2_async_unregister_subdev(). - * - * While registered, the subdev module is marked as in-use. - * - * An error is returned if the module is no longer loaded on any attempts - * to register it. - */ -int -v4l2_async_register_fwnode_subdev(struct v4l2_subdev *sd, - size_t asd_struct_size, - unsigned int *ports, - unsigned int num_ports, - parse_endpoint_func parse_endpoint); - /* Helper macros to access the connector links. */ /** v4l2_connector_last_link - Helper macro to get the first -- cgit v1.2.3-59-g8ed1b From 344897ef1d9b33e246b64e255d807ca6c053f349 Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Sat, 9 May 2020 11:04:49 +0200 Subject: media: v4l2-fwnode: Add helper to parse device properties Add an helper function to parse common device properties in the same way as v4l2_fwnode_endpoint_parse() parses common endpoint properties. Parse the 'rotation' and 'orientation' properties from the firmware interface. Signed-off-by: Jacopo Mondi Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-fwnode.c | 42 +++++++++++++++++++++++++++++++ include/media/v4l2-fwnode.h | 47 +++++++++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+) (limited to 'include/media') diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c index e1f273ae8522..6cd52e1ef5e4 100644 --- a/drivers/media/v4l2-core/v4l2-fwnode.c +++ b/drivers/media/v4l2-core/v4l2-fwnode.c @@ -756,6 +756,48 @@ err: } EXPORT_SYMBOL_GPL(v4l2_fwnode_connector_add_link); +int v4l2_fwnode_device_parse(struct device *dev, + struct v4l2_fwnode_device_properties *props) +{ + struct fwnode_handle *fwnode = dev_fwnode(dev); + u32 val; + int ret; + + memset(props, 0, sizeof(*props)); + + props->orientation = V4L2_FWNODE_PROPERTY_UNSET; + ret = fwnode_property_read_u32(fwnode, "orientation", &val); + if (!ret) { + switch (val) { + case V4L2_FWNODE_ORIENTATION_FRONT: + case V4L2_FWNODE_ORIENTATION_BACK: + case V4L2_FWNODE_ORIENTATION_EXTERNAL: + break; + default: + dev_warn(dev, "Unsupported device orientation: %u\n", val); + return -EINVAL; + } + + props->orientation = val; + dev_dbg(dev, "device orientation: %u\n", val); + } + + props->rotation = V4L2_FWNODE_PROPERTY_UNSET; + ret = fwnode_property_read_u32(fwnode, "rotation", &val); + if (!ret) { + if (val >= 360) { + dev_warn(dev, "Unsupported device rotation: %u\n", val); + return -EINVAL; + } + + props->rotation = val; + dev_dbg(dev, "device rotation: %u\n", val); + } + + return 0; +} +EXPORT_SYMBOL_GPL(v4l2_fwnode_device_parse); + static int v4l2_async_notifier_fwnode_parse_endpoint(struct device *dev, struct v4l2_async_notifier *notifier, diff --git a/include/media/v4l2-fwnode.h b/include/media/v4l2-fwnode.h index fad7a6480bf9..c47b70636e42 100644 --- a/include/media/v4l2-fwnode.h +++ b/include/media/v4l2-fwnode.h @@ -108,6 +108,36 @@ struct v4l2_fwnode_endpoint { unsigned int nr_of_link_frequencies; }; +/** + * V4L2_FWNODE_PROPERTY_UNSET - identify a non initialized property + * + * All properties in &struct v4l2_fwnode_device_properties are initialized + * to this value. + */ +#define V4L2_FWNODE_PROPERTY_UNSET (-1U) + +/** + * enum v4l2_fwnode_orientation - possible device orientation + * @V4L2_FWNODE_ORIENTATION_FRONT: device installed on the front side + * @V4L2_FWNODE_ORIENTATION_BACK: device installed on the back side + * @V4L2_FWNODE_ORIENTATION_EXTERNAL: device externally located + */ +enum v4l2_fwnode_orientation { + V4L2_FWNODE_ORIENTATION_FRONT, + V4L2_FWNODE_ORIENTATION_BACK, + V4L2_FWNODE_ORIENTATION_EXTERNAL +}; + +/** + * struct v4l2_fwnode_device_properties - fwnode device properties + * @orientation: device orientation. See &enum v4l2_fwnode_orientation + * @rotation: device rotation + */ +struct v4l2_fwnode_device_properties { + enum v4l2_fwnode_orientation orientation; + unsigned int rotation; +}; + /** * struct v4l2_fwnode_link - a link between two endpoints * @local_node: pointer to device_node of this endpoint @@ -353,6 +383,23 @@ int v4l2_fwnode_connector_parse(struct fwnode_handle *fwnode, int v4l2_fwnode_connector_add_link(struct fwnode_handle *fwnode, struct v4l2_fwnode_connector *connector); +/** + * v4l2_fwnode_device_parse() - parse fwnode device properties + * @dev: pointer to &struct device + * @props: pointer to &struct v4l2_fwnode_device_properties where to store the + * parsed properties values + * + * This function parses and validates the V4L2 fwnode device properties from the + * firmware interface, and fills the @struct v4l2_fwnode_device_properties + * provided by the caller. + * + * Return: + * % 0 on success + * %-EINVAL if a parsed property value is not valid + */ +int v4l2_fwnode_device_parse(struct device *dev, + struct v4l2_fwnode_device_properties *props); + /** * typedef parse_endpoint_func - Driver's callback function to be called on * each V4L2 fwnode endpoint. -- cgit v1.2.3-59-g8ed1b From ae6ff16cf745a56b7ef88a7177e5e8257849feb7 Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Sat, 9 May 2020 11:04:50 +0200 Subject: media: include: v4l2-ctrl: Sort forward declarations Before adding a new forward declaration to the v4l2-ctrls.h header file, sort the existing ones alphabetically. Signed-off-by: Jacopo Mondi Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- include/media/v4l2-ctrls.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'include/media') diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h index 757a713bad41..224c10823bbf 100644 --- a/include/media/v4l2-ctrls.h +++ b/include/media/v4l2-ctrls.h @@ -25,14 +25,14 @@ /* forward references */ struct file; +struct poll_table_struct; +struct v4l2_ctrl; struct v4l2_ctrl_handler; struct v4l2_ctrl_helper; -struct v4l2_ctrl; -struct video_device; +struct v4l2_fh; struct v4l2_subdev; struct v4l2_subscribed_event; -struct v4l2_fh; -struct poll_table_struct; +struct video_device; /** * union v4l2_ctrl_ptr - A pointer to a control value. -- cgit v1.2.3-59-g8ed1b From e0a360630debdf12355d9ec9f1417172c3fa6756 Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Sat, 9 May 2020 11:04:52 +0200 Subject: media: v4l2-ctrls: Add helper to register properties Add an helper function to v4l2-ctrls to register controls associated with a device property. Signed-off-by: Jacopo Mondi Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-ctrls.c | 40 ++++++++++++++++++++++++++++++++++++ include/media/v4l2-ctrls.h | 26 +++++++++++++++++++++++ 2 files changed, 66 insertions(+) (limited to 'include/media') diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index 4273d56dac65..b188577db40f 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #define dprintk(vdev, fmt, arg...) do { \ @@ -4621,3 +4622,42 @@ __poll_t v4l2_ctrl_poll(struct file *file, struct poll_table_struct *wait) return 0; } EXPORT_SYMBOL(v4l2_ctrl_poll); + +int v4l2_ctrl_new_fwnode_properties(struct v4l2_ctrl_handler *hdl, + const struct v4l2_ctrl_ops *ctrl_ops, + const struct v4l2_fwnode_device_properties *p) +{ + if (p->orientation != V4L2_FWNODE_PROPERTY_UNSET) { + u32 orientation_ctrl; + + switch (p->orientation) { + case V4L2_FWNODE_ORIENTATION_FRONT: + orientation_ctrl = V4L2_CAMERA_ORIENTATION_FRONT; + break; + case V4L2_FWNODE_ORIENTATION_BACK: + orientation_ctrl = V4L2_CAMERA_ORIENTATION_BACK; + break; + case V4L2_FWNODE_ORIENTATION_EXTERNAL: + orientation_ctrl = V4L2_CAMERA_ORIENTATION_EXTERNAL; + break; + default: + return -EINVAL; + } + if (!v4l2_ctrl_new_std_menu(hdl, ctrl_ops, + V4L2_CID_CAMERA_ORIENTATION, + V4L2_CAMERA_ORIENTATION_EXTERNAL, 0, + orientation_ctrl)) + return hdl->error; + } + + if (p->rotation != V4L2_FWNODE_PROPERTY_UNSET) { + if (!v4l2_ctrl_new_std(hdl, ctrl_ops, + V4L2_CID_CAMERA_SENSOR_ROTATION, + p->rotation, p->rotation, 1, + p->rotation)) + return hdl->error; + } + + return hdl->error; +} +EXPORT_SYMBOL(v4l2_ctrl_new_fwnode_properties); diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h index 224c10823bbf..f40e2cbb21d3 100644 --- a/include/media/v4l2-ctrls.h +++ b/include/media/v4l2-ctrls.h @@ -30,6 +30,7 @@ struct v4l2_ctrl; struct v4l2_ctrl_handler; struct v4l2_ctrl_helper; struct v4l2_fh; +struct v4l2_fwnode_device_properties; struct v4l2_subdev; struct v4l2_subscribed_event; struct video_device; @@ -1428,4 +1429,29 @@ int v4l2_ctrl_subdev_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh, */ int v4l2_ctrl_subdev_log_status(struct v4l2_subdev *sd); +/** + * v4l2_ctrl_new_fwnode_properties() - Register controls for the device + * properties + * + * @hdl: pointer to &struct v4l2_ctrl_handler to register controls on + * @ctrl_ops: pointer to &struct v4l2_ctrl_ops to register controls with + * @p: pointer to &struct v4l2_fwnode_device_properties + * + * This function registers controls associated to device properties, using the + * property values contained in @p parameter, if the property has been set to + * a value. + * + * Currently the following v4l2 controls are parsed and registered: + * - V4L2_CID_CAMERA_ORIENTATION + * - V4L2_CID_CAMERA_SENSOR_ROTATION; + * + * Controls already registered by the caller with the @hdl control handler are + * not overwritten. Callers should register the controls they want to handle + * themselves before calling this function. + * + * Return: 0 on success, a negative error code on failure. + */ +int v4l2_ctrl_new_fwnode_properties(struct v4l2_ctrl_handler *hdl, + const struct v4l2_ctrl_ops *ctrl_ops, + const struct v4l2_fwnode_device_properties *p); #endif -- cgit v1.2.3-59-g8ed1b From 528b1a1ab244d9fc130f8f3899b79cea8bd760dc Mon Sep 17 00:00:00 2001 From: Dirk Nehring Date: Mon, 11 May 2020 10:29:53 +0200 Subject: media: dvb-usb: Add Cinergy S2 PCIe Dual Port support Terratec Cinergy S2 PCIe Dual is a PCIe device with two tuners that actually contains two USB devices. The devices are visible in the lsusb printout. Bus 004 Device 002: ID 153b:1182 TerraTec Electronic GmbH Cinergy S2 PCIe Dual Port 2 Bus 003 Device 002: ID 153b:1181 TerraTec Electronic GmbH Cinergy S2 PCIe Dual Port 1 The devices use the Montage M88DS3000/M88TS2022 demod/tuner. Signed-off-by: Dirk Nehring Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb/dw2102.c | 25 +++++++++++++++++++++---- include/media/dvb-usb-ids.h | 3 +++ 2 files changed, 24 insertions(+), 4 deletions(-) (limited to 'include/media') diff --git a/drivers/media/usb/dvb-usb/dw2102.c b/drivers/media/usb/dvb-usb/dw2102.c index f6d2d2398db6..f96626fe2c0b 100644 --- a/drivers/media/usb/dvb-usb/dw2102.c +++ b/drivers/media/usb/dvb-usb/dw2102.c @@ -1779,6 +1779,8 @@ enum dw2102_table_entry { TERRATEC_CINERGY_S2_R2, TERRATEC_CINERGY_S2_R3, TERRATEC_CINERGY_S2_R4, + TERRATEC_CINERGY_S2_1, + TERRATEC_CINERGY_S2_2, GOTVIEW_SAT_HD, GENIATECH_T220, TECHNOTREND_S2_4600, @@ -1806,9 +1808,16 @@ static struct usb_device_id dw2102_table[] = { [X3M_SPC1400HD] = {USB_DEVICE(0x1f4d, 0x3100)}, [TEVII_S421] = {USB_DEVICE(0x9022, USB_PID_TEVII_S421)}, [TEVII_S632] = {USB_DEVICE(0x9022, USB_PID_TEVII_S632)}, - [TERRATEC_CINERGY_S2_R2] = {USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_S2_R2)}, - [TERRATEC_CINERGY_S2_R3] = {USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_S2_R3)}, - [TERRATEC_CINERGY_S2_R4] = {USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_S2_R4)}, + [TERRATEC_CINERGY_S2_R2] = {USB_DEVICE(USB_VID_TERRATEC, + USB_PID_TERRATEC_CINERGY_S2_R2)}, + [TERRATEC_CINERGY_S2_R3] = {USB_DEVICE(USB_VID_TERRATEC, + USB_PID_TERRATEC_CINERGY_S2_R3)}, + [TERRATEC_CINERGY_S2_R4] = {USB_DEVICE(USB_VID_TERRATEC, + USB_PID_TERRATEC_CINERGY_S2_R4)}, + [TERRATEC_CINERGY_S2_1] = {USB_DEVICE(USB_VID_TERRATEC_2, + USB_PID_TERRATEC_CINERGY_S2_1)}, + [TERRATEC_CINERGY_S2_2] = {USB_DEVICE(USB_VID_TERRATEC_2, + USB_PID_TERRATEC_CINERGY_S2_2)}, [GOTVIEW_SAT_HD] = {USB_DEVICE(0x1FE1, USB_PID_GOTVIEW_SAT_HD)}, [GENIATECH_T220] = {USB_DEVICE(0x1f4d, 0xD220)}, [TECHNOTREND_S2_4600] = {USB_DEVICE(USB_VID_TECHNOTREND, @@ -2221,7 +2230,7 @@ static struct dvb_usb_device_properties su3000_properties = { }}, } }, - .num_device_descs = 6, + .num_device_descs = 8, .devices = { { "SU3000HD DVB-S USB2.0", { &dw2102_table[GENIATECH_SU3000], NULL }, @@ -2243,6 +2252,14 @@ static struct dvb_usb_device_properties su3000_properties = { { &dw2102_table[TERRATEC_CINERGY_S2_R3], NULL }, { NULL }, }, + { "Terratec Cinergy S2 PCIe Dual Port 1", + { &dw2102_table[TERRATEC_CINERGY_S2_1], NULL }, + { NULL }, + }, + { "Terratec Cinergy S2 PCIe Dual Port 2", + { &dw2102_table[TERRATEC_CINERGY_S2_2], NULL }, + { NULL }, + }, { "GOTVIEW Satellite HD", { &dw2102_table[GOTVIEW_SAT_HD], NULL }, { NULL }, diff --git a/include/media/dvb-usb-ids.h b/include/media/dvb-usb-ids.h index 41f0bf122f53..d37cb74b769c 100644 --- a/include/media/dvb-usb-ids.h +++ b/include/media/dvb-usb-ids.h @@ -56,6 +56,7 @@ #define USB_VID_REALTEK 0x0bda #define USB_VID_TECHNOTREND 0x0b48 #define USB_VID_TERRATEC 0x0ccd +#define USB_VID_TERRATEC_2 0x153b #define USB_VID_TELESTAR 0x10b9 #define USB_VID_VISIONPLUS 0x13d3 #define USB_VID_SONY 0x1415 @@ -280,6 +281,8 @@ #define USB_PID_TERRATEC_CINERGY_S2_R2 0x00b0 #define USB_PID_TERRATEC_CINERGY_S2_R3 0x0102 #define USB_PID_TERRATEC_CINERGY_S2_R4 0x0105 +#define USB_PID_TERRATEC_CINERGY_S2_1 0x1181 +#define USB_PID_TERRATEC_CINERGY_S2_2 0x1182 #define USB_PID_TERRATEC_H7 0x10b4 #define USB_PID_TERRATEC_H7_2 0x10a3 #define USB_PID_TERRATEC_H7_3 0x10a5 -- cgit v1.2.3-59-g8ed1b