From d9d6e1f3d5bbca799910072b2110963250e0b9c6 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 24 Mar 2020 10:00:38 +0100 Subject: media: dvb-usb: auto-select CYPRESS_FIRMWARE At least some of the supported boards by dvb-usb driver need to load the cypress firmware, so select it, as otherwise missing dependencies may popup. Also, as the cypress firmware load routines are needed only by the dvb-usb, dvb-usb-v2 and go7007 drivers, and those all (now) select it, there's no need to ask the user for manually select it. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/Kconfig | 2 +- drivers/media/usb/dvb-usb/Kconfig | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/common/Kconfig b/drivers/media/common/Kconfig index 1990b7f09454..4ea03b7899a8 100644 --- a/drivers/media/common/Kconfig +++ b/drivers/media/common/Kconfig @@ -14,7 +14,7 @@ config VIDEO_TVEEPROM depends on I2C config CYPRESS_FIRMWARE - tristate "Cypress firmware helper routines" + tristate depends on USB source "drivers/media/common/videobuf2/Kconfig" diff --git a/drivers/media/usb/dvb-usb/Kconfig b/drivers/media/usb/dvb-usb/Kconfig index 1a3e5f965ae4..42334a02cdce 100644 --- a/drivers/media/usb/dvb-usb/Kconfig +++ b/drivers/media/usb/dvb-usb/Kconfig @@ -2,6 +2,7 @@ config DVB_USB tristate "Support for various USB DVB devices" depends on DVB_CORE && USB && I2C && RC_CORE + select CYPRESS_FIRMWARE help By enabling this you will be able to choose the various supported USB1.1 and USB2.0 DVB devices. -- cgit v1.2.3 From 06b93644f4d102bdfc297159121acc1de794d68d Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 24 Mar 2020 10:27:15 +0100 Subject: media: Kconfig: add an option to filter in/out platform drivers Most systems don't need support for those, while others only need those, instead of the others. So, add an option to filter in/out platform drivers. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/Kconfig | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index 9dfea5c4b6ab..2b6ea8beb919 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -87,6 +87,18 @@ config MEDIA_CEC_SUPPORT Say Y when you have an HDMI receiver, transmitter or a USB CEC adapter that supports HDMI CEC. +config MEDIA_PLATFORM_SUPPORT + bool "Platform-specific devices support" + help + Enable support for complex cameras, codecs, and other hardware + that are integrated at the CPU, GPU or on Image Signalling Processor + and don't use PCI, USB or Firewire buses. + + This is found on Embedded hardware (SoC), on V4L2 codecs and + on some GPU and newer CPU chipsets. + + Say Y when you want to be able so see such devices. + source "drivers/media/cec/Kconfig" source "drivers/media/mc/Kconfig" @@ -161,15 +173,14 @@ source "drivers/media/dvb-core/Kconfig" comment "Media drivers" -# -# V4L platform/mem2mem drivers -# - source "drivers/media/usb/Kconfig" source "drivers/media/pci/Kconfig" +source "drivers/media/radio/Kconfig" + +if MEDIA_PLATFORM_SUPPORT source "drivers/media/platform/Kconfig" source "drivers/media/mmc/Kconfig" -source "drivers/media/radio/Kconfig" +endif comment "Supported FireWire (IEEE 1394) Adapters" depends on DVB_CORE && FIREWIRE -- cgit v1.2.3 From a19f228b8dd9a67e8de4ebd4eac8a4c94ec39d1a Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 24 Mar 2020 10:03:16 +0100 Subject: media: Kconfig: not all V4L2 platform drivers are for camera When the platform drivers got added, they were all part of complex camera support. This is not the case anymore, as we now have codecs and other stuff there too. So, fix the dependencies, in order to not require users to manually select something that it doesn't make sense. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/Kconfig | 3 +-- drivers/media/platform/Kconfig | 3 --- 2 files changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index 2b6ea8beb919..31fbdb2a8d41 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -111,8 +111,7 @@ source "drivers/media/mc/Kconfig" config VIDEO_DEV tristate depends on MEDIA_SUPPORT - depends on MEDIA_CAMERA_SUPPORT || MEDIA_ANALOG_TV_SUPPORT || MEDIA_RADIO_SUPPORT || MEDIA_SDR_SUPPORT - default y + default MEDIA_CAMERA_SUPPORT || MEDIA_ANALOG_TV_SUPPORT || MEDIA_RADIO_SUPPORT || MEDIA_SDR_SUPPORT || MEDIA_PLATFORM_SUPPORT config VIDEO_V4L2_SUBDEV_API bool "V4L2 sub-device userspace API" diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index e01bbb9dd1c1..c4178420d2c5 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -5,7 +5,6 @@ menuconfig V4L_PLATFORM_DRIVERS bool "V4L platform devices" - depends on MEDIA_CAMERA_SUPPORT help Say Y here to enable support for platform-specific V4L drivers. @@ -43,7 +42,6 @@ config VIDEO_ASPEED config VIDEO_SH_VOU tristate "SuperH VOU video output driver" - depends on MEDIA_CAMERA_SUPPORT depends on VIDEO_DEV && I2C depends on ARCH_SHMOBILE || COMPILE_TEST select VIDEOBUF2_DMA_CONTIG @@ -165,7 +163,6 @@ endif # V4L_PLATFORM_DRIVERS menuconfig V4L_MEM2MEM_DRIVERS bool "Memory-to-memory multimedia devices" depends on VIDEO_V4L2 - depends on MEDIA_CAMERA_SUPPORT help Say Y here to enable selecting drivers for V4L devices that use system memory for both source and destination buffers, as opposed -- cgit v1.2.3 From f11175daffad2c53e6e3ea020d0a6c3839a2fba7 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 24 Mar 2020 10:05:18 +0100 Subject: media: pci: move VIDEO_PCI_SKELETON to a different Kconfig The V4L2 PCI skeleton is not part of the V4L2 core. Move it to appear together with the other PCI drivers, at the end, as this is something that normal users don't even need to bother. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/Kconfig | 10 ++++++++++ drivers/media/v4l2-core/Kconfig | 10 ---------- 2 files changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/Kconfig b/drivers/media/pci/Kconfig index dcb3719f440e..9336f8446cf0 100644 --- a/drivers/media/pci/Kconfig +++ b/drivers/media/pci/Kconfig @@ -56,5 +56,15 @@ endif source "drivers/media/pci/intel/ipu3/Kconfig" +config VIDEO_PCI_SKELETON + tristate "Skeleton PCI V4L2 driver" + depends on PCI + depends on SAMPLES + depends on VIDEO_V4L2 && VIDEOBUF2_CORE + depends on VIDEOBUF2_MEMOPS && VIDEOBUF2_DMA_CONTIG + help + Enable build of the skeleton PCI driver, used as a reference + when developing new drivers. + endif #MEDIA_PCI_SUPPORT endif #PCI diff --git a/drivers/media/v4l2-core/Kconfig b/drivers/media/v4l2-core/Kconfig index 39e3fb30ba0b..26276b257eae 100644 --- a/drivers/media/v4l2-core/Kconfig +++ b/drivers/media/v4l2-core/Kconfig @@ -31,16 +31,6 @@ config VIDEO_FIXED_MINOR_RANGES When in doubt, say N. -config VIDEO_PCI_SKELETON - tristate "Skeleton PCI V4L2 driver" - depends on PCI - depends on SAMPLES - depends on VIDEO_V4L2 && VIDEOBUF2_CORE - depends on VIDEOBUF2_MEMOPS && VIDEOBUF2_DMA_CONTIG - help - Enable build of the skeleton PCI driver, used as a reference - when developing new drivers. - # Used by drivers that need tuner.ko config VIDEO_TUNER tristate -- cgit v1.2.3 From dee1877d9168f3e4b5e3c384d6d217dd1bbd4b49 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 24 Mar 2020 10:15:43 +0100 Subject: media: Kconfig: update the MEDIA_SUPPORT help message There are more things than just cameras and TV devices on media. Update the help message accordingly. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/Kconfig | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index 31fbdb2a8d41..72d4f3e0b081 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -18,8 +18,10 @@ menuconfig MEDIA_SUPPORT tristate "Multimedia support" depends on HAS_IOMEM help - If you want to use Webcams, Video grabber devices and/or TV devices - enable this option and other options below. + If you want to use media devices, including Webcams, Video grabber + devices and/or TV devices, V4L2 codecs, etc, enable this option + and other options below. + Additional info and docs are available on the web at -- cgit v1.2.3 From 4b32216adb010a364f23a055c45e06e839b089f9 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 24 Mar 2020 10:39:43 +0100 Subject: media: split test drivers from platform directory When the first test device was added (vivi.c), there were just one file. I was too lazy on that time to create a separate directory just for it, so I kept it together with platform. Now, we have vivid, vicodec, vim2m and vimc. Also, a new virtual driver has been prepared to support DVB API. So, it is time to solve this mess, by placing test stuff on a separate directory. It should be noticed that we also have some skeleton drivers (for V4L and for DVB). For now, we'll keep them separate, as they're not really test drivers, but instead, just examples. The DVB frontend ones will likely be part of a new DVB test driver. By that time, it should make sense to move them here as well. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/Kconfig | 14 + drivers/media/platform/Kconfig | 23 - drivers/media/platform/Makefile | 5 - drivers/media/platform/vicodec/Kconfig | 13 - drivers/media/platform/vicodec/Makefile | 4 - drivers/media/platform/vicodec/codec-fwht.c | 958 --------- drivers/media/platform/vicodec/codec-fwht.h | 150 -- drivers/media/platform/vicodec/codec-v4l2-fwht.c | 367 ---- drivers/media/platform/vicodec/codec-v4l2-fwht.h | 64 - drivers/media/platform/vicodec/vicodec-core.c | 2238 -------------------- drivers/media/platform/vim2m.c | 1441 ------------- drivers/media/platform/vimc/Kconfig | 15 - drivers/media/platform/vimc/Makefile | 6 - drivers/media/platform/vimc/vimc-capture.c | 480 ----- drivers/media/platform/vimc/vimc-common.c | 369 ---- drivers/media/platform/vimc/vimc-common.h | 224 -- drivers/media/platform/vimc/vimc-core.c | 381 ---- drivers/media/platform/vimc/vimc-debayer.c | 581 ----- drivers/media/platform/vimc/vimc-scaler.c | 511 ----- drivers/media/platform/vimc/vimc-sensor.c | 376 ---- drivers/media/platform/vimc/vimc-streamer.c | 238 --- drivers/media/platform/vimc/vimc-streamer.h | 44 - drivers/media/platform/vivid/Kconfig | 41 - drivers/media/platform/vivid/Makefile | 12 - drivers/media/platform/vivid/vivid-cec.c | 286 --- drivers/media/platform/vivid/vivid-cec.h | 20 - drivers/media/platform/vivid/vivid-core.c | 2006 ------------------ drivers/media/platform/vivid/vivid-core.h | 612 ------ drivers/media/platform/vivid/vivid-ctrls.c | 1939 ----------------- drivers/media/platform/vivid/vivid-ctrls.h | 22 - drivers/media/platform/vivid/vivid-kthread-cap.c | 1007 --------- drivers/media/platform/vivid/vivid-kthread-cap.h | 14 - drivers/media/platform/vivid/vivid-kthread-out.c | 353 --- drivers/media/platform/vivid/vivid-kthread-out.h | 14 - drivers/media/platform/vivid/vivid-kthread-touch.c | 181 -- drivers/media/platform/vivid/vivid-kthread-touch.h | 13 - drivers/media/platform/vivid/vivid-meta-cap.c | 201 -- drivers/media/platform/vivid/vivid-meta-cap.h | 29 - drivers/media/platform/vivid/vivid-meta-out.c | 174 -- drivers/media/platform/vivid/vivid-meta-out.h | 25 - drivers/media/platform/vivid/vivid-osd.c | 388 ---- drivers/media/platform/vivid/vivid-osd.h | 15 - drivers/media/platform/vivid/vivid-radio-common.c | 177 -- drivers/media/platform/vivid/vivid-radio-common.h | 28 - drivers/media/platform/vivid/vivid-radio-rx.c | 278 --- drivers/media/platform/vivid/vivid-radio-rx.h | 19 - drivers/media/platform/vivid/vivid-radio-tx.c | 128 -- drivers/media/platform/vivid/vivid-radio-tx.h | 17 - drivers/media/platform/vivid/vivid-rds-gen.c | 157 -- drivers/media/platform/vivid/vivid-rds-gen.h | 42 - drivers/media/platform/vivid/vivid-sdr-cap.c | 570 ----- drivers/media/platform/vivid/vivid-sdr-cap.h | 24 - drivers/media/platform/vivid/vivid-touch-cap.c | 341 --- drivers/media/platform/vivid/vivid-touch-cap.h | 39 - drivers/media/platform/vivid/vivid-vbi-cap.c | 365 ---- drivers/media/platform/vivid/vivid-vbi-cap.h | 28 - drivers/media/platform/vivid/vivid-vbi-gen.c | 311 --- drivers/media/platform/vivid/vivid-vbi-gen.h | 21 - drivers/media/platform/vivid/vivid-vbi-out.c | 250 --- drivers/media/platform/vivid/vivid-vbi-out.h | 22 - drivers/media/platform/vivid/vivid-vid-cap.c | 1918 ----------------- drivers/media/platform/vivid/vivid-vid-cap.h | 59 - drivers/media/platform/vivid/vivid-vid-common.c | 1035 --------- drivers/media/platform/vivid/vivid-vid-common.h | 38 - drivers/media/platform/vivid/vivid-vid-out.c | 1210 ----------- drivers/media/platform/vivid/vivid-vid-out.h | 44 - drivers/media/test_drivers/Kconfig | 28 + drivers/media/test_drivers/Makefile | 9 + drivers/media/test_drivers/vicodec/Kconfig | 13 + drivers/media/test_drivers/vicodec/Makefile | 4 + drivers/media/test_drivers/vicodec/codec-fwht.c | 958 +++++++++ drivers/media/test_drivers/vicodec/codec-fwht.h | 150 ++ .../media/test_drivers/vicodec/codec-v4l2-fwht.c | 367 ++++ .../media/test_drivers/vicodec/codec-v4l2-fwht.h | 64 + drivers/media/test_drivers/vicodec/vicodec-core.c | 2238 ++++++++++++++++++++ drivers/media/test_drivers/vim2m.c | 1441 +++++++++++++ drivers/media/test_drivers/vimc/Kconfig | 15 + drivers/media/test_drivers/vimc/Makefile | 6 + drivers/media/test_drivers/vimc/vimc-capture.c | 480 +++++ drivers/media/test_drivers/vimc/vimc-common.c | 369 ++++ drivers/media/test_drivers/vimc/vimc-common.h | 224 ++ drivers/media/test_drivers/vimc/vimc-core.c | 381 ++++ drivers/media/test_drivers/vimc/vimc-debayer.c | 581 +++++ drivers/media/test_drivers/vimc/vimc-scaler.c | 511 +++++ drivers/media/test_drivers/vimc/vimc-sensor.c | 376 ++++ drivers/media/test_drivers/vimc/vimc-streamer.c | 238 +++ drivers/media/test_drivers/vimc/vimc-streamer.h | 44 + drivers/media/test_drivers/vivid/Kconfig | 41 + drivers/media/test_drivers/vivid/Makefile | 12 + drivers/media/test_drivers/vivid/vivid-cec.c | 286 +++ drivers/media/test_drivers/vivid/vivid-cec.h | 20 + drivers/media/test_drivers/vivid/vivid-core.c | 2006 ++++++++++++++++++ drivers/media/test_drivers/vivid/vivid-core.h | 612 ++++++ drivers/media/test_drivers/vivid/vivid-ctrls.c | 1939 +++++++++++++++++ drivers/media/test_drivers/vivid/vivid-ctrls.h | 22 + .../media/test_drivers/vivid/vivid-kthread-cap.c | 1007 +++++++++ .../media/test_drivers/vivid/vivid-kthread-cap.h | 14 + .../media/test_drivers/vivid/vivid-kthread-out.c | 353 +++ .../media/test_drivers/vivid/vivid-kthread-out.h | 14 + .../media/test_drivers/vivid/vivid-kthread-touch.c | 181 ++ .../media/test_drivers/vivid/vivid-kthread-touch.h | 13 + drivers/media/test_drivers/vivid/vivid-meta-cap.c | 201 ++ drivers/media/test_drivers/vivid/vivid-meta-cap.h | 29 + drivers/media/test_drivers/vivid/vivid-meta-out.c | 174 ++ drivers/media/test_drivers/vivid/vivid-meta-out.h | 25 + drivers/media/test_drivers/vivid/vivid-osd.c | 388 ++++ drivers/media/test_drivers/vivid/vivid-osd.h | 15 + .../media/test_drivers/vivid/vivid-radio-common.c | 177 ++ .../media/test_drivers/vivid/vivid-radio-common.h | 28 + drivers/media/test_drivers/vivid/vivid-radio-rx.c | 278 +++ drivers/media/test_drivers/vivid/vivid-radio-rx.h | 19 + drivers/media/test_drivers/vivid/vivid-radio-tx.c | 128 ++ drivers/media/test_drivers/vivid/vivid-radio-tx.h | 17 + drivers/media/test_drivers/vivid/vivid-rds-gen.c | 157 ++ drivers/media/test_drivers/vivid/vivid-rds-gen.h | 42 + drivers/media/test_drivers/vivid/vivid-sdr-cap.c | 570 +++++ drivers/media/test_drivers/vivid/vivid-sdr-cap.h | 24 + drivers/media/test_drivers/vivid/vivid-touch-cap.c | 341 +++ drivers/media/test_drivers/vivid/vivid-touch-cap.h | 39 + drivers/media/test_drivers/vivid/vivid-vbi-cap.c | 365 ++++ drivers/media/test_drivers/vivid/vivid-vbi-cap.h | 28 + drivers/media/test_drivers/vivid/vivid-vbi-gen.c | 311 +++ drivers/media/test_drivers/vivid/vivid-vbi-gen.h | 21 + drivers/media/test_drivers/vivid/vivid-vbi-out.c | 250 +++ drivers/media/test_drivers/vivid/vivid-vbi-out.h | 22 + drivers/media/test_drivers/vivid/vivid-vid-cap.c | 1918 +++++++++++++++++ drivers/media/test_drivers/vivid/vivid-vid-cap.h | 59 + .../media/test_drivers/vivid/vivid-vid-common.c | 1035 +++++++++ .../media/test_drivers/vivid/vivid-vid-common.h | 38 + drivers/media/test_drivers/vivid/vivid-vid-out.c | 1210 +++++++++++ drivers/media/test_drivers/vivid/vivid-vid-out.h | 44 + 131 files changed, 22984 insertions(+), 22961 deletions(-) delete mode 100644 drivers/media/platform/vicodec/Kconfig delete mode 100644 drivers/media/platform/vicodec/Makefile delete mode 100644 drivers/media/platform/vicodec/codec-fwht.c delete mode 100644 drivers/media/platform/vicodec/codec-fwht.h delete mode 100644 drivers/media/platform/vicodec/codec-v4l2-fwht.c delete mode 100644 drivers/media/platform/vicodec/codec-v4l2-fwht.h delete mode 100644 drivers/media/platform/vicodec/vicodec-core.c delete mode 100644 drivers/media/platform/vim2m.c delete mode 100644 drivers/media/platform/vimc/Kconfig delete mode 100644 drivers/media/platform/vimc/Makefile delete mode 100644 drivers/media/platform/vimc/vimc-capture.c delete mode 100644 drivers/media/platform/vimc/vimc-common.c delete mode 100644 drivers/media/platform/vimc/vimc-common.h delete mode 100644 drivers/media/platform/vimc/vimc-core.c delete mode 100644 drivers/media/platform/vimc/vimc-debayer.c delete mode 100644 drivers/media/platform/vimc/vimc-scaler.c delete mode 100644 drivers/media/platform/vimc/vimc-sensor.c delete mode 100644 drivers/media/platform/vimc/vimc-streamer.c delete mode 100644 drivers/media/platform/vimc/vimc-streamer.h delete mode 100644 drivers/media/platform/vivid/Kconfig delete mode 100644 drivers/media/platform/vivid/Makefile delete mode 100644 drivers/media/platform/vivid/vivid-cec.c delete mode 100644 drivers/media/platform/vivid/vivid-cec.h delete mode 100644 drivers/media/platform/vivid/vivid-core.c delete mode 100644 drivers/media/platform/vivid/vivid-core.h delete mode 100644 drivers/media/platform/vivid/vivid-ctrls.c delete mode 100644 drivers/media/platform/vivid/vivid-ctrls.h delete mode 100644 drivers/media/platform/vivid/vivid-kthread-cap.c delete mode 100644 drivers/media/platform/vivid/vivid-kthread-cap.h delete mode 100644 drivers/media/platform/vivid/vivid-kthread-out.c delete mode 100644 drivers/media/platform/vivid/vivid-kthread-out.h delete mode 100644 drivers/media/platform/vivid/vivid-kthread-touch.c delete mode 100644 drivers/media/platform/vivid/vivid-kthread-touch.h delete mode 100644 drivers/media/platform/vivid/vivid-meta-cap.c delete mode 100644 drivers/media/platform/vivid/vivid-meta-cap.h delete mode 100644 drivers/media/platform/vivid/vivid-meta-out.c delete mode 100644 drivers/media/platform/vivid/vivid-meta-out.h delete mode 100644 drivers/media/platform/vivid/vivid-osd.c delete mode 100644 drivers/media/platform/vivid/vivid-osd.h delete mode 100644 drivers/media/platform/vivid/vivid-radio-common.c delete mode 100644 drivers/media/platform/vivid/vivid-radio-common.h delete mode 100644 drivers/media/platform/vivid/vivid-radio-rx.c delete mode 100644 drivers/media/platform/vivid/vivid-radio-rx.h delete mode 100644 drivers/media/platform/vivid/vivid-radio-tx.c delete mode 100644 drivers/media/platform/vivid/vivid-radio-tx.h delete mode 100644 drivers/media/platform/vivid/vivid-rds-gen.c delete mode 100644 drivers/media/platform/vivid/vivid-rds-gen.h delete mode 100644 drivers/media/platform/vivid/vivid-sdr-cap.c delete mode 100644 drivers/media/platform/vivid/vivid-sdr-cap.h delete mode 100644 drivers/media/platform/vivid/vivid-touch-cap.c delete mode 100644 drivers/media/platform/vivid/vivid-touch-cap.h delete mode 100644 drivers/media/platform/vivid/vivid-vbi-cap.c delete mode 100644 drivers/media/platform/vivid/vivid-vbi-cap.h delete mode 100644 drivers/media/platform/vivid/vivid-vbi-gen.c delete mode 100644 drivers/media/platform/vivid/vivid-vbi-gen.h delete mode 100644 drivers/media/platform/vivid/vivid-vbi-out.c delete mode 100644 drivers/media/platform/vivid/vivid-vbi-out.h delete mode 100644 drivers/media/platform/vivid/vivid-vid-cap.c delete mode 100644 drivers/media/platform/vivid/vivid-vid-cap.h delete mode 100644 drivers/media/platform/vivid/vivid-vid-common.c delete mode 100644 drivers/media/platform/vivid/vivid-vid-common.h delete mode 100644 drivers/media/platform/vivid/vivid-vid-out.c delete mode 100644 drivers/media/platform/vivid/vivid-vid-out.h create mode 100644 drivers/media/test_drivers/Kconfig create mode 100644 drivers/media/test_drivers/Makefile create mode 100644 drivers/media/test_drivers/vicodec/Kconfig create mode 100644 drivers/media/test_drivers/vicodec/Makefile create mode 100644 drivers/media/test_drivers/vicodec/codec-fwht.c create mode 100644 drivers/media/test_drivers/vicodec/codec-fwht.h create mode 100644 drivers/media/test_drivers/vicodec/codec-v4l2-fwht.c create mode 100644 drivers/media/test_drivers/vicodec/codec-v4l2-fwht.h create mode 100644 drivers/media/test_drivers/vicodec/vicodec-core.c create mode 100644 drivers/media/test_drivers/vim2m.c create mode 100644 drivers/media/test_drivers/vimc/Kconfig create mode 100644 drivers/media/test_drivers/vimc/Makefile create mode 100644 drivers/media/test_drivers/vimc/vimc-capture.c create mode 100644 drivers/media/test_drivers/vimc/vimc-common.c create mode 100644 drivers/media/test_drivers/vimc/vimc-common.h create mode 100644 drivers/media/test_drivers/vimc/vimc-core.c create mode 100644 drivers/media/test_drivers/vimc/vimc-debayer.c create mode 100644 drivers/media/test_drivers/vimc/vimc-scaler.c create mode 100644 drivers/media/test_drivers/vimc/vimc-sensor.c create mode 100644 drivers/media/test_drivers/vimc/vimc-streamer.c create mode 100644 drivers/media/test_drivers/vimc/vimc-streamer.h create mode 100644 drivers/media/test_drivers/vivid/Kconfig create mode 100644 drivers/media/test_drivers/vivid/Makefile create mode 100644 drivers/media/test_drivers/vivid/vivid-cec.c create mode 100644 drivers/media/test_drivers/vivid/vivid-cec.h create mode 100644 drivers/media/test_drivers/vivid/vivid-core.c create mode 100644 drivers/media/test_drivers/vivid/vivid-core.h create mode 100644 drivers/media/test_drivers/vivid/vivid-ctrls.c create mode 100644 drivers/media/test_drivers/vivid/vivid-ctrls.h create mode 100644 drivers/media/test_drivers/vivid/vivid-kthread-cap.c create mode 100644 drivers/media/test_drivers/vivid/vivid-kthread-cap.h create mode 100644 drivers/media/test_drivers/vivid/vivid-kthread-out.c create mode 100644 drivers/media/test_drivers/vivid/vivid-kthread-out.h create mode 100644 drivers/media/test_drivers/vivid/vivid-kthread-touch.c create mode 100644 drivers/media/test_drivers/vivid/vivid-kthread-touch.h create mode 100644 drivers/media/test_drivers/vivid/vivid-meta-cap.c create mode 100644 drivers/media/test_drivers/vivid/vivid-meta-cap.h create mode 100644 drivers/media/test_drivers/vivid/vivid-meta-out.c create mode 100644 drivers/media/test_drivers/vivid/vivid-meta-out.h create mode 100644 drivers/media/test_drivers/vivid/vivid-osd.c create mode 100644 drivers/media/test_drivers/vivid/vivid-osd.h create mode 100644 drivers/media/test_drivers/vivid/vivid-radio-common.c create mode 100644 drivers/media/test_drivers/vivid/vivid-radio-common.h create mode 100644 drivers/media/test_drivers/vivid/vivid-radio-rx.c create mode 100644 drivers/media/test_drivers/vivid/vivid-radio-rx.h create mode 100644 drivers/media/test_drivers/vivid/vivid-radio-tx.c create mode 100644 drivers/media/test_drivers/vivid/vivid-radio-tx.h create mode 100644 drivers/media/test_drivers/vivid/vivid-rds-gen.c create mode 100644 drivers/media/test_drivers/vivid/vivid-rds-gen.h create mode 100644 drivers/media/test_drivers/vivid/vivid-sdr-cap.c create mode 100644 drivers/media/test_drivers/vivid/vivid-sdr-cap.h create mode 100644 drivers/media/test_drivers/vivid/vivid-touch-cap.c create mode 100644 drivers/media/test_drivers/vivid/vivid-touch-cap.h create mode 100644 drivers/media/test_drivers/vivid/vivid-vbi-cap.c create mode 100644 drivers/media/test_drivers/vivid/vivid-vbi-cap.h create mode 100644 drivers/media/test_drivers/vivid/vivid-vbi-gen.c create mode 100644 drivers/media/test_drivers/vivid/vivid-vbi-gen.h create mode 100644 drivers/media/test_drivers/vivid/vivid-vbi-out.c create mode 100644 drivers/media/test_drivers/vivid/vivid-vbi-out.h create mode 100644 drivers/media/test_drivers/vivid/vivid-vid-cap.c create mode 100644 drivers/media/test_drivers/vivid/vivid-vid-cap.h create mode 100644 drivers/media/test_drivers/vivid/vivid-vid-common.c create mode 100644 drivers/media/test_drivers/vivid/vivid-vid-common.h create mode 100644 drivers/media/test_drivers/vivid/vivid-vid-out.c create mode 100644 drivers/media/test_drivers/vivid/vivid-vid-out.h (limited to 'drivers/media') diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index 72d4f3e0b081..b35c980dcf56 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -101,6 +101,19 @@ config MEDIA_PLATFORM_SUPPORT Say Y when you want to be able so see such devices. +config MEDIA_TEST_SUPPORT + bool "Test drivers support" + help + Those drivers should not be used on production Kernels, but + can be useful on debug ones. It enables several dummy drivers + that simulate a real hardware. Very useful to test userspace + applications and to validate if the subsystem core is doesn't + have regressions. + + Say Y if you want to use some virtual test driver. + + In case of doubts, say N. + source "drivers/media/cec/Kconfig" source "drivers/media/mc/Kconfig" @@ -180,6 +193,7 @@ source "drivers/media/radio/Kconfig" if MEDIA_PLATFORM_SUPPORT source "drivers/media/platform/Kconfig" +source "drivers/media/test_drivers/Kconfig" source "drivers/media/mmc/Kconfig" endif diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index c4178420d2c5..80028337bf00 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -529,29 +529,6 @@ config VIDEO_TI_SC config VIDEO_TI_CSC tristate -menuconfig V4L_TEST_DRIVERS - bool "Media test drivers" - depends on MEDIA_CAMERA_SUPPORT - -if V4L_TEST_DRIVERS - -source "drivers/media/platform/vimc/Kconfig" - -source "drivers/media/platform/vivid/Kconfig" - -config VIDEO_VIM2M - tristate "Virtual Memory-to-Memory Driver" - depends on VIDEO_DEV && VIDEO_V4L2 - select VIDEOBUF2_VMALLOC - select V4L2_MEM2MEM_DEV - help - This is a virtual test device for the memory-to-memory driver - framework. - -source "drivers/media/platform/vicodec/Kconfig" - -endif #V4L_TEST_DRIVERS - menuconfig DVB_PLATFORM_DRIVERS bool "DVB platform devices" depends on MEDIA_DIGITAL_TV_SUPPORT diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile index d13db96e3015..a0194ef1211f 100644 --- a/drivers/media/platform/Makefile +++ b/drivers/media/platform/Makefile @@ -14,11 +14,6 @@ obj-$(CONFIG_VIDEO_PXA27x) += pxa_camera.o obj-$(CONFIG_VIDEO_VIU) += fsl-viu.o -obj-$(CONFIG_VIDEO_VIMC) += vimc/ -obj-$(CONFIG_VIDEO_VIVID) += vivid/ -obj-$(CONFIG_VIDEO_VIM2M) += vim2m.o -obj-$(CONFIG_VIDEO_VICODEC) += vicodec/ - obj-y += ti-vpe/ obj-$(CONFIG_VIDEO_MX2_EMMAPRP) += mx2_emmaprp.o diff --git a/drivers/media/platform/vicodec/Kconfig b/drivers/media/platform/vicodec/Kconfig deleted file mode 100644 index 89456665cb16..000000000000 --- a/drivers/media/platform/vicodec/Kconfig +++ /dev/null @@ -1,13 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -config VIDEO_VICODEC - tristate "Virtual Codec Driver" - depends on VIDEO_DEV && VIDEO_V4L2 - select VIDEOBUF2_VMALLOC - select V4L2_MEM2MEM_DEV - help - Driver for a Virtual Codec - - This driver can be compared to the vim2m driver for emulating - a video device node that exposes an emulated hardware codec. - - When in doubt, say N. diff --git a/drivers/media/platform/vicodec/Makefile b/drivers/media/platform/vicodec/Makefile deleted file mode 100644 index 01bf7e9308a6..000000000000 --- a/drivers/media/platform/vicodec/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -vicodec-objs := vicodec-core.o codec-fwht.o codec-v4l2-fwht.o - -obj-$(CONFIG_VIDEO_VICODEC) += vicodec.o diff --git a/drivers/media/platform/vicodec/codec-fwht.c b/drivers/media/platform/vicodec/codec-fwht.c deleted file mode 100644 index 31faf319e508..000000000000 --- a/drivers/media/platform/vicodec/codec-fwht.c +++ /dev/null @@ -1,958 +0,0 @@ -// SPDX-License-Identifier: LGPL-2.1+ -/* - * Copyright 2016 Tom aan de Wiel - * Copyright 2018 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * 8x8 Fast Walsh Hadamard Transform in sequency order based on the paper: - * - * A Recursive Algorithm for Sequency-Ordered Fast Walsh Transforms, - * R.D. Brown, 1977 - */ - -#include -#include -#include "codec-fwht.h" - -#define OVERFLOW_BIT BIT(14) - -/* - * Note: bit 0 of the header must always be 0. Otherwise it cannot - * be guaranteed that the magic 8 byte sequence (see below) can - * never occur in the rlc output. - */ -#define PFRAME_BIT BIT(15) -#define DUPS_MASK 0x1ffe - -#define PBLOCK 0 -#define IBLOCK 1 - -#define ALL_ZEROS 15 - -static const uint8_t zigzag[64] = { - 0, - 1, 8, - 2, 9, 16, - 3, 10, 17, 24, - 4, 11, 18, 25, 32, - 5, 12, 19, 26, 33, 40, - 6, 13, 20, 27, 34, 41, 48, - 7, 14, 21, 28, 35, 42, 49, 56, - 15, 22, 29, 36, 43, 50, 57, - 23, 30, 37, 44, 51, 58, - 31, 38, 45, 52, 59, - 39, 46, 53, 60, - 47, 54, 61, - 55, 62, - 63, -}; - -/* - * noinline_for_stack to work around - * https://bugs.llvm.org/show_bug.cgi?id=38809 - */ -static int noinline_for_stack -rlc(const s16 *in, __be16 *output, int blocktype) -{ - s16 block[8 * 8]; - s16 *wp = block; - int i = 0; - int x, y; - int ret = 0; - - /* read in block from framebuffer */ - int lastzero_run = 0; - int to_encode; - - for (y = 0; y < 8; y++) { - for (x = 0; x < 8; x++) { - *wp = in[x + y * 8]; - wp++; - } - } - - /* keep track of amount of trailing zeros */ - for (i = 63; i >= 0 && !block[zigzag[i]]; i--) - lastzero_run++; - - *output++ = (blocktype == PBLOCK ? htons(PFRAME_BIT) : 0); - ret++; - - to_encode = 8 * 8 - (lastzero_run > 14 ? lastzero_run : 0); - - i = 0; - while (i < to_encode) { - int cnt = 0; - int tmp; - - /* count leading zeros */ - while ((tmp = block[zigzag[i]]) == 0 && cnt < 14) { - cnt++; - i++; - if (i == to_encode) { - cnt--; - break; - } - } - /* 4 bits for run, 12 for coefficient (quantization by 4) */ - *output++ = htons((cnt | tmp << 4)); - i++; - ret++; - } - if (lastzero_run > 14) { - *output = htons(ALL_ZEROS | 0); - ret++; - } - - return ret; -} - -/* - * This function will worst-case increase rlc_in by 65*2 bytes: - * one s16 value for the header and 8 * 8 coefficients of type s16. - */ -static noinline_for_stack u16 -derlc(const __be16 **rlc_in, s16 *dwht_out, const __be16 *end_of_input) -{ - /* header */ - const __be16 *input = *rlc_in; - u16 stat; - int dec_count = 0; - s16 block[8 * 8 + 16]; - s16 *wp = block; - int i; - - if (input > end_of_input) - return OVERFLOW_BIT; - stat = ntohs(*input++); - - /* - * Now de-compress, it expands one byte to up to 15 bytes - * (or fills the remainder of the 64 bytes with zeroes if it - * is the last byte to expand). - * - * So block has to be 8 * 8 + 16 bytes, the '+ 16' is to - * allow for overflow if the incoming data was malformed. - */ - while (dec_count < 8 * 8) { - s16 in; - int length; - int coeff; - - if (input > end_of_input) - return OVERFLOW_BIT; - in = ntohs(*input++); - length = in & 0xf; - coeff = in >> 4; - - /* fill remainder with zeros */ - if (length == 15) { - for (i = 0; i < 64 - dec_count; i++) - *wp++ = 0; - break; - } - - for (i = 0; i < length; i++) - *wp++ = 0; - *wp++ = coeff; - dec_count += length + 1; - } - - wp = block; - - for (i = 0; i < 64; i++) { - int pos = zigzag[i]; - int y = pos / 8; - int x = pos % 8; - - dwht_out[x + y * 8] = *wp++; - } - *rlc_in = input; - return stat; -} - -static const int quant_table[] = { - 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 3, - 2, 2, 2, 2, 2, 2, 3, 6, - 2, 2, 2, 2, 2, 3, 6, 6, - 2, 2, 2, 2, 3, 6, 6, 6, - 2, 2, 2, 3, 6, 6, 6, 6, - 2, 2, 3, 6, 6, 6, 6, 8, -}; - -static const int quant_table_p[] = { - 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 6, - 3, 3, 3, 3, 3, 3, 6, 6, - 3, 3, 3, 3, 3, 6, 6, 9, - 3, 3, 3, 3, 6, 6, 9, 9, - 3, 3, 3, 6, 6, 9, 9, 10, -}; - -static void quantize_intra(s16 *coeff, s16 *de_coeff, u16 qp) -{ - const int *quant = quant_table; - int i, j; - - for (j = 0; j < 8; j++) { - for (i = 0; i < 8; i++, quant++, coeff++, de_coeff++) { - *coeff >>= *quant; - if (*coeff >= -qp && *coeff <= qp) - *coeff = *de_coeff = 0; - else - *de_coeff = *coeff << *quant; - } - } -} - -static void dequantize_intra(s16 *coeff) -{ - const int *quant = quant_table; - int i, j; - - for (j = 0; j < 8; j++) - for (i = 0; i < 8; i++, quant++, coeff++) - *coeff <<= *quant; -} - -static void quantize_inter(s16 *coeff, s16 *de_coeff, u16 qp) -{ - const int *quant = quant_table_p; - int i, j; - - for (j = 0; j < 8; j++) { - for (i = 0; i < 8; i++, quant++, coeff++, de_coeff++) { - *coeff >>= *quant; - if (*coeff >= -qp && *coeff <= qp) - *coeff = *de_coeff = 0; - else - *de_coeff = *coeff << *quant; - } - } -} - -static void dequantize_inter(s16 *coeff) -{ - const int *quant = quant_table_p; - int i, j; - - for (j = 0; j < 8; j++) - for (i = 0; i < 8; i++, quant++, coeff++) - *coeff <<= *quant; -} - -static void noinline_for_stack fwht(const u8 *block, s16 *output_block, - unsigned int stride, - unsigned int input_step, bool intra) -{ - /* we'll need more than 8 bits for the transformed coefficients */ - s32 workspace1[8], workspace2[8]; - const u8 *tmp = block; - s16 *out = output_block; - int add = intra ? 256 : 0; - unsigned int i; - - /* stage 1 */ - for (i = 0; i < 8; i++, tmp += stride, out += 8) { - switch (input_step) { - case 1: - workspace1[0] = tmp[0] + tmp[1] - add; - workspace1[1] = tmp[0] - tmp[1]; - - workspace1[2] = tmp[2] + tmp[3] - add; - workspace1[3] = tmp[2] - tmp[3]; - - workspace1[4] = tmp[4] + tmp[5] - add; - workspace1[5] = tmp[4] - tmp[5]; - - workspace1[6] = tmp[6] + tmp[7] - add; - workspace1[7] = tmp[6] - tmp[7]; - break; - case 2: - workspace1[0] = tmp[0] + tmp[2] - add; - workspace1[1] = tmp[0] - tmp[2]; - - workspace1[2] = tmp[4] + tmp[6] - add; - workspace1[3] = tmp[4] - tmp[6]; - - workspace1[4] = tmp[8] + tmp[10] - add; - workspace1[5] = tmp[8] - tmp[10]; - - workspace1[6] = tmp[12] + tmp[14] - add; - workspace1[7] = tmp[12] - tmp[14]; - break; - case 3: - workspace1[0] = tmp[0] + tmp[3] - add; - workspace1[1] = tmp[0] - tmp[3]; - - workspace1[2] = tmp[6] + tmp[9] - add; - workspace1[3] = tmp[6] - tmp[9]; - - workspace1[4] = tmp[12] + tmp[15] - add; - workspace1[5] = tmp[12] - tmp[15]; - - workspace1[6] = tmp[18] + tmp[21] - add; - workspace1[7] = tmp[18] - tmp[21]; - break; - default: - workspace1[0] = tmp[0] + tmp[4] - add; - workspace1[1] = tmp[0] - tmp[4]; - - workspace1[2] = tmp[8] + tmp[12] - add; - workspace1[3] = tmp[8] - tmp[12]; - - workspace1[4] = tmp[16] + tmp[20] - add; - workspace1[5] = tmp[16] - tmp[20]; - - workspace1[6] = tmp[24] + tmp[28] - add; - workspace1[7] = tmp[24] - tmp[28]; - break; - } - - /* stage 2 */ - workspace2[0] = workspace1[0] + workspace1[2]; - workspace2[1] = workspace1[0] - workspace1[2]; - workspace2[2] = workspace1[1] - workspace1[3]; - workspace2[3] = workspace1[1] + workspace1[3]; - - workspace2[4] = workspace1[4] + workspace1[6]; - workspace2[5] = workspace1[4] - workspace1[6]; - workspace2[6] = workspace1[5] - workspace1[7]; - workspace2[7] = workspace1[5] + workspace1[7]; - - /* stage 3 */ - out[0] = workspace2[0] + workspace2[4]; - out[1] = workspace2[0] - workspace2[4]; - out[2] = workspace2[1] - workspace2[5]; - out[3] = workspace2[1] + workspace2[5]; - out[4] = workspace2[2] + workspace2[6]; - out[5] = workspace2[2] - workspace2[6]; - out[6] = workspace2[3] - workspace2[7]; - out[7] = workspace2[3] + workspace2[7]; - } - - out = output_block; - - for (i = 0; i < 8; i++, out++) { - /* stage 1 */ - workspace1[0] = out[0] + out[1 * 8]; - workspace1[1] = out[0] - out[1 * 8]; - - workspace1[2] = out[2 * 8] + out[3 * 8]; - workspace1[3] = out[2 * 8] - out[3 * 8]; - - workspace1[4] = out[4 * 8] + out[5 * 8]; - workspace1[5] = out[4 * 8] - out[5 * 8]; - - workspace1[6] = out[6 * 8] + out[7 * 8]; - workspace1[7] = out[6 * 8] - out[7 * 8]; - - /* stage 2 */ - workspace2[0] = workspace1[0] + workspace1[2]; - workspace2[1] = workspace1[0] - workspace1[2]; - workspace2[2] = workspace1[1] - workspace1[3]; - workspace2[3] = workspace1[1] + workspace1[3]; - - workspace2[4] = workspace1[4] + workspace1[6]; - workspace2[5] = workspace1[4] - workspace1[6]; - workspace2[6] = workspace1[5] - workspace1[7]; - workspace2[7] = workspace1[5] + workspace1[7]; - /* stage 3 */ - out[0 * 8] = workspace2[0] + workspace2[4]; - out[1 * 8] = workspace2[0] - workspace2[4]; - out[2 * 8] = workspace2[1] - workspace2[5]; - out[3 * 8] = workspace2[1] + workspace2[5]; - out[4 * 8] = workspace2[2] + workspace2[6]; - out[5 * 8] = workspace2[2] - workspace2[6]; - out[6 * 8] = workspace2[3] - workspace2[7]; - out[7 * 8] = workspace2[3] + workspace2[7]; - } -} - -/* - * Not the nicest way of doing it, but P-blocks get twice the range of - * that of the I-blocks. Therefore we need a type bigger than 8 bits. - * Furthermore values can be negative... This is just a version that - * works with 16 signed data - */ -static void noinline_for_stack -fwht16(const s16 *block, s16 *output_block, int stride, int intra) -{ - /* we'll need more than 8 bits for the transformed coefficients */ - s32 workspace1[8], workspace2[8]; - const s16 *tmp = block; - s16 *out = output_block; - int i; - - for (i = 0; i < 8; i++, tmp += stride, out += 8) { - /* stage 1 */ - workspace1[0] = tmp[0] + tmp[1]; - workspace1[1] = tmp[0] - tmp[1]; - - workspace1[2] = tmp[2] + tmp[3]; - workspace1[3] = tmp[2] - tmp[3]; - - workspace1[4] = tmp[4] + tmp[5]; - workspace1[5] = tmp[4] - tmp[5]; - - workspace1[6] = tmp[6] + tmp[7]; - workspace1[7] = tmp[6] - tmp[7]; - - /* stage 2 */ - workspace2[0] = workspace1[0] + workspace1[2]; - workspace2[1] = workspace1[0] - workspace1[2]; - workspace2[2] = workspace1[1] - workspace1[3]; - workspace2[3] = workspace1[1] + workspace1[3]; - - workspace2[4] = workspace1[4] + workspace1[6]; - workspace2[5] = workspace1[4] - workspace1[6]; - workspace2[6] = workspace1[5] - workspace1[7]; - workspace2[7] = workspace1[5] + workspace1[7]; - - /* stage 3 */ - out[0] = workspace2[0] + workspace2[4]; - out[1] = workspace2[0] - workspace2[4]; - out[2] = workspace2[1] - workspace2[5]; - out[3] = workspace2[1] + workspace2[5]; - out[4] = workspace2[2] + workspace2[6]; - out[5] = workspace2[2] - workspace2[6]; - out[6] = workspace2[3] - workspace2[7]; - out[7] = workspace2[3] + workspace2[7]; - } - - out = output_block; - - for (i = 0; i < 8; i++, out++) { - /* stage 1 */ - workspace1[0] = out[0] + out[1*8]; - workspace1[1] = out[0] - out[1*8]; - - workspace1[2] = out[2*8] + out[3*8]; - workspace1[3] = out[2*8] - out[3*8]; - - workspace1[4] = out[4*8] + out[5*8]; - workspace1[5] = out[4*8] - out[5*8]; - - workspace1[6] = out[6*8] + out[7*8]; - workspace1[7] = out[6*8] - out[7*8]; - - /* stage 2 */ - workspace2[0] = workspace1[0] + workspace1[2]; - workspace2[1] = workspace1[0] - workspace1[2]; - workspace2[2] = workspace1[1] - workspace1[3]; - workspace2[3] = workspace1[1] + workspace1[3]; - - workspace2[4] = workspace1[4] + workspace1[6]; - workspace2[5] = workspace1[4] - workspace1[6]; - workspace2[6] = workspace1[5] - workspace1[7]; - workspace2[7] = workspace1[5] + workspace1[7]; - - /* stage 3 */ - out[0*8] = workspace2[0] + workspace2[4]; - out[1*8] = workspace2[0] - workspace2[4]; - out[2*8] = workspace2[1] - workspace2[5]; - out[3*8] = workspace2[1] + workspace2[5]; - out[4*8] = workspace2[2] + workspace2[6]; - out[5*8] = workspace2[2] - workspace2[6]; - out[6*8] = workspace2[3] - workspace2[7]; - out[7*8] = workspace2[3] + workspace2[7]; - } -} - -static noinline_for_stack void -ifwht(const s16 *block, s16 *output_block, int intra) -{ - /* - * we'll need more than 8 bits for the transformed coefficients - * use native unit of cpu - */ - int workspace1[8], workspace2[8]; - int inter = intra ? 0 : 1; - const s16 *tmp = block; - s16 *out = output_block; - int i; - - for (i = 0; i < 8; i++, tmp += 8, out += 8) { - /* stage 1 */ - workspace1[0] = tmp[0] + tmp[1]; - workspace1[1] = tmp[0] - tmp[1]; - - workspace1[2] = tmp[2] + tmp[3]; - workspace1[3] = tmp[2] - tmp[3]; - - workspace1[4] = tmp[4] + tmp[5]; - workspace1[5] = tmp[4] - tmp[5]; - - workspace1[6] = tmp[6] + tmp[7]; - workspace1[7] = tmp[6] - tmp[7]; - - /* stage 2 */ - workspace2[0] = workspace1[0] + workspace1[2]; - workspace2[1] = workspace1[0] - workspace1[2]; - workspace2[2] = workspace1[1] - workspace1[3]; - workspace2[3] = workspace1[1] + workspace1[3]; - - workspace2[4] = workspace1[4] + workspace1[6]; - workspace2[5] = workspace1[4] - workspace1[6]; - workspace2[6] = workspace1[5] - workspace1[7]; - workspace2[7] = workspace1[5] + workspace1[7]; - - /* stage 3 */ - out[0] = workspace2[0] + workspace2[4]; - out[1] = workspace2[0] - workspace2[4]; - out[2] = workspace2[1] - workspace2[5]; - out[3] = workspace2[1] + workspace2[5]; - out[4] = workspace2[2] + workspace2[6]; - out[5] = workspace2[2] - workspace2[6]; - out[6] = workspace2[3] - workspace2[7]; - out[7] = workspace2[3] + workspace2[7]; - } - - out = output_block; - - for (i = 0; i < 8; i++, out++) { - /* stage 1 */ - workspace1[0] = out[0] + out[1 * 8]; - workspace1[1] = out[0] - out[1 * 8]; - - workspace1[2] = out[2 * 8] + out[3 * 8]; - workspace1[3] = out[2 * 8] - out[3 * 8]; - - workspace1[4] = out[4 * 8] + out[5 * 8]; - workspace1[5] = out[4 * 8] - out[5 * 8]; - - workspace1[6] = out[6 * 8] + out[7 * 8]; - workspace1[7] = out[6 * 8] - out[7 * 8]; - - /* stage 2 */ - workspace2[0] = workspace1[0] + workspace1[2]; - workspace2[1] = workspace1[0] - workspace1[2]; - workspace2[2] = workspace1[1] - workspace1[3]; - workspace2[3] = workspace1[1] + workspace1[3]; - - workspace2[4] = workspace1[4] + workspace1[6]; - workspace2[5] = workspace1[4] - workspace1[6]; - workspace2[6] = workspace1[5] - workspace1[7]; - workspace2[7] = workspace1[5] + workspace1[7]; - - /* stage 3 */ - if (inter) { - int d; - - out[0 * 8] = workspace2[0] + workspace2[4]; - out[1 * 8] = workspace2[0] - workspace2[4]; - out[2 * 8] = workspace2[1] - workspace2[5]; - out[3 * 8] = workspace2[1] + workspace2[5]; - out[4 * 8] = workspace2[2] + workspace2[6]; - out[5 * 8] = workspace2[2] - workspace2[6]; - out[6 * 8] = workspace2[3] - workspace2[7]; - out[7 * 8] = workspace2[3] + workspace2[7]; - - for (d = 0; d < 8; d++) - out[8 * d] >>= 6; - } else { - int d; - - out[0 * 8] = workspace2[0] + workspace2[4]; - out[1 * 8] = workspace2[0] - workspace2[4]; - out[2 * 8] = workspace2[1] - workspace2[5]; - out[3 * 8] = workspace2[1] + workspace2[5]; - out[4 * 8] = workspace2[2] + workspace2[6]; - out[5 * 8] = workspace2[2] - workspace2[6]; - out[6 * 8] = workspace2[3] - workspace2[7]; - out[7 * 8] = workspace2[3] + workspace2[7]; - - for (d = 0; d < 8; d++) { - out[8 * d] >>= 6; - out[8 * d] += 128; - } - } - } -} - -static void fill_encoder_block(const u8 *input, s16 *dst, - unsigned int stride, unsigned int input_step) -{ - int i, j; - - for (i = 0; i < 8; i++) { - for (j = 0; j < 8; j++, input += input_step) - *dst++ = *input; - input += stride - 8 * input_step; - } -} - -static int var_intra(const s16 *input) -{ - int32_t mean = 0; - int32_t ret = 0; - const s16 *tmp = input; - int i; - - for (i = 0; i < 8 * 8; i++, tmp++) - mean += *tmp; - mean /= 64; - tmp = input; - for (i = 0; i < 8 * 8; i++, tmp++) - ret += (*tmp - mean) < 0 ? -(*tmp - mean) : (*tmp - mean); - return ret; -} - -static int var_inter(const s16 *old, const s16 *new) -{ - int32_t ret = 0; - int i; - - for (i = 0; i < 8 * 8; i++, old++, new++) - ret += (*old - *new) < 0 ? -(*old - *new) : (*old - *new); - return ret; -} - -static noinline_for_stack int -decide_blocktype(const u8 *cur, const u8 *reference, s16 *deltablock, - unsigned int stride, unsigned int input_step) -{ - s16 tmp[64]; - s16 old[64]; - s16 *work = tmp; - unsigned int k, l; - int vari; - int vard; - - fill_encoder_block(cur, tmp, stride, input_step); - fill_encoder_block(reference, old, 8, 1); - vari = var_intra(tmp); - - for (k = 0; k < 8; k++) { - for (l = 0; l < 8; l++) { - *deltablock = *work - *reference; - deltablock++; - work++; - reference++; - } - } - deltablock -= 64; - vard = var_inter(old, tmp); - return vari <= vard ? IBLOCK : PBLOCK; -} - -static void fill_decoder_block(u8 *dst, const s16 *input, int stride, - unsigned int dst_step) -{ - int i, j; - - for (i = 0; i < 8; i++) { - for (j = 0; j < 8; j++, input++, dst += dst_step) { - if (*input < 0) - *dst = 0; - else if (*input > 255) - *dst = 255; - else - *dst = *input; - } - dst += stride - (8 * dst_step); - } -} - -static void add_deltas(s16 *deltas, const u8 *ref, int stride, - unsigned int ref_step) -{ - int k, l; - - for (k = 0; k < 8; k++) { - for (l = 0; l < 8; l++) { - *deltas += *ref; - ref += ref_step; - /* - * Due to quantizing, it might possible that the - * decoded coefficients are slightly out of range - */ - if (*deltas < 0) - *deltas = 0; - else if (*deltas > 255) - *deltas = 255; - deltas++; - } - ref += stride - (8 * ref_step); - } -} - -static u32 encode_plane(u8 *input, u8 *refp, __be16 **rlco, __be16 *rlco_max, - struct fwht_cframe *cf, u32 height, u32 width, - u32 stride, unsigned int input_step, - bool is_intra, bool next_is_intra) -{ - u8 *input_start = input; - __be16 *rlco_start = *rlco; - s16 deltablock[64]; - __be16 pframe_bit = htons(PFRAME_BIT); - u32 encoding = 0; - unsigned int last_size = 0; - unsigned int i, j; - - width = round_up(width, 8); - height = round_up(height, 8); - - for (j = 0; j < height / 8; j++) { - input = input_start + j * 8 * stride; - for (i = 0; i < width / 8; i++) { - /* intra code, first frame is always intra coded. */ - int blocktype = IBLOCK; - unsigned int size; - - if (!is_intra) - blocktype = decide_blocktype(input, refp, - deltablock, stride, input_step); - if (blocktype == IBLOCK) { - fwht(input, cf->coeffs, stride, input_step, 1); - quantize_intra(cf->coeffs, cf->de_coeffs, - cf->i_frame_qp); - } else { - /* inter code */ - encoding |= FWHT_FRAME_PCODED; - fwht16(deltablock, cf->coeffs, 8, 0); - quantize_inter(cf->coeffs, cf->de_coeffs, - cf->p_frame_qp); - } - if (!next_is_intra) { - ifwht(cf->de_coeffs, cf->de_fwht, blocktype); - - if (blocktype == PBLOCK) - add_deltas(cf->de_fwht, refp, 8, 1); - fill_decoder_block(refp, cf->de_fwht, 8, 1); - } - - input += 8 * input_step; - refp += 8 * 8; - - size = rlc(cf->coeffs, *rlco, blocktype); - if (last_size == size && - !memcmp(*rlco + 1, *rlco - size + 1, 2 * size - 2)) { - __be16 *last_rlco = *rlco - size; - s16 hdr = ntohs(*last_rlco); - - if (!((*last_rlco ^ **rlco) & pframe_bit) && - (hdr & DUPS_MASK) < DUPS_MASK) - *last_rlco = htons(hdr + 2); - else - *rlco += size; - } else { - *rlco += size; - } - if (*rlco >= rlco_max) { - encoding |= FWHT_FRAME_UNENCODED; - goto exit_loop; - } - last_size = size; - } - } - -exit_loop: - if (encoding & FWHT_FRAME_UNENCODED) { - u8 *out = (u8 *)rlco_start; - u8 *p; - - input = input_start; - /* - * The compressed stream should never contain the magic - * header, so when we copy the YUV data we replace 0xff - * by 0xfe. Since YUV is limited range such values - * shouldn't appear anyway. - */ - for (j = 0; j < height; j++) { - for (i = 0, p = input; i < width; i++, p += input_step) - *out++ = (*p == 0xff) ? 0xfe : *p; - input += stride; - } - *rlco = (__be16 *)out; - encoding &= ~FWHT_FRAME_PCODED; - } - return encoding; -} - -u32 fwht_encode_frame(struct fwht_raw_frame *frm, - struct fwht_raw_frame *ref_frm, - struct fwht_cframe *cf, - bool is_intra, bool next_is_intra, - unsigned int width, unsigned int height, - unsigned int stride, unsigned int chroma_stride) -{ - unsigned int size = height * width; - __be16 *rlco = cf->rlc_data; - __be16 *rlco_max; - u32 encoding; - - rlco_max = rlco + size / 2 - 256; - encoding = encode_plane(frm->luma, ref_frm->luma, &rlco, rlco_max, cf, - height, width, stride, - frm->luma_alpha_step, is_intra, next_is_intra); - if (encoding & FWHT_FRAME_UNENCODED) - encoding |= FWHT_LUMA_UNENCODED; - encoding &= ~FWHT_FRAME_UNENCODED; - - if (frm->components_num >= 3) { - u32 chroma_h = height / frm->height_div; - u32 chroma_w = width / frm->width_div; - unsigned int chroma_size = chroma_h * chroma_w; - - rlco_max = rlco + chroma_size / 2 - 256; - encoding |= encode_plane(frm->cb, ref_frm->cb, &rlco, rlco_max, - cf, chroma_h, chroma_w, - chroma_stride, frm->chroma_step, - is_intra, next_is_intra); - if (encoding & FWHT_FRAME_UNENCODED) - encoding |= FWHT_CB_UNENCODED; - encoding &= ~FWHT_FRAME_UNENCODED; - rlco_max = rlco + chroma_size / 2 - 256; - encoding |= encode_plane(frm->cr, ref_frm->cr, &rlco, rlco_max, - cf, chroma_h, chroma_w, - chroma_stride, frm->chroma_step, - is_intra, next_is_intra); - if (encoding & FWHT_FRAME_UNENCODED) - encoding |= FWHT_CR_UNENCODED; - encoding &= ~FWHT_FRAME_UNENCODED; - } - - if (frm->components_num == 4) { - rlco_max = rlco + size / 2 - 256; - encoding |= encode_plane(frm->alpha, ref_frm->alpha, &rlco, - rlco_max, cf, height, width, - stride, frm->luma_alpha_step, - is_intra, next_is_intra); - if (encoding & FWHT_FRAME_UNENCODED) - encoding |= FWHT_ALPHA_UNENCODED; - encoding &= ~FWHT_FRAME_UNENCODED; - } - - cf->size = (rlco - cf->rlc_data) * sizeof(*rlco); - return encoding; -} - -static bool decode_plane(struct fwht_cframe *cf, const __be16 **rlco, - u32 height, u32 width, const u8 *ref, u32 ref_stride, - unsigned int ref_step, u8 *dst, - unsigned int dst_stride, unsigned int dst_step, - bool uncompressed, const __be16 *end_of_rlco_buf) -{ - unsigned int copies = 0; - s16 copy[8 * 8]; - u16 stat; - unsigned int i, j; - bool is_intra = !ref; - - width = round_up(width, 8); - height = round_up(height, 8); - - if (uncompressed) { - int i; - - if (end_of_rlco_buf + 1 < *rlco + width * height / 2) - return false; - for (i = 0; i < height; i++) { - memcpy(dst, *rlco, width); - dst += dst_stride; - *rlco += width / 2; - } - return true; - } - - /* - * When decoding each macroblock the rlco pointer will be increased - * by 65 * 2 bytes worst-case. - * To avoid overflow the buffer has to be 65/64th of the actual raw - * image size, just in case someone feeds it malicious data. - */ - for (j = 0; j < height / 8; j++) { - for (i = 0; i < width / 8; i++) { - const u8 *refp = ref + j * 8 * ref_stride + - i * 8 * ref_step; - u8 *dstp = dst + j * 8 * dst_stride + i * 8 * dst_step; - - if (copies) { - memcpy(cf->de_fwht, copy, sizeof(copy)); - if ((stat & PFRAME_BIT) && !is_intra) - add_deltas(cf->de_fwht, refp, - ref_stride, ref_step); - fill_decoder_block(dstp, cf->de_fwht, - dst_stride, dst_step); - copies--; - continue; - } - - stat = derlc(rlco, cf->coeffs, end_of_rlco_buf); - if (stat & OVERFLOW_BIT) - return false; - if ((stat & PFRAME_BIT) && !is_intra) - dequantize_inter(cf->coeffs); - else - dequantize_intra(cf->coeffs); - - ifwht(cf->coeffs, cf->de_fwht, - ((stat & PFRAME_BIT) && !is_intra) ? 0 : 1); - - copies = (stat & DUPS_MASK) >> 1; - if (copies) - memcpy(copy, cf->de_fwht, sizeof(copy)); - if ((stat & PFRAME_BIT) && !is_intra) - add_deltas(cf->de_fwht, refp, - ref_stride, ref_step); - fill_decoder_block(dstp, cf->de_fwht, dst_stride, - dst_step); - } - } - return true; -} - -bool fwht_decode_frame(struct fwht_cframe *cf, u32 hdr_flags, - unsigned int components_num, unsigned int width, - unsigned int height, const struct fwht_raw_frame *ref, - unsigned int ref_stride, unsigned int ref_chroma_stride, - struct fwht_raw_frame *dst, unsigned int dst_stride, - unsigned int dst_chroma_stride) -{ - const __be16 *rlco = cf->rlc_data; - const __be16 *end_of_rlco_buf = cf->rlc_data + - (cf->size / sizeof(*rlco)) - 1; - - if (!decode_plane(cf, &rlco, height, width, ref->luma, ref_stride, - ref->luma_alpha_step, dst->luma, dst_stride, - dst->luma_alpha_step, - hdr_flags & FWHT_FL_LUMA_IS_UNCOMPRESSED, - end_of_rlco_buf)) - return false; - - if (components_num >= 3) { - u32 h = height; - u32 w = width; - - if (!(hdr_flags & FWHT_FL_CHROMA_FULL_HEIGHT)) - h /= 2; - if (!(hdr_flags & FWHT_FL_CHROMA_FULL_WIDTH)) - w /= 2; - - if (!decode_plane(cf, &rlco, h, w, ref->cb, ref_chroma_stride, - ref->chroma_step, dst->cb, dst_chroma_stride, - dst->chroma_step, - hdr_flags & FWHT_FL_CB_IS_UNCOMPRESSED, - end_of_rlco_buf)) - return false; - if (!decode_plane(cf, &rlco, h, w, ref->cr, ref_chroma_stride, - ref->chroma_step, dst->cr, dst_chroma_stride, - dst->chroma_step, - hdr_flags & FWHT_FL_CR_IS_UNCOMPRESSED, - end_of_rlco_buf)) - return false; - } - - if (components_num == 4) - if (!decode_plane(cf, &rlco, height, width, ref->alpha, ref_stride, - ref->luma_alpha_step, dst->alpha, dst_stride, - dst->luma_alpha_step, - hdr_flags & FWHT_FL_ALPHA_IS_UNCOMPRESSED, - end_of_rlco_buf)) - return false; - return true; -} diff --git a/drivers/media/platform/vicodec/codec-fwht.h b/drivers/media/platform/vicodec/codec-fwht.h deleted file mode 100644 index b6fec2b1cbca..000000000000 --- a/drivers/media/platform/vicodec/codec-fwht.h +++ /dev/null @@ -1,150 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ -/* - * Copyright 2016 Tom aan de Wiel - * Copyright 2018 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - */ - -#ifndef CODEC_FWHT_H -#define CODEC_FWHT_H - -#include -#include -#include - -/* - * The compressed format consists of a fwht_cframe_hdr struct followed by the - * compressed frame data. The header contains the size of that data. - * Each Y, Cb and Cr plane is compressed separately. If the compressed - * size of each plane becomes larger than the uncompressed size, then - * that plane is stored uncompressed and the corresponding bit is set - * in the flags field of the header. - * - * Each compressed plane consists of macroblocks and each macroblock - * is run-length-encoded. Each macroblock starts with a 16 bit value. - * Bit 15 indicates if this is a P-coded macroblock (1) or not (0). - * P-coded macroblocks contain a delta against the previous frame. - * - * Bits 1-12 contain a number. If non-zero, then this same macroblock - * repeats that number of times. This results in a high degree of - * compression for generated images like colorbars. - * - * Following this macroblock header the MB coefficients are run-length - * encoded: the top 12 bits contain the coefficient, the bottom 4 bits - * tell how many times this coefficient occurs. The value 0xf indicates - * that the remainder of the macroblock should be filled with zeroes. - * - * All 16 and 32 bit values are stored in big-endian (network) order. - * - * Each fwht_cframe_hdr starts with an 8 byte magic header that is - * guaranteed not to occur in the compressed frame data. This header - * can be used to sync to the next frame. - * - * This codec uses the Fast Walsh Hadamard Transform. Tom aan de Wiel - * developed this as part of a university project, specifically for use - * with this driver. His project report can be found here: - * - * https://hverkuil.home.xs4all.nl/fwht.pdf - */ - -/* - * This is a sequence of 8 bytes with the low 4 bits set to 0xf. - * - * This sequence cannot occur in the encoded data - * - * Note that these two magic values are symmetrical so endian issues here. - */ -#define FWHT_MAGIC1 0x4f4f4f4f -#define FWHT_MAGIC2 0xffffffff - -#define FWHT_VERSION 3 - -/* Set if this is an interlaced format */ -#define FWHT_FL_IS_INTERLACED BIT(0) -/* Set if this is a bottom-first (NTSC) interlaced format */ -#define FWHT_FL_IS_BOTTOM_FIRST BIT(1) -/* Set if each 'frame' contains just one field */ -#define FWHT_FL_IS_ALTERNATE BIT(2) -/* - * If FWHT_FL_IS_ALTERNATE was set, then this is set if this - * 'frame' is the bottom field, else it is the top field. - */ -#define FWHT_FL_IS_BOTTOM_FIELD BIT(3) -/* Set if this frame is uncompressed */ -#define FWHT_FL_LUMA_IS_UNCOMPRESSED BIT(4) -#define FWHT_FL_CB_IS_UNCOMPRESSED BIT(5) -#define FWHT_FL_CR_IS_UNCOMPRESSED BIT(6) -#define FWHT_FL_CHROMA_FULL_HEIGHT BIT(7) -#define FWHT_FL_CHROMA_FULL_WIDTH BIT(8) -#define FWHT_FL_ALPHA_IS_UNCOMPRESSED BIT(9) -#define FWHT_FL_I_FRAME BIT(10) - -/* A 4-values flag - the number of components - 1 */ -#define FWHT_FL_COMPONENTS_NUM_MSK GENMASK(18, 16) -#define FWHT_FL_COMPONENTS_NUM_OFFSET 16 - -#define FWHT_FL_PIXENC_MSK GENMASK(20, 19) -#define FWHT_FL_PIXENC_OFFSET 19 -#define FWHT_FL_PIXENC_YUV (1 << FWHT_FL_PIXENC_OFFSET) -#define FWHT_FL_PIXENC_RGB (2 << FWHT_FL_PIXENC_OFFSET) -#define FWHT_FL_PIXENC_HSV (3 << FWHT_FL_PIXENC_OFFSET) - -/* - * A macro to calculate the needed padding in order to make sure - * both luma and chroma components resolutions are rounded up to - * a multiple of 8 - */ -#define vic_round_dim(dim, div) (round_up((dim) / (div), 8) * (div)) - -struct fwht_cframe_hdr { - u32 magic1; - u32 magic2; - __be32 version; - __be32 width, height; - __be32 flags; - __be32 colorspace; - __be32 xfer_func; - __be32 ycbcr_enc; - __be32 quantization; - __be32 size; -}; - -struct fwht_cframe { - u16 i_frame_qp; - u16 p_frame_qp; - __be16 *rlc_data; - s16 coeffs[8 * 8]; - s16 de_coeffs[8 * 8]; - s16 de_fwht[8 * 8]; - u32 size; -}; - -struct fwht_raw_frame { - unsigned int width_div; - unsigned int height_div; - unsigned int luma_alpha_step; - unsigned int chroma_step; - unsigned int components_num; - u8 *buf; - u8 *luma, *cb, *cr, *alpha; -}; - -#define FWHT_FRAME_PCODED BIT(0) -#define FWHT_FRAME_UNENCODED BIT(1) -#define FWHT_LUMA_UNENCODED BIT(2) -#define FWHT_CB_UNENCODED BIT(3) -#define FWHT_CR_UNENCODED BIT(4) -#define FWHT_ALPHA_UNENCODED BIT(5) - -u32 fwht_encode_frame(struct fwht_raw_frame *frm, - struct fwht_raw_frame *ref_frm, - struct fwht_cframe *cf, - bool is_intra, bool next_is_intra, - unsigned int width, unsigned int height, - unsigned int stride, unsigned int chroma_stride); -bool fwht_decode_frame(struct fwht_cframe *cf, u32 hdr_flags, - unsigned int components_num, unsigned int width, - unsigned int height, const struct fwht_raw_frame *ref, - unsigned int ref_stride, unsigned int ref_chroma_stride, - struct fwht_raw_frame *dst, unsigned int dst_stride, - unsigned int dst_chroma_stride); -#endif diff --git a/drivers/media/platform/vicodec/codec-v4l2-fwht.c b/drivers/media/platform/vicodec/codec-v4l2-fwht.c deleted file mode 100644 index b6e39fbd8ad5..000000000000 --- a/drivers/media/platform/vicodec/codec-v4l2-fwht.c +++ /dev/null @@ -1,367 +0,0 @@ -// SPDX-License-Identifier: LGPL-2.1 -/* - * A V4L2 frontend for the FWHT codec - * - * Copyright 2018 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - */ - -#include -#include -#include -#include "codec-v4l2-fwht.h" - -static const struct v4l2_fwht_pixfmt_info v4l2_fwht_pixfmts[] = { - { V4L2_PIX_FMT_YUV420, 1, 3, 2, 1, 1, 2, 2, 3, 3, FWHT_FL_PIXENC_YUV}, - { V4L2_PIX_FMT_YVU420, 1, 3, 2, 1, 1, 2, 2, 3, 3, FWHT_FL_PIXENC_YUV}, - { V4L2_PIX_FMT_YUV422P, 1, 2, 1, 1, 1, 2, 1, 3, 3, FWHT_FL_PIXENC_YUV}, - { V4L2_PIX_FMT_NV12, 1, 3, 2, 1, 2, 2, 2, 3, 2, FWHT_FL_PIXENC_YUV}, - { V4L2_PIX_FMT_NV21, 1, 3, 2, 1, 2, 2, 2, 3, 2, FWHT_FL_PIXENC_YUV}, - { V4L2_PIX_FMT_NV16, 1, 2, 1, 1, 2, 2, 1, 3, 2, FWHT_FL_PIXENC_YUV}, - { V4L2_PIX_FMT_NV61, 1, 2, 1, 1, 2, 2, 1, 3, 2, FWHT_FL_PIXENC_YUV}, - { V4L2_PIX_FMT_NV24, 1, 3, 1, 1, 2, 1, 1, 3, 2, FWHT_FL_PIXENC_YUV}, - { V4L2_PIX_FMT_NV42, 1, 3, 1, 1, 2, 1, 1, 3, 2, FWHT_FL_PIXENC_YUV}, - { V4L2_PIX_FMT_YUYV, 2, 2, 1, 2, 4, 2, 1, 3, 1, FWHT_FL_PIXENC_YUV}, - { V4L2_PIX_FMT_YVYU, 2, 2, 1, 2, 4, 2, 1, 3, 1, FWHT_FL_PIXENC_YUV}, - { V4L2_PIX_FMT_UYVY, 2, 2, 1, 2, 4, 2, 1, 3, 1, FWHT_FL_PIXENC_YUV}, - { V4L2_PIX_FMT_VYUY, 2, 2, 1, 2, 4, 2, 1, 3, 1, FWHT_FL_PIXENC_YUV}, - { V4L2_PIX_FMT_BGR24, 3, 3, 1, 3, 3, 1, 1, 3, 1, FWHT_FL_PIXENC_RGB}, - { V4L2_PIX_FMT_RGB24, 3, 3, 1, 3, 3, 1, 1, 3, 1, FWHT_FL_PIXENC_RGB}, - { V4L2_PIX_FMT_HSV24, 3, 3, 1, 3, 3, 1, 1, 3, 1, FWHT_FL_PIXENC_HSV}, - { V4L2_PIX_FMT_BGR32, 4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB}, - { V4L2_PIX_FMT_XBGR32, 4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB}, - { V4L2_PIX_FMT_ABGR32, 4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB}, - { V4L2_PIX_FMT_RGB32, 4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB}, - { V4L2_PIX_FMT_XRGB32, 4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB}, - { V4L2_PIX_FMT_ARGB32, 4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB}, - { V4L2_PIX_FMT_BGRX32, 4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB}, - { V4L2_PIX_FMT_BGRA32, 4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB}, - { V4L2_PIX_FMT_RGBX32, 4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB}, - { V4L2_PIX_FMT_RGBA32, 4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB}, - { V4L2_PIX_FMT_HSV32, 4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_HSV}, - { V4L2_PIX_FMT_GREY, 1, 1, 1, 1, 0, 1, 1, 1, 1, FWHT_FL_PIXENC_RGB}, -}; - -bool v4l2_fwht_validate_fmt(const struct v4l2_fwht_pixfmt_info *info, - u32 width_div, u32 height_div, u32 components_num, - u32 pixenc) -{ - if (info->width_div == width_div && - info->height_div == height_div && - (!pixenc || info->pixenc == pixenc) && - info->components_num == components_num) - return true; - return false; -} - -const struct v4l2_fwht_pixfmt_info *v4l2_fwht_find_nth_fmt(u32 width_div, - u32 height_div, - u32 components_num, - u32 pixenc, - unsigned int start_idx) -{ - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(v4l2_fwht_pixfmts); i++) { - bool is_valid = v4l2_fwht_validate_fmt(&v4l2_fwht_pixfmts[i], - width_div, height_div, - components_num, pixenc); - if (is_valid) { - if (start_idx == 0) - return v4l2_fwht_pixfmts + i; - start_idx--; - } - } - return NULL; -} - -const struct v4l2_fwht_pixfmt_info *v4l2_fwht_find_pixfmt(u32 pixelformat) -{ - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(v4l2_fwht_pixfmts); i++) - if (v4l2_fwht_pixfmts[i].id == pixelformat) - return v4l2_fwht_pixfmts + i; - return NULL; -} - -const struct v4l2_fwht_pixfmt_info *v4l2_fwht_get_pixfmt(u32 idx) -{ - if (idx >= ARRAY_SIZE(v4l2_fwht_pixfmts)) - return NULL; - return v4l2_fwht_pixfmts + idx; -} - -static int prepare_raw_frame(struct fwht_raw_frame *rf, - const struct v4l2_fwht_pixfmt_info *info, u8 *buf, - unsigned int size) -{ - rf->luma = buf; - rf->width_div = info->width_div; - rf->height_div = info->height_div; - rf->luma_alpha_step = info->luma_alpha_step; - rf->chroma_step = info->chroma_step; - rf->alpha = NULL; - rf->components_num = info->components_num; - - /* - * The buffer is NULL if it is the reference - * frame of an I-frame in the stateless decoder - */ - if (!buf) { - rf->luma = NULL; - rf->cb = NULL; - rf->cr = NULL; - rf->alpha = NULL; - return 0; - } - switch (info->id) { - case V4L2_PIX_FMT_GREY: - rf->cb = NULL; - rf->cr = NULL; - break; - case V4L2_PIX_FMT_YUV420: - rf->cb = rf->luma + size; - rf->cr = rf->cb + size / 4; - break; - case V4L2_PIX_FMT_YVU420: - rf->cr = rf->luma + size; - rf->cb = rf->cr + size / 4; - break; - case V4L2_PIX_FMT_YUV422P: - rf->cb = rf->luma + size; - rf->cr = rf->cb + size / 2; - break; - case V4L2_PIX_FMT_NV12: - case V4L2_PIX_FMT_NV16: - case V4L2_PIX_FMT_NV24: - rf->cb = rf->luma + size; - rf->cr = rf->cb + 1; - break; - case V4L2_PIX_FMT_NV21: - case V4L2_PIX_FMT_NV61: - case V4L2_PIX_FMT_NV42: - rf->cr = rf->luma + size; - rf->cb = rf->cr + 1; - break; - case V4L2_PIX_FMT_YUYV: - rf->cb = rf->luma + 1; - rf->cr = rf->cb + 2; - break; - case V4L2_PIX_FMT_YVYU: - rf->cr = rf->luma + 1; - rf->cb = rf->cr + 2; - break; - case V4L2_PIX_FMT_UYVY: - rf->cb = rf->luma; - rf->cr = rf->cb + 2; - rf->luma++; - break; - case V4L2_PIX_FMT_VYUY: - rf->cr = rf->luma; - rf->cb = rf->cr + 2; - rf->luma++; - break; - case V4L2_PIX_FMT_RGB24: - case V4L2_PIX_FMT_HSV24: - rf->cr = rf->luma; - rf->cb = rf->cr + 2; - rf->luma++; - break; - case V4L2_PIX_FMT_BGR24: - rf->cb = rf->luma; - rf->cr = rf->cb + 2; - rf->luma++; - break; - case V4L2_PIX_FMT_RGB32: - case V4L2_PIX_FMT_XRGB32: - case V4L2_PIX_FMT_HSV32: - case V4L2_PIX_FMT_ARGB32: - rf->alpha = rf->luma; - rf->cr = rf->luma + 1; - rf->cb = rf->cr + 2; - rf->luma += 2; - break; - case V4L2_PIX_FMT_BGR32: - case V4L2_PIX_FMT_XBGR32: - case V4L2_PIX_FMT_ABGR32: - rf->cb = rf->luma; - rf->cr = rf->cb + 2; - rf->luma++; - rf->alpha = rf->cr + 1; - break; - case V4L2_PIX_FMT_BGRX32: - case V4L2_PIX_FMT_BGRA32: - rf->alpha = rf->luma; - rf->cb = rf->luma + 1; - rf->cr = rf->cb + 2; - rf->luma += 2; - break; - case V4L2_PIX_FMT_RGBX32: - case V4L2_PIX_FMT_RGBA32: - rf->alpha = rf->luma + 3; - rf->cr = rf->luma; - rf->cb = rf->cr + 2; - rf->luma++; - break; - default: - return -EINVAL; - } - return 0; -} - -int v4l2_fwht_encode(struct v4l2_fwht_state *state, u8 *p_in, u8 *p_out) -{ - unsigned int size = state->stride * state->coded_height; - unsigned int chroma_stride = state->stride; - const struct v4l2_fwht_pixfmt_info *info = state->info; - struct fwht_cframe_hdr *p_hdr; - struct fwht_cframe cf; - struct fwht_raw_frame rf; - u32 encoding; - u32 flags = 0; - - if (!info) - return -EINVAL; - - if (prepare_raw_frame(&rf, info, p_in, size)) - return -EINVAL; - - if (info->planes_num == 3) - chroma_stride /= 2; - - if (info->id == V4L2_PIX_FMT_NV24 || - info->id == V4L2_PIX_FMT_NV42) - chroma_stride *= 2; - - cf.i_frame_qp = state->i_frame_qp; - cf.p_frame_qp = state->p_frame_qp; - cf.rlc_data = (__be16 *)(p_out + sizeof(*p_hdr)); - - encoding = fwht_encode_frame(&rf, &state->ref_frame, &cf, - !state->gop_cnt, - state->gop_cnt == state->gop_size - 1, - state->visible_width, - state->visible_height, - state->stride, chroma_stride); - if (!(encoding & FWHT_FRAME_PCODED)) - state->gop_cnt = 0; - if (++state->gop_cnt >= state->gop_size) - state->gop_cnt = 0; - - p_hdr = (struct fwht_cframe_hdr *)p_out; - p_hdr->magic1 = FWHT_MAGIC1; - p_hdr->magic2 = FWHT_MAGIC2; - p_hdr->version = htonl(FWHT_VERSION); - p_hdr->width = htonl(state->visible_width); - p_hdr->height = htonl(state->visible_height); - flags |= (info->components_num - 1) << FWHT_FL_COMPONENTS_NUM_OFFSET; - flags |= info->pixenc; - if (encoding & FWHT_LUMA_UNENCODED) - flags |= FWHT_FL_LUMA_IS_UNCOMPRESSED; - if (encoding & FWHT_CB_UNENCODED) - flags |= FWHT_FL_CB_IS_UNCOMPRESSED; - if (encoding & FWHT_CR_UNENCODED) - flags |= FWHT_FL_CR_IS_UNCOMPRESSED; - if (encoding & FWHT_ALPHA_UNENCODED) - flags |= FWHT_FL_ALPHA_IS_UNCOMPRESSED; - if (!(encoding & FWHT_FRAME_PCODED)) - flags |= FWHT_FL_I_FRAME; - if (rf.height_div == 1) - flags |= FWHT_FL_CHROMA_FULL_HEIGHT; - if (rf.width_div == 1) - flags |= FWHT_FL_CHROMA_FULL_WIDTH; - p_hdr->flags = htonl(flags); - p_hdr->colorspace = htonl(state->colorspace); - p_hdr->xfer_func = htonl(state->xfer_func); - p_hdr->ycbcr_enc = htonl(state->ycbcr_enc); - p_hdr->quantization = htonl(state->quantization); - p_hdr->size = htonl(cf.size); - return cf.size + sizeof(*p_hdr); -} - -int v4l2_fwht_decode(struct v4l2_fwht_state *state, u8 *p_in, u8 *p_out) -{ - u32 flags; - struct fwht_cframe cf; - unsigned int components_num = 3; - unsigned int version; - const struct v4l2_fwht_pixfmt_info *info; - unsigned int hdr_width_div, hdr_height_div; - struct fwht_raw_frame dst_rf; - unsigned int dst_chroma_stride = state->stride; - unsigned int ref_chroma_stride = state->ref_stride; - unsigned int dst_size = state->stride * state->coded_height; - unsigned int ref_size; - - if (!state->info) - return -EINVAL; - - info = state->info; - - version = ntohl(state->header.version); - if (!version || version > FWHT_VERSION) { - pr_err("version %d is not supported, current version is %d\n", - version, FWHT_VERSION); - return -EINVAL; - } - - if (state->header.magic1 != FWHT_MAGIC1 || - state->header.magic2 != FWHT_MAGIC2) - return -EINVAL; - - /* TODO: support resolution changes */ - if (ntohl(state->header.width) != state->visible_width || - ntohl(state->header.height) != state->visible_height) - return -EINVAL; - - flags = ntohl(state->header.flags); - - if (version >= 2) { - if ((flags & FWHT_FL_PIXENC_MSK) != info->pixenc) - return -EINVAL; - components_num = 1 + ((flags & FWHT_FL_COMPONENTS_NUM_MSK) >> - FWHT_FL_COMPONENTS_NUM_OFFSET); - } - - if (components_num != info->components_num) - return -EINVAL; - - state->colorspace = ntohl(state->header.colorspace); - state->xfer_func = ntohl(state->header.xfer_func); - state->ycbcr_enc = ntohl(state->header.ycbcr_enc); - state->quantization = ntohl(state->header.quantization); - cf.rlc_data = (__be16 *)p_in; - cf.size = ntohl(state->header.size); - - hdr_width_div = (flags & FWHT_FL_CHROMA_FULL_WIDTH) ? 1 : 2; - hdr_height_div = (flags & FWHT_FL_CHROMA_FULL_HEIGHT) ? 1 : 2; - if (hdr_width_div != info->width_div || - hdr_height_div != info->height_div) - return -EINVAL; - - if (prepare_raw_frame(&dst_rf, info, p_out, dst_size)) - return -EINVAL; - if (info->planes_num == 3) { - dst_chroma_stride /= 2; - ref_chroma_stride /= 2; - } - if (info->id == V4L2_PIX_FMT_NV24 || - info->id == V4L2_PIX_FMT_NV42) { - dst_chroma_stride *= 2; - ref_chroma_stride *= 2; - } - - - ref_size = state->ref_stride * state->coded_height; - - if (prepare_raw_frame(&state->ref_frame, info, state->ref_frame.buf, - ref_size)) - return -EINVAL; - - if (!fwht_decode_frame(&cf, flags, components_num, - state->visible_width, state->visible_height, - &state->ref_frame, state->ref_stride, ref_chroma_stride, - &dst_rf, state->stride, dst_chroma_stride)) - return -EINVAL; - return 0; -} diff --git a/drivers/media/platform/vicodec/codec-v4l2-fwht.h b/drivers/media/platform/vicodec/codec-v4l2-fwht.h deleted file mode 100644 index 1a0d2a9f931a..000000000000 --- a/drivers/media/platform/vicodec/codec-v4l2-fwht.h +++ /dev/null @@ -1,64 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1 */ -/* - * Copyright 2018 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - */ - -#ifndef CODEC_V4L2_FWHT_H -#define CODEC_V4L2_FWHT_H - -#include "codec-fwht.h" - -struct v4l2_fwht_pixfmt_info { - u32 id; - unsigned int bytesperline_mult; - unsigned int sizeimage_mult; - unsigned int sizeimage_div; - unsigned int luma_alpha_step; - unsigned int chroma_step; - /* Chroma plane subsampling */ - unsigned int width_div; - unsigned int height_div; - unsigned int components_num; - unsigned int planes_num; - unsigned int pixenc; -}; - -struct v4l2_fwht_state { - const struct v4l2_fwht_pixfmt_info *info; - unsigned int visible_width; - unsigned int visible_height; - unsigned int coded_width; - unsigned int coded_height; - unsigned int stride; - unsigned int ref_stride; - unsigned int gop_size; - unsigned int gop_cnt; - u16 i_frame_qp; - u16 p_frame_qp; - - enum v4l2_colorspace colorspace; - enum v4l2_ycbcr_encoding ycbcr_enc; - enum v4l2_xfer_func xfer_func; - enum v4l2_quantization quantization; - - struct fwht_raw_frame ref_frame; - struct fwht_cframe_hdr header; - u8 *compressed_frame; - u64 ref_frame_ts; -}; - -const struct v4l2_fwht_pixfmt_info *v4l2_fwht_find_pixfmt(u32 pixelformat); -const struct v4l2_fwht_pixfmt_info *v4l2_fwht_get_pixfmt(u32 idx); -bool v4l2_fwht_validate_fmt(const struct v4l2_fwht_pixfmt_info *info, - u32 width_div, u32 height_div, u32 components_num, - u32 pixenc); -const struct v4l2_fwht_pixfmt_info *v4l2_fwht_find_nth_fmt(u32 width_div, - u32 height_div, - u32 components_num, - u32 pixenc, - unsigned int start_idx); - -int v4l2_fwht_encode(struct v4l2_fwht_state *state, u8 *p_in, u8 *p_out); -int v4l2_fwht_decode(struct v4l2_fwht_state *state, u8 *p_in, u8 *p_out); - -#endif diff --git a/drivers/media/platform/vicodec/vicodec-core.c b/drivers/media/platform/vicodec/vicodec-core.c deleted file mode 100644 index 30ced1c21387..000000000000 --- a/drivers/media/platform/vicodec/vicodec-core.c +++ /dev/null @@ -1,2238 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * A virtual codec example device. - * - * Copyright 2018 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This is a virtual codec device driver for testing the codec framework. - * It simulates a device that uses memory buffers for both source and - * destination and encodes or decodes the data. - */ - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "codec-v4l2-fwht.h" - -MODULE_DESCRIPTION("Virtual codec device"); -MODULE_AUTHOR("Hans Verkuil "); -MODULE_LICENSE("GPL v2"); - -static bool multiplanar; -module_param(multiplanar, bool, 0444); -MODULE_PARM_DESC(multiplanar, - " use multi-planar API instead of single-planar API"); - -static unsigned int debug; -module_param(debug, uint, 0644); -MODULE_PARM_DESC(debug, " activates debug info"); - -#define VICODEC_NAME "vicodec" -#define MAX_WIDTH 4096U -#define MIN_WIDTH 640U -#define MAX_HEIGHT 2160U -#define MIN_HEIGHT 360U - -#define dprintk(dev, fmt, arg...) \ - v4l2_dbg(1, debug, &dev->v4l2_dev, "%s: " fmt, __func__, ## arg) - - -struct pixfmt_info { - u32 id; - unsigned int bytesperline_mult; - unsigned int sizeimage_mult; - unsigned int sizeimage_div; - unsigned int luma_step; - unsigned int chroma_step; - /* Chroma plane subsampling */ - unsigned int width_div; - unsigned int height_div; -}; - -static const struct v4l2_fwht_pixfmt_info pixfmt_fwht = { - V4L2_PIX_FMT_FWHT, 0, 3, 1, 1, 1, 1, 1, 0, 1 -}; - -static const struct v4l2_fwht_pixfmt_info pixfmt_stateless_fwht = { - V4L2_PIX_FMT_FWHT_STATELESS, 0, 3, 1, 1, 1, 1, 1, 0, 1 -}; - -static void vicodec_dev_release(struct device *dev) -{ -} - -static struct platform_device vicodec_pdev = { - .name = VICODEC_NAME, - .dev.release = vicodec_dev_release, -}; - -/* Per-queue, driver-specific private data */ -struct vicodec_q_data { - unsigned int coded_width; - unsigned int coded_height; - unsigned int visible_width; - unsigned int visible_height; - unsigned int sizeimage; - unsigned int vb2_sizeimage; - unsigned int sequence; - const struct v4l2_fwht_pixfmt_info *info; -}; - -enum { - V4L2_M2M_SRC = 0, - V4L2_M2M_DST = 1, -}; - -struct vicodec_dev_instance { - struct video_device vfd; - struct mutex mutex; - spinlock_t lock; - struct v4l2_m2m_dev *m2m_dev; -}; - -struct vicodec_dev { - struct v4l2_device v4l2_dev; - struct vicodec_dev_instance stateful_enc; - struct vicodec_dev_instance stateful_dec; - struct vicodec_dev_instance stateless_dec; -#ifdef CONFIG_MEDIA_CONTROLLER - struct media_device mdev; -#endif - -}; - -struct vicodec_ctx { - struct v4l2_fh fh; - struct vicodec_dev *dev; - bool is_enc; - bool is_stateless; - spinlock_t *lock; - - struct v4l2_ctrl_handler hdl; - - /* Source and destination queue data */ - struct vicodec_q_data q_data[2]; - struct v4l2_fwht_state state; - - u32 cur_buf_offset; - u32 comp_max_size; - u32 comp_size; - u32 header_size; - u32 comp_magic_cnt; - bool comp_has_frame; - bool comp_has_next_frame; - bool first_source_change_sent; - bool source_changed; -}; - -static const struct v4l2_event vicodec_eos_event = { - .type = V4L2_EVENT_EOS -}; - -static inline struct vicodec_ctx *file2ctx(struct file *file) -{ - return container_of(file->private_data, struct vicodec_ctx, fh); -} - -static struct vicodec_q_data *get_q_data(struct vicodec_ctx *ctx, - enum v4l2_buf_type type) -{ - switch (type) { - case V4L2_BUF_TYPE_VIDEO_OUTPUT: - case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - return &ctx->q_data[V4L2_M2M_SRC]; - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - return &ctx->q_data[V4L2_M2M_DST]; - default: - break; - } - return NULL; -} - -static void copy_cap_to_ref(const u8 *cap, const struct v4l2_fwht_pixfmt_info *info, - struct v4l2_fwht_state *state) -{ - int plane_idx; - u8 *p_ref = state->ref_frame.buf; - unsigned int cap_stride = state->stride; - unsigned int ref_stride = state->ref_stride; - - for (plane_idx = 0; plane_idx < info->planes_num; plane_idx++) { - int i; - unsigned int h_div = (plane_idx == 1 || plane_idx == 2) ? - info->height_div : 1; - const u8 *row_cap = cap; - u8 *row_ref = p_ref; - - if (info->planes_num == 3 && plane_idx == 1) { - cap_stride /= 2; - ref_stride /= 2; - } - - if (plane_idx == 1 && - (info->id == V4L2_PIX_FMT_NV24 || - info->id == V4L2_PIX_FMT_NV42)) { - cap_stride *= 2; - ref_stride *= 2; - } - - for (i = 0; i < state->visible_height / h_div; i++) { - memcpy(row_ref, row_cap, ref_stride); - row_ref += ref_stride; - row_cap += cap_stride; - } - cap += cap_stride * (state->coded_height / h_div); - p_ref += ref_stride * (state->coded_height / h_div); - } -} - -static bool validate_by_version(unsigned int flags, unsigned int version) -{ - if (!version || version > FWHT_VERSION) - return false; - - if (version >= 2) { - unsigned int components_num = 1 + - ((flags & FWHT_FL_COMPONENTS_NUM_MSK) >> - FWHT_FL_COMPONENTS_NUM_OFFSET); - unsigned int pixenc = flags & FWHT_FL_PIXENC_MSK; - - if (components_num == 0 || components_num > 4 || !pixenc) - return false; - } - return true; -} - -static bool validate_stateless_params_flags(const struct v4l2_ctrl_fwht_params *params, - const struct v4l2_fwht_pixfmt_info *cur_info) -{ - unsigned int width_div = - (params->flags & FWHT_FL_CHROMA_FULL_WIDTH) ? 1 : 2; - unsigned int height_div = - (params->flags & FWHT_FL_CHROMA_FULL_HEIGHT) ? 1 : 2; - unsigned int components_num = 3; - unsigned int pixenc = 0; - - if (params->version < 3) - return false; - - components_num = 1 + ((params->flags & FWHT_FL_COMPONENTS_NUM_MSK) >> - FWHT_FL_COMPONENTS_NUM_OFFSET); - pixenc = (params->flags & FWHT_FL_PIXENC_MSK); - if (v4l2_fwht_validate_fmt(cur_info, width_div, height_div, - components_num, pixenc)) - return true; - return false; -} - - -static void update_state_from_header(struct vicodec_ctx *ctx) -{ - const struct fwht_cframe_hdr *p_hdr = &ctx->state.header; - - ctx->state.visible_width = ntohl(p_hdr->width); - ctx->state.visible_height = ntohl(p_hdr->height); - ctx->state.colorspace = ntohl(p_hdr->colorspace); - ctx->state.xfer_func = ntohl(p_hdr->xfer_func); - ctx->state.ycbcr_enc = ntohl(p_hdr->ycbcr_enc); - ctx->state.quantization = ntohl(p_hdr->quantization); -} - -static int device_process(struct vicodec_ctx *ctx, - struct vb2_v4l2_buffer *src_vb, - struct vb2_v4l2_buffer *dst_vb) -{ - struct vicodec_dev *dev = ctx->dev; - struct v4l2_fwht_state *state = &ctx->state; - u8 *p_src, *p_dst; - int ret = 0; - - if (ctx->is_enc || ctx->is_stateless) - p_src = vb2_plane_vaddr(&src_vb->vb2_buf, 0); - else - p_src = state->compressed_frame; - - if (ctx->is_stateless) { - struct media_request *src_req = src_vb->vb2_buf.req_obj.req; - - ret = v4l2_ctrl_request_setup(src_req, &ctx->hdl); - if (ret) - return ret; - update_state_from_header(ctx); - - ctx->state.header.size = - htonl(vb2_get_plane_payload(&src_vb->vb2_buf, 0)); - /* - * set the reference buffer from the reference timestamp - * only if this is a P-frame - */ - if (!(ntohl(ctx->state.header.flags) & FWHT_FL_I_FRAME)) { - struct vb2_buffer *ref_vb2_buf; - int ref_buf_idx; - struct vb2_queue *vq_cap = - v4l2_m2m_get_vq(ctx->fh.m2m_ctx, - V4L2_BUF_TYPE_VIDEO_CAPTURE); - - ref_buf_idx = vb2_find_timestamp(vq_cap, - ctx->state.ref_frame_ts, 0); - if (ref_buf_idx < 0) - return -EINVAL; - - ref_vb2_buf = vq_cap->bufs[ref_buf_idx]; - if (ref_vb2_buf->state == VB2_BUF_STATE_ERROR) - ret = -EINVAL; - ctx->state.ref_frame.buf = - vb2_plane_vaddr(ref_vb2_buf, 0); - } else { - ctx->state.ref_frame.buf = NULL; - } - } - p_dst = vb2_plane_vaddr(&dst_vb->vb2_buf, 0); - if (!p_src || !p_dst) { - v4l2_err(&dev->v4l2_dev, - "Acquiring kernel pointers to buffers failed\n"); - return -EFAULT; - } - - if (ctx->is_enc) { - struct vicodec_q_data *q_src; - int comp_sz_or_errcode; - - q_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); - state->info = q_src->info; - comp_sz_or_errcode = v4l2_fwht_encode(state, p_src, p_dst); - if (comp_sz_or_errcode < 0) - return comp_sz_or_errcode; - vb2_set_plane_payload(&dst_vb->vb2_buf, 0, comp_sz_or_errcode); - } else { - struct vicodec_q_data *q_dst; - unsigned int comp_frame_size = ntohl(ctx->state.header.size); - - q_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); - if (comp_frame_size > ctx->comp_max_size) - return -EINVAL; - state->info = q_dst->info; - ret = v4l2_fwht_decode(state, p_src, p_dst); - if (ret < 0) - return ret; - if (!ctx->is_stateless) - copy_cap_to_ref(p_dst, ctx->state.info, &ctx->state); - - vb2_set_plane_payload(&dst_vb->vb2_buf, 0, q_dst->sizeimage); - if (ntohl(ctx->state.header.flags) & FWHT_FL_I_FRAME) - dst_vb->flags |= V4L2_BUF_FLAG_KEYFRAME; - else - dst_vb->flags |= V4L2_BUF_FLAG_PFRAME; - } - return ret; -} - -/* - * mem2mem callbacks - */ -static enum vb2_buffer_state get_next_header(struct vicodec_ctx *ctx, - u8 **pp, u32 sz) -{ - static const u8 magic[] = { - 0x4f, 0x4f, 0x4f, 0x4f, 0xff, 0xff, 0xff, 0xff - }; - u8 *p = *pp; - u32 state; - u8 *header = (u8 *)&ctx->state.header; - - state = VB2_BUF_STATE_DONE; - - if (!ctx->header_size) { - state = VB2_BUF_STATE_ERROR; - for (; p < *pp + sz; p++) { - u32 copy; - - p = memchr(p, magic[ctx->comp_magic_cnt], - *pp + sz - p); - if (!p) { - ctx->comp_magic_cnt = 0; - p = *pp + sz; - break; - } - copy = sizeof(magic) - ctx->comp_magic_cnt; - if (*pp + sz - p < copy) - copy = *pp + sz - p; - - memcpy(header + ctx->comp_magic_cnt, p, copy); - ctx->comp_magic_cnt += copy; - if (!memcmp(header, magic, ctx->comp_magic_cnt)) { - p += copy; - state = VB2_BUF_STATE_DONE; - break; - } - ctx->comp_magic_cnt = 0; - } - if (ctx->comp_magic_cnt < sizeof(magic)) { - *pp = p; - return state; - } - ctx->header_size = sizeof(magic); - } - - if (ctx->header_size < sizeof(struct fwht_cframe_hdr)) { - u32 copy = sizeof(struct fwht_cframe_hdr) - ctx->header_size; - - if (*pp + sz - p < copy) - copy = *pp + sz - p; - - memcpy(header + ctx->header_size, p, copy); - p += copy; - ctx->header_size += copy; - } - *pp = p; - return state; -} - -/* device_run() - prepares and starts the device */ -static void device_run(void *priv) -{ - struct vicodec_ctx *ctx = priv; - struct vicodec_dev *dev = ctx->dev; - struct vb2_v4l2_buffer *src_buf, *dst_buf; - struct vicodec_q_data *q_src, *q_dst; - u32 state; - struct media_request *src_req; - - src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); - dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); - src_req = src_buf->vb2_buf.req_obj.req; - - q_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); - q_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); - - state = VB2_BUF_STATE_DONE; - if (device_process(ctx, src_buf, dst_buf)) - state = VB2_BUF_STATE_ERROR; - else - dst_buf->sequence = q_dst->sequence++; - dst_buf->flags &= ~V4L2_BUF_FLAG_LAST; - v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, false); - - spin_lock(ctx->lock); - if (!ctx->comp_has_next_frame && - v4l2_m2m_is_last_draining_src_buf(ctx->fh.m2m_ctx, src_buf)) { - dst_buf->flags |= V4L2_BUF_FLAG_LAST; - v4l2_event_queue_fh(&ctx->fh, &vicodec_eos_event); - v4l2_m2m_mark_stopped(ctx->fh.m2m_ctx); - } - if (ctx->is_enc || ctx->is_stateless) { - src_buf->sequence = q_src->sequence++; - src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); - v4l2_m2m_buf_done(src_buf, state); - } else if (vb2_get_plane_payload(&src_buf->vb2_buf, 0) == ctx->cur_buf_offset) { - src_buf->sequence = q_src->sequence++; - src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); - v4l2_m2m_buf_done(src_buf, state); - ctx->cur_buf_offset = 0; - ctx->comp_has_next_frame = false; - } - v4l2_m2m_buf_done(dst_buf, state); - - ctx->comp_size = 0; - ctx->header_size = 0; - ctx->comp_magic_cnt = 0; - ctx->comp_has_frame = false; - spin_unlock(ctx->lock); - if (ctx->is_stateless && src_req) - v4l2_ctrl_request_complete(src_req, &ctx->hdl); - - if (ctx->is_enc) - v4l2_m2m_job_finish(dev->stateful_enc.m2m_dev, ctx->fh.m2m_ctx); - else if (ctx->is_stateless) - v4l2_m2m_job_finish(dev->stateless_dec.m2m_dev, - ctx->fh.m2m_ctx); - else - v4l2_m2m_job_finish(dev->stateful_dec.m2m_dev, ctx->fh.m2m_ctx); -} - -static void job_remove_src_buf(struct vicodec_ctx *ctx, u32 state) -{ - struct vb2_v4l2_buffer *src_buf; - struct vicodec_q_data *q_src; - - q_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); - spin_lock(ctx->lock); - src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); - src_buf->sequence = q_src->sequence++; - v4l2_m2m_buf_done(src_buf, state); - ctx->cur_buf_offset = 0; - spin_unlock(ctx->lock); -} - -static const struct v4l2_fwht_pixfmt_info * -info_from_header(const struct fwht_cframe_hdr *p_hdr) -{ - unsigned int flags = ntohl(p_hdr->flags); - unsigned int width_div = (flags & FWHT_FL_CHROMA_FULL_WIDTH) ? 1 : 2; - unsigned int height_div = (flags & FWHT_FL_CHROMA_FULL_HEIGHT) ? 1 : 2; - unsigned int components_num = 3; - unsigned int pixenc = 0; - unsigned int version = ntohl(p_hdr->version); - - if (version >= 2) { - components_num = 1 + ((flags & FWHT_FL_COMPONENTS_NUM_MSK) >> - FWHT_FL_COMPONENTS_NUM_OFFSET); - pixenc = (flags & FWHT_FL_PIXENC_MSK); - } - return v4l2_fwht_find_nth_fmt(width_div, height_div, - components_num, pixenc, 0); -} - -static bool is_header_valid(const struct fwht_cframe_hdr *p_hdr) -{ - const struct v4l2_fwht_pixfmt_info *info; - unsigned int w = ntohl(p_hdr->width); - unsigned int h = ntohl(p_hdr->height); - unsigned int version = ntohl(p_hdr->version); - unsigned int flags = ntohl(p_hdr->flags); - - if (w < MIN_WIDTH || w > MAX_WIDTH || h < MIN_HEIGHT || h > MAX_HEIGHT) - return false; - - if (!validate_by_version(flags, version)) - return false; - - info = info_from_header(p_hdr); - if (!info) - return false; - return true; -} - -static void update_capture_data_from_header(struct vicodec_ctx *ctx) -{ - struct vicodec_q_data *q_dst = get_q_data(ctx, - V4L2_BUF_TYPE_VIDEO_CAPTURE); - const struct fwht_cframe_hdr *p_hdr = &ctx->state.header; - const struct v4l2_fwht_pixfmt_info *info = info_from_header(p_hdr); - unsigned int flags = ntohl(p_hdr->flags); - unsigned int hdr_width_div = (flags & FWHT_FL_CHROMA_FULL_WIDTH) ? 1 : 2; - unsigned int hdr_height_div = (flags & FWHT_FL_CHROMA_FULL_HEIGHT) ? 1 : 2; - - /* - * This function should not be used by a stateless codec since - * it changes values in q_data that are not request specific - */ - WARN_ON(ctx->is_stateless); - - q_dst->info = info; - q_dst->visible_width = ntohl(p_hdr->width); - q_dst->visible_height = ntohl(p_hdr->height); - q_dst->coded_width = vic_round_dim(q_dst->visible_width, hdr_width_div); - q_dst->coded_height = vic_round_dim(q_dst->visible_height, - hdr_height_div); - - q_dst->sizeimage = q_dst->coded_width * q_dst->coded_height * - q_dst->info->sizeimage_mult / q_dst->info->sizeimage_div; - ctx->state.colorspace = ntohl(p_hdr->colorspace); - - ctx->state.xfer_func = ntohl(p_hdr->xfer_func); - ctx->state.ycbcr_enc = ntohl(p_hdr->ycbcr_enc); - ctx->state.quantization = ntohl(p_hdr->quantization); -} - -static void set_last_buffer(struct vb2_v4l2_buffer *dst_buf, - const struct vb2_v4l2_buffer *src_buf, - struct vicodec_ctx *ctx) -{ - struct vicodec_q_data *q_dst = get_q_data(ctx, - V4L2_BUF_TYPE_VIDEO_CAPTURE); - - vb2_set_plane_payload(&dst_buf->vb2_buf, 0, 0); - dst_buf->sequence = q_dst->sequence++; - - v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, !ctx->is_enc); - dst_buf->flags |= V4L2_BUF_FLAG_LAST; - v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE); -} - -static int job_ready(void *priv) -{ - static const u8 magic[] = { - 0x4f, 0x4f, 0x4f, 0x4f, 0xff, 0xff, 0xff, 0xff - }; - struct vicodec_ctx *ctx = priv; - struct vb2_v4l2_buffer *src_buf; - u8 *p_src; - u8 *p; - u32 sz; - u32 state; - struct vicodec_q_data *q_dst = get_q_data(ctx, - V4L2_BUF_TYPE_VIDEO_CAPTURE); - unsigned int flags; - unsigned int hdr_width_div; - unsigned int hdr_height_div; - unsigned int max_to_copy; - unsigned int comp_frame_size; - - if (ctx->source_changed) - return 0; - if (ctx->is_stateless || ctx->is_enc || ctx->comp_has_frame) - return 1; - -restart: - ctx->comp_has_next_frame = false; - src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); - if (!src_buf) - return 0; - p_src = vb2_plane_vaddr(&src_buf->vb2_buf, 0); - sz = vb2_get_plane_payload(&src_buf->vb2_buf, 0); - p = p_src + ctx->cur_buf_offset; - - state = VB2_BUF_STATE_DONE; - - if (ctx->header_size < sizeof(struct fwht_cframe_hdr)) { - state = get_next_header(ctx, &p, p_src + sz - p); - if (ctx->header_size < sizeof(struct fwht_cframe_hdr)) { - if (v4l2_m2m_is_last_draining_src_buf(ctx->fh.m2m_ctx, - src_buf)) - return 1; - job_remove_src_buf(ctx, state); - goto restart; - } - } - - comp_frame_size = ntohl(ctx->state.header.size); - - /* - * The current scanned frame might be the first frame of a new - * resolution so its size might be larger than ctx->comp_max_size. - * In that case it is copied up to the current buffer capacity and - * the copy will continue after allocating new large enough buffer - * when restreaming - */ - max_to_copy = min(comp_frame_size, ctx->comp_max_size); - - if (ctx->comp_size < max_to_copy) { - u32 copy = max_to_copy - ctx->comp_size; - - if (copy > p_src + sz - p) - copy = p_src + sz - p; - - memcpy(ctx->state.compressed_frame + ctx->comp_size, - p, copy); - p += copy; - ctx->comp_size += copy; - if (ctx->comp_size < max_to_copy) { - if (v4l2_m2m_is_last_draining_src_buf(ctx->fh.m2m_ctx, - src_buf)) - return 1; - job_remove_src_buf(ctx, state); - goto restart; - } - } - ctx->cur_buf_offset = p - p_src; - if (ctx->comp_size == comp_frame_size) - ctx->comp_has_frame = true; - ctx->comp_has_next_frame = false; - if (ctx->comp_has_frame && sz - ctx->cur_buf_offset >= - sizeof(struct fwht_cframe_hdr)) { - struct fwht_cframe_hdr *p_hdr = (struct fwht_cframe_hdr *)p; - u32 frame_size = ntohl(p_hdr->size); - u32 remaining = sz - ctx->cur_buf_offset - sizeof(*p_hdr); - - if (!memcmp(p, magic, sizeof(magic))) - ctx->comp_has_next_frame = remaining >= frame_size; - } - /* - * if the header is invalid the device_run will just drop the frame - * with an error - */ - if (!is_header_valid(&ctx->state.header) && ctx->comp_has_frame) - return 1; - flags = ntohl(ctx->state.header.flags); - hdr_width_div = (flags & FWHT_FL_CHROMA_FULL_WIDTH) ? 1 : 2; - hdr_height_div = (flags & FWHT_FL_CHROMA_FULL_HEIGHT) ? 1 : 2; - - if (ntohl(ctx->state.header.width) != q_dst->visible_width || - ntohl(ctx->state.header.height) != q_dst->visible_height || - !q_dst->info || - hdr_width_div != q_dst->info->width_div || - hdr_height_div != q_dst->info->height_div) { - static const struct v4l2_event rs_event = { - .type = V4L2_EVENT_SOURCE_CHANGE, - .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION, - }; - - struct vb2_v4l2_buffer *dst_buf = - v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); - - update_capture_data_from_header(ctx); - v4l2_event_queue_fh(&ctx->fh, &rs_event); - set_last_buffer(dst_buf, src_buf, ctx); - ctx->source_changed = true; - return 0; - } - return 1; -} - -/* - * video ioctls - */ - -static const struct v4l2_fwht_pixfmt_info *find_fmt(u32 fmt) -{ - const struct v4l2_fwht_pixfmt_info *info = - v4l2_fwht_find_pixfmt(fmt); - - if (!info) - info = v4l2_fwht_get_pixfmt(0); - return info; -} - -static int vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - strscpy(cap->driver, VICODEC_NAME, sizeof(cap->driver)); - strscpy(cap->card, VICODEC_NAME, sizeof(cap->card)); - snprintf(cap->bus_info, sizeof(cap->bus_info), - "platform:%s", VICODEC_NAME); - return 0; -} - -static int enum_fmt(struct v4l2_fmtdesc *f, struct vicodec_ctx *ctx, - bool is_out) -{ - bool is_uncomp = (ctx->is_enc && is_out) || (!ctx->is_enc && !is_out); - - if (V4L2_TYPE_IS_MULTIPLANAR(f->type) && !multiplanar) - return -EINVAL; - if (!V4L2_TYPE_IS_MULTIPLANAR(f->type) && multiplanar) - return -EINVAL; - - if (is_uncomp) { - const struct v4l2_fwht_pixfmt_info *info = - get_q_data(ctx, f->type)->info; - - if (ctx->is_enc || - !vb2_is_streaming(&ctx->fh.m2m_ctx->cap_q_ctx.q)) - info = v4l2_fwht_get_pixfmt(f->index); - else - info = v4l2_fwht_find_nth_fmt(info->width_div, - info->height_div, - info->components_num, - info->pixenc, - f->index); - if (!info) - return -EINVAL; - f->pixelformat = info->id; - } else { - if (f->index) - return -EINVAL; - f->pixelformat = ctx->is_stateless ? - V4L2_PIX_FMT_FWHT_STATELESS : V4L2_PIX_FMT_FWHT; - if (!ctx->is_enc && !ctx->is_stateless) - f->flags = V4L2_FMT_FLAG_DYN_RESOLUTION | - V4L2_FMT_FLAG_CONTINUOUS_BYTESTREAM; - } - return 0; -} - -static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - struct vicodec_ctx *ctx = file2ctx(file); - - return enum_fmt(f, ctx, false); -} - -static int vidioc_enum_fmt_vid_out(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - struct vicodec_ctx *ctx = file2ctx(file); - - return enum_fmt(f, ctx, true); -} - -static int vidioc_g_fmt(struct vicodec_ctx *ctx, struct v4l2_format *f) -{ - struct vb2_queue *vq; - struct vicodec_q_data *q_data; - struct v4l2_pix_format_mplane *pix_mp; - struct v4l2_pix_format *pix; - const struct v4l2_fwht_pixfmt_info *info; - - vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); - if (!vq) - return -EINVAL; - - q_data = get_q_data(ctx, f->type); - info = q_data->info; - - switch (f->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - case V4L2_BUF_TYPE_VIDEO_OUTPUT: - if (multiplanar) - return -EINVAL; - pix = &f->fmt.pix; - pix->width = q_data->coded_width; - pix->height = q_data->coded_height; - pix->field = V4L2_FIELD_NONE; - pix->pixelformat = info->id; - pix->bytesperline = q_data->coded_width * - info->bytesperline_mult; - pix->sizeimage = q_data->sizeimage; - pix->colorspace = ctx->state.colorspace; - pix->xfer_func = ctx->state.xfer_func; - pix->ycbcr_enc = ctx->state.ycbcr_enc; - pix->quantization = ctx->state.quantization; - break; - - case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - if (!multiplanar) - return -EINVAL; - pix_mp = &f->fmt.pix_mp; - pix_mp->width = q_data->coded_width; - pix_mp->height = q_data->coded_height; - pix_mp->field = V4L2_FIELD_NONE; - pix_mp->pixelformat = info->id; - pix_mp->num_planes = 1; - pix_mp->plane_fmt[0].bytesperline = - q_data->coded_width * info->bytesperline_mult; - pix_mp->plane_fmt[0].sizeimage = q_data->sizeimage; - pix_mp->colorspace = ctx->state.colorspace; - pix_mp->xfer_func = ctx->state.xfer_func; - pix_mp->ycbcr_enc = ctx->state.ycbcr_enc; - pix_mp->quantization = ctx->state.quantization; - memset(pix_mp->reserved, 0, sizeof(pix_mp->reserved)); - memset(pix_mp->plane_fmt[0].reserved, 0, - sizeof(pix_mp->plane_fmt[0].reserved)); - break; - default: - return -EINVAL; - } - return 0; -} - -static int vidioc_g_fmt_vid_out(struct file *file, void *priv, - struct v4l2_format *f) -{ - return vidioc_g_fmt(file2ctx(file), f); -} - -static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - return vidioc_g_fmt(file2ctx(file), f); -} - -static int vidioc_try_fmt(struct vicodec_ctx *ctx, struct v4l2_format *f) -{ - struct v4l2_pix_format_mplane *pix_mp; - struct v4l2_pix_format *pix; - struct v4l2_plane_pix_format *plane; - const struct v4l2_fwht_pixfmt_info *info = ctx->is_stateless ? - &pixfmt_stateless_fwht : &pixfmt_fwht; - - switch (f->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - case V4L2_BUF_TYPE_VIDEO_OUTPUT: - pix = &f->fmt.pix; - if (pix->pixelformat != V4L2_PIX_FMT_FWHT && - pix->pixelformat != V4L2_PIX_FMT_FWHT_STATELESS) - info = find_fmt(pix->pixelformat); - - pix->width = clamp(pix->width, MIN_WIDTH, MAX_WIDTH); - pix->width = vic_round_dim(pix->width, info->width_div); - - pix->height = clamp(pix->height, MIN_HEIGHT, MAX_HEIGHT); - pix->height = vic_round_dim(pix->height, info->height_div); - - pix->field = V4L2_FIELD_NONE; - pix->bytesperline = - pix->width * info->bytesperline_mult; - pix->sizeimage = pix->width * pix->height * - info->sizeimage_mult / info->sizeimage_div; - if (pix->pixelformat == V4L2_PIX_FMT_FWHT) - pix->sizeimage += sizeof(struct fwht_cframe_hdr); - break; - case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - pix_mp = &f->fmt.pix_mp; - plane = pix_mp->plane_fmt; - if (pix_mp->pixelformat != V4L2_PIX_FMT_FWHT && - pix_mp->pixelformat != V4L2_PIX_FMT_FWHT_STATELESS) - info = find_fmt(pix_mp->pixelformat); - pix_mp->num_planes = 1; - - pix_mp->width = clamp(pix_mp->width, MIN_WIDTH, MAX_WIDTH); - pix_mp->width = vic_round_dim(pix_mp->width, info->width_div); - - pix_mp->height = clamp(pix_mp->height, MIN_HEIGHT, MAX_HEIGHT); - pix_mp->height = vic_round_dim(pix_mp->height, - info->height_div); - - pix_mp->field = V4L2_FIELD_NONE; - plane->bytesperline = - pix_mp->width * info->bytesperline_mult; - plane->sizeimage = pix_mp->width * pix_mp->height * - info->sizeimage_mult / info->sizeimage_div; - if (pix_mp->pixelformat == V4L2_PIX_FMT_FWHT) - plane->sizeimage += sizeof(struct fwht_cframe_hdr); - memset(pix_mp->reserved, 0, sizeof(pix_mp->reserved)); - memset(plane->reserved, 0, sizeof(plane->reserved)); - break; - default: - return -EINVAL; - } - - return 0; -} - -static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct vicodec_ctx *ctx = file2ctx(file); - struct v4l2_pix_format_mplane *pix_mp; - struct v4l2_pix_format *pix; - - switch (f->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - if (multiplanar) - return -EINVAL; - pix = &f->fmt.pix; - pix->pixelformat = ctx->is_enc ? V4L2_PIX_FMT_FWHT : - find_fmt(f->fmt.pix.pixelformat)->id; - pix->colorspace = ctx->state.colorspace; - pix->xfer_func = ctx->state.xfer_func; - pix->ycbcr_enc = ctx->state.ycbcr_enc; - pix->quantization = ctx->state.quantization; - break; - case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - if (!multiplanar) - return -EINVAL; - pix_mp = &f->fmt.pix_mp; - pix_mp->pixelformat = ctx->is_enc ? V4L2_PIX_FMT_FWHT : - find_fmt(pix_mp->pixelformat)->id; - pix_mp->colorspace = ctx->state.colorspace; - pix_mp->xfer_func = ctx->state.xfer_func; - pix_mp->ycbcr_enc = ctx->state.ycbcr_enc; - pix_mp->quantization = ctx->state.quantization; - break; - default: - return -EINVAL; - } - - return vidioc_try_fmt(ctx, f); -} - -static int vidioc_try_fmt_vid_out(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct vicodec_ctx *ctx = file2ctx(file); - struct v4l2_pix_format_mplane *pix_mp; - struct v4l2_pix_format *pix; - - switch (f->type) { - case V4L2_BUF_TYPE_VIDEO_OUTPUT: - if (multiplanar) - return -EINVAL; - pix = &f->fmt.pix; - if (ctx->is_enc) - pix->pixelformat = find_fmt(pix->pixelformat)->id; - else if (ctx->is_stateless) - pix->pixelformat = V4L2_PIX_FMT_FWHT_STATELESS; - else - pix->pixelformat = V4L2_PIX_FMT_FWHT; - if (!pix->colorspace) - pix->colorspace = V4L2_COLORSPACE_REC709; - break; - case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - if (!multiplanar) - return -EINVAL; - pix_mp = &f->fmt.pix_mp; - if (ctx->is_enc) - pix_mp->pixelformat = find_fmt(pix_mp->pixelformat)->id; - else if (ctx->is_stateless) - pix_mp->pixelformat = V4L2_PIX_FMT_FWHT_STATELESS; - else - pix_mp->pixelformat = V4L2_PIX_FMT_FWHT; - if (!pix_mp->colorspace) - pix_mp->colorspace = V4L2_COLORSPACE_REC709; - break; - default: - return -EINVAL; - } - - return vidioc_try_fmt(ctx, f); -} - -static int vidioc_s_fmt(struct vicodec_ctx *ctx, struct v4l2_format *f) -{ - struct vicodec_q_data *q_data; - struct vb2_queue *vq; - bool fmt_changed = true; - struct v4l2_pix_format_mplane *pix_mp; - struct v4l2_pix_format *pix; - - vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); - if (!vq) - return -EINVAL; - - q_data = get_q_data(ctx, f->type); - if (!q_data) - return -EINVAL; - - switch (f->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - case V4L2_BUF_TYPE_VIDEO_OUTPUT: - pix = &f->fmt.pix; - if (ctx->is_enc && V4L2_TYPE_IS_OUTPUT(f->type)) - fmt_changed = - !q_data->info || - q_data->info->id != pix->pixelformat || - q_data->coded_width != pix->width || - q_data->coded_height != pix->height; - - if (vb2_is_busy(vq) && fmt_changed) - return -EBUSY; - - if (pix->pixelformat == V4L2_PIX_FMT_FWHT) - q_data->info = &pixfmt_fwht; - else if (pix->pixelformat == V4L2_PIX_FMT_FWHT_STATELESS) - q_data->info = &pixfmt_stateless_fwht; - else - q_data->info = find_fmt(pix->pixelformat); - q_data->coded_width = pix->width; - q_data->coded_height = pix->height; - q_data->sizeimage = pix->sizeimage; - break; - case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: - case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - pix_mp = &f->fmt.pix_mp; - if (ctx->is_enc && V4L2_TYPE_IS_OUTPUT(f->type)) - fmt_changed = - !q_data->info || - q_data->info->id != pix_mp->pixelformat || - q_data->coded_width != pix_mp->width || - q_data->coded_height != pix_mp->height; - - if (vb2_is_busy(vq) && fmt_changed) - return -EBUSY; - - if (pix_mp->pixelformat == V4L2_PIX_FMT_FWHT) - q_data->info = &pixfmt_fwht; - else if (pix_mp->pixelformat == V4L2_PIX_FMT_FWHT_STATELESS) - q_data->info = &pixfmt_stateless_fwht; - else - q_data->info = find_fmt(pix_mp->pixelformat); - q_data->coded_width = pix_mp->width; - q_data->coded_height = pix_mp->height; - q_data->sizeimage = pix_mp->plane_fmt[0].sizeimage; - break; - default: - return -EINVAL; - } - - dprintk(ctx->dev, - "Setting format for type %d, coded wxh: %dx%d, fourcc: 0x%08x\n", - f->type, q_data->coded_width, q_data->coded_height, - q_data->info->id); - - return 0; -} - -static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - int ret; - - ret = vidioc_try_fmt_vid_cap(file, priv, f); - if (ret) - return ret; - - return vidioc_s_fmt(file2ctx(file), f); -} - -static int vidioc_s_fmt_vid_out(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct vicodec_ctx *ctx = file2ctx(file); - struct vicodec_q_data *q_data; - struct vicodec_q_data *q_data_cap; - struct v4l2_pix_format *pix; - struct v4l2_pix_format_mplane *pix_mp; - u32 coded_w = 0, coded_h = 0; - unsigned int size = 0; - int ret; - - q_data = get_q_data(ctx, f->type); - q_data_cap = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); - - ret = vidioc_try_fmt_vid_out(file, priv, f); - if (ret) - return ret; - - if (ctx->is_enc) { - struct vb2_queue *vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); - struct vb2_queue *vq_cap = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, - V4L2_BUF_TYPE_VIDEO_CAPTURE); - const struct v4l2_fwht_pixfmt_info *info = ctx->is_stateless ? - &pixfmt_stateless_fwht : &pixfmt_fwht; - - if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { - coded_w = f->fmt.pix.width; - coded_h = f->fmt.pix.height; - } else { - coded_w = f->fmt.pix_mp.width; - coded_h = f->fmt.pix_mp.height; - } - if (vb2_is_busy(vq) && (coded_w != q_data->coded_width || - coded_h != q_data->coded_height)) - return -EBUSY; - size = coded_w * coded_h * - info->sizeimage_mult / info->sizeimage_div; - if (!ctx->is_stateless) - size += sizeof(struct fwht_cframe_hdr); - - if (vb2_is_busy(vq_cap) && size > q_data_cap->sizeimage) - return -EBUSY; - } - - ret = vidioc_s_fmt(file2ctx(file), f); - if (!ret) { - if (ctx->is_enc) { - q_data->visible_width = coded_w; - q_data->visible_height = coded_h; - q_data_cap->coded_width = coded_w; - q_data_cap->coded_height = coded_h; - q_data_cap->sizeimage = size; - } - - switch (f->type) { - case V4L2_BUF_TYPE_VIDEO_OUTPUT: - pix = &f->fmt.pix; - ctx->state.colorspace = pix->colorspace; - ctx->state.xfer_func = pix->xfer_func; - ctx->state.ycbcr_enc = pix->ycbcr_enc; - ctx->state.quantization = pix->quantization; - break; - case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: - pix_mp = &f->fmt.pix_mp; - ctx->state.colorspace = pix_mp->colorspace; - ctx->state.xfer_func = pix_mp->xfer_func; - ctx->state.ycbcr_enc = pix_mp->ycbcr_enc; - ctx->state.quantization = pix_mp->quantization; - break; - default: - break; - } - } - return ret; -} - -static int vidioc_g_selection(struct file *file, void *priv, - struct v4l2_selection *s) -{ - struct vicodec_ctx *ctx = file2ctx(file); - struct vicodec_q_data *q_data; - - q_data = get_q_data(ctx, s->type); - if (!q_data) - return -EINVAL; - /* - * encoder supports only cropping on the OUTPUT buffer - * decoder supports only composing on the CAPTURE buffer - */ - if (ctx->is_enc && s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { - switch (s->target) { - case V4L2_SEL_TGT_CROP: - s->r.left = 0; - s->r.top = 0; - s->r.width = q_data->visible_width; - s->r.height = q_data->visible_height; - return 0; - case V4L2_SEL_TGT_CROP_DEFAULT: - case V4L2_SEL_TGT_CROP_BOUNDS: - s->r.left = 0; - s->r.top = 0; - s->r.width = q_data->coded_width; - s->r.height = q_data->coded_height; - return 0; - } - } else if (!ctx->is_enc && s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { - switch (s->target) { - case V4L2_SEL_TGT_COMPOSE: - s->r.left = 0; - s->r.top = 0; - s->r.width = q_data->visible_width; - s->r.height = q_data->visible_height; - return 0; - case V4L2_SEL_TGT_COMPOSE_DEFAULT: - case V4L2_SEL_TGT_COMPOSE_BOUNDS: - s->r.left = 0; - s->r.top = 0; - s->r.width = q_data->coded_width; - s->r.height = q_data->coded_height; - return 0; - } - } - return -EINVAL; -} - -static int vidioc_s_selection(struct file *file, void *priv, - struct v4l2_selection *s) -{ - struct vicodec_ctx *ctx = file2ctx(file); - struct vicodec_q_data *q_data; - - if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) - return -EINVAL; - - q_data = get_q_data(ctx, s->type); - if (!q_data) - return -EINVAL; - - if (!ctx->is_enc || s->target != V4L2_SEL_TGT_CROP) - return -EINVAL; - - s->r.left = 0; - s->r.top = 0; - q_data->visible_width = clamp(s->r.width, MIN_WIDTH, - q_data->coded_width); - s->r.width = q_data->visible_width; - q_data->visible_height = clamp(s->r.height, MIN_HEIGHT, - q_data->coded_height); - s->r.height = q_data->visible_height; - return 0; -} - -static int vicodec_encoder_cmd(struct file *file, void *fh, - struct v4l2_encoder_cmd *ec) -{ - struct vicodec_ctx *ctx = file2ctx(file); - int ret; - - ret = v4l2_m2m_ioctl_try_encoder_cmd(file, fh, ec); - if (ret < 0) - return ret; - - if (!vb2_is_streaming(&ctx->fh.m2m_ctx->cap_q_ctx.q) || - !vb2_is_streaming(&ctx->fh.m2m_ctx->out_q_ctx.q)) - return 0; - - ret = v4l2_m2m_ioctl_encoder_cmd(file, fh, ec); - if (ret < 0) - return ret; - - if (ec->cmd == V4L2_ENC_CMD_STOP && - v4l2_m2m_has_stopped(ctx->fh.m2m_ctx)) - v4l2_event_queue_fh(&ctx->fh, &vicodec_eos_event); - - if (ec->cmd == V4L2_ENC_CMD_START && - v4l2_m2m_has_stopped(ctx->fh.m2m_ctx)) - vb2_clear_last_buffer_dequeued(&ctx->fh.m2m_ctx->cap_q_ctx.q); - - return 0; -} - -static int vicodec_decoder_cmd(struct file *file, void *fh, - struct v4l2_decoder_cmd *dc) -{ - struct vicodec_ctx *ctx = file2ctx(file); - int ret; - - ret = v4l2_m2m_ioctl_try_decoder_cmd(file, fh, dc); - if (ret < 0) - return ret; - - if (!vb2_is_streaming(&ctx->fh.m2m_ctx->cap_q_ctx.q) || - !vb2_is_streaming(&ctx->fh.m2m_ctx->out_q_ctx.q)) - return 0; - - ret = v4l2_m2m_ioctl_decoder_cmd(file, fh, dc); - if (ret < 0) - return ret; - - if (dc->cmd == V4L2_DEC_CMD_STOP && - v4l2_m2m_has_stopped(ctx->fh.m2m_ctx)) - v4l2_event_queue_fh(&ctx->fh, &vicodec_eos_event); - - if (dc->cmd == V4L2_DEC_CMD_START && - v4l2_m2m_has_stopped(ctx->fh.m2m_ctx)) - vb2_clear_last_buffer_dequeued(&ctx->fh.m2m_ctx->cap_q_ctx.q); - - return 0; -} - -static int vicodec_enum_framesizes(struct file *file, void *fh, - struct v4l2_frmsizeenum *fsize) -{ - switch (fsize->pixel_format) { - case V4L2_PIX_FMT_FWHT_STATELESS: - break; - case V4L2_PIX_FMT_FWHT: - break; - default: - if (find_fmt(fsize->pixel_format)->id == fsize->pixel_format) - break; - return -EINVAL; - } - - if (fsize->index) - return -EINVAL; - - fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; - - fsize->stepwise.min_width = MIN_WIDTH; - fsize->stepwise.max_width = MAX_WIDTH; - fsize->stepwise.step_width = 8; - fsize->stepwise.min_height = MIN_HEIGHT; - fsize->stepwise.max_height = MAX_HEIGHT; - fsize->stepwise.step_height = 8; - - return 0; -} - -static int vicodec_subscribe_event(struct v4l2_fh *fh, - const struct v4l2_event_subscription *sub) -{ - struct vicodec_ctx *ctx = container_of(fh, struct vicodec_ctx, fh); - - switch (sub->type) { - case V4L2_EVENT_SOURCE_CHANGE: - if (ctx->is_enc) - return -EINVAL; - /* fall through */ - case V4L2_EVENT_EOS: - if (ctx->is_stateless) - return -EINVAL; - return v4l2_event_subscribe(fh, sub, 0, NULL); - default: - return v4l2_ctrl_subscribe_event(fh, sub); - } -} - -static const struct v4l2_ioctl_ops vicodec_ioctl_ops = { - .vidioc_querycap = vidioc_querycap, - - .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, - .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, - .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, - - .vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt_vid_cap, - .vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt_vid_cap, - .vidioc_s_fmt_vid_cap_mplane = vidioc_s_fmt_vid_cap, - - .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out, - .vidioc_g_fmt_vid_out = vidioc_g_fmt_vid_out, - .vidioc_try_fmt_vid_out = vidioc_try_fmt_vid_out, - .vidioc_s_fmt_vid_out = vidioc_s_fmt_vid_out, - - .vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt_vid_out, - .vidioc_try_fmt_vid_out_mplane = vidioc_try_fmt_vid_out, - .vidioc_s_fmt_vid_out_mplane = vidioc_s_fmt_vid_out, - - .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, - .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, - .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, - .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, - .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf, - .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs, - .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, - - .vidioc_streamon = v4l2_m2m_ioctl_streamon, - .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, - - .vidioc_g_selection = vidioc_g_selection, - .vidioc_s_selection = vidioc_s_selection, - - .vidioc_try_encoder_cmd = v4l2_m2m_ioctl_try_encoder_cmd, - .vidioc_encoder_cmd = vicodec_encoder_cmd, - .vidioc_try_decoder_cmd = v4l2_m2m_ioctl_try_decoder_cmd, - .vidioc_decoder_cmd = vicodec_decoder_cmd, - .vidioc_enum_framesizes = vicodec_enum_framesizes, - - .vidioc_subscribe_event = vicodec_subscribe_event, - .vidioc_unsubscribe_event = v4l2_event_unsubscribe, -}; - - -/* - * Queue operations - */ - -static int vicodec_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, - unsigned int *nplanes, unsigned int sizes[], - struct device *alloc_devs[]) -{ - struct vicodec_ctx *ctx = vb2_get_drv_priv(vq); - struct vicodec_q_data *q_data = get_q_data(ctx, vq->type); - unsigned int size = q_data->sizeimage; - - if (*nplanes) - return sizes[0] < size ? -EINVAL : 0; - - *nplanes = 1; - sizes[0] = size; - q_data->vb2_sizeimage = size; - return 0; -} - -static int vicodec_buf_out_validate(struct vb2_buffer *vb) -{ - struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); - - vbuf->field = V4L2_FIELD_NONE; - return 0; -} - -static int vicodec_buf_prepare(struct vb2_buffer *vb) -{ - struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); - struct vicodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); - struct vicodec_q_data *q_data; - - dprintk(ctx->dev, "type: %d\n", vb->vb2_queue->type); - - q_data = get_q_data(ctx, vb->vb2_queue->type); - if (V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) { - if (vbuf->field == V4L2_FIELD_ANY) - vbuf->field = V4L2_FIELD_NONE; - if (vbuf->field != V4L2_FIELD_NONE) { - dprintk(ctx->dev, "%s field isn't supported\n", - __func__); - return -EINVAL; - } - } - - if (vb2_plane_size(vb, 0) < q_data->vb2_sizeimage) { - dprintk(ctx->dev, - "%s data will not fit into plane (%lu < %lu)\n", - __func__, vb2_plane_size(vb, 0), - (long)q_data->vb2_sizeimage); - return -EINVAL; - } - - return 0; -} - -static void vicodec_buf_queue(struct vb2_buffer *vb) -{ - struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); - struct vicodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); - unsigned int sz = vb2_get_plane_payload(&vbuf->vb2_buf, 0); - u8 *p_src = vb2_plane_vaddr(&vbuf->vb2_buf, 0); - u8 *p = p_src; - struct vb2_queue *vq_out = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, - V4L2_BUF_TYPE_VIDEO_OUTPUT); - struct vb2_queue *vq_cap = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, - V4L2_BUF_TYPE_VIDEO_CAPTURE); - bool header_valid = false; - static const struct v4l2_event rs_event = { - .type = V4L2_EVENT_SOURCE_CHANGE, - .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION, - }; - - if (!V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type) && - vb2_is_streaming(vb->vb2_queue) && - v4l2_m2m_dst_buf_is_last(ctx->fh.m2m_ctx)) { - unsigned int i; - - for (i = 0; i < vb->num_planes; i++) - vb->planes[i].bytesused = 0; - - vbuf->field = V4L2_FIELD_NONE; - vbuf->sequence = - get_q_data(ctx, vb->vb2_queue->type)->sequence++; - - v4l2_m2m_last_buffer_done(ctx->fh.m2m_ctx, vbuf); - v4l2_event_queue_fh(&ctx->fh, &vicodec_eos_event); - return; - } - - /* buf_queue handles only the first source change event */ - if (ctx->first_source_change_sent) { - v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); - return; - } - - /* - * if both queues are streaming, the source change event is - * handled in job_ready - */ - if (vb2_is_streaming(vq_cap) && vb2_is_streaming(vq_out)) { - v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); - return; - } - - /* - * source change event is relevant only for the stateful decoder - * in the compressed stream - */ - if (ctx->is_stateless || ctx->is_enc || - !V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) { - v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); - return; - } - - do { - enum vb2_buffer_state state = - get_next_header(ctx, &p, p_src + sz - p); - - if (ctx->header_size < sizeof(struct fwht_cframe_hdr)) { - v4l2_m2m_buf_done(vbuf, state); - return; - } - header_valid = is_header_valid(&ctx->state.header); - /* - * p points right after the end of the header in the - * buffer. If the header is invalid we set p to point - * to the next byte after the start of the header - */ - if (!header_valid) { - p = p - sizeof(struct fwht_cframe_hdr) + 1; - if (p < p_src) - p = p_src; - ctx->header_size = 0; - ctx->comp_magic_cnt = 0; - } - - } while (!header_valid); - - ctx->cur_buf_offset = p - p_src; - update_capture_data_from_header(ctx); - ctx->first_source_change_sent = true; - v4l2_event_queue_fh(&ctx->fh, &rs_event); - v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); -} - -static void vicodec_return_bufs(struct vb2_queue *q, u32 state) -{ - struct vicodec_ctx *ctx = vb2_get_drv_priv(q); - struct vb2_v4l2_buffer *vbuf; - - for (;;) { - if (V4L2_TYPE_IS_OUTPUT(q->type)) - vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); - else - vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); - if (vbuf == NULL) - return; - v4l2_ctrl_request_complete(vbuf->vb2_buf.req_obj.req, - &ctx->hdl); - spin_lock(ctx->lock); - v4l2_m2m_buf_done(vbuf, state); - spin_unlock(ctx->lock); - } -} - -static unsigned int total_frame_size(struct vicodec_q_data *q_data) -{ - unsigned int size; - unsigned int chroma_div; - - if (!q_data->info) { - WARN_ON(1); - return 0; - } - size = q_data->coded_width * q_data->coded_height; - chroma_div = q_data->info->width_div * q_data->info->height_div; - - if (q_data->info->components_num == 4) - return 2 * size + 2 * (size / chroma_div); - else if (q_data->info->components_num == 3) - return size + 2 * (size / chroma_div); - return size; -} - -static int vicodec_start_streaming(struct vb2_queue *q, - unsigned int count) -{ - struct vicodec_ctx *ctx = vb2_get_drv_priv(q); - struct vicodec_q_data *q_data = get_q_data(ctx, q->type); - struct v4l2_fwht_state *state = &ctx->state; - const struct v4l2_fwht_pixfmt_info *info = q_data->info; - unsigned int size = q_data->coded_width * q_data->coded_height; - unsigned int chroma_div; - unsigned int total_planes_size; - u8 *new_comp_frame = NULL; - - chroma_div = info->width_div * info->height_div; - q_data->sequence = 0; - - v4l2_m2m_update_start_streaming_state(ctx->fh.m2m_ctx, q); - - state->gop_cnt = 0; - - if ((V4L2_TYPE_IS_OUTPUT(q->type) && !ctx->is_enc) || - (!V4L2_TYPE_IS_OUTPUT(q->type) && ctx->is_enc)) - return 0; - - if (info->id == V4L2_PIX_FMT_FWHT || - info->id == V4L2_PIX_FMT_FWHT_STATELESS) { - vicodec_return_bufs(q, VB2_BUF_STATE_QUEUED); - return -EINVAL; - } - total_planes_size = total_frame_size(q_data); - ctx->comp_max_size = total_planes_size; - - state->visible_width = q_data->visible_width; - state->visible_height = q_data->visible_height; - state->coded_width = q_data->coded_width; - state->coded_height = q_data->coded_height; - state->stride = q_data->coded_width * - info->bytesperline_mult; - - if (ctx->is_stateless) { - state->ref_stride = state->stride; - return 0; - } - state->ref_stride = q_data->coded_width * info->luma_alpha_step; - - state->ref_frame.buf = kvmalloc(total_planes_size, GFP_KERNEL); - state->ref_frame.luma = state->ref_frame.buf; - new_comp_frame = kvmalloc(ctx->comp_max_size, GFP_KERNEL); - - if (!state->ref_frame.luma || !new_comp_frame) { - kvfree(state->ref_frame.luma); - kvfree(new_comp_frame); - vicodec_return_bufs(q, VB2_BUF_STATE_QUEUED); - return -ENOMEM; - } - /* - * if state->compressed_frame was already allocated then - * it contain data of the first frame of the new resolution - */ - if (state->compressed_frame) { - if (ctx->comp_size > ctx->comp_max_size) - ctx->comp_size = ctx->comp_max_size; - - memcpy(new_comp_frame, - state->compressed_frame, ctx->comp_size); - } - - kvfree(state->compressed_frame); - state->compressed_frame = new_comp_frame; - - if (info->components_num < 3) { - state->ref_frame.cb = NULL; - state->ref_frame.cr = NULL; - state->ref_frame.alpha = NULL; - return 0; - } - - state->ref_frame.cb = state->ref_frame.luma + size; - state->ref_frame.cr = state->ref_frame.cb + size / chroma_div; - - if (info->components_num == 4) - state->ref_frame.alpha = - state->ref_frame.cr + size / chroma_div; - else - state->ref_frame.alpha = NULL; - - return 0; -} - -static void vicodec_stop_streaming(struct vb2_queue *q) -{ - struct vicodec_ctx *ctx = vb2_get_drv_priv(q); - - vicodec_return_bufs(q, VB2_BUF_STATE_ERROR); - - v4l2_m2m_update_stop_streaming_state(ctx->fh.m2m_ctx, q); - - if (V4L2_TYPE_IS_OUTPUT(q->type) && - v4l2_m2m_has_stopped(ctx->fh.m2m_ctx)) - v4l2_event_queue_fh(&ctx->fh, &vicodec_eos_event); - - if (!ctx->is_enc && V4L2_TYPE_IS_OUTPUT(q->type)) - ctx->first_source_change_sent = false; - - if ((!V4L2_TYPE_IS_OUTPUT(q->type) && !ctx->is_enc) || - (V4L2_TYPE_IS_OUTPUT(q->type) && ctx->is_enc)) { - if (!ctx->is_stateless) - kvfree(ctx->state.ref_frame.buf); - ctx->state.ref_frame.buf = NULL; - ctx->state.ref_frame.luma = NULL; - ctx->comp_max_size = 0; - ctx->source_changed = false; - } - if (V4L2_TYPE_IS_OUTPUT(q->type) && !ctx->is_enc) { - ctx->cur_buf_offset = 0; - ctx->comp_size = 0; - ctx->header_size = 0; - ctx->comp_magic_cnt = 0; - ctx->comp_has_frame = 0; - ctx->comp_has_next_frame = 0; - } -} - -static void vicodec_buf_request_complete(struct vb2_buffer *vb) -{ - struct vicodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); - - v4l2_ctrl_request_complete(vb->req_obj.req, &ctx->hdl); -} - - -static const struct vb2_ops vicodec_qops = { - .queue_setup = vicodec_queue_setup, - .buf_out_validate = vicodec_buf_out_validate, - .buf_prepare = vicodec_buf_prepare, - .buf_queue = vicodec_buf_queue, - .buf_request_complete = vicodec_buf_request_complete, - .start_streaming = vicodec_start_streaming, - .stop_streaming = vicodec_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, -}; - -static int queue_init(void *priv, struct vb2_queue *src_vq, - struct vb2_queue *dst_vq) -{ - struct vicodec_ctx *ctx = priv; - int ret; - - src_vq->type = (multiplanar ? - V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE : - V4L2_BUF_TYPE_VIDEO_OUTPUT); - src_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; - src_vq->drv_priv = ctx; - src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); - src_vq->ops = &vicodec_qops; - src_vq->mem_ops = &vb2_vmalloc_memops; - src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; - if (ctx->is_enc) - src_vq->lock = &ctx->dev->stateful_enc.mutex; - else if (ctx->is_stateless) - src_vq->lock = &ctx->dev->stateless_dec.mutex; - else - src_vq->lock = &ctx->dev->stateful_dec.mutex; - src_vq->supports_requests = ctx->is_stateless; - src_vq->requires_requests = ctx->is_stateless; - ret = vb2_queue_init(src_vq); - if (ret) - return ret; - - dst_vq->type = (multiplanar ? - V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE : - V4L2_BUF_TYPE_VIDEO_CAPTURE); - dst_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; - dst_vq->drv_priv = ctx; - dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); - dst_vq->ops = &vicodec_qops; - dst_vq->mem_ops = &vb2_vmalloc_memops; - dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; - dst_vq->lock = src_vq->lock; - - return vb2_queue_init(dst_vq); -} - -static int vicodec_try_ctrl(struct v4l2_ctrl *ctrl) -{ - struct vicodec_ctx *ctx = container_of(ctrl->handler, - struct vicodec_ctx, hdl); - const struct v4l2_ctrl_fwht_params *params; - struct vicodec_q_data *q_dst = get_q_data(ctx, - V4L2_BUF_TYPE_VIDEO_CAPTURE); - - switch (ctrl->id) { - case V4L2_CID_MPEG_VIDEO_FWHT_PARAMS: - if (!q_dst->info) - return -EINVAL; - params = ctrl->p_new.p_fwht_params; - if (params->width > q_dst->coded_width || - params->width < MIN_WIDTH || - params->height > q_dst->coded_height || - params->height < MIN_HEIGHT) - return -EINVAL; - if (!validate_by_version(params->flags, params->version)) - return -EINVAL; - if (!validate_stateless_params_flags(params, q_dst->info)) - return -EINVAL; - return 0; - default: - return 0; - } - return 0; -} - -static void update_header_from_stateless_params(struct vicodec_ctx *ctx, - const struct v4l2_ctrl_fwht_params *params) -{ - struct fwht_cframe_hdr *p_hdr = &ctx->state.header; - - p_hdr->magic1 = FWHT_MAGIC1; - p_hdr->magic2 = FWHT_MAGIC2; - p_hdr->version = htonl(params->version); - p_hdr->width = htonl(params->width); - p_hdr->height = htonl(params->height); - p_hdr->flags = htonl(params->flags); - p_hdr->colorspace = htonl(params->colorspace); - p_hdr->xfer_func = htonl(params->xfer_func); - p_hdr->ycbcr_enc = htonl(params->ycbcr_enc); - p_hdr->quantization = htonl(params->quantization); -} - -static int vicodec_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct vicodec_ctx *ctx = container_of(ctrl->handler, - struct vicodec_ctx, hdl); - const struct v4l2_ctrl_fwht_params *params; - - switch (ctrl->id) { - case V4L2_CID_MPEG_VIDEO_GOP_SIZE: - ctx->state.gop_size = ctrl->val; - return 0; - case V4L2_CID_FWHT_I_FRAME_QP: - ctx->state.i_frame_qp = ctrl->val; - return 0; - case V4L2_CID_FWHT_P_FRAME_QP: - ctx->state.p_frame_qp = ctrl->val; - return 0; - case V4L2_CID_MPEG_VIDEO_FWHT_PARAMS: - params = ctrl->p_new.p_fwht_params; - update_header_from_stateless_params(ctx, params); - ctx->state.ref_frame_ts = params->backward_ref_ts; - return 0; - } - return -EINVAL; -} - -static const struct v4l2_ctrl_ops vicodec_ctrl_ops = { - .s_ctrl = vicodec_s_ctrl, - .try_ctrl = vicodec_try_ctrl, -}; - -static const struct v4l2_ctrl_config vicodec_ctrl_stateless_state = { - .ops = &vicodec_ctrl_ops, - .id = V4L2_CID_MPEG_VIDEO_FWHT_PARAMS, - .elem_size = sizeof(struct v4l2_ctrl_fwht_params), -}; - -/* - * File operations - */ -static int vicodec_open(struct file *file) -{ - const struct v4l2_fwht_pixfmt_info *info = v4l2_fwht_get_pixfmt(0); - struct video_device *vfd = video_devdata(file); - struct vicodec_dev *dev = video_drvdata(file); - struct vicodec_ctx *ctx = NULL; - struct v4l2_ctrl_handler *hdl; - unsigned int raw_size; - unsigned int comp_size; - int rc = 0; - - if (mutex_lock_interruptible(vfd->lock)) - return -ERESTARTSYS; - ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); - if (!ctx) { - rc = -ENOMEM; - goto open_unlock; - } - - if (vfd == &dev->stateful_enc.vfd) - ctx->is_enc = true; - else if (vfd == &dev->stateless_dec.vfd) - ctx->is_stateless = true; - - v4l2_fh_init(&ctx->fh, video_devdata(file)); - file->private_data = &ctx->fh; - ctx->dev = dev; - hdl = &ctx->hdl; - v4l2_ctrl_handler_init(hdl, 5); - v4l2_ctrl_new_std(hdl, &vicodec_ctrl_ops, V4L2_CID_MPEG_VIDEO_GOP_SIZE, - 1, 16, 1, 10); - v4l2_ctrl_new_std(hdl, &vicodec_ctrl_ops, V4L2_CID_FWHT_I_FRAME_QP, - 1, 31, 1, 20); - v4l2_ctrl_new_std(hdl, &vicodec_ctrl_ops, V4L2_CID_FWHT_P_FRAME_QP, - 1, 31, 1, 20); - if (ctx->is_enc) - v4l2_ctrl_new_std(hdl, &vicodec_ctrl_ops, - V4L2_CID_MIN_BUFFERS_FOR_OUTPUT, 1, 1, 1, 1); - if (ctx->is_stateless) - v4l2_ctrl_new_custom(hdl, &vicodec_ctrl_stateless_state, NULL); - if (hdl->error) { - rc = hdl->error; - v4l2_ctrl_handler_free(hdl); - kfree(ctx); - goto open_unlock; - } - ctx->fh.ctrl_handler = hdl; - v4l2_ctrl_handler_setup(hdl); - - if (ctx->is_enc) - ctx->q_data[V4L2_M2M_SRC].info = info; - else if (ctx->is_stateless) - ctx->q_data[V4L2_M2M_SRC].info = &pixfmt_stateless_fwht; - else - ctx->q_data[V4L2_M2M_SRC].info = &pixfmt_fwht; - ctx->q_data[V4L2_M2M_SRC].coded_width = 1280; - ctx->q_data[V4L2_M2M_SRC].coded_height = 720; - ctx->q_data[V4L2_M2M_SRC].visible_width = 1280; - ctx->q_data[V4L2_M2M_SRC].visible_height = 720; - raw_size = 1280 * 720 * info->sizeimage_mult / info->sizeimage_div; - comp_size = 1280 * 720 * pixfmt_fwht.sizeimage_mult / - pixfmt_fwht.sizeimage_div; - if (ctx->is_enc) - ctx->q_data[V4L2_M2M_SRC].sizeimage = raw_size; - else if (ctx->is_stateless) - ctx->q_data[V4L2_M2M_SRC].sizeimage = comp_size; - else - ctx->q_data[V4L2_M2M_SRC].sizeimage = - comp_size + sizeof(struct fwht_cframe_hdr); - ctx->q_data[V4L2_M2M_DST] = ctx->q_data[V4L2_M2M_SRC]; - if (ctx->is_enc) { - ctx->q_data[V4L2_M2M_DST].info = &pixfmt_fwht; - ctx->q_data[V4L2_M2M_DST].sizeimage = - comp_size + sizeof(struct fwht_cframe_hdr); - } else { - ctx->q_data[V4L2_M2M_DST].info = info; - ctx->q_data[V4L2_M2M_DST].sizeimage = raw_size; - } - - ctx->state.colorspace = V4L2_COLORSPACE_REC709; - - if (ctx->is_enc) { - ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->stateful_enc.m2m_dev, - ctx, &queue_init); - ctx->lock = &dev->stateful_enc.lock; - } else if (ctx->is_stateless) { - ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->stateless_dec.m2m_dev, - ctx, &queue_init); - ctx->lock = &dev->stateless_dec.lock; - } else { - ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->stateful_dec.m2m_dev, - ctx, &queue_init); - ctx->lock = &dev->stateful_dec.lock; - } - - if (IS_ERR(ctx->fh.m2m_ctx)) { - rc = PTR_ERR(ctx->fh.m2m_ctx); - - v4l2_ctrl_handler_free(hdl); - v4l2_fh_exit(&ctx->fh); - kfree(ctx); - goto open_unlock; - } - - v4l2_fh_add(&ctx->fh); - -open_unlock: - mutex_unlock(vfd->lock); - return rc; -} - -static int vicodec_release(struct file *file) -{ - struct video_device *vfd = video_devdata(file); - struct vicodec_ctx *ctx = file2ctx(file); - - mutex_lock(vfd->lock); - v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); - mutex_unlock(vfd->lock); - v4l2_fh_del(&ctx->fh); - v4l2_fh_exit(&ctx->fh); - v4l2_ctrl_handler_free(&ctx->hdl); - kvfree(ctx->state.compressed_frame); - kfree(ctx); - - return 0; -} - -static int vicodec_request_validate(struct media_request *req) -{ - struct media_request_object *obj; - struct v4l2_ctrl_handler *parent_hdl, *hdl; - struct vicodec_ctx *ctx = NULL; - struct v4l2_ctrl *ctrl; - unsigned int count; - - list_for_each_entry(obj, &req->objects, list) { - struct vb2_buffer *vb; - - if (vb2_request_object_is_buffer(obj)) { - vb = container_of(obj, struct vb2_buffer, req_obj); - ctx = vb2_get_drv_priv(vb->vb2_queue); - - break; - } - } - - if (!ctx) { - pr_err("No buffer was provided with the request\n"); - return -ENOENT; - } - - count = vb2_request_buffer_cnt(req); - if (!count) { - v4l2_info(&ctx->dev->v4l2_dev, - "No buffer was provided with the request\n"); - return -ENOENT; - } else if (count > 1) { - v4l2_info(&ctx->dev->v4l2_dev, - "More than one buffer was provided with the request\n"); - return -EINVAL; - } - - parent_hdl = &ctx->hdl; - - hdl = v4l2_ctrl_request_hdl_find(req, parent_hdl); - if (!hdl) { - v4l2_info(&ctx->dev->v4l2_dev, "Missing codec control\n"); - return -ENOENT; - } - ctrl = v4l2_ctrl_request_hdl_ctrl_find(hdl, - vicodec_ctrl_stateless_state.id); - if (!ctrl) { - v4l2_info(&ctx->dev->v4l2_dev, - "Missing required codec control\n"); - return -ENOENT; - } - - return vb2_request_validate(req); -} - -static const struct v4l2_file_operations vicodec_fops = { - .owner = THIS_MODULE, - .open = vicodec_open, - .release = vicodec_release, - .poll = v4l2_m2m_fop_poll, - .unlocked_ioctl = video_ioctl2, - .mmap = v4l2_m2m_fop_mmap, -}; - -static const struct video_device vicodec_videodev = { - .name = VICODEC_NAME, - .vfl_dir = VFL_DIR_M2M, - .fops = &vicodec_fops, - .ioctl_ops = &vicodec_ioctl_ops, - .minor = -1, - .release = video_device_release_empty, -}; - -static const struct media_device_ops vicodec_m2m_media_ops = { - .req_validate = vicodec_request_validate, - .req_queue = v4l2_m2m_request_queue, -}; - -static const struct v4l2_m2m_ops m2m_ops = { - .device_run = device_run, - .job_ready = job_ready, -}; - -static int register_instance(struct vicodec_dev *dev, - struct vicodec_dev_instance *dev_instance, - const char *name, bool is_enc) -{ - struct video_device *vfd; - int ret; - - spin_lock_init(&dev_instance->lock); - mutex_init(&dev_instance->mutex); - dev_instance->m2m_dev = v4l2_m2m_init(&m2m_ops); - if (IS_ERR(dev_instance->m2m_dev)) { - v4l2_err(&dev->v4l2_dev, "Failed to init vicodec enc device\n"); - return PTR_ERR(dev_instance->m2m_dev); - } - - dev_instance->vfd = vicodec_videodev; - vfd = &dev_instance->vfd; - vfd->lock = &dev_instance->mutex; - vfd->v4l2_dev = &dev->v4l2_dev; - strscpy(vfd->name, name, sizeof(vfd->name)); - vfd->device_caps = V4L2_CAP_STREAMING | - (multiplanar ? V4L2_CAP_VIDEO_M2M_MPLANE : V4L2_CAP_VIDEO_M2M); - if (is_enc) { - v4l2_disable_ioctl(vfd, VIDIOC_DECODER_CMD); - v4l2_disable_ioctl(vfd, VIDIOC_TRY_DECODER_CMD); - } else { - v4l2_disable_ioctl(vfd, VIDIOC_ENCODER_CMD); - v4l2_disable_ioctl(vfd, VIDIOC_TRY_ENCODER_CMD); - } - video_set_drvdata(vfd, dev); - - ret = video_register_device(vfd, VFL_TYPE_VIDEO, 0); - if (ret) { - v4l2_err(&dev->v4l2_dev, "Failed to register video device '%s'\n", name); - v4l2_m2m_release(dev_instance->m2m_dev); - return ret; - } - v4l2_info(&dev->v4l2_dev, "Device '%s' registered as /dev/video%d\n", - name, vfd->num); - return 0; -} - -static void vicodec_v4l2_dev_release(struct v4l2_device *v4l2_dev) -{ - struct vicodec_dev *dev = container_of(v4l2_dev, struct vicodec_dev, v4l2_dev); - - v4l2_device_unregister(&dev->v4l2_dev); - v4l2_m2m_release(dev->stateful_enc.m2m_dev); - v4l2_m2m_release(dev->stateful_dec.m2m_dev); - v4l2_m2m_release(dev->stateless_dec.m2m_dev); -#ifdef CONFIG_MEDIA_CONTROLLER - media_device_cleanup(&dev->mdev); -#endif - kfree(dev); -} - -static int vicodec_probe(struct platform_device *pdev) -{ - struct vicodec_dev *dev; - int ret; - - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) - return -ENOMEM; - - ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); - if (ret) - goto free_dev; - - dev->v4l2_dev.release = vicodec_v4l2_dev_release; - -#ifdef CONFIG_MEDIA_CONTROLLER - dev->mdev.dev = &pdev->dev; - strscpy(dev->mdev.model, "vicodec", sizeof(dev->mdev.model)); - strscpy(dev->mdev.bus_info, "platform:vicodec", - sizeof(dev->mdev.bus_info)); - media_device_init(&dev->mdev); - dev->mdev.ops = &vicodec_m2m_media_ops; - dev->v4l2_dev.mdev = &dev->mdev; -#endif - - platform_set_drvdata(pdev, dev); - - if (register_instance(dev, &dev->stateful_enc, - "stateful-encoder", true)) - goto unreg_dev; - - if (register_instance(dev, &dev->stateful_dec, - "stateful-decoder", false)) - goto unreg_sf_enc; - - if (register_instance(dev, &dev->stateless_dec, - "stateless-decoder", false)) - goto unreg_sf_dec; - -#ifdef CONFIG_MEDIA_CONTROLLER - ret = v4l2_m2m_register_media_controller(dev->stateful_enc.m2m_dev, - &dev->stateful_enc.vfd, - MEDIA_ENT_F_PROC_VIDEO_ENCODER); - if (ret) { - v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem media controller for enc\n"); - goto unreg_m2m; - } - - ret = v4l2_m2m_register_media_controller(dev->stateful_dec.m2m_dev, - &dev->stateful_dec.vfd, - MEDIA_ENT_F_PROC_VIDEO_DECODER); - if (ret) { - v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem media controller for dec\n"); - goto unreg_m2m_sf_enc_mc; - } - - ret = v4l2_m2m_register_media_controller(dev->stateless_dec.m2m_dev, - &dev->stateless_dec.vfd, - MEDIA_ENT_F_PROC_VIDEO_DECODER); - if (ret) { - v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem media controller for stateless dec\n"); - goto unreg_m2m_sf_dec_mc; - } - - ret = media_device_register(&dev->mdev); - if (ret) { - v4l2_err(&dev->v4l2_dev, "Failed to register mem2mem media device\n"); - goto unreg_m2m_sl_dec_mc; - } -#endif - return 0; - -#ifdef CONFIG_MEDIA_CONTROLLER -unreg_m2m_sl_dec_mc: - v4l2_m2m_unregister_media_controller(dev->stateless_dec.m2m_dev); -unreg_m2m_sf_dec_mc: - v4l2_m2m_unregister_media_controller(dev->stateful_dec.m2m_dev); -unreg_m2m_sf_enc_mc: - v4l2_m2m_unregister_media_controller(dev->stateful_enc.m2m_dev); -unreg_m2m: - video_unregister_device(&dev->stateless_dec.vfd); - v4l2_m2m_release(dev->stateless_dec.m2m_dev); -#endif -unreg_sf_dec: - video_unregister_device(&dev->stateful_dec.vfd); - v4l2_m2m_release(dev->stateful_dec.m2m_dev); -unreg_sf_enc: - video_unregister_device(&dev->stateful_enc.vfd); - v4l2_m2m_release(dev->stateful_enc.m2m_dev); -unreg_dev: - v4l2_device_unregister(&dev->v4l2_dev); -free_dev: - kfree(dev); - - return ret; -} - -static int vicodec_remove(struct platform_device *pdev) -{ - struct vicodec_dev *dev = platform_get_drvdata(pdev); - - v4l2_info(&dev->v4l2_dev, "Removing " VICODEC_NAME); - -#ifdef CONFIG_MEDIA_CONTROLLER - media_device_unregister(&dev->mdev); - v4l2_m2m_unregister_media_controller(dev->stateful_enc.m2m_dev); - v4l2_m2m_unregister_media_controller(dev->stateful_dec.m2m_dev); - v4l2_m2m_unregister_media_controller(dev->stateless_dec.m2m_dev); -#endif - - video_unregister_device(&dev->stateful_enc.vfd); - video_unregister_device(&dev->stateful_dec.vfd); - video_unregister_device(&dev->stateless_dec.vfd); - v4l2_device_put(&dev->v4l2_dev); - - return 0; -} - -static struct platform_driver vicodec_pdrv = { - .probe = vicodec_probe, - .remove = vicodec_remove, - .driver = { - .name = VICODEC_NAME, - }, -}; - -static void __exit vicodec_exit(void) -{ - platform_driver_unregister(&vicodec_pdrv); - platform_device_unregister(&vicodec_pdev); -} - -static int __init vicodec_init(void) -{ - int ret; - - ret = platform_device_register(&vicodec_pdev); - if (ret) - return ret; - - ret = platform_driver_register(&vicodec_pdrv); - if (ret) - platform_device_unregister(&vicodec_pdev); - - return ret; -} - -module_init(vicodec_init); -module_exit(vicodec_exit); diff --git a/drivers/media/platform/vim2m.c b/drivers/media/platform/vim2m.c deleted file mode 100644 index ac6717fbb764..000000000000 --- a/drivers/media/platform/vim2m.c +++ /dev/null @@ -1,1441 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * A virtual v4l2-mem2mem example device. - * - * This is a virtual device driver for testing mem-to-mem videobuf framework. - * It simulates a device that uses memory buffers for both source and - * destination, processes the data and issues an "irq" (simulated by a delayed - * workqueue). - * The device is capable of multi-instance, multi-buffer-per-transaction - * operation (via the mem2mem framework). - * - * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd. - * Pawel Osciak, - * Marek Szyprowski, - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the - * License, or (at your option) any later version - */ -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -MODULE_DESCRIPTION("Virtual device for mem2mem framework testing"); -MODULE_AUTHOR("Pawel Osciak, "); -MODULE_LICENSE("GPL"); -MODULE_VERSION("0.2"); -MODULE_ALIAS("mem2mem_testdev"); - -static unsigned int debug; -module_param(debug, uint, 0644); -MODULE_PARM_DESC(debug, "debug level"); - -/* Default transaction time in msec */ -static unsigned int default_transtime = 40; /* Max 25 fps */ -module_param(default_transtime, uint, 0644); -MODULE_PARM_DESC(default_transtime, "default transaction time in ms"); - -#define MIN_W 32 -#define MIN_H 32 -#define MAX_W 640 -#define MAX_H 480 - -/* Pixel alignment for non-bayer formats */ -#define WIDTH_ALIGN 2 -#define HEIGHT_ALIGN 1 - -/* Pixel alignment for bayer formats */ -#define BAYER_WIDTH_ALIGN 2 -#define BAYER_HEIGHT_ALIGN 2 - -/* Flags that indicate a format can be used for capture/output */ -#define MEM2MEM_CAPTURE BIT(0) -#define MEM2MEM_OUTPUT BIT(1) - -#define MEM2MEM_NAME "vim2m" - -/* Per queue */ -#define MEM2MEM_DEF_NUM_BUFS VIDEO_MAX_FRAME -/* In bytes, per queue */ -#define MEM2MEM_VID_MEM_LIMIT (16 * 1024 * 1024) - -/* Flags that indicate processing mode */ -#define MEM2MEM_HFLIP BIT(0) -#define MEM2MEM_VFLIP BIT(1) - -#define dprintk(dev, lvl, fmt, arg...) \ - v4l2_dbg(lvl, debug, &(dev)->v4l2_dev, "%s: " fmt, __func__, ## arg) - -static void vim2m_dev_release(struct device *dev) -{} - -static struct platform_device vim2m_pdev = { - .name = MEM2MEM_NAME, - .dev.release = vim2m_dev_release, -}; - -struct vim2m_fmt { - u32 fourcc; - int depth; - /* Types the format can be used for */ - u32 types; -}; - -static struct vim2m_fmt formats[] = { - { - .fourcc = V4L2_PIX_FMT_RGB565, /* rrrrrggg gggbbbbb */ - .depth = 16, - .types = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT, - }, { - .fourcc = V4L2_PIX_FMT_RGB565X, /* gggbbbbb rrrrrggg */ - .depth = 16, - .types = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT, - }, { - .fourcc = V4L2_PIX_FMT_RGB24, - .depth = 24, - .types = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT, - }, { - .fourcc = V4L2_PIX_FMT_BGR24, - .depth = 24, - .types = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT, - }, { - .fourcc = V4L2_PIX_FMT_YUYV, - .depth = 16, - .types = MEM2MEM_CAPTURE, - }, { - .fourcc = V4L2_PIX_FMT_SBGGR8, - .depth = 8, - .types = MEM2MEM_CAPTURE, - }, { - .fourcc = V4L2_PIX_FMT_SGBRG8, - .depth = 8, - .types = MEM2MEM_CAPTURE, - }, { - .fourcc = V4L2_PIX_FMT_SGRBG8, - .depth = 8, - .types = MEM2MEM_CAPTURE, - }, { - .fourcc = V4L2_PIX_FMT_SRGGB8, - .depth = 8, - .types = MEM2MEM_CAPTURE, - }, -}; - -#define NUM_FORMATS ARRAY_SIZE(formats) - -/* Per-queue, driver-specific private data */ -struct vim2m_q_data { - unsigned int width; - unsigned int height; - unsigned int sizeimage; - unsigned int sequence; - struct vim2m_fmt *fmt; -}; - -enum { - V4L2_M2M_SRC = 0, - V4L2_M2M_DST = 1, -}; - -#define V4L2_CID_TRANS_TIME_MSEC (V4L2_CID_USER_BASE + 0x1000) -#define V4L2_CID_TRANS_NUM_BUFS (V4L2_CID_USER_BASE + 0x1001) - -static struct vim2m_fmt *find_format(u32 fourcc) -{ - struct vim2m_fmt *fmt; - unsigned int k; - - for (k = 0; k < NUM_FORMATS; k++) { - fmt = &formats[k]; - if (fmt->fourcc == fourcc) - break; - } - - if (k == NUM_FORMATS) - return NULL; - - return &formats[k]; -} - -static void get_alignment(u32 fourcc, - unsigned int *walign, unsigned int *halign) -{ - switch (fourcc) { - case V4L2_PIX_FMT_SBGGR8: - case V4L2_PIX_FMT_SGBRG8: - case V4L2_PIX_FMT_SGRBG8: - case V4L2_PIX_FMT_SRGGB8: - *walign = BAYER_WIDTH_ALIGN; - *halign = BAYER_HEIGHT_ALIGN; - return; - default: - *walign = WIDTH_ALIGN; - *halign = HEIGHT_ALIGN; - return; - } -} - -struct vim2m_dev { - struct v4l2_device v4l2_dev; - struct video_device vfd; -#ifdef CONFIG_MEDIA_CONTROLLER - struct media_device mdev; -#endif - - atomic_t num_inst; - struct mutex dev_mutex; - - struct v4l2_m2m_dev *m2m_dev; -}; - -struct vim2m_ctx { - struct v4l2_fh fh; - struct vim2m_dev *dev; - - struct v4l2_ctrl_handler hdl; - - /* Processed buffers in this transaction */ - u8 num_processed; - - /* Transaction length (i.e. how many buffers per transaction) */ - u32 translen; - /* Transaction time (i.e. simulated processing time) in milliseconds */ - u32 transtime; - - struct mutex vb_mutex; - struct delayed_work work_run; - spinlock_t irqlock; - - /* Abort requested by m2m */ - int aborting; - - /* Processing mode */ - int mode; - - enum v4l2_colorspace colorspace; - enum v4l2_ycbcr_encoding ycbcr_enc; - enum v4l2_xfer_func xfer_func; - enum v4l2_quantization quant; - - /* Source and destination queue data */ - struct vim2m_q_data q_data[2]; -}; - -static inline struct vim2m_ctx *file2ctx(struct file *file) -{ - return container_of(file->private_data, struct vim2m_ctx, fh); -} - -static struct vim2m_q_data *get_q_data(struct vim2m_ctx *ctx, - enum v4l2_buf_type type) -{ - switch (type) { - case V4L2_BUF_TYPE_VIDEO_OUTPUT: - return &ctx->q_data[V4L2_M2M_SRC]; - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - return &ctx->q_data[V4L2_M2M_DST]; - default: - return NULL; - } -} - -static const char *type_name(enum v4l2_buf_type type) -{ - switch (type) { - case V4L2_BUF_TYPE_VIDEO_OUTPUT: - return "Output"; - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - return "Capture"; - default: - return "Invalid"; - } -} - -#define CLIP(__color) \ - (u8)(((__color) > 0xff) ? 0xff : (((__color) < 0) ? 0 : (__color))) - -static void copy_line(struct vim2m_q_data *q_data_out, - u8 *src, u8 *dst, bool reverse) -{ - int x, depth = q_data_out->fmt->depth >> 3; - - if (!reverse) { - memcpy(dst, src, q_data_out->width * depth); - } else { - for (x = 0; x < q_data_out->width >> 1; x++) { - memcpy(dst, src, depth); - memcpy(dst + depth, src - depth, depth); - src -= depth << 1; - dst += depth << 1; - } - return; - } -} - -static void copy_two_pixels(struct vim2m_q_data *q_data_in, - struct vim2m_q_data *q_data_out, - u8 *src[2], u8 **dst, int ypos, bool reverse) -{ - struct vim2m_fmt *out = q_data_out->fmt; - struct vim2m_fmt *in = q_data_in->fmt; - u8 _r[2], _g[2], _b[2], *r, *g, *b; - int i; - - /* Step 1: read two consecutive pixels from src pointer */ - - r = _r; - g = _g; - b = _b; - - switch (in->fourcc) { - case V4L2_PIX_FMT_RGB565: /* rrrrrggg gggbbbbb */ - for (i = 0; i < 2; i++) { - u16 pix = le16_to_cpu(*(__le16 *)(src[i])); - - *r++ = (u8)(((pix & 0xf800) >> 11) << 3) | 0x07; - *g++ = (u8)((((pix & 0x07e0) >> 5)) << 2) | 0x03; - *b++ = (u8)((pix & 0x1f) << 3) | 0x07; - } - break; - case V4L2_PIX_FMT_RGB565X: /* gggbbbbb rrrrrggg */ - for (i = 0; i < 2; i++) { - u16 pix = be16_to_cpu(*(__be16 *)(src[i])); - - *r++ = (u8)(((pix & 0xf800) >> 11) << 3) | 0x07; - *g++ = (u8)((((pix & 0x07e0) >> 5)) << 2) | 0x03; - *b++ = (u8)((pix & 0x1f) << 3) | 0x07; - } - break; - default: - case V4L2_PIX_FMT_RGB24: - for (i = 0; i < 2; i++) { - *r++ = src[i][0]; - *g++ = src[i][1]; - *b++ = src[i][2]; - } - break; - case V4L2_PIX_FMT_BGR24: - for (i = 0; i < 2; i++) { - *b++ = src[i][0]; - *g++ = src[i][1]; - *r++ = src[i][2]; - } - break; - } - - /* Step 2: store two consecutive points, reversing them if needed */ - - r = _r; - g = _g; - b = _b; - - switch (out->fourcc) { - case V4L2_PIX_FMT_RGB565: /* rrrrrggg gggbbbbb */ - for (i = 0; i < 2; i++) { - u16 pix; - __le16 *dst_pix = (__le16 *)*dst; - - pix = ((*r << 8) & 0xf800) | ((*g << 3) & 0x07e0) | - (*b >> 3); - - *dst_pix = cpu_to_le16(pix); - - *dst += 2; - } - return; - case V4L2_PIX_FMT_RGB565X: /* gggbbbbb rrrrrggg */ - for (i = 0; i < 2; i++) { - u16 pix; - __be16 *dst_pix = (__be16 *)*dst; - - pix = ((*r << 8) & 0xf800) | ((*g << 3) & 0x07e0) | - (*b >> 3); - - *dst_pix = cpu_to_be16(pix); - - *dst += 2; - } - return; - case V4L2_PIX_FMT_RGB24: - for (i = 0; i < 2; i++) { - *(*dst)++ = *r++; - *(*dst)++ = *g++; - *(*dst)++ = *b++; - } - return; - case V4L2_PIX_FMT_BGR24: - for (i = 0; i < 2; i++) { - *(*dst)++ = *b++; - *(*dst)++ = *g++; - *(*dst)++ = *r++; - } - return; - case V4L2_PIX_FMT_YUYV: - default: - { - u8 y, y1, u, v; - - y = ((8453 * (*r) + 16594 * (*g) + 3223 * (*b) - + 524288) >> 15); - u = ((-4878 * (*r) - 9578 * (*g) + 14456 * (*b) - + 4210688) >> 15); - v = ((14456 * (*r++) - 12105 * (*g++) - 2351 * (*b++) - + 4210688) >> 15); - y1 = ((8453 * (*r) + 16594 * (*g) + 3223 * (*b) - + 524288) >> 15); - - *(*dst)++ = y; - *(*dst)++ = u; - - *(*dst)++ = y1; - *(*dst)++ = v; - return; - } - case V4L2_PIX_FMT_SBGGR8: - if (!(ypos & 1)) { - *(*dst)++ = *b; - *(*dst)++ = *++g; - } else { - *(*dst)++ = *g; - *(*dst)++ = *++r; - } - return; - case V4L2_PIX_FMT_SGBRG8: - if (!(ypos & 1)) { - *(*dst)++ = *g; - *(*dst)++ = *++b; - } else { - *(*dst)++ = *r; - *(*dst)++ = *++g; - } - return; - case V4L2_PIX_FMT_SGRBG8: - if (!(ypos & 1)) { - *(*dst)++ = *g; - *(*dst)++ = *++r; - } else { - *(*dst)++ = *b; - *(*dst)++ = *++g; - } - return; - case V4L2_PIX_FMT_SRGGB8: - if (!(ypos & 1)) { - *(*dst)++ = *r; - *(*dst)++ = *++g; - } else { - *(*dst)++ = *g; - *(*dst)++ = *++b; - } - return; - } -} - -static int device_process(struct vim2m_ctx *ctx, - struct vb2_v4l2_buffer *in_vb, - struct vb2_v4l2_buffer *out_vb) -{ - struct vim2m_dev *dev = ctx->dev; - struct vim2m_q_data *q_data_in, *q_data_out; - u8 *p_in, *p_line, *p_in_x[2], *p, *p_out; - unsigned int width, height, bytesperline, bytes_per_pixel; - unsigned int x, y, y_in, y_out, x_int, x_fract, x_err, x_offset; - int start, end, step; - - q_data_in = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); - if (!q_data_in) - return 0; - bytesperline = (q_data_in->width * q_data_in->fmt->depth) >> 3; - bytes_per_pixel = q_data_in->fmt->depth >> 3; - - q_data_out = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); - if (!q_data_out) - return 0; - - /* As we're doing scaling, use the output dimensions here */ - height = q_data_out->height; - width = q_data_out->width; - - p_in = vb2_plane_vaddr(&in_vb->vb2_buf, 0); - p_out = vb2_plane_vaddr(&out_vb->vb2_buf, 0); - if (!p_in || !p_out) { - v4l2_err(&dev->v4l2_dev, - "Acquiring kernel pointers to buffers failed\n"); - return -EFAULT; - } - - out_vb->sequence = q_data_out->sequence++; - in_vb->sequence = q_data_in->sequence++; - v4l2_m2m_buf_copy_metadata(in_vb, out_vb, true); - - if (ctx->mode & MEM2MEM_VFLIP) { - start = height - 1; - end = -1; - step = -1; - } else { - start = 0; - end = height; - step = 1; - } - y_out = 0; - - /* - * When format and resolution are identical, - * we can use a faster copy logic - */ - if (q_data_in->fmt->fourcc == q_data_out->fmt->fourcc && - q_data_in->width == q_data_out->width && - q_data_in->height == q_data_out->height) { - for (y = start; y != end; y += step, y_out++) { - p = p_in + (y * bytesperline); - if (ctx->mode & MEM2MEM_HFLIP) - p += bytesperline - (q_data_in->fmt->depth >> 3); - - copy_line(q_data_out, p, p_out, - ctx->mode & MEM2MEM_HFLIP); - - p_out += bytesperline; - } - return 0; - } - - /* Slower algorithm with format conversion, hflip, vflip and scaler */ - - /* To speed scaler up, use Bresenham for X dimension */ - x_int = q_data_in->width / q_data_out->width; - x_fract = q_data_in->width % q_data_out->width; - - for (y = start; y != end; y += step, y_out++) { - y_in = (y * q_data_in->height) / q_data_out->height; - x_offset = 0; - x_err = 0; - - p_line = p_in + (y_in * bytesperline); - if (ctx->mode & MEM2MEM_HFLIP) - p_line += bytesperline - (q_data_in->fmt->depth >> 3); - p_in_x[0] = p_line; - - for (x = 0; x < width >> 1; x++) { - x_offset += x_int; - x_err += x_fract; - if (x_err > width) { - x_offset++; - x_err -= width; - } - - if (ctx->mode & MEM2MEM_HFLIP) - p_in_x[1] = p_line - x_offset * bytes_per_pixel; - else - p_in_x[1] = p_line + x_offset * bytes_per_pixel; - - copy_two_pixels(q_data_in, q_data_out, - p_in_x, &p_out, y_out, - ctx->mode & MEM2MEM_HFLIP); - - /* Calculate the next p_in_x0 */ - x_offset += x_int; - x_err += x_fract; - if (x_err > width) { - x_offset++; - x_err -= width; - } - - if (ctx->mode & MEM2MEM_HFLIP) - p_in_x[0] = p_line - x_offset * bytes_per_pixel; - else - p_in_x[0] = p_line + x_offset * bytes_per_pixel; - } - } - - return 0; -} - -/* - * mem2mem callbacks - */ - -/* - * job_ready() - check whether an instance is ready to be scheduled to run - */ -static int job_ready(void *priv) -{ - struct vim2m_ctx *ctx = priv; - - if (v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) < ctx->translen - || v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx) < ctx->translen) { - dprintk(ctx->dev, 1, "Not enough buffers available\n"); - return 0; - } - - return 1; -} - -static void job_abort(void *priv) -{ - struct vim2m_ctx *ctx = priv; - - /* Will cancel the transaction in the next interrupt handler */ - ctx->aborting = 1; -} - -/* device_run() - prepares and starts the device - * - * This simulates all the immediate preparations required before starting - * a device. This will be called by the framework when it decides to schedule - * a particular instance. - */ -static void device_run(void *priv) -{ - struct vim2m_ctx *ctx = priv; - struct vb2_v4l2_buffer *src_buf, *dst_buf; - - src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); - dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); - - /* Apply request controls if any */ - v4l2_ctrl_request_setup(src_buf->vb2_buf.req_obj.req, - &ctx->hdl); - - device_process(ctx, src_buf, dst_buf); - - /* Complete request controls if any */ - v4l2_ctrl_request_complete(src_buf->vb2_buf.req_obj.req, - &ctx->hdl); - - /* Run delayed work, which simulates a hardware irq */ - schedule_delayed_work(&ctx->work_run, msecs_to_jiffies(ctx->transtime)); -} - -static void device_work(struct work_struct *w) -{ - struct vim2m_ctx *curr_ctx; - struct vim2m_dev *vim2m_dev; - struct vb2_v4l2_buffer *src_vb, *dst_vb; - unsigned long flags; - - curr_ctx = container_of(w, struct vim2m_ctx, work_run.work); - - if (!curr_ctx) { - pr_err("Instance released before the end of transaction\n"); - return; - } - - vim2m_dev = curr_ctx->dev; - - src_vb = v4l2_m2m_src_buf_remove(curr_ctx->fh.m2m_ctx); - dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->fh.m2m_ctx); - - curr_ctx->num_processed++; - - spin_lock_irqsave(&curr_ctx->irqlock, flags); - v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_DONE); - v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_DONE); - spin_unlock_irqrestore(&curr_ctx->irqlock, flags); - - if (curr_ctx->num_processed == curr_ctx->translen - || curr_ctx->aborting) { - dprintk(curr_ctx->dev, 2, "Finishing capture buffer fill\n"); - curr_ctx->num_processed = 0; - v4l2_m2m_job_finish(vim2m_dev->m2m_dev, curr_ctx->fh.m2m_ctx); - } else { - device_run(curr_ctx); - } -} - -/* - * video ioctls - */ -static int vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - strscpy(cap->driver, MEM2MEM_NAME, sizeof(cap->driver)); - strscpy(cap->card, MEM2MEM_NAME, sizeof(cap->card)); - snprintf(cap->bus_info, sizeof(cap->bus_info), - "platform:%s", MEM2MEM_NAME); - return 0; -} - -static int enum_fmt(struct v4l2_fmtdesc *f, u32 type) -{ - int i, num; - struct vim2m_fmt *fmt; - - num = 0; - - for (i = 0; i < NUM_FORMATS; ++i) { - if (formats[i].types & type) { - /* index-th format of type type found ? */ - if (num == f->index) - break; - /* - * Correct type but haven't reached our index yet, - * just increment per-type index - */ - ++num; - } - } - - if (i < NUM_FORMATS) { - /* Format found */ - fmt = &formats[i]; - f->pixelformat = fmt->fourcc; - return 0; - } - - /* Format not found */ - return -EINVAL; -} - -static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - return enum_fmt(f, MEM2MEM_CAPTURE); -} - -static int vidioc_enum_fmt_vid_out(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - return enum_fmt(f, MEM2MEM_OUTPUT); -} - -static int vidioc_enum_framesizes(struct file *file, void *priv, - struct v4l2_frmsizeenum *fsize) -{ - if (fsize->index != 0) - return -EINVAL; - - if (!find_format(fsize->pixel_format)) - return -EINVAL; - - fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; - fsize->stepwise.min_width = MIN_W; - fsize->stepwise.min_height = MIN_H; - fsize->stepwise.max_width = MAX_W; - fsize->stepwise.max_height = MAX_H; - - get_alignment(fsize->pixel_format, - &fsize->stepwise.step_width, - &fsize->stepwise.step_height); - return 0; -} - -static int vidioc_g_fmt(struct vim2m_ctx *ctx, struct v4l2_format *f) -{ - struct vb2_queue *vq; - struct vim2m_q_data *q_data; - - vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); - if (!vq) - return -EINVAL; - - q_data = get_q_data(ctx, f->type); - if (!q_data) - return -EINVAL; - - f->fmt.pix.width = q_data->width; - f->fmt.pix.height = q_data->height; - f->fmt.pix.field = V4L2_FIELD_NONE; - f->fmt.pix.pixelformat = q_data->fmt->fourcc; - f->fmt.pix.bytesperline = (q_data->width * q_data->fmt->depth) >> 3; - f->fmt.pix.sizeimage = q_data->sizeimage; - f->fmt.pix.colorspace = ctx->colorspace; - f->fmt.pix.xfer_func = ctx->xfer_func; - f->fmt.pix.ycbcr_enc = ctx->ycbcr_enc; - f->fmt.pix.quantization = ctx->quant; - - return 0; -} - -static int vidioc_g_fmt_vid_out(struct file *file, void *priv, - struct v4l2_format *f) -{ - return vidioc_g_fmt(file2ctx(file), f); -} - -static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - return vidioc_g_fmt(file2ctx(file), f); -} - -static int vidioc_try_fmt(struct v4l2_format *f, struct vim2m_fmt *fmt) -{ - int walign, halign; - /* - * V4L2 specification specifies the driver corrects the - * format struct if any of the dimensions is unsupported - */ - if (f->fmt.pix.height < MIN_H) - f->fmt.pix.height = MIN_H; - else if (f->fmt.pix.height > MAX_H) - f->fmt.pix.height = MAX_H; - - if (f->fmt.pix.width < MIN_W) - f->fmt.pix.width = MIN_W; - else if (f->fmt.pix.width > MAX_W) - f->fmt.pix.width = MAX_W; - - get_alignment(f->fmt.pix.pixelformat, &walign, &halign); - f->fmt.pix.width &= ~(walign - 1); - f->fmt.pix.height &= ~(halign - 1); - f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3; - f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; - f->fmt.pix.field = V4L2_FIELD_NONE; - - return 0; -} - -static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct vim2m_fmt *fmt; - struct vim2m_ctx *ctx = file2ctx(file); - - fmt = find_format(f->fmt.pix.pixelformat); - if (!fmt) { - f->fmt.pix.pixelformat = formats[0].fourcc; - fmt = find_format(f->fmt.pix.pixelformat); - } - if (!(fmt->types & MEM2MEM_CAPTURE)) { - v4l2_err(&ctx->dev->v4l2_dev, - "Fourcc format (0x%08x) invalid.\n", - f->fmt.pix.pixelformat); - return -EINVAL; - } - f->fmt.pix.colorspace = ctx->colorspace; - f->fmt.pix.xfer_func = ctx->xfer_func; - f->fmt.pix.ycbcr_enc = ctx->ycbcr_enc; - f->fmt.pix.quantization = ctx->quant; - - return vidioc_try_fmt(f, fmt); -} - -static int vidioc_try_fmt_vid_out(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct vim2m_fmt *fmt; - struct vim2m_ctx *ctx = file2ctx(file); - - fmt = find_format(f->fmt.pix.pixelformat); - if (!fmt) { - f->fmt.pix.pixelformat = formats[0].fourcc; - fmt = find_format(f->fmt.pix.pixelformat); - } - if (!(fmt->types & MEM2MEM_OUTPUT)) { - v4l2_err(&ctx->dev->v4l2_dev, - "Fourcc format (0x%08x) invalid.\n", - f->fmt.pix.pixelformat); - return -EINVAL; - } - if (!f->fmt.pix.colorspace) - f->fmt.pix.colorspace = V4L2_COLORSPACE_REC709; - - return vidioc_try_fmt(f, fmt); -} - -static int vidioc_s_fmt(struct vim2m_ctx *ctx, struct v4l2_format *f) -{ - struct vim2m_q_data *q_data; - struct vb2_queue *vq; - - vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); - if (!vq) - return -EINVAL; - - q_data = get_q_data(ctx, f->type); - if (!q_data) - return -EINVAL; - - if (vb2_is_busy(vq)) { - v4l2_err(&ctx->dev->v4l2_dev, "%s queue busy\n", __func__); - return -EBUSY; - } - - q_data->fmt = find_format(f->fmt.pix.pixelformat); - q_data->width = f->fmt.pix.width; - q_data->height = f->fmt.pix.height; - q_data->sizeimage = q_data->width * q_data->height - * q_data->fmt->depth >> 3; - - dprintk(ctx->dev, 1, - "Format for type %s: %dx%d (%d bpp), fmt: %c%c%c%c\n", - type_name(f->type), q_data->width, q_data->height, - q_data->fmt->depth, - (q_data->fmt->fourcc & 0xff), - (q_data->fmt->fourcc >> 8) & 0xff, - (q_data->fmt->fourcc >> 16) & 0xff, - (q_data->fmt->fourcc >> 24) & 0xff); - - return 0; -} - -static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - int ret; - - ret = vidioc_try_fmt_vid_cap(file, priv, f); - if (ret) - return ret; - - return vidioc_s_fmt(file2ctx(file), f); -} - -static int vidioc_s_fmt_vid_out(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct vim2m_ctx *ctx = file2ctx(file); - int ret; - - ret = vidioc_try_fmt_vid_out(file, priv, f); - if (ret) - return ret; - - ret = vidioc_s_fmt(file2ctx(file), f); - if (!ret) { - ctx->colorspace = f->fmt.pix.colorspace; - ctx->xfer_func = f->fmt.pix.xfer_func; - ctx->ycbcr_enc = f->fmt.pix.ycbcr_enc; - ctx->quant = f->fmt.pix.quantization; - } - return ret; -} - -static int vim2m_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct vim2m_ctx *ctx = - container_of(ctrl->handler, struct vim2m_ctx, hdl); - - switch (ctrl->id) { - case V4L2_CID_HFLIP: - if (ctrl->val) - ctx->mode |= MEM2MEM_HFLIP; - else - ctx->mode &= ~MEM2MEM_HFLIP; - break; - - case V4L2_CID_VFLIP: - if (ctrl->val) - ctx->mode |= MEM2MEM_VFLIP; - else - ctx->mode &= ~MEM2MEM_VFLIP; - break; - - case V4L2_CID_TRANS_TIME_MSEC: - ctx->transtime = ctrl->val; - if (ctx->transtime < 1) - ctx->transtime = 1; - break; - - case V4L2_CID_TRANS_NUM_BUFS: - ctx->translen = ctrl->val; - break; - - default: - v4l2_err(&ctx->dev->v4l2_dev, "Invalid control\n"); - return -EINVAL; - } - - return 0; -} - -static const struct v4l2_ctrl_ops vim2m_ctrl_ops = { - .s_ctrl = vim2m_s_ctrl, -}; - -static const struct v4l2_ioctl_ops vim2m_ioctl_ops = { - .vidioc_querycap = vidioc_querycap, - - .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, - .vidioc_enum_framesizes = vidioc_enum_framesizes, - .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, - .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, - - .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out, - .vidioc_g_fmt_vid_out = vidioc_g_fmt_vid_out, - .vidioc_try_fmt_vid_out = vidioc_try_fmt_vid_out, - .vidioc_s_fmt_vid_out = vidioc_s_fmt_vid_out, - - .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, - .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, - .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, - .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, - .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf, - .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs, - .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, - - .vidioc_streamon = v4l2_m2m_ioctl_streamon, - .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, - - .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, - .vidioc_unsubscribe_event = v4l2_event_unsubscribe, -}; - -/* - * Queue operations - */ - -static int vim2m_queue_setup(struct vb2_queue *vq, - unsigned int *nbuffers, - unsigned int *nplanes, - unsigned int sizes[], - struct device *alloc_devs[]) -{ - struct vim2m_ctx *ctx = vb2_get_drv_priv(vq); - struct vim2m_q_data *q_data; - unsigned int size, count = *nbuffers; - - q_data = get_q_data(ctx, vq->type); - if (!q_data) - return -EINVAL; - - size = q_data->width * q_data->height * q_data->fmt->depth >> 3; - - while (size * count > MEM2MEM_VID_MEM_LIMIT) - (count)--; - *nbuffers = count; - - if (*nplanes) - return sizes[0] < size ? -EINVAL : 0; - - *nplanes = 1; - sizes[0] = size; - - dprintk(ctx->dev, 1, "%s: get %d buffer(s) of size %d each.\n", - type_name(vq->type), count, size); - - return 0; -} - -static int vim2m_buf_out_validate(struct vb2_buffer *vb) -{ - struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); - struct vim2m_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); - - if (vbuf->field == V4L2_FIELD_ANY) - vbuf->field = V4L2_FIELD_NONE; - if (vbuf->field != V4L2_FIELD_NONE) { - dprintk(ctx->dev, 1, "%s field isn't supported\n", __func__); - return -EINVAL; - } - - return 0; -} - -static int vim2m_buf_prepare(struct vb2_buffer *vb) -{ - struct vim2m_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); - struct vim2m_q_data *q_data; - - dprintk(ctx->dev, 2, "type: %s\n", type_name(vb->vb2_queue->type)); - - q_data = get_q_data(ctx, vb->vb2_queue->type); - if (!q_data) - return -EINVAL; - if (vb2_plane_size(vb, 0) < q_data->sizeimage) { - dprintk(ctx->dev, 1, - "%s data will not fit into plane (%lu < %lu)\n", - __func__, vb2_plane_size(vb, 0), - (long)q_data->sizeimage); - return -EINVAL; - } - - vb2_set_plane_payload(vb, 0, q_data->sizeimage); - - return 0; -} - -static void vim2m_buf_queue(struct vb2_buffer *vb) -{ - struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); - struct vim2m_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); - - v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); -} - -static int vim2m_start_streaming(struct vb2_queue *q, unsigned int count) -{ - struct vim2m_ctx *ctx = vb2_get_drv_priv(q); - struct vim2m_q_data *q_data = get_q_data(ctx, q->type); - - if (!q_data) - return -EINVAL; - - if (V4L2_TYPE_IS_OUTPUT(q->type)) - ctx->aborting = 0; - - q_data->sequence = 0; - return 0; -} - -static void vim2m_stop_streaming(struct vb2_queue *q) -{ - struct vim2m_ctx *ctx = vb2_get_drv_priv(q); - struct vb2_v4l2_buffer *vbuf; - unsigned long flags; - - cancel_delayed_work_sync(&ctx->work_run); - - for (;;) { - if (V4L2_TYPE_IS_OUTPUT(q->type)) - vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); - else - vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); - if (!vbuf) - return; - v4l2_ctrl_request_complete(vbuf->vb2_buf.req_obj.req, - &ctx->hdl); - spin_lock_irqsave(&ctx->irqlock, flags); - v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR); - spin_unlock_irqrestore(&ctx->irqlock, flags); - } -} - -static void vim2m_buf_request_complete(struct vb2_buffer *vb) -{ - struct vim2m_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); - - v4l2_ctrl_request_complete(vb->req_obj.req, &ctx->hdl); -} - -static const struct vb2_ops vim2m_qops = { - .queue_setup = vim2m_queue_setup, - .buf_out_validate = vim2m_buf_out_validate, - .buf_prepare = vim2m_buf_prepare, - .buf_queue = vim2m_buf_queue, - .start_streaming = vim2m_start_streaming, - .stop_streaming = vim2m_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, - .buf_request_complete = vim2m_buf_request_complete, -}; - -static int queue_init(void *priv, struct vb2_queue *src_vq, - struct vb2_queue *dst_vq) -{ - struct vim2m_ctx *ctx = priv; - int ret; - - src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; - src_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; - src_vq->drv_priv = ctx; - src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); - src_vq->ops = &vim2m_qops; - src_vq->mem_ops = &vb2_vmalloc_memops; - src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; - src_vq->lock = &ctx->vb_mutex; - src_vq->supports_requests = true; - - ret = vb2_queue_init(src_vq); - if (ret) - return ret; - - dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - dst_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; - dst_vq->drv_priv = ctx; - dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); - dst_vq->ops = &vim2m_qops; - dst_vq->mem_ops = &vb2_vmalloc_memops; - dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; - dst_vq->lock = &ctx->vb_mutex; - - return vb2_queue_init(dst_vq); -} - -static struct v4l2_ctrl_config vim2m_ctrl_trans_time_msec = { - .ops = &vim2m_ctrl_ops, - .id = V4L2_CID_TRANS_TIME_MSEC, - .name = "Transaction Time (msec)", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = 1, - .max = 10001, - .step = 1, -}; - -static const struct v4l2_ctrl_config vim2m_ctrl_trans_num_bufs = { - .ops = &vim2m_ctrl_ops, - .id = V4L2_CID_TRANS_NUM_BUFS, - .name = "Buffers Per Transaction", - .type = V4L2_CTRL_TYPE_INTEGER, - .def = 1, - .min = 1, - .max = MEM2MEM_DEF_NUM_BUFS, - .step = 1, -}; - -/* - * File operations - */ -static int vim2m_open(struct file *file) -{ - struct vim2m_dev *dev = video_drvdata(file); - struct vim2m_ctx *ctx = NULL; - struct v4l2_ctrl_handler *hdl; - int rc = 0; - - if (mutex_lock_interruptible(&dev->dev_mutex)) - return -ERESTARTSYS; - ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); - if (!ctx) { - rc = -ENOMEM; - goto open_unlock; - } - - v4l2_fh_init(&ctx->fh, video_devdata(file)); - file->private_data = &ctx->fh; - ctx->dev = dev; - hdl = &ctx->hdl; - v4l2_ctrl_handler_init(hdl, 4); - v4l2_ctrl_new_std(hdl, &vim2m_ctrl_ops, V4L2_CID_HFLIP, 0, 1, 1, 0); - v4l2_ctrl_new_std(hdl, &vim2m_ctrl_ops, V4L2_CID_VFLIP, 0, 1, 1, 0); - - vim2m_ctrl_trans_time_msec.def = default_transtime; - v4l2_ctrl_new_custom(hdl, &vim2m_ctrl_trans_time_msec, NULL); - v4l2_ctrl_new_custom(hdl, &vim2m_ctrl_trans_num_bufs, NULL); - if (hdl->error) { - rc = hdl->error; - v4l2_ctrl_handler_free(hdl); - kfree(ctx); - goto open_unlock; - } - ctx->fh.ctrl_handler = hdl; - v4l2_ctrl_handler_setup(hdl); - - ctx->q_data[V4L2_M2M_SRC].fmt = &formats[0]; - ctx->q_data[V4L2_M2M_SRC].width = 640; - ctx->q_data[V4L2_M2M_SRC].height = 480; - ctx->q_data[V4L2_M2M_SRC].sizeimage = - ctx->q_data[V4L2_M2M_SRC].width * - ctx->q_data[V4L2_M2M_SRC].height * - (ctx->q_data[V4L2_M2M_SRC].fmt->depth >> 3); - ctx->q_data[V4L2_M2M_DST] = ctx->q_data[V4L2_M2M_SRC]; - ctx->colorspace = V4L2_COLORSPACE_REC709; - - ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, &queue_init); - - mutex_init(&ctx->vb_mutex); - spin_lock_init(&ctx->irqlock); - INIT_DELAYED_WORK(&ctx->work_run, device_work); - - if (IS_ERR(ctx->fh.m2m_ctx)) { - rc = PTR_ERR(ctx->fh.m2m_ctx); - - v4l2_ctrl_handler_free(hdl); - v4l2_fh_exit(&ctx->fh); - kfree(ctx); - goto open_unlock; - } - - v4l2_fh_add(&ctx->fh); - atomic_inc(&dev->num_inst); - - dprintk(dev, 1, "Created instance: %p, m2m_ctx: %p\n", - ctx, ctx->fh.m2m_ctx); - -open_unlock: - mutex_unlock(&dev->dev_mutex); - return rc; -} - -static int vim2m_release(struct file *file) -{ - struct vim2m_dev *dev = video_drvdata(file); - struct vim2m_ctx *ctx = file2ctx(file); - - dprintk(dev, 1, "Releasing instance %p\n", ctx); - - v4l2_fh_del(&ctx->fh); - v4l2_fh_exit(&ctx->fh); - v4l2_ctrl_handler_free(&ctx->hdl); - mutex_lock(&dev->dev_mutex); - v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); - mutex_unlock(&dev->dev_mutex); - kfree(ctx); - - atomic_dec(&dev->num_inst); - - return 0; -} - -static void vim2m_device_release(struct video_device *vdev) -{ - struct vim2m_dev *dev = container_of(vdev, struct vim2m_dev, vfd); - - v4l2_device_unregister(&dev->v4l2_dev); - v4l2_m2m_release(dev->m2m_dev); -#ifdef CONFIG_MEDIA_CONTROLLER - media_device_cleanup(&dev->mdev); -#endif - kfree(dev); -} - -static const struct v4l2_file_operations vim2m_fops = { - .owner = THIS_MODULE, - .open = vim2m_open, - .release = vim2m_release, - .poll = v4l2_m2m_fop_poll, - .unlocked_ioctl = video_ioctl2, - .mmap = v4l2_m2m_fop_mmap, -}; - -static const struct video_device vim2m_videodev = { - .name = MEM2MEM_NAME, - .vfl_dir = VFL_DIR_M2M, - .fops = &vim2m_fops, - .ioctl_ops = &vim2m_ioctl_ops, - .minor = -1, - .release = vim2m_device_release, - .device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING, -}; - -static const struct v4l2_m2m_ops m2m_ops = { - .device_run = device_run, - .job_ready = job_ready, - .job_abort = job_abort, -}; - -static const struct media_device_ops m2m_media_ops = { - .req_validate = vb2_request_validate, - .req_queue = v4l2_m2m_request_queue, -}; - -static int vim2m_probe(struct platform_device *pdev) -{ - struct vim2m_dev *dev; - struct video_device *vfd; - int ret; - - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) - return -ENOMEM; - - ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); - if (ret) - goto error_free; - - atomic_set(&dev->num_inst, 0); - mutex_init(&dev->dev_mutex); - - dev->vfd = vim2m_videodev; - vfd = &dev->vfd; - vfd->lock = &dev->dev_mutex; - vfd->v4l2_dev = &dev->v4l2_dev; - - ret = video_register_device(vfd, VFL_TYPE_VIDEO, 0); - if (ret) { - v4l2_err(&dev->v4l2_dev, "Failed to register video device\n"); - goto error_v4l2; - } - - video_set_drvdata(vfd, dev); - v4l2_info(&dev->v4l2_dev, - "Device registered as /dev/video%d\n", vfd->num); - - platform_set_drvdata(pdev, dev); - - dev->m2m_dev = v4l2_m2m_init(&m2m_ops); - if (IS_ERR(dev->m2m_dev)) { - v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem device\n"); - ret = PTR_ERR(dev->m2m_dev); - dev->m2m_dev = NULL; - goto error_dev; - } - -#ifdef CONFIG_MEDIA_CONTROLLER - dev->mdev.dev = &pdev->dev; - strscpy(dev->mdev.model, "vim2m", sizeof(dev->mdev.model)); - strscpy(dev->mdev.bus_info, "platform:vim2m", - sizeof(dev->mdev.bus_info)); - media_device_init(&dev->mdev); - dev->mdev.ops = &m2m_media_ops; - dev->v4l2_dev.mdev = &dev->mdev; - - ret = v4l2_m2m_register_media_controller(dev->m2m_dev, vfd, - MEDIA_ENT_F_PROC_VIDEO_SCALER); - if (ret) { - v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem media controller\n"); - goto error_dev; - } - - ret = media_device_register(&dev->mdev); - if (ret) { - v4l2_err(&dev->v4l2_dev, "Failed to register mem2mem media device\n"); - goto error_m2m_mc; - } -#endif - return 0; - -#ifdef CONFIG_MEDIA_CONTROLLER -error_m2m_mc: - v4l2_m2m_unregister_media_controller(dev->m2m_dev); -#endif -error_dev: - video_unregister_device(&dev->vfd); - /* vim2m_device_release called by video_unregister_device to release various objects */ - return ret; -error_v4l2: - v4l2_device_unregister(&dev->v4l2_dev); -error_free: - kfree(dev); - - return ret; -} - -static int vim2m_remove(struct platform_device *pdev) -{ - struct vim2m_dev *dev = platform_get_drvdata(pdev); - - v4l2_info(&dev->v4l2_dev, "Removing " MEM2MEM_NAME); - -#ifdef CONFIG_MEDIA_CONTROLLER - media_device_unregister(&dev->mdev); - v4l2_m2m_unregister_media_controller(dev->m2m_dev); -#endif - video_unregister_device(&dev->vfd); - - return 0; -} - -static struct platform_driver vim2m_pdrv = { - .probe = vim2m_probe, - .remove = vim2m_remove, - .driver = { - .name = MEM2MEM_NAME, - }, -}; - -static void __exit vim2m_exit(void) -{ - platform_driver_unregister(&vim2m_pdrv); - platform_device_unregister(&vim2m_pdev); -} - -static int __init vim2m_init(void) -{ - int ret; - - ret = platform_device_register(&vim2m_pdev); - if (ret) - return ret; - - ret = platform_driver_register(&vim2m_pdrv); - if (ret) - platform_device_unregister(&vim2m_pdev); - - return ret; -} - -module_init(vim2m_init); -module_exit(vim2m_exit); diff --git a/drivers/media/platform/vimc/Kconfig b/drivers/media/platform/vimc/Kconfig deleted file mode 100644 index bd221d3e1a4a..000000000000 --- a/drivers/media/platform/vimc/Kconfig +++ /dev/null @@ -1,15 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -config VIDEO_VIMC - tristate "Virtual Media Controller Driver (VIMC)" - depends on VIDEO_DEV && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API - select VIDEOBUF2_VMALLOC - select VIDEO_V4L2_TPG - help - Skeleton driver for Virtual Media Controller - - This driver can be compared to the vivid driver for emulating - a media node that exposes a complex media topology. The topology - is hard coded for now but is meant to be highly configurable in - the future. - - When in doubt, say N. diff --git a/drivers/media/platform/vimc/Makefile b/drivers/media/platform/vimc/Makefile deleted file mode 100644 index a53b2b532e9f..000000000000 --- a/drivers/media/platform/vimc/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -vimc-y := vimc-core.o vimc-common.o vimc-streamer.o vimc-capture.o \ - vimc-debayer.o vimc-scaler.o vimc-sensor.o - -obj-$(CONFIG_VIDEO_VIMC) += vimc.o - diff --git a/drivers/media/platform/vimc/vimc-capture.c b/drivers/media/platform/vimc/vimc-capture.c deleted file mode 100644 index 23e740c1c5c0..000000000000 --- a/drivers/media/platform/vimc/vimc-capture.c +++ /dev/null @@ -1,480 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * vimc-capture.c Virtual Media Controller Driver - * - * Copyright (C) 2015-2017 Helen Koike - */ - -#include -#include -#include - -#include "vimc-common.h" -#include "vimc-streamer.h" - -struct vimc_cap_device { - struct vimc_ent_device ved; - struct video_device vdev; - struct v4l2_pix_format format; - struct vb2_queue queue; - struct list_head buf_list; - /* - * NOTE: in a real driver, a spin lock must be used to access the - * queue because the frames are generated from a hardware interruption - * and the isr is not allowed to sleep. - * Even if it is not necessary a spinlock in the vimc driver, we - * use it here as a code reference - */ - spinlock_t qlock; - struct mutex lock; - u32 sequence; - struct vimc_stream stream; - struct media_pad pad; -}; - -static const struct v4l2_pix_format fmt_default = { - .width = 640, - .height = 480, - .pixelformat = V4L2_PIX_FMT_RGB24, - .field = V4L2_FIELD_NONE, - .colorspace = V4L2_COLORSPACE_DEFAULT, -}; - -struct vimc_cap_buffer { - /* - * struct vb2_v4l2_buffer must be the first element - * the videobuf2 framework will allocate this struct based on - * buf_struct_size and use the first sizeof(struct vb2_buffer) bytes of - * memory as a vb2_buffer - */ - struct vb2_v4l2_buffer vb2; - struct list_head list; -}; - -static int vimc_cap_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - strscpy(cap->driver, VIMC_PDEV_NAME, sizeof(cap->driver)); - strscpy(cap->card, KBUILD_MODNAME, sizeof(cap->card)); - snprintf(cap->bus_info, sizeof(cap->bus_info), - "platform:%s", VIMC_PDEV_NAME); - - return 0; -} - -static void vimc_cap_get_format(struct vimc_ent_device *ved, - struct v4l2_pix_format *fmt) -{ - struct vimc_cap_device *vcap = container_of(ved, struct vimc_cap_device, - ved); - - *fmt = vcap->format; -} - -static int vimc_cap_g_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct vimc_cap_device *vcap = video_drvdata(file); - - f->fmt.pix = vcap->format; - - return 0; -} - -static int vimc_cap_try_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct v4l2_pix_format *format = &f->fmt.pix; - const struct vimc_pix_map *vpix; - - format->width = clamp_t(u32, format->width, VIMC_FRAME_MIN_WIDTH, - VIMC_FRAME_MAX_WIDTH) & ~1; - format->height = clamp_t(u32, format->height, VIMC_FRAME_MIN_HEIGHT, - VIMC_FRAME_MAX_HEIGHT) & ~1; - - /* Don't accept a pixelformat that is not on the table */ - vpix = vimc_pix_map_by_pixelformat(format->pixelformat); - if (!vpix) { - format->pixelformat = fmt_default.pixelformat; - vpix = vimc_pix_map_by_pixelformat(format->pixelformat); - } - /* TODO: Add support for custom bytesperline values */ - format->bytesperline = format->width * vpix->bpp; - format->sizeimage = format->bytesperline * format->height; - - if (format->field == V4L2_FIELD_ANY) - format->field = fmt_default.field; - - vimc_colorimetry_clamp(format); - - return 0; -} - -static int vimc_cap_s_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct vimc_cap_device *vcap = video_drvdata(file); - int ret; - - /* Do not change the format while stream is on */ - if (vb2_is_busy(&vcap->queue)) - return -EBUSY; - - ret = vimc_cap_try_fmt_vid_cap(file, priv, f); - if (ret) - return ret; - - dev_dbg(vcap->ved.dev, "%s: format update: " - "old:%dx%d (0x%x, %d, %d, %d, %d) " - "new:%dx%d (0x%x, %d, %d, %d, %d)\n", vcap->vdev.name, - /* old */ - vcap->format.width, vcap->format.height, - vcap->format.pixelformat, vcap->format.colorspace, - vcap->format.quantization, vcap->format.xfer_func, - vcap->format.ycbcr_enc, - /* new */ - f->fmt.pix.width, f->fmt.pix.height, - f->fmt.pix.pixelformat, f->fmt.pix.colorspace, - f->fmt.pix.quantization, f->fmt.pix.xfer_func, - f->fmt.pix.ycbcr_enc); - - vcap->format = f->fmt.pix; - - return 0; -} - -static int vimc_cap_enum_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - const struct vimc_pix_map *vpix = vimc_pix_map_by_index(f->index); - - if (!vpix) - return -EINVAL; - - f->pixelformat = vpix->pixelformat; - - return 0; -} - -static int vimc_cap_enum_framesizes(struct file *file, void *fh, - struct v4l2_frmsizeenum *fsize) -{ - const struct vimc_pix_map *vpix; - - if (fsize->index) - return -EINVAL; - - /* Only accept code in the pix map table */ - vpix = vimc_pix_map_by_code(fsize->pixel_format); - if (!vpix) - return -EINVAL; - - fsize->type = V4L2_FRMSIZE_TYPE_CONTINUOUS; - fsize->stepwise.min_width = VIMC_FRAME_MIN_WIDTH; - fsize->stepwise.max_width = VIMC_FRAME_MAX_WIDTH; - fsize->stepwise.min_height = VIMC_FRAME_MIN_HEIGHT; - fsize->stepwise.max_height = VIMC_FRAME_MAX_HEIGHT; - fsize->stepwise.step_width = 1; - fsize->stepwise.step_height = 1; - - return 0; -} - -static const struct v4l2_file_operations vimc_cap_fops = { - .owner = THIS_MODULE, - .open = v4l2_fh_open, - .release = vb2_fop_release, - .read = vb2_fop_read, - .poll = vb2_fop_poll, - .unlocked_ioctl = video_ioctl2, - .mmap = vb2_fop_mmap, -}; - -static const struct v4l2_ioctl_ops vimc_cap_ioctl_ops = { - .vidioc_querycap = vimc_cap_querycap, - - .vidioc_g_fmt_vid_cap = vimc_cap_g_fmt_vid_cap, - .vidioc_s_fmt_vid_cap = vimc_cap_s_fmt_vid_cap, - .vidioc_try_fmt_vid_cap = vimc_cap_try_fmt_vid_cap, - .vidioc_enum_fmt_vid_cap = vimc_cap_enum_fmt_vid_cap, - .vidioc_enum_framesizes = vimc_cap_enum_framesizes, - - .vidioc_reqbufs = vb2_ioctl_reqbufs, - .vidioc_create_bufs = vb2_ioctl_create_bufs, - .vidioc_prepare_buf = vb2_ioctl_prepare_buf, - .vidioc_querybuf = vb2_ioctl_querybuf, - .vidioc_qbuf = vb2_ioctl_qbuf, - .vidioc_dqbuf = vb2_ioctl_dqbuf, - .vidioc_expbuf = vb2_ioctl_expbuf, - .vidioc_streamon = vb2_ioctl_streamon, - .vidioc_streamoff = vb2_ioctl_streamoff, -}; - -static void vimc_cap_return_all_buffers(struct vimc_cap_device *vcap, - enum vb2_buffer_state state) -{ - struct vimc_cap_buffer *vbuf, *node; - - spin_lock(&vcap->qlock); - - list_for_each_entry_safe(vbuf, node, &vcap->buf_list, list) { - list_del(&vbuf->list); - vb2_buffer_done(&vbuf->vb2.vb2_buf, state); - } - - spin_unlock(&vcap->qlock); -} - -static int vimc_cap_start_streaming(struct vb2_queue *vq, unsigned int count) -{ - struct vimc_cap_device *vcap = vb2_get_drv_priv(vq); - struct media_entity *entity = &vcap->vdev.entity; - int ret; - - vcap->sequence = 0; - - /* Start the media pipeline */ - ret = media_pipeline_start(entity, &vcap->stream.pipe); - if (ret) { - vimc_cap_return_all_buffers(vcap, VB2_BUF_STATE_QUEUED); - return ret; - } - - ret = vimc_streamer_s_stream(&vcap->stream, &vcap->ved, 1); - if (ret) { - media_pipeline_stop(entity); - vimc_cap_return_all_buffers(vcap, VB2_BUF_STATE_QUEUED); - return ret; - } - - return 0; -} - -/* - * Stop the stream engine. Any remaining buffers in the stream queue are - * dequeued and passed on to the vb2 framework marked as STATE_ERROR. - */ -static void vimc_cap_stop_streaming(struct vb2_queue *vq) -{ - struct vimc_cap_device *vcap = vb2_get_drv_priv(vq); - - vimc_streamer_s_stream(&vcap->stream, &vcap->ved, 0); - - /* Stop the media pipeline */ - media_pipeline_stop(&vcap->vdev.entity); - - /* Release all active buffers */ - vimc_cap_return_all_buffers(vcap, VB2_BUF_STATE_ERROR); -} - -static void vimc_cap_buf_queue(struct vb2_buffer *vb2_buf) -{ - struct vimc_cap_device *vcap = vb2_get_drv_priv(vb2_buf->vb2_queue); - struct vimc_cap_buffer *buf = container_of(vb2_buf, - struct vimc_cap_buffer, - vb2.vb2_buf); - - spin_lock(&vcap->qlock); - list_add_tail(&buf->list, &vcap->buf_list); - spin_unlock(&vcap->qlock); -} - -static int vimc_cap_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, - unsigned int *nplanes, unsigned int sizes[], - struct device *alloc_devs[]) -{ - struct vimc_cap_device *vcap = vb2_get_drv_priv(vq); - - if (*nplanes) - return sizes[0] < vcap->format.sizeimage ? -EINVAL : 0; - /* We don't support multiplanes for now */ - *nplanes = 1; - sizes[0] = vcap->format.sizeimage; - - return 0; -} - -static int vimc_cap_buffer_prepare(struct vb2_buffer *vb) -{ - struct vimc_cap_device *vcap = vb2_get_drv_priv(vb->vb2_queue); - unsigned long size = vcap->format.sizeimage; - - if (vb2_plane_size(vb, 0) < size) { - dev_err(vcap->ved.dev, "%s: buffer too small (%lu < %lu)\n", - vcap->vdev.name, vb2_plane_size(vb, 0), size); - return -EINVAL; - } - return 0; -} - -static const struct vb2_ops vimc_cap_qops = { - .start_streaming = vimc_cap_start_streaming, - .stop_streaming = vimc_cap_stop_streaming, - .buf_queue = vimc_cap_buf_queue, - .queue_setup = vimc_cap_queue_setup, - .buf_prepare = vimc_cap_buffer_prepare, - /* - * Since q->lock is set we can use the standard - * vb2_ops_wait_prepare/finish helper functions. - */ - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, -}; - -static const struct media_entity_operations vimc_cap_mops = { - .link_validate = vimc_vdev_link_validate, -}; - -void vimc_cap_release(struct vimc_ent_device *ved) -{ - struct vimc_cap_device *vcap = - container_of(ved, struct vimc_cap_device, ved); - - media_entity_cleanup(vcap->ved.ent); - kfree(vcap); -} - -void vimc_cap_unregister(struct vimc_ent_device *ved) -{ - struct vimc_cap_device *vcap = - container_of(ved, struct vimc_cap_device, ved); - - vb2_queue_release(&vcap->queue); - video_unregister_device(&vcap->vdev); -} - -static void *vimc_cap_process_frame(struct vimc_ent_device *ved, - const void *frame) -{ - struct vimc_cap_device *vcap = container_of(ved, struct vimc_cap_device, - ved); - struct vimc_cap_buffer *vimc_buf; - void *vbuf; - - spin_lock(&vcap->qlock); - - /* Get the first entry of the list */ - vimc_buf = list_first_entry_or_null(&vcap->buf_list, - typeof(*vimc_buf), list); - if (!vimc_buf) { - spin_unlock(&vcap->qlock); - return ERR_PTR(-EAGAIN); - } - - /* Remove this entry from the list */ - list_del(&vimc_buf->list); - - spin_unlock(&vcap->qlock); - - /* Fill the buffer */ - vimc_buf->vb2.vb2_buf.timestamp = ktime_get_ns(); - vimc_buf->vb2.sequence = vcap->sequence++; - vimc_buf->vb2.field = vcap->format.field; - - vbuf = vb2_plane_vaddr(&vimc_buf->vb2.vb2_buf, 0); - - memcpy(vbuf, frame, vcap->format.sizeimage); - - /* Set it as ready */ - vb2_set_plane_payload(&vimc_buf->vb2.vb2_buf, 0, - vcap->format.sizeimage); - vb2_buffer_done(&vimc_buf->vb2.vb2_buf, VB2_BUF_STATE_DONE); - return NULL; -} - -struct vimc_ent_device *vimc_cap_add(struct vimc_device *vimc, - const char *vcfg_name) -{ - struct v4l2_device *v4l2_dev = &vimc->v4l2_dev; - const struct vimc_pix_map *vpix; - struct vimc_cap_device *vcap; - struct video_device *vdev; - struct vb2_queue *q; - int ret; - - /* Allocate the vimc_cap_device struct */ - vcap = kzalloc(sizeof(*vcap), GFP_KERNEL); - if (!vcap) - return NULL; - - /* Initialize the media entity */ - vcap->vdev.entity.name = vcfg_name; - vcap->vdev.entity.function = MEDIA_ENT_F_IO_V4L; - vcap->pad.flags = MEDIA_PAD_FL_SINK; - ret = media_entity_pads_init(&vcap->vdev.entity, - 1, &vcap->pad); - if (ret) - goto err_free_vcap; - - /* Initialize the lock */ - mutex_init(&vcap->lock); - - /* Initialize the vb2 queue */ - q = &vcap->queue; - q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - q->io_modes = VB2_MMAP | VB2_DMABUF | VB2_USERPTR; - q->drv_priv = vcap; - q->buf_struct_size = sizeof(struct vimc_cap_buffer); - q->ops = &vimc_cap_qops; - q->mem_ops = &vb2_vmalloc_memops; - q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; - q->min_buffers_needed = 2; - q->lock = &vcap->lock; - - ret = vb2_queue_init(q); - if (ret) { - dev_err(vimc->mdev.dev, "%s: vb2 queue init failed (err=%d)\n", - vcfg_name, ret); - goto err_clean_m_ent; - } - - /* Initialize buffer list and its lock */ - INIT_LIST_HEAD(&vcap->buf_list); - spin_lock_init(&vcap->qlock); - - /* Set default frame format */ - vcap->format = fmt_default; - vpix = vimc_pix_map_by_pixelformat(vcap->format.pixelformat); - vcap->format.bytesperline = vcap->format.width * vpix->bpp; - vcap->format.sizeimage = vcap->format.bytesperline * - vcap->format.height; - - /* Fill the vimc_ent_device struct */ - vcap->ved.ent = &vcap->vdev.entity; - vcap->ved.process_frame = vimc_cap_process_frame; - vcap->ved.vdev_get_format = vimc_cap_get_format; - vcap->ved.dev = vimc->mdev.dev; - - /* Initialize the video_device struct */ - vdev = &vcap->vdev; - vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; - vdev->entity.ops = &vimc_cap_mops; - vdev->release = video_device_release_empty; - vdev->fops = &vimc_cap_fops; - vdev->ioctl_ops = &vimc_cap_ioctl_ops; - vdev->lock = &vcap->lock; - vdev->queue = q; - vdev->v4l2_dev = v4l2_dev; - vdev->vfl_dir = VFL_DIR_RX; - strscpy(vdev->name, vcfg_name, sizeof(vdev->name)); - video_set_drvdata(vdev, &vcap->ved); - - /* Register the video_device with the v4l2 and the media framework */ - ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); - if (ret) { - dev_err(vimc->mdev.dev, "%s: video register failed (err=%d)\n", - vcap->vdev.name, ret); - goto err_release_queue; - } - - return &vcap->ved; - -err_release_queue: - vb2_queue_release(q); -err_clean_m_ent: - media_entity_cleanup(&vcap->vdev.entity); -err_free_vcap: - kfree(vcap); - - return NULL; -} diff --git a/drivers/media/platform/vimc/vimc-common.c b/drivers/media/platform/vimc/vimc-common.c deleted file mode 100644 index c95c17c048f2..000000000000 --- a/drivers/media/platform/vimc/vimc-common.c +++ /dev/null @@ -1,369 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * vimc-common.c Virtual Media Controller Driver - * - * Copyright (C) 2015-2017 Helen Koike - */ - -#include -#include - -#include "vimc-common.h" - -/* - * NOTE: non-bayer formats need to come first (necessary for enum_mbus_code - * in the scaler) - */ -static const struct vimc_pix_map vimc_pix_map_list[] = { - /* TODO: add all missing formats */ - - /* RGB formats */ - { - .code = MEDIA_BUS_FMT_BGR888_1X24, - .pixelformat = V4L2_PIX_FMT_BGR24, - .bpp = 3, - .bayer = false, - }, - { - .code = MEDIA_BUS_FMT_RGB888_1X24, - .pixelformat = V4L2_PIX_FMT_RGB24, - .bpp = 3, - .bayer = false, - }, - { - .code = MEDIA_BUS_FMT_ARGB8888_1X32, - .pixelformat = V4L2_PIX_FMT_ARGB32, - .bpp = 4, - .bayer = false, - }, - - /* Bayer formats */ - { - .code = MEDIA_BUS_FMT_SBGGR8_1X8, - .pixelformat = V4L2_PIX_FMT_SBGGR8, - .bpp = 1, - .bayer = true, - }, - { - .code = MEDIA_BUS_FMT_SGBRG8_1X8, - .pixelformat = V4L2_PIX_FMT_SGBRG8, - .bpp = 1, - .bayer = true, - }, - { - .code = MEDIA_BUS_FMT_SGRBG8_1X8, - .pixelformat = V4L2_PIX_FMT_SGRBG8, - .bpp = 1, - .bayer = true, - }, - { - .code = MEDIA_BUS_FMT_SRGGB8_1X8, - .pixelformat = V4L2_PIX_FMT_SRGGB8, - .bpp = 1, - .bayer = true, - }, - { - .code = MEDIA_BUS_FMT_SBGGR10_1X10, - .pixelformat = V4L2_PIX_FMT_SBGGR10, - .bpp = 2, - .bayer = true, - }, - { - .code = MEDIA_BUS_FMT_SGBRG10_1X10, - .pixelformat = V4L2_PIX_FMT_SGBRG10, - .bpp = 2, - .bayer = true, - }, - { - .code = MEDIA_BUS_FMT_SGRBG10_1X10, - .pixelformat = V4L2_PIX_FMT_SGRBG10, - .bpp = 2, - .bayer = true, - }, - { - .code = MEDIA_BUS_FMT_SRGGB10_1X10, - .pixelformat = V4L2_PIX_FMT_SRGGB10, - .bpp = 2, - .bayer = true, - }, - - /* 10bit raw bayer a-law compressed to 8 bits */ - { - .code = MEDIA_BUS_FMT_SBGGR10_ALAW8_1X8, - .pixelformat = V4L2_PIX_FMT_SBGGR10ALAW8, - .bpp = 1, - .bayer = true, - }, - { - .code = MEDIA_BUS_FMT_SGBRG10_ALAW8_1X8, - .pixelformat = V4L2_PIX_FMT_SGBRG10ALAW8, - .bpp = 1, - .bayer = true, - }, - { - .code = MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8, - .pixelformat = V4L2_PIX_FMT_SGRBG10ALAW8, - .bpp = 1, - .bayer = true, - }, - { - .code = MEDIA_BUS_FMT_SRGGB10_ALAW8_1X8, - .pixelformat = V4L2_PIX_FMT_SRGGB10ALAW8, - .bpp = 1, - .bayer = true, - }, - - /* 10bit raw bayer DPCM compressed to 8 bits */ - { - .code = MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8, - .pixelformat = V4L2_PIX_FMT_SBGGR10DPCM8, - .bpp = 1, - .bayer = true, - }, - { - .code = MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8, - .pixelformat = V4L2_PIX_FMT_SGBRG10DPCM8, - .bpp = 1, - .bayer = true, - }, - { - .code = MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8, - .pixelformat = V4L2_PIX_FMT_SGRBG10DPCM8, - .bpp = 1, - .bayer = true, - }, - { - .code = MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8, - .pixelformat = V4L2_PIX_FMT_SRGGB10DPCM8, - .bpp = 1, - .bayer = true, - }, - { - .code = MEDIA_BUS_FMT_SBGGR12_1X12, - .pixelformat = V4L2_PIX_FMT_SBGGR12, - .bpp = 2, - .bayer = true, - }, - { - .code = MEDIA_BUS_FMT_SGBRG12_1X12, - .pixelformat = V4L2_PIX_FMT_SGBRG12, - .bpp = 2, - .bayer = true, - }, - { - .code = MEDIA_BUS_FMT_SGRBG12_1X12, - .pixelformat = V4L2_PIX_FMT_SGRBG12, - .bpp = 2, - .bayer = true, - }, - { - .code = MEDIA_BUS_FMT_SRGGB12_1X12, - .pixelformat = V4L2_PIX_FMT_SRGGB12, - .bpp = 2, - .bayer = true, - }, -}; - -bool vimc_is_source(struct media_entity *ent) -{ - unsigned int i; - - for (i = 0; i < ent->num_pads; i++) - if (ent->pads[i].flags & MEDIA_PAD_FL_SINK) - return false; - return true; -} - -const struct vimc_pix_map *vimc_pix_map_by_index(unsigned int i) -{ - if (i >= ARRAY_SIZE(vimc_pix_map_list)) - return NULL; - - return &vimc_pix_map_list[i]; -} - -const struct vimc_pix_map *vimc_pix_map_by_code(u32 code) -{ - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(vimc_pix_map_list); i++) { - if (vimc_pix_map_list[i].code == code) - return &vimc_pix_map_list[i]; - } - return NULL; -} - -const struct vimc_pix_map *vimc_pix_map_by_pixelformat(u32 pixelformat) -{ - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(vimc_pix_map_list); i++) { - if (vimc_pix_map_list[i].pixelformat == pixelformat) - return &vimc_pix_map_list[i]; - } - return NULL; -} - -static int vimc_get_pix_format(struct media_pad *pad, - struct v4l2_pix_format *fmt) -{ - if (is_media_entity_v4l2_subdev(pad->entity)) { - struct v4l2_subdev *sd = - media_entity_to_v4l2_subdev(pad->entity); - struct v4l2_subdev_format sd_fmt; - const struct vimc_pix_map *pix_map; - int ret; - - sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; - sd_fmt.pad = pad->index; - - ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &sd_fmt); - if (ret) - return ret; - - v4l2_fill_pix_format(fmt, &sd_fmt.format); - pix_map = vimc_pix_map_by_code(sd_fmt.format.code); - fmt->pixelformat = pix_map->pixelformat; - } else if (is_media_entity_v4l2_video_device(pad->entity)) { - struct video_device *vdev = container_of(pad->entity, - struct video_device, - entity); - struct vimc_ent_device *ved = video_get_drvdata(vdev); - - if (!ved->vdev_get_format) - return -ENOIOCTLCMD; - - ved->vdev_get_format(ved, fmt); - } else { - return -EINVAL; - } - - return 0; -} - -int vimc_vdev_link_validate(struct media_link *link) -{ - struct v4l2_pix_format source_fmt, sink_fmt; - int ret; - - ret = vimc_get_pix_format(link->source, &source_fmt); - if (ret) - return ret; - - ret = vimc_get_pix_format(link->sink, &sink_fmt); - if (ret) - return ret; - - pr_info("vimc link validate: " - "%s:src:%dx%d (0x%x, %d, %d, %d, %d) " - "%s:snk:%dx%d (0x%x, %d, %d, %d, %d)\n", - /* src */ - link->source->entity->name, - source_fmt.width, source_fmt.height, - source_fmt.pixelformat, source_fmt.colorspace, - source_fmt.quantization, source_fmt.xfer_func, - source_fmt.ycbcr_enc, - /* sink */ - link->sink->entity->name, - sink_fmt.width, sink_fmt.height, - sink_fmt.pixelformat, sink_fmt.colorspace, - sink_fmt.quantization, sink_fmt.xfer_func, - sink_fmt.ycbcr_enc); - - /* The width, height and pixelformat must match. */ - if (source_fmt.width != sink_fmt.width || - source_fmt.height != sink_fmt.height || - source_fmt.pixelformat != sink_fmt.pixelformat) - return -EPIPE; - - /* - * The field order must match, or the sink field order must be NONE - * to support interlaced hardware connected to bridges that support - * progressive formats only. - */ - if (source_fmt.field != sink_fmt.field && - sink_fmt.field != V4L2_FIELD_NONE) - return -EPIPE; - - /* - * If colorspace is DEFAULT, then assume all the colorimetry is also - * DEFAULT, return 0 to skip comparing the other colorimetry parameters - */ - if (source_fmt.colorspace == V4L2_COLORSPACE_DEFAULT || - sink_fmt.colorspace == V4L2_COLORSPACE_DEFAULT) - return 0; - - /* Colorspace must match. */ - if (source_fmt.colorspace != sink_fmt.colorspace) - return -EPIPE; - - /* Colorimetry must match if they are not set to DEFAULT */ - if (source_fmt.ycbcr_enc != V4L2_YCBCR_ENC_DEFAULT && - sink_fmt.ycbcr_enc != V4L2_YCBCR_ENC_DEFAULT && - source_fmt.ycbcr_enc != sink_fmt.ycbcr_enc) - return -EPIPE; - - if (source_fmt.quantization != V4L2_QUANTIZATION_DEFAULT && - sink_fmt.quantization != V4L2_QUANTIZATION_DEFAULT && - source_fmt.quantization != sink_fmt.quantization) - return -EPIPE; - - if (source_fmt.xfer_func != V4L2_XFER_FUNC_DEFAULT && - sink_fmt.xfer_func != V4L2_XFER_FUNC_DEFAULT && - source_fmt.xfer_func != sink_fmt.xfer_func) - return -EPIPE; - - return 0; -} - -static const struct media_entity_operations vimc_ent_sd_mops = { - .link_validate = v4l2_subdev_link_validate, -}; - -int vimc_ent_sd_register(struct vimc_ent_device *ved, - struct v4l2_subdev *sd, - struct v4l2_device *v4l2_dev, - const char *const name, - u32 function, - u16 num_pads, - struct media_pad *pads, - const struct v4l2_subdev_ops *sd_ops) -{ - int ret; - - /* Fill the vimc_ent_device struct */ - ved->ent = &sd->entity; - - /* Initialize the subdev */ - v4l2_subdev_init(sd, sd_ops); - sd->entity.function = function; - sd->entity.ops = &vimc_ent_sd_mops; - sd->owner = THIS_MODULE; - strscpy(sd->name, name, sizeof(sd->name)); - v4l2_set_subdevdata(sd, ved); - - /* Expose this subdev to user space */ - sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - if (sd->ctrl_handler) - sd->flags |= V4L2_SUBDEV_FL_HAS_EVENTS; - - /* Initialize the media entity */ - ret = media_entity_pads_init(&sd->entity, num_pads, pads); - if (ret) - return ret; - - /* Register the subdev with the v4l2 and the media framework */ - ret = v4l2_device_register_subdev(v4l2_dev, sd); - if (ret) { - dev_err(v4l2_dev->dev, - "%s: subdev register failed (err=%d)\n", - name, ret); - goto err_clean_m_ent; - } - - return 0; - -err_clean_m_ent: - media_entity_cleanup(&sd->entity); - return ret; -} diff --git a/drivers/media/platform/vimc/vimc-common.h b/drivers/media/platform/vimc/vimc-common.h deleted file mode 100644 index 616d5a6b0754..000000000000 --- a/drivers/media/platform/vimc/vimc-common.h +++ /dev/null @@ -1,224 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * vimc-common.h Virtual Media Controller Driver - * - * Copyright (C) 2015-2017 Helen Koike - */ - -#ifndef _VIMC_COMMON_H_ -#define _VIMC_COMMON_H_ - -#include -#include -#include -#include - -#define VIMC_PDEV_NAME "vimc" - -/* VIMC-specific controls */ -#define VIMC_CID_VIMC_BASE (0x00f00000 | 0xf000) -#define VIMC_CID_VIMC_CLASS (0x00f00000 | 1) -#define VIMC_CID_TEST_PATTERN (VIMC_CID_VIMC_BASE + 0) -#define VIMC_CID_MEAN_WIN_SIZE (VIMC_CID_VIMC_BASE + 1) - -#define VIMC_FRAME_MAX_WIDTH 4096 -#define VIMC_FRAME_MAX_HEIGHT 2160 -#define VIMC_FRAME_MIN_WIDTH 16 -#define VIMC_FRAME_MIN_HEIGHT 16 - -#define VIMC_FRAME_INDEX(lin, col, width, bpp) ((lin * width + col) * bpp) - -/* Source and sink pad checks */ -#define VIMC_IS_SRC(pad) (pad) -#define VIMC_IS_SINK(pad) (!(pad)) - -/** - * struct vimc_colorimetry_clamp - Adjust colorimetry parameters - * - * @fmt: the pointer to struct v4l2_pix_format or - * struct v4l2_mbus_framefmt - * - * Entities must check if colorimetry given by the userspace is valid, if not - * then set them as DEFAULT - */ -#define vimc_colorimetry_clamp(fmt) \ -do { \ - if ((fmt)->colorspace == V4L2_COLORSPACE_DEFAULT \ - || (fmt)->colorspace > V4L2_COLORSPACE_DCI_P3) { \ - (fmt)->colorspace = V4L2_COLORSPACE_DEFAULT; \ - (fmt)->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; \ - (fmt)->quantization = V4L2_QUANTIZATION_DEFAULT; \ - (fmt)->xfer_func = V4L2_XFER_FUNC_DEFAULT; \ - } \ - if ((fmt)->ycbcr_enc > V4L2_YCBCR_ENC_SMPTE240M) \ - (fmt)->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; \ - if ((fmt)->quantization > V4L2_QUANTIZATION_LIM_RANGE) \ - (fmt)->quantization = V4L2_QUANTIZATION_DEFAULT; \ - if ((fmt)->xfer_func > V4L2_XFER_FUNC_SMPTE2084) \ - (fmt)->xfer_func = V4L2_XFER_FUNC_DEFAULT; \ -} while (0) - -/** - * struct vimc_pix_map - maps media bus code with v4l2 pixel format - * - * @code: media bus format code defined by MEDIA_BUS_FMT_* macros - * @bbp: number of bytes each pixel occupies - * @pixelformat: pixel format devined by V4L2_PIX_FMT_* macros - * - * Struct which matches the MEDIA_BUS_FMT_* codes with the corresponding - * V4L2_PIX_FMT_* fourcc pixelformat and its bytes per pixel (bpp) - */ -struct vimc_pix_map { - unsigned int code; - unsigned int bpp; - u32 pixelformat; - bool bayer; -}; - -/** - * struct vimc_ent_device - core struct that represents an entity in the - * topology - * - * @dev: a pointer of the device struct of the driver - * @ent: the pointer to struct media_entity for the node - * @process_frame: callback send a frame to that node - * @vdev_get_format: callback that returns the current format a pad, used - * only when is_media_entity_v4l2_video_device(ent) returns - * true - * - * Each node of the topology must create a vimc_ent_device struct. Depending on - * the node it will be of an instance of v4l2_subdev or video_device struct - * where both contains a struct media_entity. - * Those structures should embedded the vimc_ent_device struct through - * v4l2_set_subdevdata() and video_set_drvdata() respectivaly, allowing the - * vimc_ent_device struct to be retrieved from the corresponding struct - * media_entity - */ -struct vimc_ent_device { - struct device *dev; - struct media_entity *ent; - void * (*process_frame)(struct vimc_ent_device *ved, - const void *frame); - void (*vdev_get_format)(struct vimc_ent_device *ved, - struct v4l2_pix_format *fmt); -}; - -/** - * struct vimc_device - main device for vimc driver - * - * @pipe_cfg pointer to the vimc pipeline configuration structure - * @ent_devs array of vimc_ent_device pointers - * @mdev the associated media_device parent - * @v4l2_dev Internal v4l2 parent device - */ -struct vimc_device { - const struct vimc_pipeline_config *pipe_cfg; - struct vimc_ent_device **ent_devs; - struct media_device mdev; - struct v4l2_device v4l2_dev; -}; - -/** - * struct vimc_ent_config Structure which describes individual - * configuration for each entity - * - * @name entity name - * @ved pointer to vimc_ent_device (a node in the - * topology) - * @add initializes and registers - * vim entity - called from vimc-core - * @unregister unregisters vimc entity - called from vimc-core - * @release releases vimc entity - called from the v4l2_dev - * release callback - */ -struct vimc_ent_config { - const char *name; - struct vimc_ent_device *(*add)(struct vimc_device *vimc, - const char *vcfg_name); - void (*unregister)(struct vimc_ent_device *ved); - void (*release)(struct vimc_ent_device *ved); -}; - -/** - * vimc_is_source - returns true if the entity has only source pads - * - * @ent: pointer to &struct media_entity - * - */ -bool vimc_is_source(struct media_entity *ent); - -/* prototypes for vimc_ent_config hooks */ -struct vimc_ent_device *vimc_cap_add(struct vimc_device *vimc, - const char *vcfg_name); -void vimc_cap_unregister(struct vimc_ent_device *ved); -void vimc_cap_release(struct vimc_ent_device *ved); - -struct vimc_ent_device *vimc_deb_add(struct vimc_device *vimc, - const char *vcfg_name); -void vimc_deb_release(struct vimc_ent_device *ved); - -struct vimc_ent_device *vimc_sca_add(struct vimc_device *vimc, - const char *vcfg_name); -void vimc_sca_release(struct vimc_ent_device *ved); - -struct vimc_ent_device *vimc_sen_add(struct vimc_device *vimc, - const char *vcfg_name); -void vimc_sen_release(struct vimc_ent_device *ved); - -/** - * vimc_pix_map_by_index - get vimc_pix_map struct by its index - * - * @i: index of the vimc_pix_map struct in vimc_pix_map_list - */ -const struct vimc_pix_map *vimc_pix_map_by_index(unsigned int i); - -/** - * vimc_pix_map_by_code - get vimc_pix_map struct by media bus code - * - * @code: media bus format code defined by MEDIA_BUS_FMT_* macros - */ -const struct vimc_pix_map *vimc_pix_map_by_code(u32 code); - -/** - * vimc_pix_map_by_pixelformat - get vimc_pix_map struct by v4l2 pixel format - * - * @pixelformat: pixel format devined by V4L2_PIX_FMT_* macros - */ -const struct vimc_pix_map *vimc_pix_map_by_pixelformat(u32 pixelformat); - -/** - * vimc_ent_sd_register - initialize and register a subdev node - * - * @ved: the vimc_ent_device struct to be initialize - * @sd: the v4l2_subdev struct to be initialize and registered - * @v4l2_dev: the v4l2 device to register the v4l2_subdev - * @name: name of the sub-device. Please notice that the name must be - * unique. - * @function: media entity function defined by MEDIA_ENT_F_* macros - * @num_pads: number of pads to initialize - * @pads: the array of pads of the entity, the caller should set the - flags of the pads - * @sd_ops: pointer to &struct v4l2_subdev_ops. - * - * Helper function initialize and register the struct vimc_ent_device and struct - * v4l2_subdev which represents a subdev node in the topology - */ -int vimc_ent_sd_register(struct vimc_ent_device *ved, - struct v4l2_subdev *sd, - struct v4l2_device *v4l2_dev, - const char *const name, - u32 function, - u16 num_pads, - struct media_pad *pads, - const struct v4l2_subdev_ops *sd_ops); - -/** - * vimc_vdev_link_validate - validates a media link - * - * @link: pointer to &struct media_link - * - * This function calls validates if a media link is valid for streaming. - */ -int vimc_vdev_link_validate(struct media_link *link); - -#endif diff --git a/drivers/media/platform/vimc/vimc-core.c b/drivers/media/platform/vimc/vimc-core.c deleted file mode 100644 index 339126e565dc..000000000000 --- a/drivers/media/platform/vimc/vimc-core.c +++ /dev/null @@ -1,381 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * vimc-core.c Virtual Media Controller Driver - * - * Copyright (C) 2015-2017 Helen Koike - */ - -#include -#include -#include -#include -#include - -#include "vimc-common.h" - -#define VIMC_MDEV_MODEL_NAME "VIMC MDEV" - -#define VIMC_ENT_LINK(src, srcpad, sink, sinkpad, link_flags) { \ - .src_ent = src, \ - .src_pad = srcpad, \ - .sink_ent = sink, \ - .sink_pad = sinkpad, \ - .flags = link_flags, \ -} - -/* Structure which describes links between entities */ -struct vimc_ent_link { - unsigned int src_ent; - u16 src_pad; - unsigned int sink_ent; - u16 sink_pad; - u32 flags; -}; - -/* Structure which describes the whole topology */ -struct vimc_pipeline_config { - const struct vimc_ent_config *ents; - size_t num_ents; - const struct vimc_ent_link *links; - size_t num_links; -}; - -/* -------------------------------------------------------------------------- - * Topology Configuration - */ - -static struct vimc_ent_config ent_config[] = { - { - .name = "Sensor A", - .add = vimc_sen_add, - .release = vimc_sen_release, - }, - { - .name = "Sensor B", - .add = vimc_sen_add, - .release = vimc_sen_release, - }, - { - .name = "Debayer A", - .add = vimc_deb_add, - .release = vimc_deb_release, - }, - { - .name = "Debayer B", - .add = vimc_deb_add, - .release = vimc_deb_release, - }, - { - .name = "Raw Capture 0", - .add = vimc_cap_add, - .unregister = vimc_cap_unregister, - .release = vimc_cap_release, - }, - { - .name = "Raw Capture 1", - .add = vimc_cap_add, - .unregister = vimc_cap_unregister, - .release = vimc_cap_release, - }, - { - /* TODO: change this to vimc-input when it is implemented */ - .name = "RGB/YUV Input", - .add = vimc_sen_add, - .release = vimc_sen_release, - }, - { - .name = "Scaler", - .add = vimc_sca_add, - .release = vimc_sca_release, - }, - { - .name = "RGB/YUV Capture", - .add = vimc_cap_add, - .unregister = vimc_cap_unregister, - .release = vimc_cap_release, - }, -}; - -static const struct vimc_ent_link ent_links[] = { - /* Link: Sensor A (Pad 0)->(Pad 0) Debayer A */ - VIMC_ENT_LINK(0, 0, 2, 0, MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE), - /* Link: Sensor A (Pad 0)->(Pad 0) Raw Capture 0 */ - VIMC_ENT_LINK(0, 0, 4, 0, MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE), - /* Link: Sensor B (Pad 0)->(Pad 0) Debayer B */ - VIMC_ENT_LINK(1, 0, 3, 0, MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE), - /* Link: Sensor B (Pad 0)->(Pad 0) Raw Capture 1 */ - VIMC_ENT_LINK(1, 0, 5, 0, MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE), - /* Link: Debayer A (Pad 1)->(Pad 0) Scaler */ - VIMC_ENT_LINK(2, 1, 7, 0, MEDIA_LNK_FL_ENABLED), - /* Link: Debayer B (Pad 1)->(Pad 0) Scaler */ - VIMC_ENT_LINK(3, 1, 7, 0, 0), - /* Link: RGB/YUV Input (Pad 0)->(Pad 0) Scaler */ - VIMC_ENT_LINK(6, 0, 7, 0, 0), - /* Link: Scaler (Pad 1)->(Pad 0) RGB/YUV Capture */ - VIMC_ENT_LINK(7, 1, 8, 0, MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE), -}; - -static struct vimc_pipeline_config pipe_cfg = { - .ents = ent_config, - .num_ents = ARRAY_SIZE(ent_config), - .links = ent_links, - .num_links = ARRAY_SIZE(ent_links) -}; - -/* -------------------------------------------------------------------------- */ - -static void vimc_rm_links(struct vimc_device *vimc) -{ - unsigned int i; - - for (i = 0; i < vimc->pipe_cfg->num_ents; i++) - media_entity_remove_links(vimc->ent_devs[i]->ent); -} - -static int vimc_create_links(struct vimc_device *vimc) -{ - unsigned int i; - int ret; - - /* Initialize the links between entities */ - for (i = 0; i < vimc->pipe_cfg->num_links; i++) { - const struct vimc_ent_link *link = &vimc->pipe_cfg->links[i]; - - struct vimc_ent_device *ved_src = - vimc->ent_devs[link->src_ent]; - struct vimc_ent_device *ved_sink = - vimc->ent_devs[link->sink_ent]; - - ret = media_create_pad_link(ved_src->ent, link->src_pad, - ved_sink->ent, link->sink_pad, - link->flags); - if (ret) - goto err_rm_links; - } - - return 0; - -err_rm_links: - vimc_rm_links(vimc); - return ret; -} - -static int vimc_add_subdevs(struct vimc_device *vimc) -{ - unsigned int i; - - for (i = 0; i < vimc->pipe_cfg->num_ents; i++) { - dev_dbg(vimc->mdev.dev, "new entity for %s\n", - vimc->pipe_cfg->ents[i].name); - vimc->ent_devs[i] = vimc->pipe_cfg->ents[i].add(vimc, - vimc->pipe_cfg->ents[i].name); - if (!vimc->ent_devs[i]) { - dev_err(vimc->mdev.dev, "add new entity for %s\n", - vimc->pipe_cfg->ents[i].name); - return -EINVAL; - } - } - return 0; -} - -static void vimc_release_subdevs(struct vimc_device *vimc) -{ - unsigned int i; - - for (i = 0; i < vimc->pipe_cfg->num_ents; i++) - if (vimc->ent_devs[i]) - vimc->pipe_cfg->ents[i].release(vimc->ent_devs[i]); -} - -static void vimc_unregister_subdevs(struct vimc_device *vimc) -{ - unsigned int i; - - for (i = 0; i < vimc->pipe_cfg->num_ents; i++) - if (vimc->ent_devs[i] && vimc->pipe_cfg->ents[i].unregister) - vimc->pipe_cfg->ents[i].unregister(vimc->ent_devs[i]); -} - -static void vimc_v4l2_dev_release(struct v4l2_device *v4l2_dev) -{ - struct vimc_device *vimc = - container_of(v4l2_dev, struct vimc_device, v4l2_dev); - - vimc_release_subdevs(vimc); - media_device_cleanup(&vimc->mdev); - kfree(vimc->ent_devs); - kfree(vimc); -} - -static int vimc_register_devices(struct vimc_device *vimc) -{ - int ret; - - /* Register the v4l2 struct */ - ret = v4l2_device_register(vimc->mdev.dev, &vimc->v4l2_dev); - if (ret) { - dev_err(vimc->mdev.dev, - "v4l2 device register failed (err=%d)\n", ret); - return ret; - } - /* allocate ent_devs */ - vimc->ent_devs = kcalloc(vimc->pipe_cfg->num_ents, - sizeof(*vimc->ent_devs), GFP_KERNEL); - if (!vimc->ent_devs) { - ret = -ENOMEM; - goto err_v4l2_unregister; - } - - /* Invoke entity config hooks to initialize and register subdevs */ - ret = vimc_add_subdevs(vimc); - if (ret) - /* remove sundevs that got added */ - goto err_rm_subdevs; - - /* Initialize links */ - ret = vimc_create_links(vimc); - if (ret) - goto err_rm_subdevs; - - /* Register the media device */ - ret = media_device_register(&vimc->mdev); - if (ret) { - dev_err(vimc->mdev.dev, - "media device register failed (err=%d)\n", ret); - goto err_rm_subdevs; - } - - /* Expose all subdev's nodes*/ - ret = v4l2_device_register_subdev_nodes(&vimc->v4l2_dev); - if (ret) { - dev_err(vimc->mdev.dev, - "vimc subdev nodes registration failed (err=%d)\n", - ret); - goto err_mdev_unregister; - } - - return 0; - -err_mdev_unregister: - media_device_unregister(&vimc->mdev); -err_rm_subdevs: - vimc_unregister_subdevs(vimc); - vimc_release_subdevs(vimc); - kfree(vimc->ent_devs); -err_v4l2_unregister: - v4l2_device_unregister(&vimc->v4l2_dev); - - return ret; -} - -static void vimc_unregister(struct vimc_device *vimc) -{ - vimc_unregister_subdevs(vimc); - media_device_unregister(&vimc->mdev); - v4l2_device_unregister(&vimc->v4l2_dev); -} - -static int vimc_probe(struct platform_device *pdev) -{ - struct vimc_device *vimc; - int ret; - - dev_dbg(&pdev->dev, "probe"); - - vimc = kzalloc(sizeof(*vimc), GFP_KERNEL); - if (!vimc) - return -ENOMEM; - - vimc->pipe_cfg = &pipe_cfg; - - /* Link the media device within the v4l2_device */ - vimc->v4l2_dev.mdev = &vimc->mdev; - - /* Initialize media device */ - strscpy(vimc->mdev.model, VIMC_MDEV_MODEL_NAME, - sizeof(vimc->mdev.model)); - snprintf(vimc->mdev.bus_info, sizeof(vimc->mdev.bus_info), - "platform:%s", VIMC_PDEV_NAME); - vimc->mdev.dev = &pdev->dev; - media_device_init(&vimc->mdev); - - ret = vimc_register_devices(vimc); - if (ret) { - media_device_cleanup(&vimc->mdev); - kfree(vimc); - return ret; - } - /* - * the release cb is set only after successful registration. - * if the registration fails, we release directly from probe - */ - - vimc->v4l2_dev.release = vimc_v4l2_dev_release; - platform_set_drvdata(pdev, vimc); - return 0; -} - -static int vimc_remove(struct platform_device *pdev) -{ - struct vimc_device *vimc = platform_get_drvdata(pdev); - - dev_dbg(&pdev->dev, "remove"); - - vimc_unregister(vimc); - v4l2_device_put(&vimc->v4l2_dev); - - return 0; -} - -static void vimc_dev_release(struct device *dev) -{ -} - -static struct platform_device vimc_pdev = { - .name = VIMC_PDEV_NAME, - .dev.release = vimc_dev_release, -}; - -static struct platform_driver vimc_pdrv = { - .probe = vimc_probe, - .remove = vimc_remove, - .driver = { - .name = VIMC_PDEV_NAME, - }, -}; - -static int __init vimc_init(void) -{ - int ret; - - ret = platform_device_register(&vimc_pdev); - if (ret) { - dev_err(&vimc_pdev.dev, - "platform device registration failed (err=%d)\n", ret); - return ret; - } - - ret = platform_driver_register(&vimc_pdrv); - if (ret) { - dev_err(&vimc_pdev.dev, - "platform driver registration failed (err=%d)\n", ret); - platform_driver_unregister(&vimc_pdrv); - return ret; - } - - return 0; -} - -static void __exit vimc_exit(void) -{ - platform_driver_unregister(&vimc_pdrv); - - platform_device_unregister(&vimc_pdev); -} - -module_init(vimc_init); -module_exit(vimc_exit); - -MODULE_DESCRIPTION("Virtual Media Controller Driver (VIMC)"); -MODULE_AUTHOR("Helen Fornazier "); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/platform/vimc/vimc-debayer.c b/drivers/media/platform/vimc/vimc-debayer.c deleted file mode 100644 index baf6bf9f65b5..000000000000 --- a/drivers/media/platform/vimc/vimc-debayer.c +++ /dev/null @@ -1,581 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * vimc-debayer.c Virtual Media Controller Driver - * - * Copyright (C) 2015-2017 Helen Koike - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "vimc-common.h" - -enum vimc_deb_rgb_colors { - VIMC_DEB_RED = 0, - VIMC_DEB_GREEN = 1, - VIMC_DEB_BLUE = 2, -}; - -struct vimc_deb_pix_map { - u32 code; - enum vimc_deb_rgb_colors order[2][2]; -}; - -struct vimc_deb_device { - struct vimc_ent_device ved; - struct v4l2_subdev sd; - /* The active format */ - struct v4l2_mbus_framefmt sink_fmt; - u32 src_code; - void (*set_rgb_src)(struct vimc_deb_device *vdeb, unsigned int lin, - unsigned int col, unsigned int rgb[3]); - /* Values calculated when the stream starts */ - u8 *src_frame; - const struct vimc_deb_pix_map *sink_pix_map; - unsigned int sink_bpp; - unsigned int mean_win_size; - struct v4l2_ctrl_handler hdl; - struct media_pad pads[2]; -}; - -static const struct v4l2_mbus_framefmt sink_fmt_default = { - .width = 640, - .height = 480, - .code = MEDIA_BUS_FMT_SRGGB8_1X8, - .field = V4L2_FIELD_NONE, - .colorspace = V4L2_COLORSPACE_DEFAULT, -}; - -static const struct vimc_deb_pix_map vimc_deb_pix_map_list[] = { - { - .code = MEDIA_BUS_FMT_SBGGR8_1X8, - .order = { { VIMC_DEB_BLUE, VIMC_DEB_GREEN }, - { VIMC_DEB_GREEN, VIMC_DEB_RED } } - }, - { - .code = MEDIA_BUS_FMT_SGBRG8_1X8, - .order = { { VIMC_DEB_GREEN, VIMC_DEB_BLUE }, - { VIMC_DEB_RED, VIMC_DEB_GREEN } } - }, - { - .code = MEDIA_BUS_FMT_SGRBG8_1X8, - .order = { { VIMC_DEB_GREEN, VIMC_DEB_RED }, - { VIMC_DEB_BLUE, VIMC_DEB_GREEN } } - }, - { - .code = MEDIA_BUS_FMT_SRGGB8_1X8, - .order = { { VIMC_DEB_RED, VIMC_DEB_GREEN }, - { VIMC_DEB_GREEN, VIMC_DEB_BLUE } } - }, - { - .code = MEDIA_BUS_FMT_SBGGR10_1X10, - .order = { { VIMC_DEB_BLUE, VIMC_DEB_GREEN }, - { VIMC_DEB_GREEN, VIMC_DEB_RED } } - }, - { - .code = MEDIA_BUS_FMT_SGBRG10_1X10, - .order = { { VIMC_DEB_GREEN, VIMC_DEB_BLUE }, - { VIMC_DEB_RED, VIMC_DEB_GREEN } } - }, - { - .code = MEDIA_BUS_FMT_SGRBG10_1X10, - .order = { { VIMC_DEB_GREEN, VIMC_DEB_RED }, - { VIMC_DEB_BLUE, VIMC_DEB_GREEN } } - }, - { - .code = MEDIA_BUS_FMT_SRGGB10_1X10, - .order = { { VIMC_DEB_RED, VIMC_DEB_GREEN }, - { VIMC_DEB_GREEN, VIMC_DEB_BLUE } } - }, - { - .code = MEDIA_BUS_FMT_SBGGR12_1X12, - .order = { { VIMC_DEB_BLUE, VIMC_DEB_GREEN }, - { VIMC_DEB_GREEN, VIMC_DEB_RED } } - }, - { - .code = MEDIA_BUS_FMT_SGBRG12_1X12, - .order = { { VIMC_DEB_GREEN, VIMC_DEB_BLUE }, - { VIMC_DEB_RED, VIMC_DEB_GREEN } } - }, - { - .code = MEDIA_BUS_FMT_SGRBG12_1X12, - .order = { { VIMC_DEB_GREEN, VIMC_DEB_RED }, - { VIMC_DEB_BLUE, VIMC_DEB_GREEN } } - }, - { - .code = MEDIA_BUS_FMT_SRGGB12_1X12, - .order = { { VIMC_DEB_RED, VIMC_DEB_GREEN }, - { VIMC_DEB_GREEN, VIMC_DEB_BLUE } } - }, -}; - -static const struct vimc_deb_pix_map *vimc_deb_pix_map_by_code(u32 code) -{ - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(vimc_deb_pix_map_list); i++) - if (vimc_deb_pix_map_list[i].code == code) - return &vimc_deb_pix_map_list[i]; - - return NULL; -} - -static int vimc_deb_init_cfg(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg) -{ - struct vimc_deb_device *vdeb = v4l2_get_subdevdata(sd); - struct v4l2_mbus_framefmt *mf; - unsigned int i; - - mf = v4l2_subdev_get_try_format(sd, cfg, 0); - *mf = sink_fmt_default; - - for (i = 1; i < sd->entity.num_pads; i++) { - mf = v4l2_subdev_get_try_format(sd, cfg, i); - *mf = sink_fmt_default; - mf->code = vdeb->src_code; - } - - return 0; -} - -static int vimc_deb_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_mbus_code_enum *code) -{ - /* We only support one format for source pads */ - if (VIMC_IS_SRC(code->pad)) { - struct vimc_deb_device *vdeb = v4l2_get_subdevdata(sd); - - if (code->index) - return -EINVAL; - - code->code = vdeb->src_code; - } else { - if (code->index >= ARRAY_SIZE(vimc_deb_pix_map_list)) - return -EINVAL; - - code->code = vimc_deb_pix_map_list[code->index].code; - } - - return 0; -} - -static int vimc_deb_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_frame_size_enum *fse) -{ - struct vimc_deb_device *vdeb = v4l2_get_subdevdata(sd); - - if (fse->index) - return -EINVAL; - - if (VIMC_IS_SINK(fse->pad)) { - const struct vimc_deb_pix_map *vpix = - vimc_deb_pix_map_by_code(fse->code); - - if (!vpix) - return -EINVAL; - } else if (fse->code != vdeb->src_code) { - return -EINVAL; - } - - fse->min_width = VIMC_FRAME_MIN_WIDTH; - fse->max_width = VIMC_FRAME_MAX_WIDTH; - fse->min_height = VIMC_FRAME_MIN_HEIGHT; - fse->max_height = VIMC_FRAME_MAX_HEIGHT; - - return 0; -} - -static int vimc_deb_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *fmt) -{ - struct vimc_deb_device *vdeb = v4l2_get_subdevdata(sd); - - /* Get the current sink format */ - fmt->format = fmt->which == V4L2_SUBDEV_FORMAT_TRY ? - *v4l2_subdev_get_try_format(sd, cfg, 0) : - vdeb->sink_fmt; - - /* Set the right code for the source pad */ - if (VIMC_IS_SRC(fmt->pad)) - fmt->format.code = vdeb->src_code; - - return 0; -} - -static void vimc_deb_adjust_sink_fmt(struct v4l2_mbus_framefmt *fmt) -{ - const struct vimc_deb_pix_map *vpix; - - /* Don't accept a code that is not on the debayer table */ - vpix = vimc_deb_pix_map_by_code(fmt->code); - if (!vpix) - fmt->code = sink_fmt_default.code; - - fmt->width = clamp_t(u32, fmt->width, VIMC_FRAME_MIN_WIDTH, - VIMC_FRAME_MAX_WIDTH) & ~1; - fmt->height = clamp_t(u32, fmt->height, VIMC_FRAME_MIN_HEIGHT, - VIMC_FRAME_MAX_HEIGHT) & ~1; - - if (fmt->field == V4L2_FIELD_ANY) - fmt->field = sink_fmt_default.field; - - vimc_colorimetry_clamp(fmt); -} - -static int vimc_deb_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *fmt) -{ - struct vimc_deb_device *vdeb = v4l2_get_subdevdata(sd); - struct v4l2_mbus_framefmt *sink_fmt; - - if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { - /* Do not change the format while stream is on */ - if (vdeb->src_frame) - return -EBUSY; - - sink_fmt = &vdeb->sink_fmt; - } else { - sink_fmt = v4l2_subdev_get_try_format(sd, cfg, 0); - } - - /* - * Do not change the format of the source pad, - * it is propagated from the sink - */ - if (VIMC_IS_SRC(fmt->pad)) { - fmt->format = *sink_fmt; - /* TODO: Add support for other formats */ - fmt->format.code = vdeb->src_code; - } else { - /* Set the new format in the sink pad */ - vimc_deb_adjust_sink_fmt(&fmt->format); - - dev_dbg(vdeb->ved.dev, "%s: sink format update: " - "old:%dx%d (0x%x, %d, %d, %d, %d) " - "new:%dx%d (0x%x, %d, %d, %d, %d)\n", vdeb->sd.name, - /* old */ - sink_fmt->width, sink_fmt->height, sink_fmt->code, - sink_fmt->colorspace, sink_fmt->quantization, - sink_fmt->xfer_func, sink_fmt->ycbcr_enc, - /* new */ - fmt->format.width, fmt->format.height, fmt->format.code, - fmt->format.colorspace, fmt->format.quantization, - fmt->format.xfer_func, fmt->format.ycbcr_enc); - - *sink_fmt = fmt->format; - } - - return 0; -} - -static const struct v4l2_subdev_pad_ops vimc_deb_pad_ops = { - .init_cfg = vimc_deb_init_cfg, - .enum_mbus_code = vimc_deb_enum_mbus_code, - .enum_frame_size = vimc_deb_enum_frame_size, - .get_fmt = vimc_deb_get_fmt, - .set_fmt = vimc_deb_set_fmt, -}; - -static void vimc_deb_set_rgb_mbus_fmt_rgb888_1x24(struct vimc_deb_device *vdeb, - unsigned int lin, - unsigned int col, - unsigned int rgb[3]) -{ - unsigned int i, index; - - index = VIMC_FRAME_INDEX(lin, col, vdeb->sink_fmt.width, 3); - for (i = 0; i < 3; i++) - vdeb->src_frame[index + i] = rgb[i]; -} - -static int vimc_deb_s_stream(struct v4l2_subdev *sd, int enable) -{ - struct vimc_deb_device *vdeb = v4l2_get_subdevdata(sd); - - if (enable) { - const struct vimc_pix_map *vpix; - unsigned int frame_size; - - if (vdeb->src_frame) - return 0; - - /* Calculate the frame size of the source pad */ - vpix = vimc_pix_map_by_code(vdeb->src_code); - frame_size = vdeb->sink_fmt.width * vdeb->sink_fmt.height * - vpix->bpp; - - /* Save the bytes per pixel of the sink */ - vpix = vimc_pix_map_by_code(vdeb->sink_fmt.code); - vdeb->sink_bpp = vpix->bpp; - - /* Get the corresponding pixel map from the table */ - vdeb->sink_pix_map = - vimc_deb_pix_map_by_code(vdeb->sink_fmt.code); - - /* - * Allocate the frame buffer. Use vmalloc to be able to - * allocate a large amount of memory - */ - vdeb->src_frame = vmalloc(frame_size); - if (!vdeb->src_frame) - return -ENOMEM; - - } else { - if (!vdeb->src_frame) - return 0; - - vfree(vdeb->src_frame); - vdeb->src_frame = NULL; - } - - return 0; -} - -static const struct v4l2_subdev_core_ops vimc_deb_core_ops = { - .log_status = v4l2_ctrl_subdev_log_status, - .subscribe_event = v4l2_ctrl_subdev_subscribe_event, - .unsubscribe_event = v4l2_event_subdev_unsubscribe, -}; - -static const struct v4l2_subdev_video_ops vimc_deb_video_ops = { - .s_stream = vimc_deb_s_stream, -}; - -static const struct v4l2_subdev_ops vimc_deb_ops = { - .core = &vimc_deb_core_ops, - .pad = &vimc_deb_pad_ops, - .video = &vimc_deb_video_ops, -}; - -static unsigned int vimc_deb_get_val(const u8 *bytes, - const unsigned int n_bytes) -{ - unsigned int i; - unsigned int acc = 0; - - for (i = 0; i < n_bytes; i++) - acc = acc + (bytes[i] << (8 * i)); - - return acc; -} - -static void vimc_deb_calc_rgb_sink(struct vimc_deb_device *vdeb, - const u8 *frame, - const unsigned int lin, - const unsigned int col, - unsigned int rgb[3]) -{ - unsigned int i, seek, wlin, wcol; - unsigned int n_rgb[3] = {0, 0, 0}; - - for (i = 0; i < 3; i++) - rgb[i] = 0; - - /* - * Calculate how many we need to subtract to get to the pixel in - * the top left corner of the mean window (considering the current - * pixel as the center) - */ - seek = vdeb->mean_win_size / 2; - - /* Sum the values of the colors in the mean window */ - - dev_dbg(vdeb->ved.dev, - "deb: %s: --- Calc pixel %dx%d, window mean %d, seek %d ---\n", - vdeb->sd.name, lin, col, vdeb->sink_fmt.height, seek); - - /* - * Iterate through all the lines in the mean window, start - * with zero if the pixel is outside the frame and don't pass - * the height when the pixel is in the bottom border of the - * frame - */ - for (wlin = seek > lin ? 0 : lin - seek; - wlin < lin + seek + 1 && wlin < vdeb->sink_fmt.height; - wlin++) { - - /* - * Iterate through all the columns in the mean window, start - * with zero if the pixel is outside the frame and don't pass - * the width when the pixel is in the right border of the - * frame - */ - for (wcol = seek > col ? 0 : col - seek; - wcol < col + seek + 1 && wcol < vdeb->sink_fmt.width; - wcol++) { - enum vimc_deb_rgb_colors color; - unsigned int index; - - /* Check which color this pixel is */ - color = vdeb->sink_pix_map->order[wlin % 2][wcol % 2]; - - index = VIMC_FRAME_INDEX(wlin, wcol, - vdeb->sink_fmt.width, - vdeb->sink_bpp); - - dev_dbg(vdeb->ved.dev, - "deb: %s: RGB CALC: frame index %d, win pos %dx%d, color %d\n", - vdeb->sd.name, index, wlin, wcol, color); - - /* Get its value */ - rgb[color] = rgb[color] + - vimc_deb_get_val(&frame[index], vdeb->sink_bpp); - - /* Save how many values we already added */ - n_rgb[color]++; - - dev_dbg(vdeb->ved.dev, "deb: %s: RGB CALC: val %d, n %d\n", - vdeb->sd.name, rgb[color], n_rgb[color]); - } - } - - /* Calculate the mean */ - for (i = 0; i < 3; i++) { - dev_dbg(vdeb->ved.dev, - "deb: %s: PRE CALC: %dx%d Color %d, val %d, n %d\n", - vdeb->sd.name, lin, col, i, rgb[i], n_rgb[i]); - - if (n_rgb[i]) - rgb[i] = rgb[i] / n_rgb[i]; - - dev_dbg(vdeb->ved.dev, - "deb: %s: FINAL CALC: %dx%d Color %d, val %d\n", - vdeb->sd.name, lin, col, i, rgb[i]); - } -} - -static void *vimc_deb_process_frame(struct vimc_ent_device *ved, - const void *sink_frame) -{ - struct vimc_deb_device *vdeb = container_of(ved, struct vimc_deb_device, - ved); - unsigned int rgb[3]; - unsigned int i, j; - - /* If the stream in this node is not active, just return */ - if (!vdeb->src_frame) - return ERR_PTR(-EINVAL); - - for (i = 0; i < vdeb->sink_fmt.height; i++) - for (j = 0; j < vdeb->sink_fmt.width; j++) { - vimc_deb_calc_rgb_sink(vdeb, sink_frame, i, j, rgb); - vdeb->set_rgb_src(vdeb, i, j, rgb); - } - - return vdeb->src_frame; -} - -static int vimc_deb_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct vimc_deb_device *vdeb = - container_of(ctrl->handler, struct vimc_deb_device, hdl); - - switch (ctrl->id) { - case VIMC_CID_MEAN_WIN_SIZE: - vdeb->mean_win_size = ctrl->val; - break; - default: - return -EINVAL; - } - return 0; -} - -static const struct v4l2_ctrl_ops vimc_deb_ctrl_ops = { - .s_ctrl = vimc_deb_s_ctrl, -}; - -void vimc_deb_release(struct vimc_ent_device *ved) -{ - struct vimc_deb_device *vdeb = - container_of(ved, struct vimc_deb_device, ved); - - v4l2_ctrl_handler_free(&vdeb->hdl); - media_entity_cleanup(vdeb->ved.ent); - kfree(vdeb); -} - -static const struct v4l2_ctrl_config vimc_deb_ctrl_class = { - .flags = V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_WRITE_ONLY, - .id = VIMC_CID_VIMC_CLASS, - .name = "VIMC Controls", - .type = V4L2_CTRL_TYPE_CTRL_CLASS, -}; - -static const struct v4l2_ctrl_config vimc_deb_ctrl_mean_win_size = { - .ops = &vimc_deb_ctrl_ops, - .id = VIMC_CID_MEAN_WIN_SIZE, - .name = "Debayer Mean Window Size", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = 1, - .max = 25, - .step = 2, - .def = 3, -}; - -struct vimc_ent_device *vimc_deb_add(struct vimc_device *vimc, - const char *vcfg_name) -{ - struct v4l2_device *v4l2_dev = &vimc->v4l2_dev; - struct vimc_deb_device *vdeb; - int ret; - - /* Allocate the vdeb struct */ - vdeb = kzalloc(sizeof(*vdeb), GFP_KERNEL); - if (!vdeb) - return NULL; - - /* Create controls: */ - v4l2_ctrl_handler_init(&vdeb->hdl, 2); - v4l2_ctrl_new_custom(&vdeb->hdl, &vimc_deb_ctrl_class, NULL); - v4l2_ctrl_new_custom(&vdeb->hdl, &vimc_deb_ctrl_mean_win_size, NULL); - vdeb->sd.ctrl_handler = &vdeb->hdl; - if (vdeb->hdl.error) { - ret = vdeb->hdl.error; - goto err_free_vdeb; - } - - /* Initialize ved and sd */ - vdeb->pads[0].flags = MEDIA_PAD_FL_SINK; - vdeb->pads[1].flags = MEDIA_PAD_FL_SOURCE; - - ret = vimc_ent_sd_register(&vdeb->ved, &vdeb->sd, v4l2_dev, - vcfg_name, - MEDIA_ENT_F_PROC_VIDEO_PIXEL_ENC_CONV, 2, - vdeb->pads, &vimc_deb_ops); - if (ret) - goto err_free_hdl; - - vdeb->ved.process_frame = vimc_deb_process_frame; - vdeb->ved.dev = vimc->mdev.dev; - vdeb->mean_win_size = vimc_deb_ctrl_mean_win_size.def; - - /* Initialize the frame format */ - vdeb->sink_fmt = sink_fmt_default; - /* - * TODO: Add support for more output formats, we only support - * RGB888 for now - * NOTE: the src format is always the same as the sink, except - * for the code - */ - vdeb->src_code = MEDIA_BUS_FMT_RGB888_1X24; - vdeb->set_rgb_src = vimc_deb_set_rgb_mbus_fmt_rgb888_1x24; - - return &vdeb->ved; - -err_free_hdl: - v4l2_ctrl_handler_free(&vdeb->hdl); -err_free_vdeb: - kfree(vdeb); - - return NULL; -} diff --git a/drivers/media/platform/vimc/vimc-scaler.c b/drivers/media/platform/vimc/vimc-scaler.c deleted file mode 100644 index 7521439747c5..000000000000 --- a/drivers/media/platform/vimc/vimc-scaler.c +++ /dev/null @@ -1,511 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * vimc-scaler.c Virtual Media Controller Driver - * - * Copyright (C) 2015-2017 Helen Koike - */ - -#include -#include -#include -#include -#include - -#include "vimc-common.h" - -static unsigned int sca_mult = 3; -module_param(sca_mult, uint, 0000); -MODULE_PARM_DESC(sca_mult, " the image size multiplier"); - -#define MAX_ZOOM 8 - -#define VIMC_SCA_FMT_WIDTH_DEFAULT 640 -#define VIMC_SCA_FMT_HEIGHT_DEFAULT 480 - -struct vimc_sca_device { - struct vimc_ent_device ved; - struct v4l2_subdev sd; - /* NOTE: the source fmt is the same as the sink - * with the width and hight multiplied by mult - */ - struct v4l2_mbus_framefmt sink_fmt; - struct v4l2_rect crop_rect; - /* Values calculated when the stream starts */ - u8 *src_frame; - unsigned int src_line_size; - unsigned int bpp; - struct media_pad pads[2]; -}; - -static const struct v4l2_mbus_framefmt sink_fmt_default = { - .width = VIMC_SCA_FMT_WIDTH_DEFAULT, - .height = VIMC_SCA_FMT_HEIGHT_DEFAULT, - .code = MEDIA_BUS_FMT_RGB888_1X24, - .field = V4L2_FIELD_NONE, - .colorspace = V4L2_COLORSPACE_DEFAULT, -}; - -static const struct v4l2_rect crop_rect_default = { - .width = VIMC_SCA_FMT_WIDTH_DEFAULT, - .height = VIMC_SCA_FMT_HEIGHT_DEFAULT, - .top = 0, - .left = 0, -}; - -static const struct v4l2_rect crop_rect_min = { - .width = VIMC_FRAME_MIN_WIDTH, - .height = VIMC_FRAME_MIN_HEIGHT, - .top = 0, - .left = 0, -}; - -static struct v4l2_rect -vimc_sca_get_crop_bound_sink(const struct v4l2_mbus_framefmt *sink_fmt) -{ - /* Get the crop bounds to clamp the crop rectangle correctly */ - struct v4l2_rect r = { - .left = 0, - .top = 0, - .width = sink_fmt->width, - .height = sink_fmt->height, - }; - return r; -} - -static void vimc_sca_adjust_sink_crop(struct v4l2_rect *r, - const struct v4l2_mbus_framefmt *sink_fmt) -{ - const struct v4l2_rect sink_rect = - vimc_sca_get_crop_bound_sink(sink_fmt); - - /* Disallow rectangles smaller than the minimal one. */ - v4l2_rect_set_min_size(r, &crop_rect_min); - v4l2_rect_map_inside(r, &sink_rect); -} - -static int vimc_sca_init_cfg(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg) -{ - struct v4l2_mbus_framefmt *mf; - struct v4l2_rect *r; - unsigned int i; - - mf = v4l2_subdev_get_try_format(sd, cfg, 0); - *mf = sink_fmt_default; - - r = v4l2_subdev_get_try_crop(sd, cfg, 0); - *r = crop_rect_default; - - for (i = 1; i < sd->entity.num_pads; i++) { - mf = v4l2_subdev_get_try_format(sd, cfg, i); - *mf = sink_fmt_default; - mf->width = mf->width * sca_mult; - mf->height = mf->height * sca_mult; - } - - return 0; -} - -static int vimc_sca_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_mbus_code_enum *code) -{ - const struct vimc_pix_map *vpix = vimc_pix_map_by_index(code->index); - - /* We don't support bayer format */ - if (!vpix || vpix->bayer) - return -EINVAL; - - code->code = vpix->code; - - return 0; -} - -static int vimc_sca_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_frame_size_enum *fse) -{ - const struct vimc_pix_map *vpix; - - if (fse->index) - return -EINVAL; - - /* Only accept code in the pix map table in non bayer format */ - vpix = vimc_pix_map_by_code(fse->code); - if (!vpix || vpix->bayer) - return -EINVAL; - - fse->min_width = VIMC_FRAME_MIN_WIDTH; - fse->min_height = VIMC_FRAME_MIN_HEIGHT; - - if (VIMC_IS_SINK(fse->pad)) { - fse->max_width = VIMC_FRAME_MAX_WIDTH; - fse->max_height = VIMC_FRAME_MAX_HEIGHT; - } else { - fse->max_width = VIMC_FRAME_MAX_WIDTH * MAX_ZOOM; - fse->max_height = VIMC_FRAME_MAX_HEIGHT * MAX_ZOOM; - } - - return 0; -} - -static int vimc_sca_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *format) -{ - struct vimc_sca_device *vsca = v4l2_get_subdevdata(sd); - struct v4l2_rect *crop_rect; - - /* Get the current sink format */ - if (format->which == V4L2_SUBDEV_FORMAT_TRY) { - format->format = *v4l2_subdev_get_try_format(sd, cfg, 0); - crop_rect = v4l2_subdev_get_try_crop(sd, cfg, 0); - } else { - format->format = vsca->sink_fmt; - crop_rect = &vsca->crop_rect; - } - - /* Scale the frame size for the source pad */ - if (VIMC_IS_SRC(format->pad)) { - format->format.width = crop_rect->width * sca_mult; - format->format.height = crop_rect->height * sca_mult; - } - - return 0; -} - -static void vimc_sca_adjust_sink_fmt(struct v4l2_mbus_framefmt *fmt) -{ - const struct vimc_pix_map *vpix; - - /* Only accept code in the pix map table in non bayer format */ - vpix = vimc_pix_map_by_code(fmt->code); - if (!vpix || vpix->bayer) - fmt->code = sink_fmt_default.code; - - fmt->width = clamp_t(u32, fmt->width, VIMC_FRAME_MIN_WIDTH, - VIMC_FRAME_MAX_WIDTH) & ~1; - fmt->height = clamp_t(u32, fmt->height, VIMC_FRAME_MIN_HEIGHT, - VIMC_FRAME_MAX_HEIGHT) & ~1; - - if (fmt->field == V4L2_FIELD_ANY) - fmt->field = sink_fmt_default.field; - - vimc_colorimetry_clamp(fmt); -} - -static int vimc_sca_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *fmt) -{ - struct vimc_sca_device *vsca = v4l2_get_subdevdata(sd); - struct v4l2_mbus_framefmt *sink_fmt; - struct v4l2_rect *crop_rect; - - if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { - /* Do not change the format while stream is on */ - if (vsca->src_frame) - return -EBUSY; - - sink_fmt = &vsca->sink_fmt; - crop_rect = &vsca->crop_rect; - } else { - sink_fmt = v4l2_subdev_get_try_format(sd, cfg, 0); - crop_rect = v4l2_subdev_get_try_crop(sd, cfg, 0); - } - - /* - * Do not change the format of the source pad, - * it is propagated from the sink - */ - if (VIMC_IS_SRC(fmt->pad)) { - fmt->format = *sink_fmt; - fmt->format.width = crop_rect->width * sca_mult; - fmt->format.height = crop_rect->height * sca_mult; - } else { - /* Set the new format in the sink pad */ - vimc_sca_adjust_sink_fmt(&fmt->format); - - dev_dbg(vsca->ved.dev, "%s: sink format update: " - "old:%dx%d (0x%x, %d, %d, %d, %d) " - "new:%dx%d (0x%x, %d, %d, %d, %d)\n", vsca->sd.name, - /* old */ - sink_fmt->width, sink_fmt->height, sink_fmt->code, - sink_fmt->colorspace, sink_fmt->quantization, - sink_fmt->xfer_func, sink_fmt->ycbcr_enc, - /* new */ - fmt->format.width, fmt->format.height, fmt->format.code, - fmt->format.colorspace, fmt->format.quantization, - fmt->format.xfer_func, fmt->format.ycbcr_enc); - - *sink_fmt = fmt->format; - - /* Do the crop, but respect the current bounds */ - vimc_sca_adjust_sink_crop(crop_rect, sink_fmt); - } - - return 0; -} - -static int vimc_sca_get_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_selection *sel) -{ - struct vimc_sca_device *vsca = v4l2_get_subdevdata(sd); - struct v4l2_mbus_framefmt *sink_fmt; - struct v4l2_rect *crop_rect; - - if (VIMC_IS_SRC(sel->pad)) - return -EINVAL; - - if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) { - sink_fmt = &vsca->sink_fmt; - crop_rect = &vsca->crop_rect; - } else { - sink_fmt = v4l2_subdev_get_try_format(sd, cfg, 0); - crop_rect = v4l2_subdev_get_try_crop(sd, cfg, 0); - } - - switch (sel->target) { - case V4L2_SEL_TGT_CROP: - sel->r = *crop_rect; - break; - case V4L2_SEL_TGT_CROP_BOUNDS: - sel->r = vimc_sca_get_crop_bound_sink(sink_fmt); - break; - default: - return -EINVAL; - } - - return 0; -} - -static int vimc_sca_set_selection(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_selection *sel) -{ - struct vimc_sca_device *vsca = v4l2_get_subdevdata(sd); - struct v4l2_mbus_framefmt *sink_fmt; - struct v4l2_rect *crop_rect; - - if (VIMC_IS_SRC(sel->pad)) - return -EINVAL; - - if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) { - /* Do not change the format while stream is on */ - if (vsca->src_frame) - return -EBUSY; - - crop_rect = &vsca->crop_rect; - sink_fmt = &vsca->sink_fmt; - } else { - crop_rect = v4l2_subdev_get_try_crop(sd, cfg, 0); - sink_fmt = v4l2_subdev_get_try_format(sd, cfg, 0); - } - - switch (sel->target) { - case V4L2_SEL_TGT_CROP: - /* Do the crop, but respect the current bounds */ - vimc_sca_adjust_sink_crop(&sel->r, sink_fmt); - *crop_rect = sel->r; - break; - default: - return -EINVAL; - } - - return 0; -} - -static const struct v4l2_subdev_pad_ops vimc_sca_pad_ops = { - .init_cfg = vimc_sca_init_cfg, - .enum_mbus_code = vimc_sca_enum_mbus_code, - .enum_frame_size = vimc_sca_enum_frame_size, - .get_fmt = vimc_sca_get_fmt, - .set_fmt = vimc_sca_set_fmt, - .get_selection = vimc_sca_get_selection, - .set_selection = vimc_sca_set_selection, -}; - -static int vimc_sca_s_stream(struct v4l2_subdev *sd, int enable) -{ - struct vimc_sca_device *vsca = v4l2_get_subdevdata(sd); - - if (enable) { - const struct vimc_pix_map *vpix; - unsigned int frame_size; - - if (vsca->src_frame) - return 0; - - /* Save the bytes per pixel of the sink */ - vpix = vimc_pix_map_by_code(vsca->sink_fmt.code); - vsca->bpp = vpix->bpp; - - /* Calculate the width in bytes of the src frame */ - vsca->src_line_size = vsca->crop_rect.width * - sca_mult * vsca->bpp; - - /* Calculate the frame size of the source pad */ - frame_size = vsca->src_line_size * vsca->crop_rect.height * - sca_mult; - - /* Allocate the frame buffer. Use vmalloc to be able to - * allocate a large amount of memory - */ - vsca->src_frame = vmalloc(frame_size); - if (!vsca->src_frame) - return -ENOMEM; - - } else { - if (!vsca->src_frame) - return 0; - - vfree(vsca->src_frame); - vsca->src_frame = NULL; - } - - return 0; -} - -static const struct v4l2_subdev_video_ops vimc_sca_video_ops = { - .s_stream = vimc_sca_s_stream, -}; - -static const struct v4l2_subdev_ops vimc_sca_ops = { - .pad = &vimc_sca_pad_ops, - .video = &vimc_sca_video_ops, -}; - -static void vimc_sca_fill_pix(u8 *const ptr, - const u8 *const pixel, - const unsigned int bpp) -{ - unsigned int i; - - /* copy the pixel to the pointer */ - for (i = 0; i < bpp; i++) - ptr[i] = pixel[i]; -} - -static void vimc_sca_scale_pix(const struct vimc_sca_device *const vsca, - unsigned int lin, unsigned int col, - const u8 *const sink_frame) -{ - const struct v4l2_rect crop_rect = vsca->crop_rect; - unsigned int i, j, index; - const u8 *pixel; - - /* Point to the pixel value in position (lin, col) in the sink frame */ - index = VIMC_FRAME_INDEX(lin, col, - vsca->sink_fmt.width, - vsca->bpp); - pixel = &sink_frame[index]; - - dev_dbg(vsca->ved.dev, - "sca: %s: --- scale_pix sink pos %dx%d, index %d ---\n", - vsca->sd.name, lin, col, index); - - /* point to the place we are going to put the first pixel - * in the scaled src frame - */ - lin -= crop_rect.top; - col -= crop_rect.left; - index = VIMC_FRAME_INDEX(lin * sca_mult, col * sca_mult, - crop_rect.width * sca_mult, vsca->bpp); - - dev_dbg(vsca->ved.dev, "sca: %s: scale_pix src pos %dx%d, index %d\n", - vsca->sd.name, lin * sca_mult, col * sca_mult, index); - - /* Repeat this pixel mult times */ - for (i = 0; i < sca_mult; i++) { - /* Iterate through each beginning of a - * pixel repetition in a line - */ - for (j = 0; j < sca_mult * vsca->bpp; j += vsca->bpp) { - dev_dbg(vsca->ved.dev, - "sca: %s: sca: scale_pix src pos %d\n", - vsca->sd.name, index + j); - - /* copy the pixel to the position index + j */ - vimc_sca_fill_pix(&vsca->src_frame[index + j], - pixel, vsca->bpp); - } - - /* move the index to the next line */ - index += vsca->src_line_size; - } -} - -static void vimc_sca_fill_src_frame(const struct vimc_sca_device *const vsca, - const u8 *const sink_frame) -{ - const struct v4l2_rect r = vsca->crop_rect; - unsigned int i, j; - - /* Scale each pixel from the original sink frame */ - /* TODO: implement scale down, only scale up is supported for now */ - for (i = r.top; i < r.top + r.height; i++) - for (j = r.left; j < r.left + r.width; j++) - vimc_sca_scale_pix(vsca, i, j, sink_frame); -} - -static void *vimc_sca_process_frame(struct vimc_ent_device *ved, - const void *sink_frame) -{ - struct vimc_sca_device *vsca = container_of(ved, struct vimc_sca_device, - ved); - - /* If the stream in this node is not active, just return */ - if (!vsca->src_frame) - return ERR_PTR(-EINVAL); - - vimc_sca_fill_src_frame(vsca, sink_frame); - - return vsca->src_frame; -}; - -void vimc_sca_release(struct vimc_ent_device *ved) -{ - struct vimc_sca_device *vsca = - container_of(ved, struct vimc_sca_device, ved); - - media_entity_cleanup(vsca->ved.ent); - kfree(vsca); -} - -struct vimc_ent_device *vimc_sca_add(struct vimc_device *vimc, - const char *vcfg_name) -{ - struct v4l2_device *v4l2_dev = &vimc->v4l2_dev; - struct vimc_sca_device *vsca; - int ret; - - /* Allocate the vsca struct */ - vsca = kzalloc(sizeof(*vsca), GFP_KERNEL); - if (!vsca) - return NULL; - - /* Initialize ved and sd */ - vsca->pads[0].flags = MEDIA_PAD_FL_SINK; - vsca->pads[1].flags = MEDIA_PAD_FL_SOURCE; - - ret = vimc_ent_sd_register(&vsca->ved, &vsca->sd, v4l2_dev, - vcfg_name, - MEDIA_ENT_F_PROC_VIDEO_SCALER, 2, - vsca->pads, &vimc_sca_ops); - if (ret) { - kfree(vsca); - return NULL; - } - - vsca->ved.process_frame = vimc_sca_process_frame; - vsca->ved.dev = vimc->mdev.dev; - - /* Initialize the frame format */ - vsca->sink_fmt = sink_fmt_default; - - /* Initialize the crop selection */ - vsca->crop_rect = crop_rect_default; - - return &vsca->ved; -} diff --git a/drivers/media/platform/vimc/vimc-sensor.c b/drivers/media/platform/vimc/vimc-sensor.c deleted file mode 100644 index 92daee58209e..000000000000 --- a/drivers/media/platform/vimc/vimc-sensor.c +++ /dev/null @@ -1,376 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * vimc-sensor.c Virtual Media Controller Driver - * - * Copyright (C) 2015-2017 Helen Koike - */ - -#include -#include -#include -#include -#include -#include - -#include "vimc-common.h" - -struct vimc_sen_device { - struct vimc_ent_device ved; - struct v4l2_subdev sd; - struct tpg_data tpg; - u8 *frame; - /* The active format */ - struct v4l2_mbus_framefmt mbus_format; - struct v4l2_ctrl_handler hdl; - struct media_pad pad; -}; - -static const struct v4l2_mbus_framefmt fmt_default = { - .width = 640, - .height = 480, - .code = MEDIA_BUS_FMT_RGB888_1X24, - .field = V4L2_FIELD_NONE, - .colorspace = V4L2_COLORSPACE_DEFAULT, -}; - -static int vimc_sen_init_cfg(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg) -{ - unsigned int i; - - for (i = 0; i < sd->entity.num_pads; i++) { - struct v4l2_mbus_framefmt *mf; - - mf = v4l2_subdev_get_try_format(sd, cfg, i); - *mf = fmt_default; - } - - return 0; -} - -static int vimc_sen_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_mbus_code_enum *code) -{ - const struct vimc_pix_map *vpix = vimc_pix_map_by_index(code->index); - - if (!vpix) - return -EINVAL; - - code->code = vpix->code; - - return 0; -} - -static int vimc_sen_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_frame_size_enum *fse) -{ - const struct vimc_pix_map *vpix; - - if (fse->index) - return -EINVAL; - - /* Only accept code in the pix map table */ - vpix = vimc_pix_map_by_code(fse->code); - if (!vpix) - return -EINVAL; - - fse->min_width = VIMC_FRAME_MIN_WIDTH; - fse->max_width = VIMC_FRAME_MAX_WIDTH; - fse->min_height = VIMC_FRAME_MIN_HEIGHT; - fse->max_height = VIMC_FRAME_MAX_HEIGHT; - - return 0; -} - -static int vimc_sen_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *fmt) -{ - struct vimc_sen_device *vsen = - container_of(sd, struct vimc_sen_device, sd); - - fmt->format = fmt->which == V4L2_SUBDEV_FORMAT_TRY ? - *v4l2_subdev_get_try_format(sd, cfg, fmt->pad) : - vsen->mbus_format; - - return 0; -} - -static void vimc_sen_tpg_s_format(struct vimc_sen_device *vsen) -{ - const struct vimc_pix_map *vpix = - vimc_pix_map_by_code(vsen->mbus_format.code); - - tpg_reset_source(&vsen->tpg, vsen->mbus_format.width, - vsen->mbus_format.height, vsen->mbus_format.field); - tpg_s_bytesperline(&vsen->tpg, 0, vsen->mbus_format.width * vpix->bpp); - tpg_s_buf_height(&vsen->tpg, vsen->mbus_format.height); - tpg_s_fourcc(&vsen->tpg, vpix->pixelformat); - /* TODO: add support for V4L2_FIELD_ALTERNATE */ - tpg_s_field(&vsen->tpg, vsen->mbus_format.field, false); - tpg_s_colorspace(&vsen->tpg, vsen->mbus_format.colorspace); - tpg_s_ycbcr_enc(&vsen->tpg, vsen->mbus_format.ycbcr_enc); - tpg_s_quantization(&vsen->tpg, vsen->mbus_format.quantization); - tpg_s_xfer_func(&vsen->tpg, vsen->mbus_format.xfer_func); -} - -static void vimc_sen_adjust_fmt(struct v4l2_mbus_framefmt *fmt) -{ - const struct vimc_pix_map *vpix; - - /* Only accept code in the pix map table */ - vpix = vimc_pix_map_by_code(fmt->code); - if (!vpix) - fmt->code = fmt_default.code; - - fmt->width = clamp_t(u32, fmt->width, VIMC_FRAME_MIN_WIDTH, - VIMC_FRAME_MAX_WIDTH) & ~1; - fmt->height = clamp_t(u32, fmt->height, VIMC_FRAME_MIN_HEIGHT, - VIMC_FRAME_MAX_HEIGHT) & ~1; - - /* TODO: add support for V4L2_FIELD_ALTERNATE */ - if (fmt->field == V4L2_FIELD_ANY || fmt->field == V4L2_FIELD_ALTERNATE) - fmt->field = fmt_default.field; - - vimc_colorimetry_clamp(fmt); -} - -static int vimc_sen_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_pad_config *cfg, - struct v4l2_subdev_format *fmt) -{ - struct vimc_sen_device *vsen = v4l2_get_subdevdata(sd); - struct v4l2_mbus_framefmt *mf; - - if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { - /* Do not change the format while stream is on */ - if (vsen->frame) - return -EBUSY; - - mf = &vsen->mbus_format; - } else { - mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad); - } - - /* Set the new format */ - vimc_sen_adjust_fmt(&fmt->format); - - dev_dbg(vsen->ved.dev, "%s: format update: " - "old:%dx%d (0x%x, %d, %d, %d, %d) " - "new:%dx%d (0x%x, %d, %d, %d, %d)\n", vsen->sd.name, - /* old */ - mf->width, mf->height, mf->code, - mf->colorspace, mf->quantization, - mf->xfer_func, mf->ycbcr_enc, - /* new */ - fmt->format.width, fmt->format.height, fmt->format.code, - fmt->format.colorspace, fmt->format.quantization, - fmt->format.xfer_func, fmt->format.ycbcr_enc); - - *mf = fmt->format; - - return 0; -} - -static const struct v4l2_subdev_pad_ops vimc_sen_pad_ops = { - .init_cfg = vimc_sen_init_cfg, - .enum_mbus_code = vimc_sen_enum_mbus_code, - .enum_frame_size = vimc_sen_enum_frame_size, - .get_fmt = vimc_sen_get_fmt, - .set_fmt = vimc_sen_set_fmt, -}; - -static void *vimc_sen_process_frame(struct vimc_ent_device *ved, - const void *sink_frame) -{ - struct vimc_sen_device *vsen = container_of(ved, struct vimc_sen_device, - ved); - - tpg_fill_plane_buffer(&vsen->tpg, 0, 0, vsen->frame); - return vsen->frame; -} - -static int vimc_sen_s_stream(struct v4l2_subdev *sd, int enable) -{ - struct vimc_sen_device *vsen = - container_of(sd, struct vimc_sen_device, sd); - - if (enable) { - const struct vimc_pix_map *vpix; - unsigned int frame_size; - - /* Calculate the frame size */ - vpix = vimc_pix_map_by_code(vsen->mbus_format.code); - frame_size = vsen->mbus_format.width * vpix->bpp * - vsen->mbus_format.height; - - /* - * Allocate the frame buffer. Use vmalloc to be able to - * allocate a large amount of memory - */ - vsen->frame = vmalloc(frame_size); - if (!vsen->frame) - return -ENOMEM; - - /* configure the test pattern generator */ - vimc_sen_tpg_s_format(vsen); - - } else { - - vfree(vsen->frame); - vsen->frame = NULL; - } - - return 0; -} - -static const struct v4l2_subdev_core_ops vimc_sen_core_ops = { - .log_status = v4l2_ctrl_subdev_log_status, - .subscribe_event = v4l2_ctrl_subdev_subscribe_event, - .unsubscribe_event = v4l2_event_subdev_unsubscribe, -}; - -static const struct v4l2_subdev_video_ops vimc_sen_video_ops = { - .s_stream = vimc_sen_s_stream, -}; - -static const struct v4l2_subdev_ops vimc_sen_ops = { - .core = &vimc_sen_core_ops, - .pad = &vimc_sen_pad_ops, - .video = &vimc_sen_video_ops, -}; - -static int vimc_sen_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct vimc_sen_device *vsen = - container_of(ctrl->handler, struct vimc_sen_device, hdl); - - switch (ctrl->id) { - case VIMC_CID_TEST_PATTERN: - tpg_s_pattern(&vsen->tpg, ctrl->val); - break; - case V4L2_CID_HFLIP: - tpg_s_hflip(&vsen->tpg, ctrl->val); - break; - case V4L2_CID_VFLIP: - tpg_s_vflip(&vsen->tpg, ctrl->val); - break; - case V4L2_CID_BRIGHTNESS: - tpg_s_brightness(&vsen->tpg, ctrl->val); - break; - case V4L2_CID_CONTRAST: - tpg_s_contrast(&vsen->tpg, ctrl->val); - break; - case V4L2_CID_HUE: - tpg_s_hue(&vsen->tpg, ctrl->val); - break; - case V4L2_CID_SATURATION: - tpg_s_saturation(&vsen->tpg, ctrl->val); - break; - default: - return -EINVAL; - } - return 0; -} - -static const struct v4l2_ctrl_ops vimc_sen_ctrl_ops = { - .s_ctrl = vimc_sen_s_ctrl, -}; - -void vimc_sen_release(struct vimc_ent_device *ved) -{ - struct vimc_sen_device *vsen = - container_of(ved, struct vimc_sen_device, ved); - - v4l2_ctrl_handler_free(&vsen->hdl); - tpg_free(&vsen->tpg); - media_entity_cleanup(vsen->ved.ent); - kfree(vsen); -} - -/* Image Processing Controls */ -static const struct v4l2_ctrl_config vimc_sen_ctrl_class = { - .flags = V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_WRITE_ONLY, - .id = VIMC_CID_VIMC_CLASS, - .name = "VIMC Controls", - .type = V4L2_CTRL_TYPE_CTRL_CLASS, -}; - -static const struct v4l2_ctrl_config vimc_sen_ctrl_test_pattern = { - .ops = &vimc_sen_ctrl_ops, - .id = VIMC_CID_TEST_PATTERN, - .name = "Test Pattern", - .type = V4L2_CTRL_TYPE_MENU, - .max = TPG_PAT_NOISE, - .qmenu = tpg_pattern_strings, -}; - -struct vimc_ent_device *vimc_sen_add(struct vimc_device *vimc, - const char *vcfg_name) -{ - struct v4l2_device *v4l2_dev = &vimc->v4l2_dev; - struct vimc_sen_device *vsen; - int ret; - - /* Allocate the vsen struct */ - vsen = kzalloc(sizeof(*vsen), GFP_KERNEL); - if (!vsen) - return NULL; - - v4l2_ctrl_handler_init(&vsen->hdl, 4); - - v4l2_ctrl_new_custom(&vsen->hdl, &vimc_sen_ctrl_class, NULL); - v4l2_ctrl_new_custom(&vsen->hdl, &vimc_sen_ctrl_test_pattern, NULL); - v4l2_ctrl_new_std(&vsen->hdl, &vimc_sen_ctrl_ops, - V4L2_CID_VFLIP, 0, 1, 1, 0); - v4l2_ctrl_new_std(&vsen->hdl, &vimc_sen_ctrl_ops, - V4L2_CID_HFLIP, 0, 1, 1, 0); - v4l2_ctrl_new_std(&vsen->hdl, &vimc_sen_ctrl_ops, - V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); - v4l2_ctrl_new_std(&vsen->hdl, &vimc_sen_ctrl_ops, - V4L2_CID_CONTRAST, 0, 255, 1, 128); - v4l2_ctrl_new_std(&vsen->hdl, &vimc_sen_ctrl_ops, - V4L2_CID_HUE, -128, 127, 1, 0); - v4l2_ctrl_new_std(&vsen->hdl, &vimc_sen_ctrl_ops, - V4L2_CID_SATURATION, 0, 255, 1, 128); - vsen->sd.ctrl_handler = &vsen->hdl; - if (vsen->hdl.error) { - ret = vsen->hdl.error; - goto err_free_vsen; - } - - /* Initialize the test pattern generator */ - tpg_init(&vsen->tpg, vsen->mbus_format.width, - vsen->mbus_format.height); - ret = tpg_alloc(&vsen->tpg, VIMC_FRAME_MAX_WIDTH); - if (ret) - goto err_free_hdl; - - /* Initialize ved and sd */ - vsen->pad.flags = MEDIA_PAD_FL_SOURCE; - ret = vimc_ent_sd_register(&vsen->ved, &vsen->sd, v4l2_dev, - vcfg_name, - MEDIA_ENT_F_CAM_SENSOR, 1, &vsen->pad, - &vimc_sen_ops); - if (ret) - goto err_free_tpg; - - vsen->ved.process_frame = vimc_sen_process_frame; - vsen->ved.dev = vimc->mdev.dev; - - /* Initialize the frame format */ - vsen->mbus_format = fmt_default; - - return &vsen->ved; - -err_free_tpg: - tpg_free(&vsen->tpg); -err_free_hdl: - v4l2_ctrl_handler_free(&vsen->hdl); -err_free_vsen: - kfree(vsen); - - return NULL; -} diff --git a/drivers/media/platform/vimc/vimc-streamer.c b/drivers/media/platform/vimc/vimc-streamer.c deleted file mode 100644 index 65feb3c596db..000000000000 --- a/drivers/media/platform/vimc/vimc-streamer.c +++ /dev/null @@ -1,238 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * vimc-streamer.c Virtual Media Controller Driver - * - * Copyright (C) 2018 Lucas A. M. Magalhães - * - */ - -#include -#include -#include - -#include "vimc-streamer.h" - -/** - * vimc_get_source_entity - get the entity connected with the first sink pad - * - * @ent: reference media_entity - * - * Helper function that returns the media entity containing the source pad - * linked with the first sink pad from the given media entity pad list. - * - * Return: The source pad or NULL, if it wasn't found. - */ -static struct media_entity *vimc_get_source_entity(struct media_entity *ent) -{ - struct media_pad *pad; - int i; - - for (i = 0; i < ent->num_pads; i++) { - if (ent->pads[i].flags & MEDIA_PAD_FL_SOURCE) - continue; - pad = media_entity_remote_pad(&ent->pads[i]); - return pad ? pad->entity : NULL; - } - return NULL; -} - -/** - * vimc_streamer_pipeline_terminate - Disable stream in all ved in stream - * - * @stream: the pointer to the stream structure with the pipeline to be - * disabled. - * - * Calls s_stream to disable the stream in each entity of the pipeline - * - */ -static void vimc_streamer_pipeline_terminate(struct vimc_stream *stream) -{ - struct vimc_ent_device *ved; - struct v4l2_subdev *sd; - - while (stream->pipe_size) { - stream->pipe_size--; - ved = stream->ved_pipeline[stream->pipe_size]; - stream->ved_pipeline[stream->pipe_size] = NULL; - - if (!is_media_entity_v4l2_subdev(ved->ent)) - continue; - - sd = media_entity_to_v4l2_subdev(ved->ent); - v4l2_subdev_call(sd, video, s_stream, 0); - } -} - -/** - * vimc_streamer_pipeline_init - Initializes the stream structure - * - * @stream: the pointer to the stream structure to be initialized - * @ved: the pointer to the vimc entity initializing the stream - * - * Initializes the stream structure. Walks through the entity graph to - * construct the pipeline used later on the streamer thread. - * Calls vimc_streamer_s_stream() to enable stream in all entities of - * the pipeline. - * - * Return: 0 if success, error code otherwise. - */ -static int vimc_streamer_pipeline_init(struct vimc_stream *stream, - struct vimc_ent_device *ved) -{ - struct media_entity *entity; - struct video_device *vdev; - struct v4l2_subdev *sd; - int ret = 0; - - stream->pipe_size = 0; - while (stream->pipe_size < VIMC_STREAMER_PIPELINE_MAX_SIZE) { - if (!ved) { - vimc_streamer_pipeline_terminate(stream); - return -EINVAL; - } - stream->ved_pipeline[stream->pipe_size++] = ved; - - if (is_media_entity_v4l2_subdev(ved->ent)) { - sd = media_entity_to_v4l2_subdev(ved->ent); - ret = v4l2_subdev_call(sd, video, s_stream, 1); - if (ret && ret != -ENOIOCTLCMD) { - dev_err(ved->dev, "subdev_call error %s\n", - ved->ent->name); - vimc_streamer_pipeline_terminate(stream); - return ret; - } - } - - entity = vimc_get_source_entity(ved->ent); - /* Check if the end of the pipeline was reached */ - if (!entity) { - /* the first entity of the pipe should be source only */ - if (!vimc_is_source(ved->ent)) { - dev_err(ved->dev, - "first entity in the pipe '%s' is not a source\n", - ved->ent->name); - vimc_streamer_pipeline_terminate(stream); - return -EPIPE; - } - return 0; - } - - /* Get the next device in the pipeline */ - if (is_media_entity_v4l2_subdev(entity)) { - sd = media_entity_to_v4l2_subdev(entity); - ved = v4l2_get_subdevdata(sd); - } else { - vdev = container_of(entity, - struct video_device, - entity); - ved = video_get_drvdata(vdev); - } - } - - vimc_streamer_pipeline_terminate(stream); - return -EINVAL; -} - -/** - * vimc_streamer_thread - Process frames through the pipeline - * - * @data: vimc_stream struct of the current stream - * - * From the source to the sink, gets a frame from each subdevice and send to - * the next one of the pipeline at a fixed framerate. - * - * Return: - * Always zero (created as ``int`` instead of ``void`` to comply with - * kthread API). - */ -static int vimc_streamer_thread(void *data) -{ - struct vimc_stream *stream = data; - u8 *frame = NULL; - int i; - - set_freezable(); - - for (;;) { - try_to_freeze(); - if (kthread_should_stop()) - break; - - for (i = stream->pipe_size - 1; i >= 0; i--) { - frame = stream->ved_pipeline[i]->process_frame( - stream->ved_pipeline[i], frame); - if (!frame || IS_ERR(frame)) - break; - } - //wait for 60hz - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ / 60); - } - - return 0; -} - -/** - * vimc_streamer_s_stream - Start/stop the streaming on the media pipeline - * - * @stream: the pointer to the stream structure of the current stream - * @ved: pointer to the vimc entity of the entity of the stream - * @enable: flag to determine if stream should start/stop - * - * When starting, check if there is no ``stream->kthread`` allocated. This - * should indicate that a stream is already running. Then, it initializes the - * pipeline, creates and runs a kthread to consume buffers through the pipeline. - * When stopping, analogously check if there is a stream running, stop the - * thread and terminates the pipeline. - * - * Return: 0 if success, error code otherwise. - */ -int vimc_streamer_s_stream(struct vimc_stream *stream, - struct vimc_ent_device *ved, - int enable) -{ - int ret; - - if (!stream || !ved) - return -EINVAL; - - if (enable) { - if (stream->kthread) - return 0; - - ret = vimc_streamer_pipeline_init(stream, ved); - if (ret) - return ret; - - stream->kthread = kthread_run(vimc_streamer_thread, stream, - "vimc-streamer thread"); - - if (IS_ERR(stream->kthread)) { - ret = PTR_ERR(stream->kthread); - dev_err(ved->dev, "kthread_run failed with %d\n", ret); - vimc_streamer_pipeline_terminate(stream); - stream->kthread = NULL; - return ret; - } - - } else { - if (!stream->kthread) - return 0; - - ret = kthread_stop(stream->kthread); - /* - * kthread_stop returns -EINTR in cases when streamon was - * immediately followed by streamoff, and the thread didn't had - * a chance to run. Ignore errors to stop the stream in the - * pipeline. - */ - if (ret) - dev_dbg(ved->dev, "kthread_stop returned '%d'\n", ret); - - stream->kthread = NULL; - - vimc_streamer_pipeline_terminate(stream); - } - - return 0; -} diff --git a/drivers/media/platform/vimc/vimc-streamer.h b/drivers/media/platform/vimc/vimc-streamer.h deleted file mode 100644 index fe3c51f15fad..000000000000 --- a/drivers/media/platform/vimc/vimc-streamer.h +++ /dev/null @@ -1,44 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * vimc-streamer.h Virtual Media Controller Driver - * - * Copyright (C) 2018 Lucas A. M. Magalhães - * - */ - -#ifndef _VIMC_STREAMER_H_ -#define _VIMC_STREAMER_H_ - -#include - -#include "vimc-common.h" - -#define VIMC_STREAMER_PIPELINE_MAX_SIZE 16 - -/** - * struct vimc_stream - struct that represents a stream in the pipeline - * - * @pipe: the media pipeline object associated with this stream - * @ved_pipeline: array containing all the entities participating in the - * stream. The order is from a video device (usually a capture device) where - * stream_on was called, to the entity generating the first base image to be - * processed in the pipeline. - * @pipe_size: size of @ved_pipeline - * @kthread: thread that generates the frames of the stream. - * - * When the user call stream_on in a video device, struct vimc_stream is - * used to keep track of all entities and subdevices that generates and - * process frames for the stream. - */ -struct vimc_stream { - struct media_pipeline pipe; - struct vimc_ent_device *ved_pipeline[VIMC_STREAMER_PIPELINE_MAX_SIZE]; - unsigned int pipe_size; - struct task_struct *kthread; -}; - -int vimc_streamer_s_stream(struct vimc_stream *stream, - struct vimc_ent_device *ved, - int enable); - -#endif //_VIMC_STREAMER_H_ diff --git a/drivers/media/platform/vivid/Kconfig b/drivers/media/platform/vivid/Kconfig deleted file mode 100644 index e2ff06edfa93..000000000000 --- a/drivers/media/platform/vivid/Kconfig +++ /dev/null @@ -1,41 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0-only -config VIDEO_VIVID - tristate "Virtual Video Test Driver" - depends on VIDEO_DEV && VIDEO_V4L2 && !SPARC32 && !SPARC64 && FB - depends on HAS_DMA - select FONT_SUPPORT - select FONT_8x16 - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - select VIDEOBUF2_VMALLOC - select VIDEOBUF2_DMA_CONTIG - select VIDEO_V4L2_TPG - help - Enables a virtual video driver. This driver emulates a webcam, - TV, S-Video and HDMI capture hardware, including VBI support for - the SDTV inputs. Also video output, VBI output, radio receivers, - transmitters and software defined radio capture is emulated. - - It is highly configurable and is ideal for testing applications. - Error injection is supported to test rare errors that are hard - to reproduce in real hardware. - - Say Y here if you want to test video apps or debug V4L devices. - When in doubt, say N. - -config VIDEO_VIVID_CEC - bool "Enable CEC emulation support" - depends on VIDEO_VIVID - select CEC_CORE - help - When selected the vivid module will emulate the optional - HDMI CEC feature. - -config VIDEO_VIVID_MAX_DEVS - int "Maximum number of devices" - depends on VIDEO_VIVID - default "64" - help - This allows you to specify the maximum number of devices supported - by the vivid driver. diff --git a/drivers/media/platform/vivid/Makefile b/drivers/media/platform/vivid/Makefile deleted file mode 100644 index b12ad0152a3e..000000000000 --- a/drivers/media/platform/vivid/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -vivid-objs := vivid-core.o vivid-ctrls.o vivid-vid-common.o vivid-vbi-gen.o \ - vivid-vid-cap.o vivid-vid-out.o vivid-kthread-cap.o vivid-kthread-out.o \ - vivid-radio-rx.o vivid-radio-tx.o vivid-radio-common.o \ - vivid-rds-gen.o vivid-sdr-cap.o vivid-vbi-cap.o vivid-vbi-out.o \ - vivid-osd.o vivid-meta-cap.o vivid-meta-out.o \ - vivid-kthread-touch.o vivid-touch-cap.o -ifeq ($(CONFIG_VIDEO_VIVID_CEC),y) - vivid-objs += vivid-cec.o -endif - -obj-$(CONFIG_VIDEO_VIVID) += vivid.o diff --git a/drivers/media/platform/vivid/vivid-cec.c b/drivers/media/platform/vivid/vivid-cec.c deleted file mode 100644 index 4d2413e87730..000000000000 --- a/drivers/media/platform/vivid/vivid-cec.c +++ /dev/null @@ -1,286 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * vivid-cec.c - A Virtual Video Test Driver, cec emulation - * - * Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - */ - -#include - -#include "vivid-core.h" -#include "vivid-cec.h" - -#define CEC_TIM_START_BIT_TOTAL 4500 -#define CEC_TIM_START_BIT_LOW 3700 -#define CEC_TIM_START_BIT_HIGH 800 -#define CEC_TIM_DATA_BIT_TOTAL 2400 -#define CEC_TIM_DATA_BIT_0_LOW 1500 -#define CEC_TIM_DATA_BIT_0_HIGH 900 -#define CEC_TIM_DATA_BIT_1_LOW 600 -#define CEC_TIM_DATA_BIT_1_HIGH 1800 - -void vivid_cec_bus_free_work(struct vivid_dev *dev) -{ - spin_lock(&dev->cec_slock); - while (!list_empty(&dev->cec_work_list)) { - struct vivid_cec_work *cw = - list_first_entry(&dev->cec_work_list, - struct vivid_cec_work, list); - - spin_unlock(&dev->cec_slock); - cancel_delayed_work_sync(&cw->work); - spin_lock(&dev->cec_slock); - list_del(&cw->list); - cec_transmit_attempt_done(cw->adap, CEC_TX_STATUS_LOW_DRIVE); - kfree(cw); - } - spin_unlock(&dev->cec_slock); -} - -static bool vivid_cec_find_dest_adap(struct vivid_dev *dev, - struct cec_adapter *adap, u8 dest) -{ - unsigned int i; - - if (dest >= 0xf) - return false; - - if (adap != dev->cec_rx_adap && dev->cec_rx_adap && - dev->cec_rx_adap->is_configured && - cec_has_log_addr(dev->cec_rx_adap, dest)) - return true; - - for (i = 0; i < MAX_OUTPUTS && dev->cec_tx_adap[i]; i++) { - if (adap == dev->cec_tx_adap[i]) - continue; - if (!dev->cec_tx_adap[i]->is_configured) - continue; - if (cec_has_log_addr(dev->cec_tx_adap[i], dest)) - return true; - } - return false; -} - -static void vivid_cec_pin_adap_events(struct cec_adapter *adap, ktime_t ts, - const struct cec_msg *msg, bool nacked) -{ - unsigned int len = nacked ? 1 : msg->len; - unsigned int i; - bool bit; - - if (adap == NULL) - return; - - /* - * Suffix ULL on constant 10 makes the expression - * CEC_TIM_START_BIT_TOTAL + 10ULL * len * CEC_TIM_DATA_BIT_TOTAL - * to be evaluated using 64-bit unsigned arithmetic (u64), which - * is what ktime_sub_us expects as second argument. - */ - ts = ktime_sub_us(ts, CEC_TIM_START_BIT_TOTAL + - 10ULL * len * CEC_TIM_DATA_BIT_TOTAL); - cec_queue_pin_cec_event(adap, false, false, ts); - ts = ktime_add_us(ts, CEC_TIM_START_BIT_LOW); - cec_queue_pin_cec_event(adap, true, false, ts); - ts = ktime_add_us(ts, CEC_TIM_START_BIT_HIGH); - - for (i = 0; i < 10 * len; i++) { - switch (i % 10) { - case 0 ... 7: - bit = msg->msg[i / 10] & (0x80 >> (i % 10)); - break; - case 8: /* EOM */ - bit = i / 10 == msg->len - 1; - break; - case 9: /* ACK */ - bit = cec_msg_is_broadcast(msg) ^ nacked; - break; - } - cec_queue_pin_cec_event(adap, false, false, ts); - if (bit) - ts = ktime_add_us(ts, CEC_TIM_DATA_BIT_1_LOW); - else - ts = ktime_add_us(ts, CEC_TIM_DATA_BIT_0_LOW); - cec_queue_pin_cec_event(adap, true, false, ts); - if (bit) - ts = ktime_add_us(ts, CEC_TIM_DATA_BIT_1_HIGH); - else - ts = ktime_add_us(ts, CEC_TIM_DATA_BIT_0_HIGH); - } -} - -static void vivid_cec_pin_events(struct vivid_dev *dev, - const struct cec_msg *msg, bool nacked) -{ - ktime_t ts = ktime_get(); - unsigned int i; - - vivid_cec_pin_adap_events(dev->cec_rx_adap, ts, msg, nacked); - for (i = 0; i < MAX_OUTPUTS; i++) - vivid_cec_pin_adap_events(dev->cec_tx_adap[i], ts, msg, nacked); -} - -static void vivid_cec_xfer_done_worker(struct work_struct *work) -{ - struct vivid_cec_work *cw = - container_of(work, struct vivid_cec_work, work.work); - struct vivid_dev *dev = cw->dev; - struct cec_adapter *adap = cw->adap; - u8 dest = cec_msg_destination(&cw->msg); - bool valid_dest; - unsigned int i; - - valid_dest = cec_msg_is_broadcast(&cw->msg); - if (!valid_dest) - valid_dest = vivid_cec_find_dest_adap(dev, adap, dest); - - cw->tx_status = valid_dest ? CEC_TX_STATUS_OK : CEC_TX_STATUS_NACK; - spin_lock(&dev->cec_slock); - dev->cec_xfer_time_jiffies = 0; - dev->cec_xfer_start_jiffies = 0; - list_del(&cw->list); - spin_unlock(&dev->cec_slock); - vivid_cec_pin_events(dev, &cw->msg, !valid_dest); - cec_transmit_attempt_done(cw->adap, cw->tx_status); - - /* Broadcast message */ - if (adap != dev->cec_rx_adap) - cec_received_msg(dev->cec_rx_adap, &cw->msg); - for (i = 0; i < MAX_OUTPUTS && dev->cec_tx_adap[i]; i++) - if (adap != dev->cec_tx_adap[i]) - cec_received_msg(dev->cec_tx_adap[i], &cw->msg); - kfree(cw); -} - -static void vivid_cec_xfer_try_worker(struct work_struct *work) -{ - struct vivid_cec_work *cw = - container_of(work, struct vivid_cec_work, work.work); - struct vivid_dev *dev = cw->dev; - - spin_lock(&dev->cec_slock); - if (dev->cec_xfer_time_jiffies) { - list_del(&cw->list); - spin_unlock(&dev->cec_slock); - cec_transmit_attempt_done(cw->adap, CEC_TX_STATUS_ARB_LOST); - kfree(cw); - } else { - INIT_DELAYED_WORK(&cw->work, vivid_cec_xfer_done_worker); - dev->cec_xfer_start_jiffies = jiffies; - dev->cec_xfer_time_jiffies = usecs_to_jiffies(cw->usecs); - spin_unlock(&dev->cec_slock); - schedule_delayed_work(&cw->work, dev->cec_xfer_time_jiffies); - } -} - -static int vivid_cec_adap_enable(struct cec_adapter *adap, bool enable) -{ - adap->cec_pin_is_high = true; - return 0; -} - -static int vivid_cec_adap_log_addr(struct cec_adapter *adap, u8 log_addr) -{ - return 0; -} - -/* - * One data bit takes 2400 us, each byte needs 10 bits so that's 24000 us - * per byte. - */ -#define USECS_PER_BYTE 24000 - -static int vivid_cec_adap_transmit(struct cec_adapter *adap, u8 attempts, - u32 signal_free_time, struct cec_msg *msg) -{ - struct vivid_dev *dev = cec_get_drvdata(adap); - struct vivid_cec_work *cw = kzalloc(sizeof(*cw), GFP_KERNEL); - long delta_jiffies = 0; - - if (cw == NULL) - return -ENOMEM; - cw->dev = dev; - cw->adap = adap; - cw->usecs = CEC_FREE_TIME_TO_USEC(signal_free_time) + - msg->len * USECS_PER_BYTE; - cw->msg = *msg; - - spin_lock(&dev->cec_slock); - list_add(&cw->list, &dev->cec_work_list); - if (dev->cec_xfer_time_jiffies == 0) { - INIT_DELAYED_WORK(&cw->work, vivid_cec_xfer_done_worker); - dev->cec_xfer_start_jiffies = jiffies; - dev->cec_xfer_time_jiffies = usecs_to_jiffies(cw->usecs); - delta_jiffies = dev->cec_xfer_time_jiffies; - } else { - INIT_DELAYED_WORK(&cw->work, vivid_cec_xfer_try_worker); - delta_jiffies = dev->cec_xfer_start_jiffies + - dev->cec_xfer_time_jiffies - jiffies; - } - spin_unlock(&dev->cec_slock); - schedule_delayed_work(&cw->work, delta_jiffies < 0 ? 0 : delta_jiffies); - return 0; -} - -static int vivid_received(struct cec_adapter *adap, struct cec_msg *msg) -{ - struct vivid_dev *dev = cec_get_drvdata(adap); - struct cec_msg reply; - u8 dest = cec_msg_destination(msg); - u8 disp_ctl; - char osd[14]; - - if (cec_msg_is_broadcast(msg)) - dest = adap->log_addrs.log_addr[0]; - cec_msg_init(&reply, dest, cec_msg_initiator(msg)); - - switch (cec_msg_opcode(msg)) { - case CEC_MSG_SET_OSD_STRING: - if (!cec_is_sink(adap)) - return -ENOMSG; - cec_ops_set_osd_string(msg, &disp_ctl, osd); - switch (disp_ctl) { - case CEC_OP_DISP_CTL_DEFAULT: - strscpy(dev->osd, osd, sizeof(dev->osd)); - dev->osd_jiffies = jiffies; - break; - case CEC_OP_DISP_CTL_UNTIL_CLEARED: - strscpy(dev->osd, osd, sizeof(dev->osd)); - dev->osd_jiffies = 0; - break; - case CEC_OP_DISP_CTL_CLEAR: - dev->osd[0] = 0; - dev->osd_jiffies = 0; - break; - default: - cec_msg_feature_abort(&reply, cec_msg_opcode(msg), - CEC_OP_ABORT_INVALID_OP); - cec_transmit_msg(adap, &reply, false); - break; - } - break; - default: - return -ENOMSG; - } - return 0; -} - -static const struct cec_adap_ops vivid_cec_adap_ops = { - .adap_enable = vivid_cec_adap_enable, - .adap_log_addr = vivid_cec_adap_log_addr, - .adap_transmit = vivid_cec_adap_transmit, - .received = vivid_received, -}; - -struct cec_adapter *vivid_cec_alloc_adap(struct vivid_dev *dev, - unsigned int idx, - bool is_source) -{ - u32 caps = CEC_CAP_DEFAULTS | CEC_CAP_MONITOR_ALL | CEC_CAP_MONITOR_PIN; - char name[32]; - - snprintf(name, sizeof(name), "vivid-%03d-vid-%s%d", - dev->inst, is_source ? "out" : "cap", idx); - return cec_allocate_adapter(&vivid_cec_adap_ops, dev, - name, caps, 1); -} diff --git a/drivers/media/platform/vivid/vivid-cec.h b/drivers/media/platform/vivid/vivid-cec.h deleted file mode 100644 index 7524ed48a914..000000000000 --- a/drivers/media/platform/vivid/vivid-cec.h +++ /dev/null @@ -1,20 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * vivid-cec.h - A Virtual Video Test Driver, cec emulation - * - * Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - */ - -#ifdef CONFIG_VIDEO_VIVID_CEC -struct cec_adapter *vivid_cec_alloc_adap(struct vivid_dev *dev, - unsigned int idx, - bool is_source); -void vivid_cec_bus_free_work(struct vivid_dev *dev); - -#else - -static inline void vivid_cec_bus_free_work(struct vivid_dev *dev) -{ -} - -#endif diff --git a/drivers/media/platform/vivid/vivid-core.c b/drivers/media/platform/vivid/vivid-core.c deleted file mode 100644 index 6c740e3e6999..000000000000 --- a/drivers/media/platform/vivid/vivid-core.c +++ /dev/null @@ -1,2006 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * vivid-core.c - A Virtual Video Test Driver, core initialization - * - * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "vivid-core.h" -#include "vivid-vid-common.h" -#include "vivid-vid-cap.h" -#include "vivid-vid-out.h" -#include "vivid-radio-common.h" -#include "vivid-radio-rx.h" -#include "vivid-radio-tx.h" -#include "vivid-sdr-cap.h" -#include "vivid-vbi-cap.h" -#include "vivid-vbi-out.h" -#include "vivid-osd.h" -#include "vivid-cec.h" -#include "vivid-ctrls.h" -#include "vivid-meta-cap.h" -#include "vivid-meta-out.h" -#include "vivid-touch-cap.h" - -#define VIVID_MODULE_NAME "vivid" - -/* The maximum number of vivid devices */ -#define VIVID_MAX_DEVS CONFIG_VIDEO_VIVID_MAX_DEVS - -MODULE_DESCRIPTION("Virtual Video Test Driver"); -MODULE_AUTHOR("Hans Verkuil"); -MODULE_LICENSE("GPL"); - -static unsigned n_devs = 1; -module_param(n_devs, uint, 0444); -MODULE_PARM_DESC(n_devs, " number of driver instances to create"); - -static int vid_cap_nr[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 }; -module_param_array(vid_cap_nr, int, NULL, 0444); -MODULE_PARM_DESC(vid_cap_nr, " videoX start number, -1 is autodetect"); - -static int vid_out_nr[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 }; -module_param_array(vid_out_nr, int, NULL, 0444); -MODULE_PARM_DESC(vid_out_nr, " videoX start number, -1 is autodetect"); - -static int vbi_cap_nr[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 }; -module_param_array(vbi_cap_nr, int, NULL, 0444); -MODULE_PARM_DESC(vbi_cap_nr, " vbiX start number, -1 is autodetect"); - -static int vbi_out_nr[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 }; -module_param_array(vbi_out_nr, int, NULL, 0444); -MODULE_PARM_DESC(vbi_out_nr, " vbiX start number, -1 is autodetect"); - -static int sdr_cap_nr[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 }; -module_param_array(sdr_cap_nr, int, NULL, 0444); -MODULE_PARM_DESC(sdr_cap_nr, " swradioX start number, -1 is autodetect"); - -static int radio_rx_nr[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 }; -module_param_array(radio_rx_nr, int, NULL, 0444); -MODULE_PARM_DESC(radio_rx_nr, " radioX start number, -1 is autodetect"); - -static int radio_tx_nr[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 }; -module_param_array(radio_tx_nr, int, NULL, 0444); -MODULE_PARM_DESC(radio_tx_nr, " radioX start number, -1 is autodetect"); - -static int meta_cap_nr[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 }; -module_param_array(meta_cap_nr, int, NULL, 0444); -MODULE_PARM_DESC(meta_cap_nr, " videoX start number, -1 is autodetect"); - -static int meta_out_nr[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 }; -module_param_array(meta_out_nr, int, NULL, 0444); -MODULE_PARM_DESC(meta_out_nr, " videoX start number, -1 is autodetect"); - -static int touch_cap_nr[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 }; -module_param_array(touch_cap_nr, int, NULL, 0444); -MODULE_PARM_DESC(touch_cap_nr, " v4l-touchX start number, -1 is autodetect"); - -static int ccs_cap_mode[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 }; -module_param_array(ccs_cap_mode, int, NULL, 0444); -MODULE_PARM_DESC(ccs_cap_mode, " capture crop/compose/scale mode:\n" - "\t\t bit 0=crop, 1=compose, 2=scale,\n" - "\t\t -1=user-controlled (default)"); - -static int ccs_out_mode[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 }; -module_param_array(ccs_out_mode, int, NULL, 0444); -MODULE_PARM_DESC(ccs_out_mode, " output crop/compose/scale mode:\n" - "\t\t bit 0=crop, 1=compose, 2=scale,\n" - "\t\t -1=user-controlled (default)"); - -static unsigned multiplanar[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = 1 }; -module_param_array(multiplanar, uint, NULL, 0444); -MODULE_PARM_DESC(multiplanar, " 1 (default) creates a single planar device, 2 creates a multiplanar device."); - -/* - * Default: video + vbi-cap (raw and sliced) + radio rx + radio tx + sdr + - * vbi-out + vid-out + meta-cap - */ -static unsigned int node_types[VIVID_MAX_DEVS] = { - [0 ... (VIVID_MAX_DEVS - 1)] = 0xe1d3d -}; -module_param_array(node_types, uint, NULL, 0444); -MODULE_PARM_DESC(node_types, " node types, default is 0xe1d3d. Bitmask with the following meaning:\n" - "\t\t bit 0: Video Capture node\n" - "\t\t bit 2-3: VBI Capture node: 0 = none, 1 = raw vbi, 2 = sliced vbi, 3 = both\n" - "\t\t bit 4: Radio Receiver node\n" - "\t\t bit 5: Software Defined Radio Receiver node\n" - "\t\t bit 8: Video Output node\n" - "\t\t bit 10-11: VBI Output node: 0 = none, 1 = raw vbi, 2 = sliced vbi, 3 = both\n" - "\t\t bit 12: Radio Transmitter node\n" - "\t\t bit 16: Framebuffer for testing overlays\n" - "\t\t bit 17: Metadata Capture node\n" - "\t\t bit 18: Metadata Output node\n" - "\t\t bit 19: Touch Capture node\n"); - -/* Default: 4 inputs */ -static unsigned num_inputs[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = 4 }; -module_param_array(num_inputs, uint, NULL, 0444); -MODULE_PARM_DESC(num_inputs, " number of inputs, default is 4"); - -/* Default: input 0 = WEBCAM, 1 = TV, 2 = SVID, 3 = HDMI */ -static unsigned input_types[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = 0xe4 }; -module_param_array(input_types, uint, NULL, 0444); -MODULE_PARM_DESC(input_types, " input types, default is 0xe4. Two bits per input,\n" - "\t\t bits 0-1 == input 0, bits 31-30 == input 15.\n" - "\t\t Type 0 == webcam, 1 == TV, 2 == S-Video, 3 == HDMI"); - -/* Default: 2 outputs */ -static unsigned num_outputs[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = 2 }; -module_param_array(num_outputs, uint, NULL, 0444); -MODULE_PARM_DESC(num_outputs, " number of outputs, default is 2"); - -/* Default: output 0 = SVID, 1 = HDMI */ -static unsigned output_types[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = 2 }; -module_param_array(output_types, uint, NULL, 0444); -MODULE_PARM_DESC(output_types, " output types, default is 0x02. One bit per output,\n" - "\t\t bit 0 == output 0, bit 15 == output 15.\n" - "\t\t Type 0 == S-Video, 1 == HDMI"); - -unsigned vivid_debug; -module_param(vivid_debug, uint, 0644); -MODULE_PARM_DESC(vivid_debug, " activates debug info"); - -static bool no_error_inj; -module_param(no_error_inj, bool, 0444); -MODULE_PARM_DESC(no_error_inj, " if set disable the error injecting controls"); - -static unsigned int allocators[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = 0 }; -module_param_array(allocators, uint, NULL, 0444); -MODULE_PARM_DESC(allocators, " memory allocator selection, default is 0.\n" - "\t\t 0 == vmalloc\n" - "\t\t 1 == dma-contig"); - -static struct vivid_dev *vivid_devs[VIVID_MAX_DEVS]; - -const struct v4l2_rect vivid_min_rect = { - 0, 0, MIN_WIDTH, MIN_HEIGHT -}; - -const struct v4l2_rect vivid_max_rect = { - 0, 0, MAX_WIDTH * MAX_ZOOM, MAX_HEIGHT * MAX_ZOOM -}; - -static const u8 vivid_hdmi_edid[256] = { - 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, - 0x31, 0xd8, 0x34, 0x12, 0x00, 0x00, 0x00, 0x00, - 0x22, 0x1a, 0x01, 0x03, 0x80, 0x60, 0x36, 0x78, - 0x0f, 0xee, 0x91, 0xa3, 0x54, 0x4c, 0x99, 0x26, - 0x0f, 0x50, 0x54, 0x2f, 0xcf, 0x00, 0x31, 0x59, - 0x45, 0x59, 0x81, 0x80, 0x81, 0x40, 0x90, 0x40, - 0x95, 0x00, 0xa9, 0x40, 0xb3, 0x00, 0x08, 0xe8, - 0x00, 0x30, 0xf2, 0x70, 0x5a, 0x80, 0xb0, 0x58, - 0x8a, 0x00, 0xc0, 0x1c, 0x32, 0x00, 0x00, 0x1e, - 0x00, 0x00, 0x00, 0xfd, 0x00, 0x18, 0x55, 0x18, - 0x87, 0x3c, 0x00, 0x0a, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x76, - 0x69, 0x76, 0x69, 0x64, 0x0a, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x10, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x7b, - - 0x02, 0x03, 0x3f, 0xf0, 0x51, 0x61, 0x60, 0x5f, - 0x5e, 0x5d, 0x10, 0x1f, 0x04, 0x13, 0x22, 0x21, - 0x20, 0x05, 0x14, 0x02, 0x11, 0x01, 0x23, 0x09, - 0x07, 0x07, 0x83, 0x01, 0x00, 0x00, 0x6d, 0x03, - 0x0c, 0x00, 0x10, 0x00, 0x00, 0x3c, 0x21, 0x00, - 0x60, 0x01, 0x02, 0x03, 0x67, 0xd8, 0x5d, 0xc4, - 0x01, 0x78, 0x00, 0x00, 0xe2, 0x00, 0xea, 0xe3, - 0x05, 0x00, 0x00, 0xe3, 0x06, 0x01, 0x00, 0x4d, - 0xd0, 0x00, 0xa0, 0xf0, 0x70, 0x3e, 0x80, 0x30, - 0x20, 0x35, 0x00, 0xc0, 0x1c, 0x32, 0x00, 0x00, - 0x1e, 0x1a, 0x36, 0x80, 0xa0, 0x70, 0x38, 0x1f, - 0x40, 0x30, 0x20, 0x35, 0x00, 0xc0, 0x1c, 0x32, - 0x00, 0x00, 0x1a, 0x1a, 0x1d, 0x00, 0x80, 0x51, - 0xd0, 0x1c, 0x20, 0x40, 0x80, 0x35, 0x00, 0xc0, - 0x1c, 0x32, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, -}; - -static int vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) -{ - struct vivid_dev *dev = video_drvdata(file); - - strscpy(cap->driver, "vivid", sizeof(cap->driver)); - strscpy(cap->card, "vivid", sizeof(cap->card)); - snprintf(cap->bus_info, sizeof(cap->bus_info), - "platform:%s", dev->v4l2_dev.name); - - cap->capabilities = dev->vid_cap_caps | dev->vid_out_caps | - dev->vbi_cap_caps | dev->vbi_out_caps | - dev->radio_rx_caps | dev->radio_tx_caps | - dev->sdr_cap_caps | dev->meta_cap_caps | - dev->meta_out_caps | dev->touch_cap_caps | - V4L2_CAP_DEVICE_CAPS; - return 0; -} - -static int vidioc_s_hw_freq_seek(struct file *file, void *fh, const struct v4l2_hw_freq_seek *a) -{ - struct video_device *vdev = video_devdata(file); - - if (vdev->vfl_type == VFL_TYPE_RADIO) - return vivid_radio_rx_s_hw_freq_seek(file, fh, a); - return -ENOTTY; -} - -static int vidioc_enum_freq_bands(struct file *file, void *fh, struct v4l2_frequency_band *band) -{ - struct video_device *vdev = video_devdata(file); - - if (vdev->vfl_type == VFL_TYPE_RADIO) - return vivid_radio_rx_enum_freq_bands(file, fh, band); - if (vdev->vfl_type == VFL_TYPE_SDR) - return vivid_sdr_enum_freq_bands(file, fh, band); - return -ENOTTY; -} - -static int vidioc_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt) -{ - struct video_device *vdev = video_devdata(file); - - if (vdev->vfl_type == VFL_TYPE_RADIO) - return vivid_radio_rx_g_tuner(file, fh, vt); - if (vdev->vfl_type == VFL_TYPE_SDR) - return vivid_sdr_g_tuner(file, fh, vt); - return vivid_video_g_tuner(file, fh, vt); -} - -static int vidioc_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *vt) -{ - struct video_device *vdev = video_devdata(file); - - if (vdev->vfl_type == VFL_TYPE_RADIO) - return vivid_radio_rx_s_tuner(file, fh, vt); - if (vdev->vfl_type == VFL_TYPE_SDR) - return vivid_sdr_s_tuner(file, fh, vt); - return vivid_video_s_tuner(file, fh, vt); -} - -static int vidioc_g_frequency(struct file *file, void *fh, struct v4l2_frequency *vf) -{ - struct vivid_dev *dev = video_drvdata(file); - struct video_device *vdev = video_devdata(file); - - if (vdev->vfl_type == VFL_TYPE_RADIO) - return vivid_radio_g_frequency(file, - vdev->vfl_dir == VFL_DIR_RX ? - &dev->radio_rx_freq : &dev->radio_tx_freq, vf); - if (vdev->vfl_type == VFL_TYPE_SDR) - return vivid_sdr_g_frequency(file, fh, vf); - return vivid_video_g_frequency(file, fh, vf); -} - -static int vidioc_s_frequency(struct file *file, void *fh, const struct v4l2_frequency *vf) -{ - struct vivid_dev *dev = video_drvdata(file); - struct video_device *vdev = video_devdata(file); - - if (vdev->vfl_type == VFL_TYPE_RADIO) - return vivid_radio_s_frequency(file, - vdev->vfl_dir == VFL_DIR_RX ? - &dev->radio_rx_freq : &dev->radio_tx_freq, vf); - if (vdev->vfl_type == VFL_TYPE_SDR) - return vivid_sdr_s_frequency(file, fh, vf); - return vivid_video_s_frequency(file, fh, vf); -} - -static int vidioc_overlay(struct file *file, void *fh, unsigned i) -{ - struct video_device *vdev = video_devdata(file); - - if (vdev->vfl_dir == VFL_DIR_RX) - return vivid_vid_cap_overlay(file, fh, i); - return vivid_vid_out_overlay(file, fh, i); -} - -static int vidioc_g_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *a) -{ - struct video_device *vdev = video_devdata(file); - - if (vdev->vfl_dir == VFL_DIR_RX) - return vivid_vid_cap_g_fbuf(file, fh, a); - return vivid_vid_out_g_fbuf(file, fh, a); -} - -static int vidioc_s_fbuf(struct file *file, void *fh, const struct v4l2_framebuffer *a) -{ - struct video_device *vdev = video_devdata(file); - - if (vdev->vfl_dir == VFL_DIR_RX) - return vivid_vid_cap_s_fbuf(file, fh, a); - return vivid_vid_out_s_fbuf(file, fh, a); -} - -static int vidioc_s_std(struct file *file, void *fh, v4l2_std_id id) -{ - struct video_device *vdev = video_devdata(file); - - if (vdev->vfl_dir == VFL_DIR_RX) - return vivid_vid_cap_s_std(file, fh, id); - return vivid_vid_out_s_std(file, fh, id); -} - -static int vidioc_s_dv_timings(struct file *file, void *fh, struct v4l2_dv_timings *timings) -{ - struct video_device *vdev = video_devdata(file); - - if (vdev->vfl_dir == VFL_DIR_RX) - return vivid_vid_cap_s_dv_timings(file, fh, timings); - return vivid_vid_out_s_dv_timings(file, fh, timings); -} - -static int vidioc_g_pixelaspect(struct file *file, void *fh, - int type, struct v4l2_fract *f) -{ - struct video_device *vdev = video_devdata(file); - - if (vdev->vfl_dir == VFL_DIR_RX) - return vivid_vid_cap_g_pixelaspect(file, fh, type, f); - return vivid_vid_out_g_pixelaspect(file, fh, type, f); -} - -static int vidioc_g_selection(struct file *file, void *fh, - struct v4l2_selection *sel) -{ - struct video_device *vdev = video_devdata(file); - - if (vdev->vfl_dir == VFL_DIR_RX) - return vivid_vid_cap_g_selection(file, fh, sel); - return vivid_vid_out_g_selection(file, fh, sel); -} - -static int vidioc_s_selection(struct file *file, void *fh, - struct v4l2_selection *sel) -{ - struct video_device *vdev = video_devdata(file); - - if (vdev->vfl_dir == VFL_DIR_RX) - return vivid_vid_cap_s_selection(file, fh, sel); - return vivid_vid_out_s_selection(file, fh, sel); -} - -static int vidioc_g_parm(struct file *file, void *fh, - struct v4l2_streamparm *parm) -{ - struct video_device *vdev = video_devdata(file); - - if (vdev->vfl_type == VFL_TYPE_TOUCH) - return vivid_g_parm_tch(file, fh, parm); - if (vdev->vfl_dir == VFL_DIR_RX) - return vivid_vid_cap_g_parm(file, fh, parm); - return vivid_vid_out_g_parm(file, fh, parm); -} - -static int vidioc_s_parm(struct file *file, void *fh, - struct v4l2_streamparm *parm) -{ - struct video_device *vdev = video_devdata(file); - - if (vdev->vfl_dir == VFL_DIR_RX) - return vivid_vid_cap_s_parm(file, fh, parm); - return -ENOTTY; -} - -static int vidioc_log_status(struct file *file, void *fh) -{ - struct vivid_dev *dev = video_drvdata(file); - struct video_device *vdev = video_devdata(file); - - v4l2_ctrl_log_status(file, fh); - if (vdev->vfl_dir == VFL_DIR_RX && vdev->vfl_type == VFL_TYPE_VIDEO) - tpg_log_status(&dev->tpg); - return 0; -} - -static ssize_t vivid_radio_read(struct file *file, char __user *buf, - size_t size, loff_t *offset) -{ - struct video_device *vdev = video_devdata(file); - - if (vdev->vfl_dir == VFL_DIR_TX) - return -EINVAL; - return vivid_radio_rx_read(file, buf, size, offset); -} - -static ssize_t vivid_radio_write(struct file *file, const char __user *buf, - size_t size, loff_t *offset) -{ - struct video_device *vdev = video_devdata(file); - - if (vdev->vfl_dir == VFL_DIR_RX) - return -EINVAL; - return vivid_radio_tx_write(file, buf, size, offset); -} - -static __poll_t vivid_radio_poll(struct file *file, struct poll_table_struct *wait) -{ - struct video_device *vdev = video_devdata(file); - - if (vdev->vfl_dir == VFL_DIR_RX) - return vivid_radio_rx_poll(file, wait); - return vivid_radio_tx_poll(file, wait); -} - -static int vivid_enum_input(struct file *file, void *priv, - struct v4l2_input *inp) -{ - struct video_device *vdev = video_devdata(file); - - if (vdev->vfl_type == VFL_TYPE_TOUCH) - return vivid_enum_input_tch(file, priv, inp); - return vidioc_enum_input(file, priv, inp); -} - -static int vivid_g_input(struct file *file, void *priv, unsigned int *i) -{ - struct video_device *vdev = video_devdata(file); - - if (vdev->vfl_type == VFL_TYPE_TOUCH) - return vivid_g_input_tch(file, priv, i); - return vidioc_g_input(file, priv, i); -} - -static int vivid_s_input(struct file *file, void *priv, unsigned int i) -{ - struct video_device *vdev = video_devdata(file); - - if (vdev->vfl_type == VFL_TYPE_TOUCH) - return vivid_s_input_tch(file, priv, i); - return vidioc_s_input(file, priv, i); -} - -static int vivid_enum_fmt_cap(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - struct video_device *vdev = video_devdata(file); - - if (vdev->vfl_type == VFL_TYPE_TOUCH) - return vivid_enum_fmt_tch(file, priv, f); - return vivid_enum_fmt_vid(file, priv, f); -} - -static int vivid_g_fmt_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct video_device *vdev = video_devdata(file); - - if (vdev->vfl_type == VFL_TYPE_TOUCH) - return vivid_g_fmt_tch(file, priv, f); - return vidioc_g_fmt_vid_cap(file, priv, f); -} - -static int vivid_try_fmt_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct video_device *vdev = video_devdata(file); - - if (vdev->vfl_type == VFL_TYPE_TOUCH) - return vivid_g_fmt_tch(file, priv, f); - return vidioc_try_fmt_vid_cap(file, priv, f); -} - -static int vivid_s_fmt_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct video_device *vdev = video_devdata(file); - - if (vdev->vfl_type == VFL_TYPE_TOUCH) - return vivid_g_fmt_tch(file, priv, f); - return vidioc_s_fmt_vid_cap(file, priv, f); -} - -static int vivid_g_fmt_cap_mplane(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct video_device *vdev = video_devdata(file); - - if (vdev->vfl_type == VFL_TYPE_TOUCH) - return vivid_g_fmt_tch_mplane(file, priv, f); - return vidioc_g_fmt_vid_cap_mplane(file, priv, f); -} - -static int vivid_try_fmt_cap_mplane(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct video_device *vdev = video_devdata(file); - - if (vdev->vfl_type == VFL_TYPE_TOUCH) - return vivid_g_fmt_tch_mplane(file, priv, f); - return vidioc_try_fmt_vid_cap_mplane(file, priv, f); -} - -static int vivid_s_fmt_cap_mplane(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct video_device *vdev = video_devdata(file); - - if (vdev->vfl_type == VFL_TYPE_TOUCH) - return vivid_g_fmt_tch_mplane(file, priv, f); - return vidioc_s_fmt_vid_cap_mplane(file, priv, f); -} - -static bool vivid_is_in_use(struct video_device *vdev) -{ - unsigned long flags; - bool res; - - spin_lock_irqsave(&vdev->fh_lock, flags); - res = !list_empty(&vdev->fh_list); - spin_unlock_irqrestore(&vdev->fh_lock, flags); - return res; -} - -static bool vivid_is_last_user(struct vivid_dev *dev) -{ - unsigned uses = vivid_is_in_use(&dev->vid_cap_dev) + - vivid_is_in_use(&dev->vid_out_dev) + - vivid_is_in_use(&dev->vbi_cap_dev) + - vivid_is_in_use(&dev->vbi_out_dev) + - vivid_is_in_use(&dev->sdr_cap_dev) + - vivid_is_in_use(&dev->radio_rx_dev) + - vivid_is_in_use(&dev->radio_tx_dev) + - vivid_is_in_use(&dev->meta_cap_dev) + - vivid_is_in_use(&dev->meta_out_dev) + - vivid_is_in_use(&dev->touch_cap_dev); - - return uses == 1; -} - -static int vivid_fop_release(struct file *file) -{ - struct vivid_dev *dev = video_drvdata(file); - struct video_device *vdev = video_devdata(file); - - mutex_lock(&dev->mutex); - if (!no_error_inj && v4l2_fh_is_singular_file(file) && - !video_is_registered(vdev) && vivid_is_last_user(dev)) { - /* - * I am the last user of this driver, and a disconnect - * was forced (since this video_device is unregistered), - * so re-register all video_device's again. - */ - v4l2_info(&dev->v4l2_dev, "reconnect\n"); - set_bit(V4L2_FL_REGISTERED, &dev->vid_cap_dev.flags); - set_bit(V4L2_FL_REGISTERED, &dev->vid_out_dev.flags); - set_bit(V4L2_FL_REGISTERED, &dev->vbi_cap_dev.flags); - set_bit(V4L2_FL_REGISTERED, &dev->vbi_out_dev.flags); - set_bit(V4L2_FL_REGISTERED, &dev->sdr_cap_dev.flags); - set_bit(V4L2_FL_REGISTERED, &dev->radio_rx_dev.flags); - set_bit(V4L2_FL_REGISTERED, &dev->radio_tx_dev.flags); - set_bit(V4L2_FL_REGISTERED, &dev->meta_cap_dev.flags); - set_bit(V4L2_FL_REGISTERED, &dev->meta_out_dev.flags); - set_bit(V4L2_FL_REGISTERED, &dev->touch_cap_dev.flags); - } - mutex_unlock(&dev->mutex); - if (file->private_data == dev->overlay_cap_owner) - dev->overlay_cap_owner = NULL; - if (file->private_data == dev->radio_rx_rds_owner) { - dev->radio_rx_rds_last_block = 0; - dev->radio_rx_rds_owner = NULL; - } - if (file->private_data == dev->radio_tx_rds_owner) { - dev->radio_tx_rds_last_block = 0; - dev->radio_tx_rds_owner = NULL; - } - if (vdev->queue) - return vb2_fop_release(file); - return v4l2_fh_release(file); -} - -static const struct v4l2_file_operations vivid_fops = { - .owner = THIS_MODULE, - .open = v4l2_fh_open, - .release = vivid_fop_release, - .read = vb2_fop_read, - .write = vb2_fop_write, - .poll = vb2_fop_poll, - .unlocked_ioctl = video_ioctl2, - .mmap = vb2_fop_mmap, -}; - -static const struct v4l2_file_operations vivid_radio_fops = { - .owner = THIS_MODULE, - .open = v4l2_fh_open, - .release = vivid_fop_release, - .read = vivid_radio_read, - .write = vivid_radio_write, - .poll = vivid_radio_poll, - .unlocked_ioctl = video_ioctl2, -}; - -static const struct v4l2_ioctl_ops vivid_ioctl_ops = { - .vidioc_querycap = vidioc_querycap, - - .vidioc_enum_fmt_vid_cap = vivid_enum_fmt_cap, - .vidioc_g_fmt_vid_cap = vivid_g_fmt_cap, - .vidioc_try_fmt_vid_cap = vivid_try_fmt_cap, - .vidioc_s_fmt_vid_cap = vivid_s_fmt_cap, - .vidioc_g_fmt_vid_cap_mplane = vivid_g_fmt_cap_mplane, - .vidioc_try_fmt_vid_cap_mplane = vivid_try_fmt_cap_mplane, - .vidioc_s_fmt_vid_cap_mplane = vivid_s_fmt_cap_mplane, - - .vidioc_enum_fmt_vid_out = vivid_enum_fmt_vid, - .vidioc_g_fmt_vid_out = vidioc_g_fmt_vid_out, - .vidioc_try_fmt_vid_out = vidioc_try_fmt_vid_out, - .vidioc_s_fmt_vid_out = vidioc_s_fmt_vid_out, - .vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt_vid_out_mplane, - .vidioc_try_fmt_vid_out_mplane = vidioc_try_fmt_vid_out_mplane, - .vidioc_s_fmt_vid_out_mplane = vidioc_s_fmt_vid_out_mplane, - - .vidioc_g_selection = vidioc_g_selection, - .vidioc_s_selection = vidioc_s_selection, - .vidioc_g_pixelaspect = vidioc_g_pixelaspect, - - .vidioc_g_fmt_vbi_cap = vidioc_g_fmt_vbi_cap, - .vidioc_try_fmt_vbi_cap = vidioc_g_fmt_vbi_cap, - .vidioc_s_fmt_vbi_cap = vidioc_s_fmt_vbi_cap, - - .vidioc_g_fmt_sliced_vbi_cap = vidioc_g_fmt_sliced_vbi_cap, - .vidioc_try_fmt_sliced_vbi_cap = vidioc_try_fmt_sliced_vbi_cap, - .vidioc_s_fmt_sliced_vbi_cap = vidioc_s_fmt_sliced_vbi_cap, - .vidioc_g_sliced_vbi_cap = vidioc_g_sliced_vbi_cap, - - .vidioc_g_fmt_vbi_out = vidioc_g_fmt_vbi_out, - .vidioc_try_fmt_vbi_out = vidioc_g_fmt_vbi_out, - .vidioc_s_fmt_vbi_out = vidioc_s_fmt_vbi_out, - - .vidioc_g_fmt_sliced_vbi_out = vidioc_g_fmt_sliced_vbi_out, - .vidioc_try_fmt_sliced_vbi_out = vidioc_try_fmt_sliced_vbi_out, - .vidioc_s_fmt_sliced_vbi_out = vidioc_s_fmt_sliced_vbi_out, - - .vidioc_enum_fmt_sdr_cap = vidioc_enum_fmt_sdr_cap, - .vidioc_g_fmt_sdr_cap = vidioc_g_fmt_sdr_cap, - .vidioc_try_fmt_sdr_cap = vidioc_try_fmt_sdr_cap, - .vidioc_s_fmt_sdr_cap = vidioc_s_fmt_sdr_cap, - - .vidioc_overlay = vidioc_overlay, - .vidioc_enum_framesizes = vidioc_enum_framesizes, - .vidioc_enum_frameintervals = vidioc_enum_frameintervals, - .vidioc_g_parm = vidioc_g_parm, - .vidioc_s_parm = vidioc_s_parm, - - .vidioc_enum_fmt_vid_overlay = vidioc_enum_fmt_vid_overlay, - .vidioc_g_fmt_vid_overlay = vidioc_g_fmt_vid_overlay, - .vidioc_try_fmt_vid_overlay = vidioc_try_fmt_vid_overlay, - .vidioc_s_fmt_vid_overlay = vidioc_s_fmt_vid_overlay, - .vidioc_g_fmt_vid_out_overlay = vidioc_g_fmt_vid_out_overlay, - .vidioc_try_fmt_vid_out_overlay = vidioc_try_fmt_vid_out_overlay, - .vidioc_s_fmt_vid_out_overlay = vidioc_s_fmt_vid_out_overlay, - .vidioc_g_fbuf = vidioc_g_fbuf, - .vidioc_s_fbuf = vidioc_s_fbuf, - - .vidioc_reqbufs = vb2_ioctl_reqbufs, - .vidioc_create_bufs = vb2_ioctl_create_bufs, - .vidioc_prepare_buf = vb2_ioctl_prepare_buf, - .vidioc_querybuf = vb2_ioctl_querybuf, - .vidioc_qbuf = vb2_ioctl_qbuf, - .vidioc_dqbuf = vb2_ioctl_dqbuf, - .vidioc_expbuf = vb2_ioctl_expbuf, - .vidioc_streamon = vb2_ioctl_streamon, - .vidioc_streamoff = vb2_ioctl_streamoff, - - .vidioc_enum_input = vivid_enum_input, - .vidioc_g_input = vivid_g_input, - .vidioc_s_input = vivid_s_input, - .vidioc_s_audio = vidioc_s_audio, - .vidioc_g_audio = vidioc_g_audio, - .vidioc_enumaudio = vidioc_enumaudio, - .vidioc_s_frequency = vidioc_s_frequency, - .vidioc_g_frequency = vidioc_g_frequency, - .vidioc_s_tuner = vidioc_s_tuner, - .vidioc_g_tuner = vidioc_g_tuner, - .vidioc_s_modulator = vidioc_s_modulator, - .vidioc_g_modulator = vidioc_g_modulator, - .vidioc_s_hw_freq_seek = vidioc_s_hw_freq_seek, - .vidioc_enum_freq_bands = vidioc_enum_freq_bands, - - .vidioc_enum_output = vidioc_enum_output, - .vidioc_g_output = vidioc_g_output, - .vidioc_s_output = vidioc_s_output, - .vidioc_s_audout = vidioc_s_audout, - .vidioc_g_audout = vidioc_g_audout, - .vidioc_enumaudout = vidioc_enumaudout, - - .vidioc_querystd = vidioc_querystd, - .vidioc_g_std = vidioc_g_std, - .vidioc_s_std = vidioc_s_std, - .vidioc_s_dv_timings = vidioc_s_dv_timings, - .vidioc_g_dv_timings = vidioc_g_dv_timings, - .vidioc_query_dv_timings = vidioc_query_dv_timings, - .vidioc_enum_dv_timings = vidioc_enum_dv_timings, - .vidioc_dv_timings_cap = vidioc_dv_timings_cap, - .vidioc_g_edid = vidioc_g_edid, - .vidioc_s_edid = vidioc_s_edid, - - .vidioc_log_status = vidioc_log_status, - .vidioc_subscribe_event = vidioc_subscribe_event, - .vidioc_unsubscribe_event = v4l2_event_unsubscribe, - - .vidioc_enum_fmt_meta_cap = vidioc_enum_fmt_meta_cap, - .vidioc_g_fmt_meta_cap = vidioc_g_fmt_meta_cap, - .vidioc_s_fmt_meta_cap = vidioc_g_fmt_meta_cap, - .vidioc_try_fmt_meta_cap = vidioc_g_fmt_meta_cap, - - .vidioc_enum_fmt_meta_out = vidioc_enum_fmt_meta_out, - .vidioc_g_fmt_meta_out = vidioc_g_fmt_meta_out, - .vidioc_s_fmt_meta_out = vidioc_g_fmt_meta_out, - .vidioc_try_fmt_meta_out = vidioc_g_fmt_meta_out, -}; - -/* ----------------------------------------------------------------- - Initialization and module stuff - ------------------------------------------------------------------*/ - -static void vivid_dev_release(struct v4l2_device *v4l2_dev) -{ - struct vivid_dev *dev = container_of(v4l2_dev, struct vivid_dev, v4l2_dev); - - vivid_free_controls(dev); - v4l2_device_unregister(&dev->v4l2_dev); -#ifdef CONFIG_MEDIA_CONTROLLER - media_device_cleanup(&dev->mdev); -#endif - vfree(dev->scaled_line); - vfree(dev->blended_line); - vfree(dev->edid); - vfree(dev->bitmap_cap); - vfree(dev->bitmap_out); - tpg_free(&dev->tpg); - kfree(dev->query_dv_timings_qmenu); - kfree(dev->query_dv_timings_qmenu_strings); - kfree(dev); -} - -#ifdef CONFIG_MEDIA_CONTROLLER -static int vivid_req_validate(struct media_request *req) -{ - struct vivid_dev *dev = container_of(req->mdev, struct vivid_dev, mdev); - - if (dev->req_validate_error) { - dev->req_validate_error = false; - return -EINVAL; - } - return vb2_request_validate(req); -} - -static const struct media_device_ops vivid_media_ops = { - .req_validate = vivid_req_validate, - .req_queue = vb2_request_queue, -}; -#endif - -static int vivid_create_queue(struct vivid_dev *dev, - struct vb2_queue *q, - u32 buf_type, - unsigned int min_buffers_needed, - const struct vb2_ops *ops) -{ - if (buf_type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->multiplanar) - buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; - else if (buf_type == V4L2_BUF_TYPE_VIDEO_OUTPUT && dev->multiplanar) - buf_type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; - else if (buf_type == V4L2_BUF_TYPE_VBI_CAPTURE && !dev->has_raw_vbi_cap) - buf_type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE; - else if (buf_type == V4L2_BUF_TYPE_VBI_OUTPUT && !dev->has_raw_vbi_out) - buf_type = V4L2_BUF_TYPE_SLICED_VBI_OUTPUT; - - q->type = buf_type; - q->io_modes = VB2_MMAP | VB2_DMABUF; - q->io_modes |= V4L2_TYPE_IS_OUTPUT(buf_type) ? VB2_WRITE : VB2_READ; - if (allocators[dev->inst] != 1) - q->io_modes |= VB2_USERPTR; - q->drv_priv = dev; - q->buf_struct_size = sizeof(struct vivid_buffer); - q->ops = ops; - q->mem_ops = allocators[dev->inst] == 1 ? &vb2_dma_contig_memops : - &vb2_vmalloc_memops; - q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; - q->min_buffers_needed = min_buffers_needed; - q->lock = &dev->mutex; - q->dev = dev->v4l2_dev.dev; - q->supports_requests = true; - - return vb2_queue_init(q); -} - -static int vivid_create_instance(struct platform_device *pdev, int inst) -{ - static const struct v4l2_dv_timings def_dv_timings = - V4L2_DV_BT_CEA_1280X720P60; - unsigned in_type_counter[4] = { 0, 0, 0, 0 }; - unsigned out_type_counter[4] = { 0, 0, 0, 0 }; - int ccs_cap = ccs_cap_mode[inst]; - int ccs_out = ccs_out_mode[inst]; - bool has_tuner; - bool has_modulator; - struct vivid_dev *dev; - struct video_device *vfd; - unsigned node_type = node_types[inst]; - v4l2_std_id tvnorms_cap = 0, tvnorms_out = 0; - int ret; - int i; -#ifdef CONFIG_VIDEO_VIVID_CEC - unsigned int cec_tx_bus_cnt = 0; -#endif - - /* allocate main vivid state structure */ - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) - return -ENOMEM; - - dev->inst = inst; - -#ifdef CONFIG_MEDIA_CONTROLLER - dev->v4l2_dev.mdev = &dev->mdev; - - /* Initialize media device */ - strscpy(dev->mdev.model, VIVID_MODULE_NAME, sizeof(dev->mdev.model)); - snprintf(dev->mdev.bus_info, sizeof(dev->mdev.bus_info), - "platform:%s-%03d", VIVID_MODULE_NAME, inst); - dev->mdev.dev = &pdev->dev; - media_device_init(&dev->mdev); - dev->mdev.ops = &vivid_media_ops; -#endif - - /* register v4l2_device */ - snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name), - "%s-%03d", VIVID_MODULE_NAME, inst); - ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); - if (ret) { - kfree(dev); - return ret; - } - dev->v4l2_dev.release = vivid_dev_release; - - /* start detecting feature set */ - - /* do we use single- or multi-planar? */ - dev->multiplanar = multiplanar[inst] > 1; - v4l2_info(&dev->v4l2_dev, "using %splanar format API\n", - dev->multiplanar ? "multi" : "single "); - - /* how many inputs do we have and of what type? */ - dev->num_inputs = num_inputs[inst]; - if (dev->num_inputs < 1) - dev->num_inputs = 1; - if (dev->num_inputs >= MAX_INPUTS) - dev->num_inputs = MAX_INPUTS; - for (i = 0; i < dev->num_inputs; i++) { - dev->input_type[i] = (input_types[inst] >> (i * 2)) & 0x3; - dev->input_name_counter[i] = in_type_counter[dev->input_type[i]]++; - } - dev->has_audio_inputs = in_type_counter[TV] && in_type_counter[SVID]; - if (in_type_counter[HDMI] == 16) { - /* The CEC physical address only allows for max 15 inputs */ - in_type_counter[HDMI]--; - dev->num_inputs--; - } - dev->num_hdmi_inputs = in_type_counter[HDMI]; - - /* how many outputs do we have and of what type? */ - dev->num_outputs = num_outputs[inst]; - if (dev->num_outputs < 1) - dev->num_outputs = 1; - if (dev->num_outputs >= MAX_OUTPUTS) - dev->num_outputs = MAX_OUTPUTS; - for (i = 0; i < dev->num_outputs; i++) { - dev->output_type[i] = ((output_types[inst] >> i) & 1) ? HDMI : SVID; - dev->output_name_counter[i] = out_type_counter[dev->output_type[i]]++; - dev->display_present[i] = true; - } - dev->has_audio_outputs = out_type_counter[SVID]; - if (out_type_counter[HDMI] == 16) { - /* - * The CEC physical address only allows for max 15 inputs, - * so outputs are also limited to 15 to allow for easy - * CEC output to input mapping. - */ - out_type_counter[HDMI]--; - dev->num_outputs--; - } - dev->num_hdmi_outputs = out_type_counter[HDMI]; - - /* do we create a video capture device? */ - dev->has_vid_cap = node_type & 0x0001; - - /* do we create a vbi capture device? */ - if (in_type_counter[TV] || in_type_counter[SVID]) { - dev->has_raw_vbi_cap = node_type & 0x0004; - dev->has_sliced_vbi_cap = node_type & 0x0008; - dev->has_vbi_cap = dev->has_raw_vbi_cap | dev->has_sliced_vbi_cap; - } - - /* do we create a meta capture device */ - dev->has_meta_cap = node_type & 0x20000; - - /* sanity checks */ - if ((in_type_counter[WEBCAM] || in_type_counter[HDMI]) && - !dev->has_vid_cap && !dev->has_meta_cap) { - v4l2_warn(&dev->v4l2_dev, - "Webcam or HDMI input without video or metadata nodes\n"); - kfree(dev); - return -EINVAL; - } - if ((in_type_counter[TV] || in_type_counter[SVID]) && - !dev->has_vid_cap && !dev->has_vbi_cap && !dev->has_meta_cap) { - v4l2_warn(&dev->v4l2_dev, - "TV or S-Video input without video, VBI or metadata nodes\n"); - kfree(dev); - return -EINVAL; - } - - /* do we create a video output device? */ - dev->has_vid_out = node_type & 0x0100; - - /* do we create a vbi output device? */ - if (out_type_counter[SVID]) { - dev->has_raw_vbi_out = node_type & 0x0400; - dev->has_sliced_vbi_out = node_type & 0x0800; - dev->has_vbi_out = dev->has_raw_vbi_out | dev->has_sliced_vbi_out; - } - - /* do we create a metadata output device */ - dev->has_meta_out = node_type & 0x40000; - - /* sanity checks */ - if (out_type_counter[SVID] && - !dev->has_vid_out && !dev->has_vbi_out && !dev->has_meta_out) { - v4l2_warn(&dev->v4l2_dev, - "S-Video output without video, VBI or metadata nodes\n"); - kfree(dev); - return -EINVAL; - } - if (out_type_counter[HDMI] && !dev->has_vid_out && !dev->has_meta_out) { - v4l2_warn(&dev->v4l2_dev, - "HDMI output without video or metadata nodes\n"); - kfree(dev); - return -EINVAL; - } - - /* do we create a radio receiver device? */ - dev->has_radio_rx = node_type & 0x0010; - - /* do we create a radio transmitter device? */ - dev->has_radio_tx = node_type & 0x1000; - - /* do we create a software defined radio capture device? */ - dev->has_sdr_cap = node_type & 0x0020; - - /* do we have a TV tuner? */ - dev->has_tv_tuner = in_type_counter[TV]; - - /* do we have a tuner? */ - has_tuner = ((dev->has_vid_cap || dev->has_vbi_cap) && in_type_counter[TV]) || - dev->has_radio_rx || dev->has_sdr_cap; - - /* do we have a modulator? */ - has_modulator = dev->has_radio_tx; - - if (dev->has_vid_cap) - /* do we have a framebuffer for overlay testing? */ - dev->has_fb = node_type & 0x10000; - - /* can we do crop/compose/scaling while capturing? */ - if (no_error_inj && ccs_cap == -1) - ccs_cap = 7; - - /* if ccs_cap == -1, then the user can select it using controls */ - if (ccs_cap != -1) { - dev->has_crop_cap = ccs_cap & 1; - dev->has_compose_cap = ccs_cap & 2; - dev->has_scaler_cap = ccs_cap & 4; - v4l2_info(&dev->v4l2_dev, "Capture Crop: %c Compose: %c Scaler: %c\n", - dev->has_crop_cap ? 'Y' : 'N', - dev->has_compose_cap ? 'Y' : 'N', - dev->has_scaler_cap ? 'Y' : 'N'); - } - - /* can we do crop/compose/scaling with video output? */ - if (no_error_inj && ccs_out == -1) - ccs_out = 7; - - /* if ccs_out == -1, then the user can select it using controls */ - if (ccs_out != -1) { - dev->has_crop_out = ccs_out & 1; - dev->has_compose_out = ccs_out & 2; - dev->has_scaler_out = ccs_out & 4; - v4l2_info(&dev->v4l2_dev, "Output Crop: %c Compose: %c Scaler: %c\n", - dev->has_crop_out ? 'Y' : 'N', - dev->has_compose_out ? 'Y' : 'N', - dev->has_scaler_out ? 'Y' : 'N'); - } - - /* do we create a touch capture device */ - dev->has_touch_cap = node_type & 0x80000; - - /* end detecting feature set */ - - if (dev->has_vid_cap) { - /* set up the capabilities of the video capture device */ - dev->vid_cap_caps = dev->multiplanar ? - V4L2_CAP_VIDEO_CAPTURE_MPLANE : - V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OVERLAY; - dev->vid_cap_caps |= V4L2_CAP_STREAMING | V4L2_CAP_READWRITE; - if (dev->has_audio_inputs) - dev->vid_cap_caps |= V4L2_CAP_AUDIO; - if (dev->has_tv_tuner) - dev->vid_cap_caps |= V4L2_CAP_TUNER; - } - if (dev->has_vid_out) { - /* set up the capabilities of the video output device */ - dev->vid_out_caps = dev->multiplanar ? - V4L2_CAP_VIDEO_OUTPUT_MPLANE : - V4L2_CAP_VIDEO_OUTPUT; - if (dev->has_fb) - dev->vid_out_caps |= V4L2_CAP_VIDEO_OUTPUT_OVERLAY; - dev->vid_out_caps |= V4L2_CAP_STREAMING | V4L2_CAP_READWRITE; - if (dev->has_audio_outputs) - dev->vid_out_caps |= V4L2_CAP_AUDIO; - } - if (dev->has_vbi_cap) { - /* set up the capabilities of the vbi capture device */ - dev->vbi_cap_caps = (dev->has_raw_vbi_cap ? V4L2_CAP_VBI_CAPTURE : 0) | - (dev->has_sliced_vbi_cap ? V4L2_CAP_SLICED_VBI_CAPTURE : 0); - dev->vbi_cap_caps |= V4L2_CAP_STREAMING | V4L2_CAP_READWRITE; - if (dev->has_audio_inputs) - dev->vbi_cap_caps |= V4L2_CAP_AUDIO; - if (dev->has_tv_tuner) - dev->vbi_cap_caps |= V4L2_CAP_TUNER; - } - if (dev->has_vbi_out) { - /* set up the capabilities of the vbi output device */ - dev->vbi_out_caps = (dev->has_raw_vbi_out ? V4L2_CAP_VBI_OUTPUT : 0) | - (dev->has_sliced_vbi_out ? V4L2_CAP_SLICED_VBI_OUTPUT : 0); - dev->vbi_out_caps |= V4L2_CAP_STREAMING | V4L2_CAP_READWRITE; - if (dev->has_audio_outputs) - dev->vbi_out_caps |= V4L2_CAP_AUDIO; - } - if (dev->has_sdr_cap) { - /* set up the capabilities of the sdr capture device */ - dev->sdr_cap_caps = V4L2_CAP_SDR_CAPTURE | V4L2_CAP_TUNER; - dev->sdr_cap_caps |= V4L2_CAP_STREAMING | V4L2_CAP_READWRITE; - } - /* set up the capabilities of the radio receiver device */ - if (dev->has_radio_rx) - dev->radio_rx_caps = V4L2_CAP_RADIO | V4L2_CAP_RDS_CAPTURE | - V4L2_CAP_HW_FREQ_SEEK | V4L2_CAP_TUNER | - V4L2_CAP_READWRITE; - /* set up the capabilities of the radio transmitter device */ - if (dev->has_radio_tx) - dev->radio_tx_caps = V4L2_CAP_RDS_OUTPUT | V4L2_CAP_MODULATOR | - V4L2_CAP_READWRITE; - - /* set up the capabilities of meta capture device */ - if (dev->has_meta_cap) { - dev->meta_cap_caps = V4L2_CAP_META_CAPTURE | - V4L2_CAP_STREAMING | V4L2_CAP_READWRITE; - if (dev->has_audio_inputs) - dev->meta_cap_caps |= V4L2_CAP_AUDIO; - if (dev->has_tv_tuner) - dev->meta_cap_caps |= V4L2_CAP_TUNER; - } - /* set up the capabilities of meta output device */ - if (dev->has_meta_out) { - dev->meta_out_caps = V4L2_CAP_META_OUTPUT | - V4L2_CAP_STREAMING | V4L2_CAP_READWRITE; - if (dev->has_audio_outputs) - dev->meta_out_caps |= V4L2_CAP_AUDIO; - } - /* set up the capabilities of the touch capture device */ - if (dev->has_touch_cap) { - dev->touch_cap_caps = V4L2_CAP_TOUCH | V4L2_CAP_STREAMING | - V4L2_CAP_READWRITE; - dev->touch_cap_caps |= dev->multiplanar ? - V4L2_CAP_VIDEO_CAPTURE_MPLANE : V4L2_CAP_VIDEO_CAPTURE; - } - - ret = -ENOMEM; - /* initialize the test pattern generator */ - tpg_init(&dev->tpg, 640, 360); - if (tpg_alloc(&dev->tpg, MAX_ZOOM * MAX_WIDTH)) - goto free_dev; - dev->scaled_line = vzalloc(array_size(MAX_WIDTH, MAX_ZOOM)); - if (!dev->scaled_line) - goto free_dev; - dev->blended_line = vzalloc(array_size(MAX_WIDTH, MAX_ZOOM)); - if (!dev->blended_line) - goto free_dev; - - /* load the edid */ - dev->edid = vmalloc(256 * 128); - if (!dev->edid) - goto free_dev; - - while (v4l2_dv_timings_presets[dev->query_dv_timings_size].bt.width) - dev->query_dv_timings_size++; - - /* - * Create a char pointer array that points to the names of all the - * preset timings - */ - dev->query_dv_timings_qmenu = kmalloc_array(dev->query_dv_timings_size, - sizeof(char *), GFP_KERNEL); - /* - * Create a string array containing the names of all the preset - * timings. Each name is max 31 chars long (+ terminating 0). - */ - dev->query_dv_timings_qmenu_strings = - kmalloc_array(dev->query_dv_timings_size, 32, GFP_KERNEL); - - if (!dev->query_dv_timings_qmenu || - !dev->query_dv_timings_qmenu_strings) - goto free_dev; - - for (i = 0; i < dev->query_dv_timings_size; i++) { - const struct v4l2_bt_timings *bt = &v4l2_dv_timings_presets[i].bt; - char *p = dev->query_dv_timings_qmenu_strings + i * 32; - u32 htot, vtot; - - dev->query_dv_timings_qmenu[i] = p; - - htot = V4L2_DV_BT_FRAME_WIDTH(bt); - vtot = V4L2_DV_BT_FRAME_HEIGHT(bt); - snprintf(p, 32, "%ux%u%s%u", - bt->width, bt->height, bt->interlaced ? "i" : "p", - (u32)bt->pixelclock / (htot * vtot)); - } - - /* disable invalid ioctls based on the feature set */ - if (!dev->has_audio_inputs) { - v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_S_AUDIO); - v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_G_AUDIO); - v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_ENUMAUDIO); - v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_S_AUDIO); - v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_G_AUDIO); - v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_ENUMAUDIO); - v4l2_disable_ioctl(&dev->meta_cap_dev, VIDIOC_S_AUDIO); - v4l2_disable_ioctl(&dev->meta_cap_dev, VIDIOC_G_AUDIO); - v4l2_disable_ioctl(&dev->meta_cap_dev, VIDIOC_ENUMAUDIO); - } - if (!dev->has_audio_outputs) { - v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_S_AUDOUT); - v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_G_AUDOUT); - v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_ENUMAUDOUT); - v4l2_disable_ioctl(&dev->vbi_out_dev, VIDIOC_S_AUDOUT); - v4l2_disable_ioctl(&dev->vbi_out_dev, VIDIOC_G_AUDOUT); - v4l2_disable_ioctl(&dev->vbi_out_dev, VIDIOC_ENUMAUDOUT); - v4l2_disable_ioctl(&dev->meta_out_dev, VIDIOC_S_AUDOUT); - v4l2_disable_ioctl(&dev->meta_out_dev, VIDIOC_G_AUDOUT); - v4l2_disable_ioctl(&dev->meta_out_dev, VIDIOC_ENUMAUDOUT); - } - if (!in_type_counter[TV] && !in_type_counter[SVID]) { - v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_S_STD); - v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_G_STD); - v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_ENUMSTD); - v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_QUERYSTD); - } - if (!out_type_counter[SVID]) { - v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_S_STD); - v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_G_STD); - v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_ENUMSTD); - } - if (!has_tuner && !has_modulator) { - v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_S_FREQUENCY); - v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_G_FREQUENCY); - v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_S_FREQUENCY); - v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_G_FREQUENCY); - v4l2_disable_ioctl(&dev->meta_cap_dev, VIDIOC_S_FREQUENCY); - v4l2_disable_ioctl(&dev->meta_cap_dev, VIDIOC_G_FREQUENCY); - } - if (!has_tuner) { - v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_S_TUNER); - v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_G_TUNER); - v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_S_TUNER); - v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_G_TUNER); - v4l2_disable_ioctl(&dev->meta_cap_dev, VIDIOC_S_TUNER); - v4l2_disable_ioctl(&dev->meta_cap_dev, VIDIOC_G_TUNER); - } - if (in_type_counter[HDMI] == 0) { - v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_S_EDID); - v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_G_EDID); - v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_DV_TIMINGS_CAP); - v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_G_DV_TIMINGS); - v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_S_DV_TIMINGS); - v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_ENUM_DV_TIMINGS); - v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_QUERY_DV_TIMINGS); - } - if (out_type_counter[HDMI] == 0) { - v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_G_EDID); - v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_DV_TIMINGS_CAP); - v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_G_DV_TIMINGS); - v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_S_DV_TIMINGS); - v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_ENUM_DV_TIMINGS); - } - if (!dev->has_fb) { - v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_G_FBUF); - v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_S_FBUF); - v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_OVERLAY); - } - v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_S_HW_FREQ_SEEK); - v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_S_HW_FREQ_SEEK); - v4l2_disable_ioctl(&dev->sdr_cap_dev, VIDIOC_S_HW_FREQ_SEEK); - v4l2_disable_ioctl(&dev->meta_cap_dev, VIDIOC_S_HW_FREQ_SEEK); - v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_S_FREQUENCY); - v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_G_FREQUENCY); - v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_ENUM_FRAMESIZES); - v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_ENUM_FRAMEINTERVALS); - v4l2_disable_ioctl(&dev->vbi_out_dev, VIDIOC_S_FREQUENCY); - v4l2_disable_ioctl(&dev->vbi_out_dev, VIDIOC_G_FREQUENCY); - v4l2_disable_ioctl(&dev->meta_out_dev, VIDIOC_S_FREQUENCY); - v4l2_disable_ioctl(&dev->meta_out_dev, VIDIOC_G_FREQUENCY); - v4l2_disable_ioctl(&dev->touch_cap_dev, VIDIOC_S_PARM); - v4l2_disable_ioctl(&dev->touch_cap_dev, VIDIOC_ENUM_FRAMESIZES); - v4l2_disable_ioctl(&dev->touch_cap_dev, VIDIOC_ENUM_FRAMEINTERVALS); - - /* configure internal data */ - dev->fmt_cap = &vivid_formats[0]; - dev->fmt_out = &vivid_formats[0]; - if (!dev->multiplanar) - vivid_formats[0].data_offset[0] = 0; - dev->webcam_size_idx = 1; - dev->webcam_ival_idx = 3; - tpg_s_fourcc(&dev->tpg, dev->fmt_cap->fourcc); - dev->std_out = V4L2_STD_PAL; - if (dev->input_type[0] == TV || dev->input_type[0] == SVID) - tvnorms_cap = V4L2_STD_ALL; - if (dev->output_type[0] == SVID) - tvnorms_out = V4L2_STD_ALL; - for (i = 0; i < MAX_INPUTS; i++) { - dev->dv_timings_cap[i] = def_dv_timings; - dev->std_cap[i] = V4L2_STD_PAL; - } - dev->dv_timings_out = def_dv_timings; - dev->tv_freq = 2804 /* 175.25 * 16 */; - dev->tv_audmode = V4L2_TUNER_MODE_STEREO; - dev->tv_field_cap = V4L2_FIELD_INTERLACED; - dev->tv_field_out = V4L2_FIELD_INTERLACED; - dev->radio_rx_freq = 95000 * 16; - dev->radio_rx_audmode = V4L2_TUNER_MODE_STEREO; - if (dev->has_radio_tx) { - dev->radio_tx_freq = 95500 * 16; - dev->radio_rds_loop = false; - } - dev->radio_tx_subchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_RDS; - dev->sdr_adc_freq = 300000; - dev->sdr_fm_freq = 50000000; - dev->sdr_pixelformat = V4L2_SDR_FMT_CU8; - dev->sdr_buffersize = SDR_CAP_SAMPLES_PER_BUF * 2; - - dev->edid_max_blocks = dev->edid_blocks = 2; - memcpy(dev->edid, vivid_hdmi_edid, sizeof(vivid_hdmi_edid)); - dev->radio_rds_init_time = ktime_get(); - - /* create all controls */ - ret = vivid_create_controls(dev, ccs_cap == -1, ccs_out == -1, no_error_inj, - in_type_counter[TV] || in_type_counter[SVID] || - out_type_counter[SVID], - in_type_counter[HDMI] || out_type_counter[HDMI]); - if (ret) - goto unreg_dev; - - /* enable/disable interface specific controls */ - if (dev->num_outputs && dev->output_type[0] != HDMI) - v4l2_ctrl_activate(dev->ctrl_display_present, false); - if (dev->num_inputs && dev->input_type[0] != HDMI) { - v4l2_ctrl_activate(dev->ctrl_dv_timings_signal_mode, false); - v4l2_ctrl_activate(dev->ctrl_dv_timings, false); - } else if (dev->num_inputs && dev->input_type[0] == HDMI) { - v4l2_ctrl_activate(dev->ctrl_std_signal_mode, false); - v4l2_ctrl_activate(dev->ctrl_standard, false); - } - - /* - * update the capture and output formats to do a proper initial - * configuration. - */ - vivid_update_format_cap(dev, false); - vivid_update_format_out(dev); - - /* initialize overlay */ - dev->fb_cap.fmt.width = dev->src_rect.width; - dev->fb_cap.fmt.height = dev->src_rect.height; - dev->fb_cap.fmt.pixelformat = dev->fmt_cap->fourcc; - dev->fb_cap.fmt.bytesperline = dev->src_rect.width * tpg_g_twopixelsize(&dev->tpg, 0) / 2; - dev->fb_cap.fmt.sizeimage = dev->src_rect.height * dev->fb_cap.fmt.bytesperline; - - /* update touch configuration */ - dev->timeperframe_tch_cap.numerator = 1; - dev->timeperframe_tch_cap.denominator = 10; - vivid_set_touch(dev, 0); - - /* initialize locks */ - spin_lock_init(&dev->slock); - mutex_init(&dev->mutex); - - /* init dma queues */ - INIT_LIST_HEAD(&dev->vid_cap_active); - INIT_LIST_HEAD(&dev->vid_out_active); - INIT_LIST_HEAD(&dev->vbi_cap_active); - INIT_LIST_HEAD(&dev->vbi_out_active); - INIT_LIST_HEAD(&dev->sdr_cap_active); - INIT_LIST_HEAD(&dev->meta_cap_active); - INIT_LIST_HEAD(&dev->meta_out_active); - INIT_LIST_HEAD(&dev->touch_cap_active); - - INIT_LIST_HEAD(&dev->cec_work_list); - spin_lock_init(&dev->cec_slock); - /* - * Same as create_singlethread_workqueue, but now I can use the - * string formatting of alloc_ordered_workqueue. - */ - dev->cec_workqueue = - alloc_ordered_workqueue("vivid-%03d-cec", WQ_MEM_RECLAIM, inst); - if (!dev->cec_workqueue) { - ret = -ENOMEM; - goto unreg_dev; - } - - if (allocators[inst] == 1) - dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); - - /* start creating the vb2 queues */ - if (dev->has_vid_cap) { - /* initialize vid_cap queue */ - ret = vivid_create_queue(dev, &dev->vb_vid_cap_q, - V4L2_BUF_TYPE_VIDEO_CAPTURE, 2, - &vivid_vid_cap_qops); - if (ret) - goto unreg_dev; - } - - if (dev->has_vid_out) { - /* initialize vid_out queue */ - ret = vivid_create_queue(dev, &dev->vb_vid_out_q, - V4L2_BUF_TYPE_VIDEO_OUTPUT, 2, - &vivid_vid_out_qops); - if (ret) - goto unreg_dev; - } - - if (dev->has_vbi_cap) { - /* initialize vbi_cap queue */ - ret = vivid_create_queue(dev, &dev->vb_vbi_cap_q, - V4L2_BUF_TYPE_VBI_CAPTURE, 2, - &vivid_vbi_cap_qops); - if (ret) - goto unreg_dev; - } - - if (dev->has_vbi_out) { - /* initialize vbi_out queue */ - ret = vivid_create_queue(dev, &dev->vb_vbi_out_q, - V4L2_BUF_TYPE_VBI_OUTPUT, 2, - &vivid_vbi_out_qops); - if (ret) - goto unreg_dev; - } - - if (dev->has_sdr_cap) { - /* initialize sdr_cap queue */ - ret = vivid_create_queue(dev, &dev->vb_sdr_cap_q, - V4L2_BUF_TYPE_SDR_CAPTURE, 8, - &vivid_sdr_cap_qops); - if (ret) - goto unreg_dev; - } - - if (dev->has_meta_cap) { - /* initialize meta_cap queue */ - ret = vivid_create_queue(dev, &dev->vb_meta_cap_q, - V4L2_BUF_TYPE_META_CAPTURE, 2, - &vivid_meta_cap_qops); - if (ret) - goto unreg_dev; - } - - if (dev->has_meta_out) { - /* initialize meta_out queue */ - ret = vivid_create_queue(dev, &dev->vb_meta_out_q, - V4L2_BUF_TYPE_META_OUTPUT, 1, - &vivid_meta_out_qops); - if (ret) - goto unreg_dev; - } - - if (dev->has_touch_cap) { - /* initialize touch_cap queue */ - ret = vivid_create_queue(dev, &dev->vb_touch_cap_q, - V4L2_BUF_TYPE_VIDEO_CAPTURE, 1, - &vivid_touch_cap_qops); - if (ret) - goto unreg_dev; - } - - if (dev->has_fb) { - /* Create framebuffer for testing capture/output overlay */ - ret = vivid_fb_init(dev); - if (ret) - goto unreg_dev; - v4l2_info(&dev->v4l2_dev, "Framebuffer device registered as fb%d\n", - dev->fb_info.node); - } - -#ifdef CONFIG_VIDEO_VIVID_CEC - if (dev->has_vid_cap && in_type_counter[HDMI]) { - struct cec_adapter *adap; - - adap = vivid_cec_alloc_adap(dev, 0, false); - ret = PTR_ERR_OR_ZERO(adap); - if (ret < 0) - goto unreg_dev; - dev->cec_rx_adap = adap; - } - - if (dev->has_vid_out) { - for (i = 0; i < dev->num_outputs; i++) { - struct cec_adapter *adap; - - if (dev->output_type[i] != HDMI) - continue; - - dev->cec_output2bus_map[i] = cec_tx_bus_cnt; - adap = vivid_cec_alloc_adap(dev, cec_tx_bus_cnt, true); - ret = PTR_ERR_OR_ZERO(adap); - if (ret < 0) { - for (i = 0; i < dev->num_outputs; i++) - cec_delete_adapter(dev->cec_tx_adap[i]); - goto unreg_dev; - } - - dev->cec_tx_adap[cec_tx_bus_cnt] = adap; - cec_tx_bus_cnt++; - } - } -#endif - - v4l2_ctrl_handler_setup(&dev->ctrl_hdl_vid_cap); - v4l2_ctrl_handler_setup(&dev->ctrl_hdl_vid_out); - v4l2_ctrl_handler_setup(&dev->ctrl_hdl_vbi_cap); - v4l2_ctrl_handler_setup(&dev->ctrl_hdl_vbi_out); - v4l2_ctrl_handler_setup(&dev->ctrl_hdl_radio_rx); - v4l2_ctrl_handler_setup(&dev->ctrl_hdl_radio_tx); - v4l2_ctrl_handler_setup(&dev->ctrl_hdl_sdr_cap); - v4l2_ctrl_handler_setup(&dev->ctrl_hdl_meta_cap); - v4l2_ctrl_handler_setup(&dev->ctrl_hdl_meta_out); - v4l2_ctrl_handler_setup(&dev->ctrl_hdl_touch_cap); - - /* finally start creating the device nodes */ - if (dev->has_vid_cap) { - vfd = &dev->vid_cap_dev; - snprintf(vfd->name, sizeof(vfd->name), - "vivid-%03d-vid-cap", inst); - vfd->fops = &vivid_fops; - vfd->ioctl_ops = &vivid_ioctl_ops; - vfd->device_caps = dev->vid_cap_caps; - vfd->release = video_device_release_empty; - vfd->v4l2_dev = &dev->v4l2_dev; - vfd->queue = &dev->vb_vid_cap_q; - vfd->tvnorms = tvnorms_cap; - - /* - * Provide a mutex to v4l2 core. It will be used to protect - * all fops and v4l2 ioctls. - */ - vfd->lock = &dev->mutex; - video_set_drvdata(vfd, dev); - -#ifdef CONFIG_MEDIA_CONTROLLER - dev->vid_cap_pad.flags = MEDIA_PAD_FL_SINK; - ret = media_entity_pads_init(&vfd->entity, 1, &dev->vid_cap_pad); - if (ret) - goto unreg_dev; -#endif - -#ifdef CONFIG_VIDEO_VIVID_CEC - if (in_type_counter[HDMI]) { - ret = cec_register_adapter(dev->cec_rx_adap, &pdev->dev); - if (ret < 0) { - cec_delete_adapter(dev->cec_rx_adap); - dev->cec_rx_adap = NULL; - goto unreg_dev; - } - cec_s_phys_addr(dev->cec_rx_adap, 0, false); - v4l2_info(&dev->v4l2_dev, "CEC adapter %s registered for HDMI input 0\n", - dev_name(&dev->cec_rx_adap->devnode.dev)); - } -#endif - - ret = video_register_device(vfd, VFL_TYPE_VIDEO, vid_cap_nr[inst]); - if (ret < 0) - goto unreg_dev; - v4l2_info(&dev->v4l2_dev, "V4L2 capture device registered as %s\n", - video_device_node_name(vfd)); - } - - if (dev->has_vid_out) { - vfd = &dev->vid_out_dev; - snprintf(vfd->name, sizeof(vfd->name), - "vivid-%03d-vid-out", inst); - vfd->vfl_dir = VFL_DIR_TX; - vfd->fops = &vivid_fops; - vfd->ioctl_ops = &vivid_ioctl_ops; - vfd->device_caps = dev->vid_out_caps; - vfd->release = video_device_release_empty; - vfd->v4l2_dev = &dev->v4l2_dev; - vfd->queue = &dev->vb_vid_out_q; - vfd->tvnorms = tvnorms_out; - - /* - * Provide a mutex to v4l2 core. It will be used to protect - * all fops and v4l2 ioctls. - */ - vfd->lock = &dev->mutex; - video_set_drvdata(vfd, dev); - -#ifdef CONFIG_MEDIA_CONTROLLER - dev->vid_out_pad.flags = MEDIA_PAD_FL_SOURCE; - ret = media_entity_pads_init(&vfd->entity, 1, &dev->vid_out_pad); - if (ret) - goto unreg_dev; -#endif - -#ifdef CONFIG_VIDEO_VIVID_CEC - for (i = 0; i < cec_tx_bus_cnt; i++) { - ret = cec_register_adapter(dev->cec_tx_adap[i], &pdev->dev); - if (ret < 0) { - for (; i < cec_tx_bus_cnt; i++) { - cec_delete_adapter(dev->cec_tx_adap[i]); - dev->cec_tx_adap[i] = NULL; - } - goto unreg_dev; - } - v4l2_info(&dev->v4l2_dev, "CEC adapter %s registered for HDMI output %d\n", - dev_name(&dev->cec_tx_adap[i]->devnode.dev), i); - if (i < out_type_counter[HDMI]) - cec_s_phys_addr(dev->cec_tx_adap[i], (i + 1) << 12, false); - else - cec_s_phys_addr(dev->cec_tx_adap[i], 0x1000, false); - } -#endif - - ret = video_register_device(vfd, VFL_TYPE_VIDEO, vid_out_nr[inst]); - if (ret < 0) - goto unreg_dev; - v4l2_info(&dev->v4l2_dev, "V4L2 output device registered as %s\n", - video_device_node_name(vfd)); - } - - if (dev->has_vbi_cap) { - vfd = &dev->vbi_cap_dev; - snprintf(vfd->name, sizeof(vfd->name), - "vivid-%03d-vbi-cap", inst); - vfd->fops = &vivid_fops; - vfd->ioctl_ops = &vivid_ioctl_ops; - vfd->device_caps = dev->vbi_cap_caps; - vfd->release = video_device_release_empty; - vfd->v4l2_dev = &dev->v4l2_dev; - vfd->queue = &dev->vb_vbi_cap_q; - vfd->lock = &dev->mutex; - vfd->tvnorms = tvnorms_cap; - video_set_drvdata(vfd, dev); - -#ifdef CONFIG_MEDIA_CONTROLLER - dev->vbi_cap_pad.flags = MEDIA_PAD_FL_SINK; - ret = media_entity_pads_init(&vfd->entity, 1, &dev->vbi_cap_pad); - if (ret) - goto unreg_dev; -#endif - - ret = video_register_device(vfd, VFL_TYPE_VBI, vbi_cap_nr[inst]); - if (ret < 0) - goto unreg_dev; - v4l2_info(&dev->v4l2_dev, "V4L2 capture device registered as %s, supports %s VBI\n", - video_device_node_name(vfd), - (dev->has_raw_vbi_cap && dev->has_sliced_vbi_cap) ? - "raw and sliced" : - (dev->has_raw_vbi_cap ? "raw" : "sliced")); - } - - if (dev->has_vbi_out) { - vfd = &dev->vbi_out_dev; - snprintf(vfd->name, sizeof(vfd->name), - "vivid-%03d-vbi-out", inst); - vfd->vfl_dir = VFL_DIR_TX; - vfd->fops = &vivid_fops; - vfd->ioctl_ops = &vivid_ioctl_ops; - vfd->device_caps = dev->vbi_out_caps; - vfd->release = video_device_release_empty; - vfd->v4l2_dev = &dev->v4l2_dev; - vfd->queue = &dev->vb_vbi_out_q; - vfd->lock = &dev->mutex; - vfd->tvnorms = tvnorms_out; - video_set_drvdata(vfd, dev); - -#ifdef CONFIG_MEDIA_CONTROLLER - dev->vbi_out_pad.flags = MEDIA_PAD_FL_SOURCE; - ret = media_entity_pads_init(&vfd->entity, 1, &dev->vbi_out_pad); - if (ret) - goto unreg_dev; -#endif - - ret = video_register_device(vfd, VFL_TYPE_VBI, vbi_out_nr[inst]); - if (ret < 0) - goto unreg_dev; - v4l2_info(&dev->v4l2_dev, "V4L2 output device registered as %s, supports %s VBI\n", - video_device_node_name(vfd), - (dev->has_raw_vbi_out && dev->has_sliced_vbi_out) ? - "raw and sliced" : - (dev->has_raw_vbi_out ? "raw" : "sliced")); - } - - if (dev->has_sdr_cap) { - vfd = &dev->sdr_cap_dev; - snprintf(vfd->name, sizeof(vfd->name), - "vivid-%03d-sdr-cap", inst); - vfd->fops = &vivid_fops; - vfd->ioctl_ops = &vivid_ioctl_ops; - vfd->device_caps = dev->sdr_cap_caps; - vfd->release = video_device_release_empty; - vfd->v4l2_dev = &dev->v4l2_dev; - vfd->queue = &dev->vb_sdr_cap_q; - vfd->lock = &dev->mutex; - video_set_drvdata(vfd, dev); - -#ifdef CONFIG_MEDIA_CONTROLLER - dev->sdr_cap_pad.flags = MEDIA_PAD_FL_SINK; - ret = media_entity_pads_init(&vfd->entity, 1, &dev->sdr_cap_pad); - if (ret) - goto unreg_dev; -#endif - - ret = video_register_device(vfd, VFL_TYPE_SDR, sdr_cap_nr[inst]); - if (ret < 0) - goto unreg_dev; - v4l2_info(&dev->v4l2_dev, "V4L2 capture device registered as %s\n", - video_device_node_name(vfd)); - } - - if (dev->has_radio_rx) { - vfd = &dev->radio_rx_dev; - snprintf(vfd->name, sizeof(vfd->name), - "vivid-%03d-rad-rx", inst); - vfd->fops = &vivid_radio_fops; - vfd->ioctl_ops = &vivid_ioctl_ops; - vfd->device_caps = dev->radio_rx_caps; - vfd->release = video_device_release_empty; - vfd->v4l2_dev = &dev->v4l2_dev; - vfd->lock = &dev->mutex; - video_set_drvdata(vfd, dev); - - ret = video_register_device(vfd, VFL_TYPE_RADIO, radio_rx_nr[inst]); - if (ret < 0) - goto unreg_dev; - v4l2_info(&dev->v4l2_dev, "V4L2 receiver device registered as %s\n", - video_device_node_name(vfd)); - } - - if (dev->has_radio_tx) { - vfd = &dev->radio_tx_dev; - snprintf(vfd->name, sizeof(vfd->name), - "vivid-%03d-rad-tx", inst); - vfd->vfl_dir = VFL_DIR_TX; - vfd->fops = &vivid_radio_fops; - vfd->ioctl_ops = &vivid_ioctl_ops; - vfd->device_caps = dev->radio_tx_caps; - vfd->release = video_device_release_empty; - vfd->v4l2_dev = &dev->v4l2_dev; - vfd->lock = &dev->mutex; - video_set_drvdata(vfd, dev); - - ret = video_register_device(vfd, VFL_TYPE_RADIO, radio_tx_nr[inst]); - if (ret < 0) - goto unreg_dev; - v4l2_info(&dev->v4l2_dev, "V4L2 transmitter device registered as %s\n", - video_device_node_name(vfd)); - } - - if (dev->has_meta_cap) { - vfd = &dev->meta_cap_dev; - snprintf(vfd->name, sizeof(vfd->name), - "vivid-%03d-meta-cap", inst); - vfd->fops = &vivid_fops; - vfd->ioctl_ops = &vivid_ioctl_ops; - vfd->device_caps = dev->meta_cap_caps; - vfd->release = video_device_release_empty; - vfd->v4l2_dev = &dev->v4l2_dev; - vfd->queue = &dev->vb_meta_cap_q; - vfd->lock = &dev->mutex; - vfd->tvnorms = tvnorms_cap; - video_set_drvdata(vfd, dev); -#ifdef CONFIG_MEDIA_CONTROLLER - dev->meta_cap_pad.flags = MEDIA_PAD_FL_SINK; - ret = media_entity_pads_init(&vfd->entity, 1, - &dev->meta_cap_pad); - if (ret) - goto unreg_dev; -#endif - ret = video_register_device(vfd, VFL_TYPE_VIDEO, - meta_cap_nr[inst]); - if (ret < 0) - goto unreg_dev; - v4l2_info(&dev->v4l2_dev, - "V4L2 metadata capture device registered as %s\n", - video_device_node_name(vfd)); - } - - if (dev->has_meta_out) { - vfd = &dev->meta_out_dev; - snprintf(vfd->name, sizeof(vfd->name), - "vivid-%03d-meta-out", inst); - vfd->vfl_dir = VFL_DIR_TX; - vfd->fops = &vivid_fops; - vfd->ioctl_ops = &vivid_ioctl_ops; - vfd->device_caps = dev->meta_out_caps; - vfd->release = video_device_release_empty; - vfd->v4l2_dev = &dev->v4l2_dev; - vfd->queue = &dev->vb_meta_out_q; - vfd->lock = &dev->mutex; - vfd->tvnorms = tvnorms_out; - video_set_drvdata(vfd, dev); -#ifdef CONFIG_MEDIA_CONTROLLER - dev->meta_out_pad.flags = MEDIA_PAD_FL_SOURCE; - ret = media_entity_pads_init(&vfd->entity, 1, - &dev->meta_out_pad); - if (ret) - goto unreg_dev; -#endif - ret = video_register_device(vfd, VFL_TYPE_VIDEO, - meta_out_nr[inst]); - if (ret < 0) - goto unreg_dev; - v4l2_info(&dev->v4l2_dev, - "V4L2 metadata output device registered as %s\n", - video_device_node_name(vfd)); - } - - if (dev->has_touch_cap) { - vfd = &dev->touch_cap_dev; - snprintf(vfd->name, sizeof(vfd->name), - "vivid-%03d-touch-cap", inst); - vfd->fops = &vivid_fops; - vfd->ioctl_ops = &vivid_ioctl_ops; - vfd->device_caps = dev->touch_cap_caps; - vfd->release = video_device_release_empty; - vfd->v4l2_dev = &dev->v4l2_dev; - vfd->queue = &dev->vb_touch_cap_q; - vfd->tvnorms = tvnorms_cap; - vfd->lock = &dev->mutex; - video_set_drvdata(vfd, dev); -#ifdef CONFIG_MEDIA_CONTROLLER - dev->touch_cap_pad.flags = MEDIA_PAD_FL_SINK; - ret = media_entity_pads_init(&vfd->entity, 1, - &dev->touch_cap_pad); - if (ret) - goto unreg_dev; -#endif - ret = video_register_device(vfd, VFL_TYPE_TOUCH, - touch_cap_nr[inst]); - if (ret < 0) - goto unreg_dev; - v4l2_info(&dev->v4l2_dev, - "V4L2 touch capture device registered as %s\n", - video_device_node_name(vfd)); - } - -#ifdef CONFIG_MEDIA_CONTROLLER - /* Register the media device */ - ret = media_device_register(&dev->mdev); - if (ret) { - dev_err(dev->mdev.dev, - "media device register failed (err=%d)\n", ret); - goto unreg_dev; - } -#endif - - /* Now that everything is fine, let's add it to device list */ - vivid_devs[inst] = dev; - - return 0; - -unreg_dev: - video_unregister_device(&dev->touch_cap_dev); - video_unregister_device(&dev->meta_out_dev); - video_unregister_device(&dev->meta_cap_dev); - video_unregister_device(&dev->radio_tx_dev); - video_unregister_device(&dev->radio_rx_dev); - video_unregister_device(&dev->sdr_cap_dev); - video_unregister_device(&dev->vbi_out_dev); - video_unregister_device(&dev->vbi_cap_dev); - video_unregister_device(&dev->vid_out_dev); - video_unregister_device(&dev->vid_cap_dev); - cec_unregister_adapter(dev->cec_rx_adap); - for (i = 0; i < MAX_OUTPUTS; i++) - cec_unregister_adapter(dev->cec_tx_adap[i]); - if (dev->cec_workqueue) { - vivid_cec_bus_free_work(dev); - destroy_workqueue(dev->cec_workqueue); - } -free_dev: - v4l2_device_put(&dev->v4l2_dev); - return ret; -} - -/* This routine allocates from 1 to n_devs virtual drivers. - - The real maximum number of virtual drivers will depend on how many drivers - will succeed. This is limited to the maximum number of devices that - videodev supports, which is equal to VIDEO_NUM_DEVICES. - */ -static int vivid_probe(struct platform_device *pdev) -{ - const struct font_desc *font = find_font("VGA8x16"); - int ret = 0, i; - - if (font == NULL) { - pr_err("vivid: could not find font\n"); - return -ENODEV; - } - - tpg_set_font(font->data); - - n_devs = clamp_t(unsigned, n_devs, 1, VIVID_MAX_DEVS); - - for (i = 0; i < n_devs; i++) { - ret = vivid_create_instance(pdev, i); - if (ret) { - /* If some instantiations succeeded, keep driver */ - if (i) - ret = 0; - break; - } - } - - if (ret < 0) { - pr_err("vivid: error %d while loading driver\n", ret); - return ret; - } - - /* n_devs will reflect the actual number of allocated devices */ - n_devs = i; - - return ret; -} - -static int vivid_remove(struct platform_device *pdev) -{ - struct vivid_dev *dev; - unsigned int i, j; - - for (i = 0; i < n_devs; i++) { - dev = vivid_devs[i]; - if (!dev) - continue; - -#ifdef CONFIG_MEDIA_CONTROLLER - media_device_unregister(&dev->mdev); -#endif - - if (dev->has_vid_cap) { - v4l2_info(&dev->v4l2_dev, "unregistering %s\n", - video_device_node_name(&dev->vid_cap_dev)); - video_unregister_device(&dev->vid_cap_dev); - } - if (dev->has_vid_out) { - v4l2_info(&dev->v4l2_dev, "unregistering %s\n", - video_device_node_name(&dev->vid_out_dev)); - video_unregister_device(&dev->vid_out_dev); - } - if (dev->has_vbi_cap) { - v4l2_info(&dev->v4l2_dev, "unregistering %s\n", - video_device_node_name(&dev->vbi_cap_dev)); - video_unregister_device(&dev->vbi_cap_dev); - } - if (dev->has_vbi_out) { - v4l2_info(&dev->v4l2_dev, "unregistering %s\n", - video_device_node_name(&dev->vbi_out_dev)); - video_unregister_device(&dev->vbi_out_dev); - } - if (dev->has_sdr_cap) { - v4l2_info(&dev->v4l2_dev, "unregistering %s\n", - video_device_node_name(&dev->sdr_cap_dev)); - video_unregister_device(&dev->sdr_cap_dev); - } - if (dev->has_radio_rx) { - v4l2_info(&dev->v4l2_dev, "unregistering %s\n", - video_device_node_name(&dev->radio_rx_dev)); - video_unregister_device(&dev->radio_rx_dev); - } - if (dev->has_radio_tx) { - v4l2_info(&dev->v4l2_dev, "unregistering %s\n", - video_device_node_name(&dev->radio_tx_dev)); - video_unregister_device(&dev->radio_tx_dev); - } - if (dev->has_fb) { - v4l2_info(&dev->v4l2_dev, "unregistering fb%d\n", - dev->fb_info.node); - unregister_framebuffer(&dev->fb_info); - vivid_fb_release_buffers(dev); - } - if (dev->has_meta_cap) { - v4l2_info(&dev->v4l2_dev, "unregistering %s\n", - video_device_node_name(&dev->meta_cap_dev)); - video_unregister_device(&dev->meta_cap_dev); - } - if (dev->has_meta_out) { - v4l2_info(&dev->v4l2_dev, "unregistering %s\n", - video_device_node_name(&dev->meta_out_dev)); - video_unregister_device(&dev->meta_out_dev); - } - if (dev->has_touch_cap) { - v4l2_info(&dev->v4l2_dev, "unregistering %s\n", - video_device_node_name(&dev->touch_cap_dev)); - video_unregister_device(&dev->touch_cap_dev); - } - cec_unregister_adapter(dev->cec_rx_adap); - for (j = 0; j < MAX_OUTPUTS; j++) - cec_unregister_adapter(dev->cec_tx_adap[j]); - if (dev->cec_workqueue) { - vivid_cec_bus_free_work(dev); - destroy_workqueue(dev->cec_workqueue); - } - v4l2_device_put(&dev->v4l2_dev); - vivid_devs[i] = NULL; - } - return 0; -} - -static void vivid_pdev_release(struct device *dev) -{ -} - -static struct platform_device vivid_pdev = { - .name = "vivid", - .dev.release = vivid_pdev_release, -}; - -static struct platform_driver vivid_pdrv = { - .probe = vivid_probe, - .remove = vivid_remove, - .driver = { - .name = "vivid", - }, -}; - -static int __init vivid_init(void) -{ - int ret; - - ret = platform_device_register(&vivid_pdev); - if (ret) - return ret; - - ret = platform_driver_register(&vivid_pdrv); - if (ret) - platform_device_unregister(&vivid_pdev); - - return ret; -} - -static void __exit vivid_exit(void) -{ - platform_driver_unregister(&vivid_pdrv); - platform_device_unregister(&vivid_pdev); -} - -module_init(vivid_init); -module_exit(vivid_exit); diff --git a/drivers/media/platform/vivid/vivid-core.h b/drivers/media/platform/vivid/vivid-core.h deleted file mode 100644 index 99e69b8f770f..000000000000 --- a/drivers/media/platform/vivid/vivid-core.h +++ /dev/null @@ -1,612 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * vivid-core.h - core datastructures - * - * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - */ - -#ifndef _VIVID_CORE_H_ -#define _VIVID_CORE_H_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include "vivid-rds-gen.h" -#include "vivid-vbi-gen.h" - -#define dprintk(dev, level, fmt, arg...) \ - v4l2_dbg(level, vivid_debug, &dev->v4l2_dev, fmt, ## arg) - -/* The maximum number of clip rectangles */ -#define MAX_CLIPS 16 -/* The maximum number of inputs */ -#define MAX_INPUTS 16 -/* The maximum number of outputs */ -#define MAX_OUTPUTS 16 -/* The maximum up or down scaling factor is 4 */ -#define MAX_ZOOM 4 -/* The maximum image width/height are set to 4K DMT */ -#define MAX_WIDTH 4096 -#define MAX_HEIGHT 2160 -/* The minimum image width/height */ -#define MIN_WIDTH 16 -#define MIN_HEIGHT 16 -/* The data_offset of plane 0 for the multiplanar formats */ -#define PLANE0_DATA_OFFSET 128 - -/* The supported TV frequency range in MHz */ -#define MIN_TV_FREQ (44U * 16U) -#define MAX_TV_FREQ (958U * 16U) - -/* The number of samples returned in every SDR buffer */ -#define SDR_CAP_SAMPLES_PER_BUF 0x4000 - -/* used by the threads to know when to resync internal counters */ -#define JIFFIES_PER_DAY (3600U * 24U * HZ) -#define JIFFIES_RESYNC (JIFFIES_PER_DAY * (0xf0000000U / JIFFIES_PER_DAY)) - -extern const struct v4l2_rect vivid_min_rect; -extern const struct v4l2_rect vivid_max_rect; -extern unsigned vivid_debug; - -struct vivid_fmt { - u32 fourcc; /* v4l2 format id */ - enum tgp_color_enc color_enc; - bool can_do_overlay; - u8 vdownsampling[TPG_MAX_PLANES]; - u32 alpha_mask; - u8 planes; - u8 buffers; - u32 data_offset[TPG_MAX_PLANES]; - u32 bit_depth[TPG_MAX_PLANES]; -}; - -extern struct vivid_fmt vivid_formats[]; - -/* buffer for one video frame */ -struct vivid_buffer { - /* common v4l buffer stuff -- must be first */ - struct vb2_v4l2_buffer vb; - struct list_head list; -}; - -enum vivid_input { - WEBCAM, - TV, - SVID, - HDMI, -}; - -enum vivid_signal_mode { - CURRENT_DV_TIMINGS, - CURRENT_STD = CURRENT_DV_TIMINGS, - NO_SIGNAL, - NO_LOCK, - OUT_OF_RANGE, - SELECTED_DV_TIMINGS, - SELECTED_STD = SELECTED_DV_TIMINGS, - CYCLE_DV_TIMINGS, - CYCLE_STD = CYCLE_DV_TIMINGS, - CUSTOM_DV_TIMINGS, -}; - -enum vivid_colorspace { - VIVID_CS_170M, - VIVID_CS_709, - VIVID_CS_SRGB, - VIVID_CS_OPRGB, - VIVID_CS_2020, - VIVID_CS_DCI_P3, - VIVID_CS_240M, - VIVID_CS_SYS_M, - VIVID_CS_SYS_BG, -}; - -#define VIVID_INVALID_SIGNAL(mode) \ - ((mode) == NO_SIGNAL || (mode) == NO_LOCK || (mode) == OUT_OF_RANGE) - -struct vivid_cec_work { - struct list_head list; - struct delayed_work work; - struct cec_adapter *adap; - struct vivid_dev *dev; - unsigned int usecs; - unsigned int timeout_ms; - u8 tx_status; - struct cec_msg msg; -}; - -struct vivid_dev { - unsigned inst; - struct v4l2_device v4l2_dev; -#ifdef CONFIG_MEDIA_CONTROLLER - struct media_device mdev; - struct media_pad vid_cap_pad; - struct media_pad vid_out_pad; - struct media_pad vbi_cap_pad; - struct media_pad vbi_out_pad; - struct media_pad sdr_cap_pad; - struct media_pad meta_cap_pad; - struct media_pad meta_out_pad; - struct media_pad touch_cap_pad; -#endif - struct v4l2_ctrl_handler ctrl_hdl_user_gen; - struct v4l2_ctrl_handler ctrl_hdl_user_vid; - struct v4l2_ctrl_handler ctrl_hdl_user_aud; - struct v4l2_ctrl_handler ctrl_hdl_streaming; - struct v4l2_ctrl_handler ctrl_hdl_sdtv_cap; - struct v4l2_ctrl_handler ctrl_hdl_loop_cap; - struct v4l2_ctrl_handler ctrl_hdl_fb; - struct video_device vid_cap_dev; - struct v4l2_ctrl_handler ctrl_hdl_vid_cap; - struct video_device vid_out_dev; - struct v4l2_ctrl_handler ctrl_hdl_vid_out; - struct video_device vbi_cap_dev; - struct v4l2_ctrl_handler ctrl_hdl_vbi_cap; - struct video_device vbi_out_dev; - struct v4l2_ctrl_handler ctrl_hdl_vbi_out; - struct video_device radio_rx_dev; - struct v4l2_ctrl_handler ctrl_hdl_radio_rx; - struct video_device radio_tx_dev; - struct v4l2_ctrl_handler ctrl_hdl_radio_tx; - struct video_device sdr_cap_dev; - struct v4l2_ctrl_handler ctrl_hdl_sdr_cap; - struct video_device meta_cap_dev; - struct v4l2_ctrl_handler ctrl_hdl_meta_cap; - struct video_device meta_out_dev; - struct v4l2_ctrl_handler ctrl_hdl_meta_out; - struct video_device touch_cap_dev; - struct v4l2_ctrl_handler ctrl_hdl_touch_cap; - - spinlock_t slock; - struct mutex mutex; - - /* capabilities */ - u32 vid_cap_caps; - u32 vid_out_caps; - u32 vbi_cap_caps; - u32 vbi_out_caps; - u32 sdr_cap_caps; - u32 radio_rx_caps; - u32 radio_tx_caps; - u32 meta_cap_caps; - u32 meta_out_caps; - u32 touch_cap_caps; - - /* supported features */ - bool multiplanar; - unsigned num_inputs; - unsigned int num_hdmi_inputs; - u8 input_type[MAX_INPUTS]; - u8 input_name_counter[MAX_INPUTS]; - unsigned num_outputs; - unsigned int num_hdmi_outputs; - u8 output_type[MAX_OUTPUTS]; - u8 output_name_counter[MAX_OUTPUTS]; - bool has_audio_inputs; - bool has_audio_outputs; - bool has_vid_cap; - bool has_vid_out; - bool has_vbi_cap; - bool has_raw_vbi_cap; - bool has_sliced_vbi_cap; - bool has_vbi_out; - bool has_raw_vbi_out; - bool has_sliced_vbi_out; - bool has_radio_rx; - bool has_radio_tx; - bool has_sdr_cap; - bool has_fb; - bool has_meta_cap; - bool has_meta_out; - bool has_tv_tuner; - bool has_touch_cap; - - bool can_loop_video; - - /* controls */ - struct v4l2_ctrl *brightness; - struct v4l2_ctrl *contrast; - struct v4l2_ctrl *saturation; - struct v4l2_ctrl *hue; - struct { - /* autogain/gain cluster */ - struct v4l2_ctrl *autogain; - struct v4l2_ctrl *gain; - }; - struct v4l2_ctrl *volume; - struct v4l2_ctrl *mute; - struct v4l2_ctrl *alpha; - struct v4l2_ctrl *button; - struct v4l2_ctrl *boolean; - struct v4l2_ctrl *int32; - struct v4l2_ctrl *int64; - struct v4l2_ctrl *menu; - struct v4l2_ctrl *string; - struct v4l2_ctrl *bitmask; - struct v4l2_ctrl *int_menu; - struct v4l2_ctrl *test_pattern; - struct v4l2_ctrl *colorspace; - struct v4l2_ctrl *rgb_range_cap; - struct v4l2_ctrl *real_rgb_range_cap; - struct { - /* std_signal_mode/standard cluster */ - struct v4l2_ctrl *ctrl_std_signal_mode; - struct v4l2_ctrl *ctrl_standard; - }; - struct { - /* dv_timings_signal_mode/timings cluster */ - struct v4l2_ctrl *ctrl_dv_timings_signal_mode; - struct v4l2_ctrl *ctrl_dv_timings; - }; - struct v4l2_ctrl *ctrl_display_present; - struct v4l2_ctrl *ctrl_has_crop_cap; - struct v4l2_ctrl *ctrl_has_compose_cap; - struct v4l2_ctrl *ctrl_has_scaler_cap; - struct v4l2_ctrl *ctrl_has_crop_out; - struct v4l2_ctrl *ctrl_has_compose_out; - struct v4l2_ctrl *ctrl_has_scaler_out; - struct v4l2_ctrl *ctrl_tx_mode; - struct v4l2_ctrl *ctrl_tx_rgb_range; - struct v4l2_ctrl *ctrl_tx_edid_present; - struct v4l2_ctrl *ctrl_tx_hotplug; - struct v4l2_ctrl *ctrl_tx_rxsense; - - struct v4l2_ctrl *ctrl_rx_power_present; - - struct v4l2_ctrl *radio_tx_rds_pi; - struct v4l2_ctrl *radio_tx_rds_pty; - struct v4l2_ctrl *radio_tx_rds_mono_stereo; - struct v4l2_ctrl *radio_tx_rds_art_head; - struct v4l2_ctrl *radio_tx_rds_compressed; - struct v4l2_ctrl *radio_tx_rds_dyn_pty; - struct v4l2_ctrl *radio_tx_rds_ta; - struct v4l2_ctrl *radio_tx_rds_tp; - struct v4l2_ctrl *radio_tx_rds_ms; - struct v4l2_ctrl *radio_tx_rds_psname; - struct v4l2_ctrl *radio_tx_rds_radiotext; - - struct v4l2_ctrl *radio_rx_rds_pty; - struct v4l2_ctrl *radio_rx_rds_ta; - struct v4l2_ctrl *radio_rx_rds_tp; - struct v4l2_ctrl *radio_rx_rds_ms; - struct v4l2_ctrl *radio_rx_rds_psname; - struct v4l2_ctrl *radio_rx_rds_radiotext; - - unsigned input_brightness[MAX_INPUTS]; - unsigned osd_mode; - unsigned button_pressed; - bool sensor_hflip; - bool sensor_vflip; - bool hflip; - bool vflip; - bool vbi_cap_interlaced; - bool loop_video; - bool reduced_fps; - - /* Framebuffer */ - unsigned long video_pbase; - void *video_vbase; - u32 video_buffer_size; - int display_width; - int display_height; - int display_byte_stride; - int bits_per_pixel; - int bytes_per_pixel; - struct fb_info fb_info; - struct fb_var_screeninfo fb_defined; - struct fb_fix_screeninfo fb_fix; - - /* Error injection */ - bool queue_setup_error; - bool buf_prepare_error; - bool start_streaming_error; - bool dqbuf_error; - bool req_validate_error; - bool seq_wrap; - bool time_wrap; - u64 time_wrap_offset; - unsigned perc_dropped_buffers; - enum vivid_signal_mode std_signal_mode[MAX_INPUTS]; - unsigned int query_std_last[MAX_INPUTS]; - v4l2_std_id query_std[MAX_INPUTS]; - enum tpg_video_aspect std_aspect_ratio[MAX_INPUTS]; - - enum vivid_signal_mode dv_timings_signal_mode[MAX_INPUTS]; - char **query_dv_timings_qmenu; - char *query_dv_timings_qmenu_strings; - unsigned query_dv_timings_size; - unsigned int query_dv_timings_last[MAX_INPUTS]; - unsigned int query_dv_timings[MAX_INPUTS]; - enum tpg_video_aspect dv_timings_aspect_ratio[MAX_INPUTS]; - - /* Input */ - unsigned input; - v4l2_std_id std_cap[MAX_INPUTS]; - struct v4l2_dv_timings dv_timings_cap[MAX_INPUTS]; - int dv_timings_cap_sel[MAX_INPUTS]; - u32 service_set_cap; - struct vivid_vbi_gen_data vbi_gen; - u8 *edid; - unsigned edid_blocks; - unsigned edid_max_blocks; - unsigned webcam_size_idx; - unsigned webcam_ival_idx; - unsigned tv_freq; - unsigned tv_audmode; - unsigned tv_field_cap; - unsigned tv_audio_input; - - u32 power_present; - - /* Capture Overlay */ - struct v4l2_framebuffer fb_cap; - struct v4l2_fh *overlay_cap_owner; - void *fb_vbase_cap; - int overlay_cap_top, overlay_cap_left; - enum v4l2_field overlay_cap_field; - void *bitmap_cap; - struct v4l2_clip clips_cap[MAX_CLIPS]; - struct v4l2_clip try_clips_cap[MAX_CLIPS]; - unsigned clipcount_cap; - - /* Output */ - unsigned output; - v4l2_std_id std_out; - struct v4l2_dv_timings dv_timings_out; - u32 colorspace_out; - u32 ycbcr_enc_out; - u32 hsv_enc_out; - u32 quantization_out; - u32 xfer_func_out; - u32 service_set_out; - unsigned bytesperline_out[TPG_MAX_PLANES]; - unsigned tv_field_out; - unsigned tv_audio_output; - bool vbi_out_have_wss; - u8 vbi_out_wss[2]; - bool vbi_out_have_cc[2]; - u8 vbi_out_cc[2][2]; - bool dvi_d_out; - u8 *scaled_line; - u8 *blended_line; - unsigned cur_scaled_line; - bool display_present[MAX_OUTPUTS]; - - /* Output Overlay */ - void *fb_vbase_out; - bool overlay_out_enabled; - int overlay_out_top, overlay_out_left; - void *bitmap_out; - struct v4l2_clip clips_out[MAX_CLIPS]; - struct v4l2_clip try_clips_out[MAX_CLIPS]; - unsigned clipcount_out; - unsigned fbuf_out_flags; - u32 chromakey_out; - u8 global_alpha_out; - - /* video capture */ - struct tpg_data tpg; - unsigned ms_vid_cap; - bool must_blank[VIDEO_MAX_FRAME]; - - const struct vivid_fmt *fmt_cap; - struct v4l2_fract timeperframe_vid_cap; - enum v4l2_field field_cap; - struct v4l2_rect src_rect; - struct v4l2_rect fmt_cap_rect; - struct v4l2_rect crop_cap; - struct v4l2_rect compose_cap; - struct v4l2_rect crop_bounds_cap; - struct vb2_queue vb_vid_cap_q; - struct list_head vid_cap_active; - struct vb2_queue vb_vbi_cap_q; - struct list_head vbi_cap_active; - struct vb2_queue vb_meta_cap_q; - struct list_head meta_cap_active; - struct vb2_queue vb_touch_cap_q; - struct list_head touch_cap_active; - - /* thread for generating video capture stream */ - struct task_struct *kthread_vid_cap; - unsigned long jiffies_vid_cap; - u64 cap_stream_start; - u64 cap_frame_period; - u64 cap_frame_eof_offset; - u32 cap_seq_offset; - u32 cap_seq_count; - bool cap_seq_resync; - u32 vid_cap_seq_start; - u32 vid_cap_seq_count; - bool vid_cap_streaming; - u32 vbi_cap_seq_start; - u32 vbi_cap_seq_count; - bool vbi_cap_streaming; - bool stream_sliced_vbi_cap; - u32 meta_cap_seq_start; - u32 meta_cap_seq_count; - bool meta_cap_streaming; - - /* Touch capture */ - struct task_struct *kthread_touch_cap; - unsigned long jiffies_touch_cap; - u64 touch_cap_stream_start; - u32 touch_cap_seq_offset; - bool touch_cap_seq_resync; - u32 touch_cap_seq_start; - u32 touch_cap_seq_count; - bool touch_cap_streaming; - struct v4l2_fract timeperframe_tch_cap; - struct v4l2_pix_format tch_format; - int tch_pat_random; - - /* video output */ - const struct vivid_fmt *fmt_out; - struct v4l2_fract timeperframe_vid_out; - enum v4l2_field field_out; - struct v4l2_rect sink_rect; - struct v4l2_rect fmt_out_rect; - struct v4l2_rect crop_out; - struct v4l2_rect compose_out; - struct v4l2_rect compose_bounds_out; - struct vb2_queue vb_vid_out_q; - struct list_head vid_out_active; - struct vb2_queue vb_vbi_out_q; - struct list_head vbi_out_active; - struct vb2_queue vb_meta_out_q; - struct list_head meta_out_active; - - /* video loop precalculated rectangles */ - - /* - * Intersection between what the output side composes and the capture side - * crops. I.e., what actually needs to be copied from the output buffer to - * the capture buffer. - */ - struct v4l2_rect loop_vid_copy; - /* The part of the output buffer that (after scaling) corresponds to loop_vid_copy. */ - struct v4l2_rect loop_vid_out; - /* The part of the capture buffer that (after scaling) corresponds to loop_vid_copy. */ - struct v4l2_rect loop_vid_cap; - /* - * The intersection of the framebuffer, the overlay output window and - * loop_vid_copy. I.e., the part of the framebuffer that actually should be - * blended with the compose_out rectangle. This uses the framebuffer origin. - */ - struct v4l2_rect loop_fb_copy; - /* The same as loop_fb_copy but with compose_out origin. */ - struct v4l2_rect loop_vid_overlay; - /* - * The part of the capture buffer that (after scaling) corresponds - * to loop_vid_overlay. - */ - struct v4l2_rect loop_vid_overlay_cap; - - /* thread for generating video output stream */ - struct task_struct *kthread_vid_out; - unsigned long jiffies_vid_out; - u32 out_seq_offset; - u32 out_seq_count; - bool out_seq_resync; - u32 vid_out_seq_start; - u32 vid_out_seq_count; - bool vid_out_streaming; - u32 vbi_out_seq_start; - u32 vbi_out_seq_count; - bool vbi_out_streaming; - bool stream_sliced_vbi_out; - u32 meta_out_seq_start; - u32 meta_out_seq_count; - bool meta_out_streaming; - - /* SDR capture */ - struct vb2_queue vb_sdr_cap_q; - struct list_head sdr_cap_active; - u32 sdr_pixelformat; /* v4l2 format id */ - unsigned sdr_buffersize; - unsigned sdr_adc_freq; - unsigned sdr_fm_freq; - unsigned sdr_fm_deviation; - int sdr_fixp_src_phase; - int sdr_fixp_mod_phase; - - bool tstamp_src_is_soe; - bool has_crop_cap; - bool has_compose_cap; - bool has_scaler_cap; - bool has_crop_out; - bool has_compose_out; - bool has_scaler_out; - - /* thread for generating SDR stream */ - struct task_struct *kthread_sdr_cap; - unsigned long jiffies_sdr_cap; - u32 sdr_cap_seq_offset; - u32 sdr_cap_seq_count; - bool sdr_cap_seq_resync; - - /* RDS generator */ - struct vivid_rds_gen rds_gen; - - /* Radio receiver */ - unsigned radio_rx_freq; - unsigned radio_rx_audmode; - int radio_rx_sig_qual; - unsigned radio_rx_hw_seek_mode; - bool radio_rx_hw_seek_prog_lim; - bool radio_rx_rds_controls; - bool radio_rx_rds_enabled; - unsigned radio_rx_rds_use_alternates; - unsigned radio_rx_rds_last_block; - struct v4l2_fh *radio_rx_rds_owner; - - /* Radio transmitter */ - unsigned radio_tx_freq; - unsigned radio_tx_subchans; - bool radio_tx_rds_controls; - unsigned radio_tx_rds_last_block; - struct v4l2_fh *radio_tx_rds_owner; - - /* Shared between radio receiver and transmitter */ - bool radio_rds_loop; - ktime_t radio_rds_init_time; - - /* CEC */ - struct cec_adapter *cec_rx_adap; - struct cec_adapter *cec_tx_adap[MAX_OUTPUTS]; - struct workqueue_struct *cec_workqueue; - spinlock_t cec_slock; - struct list_head cec_work_list; - unsigned int cec_xfer_time_jiffies; - unsigned long cec_xfer_start_jiffies; - u8 cec_output2bus_map[MAX_OUTPUTS]; - - /* CEC OSD String */ - char osd[14]; - unsigned long osd_jiffies; - - bool meta_pts; - bool meta_scr; -}; - -static inline bool vivid_is_webcam(const struct vivid_dev *dev) -{ - return dev->input_type[dev->input] == WEBCAM; -} - -static inline bool vivid_is_tv_cap(const struct vivid_dev *dev) -{ - return dev->input_type[dev->input] == TV; -} - -static inline bool vivid_is_svid_cap(const struct vivid_dev *dev) -{ - return dev->input_type[dev->input] == SVID; -} - -static inline bool vivid_is_hdmi_cap(const struct vivid_dev *dev) -{ - return dev->input_type[dev->input] == HDMI; -} - -static inline bool vivid_is_sdtv_cap(const struct vivid_dev *dev) -{ - return vivid_is_tv_cap(dev) || vivid_is_svid_cap(dev); -} - -static inline bool vivid_is_svid_out(const struct vivid_dev *dev) -{ - return dev->output_type[dev->output] == SVID; -} - -static inline bool vivid_is_hdmi_out(const struct vivid_dev *dev) -{ - return dev->output_type[dev->output] == HDMI; -} - -#endif diff --git a/drivers/media/platform/vivid/vivid-ctrls.c b/drivers/media/platform/vivid/vivid-ctrls.c deleted file mode 100644 index 334130568dcb..000000000000 --- a/drivers/media/platform/vivid/vivid-ctrls.c +++ /dev/null @@ -1,1939 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * vivid-ctrls.c - control support functions. - * - * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - */ - -#include -#include -#include -#include -#include - -#include "vivid-core.h" -#include "vivid-vid-cap.h" -#include "vivid-vid-out.h" -#include "vivid-vid-common.h" -#include "vivid-radio-common.h" -#include "vivid-osd.h" -#include "vivid-ctrls.h" -#include "vivid-cec.h" - -#define VIVID_CID_CUSTOM_BASE (V4L2_CID_USER_BASE | 0xf000) -#define VIVID_CID_BUTTON (VIVID_CID_CUSTOM_BASE + 0) -#define VIVID_CID_BOOLEAN (VIVID_CID_CUSTOM_BASE + 1) -#define VIVID_CID_INTEGER (VIVID_CID_CUSTOM_BASE + 2) -#define VIVID_CID_INTEGER64 (VIVID_CID_CUSTOM_BASE + 3) -#define VIVID_CID_MENU (VIVID_CID_CUSTOM_BASE + 4) -#define VIVID_CID_STRING (VIVID_CID_CUSTOM_BASE + 5) -#define VIVID_CID_BITMASK (VIVID_CID_CUSTOM_BASE + 6) -#define VIVID_CID_INTMENU (VIVID_CID_CUSTOM_BASE + 7) -#define VIVID_CID_U32_ARRAY (VIVID_CID_CUSTOM_BASE + 8) -#define VIVID_CID_U16_MATRIX (VIVID_CID_CUSTOM_BASE + 9) -#define VIVID_CID_U8_4D_ARRAY (VIVID_CID_CUSTOM_BASE + 10) -#define VIVID_CID_AREA (VIVID_CID_CUSTOM_BASE + 11) - -#define VIVID_CID_VIVID_BASE (0x00f00000 | 0xf000) -#define VIVID_CID_VIVID_CLASS (0x00f00000 | 1) -#define VIVID_CID_TEST_PATTERN (VIVID_CID_VIVID_BASE + 0) -#define VIVID_CID_OSD_TEXT_MODE (VIVID_CID_VIVID_BASE + 1) -#define VIVID_CID_HOR_MOVEMENT (VIVID_CID_VIVID_BASE + 2) -#define VIVID_CID_VERT_MOVEMENT (VIVID_CID_VIVID_BASE + 3) -#define VIVID_CID_SHOW_BORDER (VIVID_CID_VIVID_BASE + 4) -#define VIVID_CID_SHOW_SQUARE (VIVID_CID_VIVID_BASE + 5) -#define VIVID_CID_INSERT_SAV (VIVID_CID_VIVID_BASE + 6) -#define VIVID_CID_INSERT_EAV (VIVID_CID_VIVID_BASE + 7) -#define VIVID_CID_VBI_CAP_INTERLACED (VIVID_CID_VIVID_BASE + 8) - -#define VIVID_CID_HFLIP (VIVID_CID_VIVID_BASE + 20) -#define VIVID_CID_VFLIP (VIVID_CID_VIVID_BASE + 21) -#define VIVID_CID_STD_ASPECT_RATIO (VIVID_CID_VIVID_BASE + 22) -#define VIVID_CID_DV_TIMINGS_ASPECT_RATIO (VIVID_CID_VIVID_BASE + 23) -#define VIVID_CID_TSTAMP_SRC (VIVID_CID_VIVID_BASE + 24) -#define VIVID_CID_COLORSPACE (VIVID_CID_VIVID_BASE + 25) -#define VIVID_CID_XFER_FUNC (VIVID_CID_VIVID_BASE + 26) -#define VIVID_CID_YCBCR_ENC (VIVID_CID_VIVID_BASE + 27) -#define VIVID_CID_QUANTIZATION (VIVID_CID_VIVID_BASE + 28) -#define VIVID_CID_LIMITED_RGB_RANGE (VIVID_CID_VIVID_BASE + 29) -#define VIVID_CID_ALPHA_MODE (VIVID_CID_VIVID_BASE + 30) -#define VIVID_CID_HAS_CROP_CAP (VIVID_CID_VIVID_BASE + 31) -#define VIVID_CID_HAS_COMPOSE_CAP (VIVID_CID_VIVID_BASE + 32) -#define VIVID_CID_HAS_SCALER_CAP (VIVID_CID_VIVID_BASE + 33) -#define VIVID_CID_HAS_CROP_OUT (VIVID_CID_VIVID_BASE + 34) -#define VIVID_CID_HAS_COMPOSE_OUT (VIVID_CID_VIVID_BASE + 35) -#define VIVID_CID_HAS_SCALER_OUT (VIVID_CID_VIVID_BASE + 36) -#define VIVID_CID_LOOP_VIDEO (VIVID_CID_VIVID_BASE + 37) -#define VIVID_CID_SEQ_WRAP (VIVID_CID_VIVID_BASE + 38) -#define VIVID_CID_TIME_WRAP (VIVID_CID_VIVID_BASE + 39) -#define VIVID_CID_MAX_EDID_BLOCKS (VIVID_CID_VIVID_BASE + 40) -#define VIVID_CID_PERCENTAGE_FILL (VIVID_CID_VIVID_BASE + 41) -#define VIVID_CID_REDUCED_FPS (VIVID_CID_VIVID_BASE + 42) -#define VIVID_CID_HSV_ENC (VIVID_CID_VIVID_BASE + 43) -#define VIVID_CID_DISPLAY_PRESENT (VIVID_CID_VIVID_BASE + 44) - -#define VIVID_CID_STD_SIGNAL_MODE (VIVID_CID_VIVID_BASE + 60) -#define VIVID_CID_STANDARD (VIVID_CID_VIVID_BASE + 61) -#define VIVID_CID_DV_TIMINGS_SIGNAL_MODE (VIVID_CID_VIVID_BASE + 62) -#define VIVID_CID_DV_TIMINGS (VIVID_CID_VIVID_BASE + 63) -#define VIVID_CID_PERC_DROPPED (VIVID_CID_VIVID_BASE + 64) -#define VIVID_CID_DISCONNECT (VIVID_CID_VIVID_BASE + 65) -#define VIVID_CID_DQBUF_ERROR (VIVID_CID_VIVID_BASE + 66) -#define VIVID_CID_QUEUE_SETUP_ERROR (VIVID_CID_VIVID_BASE + 67) -#define VIVID_CID_BUF_PREPARE_ERROR (VIVID_CID_VIVID_BASE + 68) -#define VIVID_CID_START_STR_ERROR (VIVID_CID_VIVID_BASE + 69) -#define VIVID_CID_QUEUE_ERROR (VIVID_CID_VIVID_BASE + 70) -#define VIVID_CID_CLEAR_FB (VIVID_CID_VIVID_BASE + 71) -#define VIVID_CID_REQ_VALIDATE_ERROR (VIVID_CID_VIVID_BASE + 72) - -#define VIVID_CID_RADIO_SEEK_MODE (VIVID_CID_VIVID_BASE + 90) -#define VIVID_CID_RADIO_SEEK_PROG_LIM (VIVID_CID_VIVID_BASE + 91) -#define VIVID_CID_RADIO_RX_RDS_RBDS (VIVID_CID_VIVID_BASE + 92) -#define VIVID_CID_RADIO_RX_RDS_BLOCKIO (VIVID_CID_VIVID_BASE + 93) - -#define VIVID_CID_RADIO_TX_RDS_BLOCKIO (VIVID_CID_VIVID_BASE + 94) - -#define VIVID_CID_SDR_CAP_FM_DEVIATION (VIVID_CID_VIVID_BASE + 110) - -#define VIVID_CID_META_CAP_GENERATE_PTS (VIVID_CID_VIVID_BASE + 111) -#define VIVID_CID_META_CAP_GENERATE_SCR (VIVID_CID_VIVID_BASE + 112) - -/* General User Controls */ - -static int vivid_user_gen_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_user_gen); - - switch (ctrl->id) { - case VIVID_CID_DISCONNECT: - v4l2_info(&dev->v4l2_dev, "disconnect\n"); - clear_bit(V4L2_FL_REGISTERED, &dev->vid_cap_dev.flags); - clear_bit(V4L2_FL_REGISTERED, &dev->vid_out_dev.flags); - clear_bit(V4L2_FL_REGISTERED, &dev->vbi_cap_dev.flags); - clear_bit(V4L2_FL_REGISTERED, &dev->vbi_out_dev.flags); - clear_bit(V4L2_FL_REGISTERED, &dev->sdr_cap_dev.flags); - clear_bit(V4L2_FL_REGISTERED, &dev->radio_rx_dev.flags); - clear_bit(V4L2_FL_REGISTERED, &dev->radio_tx_dev.flags); - clear_bit(V4L2_FL_REGISTERED, &dev->meta_cap_dev.flags); - break; - case VIVID_CID_BUTTON: - dev->button_pressed = 30; - break; - } - return 0; -} - -static const struct v4l2_ctrl_ops vivid_user_gen_ctrl_ops = { - .s_ctrl = vivid_user_gen_s_ctrl, -}; - -static const struct v4l2_ctrl_config vivid_ctrl_button = { - .ops = &vivid_user_gen_ctrl_ops, - .id = VIVID_CID_BUTTON, - .name = "Button", - .type = V4L2_CTRL_TYPE_BUTTON, -}; - -static const struct v4l2_ctrl_config vivid_ctrl_boolean = { - .ops = &vivid_user_gen_ctrl_ops, - .id = VIVID_CID_BOOLEAN, - .name = "Boolean", - .type = V4L2_CTRL_TYPE_BOOLEAN, - .min = 0, - .max = 1, - .step = 1, - .def = 1, -}; - -static const struct v4l2_ctrl_config vivid_ctrl_int32 = { - .ops = &vivid_user_gen_ctrl_ops, - .id = VIVID_CID_INTEGER, - .name = "Integer 32 Bits", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = 0xffffffff80000000ULL, - .max = 0x7fffffff, - .step = 1, -}; - -static const struct v4l2_ctrl_config vivid_ctrl_int64 = { - .ops = &vivid_user_gen_ctrl_ops, - .id = VIVID_CID_INTEGER64, - .name = "Integer 64 Bits", - .type = V4L2_CTRL_TYPE_INTEGER64, - .min = 0x8000000000000000ULL, - .max = 0x7fffffffffffffffLL, - .step = 1, -}; - -static const struct v4l2_ctrl_config vivid_ctrl_u32_array = { - .ops = &vivid_user_gen_ctrl_ops, - .id = VIVID_CID_U32_ARRAY, - .name = "U32 1 Element Array", - .type = V4L2_CTRL_TYPE_U32, - .def = 0x18, - .min = 0x10, - .max = 0x20000, - .step = 1, - .dims = { 1 }, -}; - -static const struct v4l2_ctrl_config vivid_ctrl_u16_matrix = { - .ops = &vivid_user_gen_ctrl_ops, - .id = VIVID_CID_U16_MATRIX, - .name = "U16 8x16 Matrix", - .type = V4L2_CTRL_TYPE_U16, - .def = 0x18, - .min = 0x10, - .max = 0x2000, - .step = 1, - .dims = { 8, 16 }, -}; - -static const struct v4l2_ctrl_config vivid_ctrl_u8_4d_array = { - .ops = &vivid_user_gen_ctrl_ops, - .id = VIVID_CID_U8_4D_ARRAY, - .name = "U8 2x3x4x5 Array", - .type = V4L2_CTRL_TYPE_U8, - .def = 0x18, - .min = 0x10, - .max = 0x20, - .step = 1, - .dims = { 2, 3, 4, 5 }, -}; - -static const char * const vivid_ctrl_menu_strings[] = { - "Menu Item 0 (Skipped)", - "Menu Item 1", - "Menu Item 2 (Skipped)", - "Menu Item 3", - "Menu Item 4", - "Menu Item 5 (Skipped)", - NULL, -}; - -static const struct v4l2_ctrl_config vivid_ctrl_menu = { - .ops = &vivid_user_gen_ctrl_ops, - .id = VIVID_CID_MENU, - .name = "Menu", - .type = V4L2_CTRL_TYPE_MENU, - .min = 1, - .max = 4, - .def = 3, - .menu_skip_mask = 0x04, - .qmenu = vivid_ctrl_menu_strings, -}; - -static const struct v4l2_ctrl_config vivid_ctrl_string = { - .ops = &vivid_user_gen_ctrl_ops, - .id = VIVID_CID_STRING, - .name = "String", - .type = V4L2_CTRL_TYPE_STRING, - .min = 2, - .max = 4, - .step = 1, -}; - -static const struct v4l2_ctrl_config vivid_ctrl_bitmask = { - .ops = &vivid_user_gen_ctrl_ops, - .id = VIVID_CID_BITMASK, - .name = "Bitmask", - .type = V4L2_CTRL_TYPE_BITMASK, - .def = 0x80002000, - .min = 0, - .max = 0x80402010, - .step = 0, -}; - -static const s64 vivid_ctrl_int_menu_values[] = { - 1, 1, 2, 3, 5, 8, 13, 21, 42, -}; - -static const struct v4l2_ctrl_config vivid_ctrl_int_menu = { - .ops = &vivid_user_gen_ctrl_ops, - .id = VIVID_CID_INTMENU, - .name = "Integer Menu", - .type = V4L2_CTRL_TYPE_INTEGER_MENU, - .min = 1, - .max = 8, - .def = 4, - .menu_skip_mask = 0x02, - .qmenu_int = vivid_ctrl_int_menu_values, -}; - -static const struct v4l2_ctrl_config vivid_ctrl_disconnect = { - .ops = &vivid_user_gen_ctrl_ops, - .id = VIVID_CID_DISCONNECT, - .name = "Disconnect", - .type = V4L2_CTRL_TYPE_BUTTON, -}; - -static const struct v4l2_area area = { - .width = 1000, - .height = 2000, -}; - -static const struct v4l2_ctrl_config vivid_ctrl_area = { - .ops = &vivid_user_gen_ctrl_ops, - .id = VIVID_CID_AREA, - .name = "Area", - .type = V4L2_CTRL_TYPE_AREA, - .p_def.p_const = &area, -}; - -/* Framebuffer Controls */ - -static int vivid_fb_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct vivid_dev *dev = container_of(ctrl->handler, - struct vivid_dev, ctrl_hdl_fb); - - switch (ctrl->id) { - case VIVID_CID_CLEAR_FB: - vivid_clear_fb(dev); - break; - } - return 0; -} - -static const struct v4l2_ctrl_ops vivid_fb_ctrl_ops = { - .s_ctrl = vivid_fb_s_ctrl, -}; - -static const struct v4l2_ctrl_config vivid_ctrl_clear_fb = { - .ops = &vivid_fb_ctrl_ops, - .id = VIVID_CID_CLEAR_FB, - .name = "Clear Framebuffer", - .type = V4L2_CTRL_TYPE_BUTTON, -}; - - -/* Video User Controls */ - -static int vivid_user_vid_g_volatile_ctrl(struct v4l2_ctrl *ctrl) -{ - struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_user_vid); - - switch (ctrl->id) { - case V4L2_CID_AUTOGAIN: - dev->gain->val = (jiffies_to_msecs(jiffies) / 1000) & 0xff; - break; - } - return 0; -} - -static int vivid_user_vid_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_user_vid); - - switch (ctrl->id) { - case V4L2_CID_BRIGHTNESS: - dev->input_brightness[dev->input] = ctrl->val - dev->input * 128; - tpg_s_brightness(&dev->tpg, dev->input_brightness[dev->input]); - break; - case V4L2_CID_CONTRAST: - tpg_s_contrast(&dev->tpg, ctrl->val); - break; - case V4L2_CID_SATURATION: - tpg_s_saturation(&dev->tpg, ctrl->val); - break; - case V4L2_CID_HUE: - tpg_s_hue(&dev->tpg, ctrl->val); - break; - case V4L2_CID_HFLIP: - dev->hflip = ctrl->val; - tpg_s_hflip(&dev->tpg, dev->sensor_hflip ^ dev->hflip); - break; - case V4L2_CID_VFLIP: - dev->vflip = ctrl->val; - tpg_s_vflip(&dev->tpg, dev->sensor_vflip ^ dev->vflip); - break; - case V4L2_CID_ALPHA_COMPONENT: - tpg_s_alpha_component(&dev->tpg, ctrl->val); - break; - } - return 0; -} - -static const struct v4l2_ctrl_ops vivid_user_vid_ctrl_ops = { - .g_volatile_ctrl = vivid_user_vid_g_volatile_ctrl, - .s_ctrl = vivid_user_vid_s_ctrl, -}; - - -/* Video Capture Controls */ - -static int vivid_vid_cap_s_ctrl(struct v4l2_ctrl *ctrl) -{ - static const u32 colorspaces[] = { - V4L2_COLORSPACE_SMPTE170M, - V4L2_COLORSPACE_REC709, - V4L2_COLORSPACE_SRGB, - V4L2_COLORSPACE_OPRGB, - V4L2_COLORSPACE_BT2020, - V4L2_COLORSPACE_DCI_P3, - V4L2_COLORSPACE_SMPTE240M, - V4L2_COLORSPACE_470_SYSTEM_M, - V4L2_COLORSPACE_470_SYSTEM_BG, - }; - struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_vid_cap); - unsigned int i, j; - - switch (ctrl->id) { - case VIVID_CID_TEST_PATTERN: - vivid_update_quality(dev); - tpg_s_pattern(&dev->tpg, ctrl->val); - break; - case VIVID_CID_COLORSPACE: - tpg_s_colorspace(&dev->tpg, colorspaces[ctrl->val]); - vivid_send_source_change(dev, TV); - vivid_send_source_change(dev, SVID); - vivid_send_source_change(dev, HDMI); - vivid_send_source_change(dev, WEBCAM); - break; - case VIVID_CID_XFER_FUNC: - tpg_s_xfer_func(&dev->tpg, ctrl->val); - vivid_send_source_change(dev, TV); - vivid_send_source_change(dev, SVID); - vivid_send_source_change(dev, HDMI); - vivid_send_source_change(dev, WEBCAM); - break; - case VIVID_CID_YCBCR_ENC: - tpg_s_ycbcr_enc(&dev->tpg, ctrl->val); - vivid_send_source_change(dev, TV); - vivid_send_source_change(dev, SVID); - vivid_send_source_change(dev, HDMI); - vivid_send_source_change(dev, WEBCAM); - break; - case VIVID_CID_HSV_ENC: - tpg_s_hsv_enc(&dev->tpg, ctrl->val ? V4L2_HSV_ENC_256 : - V4L2_HSV_ENC_180); - vivid_send_source_change(dev, TV); - vivid_send_source_change(dev, SVID); - vivid_send_source_change(dev, HDMI); - vivid_send_source_change(dev, WEBCAM); - break; - case VIVID_CID_QUANTIZATION: - tpg_s_quantization(&dev->tpg, ctrl->val); - vivid_send_source_change(dev, TV); - vivid_send_source_change(dev, SVID); - vivid_send_source_change(dev, HDMI); - vivid_send_source_change(dev, WEBCAM); - break; - case V4L2_CID_DV_RX_RGB_RANGE: - if (!vivid_is_hdmi_cap(dev)) - break; - tpg_s_rgb_range(&dev->tpg, ctrl->val); - break; - case VIVID_CID_LIMITED_RGB_RANGE: - tpg_s_real_rgb_range(&dev->tpg, ctrl->val ? - V4L2_DV_RGB_RANGE_LIMITED : V4L2_DV_RGB_RANGE_FULL); - break; - case VIVID_CID_ALPHA_MODE: - tpg_s_alpha_mode(&dev->tpg, ctrl->val); - break; - case VIVID_CID_HOR_MOVEMENT: - tpg_s_mv_hor_mode(&dev->tpg, ctrl->val); - break; - case VIVID_CID_VERT_MOVEMENT: - tpg_s_mv_vert_mode(&dev->tpg, ctrl->val); - break; - case VIVID_CID_OSD_TEXT_MODE: - dev->osd_mode = ctrl->val; - break; - case VIVID_CID_PERCENTAGE_FILL: - tpg_s_perc_fill(&dev->tpg, ctrl->val); - for (i = 0; i < VIDEO_MAX_FRAME; i++) - dev->must_blank[i] = ctrl->val < 100; - break; - case VIVID_CID_INSERT_SAV: - tpg_s_insert_sav(&dev->tpg, ctrl->val); - break; - case VIVID_CID_INSERT_EAV: - tpg_s_insert_eav(&dev->tpg, ctrl->val); - break; - case VIVID_CID_HFLIP: - dev->sensor_hflip = ctrl->val; - tpg_s_hflip(&dev->tpg, dev->sensor_hflip ^ dev->hflip); - break; - case VIVID_CID_VFLIP: - dev->sensor_vflip = ctrl->val; - tpg_s_vflip(&dev->tpg, dev->sensor_vflip ^ dev->vflip); - break; - case VIVID_CID_REDUCED_FPS: - dev->reduced_fps = ctrl->val; - vivid_update_format_cap(dev, true); - break; - case VIVID_CID_HAS_CROP_CAP: - dev->has_crop_cap = ctrl->val; - vivid_update_format_cap(dev, true); - break; - case VIVID_CID_HAS_COMPOSE_CAP: - dev->has_compose_cap = ctrl->val; - vivid_update_format_cap(dev, true); - break; - case VIVID_CID_HAS_SCALER_CAP: - dev->has_scaler_cap = ctrl->val; - vivid_update_format_cap(dev, true); - break; - case VIVID_CID_SHOW_BORDER: - tpg_s_show_border(&dev->tpg, ctrl->val); - break; - case VIVID_CID_SHOW_SQUARE: - tpg_s_show_square(&dev->tpg, ctrl->val); - break; - case VIVID_CID_STD_ASPECT_RATIO: - dev->std_aspect_ratio[dev->input] = ctrl->val; - tpg_s_video_aspect(&dev->tpg, vivid_get_video_aspect(dev)); - break; - case VIVID_CID_DV_TIMINGS_SIGNAL_MODE: - dev->dv_timings_signal_mode[dev->input] = - dev->ctrl_dv_timings_signal_mode->val; - dev->query_dv_timings[dev->input] = dev->ctrl_dv_timings->val; - - dev->power_present = 0; - for (i = 0, j = 0; - i < ARRAY_SIZE(dev->dv_timings_signal_mode); - i++) - if (dev->input_type[i] == HDMI) { - if (dev->dv_timings_signal_mode[i] != NO_SIGNAL) - dev->power_present |= (1 << j); - j++; - } - __v4l2_ctrl_s_ctrl(dev->ctrl_rx_power_present, - dev->power_present); - - v4l2_ctrl_activate(dev->ctrl_dv_timings, - dev->dv_timings_signal_mode[dev->input] == - SELECTED_DV_TIMINGS); - - vivid_update_quality(dev); - vivid_send_source_change(dev, HDMI); - break; - case VIVID_CID_DV_TIMINGS_ASPECT_RATIO: - dev->dv_timings_aspect_ratio[dev->input] = ctrl->val; - tpg_s_video_aspect(&dev->tpg, vivid_get_video_aspect(dev)); - break; - case VIVID_CID_TSTAMP_SRC: - dev->tstamp_src_is_soe = ctrl->val; - dev->vb_vid_cap_q.timestamp_flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK; - if (dev->tstamp_src_is_soe) - dev->vb_vid_cap_q.timestamp_flags |= V4L2_BUF_FLAG_TSTAMP_SRC_SOE; - break; - case VIVID_CID_MAX_EDID_BLOCKS: - dev->edid_max_blocks = ctrl->val; - if (dev->edid_blocks > dev->edid_max_blocks) - dev->edid_blocks = dev->edid_max_blocks; - break; - } - return 0; -} - -static const struct v4l2_ctrl_ops vivid_vid_cap_ctrl_ops = { - .s_ctrl = vivid_vid_cap_s_ctrl, -}; - -static const char * const vivid_ctrl_hor_movement_strings[] = { - "Move Left Fast", - "Move Left", - "Move Left Slow", - "No Movement", - "Move Right Slow", - "Move Right", - "Move Right Fast", - NULL, -}; - -static const struct v4l2_ctrl_config vivid_ctrl_hor_movement = { - .ops = &vivid_vid_cap_ctrl_ops, - .id = VIVID_CID_HOR_MOVEMENT, - .name = "Horizontal Movement", - .type = V4L2_CTRL_TYPE_MENU, - .max = TPG_MOVE_POS_FAST, - .def = TPG_MOVE_NONE, - .qmenu = vivid_ctrl_hor_movement_strings, -}; - -static const char * const vivid_ctrl_vert_movement_strings[] = { - "Move Up Fast", - "Move Up", - "Move Up Slow", - "No Movement", - "Move Down Slow", - "Move Down", - "Move Down Fast", - NULL, -}; - -static const struct v4l2_ctrl_config vivid_ctrl_vert_movement = { - .ops = &vivid_vid_cap_ctrl_ops, - .id = VIVID_CID_VERT_MOVEMENT, - .name = "Vertical Movement", - .type = V4L2_CTRL_TYPE_MENU, - .max = TPG_MOVE_POS_FAST, - .def = TPG_MOVE_NONE, - .qmenu = vivid_ctrl_vert_movement_strings, -}; - -static const struct v4l2_ctrl_config vivid_ctrl_show_border = { - .ops = &vivid_vid_cap_ctrl_ops, - .id = VIVID_CID_SHOW_BORDER, - .name = "Show Border", - .type = V4L2_CTRL_TYPE_BOOLEAN, - .max = 1, - .step = 1, -}; - -static const struct v4l2_ctrl_config vivid_ctrl_show_square = { - .ops = &vivid_vid_cap_ctrl_ops, - .id = VIVID_CID_SHOW_SQUARE, - .name = "Show Square", - .type = V4L2_CTRL_TYPE_BOOLEAN, - .max = 1, - .step = 1, -}; - -static const char * const vivid_ctrl_osd_mode_strings[] = { - "All", - "Counters Only", - "None", - NULL, -}; - -static const struct v4l2_ctrl_config vivid_ctrl_osd_mode = { - .ops = &vivid_vid_cap_ctrl_ops, - .id = VIVID_CID_OSD_TEXT_MODE, - .name = "OSD Text Mode", - .type = V4L2_CTRL_TYPE_MENU, - .max = ARRAY_SIZE(vivid_ctrl_osd_mode_strings) - 2, - .qmenu = vivid_ctrl_osd_mode_strings, -}; - -static const struct v4l2_ctrl_config vivid_ctrl_perc_fill = { - .ops = &vivid_vid_cap_ctrl_ops, - .id = VIVID_CID_PERCENTAGE_FILL, - .name = "Fill Percentage of Frame", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = 0, - .max = 100, - .def = 100, - .step = 1, -}; - -static const struct v4l2_ctrl_config vivid_ctrl_insert_sav = { - .ops = &vivid_vid_cap_ctrl_ops, - .id = VIVID_CID_INSERT_SAV, - .name = "Insert SAV Code in Image", - .type = V4L2_CTRL_TYPE_BOOLEAN, - .max = 1, - .step = 1, -}; - -static const struct v4l2_ctrl_config vivid_ctrl_insert_eav = { - .ops = &vivid_vid_cap_ctrl_ops, - .id = VIVID_CID_INSERT_EAV, - .name = "Insert EAV Code in Image", - .type = V4L2_CTRL_TYPE_BOOLEAN, - .max = 1, - .step = 1, -}; - -static const struct v4l2_ctrl_config vivid_ctrl_hflip = { - .ops = &vivid_vid_cap_ctrl_ops, - .id = VIVID_CID_HFLIP, - .name = "Sensor Flipped Horizontally", - .type = V4L2_CTRL_TYPE_BOOLEAN, - .max = 1, - .step = 1, -}; - -static const struct v4l2_ctrl_config vivid_ctrl_vflip = { - .ops = &vivid_vid_cap_ctrl_ops, - .id = VIVID_CID_VFLIP, - .name = "Sensor Flipped Vertically", - .type = V4L2_CTRL_TYPE_BOOLEAN, - .max = 1, - .step = 1, -}; - -static const struct v4l2_ctrl_config vivid_ctrl_reduced_fps = { - .ops = &vivid_vid_cap_ctrl_ops, - .id = VIVID_CID_REDUCED_FPS, - .name = "Reduced Framerate", - .type = V4L2_CTRL_TYPE_BOOLEAN, - .max = 1, - .step = 1, -}; - -static const struct v4l2_ctrl_config vivid_ctrl_has_crop_cap = { - .ops = &vivid_vid_cap_ctrl_ops, - .id = VIVID_CID_HAS_CROP_CAP, - .name = "Enable Capture Cropping", - .type = V4L2_CTRL_TYPE_BOOLEAN, - .max = 1, - .def = 1, - .step = 1, -}; - -static const struct v4l2_ctrl_config vivid_ctrl_has_compose_cap = { - .ops = &vivid_vid_cap_ctrl_ops, - .id = VIVID_CID_HAS_COMPOSE_CAP, - .name = "Enable Capture Composing", - .type = V4L2_CTRL_TYPE_BOOLEAN, - .max = 1, - .def = 1, - .step = 1, -}; - -static const struct v4l2_ctrl_config vivid_ctrl_has_scaler_cap = { - .ops = &vivid_vid_cap_ctrl_ops, - .id = VIVID_CID_HAS_SCALER_CAP, - .name = "Enable Capture Scaler", - .type = V4L2_CTRL_TYPE_BOOLEAN, - .max = 1, - .def = 1, - .step = 1, -}; - -static const char * const vivid_ctrl_tstamp_src_strings[] = { - "End of Frame", - "Start of Exposure", - NULL, -}; - -static const struct v4l2_ctrl_config vivid_ctrl_tstamp_src = { - .ops = &vivid_vid_cap_ctrl_ops, - .id = VIVID_CID_TSTAMP_SRC, - .name = "Timestamp Source", - .type = V4L2_CTRL_TYPE_MENU, - .max = ARRAY_SIZE(vivid_ctrl_tstamp_src_strings) - 2, - .qmenu = vivid_ctrl_tstamp_src_strings, -}; - -static const struct v4l2_ctrl_config vivid_ctrl_std_aspect_ratio = { - .ops = &vivid_vid_cap_ctrl_ops, - .id = VIVID_CID_STD_ASPECT_RATIO, - .name = "Standard Aspect Ratio", - .type = V4L2_CTRL_TYPE_MENU, - .min = 1, - .max = 4, - .def = 1, - .qmenu = tpg_aspect_strings, -}; - -static const char * const vivid_ctrl_dv_timings_signal_mode_strings[] = { - "Current DV Timings", - "No Signal", - "No Lock", - "Out of Range", - "Selected DV Timings", - "Cycle Through All DV Timings", - "Custom DV Timings", - NULL, -}; - -static const struct v4l2_ctrl_config vivid_ctrl_dv_timings_signal_mode = { - .ops = &vivid_vid_cap_ctrl_ops, - .id = VIVID_CID_DV_TIMINGS_SIGNAL_MODE, - .name = "DV Timings Signal Mode", - .type = V4L2_CTRL_TYPE_MENU, - .max = 5, - .qmenu = vivid_ctrl_dv_timings_signal_mode_strings, -}; - -static const struct v4l2_ctrl_config vivid_ctrl_dv_timings_aspect_ratio = { - .ops = &vivid_vid_cap_ctrl_ops, - .id = VIVID_CID_DV_TIMINGS_ASPECT_RATIO, - .name = "DV Timings Aspect Ratio", - .type = V4L2_CTRL_TYPE_MENU, - .max = 3, - .qmenu = tpg_aspect_strings, -}; - -static const struct v4l2_ctrl_config vivid_ctrl_max_edid_blocks = { - .ops = &vivid_vid_cap_ctrl_ops, - .id = VIVID_CID_MAX_EDID_BLOCKS, - .name = "Maximum EDID Blocks", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = 1, - .max = 256, - .def = 2, - .step = 1, -}; - -static const char * const vivid_ctrl_colorspace_strings[] = { - "SMPTE 170M", - "Rec. 709", - "sRGB", - "opRGB", - "BT.2020", - "DCI-P3", - "SMPTE 240M", - "470 System M", - "470 System BG", - NULL, -}; - -static const struct v4l2_ctrl_config vivid_ctrl_colorspace = { - .ops = &vivid_vid_cap_ctrl_ops, - .id = VIVID_CID_COLORSPACE, - .name = "Colorspace", - .type = V4L2_CTRL_TYPE_MENU, - .max = ARRAY_SIZE(vivid_ctrl_colorspace_strings) - 2, - .def = 2, - .qmenu = vivid_ctrl_colorspace_strings, -}; - -static const char * const vivid_ctrl_xfer_func_strings[] = { - "Default", - "Rec. 709", - "sRGB", - "opRGB", - "SMPTE 240M", - "None", - "DCI-P3", - "SMPTE 2084", - NULL, -}; - -static const struct v4l2_ctrl_config vivid_ctrl_xfer_func = { - .ops = &vivid_vid_cap_ctrl_ops, - .id = VIVID_CID_XFER_FUNC, - .name = "Transfer Function", - .type = V4L2_CTRL_TYPE_MENU, - .max = ARRAY_SIZE(vivid_ctrl_xfer_func_strings) - 2, - .qmenu = vivid_ctrl_xfer_func_strings, -}; - -static const char * const vivid_ctrl_ycbcr_enc_strings[] = { - "Default", - "ITU-R 601", - "Rec. 709", - "xvYCC 601", - "xvYCC 709", - "", - "BT.2020", - "BT.2020 Constant Luminance", - "SMPTE 240M", - NULL, -}; - -static const struct v4l2_ctrl_config vivid_ctrl_ycbcr_enc = { - .ops = &vivid_vid_cap_ctrl_ops, - .id = VIVID_CID_YCBCR_ENC, - .name = "Y'CbCr Encoding", - .type = V4L2_CTRL_TYPE_MENU, - .menu_skip_mask = 1 << 5, - .max = ARRAY_SIZE(vivid_ctrl_ycbcr_enc_strings) - 2, - .qmenu = vivid_ctrl_ycbcr_enc_strings, -}; - -static const char * const vivid_ctrl_hsv_enc_strings[] = { - "Hue 0-179", - "Hue 0-256", - NULL, -}; - -static const struct v4l2_ctrl_config vivid_ctrl_hsv_enc = { - .ops = &vivid_vid_cap_ctrl_ops, - .id = VIVID_CID_HSV_ENC, - .name = "HSV Encoding", - .type = V4L2_CTRL_TYPE_MENU, - .max = ARRAY_SIZE(vivid_ctrl_hsv_enc_strings) - 2, - .qmenu = vivid_ctrl_hsv_enc_strings, -}; - -static const char * const vivid_ctrl_quantization_strings[] = { - "Default", - "Full Range", - "Limited Range", - NULL, -}; - -static const struct v4l2_ctrl_config vivid_ctrl_quantization = { - .ops = &vivid_vid_cap_ctrl_ops, - .id = VIVID_CID_QUANTIZATION, - .name = "Quantization", - .type = V4L2_CTRL_TYPE_MENU, - .max = ARRAY_SIZE(vivid_ctrl_quantization_strings) - 2, - .qmenu = vivid_ctrl_quantization_strings, -}; - -static const struct v4l2_ctrl_config vivid_ctrl_alpha_mode = { - .ops = &vivid_vid_cap_ctrl_ops, - .id = VIVID_CID_ALPHA_MODE, - .name = "Apply Alpha To Red Only", - .type = V4L2_CTRL_TYPE_BOOLEAN, - .max = 1, - .step = 1, -}; - -static const struct v4l2_ctrl_config vivid_ctrl_limited_rgb_range = { - .ops = &vivid_vid_cap_ctrl_ops, - .id = VIVID_CID_LIMITED_RGB_RANGE, - .name = "Limited RGB Range (16-235)", - .type = V4L2_CTRL_TYPE_BOOLEAN, - .max = 1, - .step = 1, -}; - - -/* Video Loop Control */ - -static int vivid_loop_cap_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_loop_cap); - - switch (ctrl->id) { - case VIVID_CID_LOOP_VIDEO: - dev->loop_video = ctrl->val; - vivid_update_quality(dev); - vivid_send_source_change(dev, SVID); - vivid_send_source_change(dev, HDMI); - break; - } - return 0; -} - -static const struct v4l2_ctrl_ops vivid_loop_cap_ctrl_ops = { - .s_ctrl = vivid_loop_cap_s_ctrl, -}; - -static const struct v4l2_ctrl_config vivid_ctrl_loop_video = { - .ops = &vivid_loop_cap_ctrl_ops, - .id = VIVID_CID_LOOP_VIDEO, - .name = "Loop Video", - .type = V4L2_CTRL_TYPE_BOOLEAN, - .max = 1, - .step = 1, -}; - - -/* VBI Capture Control */ - -static int vivid_vbi_cap_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_vbi_cap); - - switch (ctrl->id) { - case VIVID_CID_VBI_CAP_INTERLACED: - dev->vbi_cap_interlaced = ctrl->val; - break; - } - return 0; -} - -static const struct v4l2_ctrl_ops vivid_vbi_cap_ctrl_ops = { - .s_ctrl = vivid_vbi_cap_s_ctrl, -}; - -static const struct v4l2_ctrl_config vivid_ctrl_vbi_cap_interlaced = { - .ops = &vivid_vbi_cap_ctrl_ops, - .id = VIVID_CID_VBI_CAP_INTERLACED, - .name = "Interlaced VBI Format", - .type = V4L2_CTRL_TYPE_BOOLEAN, - .max = 1, - .step = 1, -}; - - -/* Video Output Controls */ - -static int vivid_vid_out_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_vid_out); - struct v4l2_bt_timings *bt = &dev->dv_timings_out.bt; - u32 display_present = 0; - unsigned int i, j, bus_idx; - - switch (ctrl->id) { - case VIVID_CID_HAS_CROP_OUT: - dev->has_crop_out = ctrl->val; - vivid_update_format_out(dev); - break; - case VIVID_CID_HAS_COMPOSE_OUT: - dev->has_compose_out = ctrl->val; - vivid_update_format_out(dev); - break; - case VIVID_CID_HAS_SCALER_OUT: - dev->has_scaler_out = ctrl->val; - vivid_update_format_out(dev); - break; - case V4L2_CID_DV_TX_MODE: - dev->dvi_d_out = ctrl->val == V4L2_DV_TX_MODE_DVI_D; - if (!vivid_is_hdmi_out(dev)) - break; - if (!dev->dvi_d_out && (bt->flags & V4L2_DV_FL_IS_CE_VIDEO)) { - if (bt->width == 720 && bt->height <= 576) - dev->colorspace_out = V4L2_COLORSPACE_SMPTE170M; - else - dev->colorspace_out = V4L2_COLORSPACE_REC709; - dev->quantization_out = V4L2_QUANTIZATION_DEFAULT; - } else { - dev->colorspace_out = V4L2_COLORSPACE_SRGB; - dev->quantization_out = dev->dvi_d_out ? - V4L2_QUANTIZATION_LIM_RANGE : - V4L2_QUANTIZATION_DEFAULT; - } - if (dev->loop_video) - vivid_send_source_change(dev, HDMI); - break; - case VIVID_CID_DISPLAY_PRESENT: - if (dev->output_type[dev->output] != HDMI) - break; - - dev->display_present[dev->output] = ctrl->val; - for (i = 0, j = 0; i < dev->num_outputs; i++) - if (dev->output_type[i] == HDMI) - display_present |= - dev->display_present[i] << j++; - - __v4l2_ctrl_s_ctrl(dev->ctrl_tx_rxsense, display_present); - - if (dev->edid_blocks) { - __v4l2_ctrl_s_ctrl(dev->ctrl_tx_edid_present, - display_present); - __v4l2_ctrl_s_ctrl(dev->ctrl_tx_hotplug, - display_present); - } - - bus_idx = dev->cec_output2bus_map[dev->output]; - if (!dev->cec_tx_adap[bus_idx]) - break; - - if (ctrl->val && dev->edid_blocks) - cec_s_phys_addr(dev->cec_tx_adap[bus_idx], - dev->cec_tx_adap[bus_idx]->phys_addr, - false); - else - cec_phys_addr_invalidate(dev->cec_tx_adap[bus_idx]); - - break; - } - return 0; -} - -static const struct v4l2_ctrl_ops vivid_vid_out_ctrl_ops = { - .s_ctrl = vivid_vid_out_s_ctrl, -}; - -static const struct v4l2_ctrl_config vivid_ctrl_has_crop_out = { - .ops = &vivid_vid_out_ctrl_ops, - .id = VIVID_CID_HAS_CROP_OUT, - .name = "Enable Output Cropping", - .type = V4L2_CTRL_TYPE_BOOLEAN, - .max = 1, - .def = 1, - .step = 1, -}; - -static const struct v4l2_ctrl_config vivid_ctrl_has_compose_out = { - .ops = &vivid_vid_out_ctrl_ops, - .id = VIVID_CID_HAS_COMPOSE_OUT, - .name = "Enable Output Composing", - .type = V4L2_CTRL_TYPE_BOOLEAN, - .max = 1, - .def = 1, - .step = 1, -}; - -static const struct v4l2_ctrl_config vivid_ctrl_has_scaler_out = { - .ops = &vivid_vid_out_ctrl_ops, - .id = VIVID_CID_HAS_SCALER_OUT, - .name = "Enable Output Scaler", - .type = V4L2_CTRL_TYPE_BOOLEAN, - .max = 1, - .def = 1, - .step = 1, -}; - -static const struct v4l2_ctrl_config vivid_ctrl_display_present = { - .ops = &vivid_vid_out_ctrl_ops, - .id = VIVID_CID_DISPLAY_PRESENT, - .name = "Display Present", - .type = V4L2_CTRL_TYPE_BOOLEAN, - .max = 1, - .def = 1, - .step = 1, -}; - -/* Streaming Controls */ - -static int vivid_streaming_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_streaming); - u64 rem; - - switch (ctrl->id) { - case VIVID_CID_DQBUF_ERROR: - dev->dqbuf_error = true; - break; - case VIVID_CID_PERC_DROPPED: - dev->perc_dropped_buffers = ctrl->val; - break; - case VIVID_CID_QUEUE_SETUP_ERROR: - dev->queue_setup_error = true; - break; - case VIVID_CID_BUF_PREPARE_ERROR: - dev->buf_prepare_error = true; - break; - case VIVID_CID_START_STR_ERROR: - dev->start_streaming_error = true; - break; - case VIVID_CID_REQ_VALIDATE_ERROR: - dev->req_validate_error = true; - break; - case VIVID_CID_QUEUE_ERROR: - if (vb2_start_streaming_called(&dev->vb_vid_cap_q)) - vb2_queue_error(&dev->vb_vid_cap_q); - if (vb2_start_streaming_called(&dev->vb_vbi_cap_q)) - vb2_queue_error(&dev->vb_vbi_cap_q); - if (vb2_start_streaming_called(&dev->vb_vid_out_q)) - vb2_queue_error(&dev->vb_vid_out_q); - if (vb2_start_streaming_called(&dev->vb_vbi_out_q)) - vb2_queue_error(&dev->vb_vbi_out_q); - if (vb2_start_streaming_called(&dev->vb_sdr_cap_q)) - vb2_queue_error(&dev->vb_sdr_cap_q); - break; - case VIVID_CID_SEQ_WRAP: - dev->seq_wrap = ctrl->val; - break; - case VIVID_CID_TIME_WRAP: - dev->time_wrap = ctrl->val; - if (ctrl->val == 0) { - dev->time_wrap_offset = 0; - break; - } - /* - * We want to set the time 16 seconds before the 32 bit tv_sec - * value of struct timeval would wrap around. So first we - * calculate ktime_get_ns() % ((1 << 32) * NSEC_PER_SEC), and - * then we set the offset to ((1 << 32) - 16) * NSEC_PER_SEC). - */ - div64_u64_rem(ktime_get_ns(), - 0x100000000ULL * NSEC_PER_SEC, &rem); - dev->time_wrap_offset = - (0x100000000ULL - 16) * NSEC_PER_SEC - rem; - break; - } - return 0; -} - -static const struct v4l2_ctrl_ops vivid_streaming_ctrl_ops = { - .s_ctrl = vivid_streaming_s_ctrl, -}; - -static const struct v4l2_ctrl_config vivid_ctrl_dqbuf_error = { - .ops = &vivid_streaming_ctrl_ops, - .id = VIVID_CID_DQBUF_ERROR, - .name = "Inject V4L2_BUF_FLAG_ERROR", - .type = V4L2_CTRL_TYPE_BUTTON, -}; - -static const struct v4l2_ctrl_config vivid_ctrl_perc_dropped = { - .ops = &vivid_streaming_ctrl_ops, - .id = VIVID_CID_PERC_DROPPED, - .name = "Percentage of Dropped Buffers", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = 0, - .max = 100, - .step = 1, -}; - -static const struct v4l2_ctrl_config vivid_ctrl_queue_setup_error = { - .ops = &vivid_streaming_ctrl_ops, - .id = VIVID_CID_QUEUE_SETUP_ERROR, - .name = "Inject VIDIOC_REQBUFS Error", - .type = V4L2_CTRL_TYPE_BUTTON, -}; - -static const struct v4l2_ctrl_config vivid_ctrl_buf_prepare_error = { - .ops = &vivid_streaming_ctrl_ops, - .id = VIVID_CID_BUF_PREPARE_ERROR, - .name = "Inject VIDIOC_QBUF Error", - .type = V4L2_CTRL_TYPE_BUTTON, -}; - -static const struct v4l2_ctrl_config vivid_ctrl_start_streaming_error = { - .ops = &vivid_streaming_ctrl_ops, - .id = VIVID_CID_START_STR_ERROR, - .name = "Inject VIDIOC_STREAMON Error", - .type = V4L2_CTRL_TYPE_BUTTON, -}; - -static const struct v4l2_ctrl_config vivid_ctrl_queue_error = { - .ops = &vivid_streaming_ctrl_ops, - .id = VIVID_CID_QUEUE_ERROR, - .name = "Inject Fatal Streaming Error", - .type = V4L2_CTRL_TYPE_BUTTON, -}; - -#ifdef CONFIG_MEDIA_CONTROLLER -static const struct v4l2_ctrl_config vivid_ctrl_req_validate_error = { - .ops = &vivid_streaming_ctrl_ops, - .id = VIVID_CID_REQ_VALIDATE_ERROR, - .name = "Inject req_validate() Error", - .type = V4L2_CTRL_TYPE_BUTTON, -}; -#endif - -static const struct v4l2_ctrl_config vivid_ctrl_seq_wrap = { - .ops = &vivid_streaming_ctrl_ops, - .id = VIVID_CID_SEQ_WRAP, - .name = "Wrap Sequence Number", - .type = V4L2_CTRL_TYPE_BOOLEAN, - .max = 1, - .step = 1, -}; - -static const struct v4l2_ctrl_config vivid_ctrl_time_wrap = { - .ops = &vivid_streaming_ctrl_ops, - .id = VIVID_CID_TIME_WRAP, - .name = "Wrap Timestamp", - .type = V4L2_CTRL_TYPE_BOOLEAN, - .max = 1, - .step = 1, -}; - - -/* SDTV Capture Controls */ - -static int vivid_sdtv_cap_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_sdtv_cap); - - switch (ctrl->id) { - case VIVID_CID_STD_SIGNAL_MODE: - dev->std_signal_mode[dev->input] = - dev->ctrl_std_signal_mode->val; - if (dev->std_signal_mode[dev->input] == SELECTED_STD) - dev->query_std[dev->input] = - vivid_standard[dev->ctrl_standard->val]; - v4l2_ctrl_activate(dev->ctrl_standard, - dev->std_signal_mode[dev->input] == - SELECTED_STD); - vivid_update_quality(dev); - vivid_send_source_change(dev, TV); - vivid_send_source_change(dev, SVID); - break; - } - return 0; -} - -static const struct v4l2_ctrl_ops vivid_sdtv_cap_ctrl_ops = { - .s_ctrl = vivid_sdtv_cap_s_ctrl, -}; - -static const char * const vivid_ctrl_std_signal_mode_strings[] = { - "Current Standard", - "No Signal", - "No Lock", - "", - "Selected Standard", - "Cycle Through All Standards", - NULL, -}; - -static const struct v4l2_ctrl_config vivid_ctrl_std_signal_mode = { - .ops = &vivid_sdtv_cap_ctrl_ops, - .id = VIVID_CID_STD_SIGNAL_MODE, - .name = "Standard Signal Mode", - .type = V4L2_CTRL_TYPE_MENU, - .max = ARRAY_SIZE(vivid_ctrl_std_signal_mode_strings) - 2, - .menu_skip_mask = 1 << 3, - .qmenu = vivid_ctrl_std_signal_mode_strings, -}; - -static const struct v4l2_ctrl_config vivid_ctrl_standard = { - .ops = &vivid_sdtv_cap_ctrl_ops, - .id = VIVID_CID_STANDARD, - .name = "Standard", - .type = V4L2_CTRL_TYPE_MENU, - .max = 14, - .qmenu = vivid_ctrl_standard_strings, -}; - - - -/* Radio Receiver Controls */ - -static int vivid_radio_rx_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_radio_rx); - - switch (ctrl->id) { - case VIVID_CID_RADIO_SEEK_MODE: - dev->radio_rx_hw_seek_mode = ctrl->val; - break; - case VIVID_CID_RADIO_SEEK_PROG_LIM: - dev->radio_rx_hw_seek_prog_lim = ctrl->val; - break; - case VIVID_CID_RADIO_RX_RDS_RBDS: - dev->rds_gen.use_rbds = ctrl->val; - break; - case VIVID_CID_RADIO_RX_RDS_BLOCKIO: - dev->radio_rx_rds_controls = ctrl->val; - dev->radio_rx_caps &= ~V4L2_CAP_READWRITE; - dev->radio_rx_rds_use_alternates = false; - if (!dev->radio_rx_rds_controls) { - dev->radio_rx_caps |= V4L2_CAP_READWRITE; - __v4l2_ctrl_s_ctrl(dev->radio_rx_rds_pty, 0); - __v4l2_ctrl_s_ctrl(dev->radio_rx_rds_ta, 0); - __v4l2_ctrl_s_ctrl(dev->radio_rx_rds_tp, 0); - __v4l2_ctrl_s_ctrl(dev->radio_rx_rds_ms, 0); - __v4l2_ctrl_s_ctrl_string(dev->radio_rx_rds_psname, ""); - __v4l2_ctrl_s_ctrl_string(dev->radio_rx_rds_radiotext, ""); - } - v4l2_ctrl_activate(dev->radio_rx_rds_pty, dev->radio_rx_rds_controls); - v4l2_ctrl_activate(dev->radio_rx_rds_psname, dev->radio_rx_rds_controls); - v4l2_ctrl_activate(dev->radio_rx_rds_radiotext, dev->radio_rx_rds_controls); - v4l2_ctrl_activate(dev->radio_rx_rds_ta, dev->radio_rx_rds_controls); - v4l2_ctrl_activate(dev->radio_rx_rds_tp, dev->radio_rx_rds_controls); - v4l2_ctrl_activate(dev->radio_rx_rds_ms, dev->radio_rx_rds_controls); - dev->radio_rx_dev.device_caps = dev->radio_rx_caps; - break; - case V4L2_CID_RDS_RECEPTION: - dev->radio_rx_rds_enabled = ctrl->val; - break; - } - return 0; -} - -static const struct v4l2_ctrl_ops vivid_radio_rx_ctrl_ops = { - .s_ctrl = vivid_radio_rx_s_ctrl, -}; - -static const char * const vivid_ctrl_radio_rds_mode_strings[] = { - "Block I/O", - "Controls", - NULL, -}; - -static const struct v4l2_ctrl_config vivid_ctrl_radio_rx_rds_blockio = { - .ops = &vivid_radio_rx_ctrl_ops, - .id = VIVID_CID_RADIO_RX_RDS_BLOCKIO, - .name = "RDS Rx I/O Mode", - .type = V4L2_CTRL_TYPE_MENU, - .qmenu = vivid_ctrl_radio_rds_mode_strings, - .max = 1, -}; - -static const struct v4l2_ctrl_config vivid_ctrl_radio_rx_rds_rbds = { - .ops = &vivid_radio_rx_ctrl_ops, - .id = VIVID_CID_RADIO_RX_RDS_RBDS, - .name = "Generate RBDS Instead of RDS", - .type = V4L2_CTRL_TYPE_BOOLEAN, - .max = 1, - .step = 1, -}; - -static const char * const vivid_ctrl_radio_hw_seek_mode_strings[] = { - "Bounded", - "Wrap Around", - "Both", - NULL, -}; - -static const struct v4l2_ctrl_config vivid_ctrl_radio_hw_seek_mode = { - .ops = &vivid_radio_rx_ctrl_ops, - .id = VIVID_CID_RADIO_SEEK_MODE, - .name = "Radio HW Seek Mode", - .type = V4L2_CTRL_TYPE_MENU, - .max = 2, - .qmenu = vivid_ctrl_radio_hw_seek_mode_strings, -}; - -static const struct v4l2_ctrl_config vivid_ctrl_radio_hw_seek_prog_lim = { - .ops = &vivid_radio_rx_ctrl_ops, - .id = VIVID_CID_RADIO_SEEK_PROG_LIM, - .name = "Radio Programmable HW Seek", - .type = V4L2_CTRL_TYPE_BOOLEAN, - .max = 1, - .step = 1, -}; - - -/* Radio Transmitter Controls */ - -static int vivid_radio_tx_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_radio_tx); - - switch (ctrl->id) { - case VIVID_CID_RADIO_TX_RDS_BLOCKIO: - dev->radio_tx_rds_controls = ctrl->val; - dev->radio_tx_caps &= ~V4L2_CAP_READWRITE; - if (!dev->radio_tx_rds_controls) - dev->radio_tx_caps |= V4L2_CAP_READWRITE; - dev->radio_tx_dev.device_caps = dev->radio_tx_caps; - break; - case V4L2_CID_RDS_TX_PTY: - if (dev->radio_rx_rds_controls) - v4l2_ctrl_s_ctrl(dev->radio_rx_rds_pty, ctrl->val); - break; - case V4L2_CID_RDS_TX_PS_NAME: - if (dev->radio_rx_rds_controls) - v4l2_ctrl_s_ctrl_string(dev->radio_rx_rds_psname, ctrl->p_new.p_char); - break; - case V4L2_CID_RDS_TX_RADIO_TEXT: - if (dev->radio_rx_rds_controls) - v4l2_ctrl_s_ctrl_string(dev->radio_rx_rds_radiotext, ctrl->p_new.p_char); - break; - case V4L2_CID_RDS_TX_TRAFFIC_ANNOUNCEMENT: - if (dev->radio_rx_rds_controls) - v4l2_ctrl_s_ctrl(dev->radio_rx_rds_ta, ctrl->val); - break; - case V4L2_CID_RDS_TX_TRAFFIC_PROGRAM: - if (dev->radio_rx_rds_controls) - v4l2_ctrl_s_ctrl(dev->radio_rx_rds_tp, ctrl->val); - break; - case V4L2_CID_RDS_TX_MUSIC_SPEECH: - if (dev->radio_rx_rds_controls) - v4l2_ctrl_s_ctrl(dev->radio_rx_rds_ms, ctrl->val); - break; - } - return 0; -} - -static const struct v4l2_ctrl_ops vivid_radio_tx_ctrl_ops = { - .s_ctrl = vivid_radio_tx_s_ctrl, -}; - -static const struct v4l2_ctrl_config vivid_ctrl_radio_tx_rds_blockio = { - .ops = &vivid_radio_tx_ctrl_ops, - .id = VIVID_CID_RADIO_TX_RDS_BLOCKIO, - .name = "RDS Tx I/O Mode", - .type = V4L2_CTRL_TYPE_MENU, - .qmenu = vivid_ctrl_radio_rds_mode_strings, - .max = 1, - .def = 1, -}; - - -/* SDR Capture Controls */ - -static int vivid_sdr_cap_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_sdr_cap); - - switch (ctrl->id) { - case VIVID_CID_SDR_CAP_FM_DEVIATION: - dev->sdr_fm_deviation = ctrl->val; - break; - } - return 0; -} - -static const struct v4l2_ctrl_ops vivid_sdr_cap_ctrl_ops = { - .s_ctrl = vivid_sdr_cap_s_ctrl, -}; - -static const struct v4l2_ctrl_config vivid_ctrl_sdr_cap_fm_deviation = { - .ops = &vivid_sdr_cap_ctrl_ops, - .id = VIVID_CID_SDR_CAP_FM_DEVIATION, - .name = "FM Deviation", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = 100, - .max = 200000, - .def = 75000, - .step = 1, -}; - -/* Metadata Capture Control */ - -static int vivid_meta_cap_s_ctrl(struct v4l2_ctrl *ctrl) -{ - struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, - ctrl_hdl_meta_cap); - - switch (ctrl->id) { - case VIVID_CID_META_CAP_GENERATE_PTS: - dev->meta_pts = ctrl->val; - break; - case VIVID_CID_META_CAP_GENERATE_SCR: - dev->meta_scr = ctrl->val; - break; - } - return 0; -} - -static const struct v4l2_ctrl_ops vivid_meta_cap_ctrl_ops = { - .s_ctrl = vivid_meta_cap_s_ctrl, -}; - -static const struct v4l2_ctrl_config vivid_ctrl_meta_has_pts = { - .ops = &vivid_meta_cap_ctrl_ops, - .id = VIVID_CID_META_CAP_GENERATE_PTS, - .name = "Generate PTS", - .type = V4L2_CTRL_TYPE_BOOLEAN, - .max = 1, - .def = 1, - .step = 1, -}; - -static const struct v4l2_ctrl_config vivid_ctrl_meta_has_src_clk = { - .ops = &vivid_meta_cap_ctrl_ops, - .id = VIVID_CID_META_CAP_GENERATE_SCR, - .name = "Generate SCR", - .type = V4L2_CTRL_TYPE_BOOLEAN, - .max = 1, - .def = 1, - .step = 1, -}; - -static const struct v4l2_ctrl_config vivid_ctrl_class = { - .ops = &vivid_user_gen_ctrl_ops, - .flags = V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_WRITE_ONLY, - .id = VIVID_CID_VIVID_CLASS, - .name = "Vivid Controls", - .type = V4L2_CTRL_TYPE_CTRL_CLASS, -}; - -int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap, - bool show_ccs_out, bool no_error_inj, - bool has_sdtv, bool has_hdmi) -{ - struct v4l2_ctrl_handler *hdl_user_gen = &dev->ctrl_hdl_user_gen; - struct v4l2_ctrl_handler *hdl_user_vid = &dev->ctrl_hdl_user_vid; - struct v4l2_ctrl_handler *hdl_user_aud = &dev->ctrl_hdl_user_aud; - struct v4l2_ctrl_handler *hdl_streaming = &dev->ctrl_hdl_streaming; - struct v4l2_ctrl_handler *hdl_sdtv_cap = &dev->ctrl_hdl_sdtv_cap; - struct v4l2_ctrl_handler *hdl_loop_cap = &dev->ctrl_hdl_loop_cap; - struct v4l2_ctrl_handler *hdl_fb = &dev->ctrl_hdl_fb; - struct v4l2_ctrl_handler *hdl_vid_cap = &dev->ctrl_hdl_vid_cap; - struct v4l2_ctrl_handler *hdl_vid_out = &dev->ctrl_hdl_vid_out; - struct v4l2_ctrl_handler *hdl_vbi_cap = &dev->ctrl_hdl_vbi_cap; - struct v4l2_ctrl_handler *hdl_vbi_out = &dev->ctrl_hdl_vbi_out; - struct v4l2_ctrl_handler *hdl_radio_rx = &dev->ctrl_hdl_radio_rx; - struct v4l2_ctrl_handler *hdl_radio_tx = &dev->ctrl_hdl_radio_tx; - struct v4l2_ctrl_handler *hdl_sdr_cap = &dev->ctrl_hdl_sdr_cap; - struct v4l2_ctrl_handler *hdl_meta_cap = &dev->ctrl_hdl_meta_cap; - struct v4l2_ctrl_handler *hdl_meta_out = &dev->ctrl_hdl_meta_out; - struct v4l2_ctrl_handler *hdl_tch_cap = &dev->ctrl_hdl_touch_cap; - - struct v4l2_ctrl_config vivid_ctrl_dv_timings = { - .ops = &vivid_vid_cap_ctrl_ops, - .id = VIVID_CID_DV_TIMINGS, - .name = "DV Timings", - .type = V4L2_CTRL_TYPE_MENU, - }; - int i; - - v4l2_ctrl_handler_init(hdl_user_gen, 10); - v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_class, NULL); - v4l2_ctrl_handler_init(hdl_user_vid, 9); - v4l2_ctrl_new_custom(hdl_user_vid, &vivid_ctrl_class, NULL); - v4l2_ctrl_handler_init(hdl_user_aud, 2); - v4l2_ctrl_new_custom(hdl_user_aud, &vivid_ctrl_class, NULL); - v4l2_ctrl_handler_init(hdl_streaming, 8); - v4l2_ctrl_new_custom(hdl_streaming, &vivid_ctrl_class, NULL); - v4l2_ctrl_handler_init(hdl_sdtv_cap, 2); - v4l2_ctrl_new_custom(hdl_sdtv_cap, &vivid_ctrl_class, NULL); - v4l2_ctrl_handler_init(hdl_loop_cap, 1); - v4l2_ctrl_new_custom(hdl_loop_cap, &vivid_ctrl_class, NULL); - v4l2_ctrl_handler_init(hdl_fb, 1); - v4l2_ctrl_new_custom(hdl_fb, &vivid_ctrl_class, NULL); - v4l2_ctrl_handler_init(hdl_vid_cap, 55); - v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_class, NULL); - v4l2_ctrl_handler_init(hdl_vid_out, 26); - if (!no_error_inj || dev->has_fb || dev->num_hdmi_outputs) - v4l2_ctrl_new_custom(hdl_vid_out, &vivid_ctrl_class, NULL); - v4l2_ctrl_handler_init(hdl_vbi_cap, 21); - v4l2_ctrl_new_custom(hdl_vbi_cap, &vivid_ctrl_class, NULL); - v4l2_ctrl_handler_init(hdl_vbi_out, 19); - if (!no_error_inj) - v4l2_ctrl_new_custom(hdl_vbi_out, &vivid_ctrl_class, NULL); - v4l2_ctrl_handler_init(hdl_radio_rx, 17); - v4l2_ctrl_new_custom(hdl_radio_rx, &vivid_ctrl_class, NULL); - v4l2_ctrl_handler_init(hdl_radio_tx, 17); - v4l2_ctrl_new_custom(hdl_radio_tx, &vivid_ctrl_class, NULL); - v4l2_ctrl_handler_init(hdl_sdr_cap, 19); - v4l2_ctrl_new_custom(hdl_sdr_cap, &vivid_ctrl_class, NULL); - v4l2_ctrl_handler_init(hdl_meta_cap, 2); - v4l2_ctrl_new_custom(hdl_meta_cap, &vivid_ctrl_class, NULL); - v4l2_ctrl_handler_init(hdl_meta_out, 2); - v4l2_ctrl_new_custom(hdl_meta_out, &vivid_ctrl_class, NULL); - v4l2_ctrl_handler_init(hdl_tch_cap, 2); - v4l2_ctrl_new_custom(hdl_tch_cap, &vivid_ctrl_class, NULL); - - /* User Controls */ - dev->volume = v4l2_ctrl_new_std(hdl_user_aud, NULL, - V4L2_CID_AUDIO_VOLUME, 0, 255, 1, 200); - dev->mute = v4l2_ctrl_new_std(hdl_user_aud, NULL, - V4L2_CID_AUDIO_MUTE, 0, 1, 1, 0); - if (dev->has_vid_cap) { - dev->brightness = v4l2_ctrl_new_std(hdl_user_vid, &vivid_user_vid_ctrl_ops, - V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); - for (i = 0; i < MAX_INPUTS; i++) - dev->input_brightness[i] = 128; - dev->contrast = v4l2_ctrl_new_std(hdl_user_vid, &vivid_user_vid_ctrl_ops, - V4L2_CID_CONTRAST, 0, 255, 1, 128); - dev->saturation = v4l2_ctrl_new_std(hdl_user_vid, &vivid_user_vid_ctrl_ops, - V4L2_CID_SATURATION, 0, 255, 1, 128); - dev->hue = v4l2_ctrl_new_std(hdl_user_vid, &vivid_user_vid_ctrl_ops, - V4L2_CID_HUE, -128, 128, 1, 0); - v4l2_ctrl_new_std(hdl_user_vid, &vivid_user_vid_ctrl_ops, - V4L2_CID_HFLIP, 0, 1, 1, 0); - v4l2_ctrl_new_std(hdl_user_vid, &vivid_user_vid_ctrl_ops, - V4L2_CID_VFLIP, 0, 1, 1, 0); - dev->autogain = v4l2_ctrl_new_std(hdl_user_vid, &vivid_user_vid_ctrl_ops, - V4L2_CID_AUTOGAIN, 0, 1, 1, 1); - dev->gain = v4l2_ctrl_new_std(hdl_user_vid, &vivid_user_vid_ctrl_ops, - V4L2_CID_GAIN, 0, 255, 1, 100); - dev->alpha = v4l2_ctrl_new_std(hdl_user_vid, &vivid_user_vid_ctrl_ops, - V4L2_CID_ALPHA_COMPONENT, 0, 255, 1, 0); - } - dev->button = v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_button, NULL); - dev->int32 = v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_int32, NULL); - dev->int64 = v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_int64, NULL); - dev->boolean = v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_boolean, NULL); - dev->menu = v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_menu, NULL); - dev->string = v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_string, NULL); - dev->bitmask = v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_bitmask, NULL); - dev->int_menu = v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_int_menu, NULL); - v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_area, NULL); - v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_u32_array, NULL); - v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_u16_matrix, NULL); - v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_u8_4d_array, NULL); - - if (dev->has_vid_cap) { - /* Image Processing Controls */ - struct v4l2_ctrl_config vivid_ctrl_test_pattern = { - .ops = &vivid_vid_cap_ctrl_ops, - .id = VIVID_CID_TEST_PATTERN, - .name = "Test Pattern", - .type = V4L2_CTRL_TYPE_MENU, - .max = TPG_PAT_NOISE, - .qmenu = tpg_pattern_strings, - }; - - dev->test_pattern = v4l2_ctrl_new_custom(hdl_vid_cap, - &vivid_ctrl_test_pattern, NULL); - v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_perc_fill, NULL); - v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_hor_movement, NULL); - v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_vert_movement, NULL); - v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_osd_mode, NULL); - v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_show_border, NULL); - v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_show_square, NULL); - v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_hflip, NULL); - v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_vflip, NULL); - v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_insert_sav, NULL); - v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_insert_eav, NULL); - v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_reduced_fps, NULL); - if (show_ccs_cap) { - dev->ctrl_has_crop_cap = v4l2_ctrl_new_custom(hdl_vid_cap, - &vivid_ctrl_has_crop_cap, NULL); - dev->ctrl_has_compose_cap = v4l2_ctrl_new_custom(hdl_vid_cap, - &vivid_ctrl_has_compose_cap, NULL); - dev->ctrl_has_scaler_cap = v4l2_ctrl_new_custom(hdl_vid_cap, - &vivid_ctrl_has_scaler_cap, NULL); - } - - v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_tstamp_src, NULL); - dev->colorspace = v4l2_ctrl_new_custom(hdl_vid_cap, - &vivid_ctrl_colorspace, NULL); - v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_xfer_func, NULL); - v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_ycbcr_enc, NULL); - v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_hsv_enc, NULL); - v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_quantization, NULL); - v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_alpha_mode, NULL); - } - - if (dev->has_vid_out && show_ccs_out) { - dev->ctrl_has_crop_out = v4l2_ctrl_new_custom(hdl_vid_out, - &vivid_ctrl_has_crop_out, NULL); - dev->ctrl_has_compose_out = v4l2_ctrl_new_custom(hdl_vid_out, - &vivid_ctrl_has_compose_out, NULL); - dev->ctrl_has_scaler_out = v4l2_ctrl_new_custom(hdl_vid_out, - &vivid_ctrl_has_scaler_out, NULL); - } - - /* - * Testing this driver with v4l2-compliance will trigger the error - * injection controls, and after that nothing will work as expected. - * So we have a module option to drop these error injecting controls - * allowing us to run v4l2_compliance again. - */ - if (!no_error_inj) { - v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_disconnect, NULL); - v4l2_ctrl_new_custom(hdl_streaming, &vivid_ctrl_dqbuf_error, NULL); - v4l2_ctrl_new_custom(hdl_streaming, &vivid_ctrl_perc_dropped, NULL); - v4l2_ctrl_new_custom(hdl_streaming, &vivid_ctrl_queue_setup_error, NULL); - v4l2_ctrl_new_custom(hdl_streaming, &vivid_ctrl_buf_prepare_error, NULL); - v4l2_ctrl_new_custom(hdl_streaming, &vivid_ctrl_start_streaming_error, NULL); - v4l2_ctrl_new_custom(hdl_streaming, &vivid_ctrl_queue_error, NULL); -#ifdef CONFIG_MEDIA_CONTROLLER - v4l2_ctrl_new_custom(hdl_streaming, &vivid_ctrl_req_validate_error, NULL); -#endif - v4l2_ctrl_new_custom(hdl_streaming, &vivid_ctrl_seq_wrap, NULL); - v4l2_ctrl_new_custom(hdl_streaming, &vivid_ctrl_time_wrap, NULL); - } - - if (has_sdtv && (dev->has_vid_cap || dev->has_vbi_cap)) { - if (dev->has_vid_cap) - v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_std_aspect_ratio, NULL); - dev->ctrl_std_signal_mode = v4l2_ctrl_new_custom(hdl_sdtv_cap, - &vivid_ctrl_std_signal_mode, NULL); - dev->ctrl_standard = v4l2_ctrl_new_custom(hdl_sdtv_cap, - &vivid_ctrl_standard, NULL); - if (dev->ctrl_std_signal_mode) - v4l2_ctrl_cluster(2, &dev->ctrl_std_signal_mode); - if (dev->has_raw_vbi_cap) - v4l2_ctrl_new_custom(hdl_vbi_cap, &vivid_ctrl_vbi_cap_interlaced, NULL); - } - - if (dev->num_hdmi_inputs) { - s64 hdmi_input_mask = GENMASK(dev->num_hdmi_inputs - 1, 0); - - dev->ctrl_dv_timings_signal_mode = v4l2_ctrl_new_custom(hdl_vid_cap, - &vivid_ctrl_dv_timings_signal_mode, NULL); - - vivid_ctrl_dv_timings.max = dev->query_dv_timings_size - 1; - vivid_ctrl_dv_timings.qmenu = - (const char * const *)dev->query_dv_timings_qmenu; - dev->ctrl_dv_timings = v4l2_ctrl_new_custom(hdl_vid_cap, - &vivid_ctrl_dv_timings, NULL); - if (dev->ctrl_dv_timings_signal_mode) - v4l2_ctrl_cluster(2, &dev->ctrl_dv_timings_signal_mode); - - v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_dv_timings_aspect_ratio, NULL); - v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_max_edid_blocks, NULL); - dev->real_rgb_range_cap = v4l2_ctrl_new_custom(hdl_vid_cap, - &vivid_ctrl_limited_rgb_range, NULL); - dev->rgb_range_cap = v4l2_ctrl_new_std_menu(hdl_vid_cap, - &vivid_vid_cap_ctrl_ops, - V4L2_CID_DV_RX_RGB_RANGE, V4L2_DV_RGB_RANGE_FULL, - 0, V4L2_DV_RGB_RANGE_AUTO); - dev->ctrl_rx_power_present = v4l2_ctrl_new_std(hdl_vid_cap, - NULL, V4L2_CID_DV_RX_POWER_PRESENT, 0, hdmi_input_mask, - 0, hdmi_input_mask); - - } - if (dev->num_hdmi_outputs) { - s64 hdmi_output_mask = GENMASK(dev->num_hdmi_outputs - 1, 0); - - /* - * We aren't doing anything with this at the moment, but - * HDMI outputs typically have this controls. - */ - dev->ctrl_tx_rgb_range = v4l2_ctrl_new_std_menu(hdl_vid_out, NULL, - V4L2_CID_DV_TX_RGB_RANGE, V4L2_DV_RGB_RANGE_FULL, - 0, V4L2_DV_RGB_RANGE_AUTO); - dev->ctrl_tx_mode = v4l2_ctrl_new_std_menu(hdl_vid_out, NULL, - V4L2_CID_DV_TX_MODE, V4L2_DV_TX_MODE_HDMI, - 0, V4L2_DV_TX_MODE_HDMI); - dev->ctrl_display_present = v4l2_ctrl_new_custom(hdl_vid_out, - &vivid_ctrl_display_present, NULL); - dev->ctrl_tx_hotplug = v4l2_ctrl_new_std(hdl_vid_out, - NULL, V4L2_CID_DV_TX_HOTPLUG, 0, hdmi_output_mask, - 0, hdmi_output_mask); - dev->ctrl_tx_rxsense = v4l2_ctrl_new_std(hdl_vid_out, - NULL, V4L2_CID_DV_TX_RXSENSE, 0, hdmi_output_mask, - 0, hdmi_output_mask); - dev->ctrl_tx_edid_present = v4l2_ctrl_new_std(hdl_vid_out, - NULL, V4L2_CID_DV_TX_EDID_PRESENT, 0, hdmi_output_mask, - 0, hdmi_output_mask); - } - if ((dev->has_vid_cap && dev->has_vid_out) || - (dev->has_vbi_cap && dev->has_vbi_out)) - v4l2_ctrl_new_custom(hdl_loop_cap, &vivid_ctrl_loop_video, NULL); - - if (dev->has_fb) - v4l2_ctrl_new_custom(hdl_fb, &vivid_ctrl_clear_fb, NULL); - - if (dev->has_radio_rx) { - v4l2_ctrl_new_custom(hdl_radio_rx, &vivid_ctrl_radio_hw_seek_mode, NULL); - v4l2_ctrl_new_custom(hdl_radio_rx, &vivid_ctrl_radio_hw_seek_prog_lim, NULL); - v4l2_ctrl_new_custom(hdl_radio_rx, &vivid_ctrl_radio_rx_rds_blockio, NULL); - v4l2_ctrl_new_custom(hdl_radio_rx, &vivid_ctrl_radio_rx_rds_rbds, NULL); - v4l2_ctrl_new_std(hdl_radio_rx, &vivid_radio_rx_ctrl_ops, - V4L2_CID_RDS_RECEPTION, 0, 1, 1, 1); - dev->radio_rx_rds_pty = v4l2_ctrl_new_std(hdl_radio_rx, - &vivid_radio_rx_ctrl_ops, - V4L2_CID_RDS_RX_PTY, 0, 31, 1, 0); - dev->radio_rx_rds_psname = v4l2_ctrl_new_std(hdl_radio_rx, - &vivid_radio_rx_ctrl_ops, - V4L2_CID_RDS_RX_PS_NAME, 0, 8, 8, 0); - dev->radio_rx_rds_radiotext = v4l2_ctrl_new_std(hdl_radio_rx, - &vivid_radio_rx_ctrl_ops, - V4L2_CID_RDS_RX_RADIO_TEXT, 0, 64, 64, 0); - dev->radio_rx_rds_ta = v4l2_ctrl_new_std(hdl_radio_rx, - &vivid_radio_rx_ctrl_ops, - V4L2_CID_RDS_RX_TRAFFIC_ANNOUNCEMENT, 0, 1, 1, 0); - dev->radio_rx_rds_tp = v4l2_ctrl_new_std(hdl_radio_rx, - &vivid_radio_rx_ctrl_ops, - V4L2_CID_RDS_RX_TRAFFIC_PROGRAM, 0, 1, 1, 0); - dev->radio_rx_rds_ms = v4l2_ctrl_new_std(hdl_radio_rx, - &vivid_radio_rx_ctrl_ops, - V4L2_CID_RDS_RX_MUSIC_SPEECH, 0, 1, 1, 1); - } - if (dev->has_radio_tx) { - v4l2_ctrl_new_custom(hdl_radio_tx, - &vivid_ctrl_radio_tx_rds_blockio, NULL); - dev->radio_tx_rds_pi = v4l2_ctrl_new_std(hdl_radio_tx, - &vivid_radio_tx_ctrl_ops, - V4L2_CID_RDS_TX_PI, 0, 0xffff, 1, 0x8088); - dev->radio_tx_rds_pty = v4l2_ctrl_new_std(hdl_radio_tx, - &vivid_radio_tx_ctrl_ops, - V4L2_CID_RDS_TX_PTY, 0, 31, 1, 3); - dev->radio_tx_rds_psname = v4l2_ctrl_new_std(hdl_radio_tx, - &vivid_radio_tx_ctrl_ops, - V4L2_CID_RDS_TX_PS_NAME, 0, 8, 8, 0); - if (dev->radio_tx_rds_psname) - v4l2_ctrl_s_ctrl_string(dev->radio_tx_rds_psname, "VIVID-TX"); - dev->radio_tx_rds_radiotext = v4l2_ctrl_new_std(hdl_radio_tx, - &vivid_radio_tx_ctrl_ops, - V4L2_CID_RDS_TX_RADIO_TEXT, 0, 64 * 2, 64, 0); - if (dev->radio_tx_rds_radiotext) - v4l2_ctrl_s_ctrl_string(dev->radio_tx_rds_radiotext, - "This is a VIVID default Radio Text template text, change at will"); - dev->radio_tx_rds_mono_stereo = v4l2_ctrl_new_std(hdl_radio_tx, - &vivid_radio_tx_ctrl_ops, - V4L2_CID_RDS_TX_MONO_STEREO, 0, 1, 1, 1); - dev->radio_tx_rds_art_head = v4l2_ctrl_new_std(hdl_radio_tx, - &vivid_radio_tx_ctrl_ops, - V4L2_CID_RDS_TX_ARTIFICIAL_HEAD, 0, 1, 1, 0); - dev->radio_tx_rds_compressed = v4l2_ctrl_new_std(hdl_radio_tx, - &vivid_radio_tx_ctrl_ops, - V4L2_CID_RDS_TX_COMPRESSED, 0, 1, 1, 0); - dev->radio_tx_rds_dyn_pty = v4l2_ctrl_new_std(hdl_radio_tx, - &vivid_radio_tx_ctrl_ops, - V4L2_CID_RDS_TX_DYNAMIC_PTY, 0, 1, 1, 0); - dev->radio_tx_rds_ta = v4l2_ctrl_new_std(hdl_radio_tx, - &vivid_radio_tx_ctrl_ops, - V4L2_CID_RDS_TX_TRAFFIC_ANNOUNCEMENT, 0, 1, 1, 0); - dev->radio_tx_rds_tp = v4l2_ctrl_new_std(hdl_radio_tx, - &vivid_radio_tx_ctrl_ops, - V4L2_CID_RDS_TX_TRAFFIC_PROGRAM, 0, 1, 1, 1); - dev->radio_tx_rds_ms = v4l2_ctrl_new_std(hdl_radio_tx, - &vivid_radio_tx_ctrl_ops, - V4L2_CID_RDS_TX_MUSIC_SPEECH, 0, 1, 1, 1); - } - if (dev->has_sdr_cap) { - v4l2_ctrl_new_custom(hdl_sdr_cap, - &vivid_ctrl_sdr_cap_fm_deviation, NULL); - } - if (dev->has_meta_cap) { - v4l2_ctrl_new_custom(hdl_meta_cap, - &vivid_ctrl_meta_has_pts, NULL); - v4l2_ctrl_new_custom(hdl_meta_cap, - &vivid_ctrl_meta_has_src_clk, NULL); - } - - if (hdl_user_gen->error) - return hdl_user_gen->error; - if (hdl_user_vid->error) - return hdl_user_vid->error; - if (hdl_user_aud->error) - return hdl_user_aud->error; - if (hdl_streaming->error) - return hdl_streaming->error; - if (hdl_sdr_cap->error) - return hdl_sdr_cap->error; - if (hdl_loop_cap->error) - return hdl_loop_cap->error; - - if (dev->autogain) - v4l2_ctrl_auto_cluster(2, &dev->autogain, 0, true); - - if (dev->has_vid_cap) { - v4l2_ctrl_add_handler(hdl_vid_cap, hdl_user_gen, NULL, false); - v4l2_ctrl_add_handler(hdl_vid_cap, hdl_user_vid, NULL, false); - v4l2_ctrl_add_handler(hdl_vid_cap, hdl_user_aud, NULL, false); - v4l2_ctrl_add_handler(hdl_vid_cap, hdl_streaming, NULL, false); - v4l2_ctrl_add_handler(hdl_vid_cap, hdl_sdtv_cap, NULL, false); - v4l2_ctrl_add_handler(hdl_vid_cap, hdl_loop_cap, NULL, false); - v4l2_ctrl_add_handler(hdl_vid_cap, hdl_fb, NULL, false); - if (hdl_vid_cap->error) - return hdl_vid_cap->error; - dev->vid_cap_dev.ctrl_handler = hdl_vid_cap; - } - if (dev->has_vid_out) { - v4l2_ctrl_add_handler(hdl_vid_out, hdl_user_gen, NULL, false); - v4l2_ctrl_add_handler(hdl_vid_out, hdl_user_aud, NULL, false); - v4l2_ctrl_add_handler(hdl_vid_out, hdl_streaming, NULL, false); - v4l2_ctrl_add_handler(hdl_vid_out, hdl_fb, NULL, false); - if (hdl_vid_out->error) - return hdl_vid_out->error; - dev->vid_out_dev.ctrl_handler = hdl_vid_out; - } - if (dev->has_vbi_cap) { - v4l2_ctrl_add_handler(hdl_vbi_cap, hdl_user_gen, NULL, false); - v4l2_ctrl_add_handler(hdl_vbi_cap, hdl_streaming, NULL, false); - v4l2_ctrl_add_handler(hdl_vbi_cap, hdl_sdtv_cap, NULL, false); - v4l2_ctrl_add_handler(hdl_vbi_cap, hdl_loop_cap, NULL, false); - if (hdl_vbi_cap->error) - return hdl_vbi_cap->error; - dev->vbi_cap_dev.ctrl_handler = hdl_vbi_cap; - } - if (dev->has_vbi_out) { - v4l2_ctrl_add_handler(hdl_vbi_out, hdl_user_gen, NULL, false); - v4l2_ctrl_add_handler(hdl_vbi_out, hdl_streaming, NULL, false); - if (hdl_vbi_out->error) - return hdl_vbi_out->error; - dev->vbi_out_dev.ctrl_handler = hdl_vbi_out; - } - if (dev->has_radio_rx) { - v4l2_ctrl_add_handler(hdl_radio_rx, hdl_user_gen, NULL, false); - v4l2_ctrl_add_handler(hdl_radio_rx, hdl_user_aud, NULL, false); - if (hdl_radio_rx->error) - return hdl_radio_rx->error; - dev->radio_rx_dev.ctrl_handler = hdl_radio_rx; - } - if (dev->has_radio_tx) { - v4l2_ctrl_add_handler(hdl_radio_tx, hdl_user_gen, NULL, false); - v4l2_ctrl_add_handler(hdl_radio_tx, hdl_user_aud, NULL, false); - if (hdl_radio_tx->error) - return hdl_radio_tx->error; - dev->radio_tx_dev.ctrl_handler = hdl_radio_tx; - } - if (dev->has_sdr_cap) { - v4l2_ctrl_add_handler(hdl_sdr_cap, hdl_user_gen, NULL, false); - v4l2_ctrl_add_handler(hdl_sdr_cap, hdl_streaming, NULL, false); - if (hdl_sdr_cap->error) - return hdl_sdr_cap->error; - dev->sdr_cap_dev.ctrl_handler = hdl_sdr_cap; - } - if (dev->has_meta_cap) { - v4l2_ctrl_add_handler(hdl_meta_cap, hdl_user_gen, NULL, false); - v4l2_ctrl_add_handler(hdl_meta_cap, hdl_streaming, NULL, false); - if (hdl_meta_cap->error) - return hdl_meta_cap->error; - dev->meta_cap_dev.ctrl_handler = hdl_meta_cap; - } - if (dev->has_meta_out) { - v4l2_ctrl_add_handler(hdl_meta_out, hdl_user_gen, NULL, false); - v4l2_ctrl_add_handler(hdl_meta_out, hdl_streaming, NULL, false); - if (hdl_meta_out->error) - return hdl_meta_out->error; - dev->meta_out_dev.ctrl_handler = hdl_meta_out; - } - if (dev->has_touch_cap) { - v4l2_ctrl_add_handler(hdl_tch_cap, hdl_user_gen, NULL, false); - v4l2_ctrl_add_handler(hdl_tch_cap, hdl_streaming, NULL, false); - if (hdl_tch_cap->error) - return hdl_tch_cap->error; - dev->touch_cap_dev.ctrl_handler = hdl_tch_cap; - } - return 0; -} - -void vivid_free_controls(struct vivid_dev *dev) -{ - v4l2_ctrl_handler_free(&dev->ctrl_hdl_vid_cap); - v4l2_ctrl_handler_free(&dev->ctrl_hdl_vid_out); - v4l2_ctrl_handler_free(&dev->ctrl_hdl_vbi_cap); - v4l2_ctrl_handler_free(&dev->ctrl_hdl_vbi_out); - v4l2_ctrl_handler_free(&dev->ctrl_hdl_radio_rx); - v4l2_ctrl_handler_free(&dev->ctrl_hdl_radio_tx); - v4l2_ctrl_handler_free(&dev->ctrl_hdl_sdr_cap); - v4l2_ctrl_handler_free(&dev->ctrl_hdl_user_gen); - v4l2_ctrl_handler_free(&dev->ctrl_hdl_user_vid); - v4l2_ctrl_handler_free(&dev->ctrl_hdl_user_aud); - v4l2_ctrl_handler_free(&dev->ctrl_hdl_streaming); - v4l2_ctrl_handler_free(&dev->ctrl_hdl_sdtv_cap); - v4l2_ctrl_handler_free(&dev->ctrl_hdl_loop_cap); - v4l2_ctrl_handler_free(&dev->ctrl_hdl_fb); - v4l2_ctrl_handler_free(&dev->ctrl_hdl_meta_cap); - v4l2_ctrl_handler_free(&dev->ctrl_hdl_meta_out); - v4l2_ctrl_handler_free(&dev->ctrl_hdl_touch_cap); -} diff --git a/drivers/media/platform/vivid/vivid-ctrls.h b/drivers/media/platform/vivid/vivid-ctrls.h deleted file mode 100644 index 6fad5f5d0054..000000000000 --- a/drivers/media/platform/vivid/vivid-ctrls.h +++ /dev/null @@ -1,22 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * vivid-ctrls.h - control support functions. - * - * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - */ - -#ifndef _VIVID_CTRLS_H_ -#define _VIVID_CTRLS_H_ - -enum vivid_hw_seek_modes { - VIVID_HW_SEEK_BOUNDED, - VIVID_HW_SEEK_WRAP, - VIVID_HW_SEEK_BOTH, -}; - -int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap, - bool show_ccs_out, bool no_error_inj, - bool has_sdtv, bool has_hdmi); -void vivid_free_controls(struct vivid_dev *dev); - -#endif diff --git a/drivers/media/platform/vivid/vivid-kthread-cap.c b/drivers/media/platform/vivid/vivid-kthread-cap.c deleted file mode 100644 index 01a9d671b947..000000000000 --- a/drivers/media/platform/vivid/vivid-kthread-cap.c +++ /dev/null @@ -1,1007 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * vivid-kthread-cap.h - video/vbi capture thread support functions. - * - * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "vivid-core.h" -#include "vivid-vid-common.h" -#include "vivid-vid-cap.h" -#include "vivid-vid-out.h" -#include "vivid-radio-common.h" -#include "vivid-radio-rx.h" -#include "vivid-radio-tx.h" -#include "vivid-sdr-cap.h" -#include "vivid-vbi-cap.h" -#include "vivid-vbi-out.h" -#include "vivid-osd.h" -#include "vivid-ctrls.h" -#include "vivid-kthread-cap.h" -#include "vivid-meta-cap.h" - -static inline v4l2_std_id vivid_get_std_cap(const struct vivid_dev *dev) -{ - if (vivid_is_sdtv_cap(dev)) - return dev->std_cap[dev->input]; - return 0; -} - -static void copy_pix(struct vivid_dev *dev, int win_y, int win_x, - u16 *cap, const u16 *osd) -{ - u16 out; - int left = dev->overlay_out_left; - int top = dev->overlay_out_top; - int fb_x = win_x + left; - int fb_y = win_y + top; - int i; - - out = *cap; - *cap = *osd; - if (dev->bitmap_out) { - const u8 *p = dev->bitmap_out; - unsigned stride = (dev->compose_out.width + 7) / 8; - - win_x -= dev->compose_out.left; - win_y -= dev->compose_out.top; - if (!(p[stride * win_y + win_x / 8] & (1 << (win_x & 7)))) - return; - } - - for (i = 0; i < dev->clipcount_out; i++) { - struct v4l2_rect *r = &dev->clips_out[i].c; - - if (fb_y >= r->top && fb_y < r->top + r->height && - fb_x >= r->left && fb_x < r->left + r->width) - return; - } - if ((dev->fbuf_out_flags & V4L2_FBUF_FLAG_CHROMAKEY) && - *osd != dev->chromakey_out) - return; - if ((dev->fbuf_out_flags & V4L2_FBUF_FLAG_SRC_CHROMAKEY) && - out == dev->chromakey_out) - return; - if (dev->fmt_cap->alpha_mask) { - if ((dev->fbuf_out_flags & V4L2_FBUF_FLAG_GLOBAL_ALPHA) && - dev->global_alpha_out) - return; - if ((dev->fbuf_out_flags & V4L2_FBUF_FLAG_LOCAL_ALPHA) && - *cap & dev->fmt_cap->alpha_mask) - return; - if ((dev->fbuf_out_flags & V4L2_FBUF_FLAG_LOCAL_INV_ALPHA) && - !(*cap & dev->fmt_cap->alpha_mask)) - return; - } - *cap = out; -} - -static void blend_line(struct vivid_dev *dev, unsigned y_offset, unsigned x_offset, - u8 *vcapbuf, const u8 *vosdbuf, - unsigned width, unsigned pixsize) -{ - unsigned x; - - for (x = 0; x < width; x++, vcapbuf += pixsize, vosdbuf += pixsize) { - copy_pix(dev, y_offset, x_offset + x, - (u16 *)vcapbuf, (const u16 *)vosdbuf); - } -} - -static void scale_line(const u8 *src, u8 *dst, unsigned srcw, unsigned dstw, unsigned twopixsize) -{ - /* Coarse scaling with Bresenham */ - unsigned int_part; - unsigned fract_part; - unsigned src_x = 0; - unsigned error = 0; - unsigned x; - - /* - * We always combine two pixels to prevent color bleed in the packed - * yuv case. - */ - srcw /= 2; - dstw /= 2; - int_part = srcw / dstw; - fract_part = srcw % dstw; - for (x = 0; x < dstw; x++, dst += twopixsize) { - memcpy(dst, src + src_x * twopixsize, twopixsize); - src_x += int_part; - error += fract_part; - if (error >= dstw) { - error -= dstw; - src_x++; - } - } -} - -/* - * Precalculate the rectangles needed to perform video looping: - * - * The nominal pipeline is that the video output buffer is cropped by - * crop_out, scaled to compose_out, overlaid with the output overlay, - * cropped on the capture side by crop_cap and scaled again to the video - * capture buffer using compose_cap. - * - * To keep things efficient we calculate the intersection of compose_out - * and crop_cap (since that's the only part of the video that will - * actually end up in the capture buffer), determine which part of the - * video output buffer that is and which part of the video capture buffer - * so we can scale the video straight from the output buffer to the capture - * buffer without any intermediate steps. - * - * If we need to deal with an output overlay, then there is no choice and - * that intermediate step still has to be taken. For the output overlay - * support we calculate the intersection of the framebuffer and the overlay - * window (which may be partially or wholly outside of the framebuffer - * itself) and the intersection of that with loop_vid_copy (i.e. the part of - * the actual looped video that will be overlaid). The result is calculated - * both in framebuffer coordinates (loop_fb_copy) and compose_out coordinates - * (loop_vid_overlay). Finally calculate the part of the capture buffer that - * will receive that overlaid video. - */ -static void vivid_precalc_copy_rects(struct vivid_dev *dev) -{ - /* Framebuffer rectangle */ - struct v4l2_rect r_fb = { - 0, 0, dev->display_width, dev->display_height - }; - /* Overlay window rectangle in framebuffer coordinates */ - struct v4l2_rect r_overlay = { - dev->overlay_out_left, dev->overlay_out_top, - dev->compose_out.width, dev->compose_out.height - }; - - v4l2_rect_intersect(&dev->loop_vid_copy, &dev->crop_cap, &dev->compose_out); - - dev->loop_vid_out = dev->loop_vid_copy; - v4l2_rect_scale(&dev->loop_vid_out, &dev->compose_out, &dev->crop_out); - dev->loop_vid_out.left += dev->crop_out.left; - dev->loop_vid_out.top += dev->crop_out.top; - - dev->loop_vid_cap = dev->loop_vid_copy; - v4l2_rect_scale(&dev->loop_vid_cap, &dev->crop_cap, &dev->compose_cap); - - dprintk(dev, 1, - "loop_vid_copy: %dx%d@%dx%d loop_vid_out: %dx%d@%dx%d loop_vid_cap: %dx%d@%dx%d\n", - dev->loop_vid_copy.width, dev->loop_vid_copy.height, - dev->loop_vid_copy.left, dev->loop_vid_copy.top, - dev->loop_vid_out.width, dev->loop_vid_out.height, - dev->loop_vid_out.left, dev->loop_vid_out.top, - dev->loop_vid_cap.width, dev->loop_vid_cap.height, - dev->loop_vid_cap.left, dev->loop_vid_cap.top); - - v4l2_rect_intersect(&r_overlay, &r_fb, &r_overlay); - - /* shift r_overlay to the same origin as compose_out */ - r_overlay.left += dev->compose_out.left - dev->overlay_out_left; - r_overlay.top += dev->compose_out.top - dev->overlay_out_top; - - v4l2_rect_intersect(&dev->loop_vid_overlay, &r_overlay, &dev->loop_vid_copy); - dev->loop_fb_copy = dev->loop_vid_overlay; - - /* shift dev->loop_fb_copy back again to the fb origin */ - dev->loop_fb_copy.left -= dev->compose_out.left - dev->overlay_out_left; - dev->loop_fb_copy.top -= dev->compose_out.top - dev->overlay_out_top; - - dev->loop_vid_overlay_cap = dev->loop_vid_overlay; - v4l2_rect_scale(&dev->loop_vid_overlay_cap, &dev->crop_cap, &dev->compose_cap); - - dprintk(dev, 1, - "loop_fb_copy: %dx%d@%dx%d loop_vid_overlay: %dx%d@%dx%d loop_vid_overlay_cap: %dx%d@%dx%d\n", - dev->loop_fb_copy.width, dev->loop_fb_copy.height, - dev->loop_fb_copy.left, dev->loop_fb_copy.top, - dev->loop_vid_overlay.width, dev->loop_vid_overlay.height, - dev->loop_vid_overlay.left, dev->loop_vid_overlay.top, - dev->loop_vid_overlay_cap.width, dev->loop_vid_overlay_cap.height, - dev->loop_vid_overlay_cap.left, dev->loop_vid_overlay_cap.top); -} - -static void *plane_vaddr(struct tpg_data *tpg, struct vivid_buffer *buf, - unsigned p, unsigned bpl[TPG_MAX_PLANES], unsigned h) -{ - unsigned i; - void *vbuf; - - if (p == 0 || tpg_g_buffers(tpg) > 1) - return vb2_plane_vaddr(&buf->vb.vb2_buf, p); - vbuf = vb2_plane_vaddr(&buf->vb.vb2_buf, 0); - for (i = 0; i < p; i++) - vbuf += bpl[i] * h / tpg->vdownsampling[i]; - return vbuf; -} - -static noinline_for_stack int vivid_copy_buffer(struct vivid_dev *dev, unsigned p, - u8 *vcapbuf, struct vivid_buffer *vid_cap_buf) -{ - bool blank = dev->must_blank[vid_cap_buf->vb.vb2_buf.index]; - struct tpg_data *tpg = &dev->tpg; - struct vivid_buffer *vid_out_buf = NULL; - unsigned vdiv = dev->fmt_out->vdownsampling[p]; - unsigned twopixsize = tpg_g_twopixelsize(tpg, p); - unsigned img_width = tpg_hdiv(tpg, p, dev->compose_cap.width); - unsigned img_height = dev->compose_cap.height; - unsigned stride_cap = tpg->bytesperline[p]; - unsigned stride_out = dev->bytesperline_out[p]; - unsigned stride_osd = dev->display_byte_stride; - unsigned hmax = (img_height * tpg->perc_fill) / 100; - u8 *voutbuf; - u8 *vosdbuf = NULL; - unsigned y; - bool blend = dev->bitmap_out || dev->clipcount_out || dev->fbuf_out_flags; - /* Coarse scaling with Bresenham */ - unsigned vid_out_int_part; - unsigned vid_out_fract_part; - unsigned vid_out_y = 0; - unsigned vid_out_error = 0; - unsigned vid_overlay_int_part = 0; - unsigned vid_overlay_fract_part = 0; - unsigned vid_overlay_y = 0; - unsigned vid_overlay_error = 0; - unsigned vid_cap_left = tpg_hdiv(tpg, p, dev->loop_vid_cap.left); - unsigned vid_cap_right; - bool quick; - - vid_out_int_part = dev->loop_vid_out.height / dev->loop_vid_cap.height; - vid_out_fract_part = dev->loop_vid_out.height % dev->loop_vid_cap.height; - - if (!list_empty(&dev->vid_out_active)) - vid_out_buf = list_entry(dev->vid_out_active.next, - struct vivid_buffer, list); - if (vid_out_buf == NULL) - return -ENODATA; - - vid_cap_buf->vb.field = vid_out_buf->vb.field; - - voutbuf = plane_vaddr(tpg, vid_out_buf, p, - dev->bytesperline_out, dev->fmt_out_rect.height); - if (p < dev->fmt_out->buffers) - voutbuf += vid_out_buf->vb.vb2_buf.planes[p].data_offset; - voutbuf += tpg_hdiv(tpg, p, dev->loop_vid_out.left) + - (dev->loop_vid_out.top / vdiv) * stride_out; - vcapbuf += tpg_hdiv(tpg, p, dev->compose_cap.left) + - (dev->compose_cap.top / vdiv) * stride_cap; - - if (dev->loop_vid_copy.width == 0 || dev->loop_vid_copy.height == 0) { - /* - * If there is nothing to copy, then just fill the capture window - * with black. - */ - for (y = 0; y < hmax / vdiv; y++, vcapbuf += stride_cap) - memcpy(vcapbuf, tpg->black_line[p], img_width); - return 0; - } - - if (dev->overlay_out_enabled && - dev->loop_vid_overlay.width && dev->loop_vid_overlay.height) { - vosdbuf = dev->video_vbase; - vosdbuf += (dev->loop_fb_copy.left * twopixsize) / 2 + - dev->loop_fb_copy.top * stride_osd; - vid_overlay_int_part = dev->loop_vid_overlay.height / - dev->loop_vid_overlay_cap.height; - vid_overlay_fract_part = dev->loop_vid_overlay.height % - dev->loop_vid_overlay_cap.height; - } - - vid_cap_right = tpg_hdiv(tpg, p, dev->loop_vid_cap.left + dev->loop_vid_cap.width); - /* quick is true if no video scaling is needed */ - quick = dev->loop_vid_out.width == dev->loop_vid_cap.width; - - dev->cur_scaled_line = dev->loop_vid_out.height; - for (y = 0; y < hmax; y += vdiv, vcapbuf += stride_cap) { - /* osdline is true if this line requires overlay blending */ - bool osdline = vosdbuf && y >= dev->loop_vid_overlay_cap.top && - y < dev->loop_vid_overlay_cap.top + dev->loop_vid_overlay_cap.height; - - /* - * If this line of the capture buffer doesn't get any video, then - * just fill with black. - */ - if (y < dev->loop_vid_cap.top || - y >= dev->loop_vid_cap.top + dev->loop_vid_cap.height) { - memcpy(vcapbuf, tpg->black_line[p], img_width); - continue; - } - - /* fill the left border with black */ - if (dev->loop_vid_cap.left) - memcpy(vcapbuf, tpg->black_line[p], vid_cap_left); - - /* fill the right border with black */ - if (vid_cap_right < img_width) - memcpy(vcapbuf + vid_cap_right, tpg->black_line[p], - img_width - vid_cap_right); - - if (quick && !osdline) { - memcpy(vcapbuf + vid_cap_left, - voutbuf + vid_out_y * stride_out, - tpg_hdiv(tpg, p, dev->loop_vid_cap.width)); - goto update_vid_out_y; - } - if (dev->cur_scaled_line == vid_out_y) { - memcpy(vcapbuf + vid_cap_left, dev->scaled_line, - tpg_hdiv(tpg, p, dev->loop_vid_cap.width)); - goto update_vid_out_y; - } - if (!osdline) { - scale_line(voutbuf + vid_out_y * stride_out, dev->scaled_line, - tpg_hdiv(tpg, p, dev->loop_vid_out.width), - tpg_hdiv(tpg, p, dev->loop_vid_cap.width), - tpg_g_twopixelsize(tpg, p)); - } else { - /* - * Offset in bytes within loop_vid_copy to the start of the - * loop_vid_overlay rectangle. - */ - unsigned offset = - ((dev->loop_vid_overlay.left - dev->loop_vid_copy.left) * - twopixsize) / 2; - u8 *osd = vosdbuf + vid_overlay_y * stride_osd; - - scale_line(voutbuf + vid_out_y * stride_out, dev->blended_line, - dev->loop_vid_out.width, dev->loop_vid_copy.width, - tpg_g_twopixelsize(tpg, p)); - if (blend) - blend_line(dev, vid_overlay_y + dev->loop_vid_overlay.top, - dev->loop_vid_overlay.left, - dev->blended_line + offset, osd, - dev->loop_vid_overlay.width, twopixsize / 2); - else - memcpy(dev->blended_line + offset, - osd, (dev->loop_vid_overlay.width * twopixsize) / 2); - scale_line(dev->blended_line, dev->scaled_line, - dev->loop_vid_copy.width, dev->loop_vid_cap.width, - tpg_g_twopixelsize(tpg, p)); - } - dev->cur_scaled_line = vid_out_y; - memcpy(vcapbuf + vid_cap_left, dev->scaled_line, - tpg_hdiv(tpg, p, dev->loop_vid_cap.width)); - -update_vid_out_y: - if (osdline) { - vid_overlay_y += vid_overlay_int_part; - vid_overlay_error += vid_overlay_fract_part; - if (vid_overlay_error >= dev->loop_vid_overlay_cap.height) { - vid_overlay_error -= dev->loop_vid_overlay_cap.height; - vid_overlay_y++; - } - } - vid_out_y += vid_out_int_part; - vid_out_error += vid_out_fract_part; - if (vid_out_error >= dev->loop_vid_cap.height / vdiv) { - vid_out_error -= dev->loop_vid_cap.height / vdiv; - vid_out_y++; - } - } - - if (!blank) - return 0; - for (; y < img_height; y += vdiv, vcapbuf += stride_cap) - memcpy(vcapbuf, tpg->contrast_line[p], img_width); - return 0; -} - -static void vivid_fillbuff(struct vivid_dev *dev, struct vivid_buffer *buf) -{ - struct tpg_data *tpg = &dev->tpg; - unsigned factor = V4L2_FIELD_HAS_T_OR_B(dev->field_cap) ? 2 : 1; - unsigned line_height = 16 / factor; - bool is_tv = vivid_is_sdtv_cap(dev); - bool is_60hz = is_tv && (dev->std_cap[dev->input] & V4L2_STD_525_60); - unsigned p; - int line = 1; - u8 *basep[TPG_MAX_PLANES][2]; - unsigned ms; - char str[100]; - s32 gain; - bool is_loop = false; - - if (dev->loop_video && dev->can_loop_video && - ((vivid_is_svid_cap(dev) && - !VIVID_INVALID_SIGNAL(dev->std_signal_mode[dev->input])) || - (vivid_is_hdmi_cap(dev) && - !VIVID_INVALID_SIGNAL(dev->dv_timings_signal_mode[dev->input])))) - is_loop = true; - - buf->vb.sequence = dev->vid_cap_seq_count; - if (dev->field_cap == V4L2_FIELD_ALTERNATE) { - /* - * 60 Hz standards start with the bottom field, 50 Hz standards - * with the top field. So if the 0-based seq_count is even, - * then the field is TOP for 50 Hz and BOTTOM for 60 Hz - * standards. - */ - buf->vb.field = ((dev->vid_cap_seq_count & 1) ^ is_60hz) ? - V4L2_FIELD_BOTTOM : V4L2_FIELD_TOP; - /* - * The sequence counter counts frames, not fields. So divide - * by two. - */ - buf->vb.sequence /= 2; - } else { - buf->vb.field = dev->field_cap; - } - tpg_s_field(tpg, buf->vb.field, - dev->field_cap == V4L2_FIELD_ALTERNATE); - tpg_s_perc_fill_blank(tpg, dev->must_blank[buf->vb.vb2_buf.index]); - - vivid_precalc_copy_rects(dev); - - for (p = 0; p < tpg_g_planes(tpg); p++) { - void *vbuf = plane_vaddr(tpg, buf, p, - tpg->bytesperline, tpg->buf_height); - - /* - * The first plane of a multiplanar format has a non-zero - * data_offset. This helps testing whether the application - * correctly supports non-zero data offsets. - */ - if (p < tpg_g_buffers(tpg) && dev->fmt_cap->data_offset[p]) { - memset(vbuf, dev->fmt_cap->data_offset[p] & 0xff, - dev->fmt_cap->data_offset[p]); - vbuf += dev->fmt_cap->data_offset[p]; - } - tpg_calc_text_basep(tpg, basep, p, vbuf); - if (!is_loop || vivid_copy_buffer(dev, p, vbuf, buf)) - tpg_fill_plane_buffer(tpg, vivid_get_std_cap(dev), - p, vbuf); - } - dev->must_blank[buf->vb.vb2_buf.index] = false; - - /* Updates stream time, only update at the start of a new frame. */ - if (dev->field_cap != V4L2_FIELD_ALTERNATE || - (dev->vid_cap_seq_count & 1) == 0) - dev->ms_vid_cap = - jiffies_to_msecs(jiffies - dev->jiffies_vid_cap); - - ms = dev->ms_vid_cap; - if (dev->osd_mode <= 1) { - snprintf(str, sizeof(str), " %02d:%02d:%02d:%03d %u%s", - (ms / (60 * 60 * 1000)) % 24, - (ms / (60 * 1000)) % 60, - (ms / 1000) % 60, - ms % 1000, - buf->vb.sequence, - (dev->field_cap == V4L2_FIELD_ALTERNATE) ? - (buf->vb.field == V4L2_FIELD_TOP ? - " top" : " bottom") : ""); - tpg_gen_text(tpg, basep, line++ * line_height, 16, str); - } - if (dev->osd_mode == 0) { - snprintf(str, sizeof(str), " %dx%d, input %d ", - dev->src_rect.width, dev->src_rect.height, dev->input); - tpg_gen_text(tpg, basep, line++ * line_height, 16, str); - - gain = v4l2_ctrl_g_ctrl(dev->gain); - mutex_lock(dev->ctrl_hdl_user_vid.lock); - snprintf(str, sizeof(str), - " brightness %3d, contrast %3d, saturation %3d, hue %d ", - dev->brightness->cur.val, - dev->contrast->cur.val, - dev->saturation->cur.val, - dev->hue->cur.val); - tpg_gen_text(tpg, basep, line++ * line_height, 16, str); - snprintf(str, sizeof(str), - " autogain %d, gain %3d, alpha 0x%02x ", - dev->autogain->cur.val, gain, dev->alpha->cur.val); - mutex_unlock(dev->ctrl_hdl_user_vid.lock); - tpg_gen_text(tpg, basep, line++ * line_height, 16, str); - mutex_lock(dev->ctrl_hdl_user_aud.lock); - snprintf(str, sizeof(str), - " volume %3d, mute %d ", - dev->volume->cur.val, dev->mute->cur.val); - mutex_unlock(dev->ctrl_hdl_user_aud.lock); - tpg_gen_text(tpg, basep, line++ * line_height, 16, str); - mutex_lock(dev->ctrl_hdl_user_gen.lock); - snprintf(str, sizeof(str), " int32 %d, int64 %lld, bitmask %08x ", - dev->int32->cur.val, - *dev->int64->p_cur.p_s64, - dev->bitmask->cur.val); - tpg_gen_text(tpg, basep, line++ * line_height, 16, str); - snprintf(str, sizeof(str), " boolean %d, menu %s, string \"%s\" ", - dev->boolean->cur.val, - dev->menu->qmenu[dev->menu->cur.val], - dev->string->p_cur.p_char); - tpg_gen_text(tpg, basep, line++ * line_height, 16, str); - snprintf(str, sizeof(str), " integer_menu %lld, value %d ", - dev->int_menu->qmenu_int[dev->int_menu->cur.val], - dev->int_menu->cur.val); - mutex_unlock(dev->ctrl_hdl_user_gen.lock); - tpg_gen_text(tpg, basep, line++ * line_height, 16, str); - if (dev->button_pressed) { - dev->button_pressed--; - snprintf(str, sizeof(str), " button pressed!"); - tpg_gen_text(tpg, basep, line++ * line_height, 16, str); - } - if (dev->osd[0]) { - if (vivid_is_hdmi_cap(dev)) { - snprintf(str, sizeof(str), - " OSD \"%s\"", dev->osd); - tpg_gen_text(tpg, basep, line++ * line_height, - 16, str); - } - if (dev->osd_jiffies && - time_is_before_jiffies(dev->osd_jiffies + 5 * HZ)) { - dev->osd[0] = 0; - dev->osd_jiffies = 0; - } - } - } -} - -/* - * Return true if this pixel coordinate is a valid video pixel. - */ -static bool valid_pix(struct vivid_dev *dev, int win_y, int win_x, int fb_y, int fb_x) -{ - int i; - - if (dev->bitmap_cap) { - /* - * Only if the corresponding bit in the bitmap is set can - * the video pixel be shown. Coordinates are relative to - * the overlay window set by VIDIOC_S_FMT. - */ - const u8 *p = dev->bitmap_cap; - unsigned stride = (dev->compose_cap.width + 7) / 8; - - if (!(p[stride * win_y + win_x / 8] & (1 << (win_x & 7)))) - return false; - } - - for (i = 0; i < dev->clipcount_cap; i++) { - /* - * Only if the framebuffer coordinate is not in any of the - * clip rectangles will be video pixel be shown. - */ - struct v4l2_rect *r = &dev->clips_cap[i].c; - - if (fb_y >= r->top && fb_y < r->top + r->height && - fb_x >= r->left && fb_x < r->left + r->width) - return false; - } - return true; -} - -/* - * Draw the image into the overlay buffer. - * Note that the combination of overlay and multiplanar is not supported. - */ -static void vivid_overlay(struct vivid_dev *dev, struct vivid_buffer *buf) -{ - struct tpg_data *tpg = &dev->tpg; - unsigned pixsize = tpg_g_twopixelsize(tpg, 0) / 2; - void *vbase = dev->fb_vbase_cap; - void *vbuf = vb2_plane_vaddr(&buf->vb.vb2_buf, 0); - unsigned img_width = dev->compose_cap.width; - unsigned img_height = dev->compose_cap.height; - unsigned stride = tpg->bytesperline[0]; - /* if quick is true, then valid_pix() doesn't have to be called */ - bool quick = dev->bitmap_cap == NULL && dev->clipcount_cap == 0; - int x, y, w, out_x = 0; - - /* - * Overlay support is only supported for formats that have a twopixelsize - * that's >= 2. Warn and bail out if that's not the case. - */ - if (WARN_ON(pixsize == 0)) - return; - if ((dev->overlay_cap_field == V4L2_FIELD_TOP || - dev->overlay_cap_field == V4L2_FIELD_BOTTOM) && - dev->overlay_cap_field != buf->vb.field) - return; - - vbuf += dev->compose_cap.left * pixsize + dev->compose_cap.top * stride; - x = dev->overlay_cap_left; - w = img_width; - if (x < 0) { - out_x = -x; - w = w - out_x; - x = 0; - } else { - w = dev->fb_cap.fmt.width - x; - if (w > img_width) - w = img_width; - } - if (w <= 0) - return; - if (dev->overlay_cap_top >= 0) - vbase += dev->overlay_cap_top * dev->fb_cap.fmt.bytesperline; - for (y = dev->overlay_cap_top; - y < dev->overlay_cap_top + (int)img_height; - y++, vbuf += stride) { - int px; - - if (y < 0 || y > dev->fb_cap.fmt.height) - continue; - if (quick) { - memcpy(vbase + x * pixsize, - vbuf + out_x * pixsize, w * pixsize); - vbase += dev->fb_cap.fmt.bytesperline; - continue; - } - for (px = 0; px < w; px++) { - if (!valid_pix(dev, y - dev->overlay_cap_top, - px + out_x, y, px + x)) - continue; - memcpy(vbase + (px + x) * pixsize, - vbuf + (px + out_x) * pixsize, - pixsize); - } - vbase += dev->fb_cap.fmt.bytesperline; - } -} - -static void vivid_cap_update_frame_period(struct vivid_dev *dev) -{ - u64 f_period; - - f_period = (u64)dev->timeperframe_vid_cap.numerator * 1000000000; - if (WARN_ON(dev->timeperframe_vid_cap.denominator == 0)) - dev->timeperframe_vid_cap.denominator = 1; - do_div(f_period, dev->timeperframe_vid_cap.denominator); - if (dev->field_cap == V4L2_FIELD_ALTERNATE) - f_period >>= 1; - /* - * If "End of Frame", then offset the exposure time by 0.9 - * of the frame period. - */ - dev->cap_frame_eof_offset = f_period * 9; - do_div(dev->cap_frame_eof_offset, 10); - dev->cap_frame_period = f_period; -} - -static noinline_for_stack void vivid_thread_vid_cap_tick(struct vivid_dev *dev, - int dropped_bufs) -{ - struct vivid_buffer *vid_cap_buf = NULL; - struct vivid_buffer *vbi_cap_buf = NULL; - struct vivid_buffer *meta_cap_buf = NULL; - u64 f_time = 0; - - dprintk(dev, 1, "Video Capture Thread Tick\n"); - - while (dropped_bufs-- > 1) - tpg_update_mv_count(&dev->tpg, - dev->field_cap == V4L2_FIELD_NONE || - dev->field_cap == V4L2_FIELD_ALTERNATE); - - /* Drop a certain percentage of buffers. */ - if (dev->perc_dropped_buffers && - prandom_u32_max(100) < dev->perc_dropped_buffers) - goto update_mv; - - spin_lock(&dev->slock); - if (!list_empty(&dev->vid_cap_active)) { - vid_cap_buf = list_entry(dev->vid_cap_active.next, struct vivid_buffer, list); - list_del(&vid_cap_buf->list); - } - if (!list_empty(&dev->vbi_cap_active)) { - if (dev->field_cap != V4L2_FIELD_ALTERNATE || - (dev->vbi_cap_seq_count & 1)) { - vbi_cap_buf = list_entry(dev->vbi_cap_active.next, - struct vivid_buffer, list); - list_del(&vbi_cap_buf->list); - } - } - if (!list_empty(&dev->meta_cap_active)) { - meta_cap_buf = list_entry(dev->meta_cap_active.next, - struct vivid_buffer, list); - list_del(&meta_cap_buf->list); - } - - spin_unlock(&dev->slock); - - if (!vid_cap_buf && !vbi_cap_buf && !meta_cap_buf) - goto update_mv; - - f_time = dev->cap_frame_period * dev->vid_cap_seq_count + - dev->cap_stream_start + dev->time_wrap_offset; - - if (vid_cap_buf) { - v4l2_ctrl_request_setup(vid_cap_buf->vb.vb2_buf.req_obj.req, - &dev->ctrl_hdl_vid_cap); - /* Fill buffer */ - vivid_fillbuff(dev, vid_cap_buf); - dprintk(dev, 1, "filled buffer %d\n", - vid_cap_buf->vb.vb2_buf.index); - - /* Handle overlay */ - if (dev->overlay_cap_owner && dev->fb_cap.base && - dev->fb_cap.fmt.pixelformat == dev->fmt_cap->fourcc) - vivid_overlay(dev, vid_cap_buf); - - v4l2_ctrl_request_complete(vid_cap_buf->vb.vb2_buf.req_obj.req, - &dev->ctrl_hdl_vid_cap); - vb2_buffer_done(&vid_cap_buf->vb.vb2_buf, dev->dqbuf_error ? - VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE); - dprintk(dev, 2, "vid_cap buffer %d done\n", - vid_cap_buf->vb.vb2_buf.index); - - vid_cap_buf->vb.vb2_buf.timestamp = f_time; - if (!dev->tstamp_src_is_soe) - vid_cap_buf->vb.vb2_buf.timestamp += dev->cap_frame_eof_offset; - } - - if (vbi_cap_buf) { - u64 vbi_period; - - v4l2_ctrl_request_setup(vbi_cap_buf->vb.vb2_buf.req_obj.req, - &dev->ctrl_hdl_vbi_cap); - if (dev->stream_sliced_vbi_cap) - vivid_sliced_vbi_cap_process(dev, vbi_cap_buf); - else - vivid_raw_vbi_cap_process(dev, vbi_cap_buf); - v4l2_ctrl_request_complete(vbi_cap_buf->vb.vb2_buf.req_obj.req, - &dev->ctrl_hdl_vbi_cap); - vb2_buffer_done(&vbi_cap_buf->vb.vb2_buf, dev->dqbuf_error ? - VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE); - dprintk(dev, 2, "vbi_cap %d done\n", - vbi_cap_buf->vb.vb2_buf.index); - - /* If capturing a VBI, offset by 0.05 */ - vbi_period = dev->cap_frame_period * 5; - do_div(vbi_period, 100); - vbi_cap_buf->vb.vb2_buf.timestamp = f_time + dev->cap_frame_eof_offset + vbi_period; - } - - if (meta_cap_buf) { - v4l2_ctrl_request_setup(meta_cap_buf->vb.vb2_buf.req_obj.req, - &dev->ctrl_hdl_meta_cap); - vivid_meta_cap_fillbuff(dev, meta_cap_buf, f_time); - v4l2_ctrl_request_complete(meta_cap_buf->vb.vb2_buf.req_obj.req, - &dev->ctrl_hdl_meta_cap); - vb2_buffer_done(&meta_cap_buf->vb.vb2_buf, dev->dqbuf_error ? - VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE); - dprintk(dev, 2, "meta_cap %d done\n", - meta_cap_buf->vb.vb2_buf.index); - meta_cap_buf->vb.vb2_buf.timestamp = f_time + dev->cap_frame_eof_offset; - } - - dev->dqbuf_error = false; - -update_mv: - /* Update the test pattern movement counters */ - tpg_update_mv_count(&dev->tpg, dev->field_cap == V4L2_FIELD_NONE || - dev->field_cap == V4L2_FIELD_ALTERNATE); -} - -static int vivid_thread_vid_cap(void *data) -{ - struct vivid_dev *dev = data; - u64 numerators_since_start; - u64 buffers_since_start; - u64 next_jiffies_since_start; - unsigned long jiffies_since_start; - unsigned long cur_jiffies; - unsigned wait_jiffies; - unsigned numerator; - unsigned denominator; - int dropped_bufs; - - dprintk(dev, 1, "Video Capture Thread Start\n"); - - set_freezable(); - - /* Resets frame counters */ - dev->cap_seq_offset = 0; - dev->cap_seq_count = 0; - dev->cap_seq_resync = false; - dev->jiffies_vid_cap = jiffies; - dev->cap_stream_start = ktime_get_ns(); - vivid_cap_update_frame_period(dev); - - for (;;) { - try_to_freeze(); - if (kthread_should_stop()) - break; - - if (!mutex_trylock(&dev->mutex)) { - schedule_timeout_uninterruptible(1); - continue; - } - - cur_jiffies = jiffies; - if (dev->cap_seq_resync) { - dev->jiffies_vid_cap = cur_jiffies; - dev->cap_seq_offset = dev->cap_seq_count + 1; - dev->cap_seq_count = 0; - dev->cap_stream_start += dev->cap_frame_period * - dev->cap_seq_offset; - vivid_cap_update_frame_period(dev); - dev->cap_seq_resync = false; - } - numerator = dev->timeperframe_vid_cap.numerator; - denominator = dev->timeperframe_vid_cap.denominator; - - if (dev->field_cap == V4L2_FIELD_ALTERNATE) - denominator *= 2; - - /* Calculate the number of jiffies since we started streaming */ - jiffies_since_start = cur_jiffies - dev->jiffies_vid_cap; - /* Get the number of buffers streamed since the start */ - buffers_since_start = (u64)jiffies_since_start * denominator + - (HZ * numerator) / 2; - do_div(buffers_since_start, HZ * numerator); - - /* - * After more than 0xf0000000 (rounded down to a multiple of - * 'jiffies-per-day' to ease jiffies_to_msecs calculation) - * jiffies have passed since we started streaming reset the - * counters and keep track of the sequence offset. - */ - if (jiffies_since_start > JIFFIES_RESYNC) { - dev->jiffies_vid_cap = cur_jiffies; - dev->cap_seq_offset = buffers_since_start; - buffers_since_start = 0; - } - dropped_bufs = buffers_since_start + dev->cap_seq_offset - dev->cap_seq_count; - dev->cap_seq_count = buffers_since_start + dev->cap_seq_offset; - dev->vid_cap_seq_count = dev->cap_seq_count - dev->vid_cap_seq_start; - dev->vbi_cap_seq_count = dev->cap_seq_count - dev->vbi_cap_seq_start; - dev->meta_cap_seq_count = dev->cap_seq_count - dev->meta_cap_seq_start; - - vivid_thread_vid_cap_tick(dev, dropped_bufs); - - /* - * Calculate the number of 'numerators' streamed since we started, - * including the current buffer. - */ - numerators_since_start = ++buffers_since_start * numerator; - - /* And the number of jiffies since we started */ - jiffies_since_start = jiffies - dev->jiffies_vid_cap; - - mutex_unlock(&dev->mutex); - - /* - * Calculate when that next buffer is supposed to start - * in jiffies since we started streaming. - */ - next_jiffies_since_start = numerators_since_start * HZ + - denominator / 2; - do_div(next_jiffies_since_start, denominator); - /* If it is in the past, then just schedule asap */ - if (next_jiffies_since_start < jiffies_since_start) - next_jiffies_since_start = jiffies_since_start; - - wait_jiffies = next_jiffies_since_start - jiffies_since_start; - schedule_timeout_interruptible(wait_jiffies ? wait_jiffies : 1); - } - dprintk(dev, 1, "Video Capture Thread End\n"); - return 0; -} - -static void vivid_grab_controls(struct vivid_dev *dev, bool grab) -{ - v4l2_ctrl_grab(dev->ctrl_has_crop_cap, grab); - v4l2_ctrl_grab(dev->ctrl_has_compose_cap, grab); - v4l2_ctrl_grab(dev->ctrl_has_scaler_cap, grab); -} - -int vivid_start_generating_vid_cap(struct vivid_dev *dev, bool *pstreaming) -{ - dprintk(dev, 1, "%s\n", __func__); - - if (dev->kthread_vid_cap) { - u32 seq_count = dev->cap_seq_count + dev->seq_wrap * 128; - - if (pstreaming == &dev->vid_cap_streaming) - dev->vid_cap_seq_start = seq_count; - else if (pstreaming == &dev->vbi_cap_streaming) - dev->vbi_cap_seq_start = seq_count; - else - dev->meta_cap_seq_start = seq_count; - *pstreaming = true; - return 0; - } - - /* Resets frame counters */ - tpg_init_mv_count(&dev->tpg); - - dev->vid_cap_seq_start = dev->seq_wrap * 128; - dev->vbi_cap_seq_start = dev->seq_wrap * 128; - dev->meta_cap_seq_start = dev->seq_wrap * 128; - - dev->kthread_vid_cap = kthread_run(vivid_thread_vid_cap, dev, - "%s-vid-cap", dev->v4l2_dev.name); - - if (IS_ERR(dev->kthread_vid_cap)) { - int err = PTR_ERR(dev->kthread_vid_cap); - - dev->kthread_vid_cap = NULL; - v4l2_err(&dev->v4l2_dev, "kernel_thread() failed\n"); - return err; - } - *pstreaming = true; - vivid_grab_controls(dev, true); - - dprintk(dev, 1, "returning from %s\n", __func__); - return 0; -} - -void vivid_stop_generating_vid_cap(struct vivid_dev *dev, bool *pstreaming) -{ - dprintk(dev, 1, "%s\n", __func__); - - if (dev->kthread_vid_cap == NULL) - return; - - *pstreaming = false; - if (pstreaming == &dev->vid_cap_streaming) { - /* Release all active buffers */ - while (!list_empty(&dev->vid_cap_active)) { - struct vivid_buffer *buf; - - buf = list_entry(dev->vid_cap_active.next, - struct vivid_buffer, list); - list_del(&buf->list); - v4l2_ctrl_request_complete(buf->vb.vb2_buf.req_obj.req, - &dev->ctrl_hdl_vid_cap); - vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); - dprintk(dev, 2, "vid_cap buffer %d done\n", - buf->vb.vb2_buf.index); - } - } - - if (pstreaming == &dev->vbi_cap_streaming) { - while (!list_empty(&dev->vbi_cap_active)) { - struct vivid_buffer *buf; - - buf = list_entry(dev->vbi_cap_active.next, - struct vivid_buffer, list); - list_del(&buf->list); - v4l2_ctrl_request_complete(buf->vb.vb2_buf.req_obj.req, - &dev->ctrl_hdl_vbi_cap); - vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); - dprintk(dev, 2, "vbi_cap buffer %d done\n", - buf->vb.vb2_buf.index); - } - } - - if (pstreaming == &dev->meta_cap_streaming) { - while (!list_empty(&dev->meta_cap_active)) { - struct vivid_buffer *buf; - - buf = list_entry(dev->meta_cap_active.next, - struct vivid_buffer, list); - list_del(&buf->list); - v4l2_ctrl_request_complete(buf->vb.vb2_buf.req_obj.req, - &dev->ctrl_hdl_meta_cap); - vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); - dprintk(dev, 2, "meta_cap buffer %d done\n", - buf->vb.vb2_buf.index); - } - } - - if (dev->vid_cap_streaming || dev->vbi_cap_streaming || - dev->meta_cap_streaming) - return; - - /* shutdown control thread */ - vivid_grab_controls(dev, false); - kthread_stop(dev->kthread_vid_cap); - dev->kthread_vid_cap = NULL; -} diff --git a/drivers/media/platform/vivid/vivid-kthread-cap.h b/drivers/media/platform/vivid/vivid-kthread-cap.h deleted file mode 100644 index 0f43015306d6..000000000000 --- a/drivers/media/platform/vivid/vivid-kthread-cap.h +++ /dev/null @@ -1,14 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * vivid-kthread-cap.h - video/vbi capture thread support functions. - * - * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - */ - -#ifndef _VIVID_KTHREAD_CAP_H_ -#define _VIVID_KTHREAD_CAP_H_ - -int vivid_start_generating_vid_cap(struct vivid_dev *dev, bool *pstreaming); -void vivid_stop_generating_vid_cap(struct vivid_dev *dev, bool *pstreaming); - -#endif diff --git a/drivers/media/platform/vivid/vivid-kthread-out.c b/drivers/media/platform/vivid/vivid-kthread-out.c deleted file mode 100644 index 6780687978f9..000000000000 --- a/drivers/media/platform/vivid/vivid-kthread-out.c +++ /dev/null @@ -1,353 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * vivid-kthread-out.h - video/vbi output thread support functions. - * - * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "vivid-core.h" -#include "vivid-vid-common.h" -#include "vivid-vid-cap.h" -#include "vivid-vid-out.h" -#include "vivid-radio-common.h" -#include "vivid-radio-rx.h" -#include "vivid-radio-tx.h" -#include "vivid-sdr-cap.h" -#include "vivid-vbi-cap.h" -#include "vivid-vbi-out.h" -#include "vivid-osd.h" -#include "vivid-ctrls.h" -#include "vivid-kthread-out.h" -#include "vivid-meta-out.h" - -static void vivid_thread_vid_out_tick(struct vivid_dev *dev) -{ - struct vivid_buffer *vid_out_buf = NULL; - struct vivid_buffer *vbi_out_buf = NULL; - struct vivid_buffer *meta_out_buf = NULL; - - dprintk(dev, 1, "Video Output Thread Tick\n"); - - /* Drop a certain percentage of buffers. */ - if (dev->perc_dropped_buffers && - prandom_u32_max(100) < dev->perc_dropped_buffers) - return; - - spin_lock(&dev->slock); - /* - * Only dequeue buffer if there is at least one more pending. - * This makes video loopback possible. - */ - if (!list_empty(&dev->vid_out_active) && - !list_is_singular(&dev->vid_out_active)) { - vid_out_buf = list_entry(dev->vid_out_active.next, - struct vivid_buffer, list); - list_del(&vid_out_buf->list); - } - if (!list_empty(&dev->vbi_out_active) && - (dev->field_out != V4L2_FIELD_ALTERNATE || - (dev->vbi_out_seq_count & 1))) { - vbi_out_buf = list_entry(dev->vbi_out_active.next, - struct vivid_buffer, list); - list_del(&vbi_out_buf->list); - } - if (!list_empty(&dev->meta_out_active)) { - meta_out_buf = list_entry(dev->meta_out_active.next, - struct vivid_buffer, list); - list_del(&meta_out_buf->list); - } - spin_unlock(&dev->slock); - - if (!vid_out_buf && !vbi_out_buf && !meta_out_buf) - return; - - if (vid_out_buf) { - v4l2_ctrl_request_setup(vid_out_buf->vb.vb2_buf.req_obj.req, - &dev->ctrl_hdl_vid_out); - v4l2_ctrl_request_complete(vid_out_buf->vb.vb2_buf.req_obj.req, - &dev->ctrl_hdl_vid_out); - vid_out_buf->vb.sequence = dev->vid_out_seq_count; - if (dev->field_out == V4L2_FIELD_ALTERNATE) { - /* - * The sequence counter counts frames, not fields. - * So divide by two. - */ - vid_out_buf->vb.sequence /= 2; - } - vid_out_buf->vb.vb2_buf.timestamp = - ktime_get_ns() + dev->time_wrap_offset; - vb2_buffer_done(&vid_out_buf->vb.vb2_buf, dev->dqbuf_error ? - VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE); - dprintk(dev, 2, "vid_out buffer %d done\n", - vid_out_buf->vb.vb2_buf.index); - } - - if (vbi_out_buf) { - v4l2_ctrl_request_setup(vbi_out_buf->vb.vb2_buf.req_obj.req, - &dev->ctrl_hdl_vbi_out); - v4l2_ctrl_request_complete(vbi_out_buf->vb.vb2_buf.req_obj.req, - &dev->ctrl_hdl_vbi_out); - if (dev->stream_sliced_vbi_out) - vivid_sliced_vbi_out_process(dev, vbi_out_buf); - - vbi_out_buf->vb.sequence = dev->vbi_out_seq_count; - vbi_out_buf->vb.vb2_buf.timestamp = - ktime_get_ns() + dev->time_wrap_offset; - vb2_buffer_done(&vbi_out_buf->vb.vb2_buf, dev->dqbuf_error ? - VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE); - dprintk(dev, 2, "vbi_out buffer %d done\n", - vbi_out_buf->vb.vb2_buf.index); - } - if (meta_out_buf) { - v4l2_ctrl_request_setup(meta_out_buf->vb.vb2_buf.req_obj.req, - &dev->ctrl_hdl_meta_out); - v4l2_ctrl_request_complete(meta_out_buf->vb.vb2_buf.req_obj.req, - &dev->ctrl_hdl_meta_out); - vivid_meta_out_process(dev, meta_out_buf); - meta_out_buf->vb.sequence = dev->meta_out_seq_count; - meta_out_buf->vb.vb2_buf.timestamp = - ktime_get_ns() + dev->time_wrap_offset; - vb2_buffer_done(&meta_out_buf->vb.vb2_buf, dev->dqbuf_error ? - VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE); - dprintk(dev, 2, "meta_out buffer %d done\n", - meta_out_buf->vb.vb2_buf.index); - } - - dev->dqbuf_error = false; -} - -static int vivid_thread_vid_out(void *data) -{ - struct vivid_dev *dev = data; - u64 numerators_since_start; - u64 buffers_since_start; - u64 next_jiffies_since_start; - unsigned long jiffies_since_start; - unsigned long cur_jiffies; - unsigned wait_jiffies; - unsigned numerator; - unsigned denominator; - - dprintk(dev, 1, "Video Output Thread Start\n"); - - set_freezable(); - - /* Resets frame counters */ - dev->out_seq_offset = 0; - if (dev->seq_wrap) - dev->out_seq_count = 0xffffff80U; - dev->jiffies_vid_out = jiffies; - dev->vid_out_seq_start = dev->vbi_out_seq_start = 0; - dev->meta_out_seq_start = 0; - dev->out_seq_resync = false; - - for (;;) { - try_to_freeze(); - if (kthread_should_stop()) - break; - - if (!mutex_trylock(&dev->mutex)) { - schedule_timeout_uninterruptible(1); - continue; - } - - cur_jiffies = jiffies; - if (dev->out_seq_resync) { - dev->jiffies_vid_out = cur_jiffies; - dev->out_seq_offset = dev->out_seq_count + 1; - dev->out_seq_count = 0; - dev->out_seq_resync = false; - } - numerator = dev->timeperframe_vid_out.numerator; - denominator = dev->timeperframe_vid_out.denominator; - - if (dev->field_out == V4L2_FIELD_ALTERNATE) - denominator *= 2; - - /* Calculate the number of jiffies since we started streaming */ - jiffies_since_start = cur_jiffies - dev->jiffies_vid_out; - /* Get the number of buffers streamed since the start */ - buffers_since_start = (u64)jiffies_since_start * denominator + - (HZ * numerator) / 2; - do_div(buffers_since_start, HZ * numerator); - - /* - * After more than 0xf0000000 (rounded down to a multiple of - * 'jiffies-per-day' to ease jiffies_to_msecs calculation) - * jiffies have passed since we started streaming reset the - * counters and keep track of the sequence offset. - */ - if (jiffies_since_start > JIFFIES_RESYNC) { - dev->jiffies_vid_out = cur_jiffies; - dev->out_seq_offset = buffers_since_start; - buffers_since_start = 0; - } - dev->out_seq_count = buffers_since_start + dev->out_seq_offset; - dev->vid_out_seq_count = dev->out_seq_count - dev->vid_out_seq_start; - dev->vbi_out_seq_count = dev->out_seq_count - dev->vbi_out_seq_start; - dev->meta_out_seq_count = dev->out_seq_count - dev->meta_out_seq_start; - - vivid_thread_vid_out_tick(dev); - mutex_unlock(&dev->mutex); - - /* - * Calculate the number of 'numerators' streamed since we started, - * not including the current buffer. - */ - numerators_since_start = buffers_since_start * numerator; - - /* And the number of jiffies since we started */ - jiffies_since_start = jiffies - dev->jiffies_vid_out; - - /* Increase by the 'numerator' of one buffer */ - numerators_since_start += numerator; - /* - * Calculate when that next buffer is supposed to start - * in jiffies since we started streaming. - */ - next_jiffies_since_start = numerators_since_start * HZ + - denominator / 2; - do_div(next_jiffies_since_start, denominator); - /* If it is in the past, then just schedule asap */ - if (next_jiffies_since_start < jiffies_since_start) - next_jiffies_since_start = jiffies_since_start; - - wait_jiffies = next_jiffies_since_start - jiffies_since_start; - schedule_timeout_interruptible(wait_jiffies ? wait_jiffies : 1); - } - dprintk(dev, 1, "Video Output Thread End\n"); - return 0; -} - -static void vivid_grab_controls(struct vivid_dev *dev, bool grab) -{ - v4l2_ctrl_grab(dev->ctrl_has_crop_out, grab); - v4l2_ctrl_grab(dev->ctrl_has_compose_out, grab); - v4l2_ctrl_grab(dev->ctrl_has_scaler_out, grab); - v4l2_ctrl_grab(dev->ctrl_tx_mode, grab); - v4l2_ctrl_grab(dev->ctrl_tx_rgb_range, grab); -} - -int vivid_start_generating_vid_out(struct vivid_dev *dev, bool *pstreaming) -{ - dprintk(dev, 1, "%s\n", __func__); - - if (dev->kthread_vid_out) { - u32 seq_count = dev->out_seq_count + dev->seq_wrap * 128; - - if (pstreaming == &dev->vid_out_streaming) - dev->vid_out_seq_start = seq_count; - else if (pstreaming == &dev->vbi_out_streaming) - dev->vbi_out_seq_start = seq_count; - else - dev->meta_out_seq_start = seq_count; - *pstreaming = true; - return 0; - } - - /* Resets frame counters */ - dev->jiffies_vid_out = jiffies; - dev->vid_out_seq_start = dev->seq_wrap * 128; - dev->vbi_out_seq_start = dev->seq_wrap * 128; - dev->meta_out_seq_start = dev->seq_wrap * 128; - - dev->kthread_vid_out = kthread_run(vivid_thread_vid_out, dev, - "%s-vid-out", dev->v4l2_dev.name); - - if (IS_ERR(dev->kthread_vid_out)) { - int err = PTR_ERR(dev->kthread_vid_out); - - dev->kthread_vid_out = NULL; - v4l2_err(&dev->v4l2_dev, "kernel_thread() failed\n"); - return err; - } - *pstreaming = true; - vivid_grab_controls(dev, true); - - dprintk(dev, 1, "returning from %s\n", __func__); - return 0; -} - -void vivid_stop_generating_vid_out(struct vivid_dev *dev, bool *pstreaming) -{ - dprintk(dev, 1, "%s\n", __func__); - - if (dev->kthread_vid_out == NULL) - return; - - *pstreaming = false; - if (pstreaming == &dev->vid_out_streaming) { - /* Release all active buffers */ - while (!list_empty(&dev->vid_out_active)) { - struct vivid_buffer *buf; - - buf = list_entry(dev->vid_out_active.next, - struct vivid_buffer, list); - list_del(&buf->list); - v4l2_ctrl_request_complete(buf->vb.vb2_buf.req_obj.req, - &dev->ctrl_hdl_vid_out); - vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); - dprintk(dev, 2, "vid_out buffer %d done\n", - buf->vb.vb2_buf.index); - } - } - - if (pstreaming == &dev->vbi_out_streaming) { - while (!list_empty(&dev->vbi_out_active)) { - struct vivid_buffer *buf; - - buf = list_entry(dev->vbi_out_active.next, - struct vivid_buffer, list); - list_del(&buf->list); - v4l2_ctrl_request_complete(buf->vb.vb2_buf.req_obj.req, - &dev->ctrl_hdl_vbi_out); - vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); - dprintk(dev, 2, "vbi_out buffer %d done\n", - buf->vb.vb2_buf.index); - } - } - - if (pstreaming == &dev->meta_out_streaming) { - while (!list_empty(&dev->meta_out_active)) { - struct vivid_buffer *buf; - - buf = list_entry(dev->meta_out_active.next, - struct vivid_buffer, list); - list_del(&buf->list); - v4l2_ctrl_request_complete(buf->vb.vb2_buf.req_obj.req, - &dev->ctrl_hdl_meta_out); - vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); - dprintk(dev, 2, "meta_out buffer %d done\n", - buf->vb.vb2_buf.index); - } - } - - if (dev->vid_out_streaming || dev->vbi_out_streaming || - dev->meta_out_streaming) - return; - - /* shutdown control thread */ - vivid_grab_controls(dev, false); - kthread_stop(dev->kthread_vid_out); - dev->kthread_vid_out = NULL; -} diff --git a/drivers/media/platform/vivid/vivid-kthread-out.h b/drivers/media/platform/vivid/vivid-kthread-out.h deleted file mode 100644 index d5bcf44bbaca..000000000000 --- a/drivers/media/platform/vivid/vivid-kthread-out.h +++ /dev/null @@ -1,14 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * vivid-kthread-out.h - video/vbi output thread support functions. - * - * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - */ - -#ifndef _VIVID_KTHREAD_OUT_H_ -#define _VIVID_KTHREAD_OUT_H_ - -int vivid_start_generating_vid_out(struct vivid_dev *dev, bool *pstreaming); -void vivid_stop_generating_vid_out(struct vivid_dev *dev, bool *pstreaming); - -#endif diff --git a/drivers/media/platform/vivid/vivid-kthread-touch.c b/drivers/media/platform/vivid/vivid-kthread-touch.c deleted file mode 100644 index 674507b5ccb5..000000000000 --- a/drivers/media/platform/vivid/vivid-kthread-touch.c +++ /dev/null @@ -1,181 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * vivid-kthread-touch.c - touch capture thread support functions. - * - */ - -#include -#include "vivid-core.h" -#include "vivid-kthread-touch.h" -#include "vivid-touch-cap.h" - -static noinline_for_stack void vivid_thread_tch_cap_tick(struct vivid_dev *dev, - int dropped_bufs) -{ - struct vivid_buffer *tch_cap_buf = NULL; - - spin_lock(&dev->slock); - if (!list_empty(&dev->touch_cap_active)) { - tch_cap_buf = list_entry(dev->touch_cap_active.next, - struct vivid_buffer, list); - list_del(&tch_cap_buf->list); - } - - spin_unlock(&dev->slock); - - if (tch_cap_buf) { - v4l2_ctrl_request_setup(tch_cap_buf->vb.vb2_buf.req_obj.req, - &dev->ctrl_hdl_touch_cap); - - vivid_fillbuff_tch(dev, tch_cap_buf); - v4l2_ctrl_request_complete(tch_cap_buf->vb.vb2_buf.req_obj.req, - &dev->ctrl_hdl_touch_cap); - vb2_buffer_done(&tch_cap_buf->vb.vb2_buf, dev->dqbuf_error ? - VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE); - dprintk(dev, 2, "touch_cap buffer %d done\n", - tch_cap_buf->vb.vb2_buf.index); - - tch_cap_buf->vb.vb2_buf.timestamp = ktime_get_ns() + dev->time_wrap_offset; - } - dev->dqbuf_error = false; -} - -static int vivid_thread_touch_cap(void *data) -{ - struct vivid_dev *dev = data; - u64 numerators_since_start; - u64 buffers_since_start; - u64 next_jiffies_since_start; - unsigned long jiffies_since_start; - unsigned long cur_jiffies; - unsigned int wait_jiffies; - unsigned int numerator; - unsigned int denominator; - int dropped_bufs; - - dprintk(dev, 1, "Touch Capture Thread Start\n"); - - set_freezable(); - - /* Resets frame counters */ - dev->touch_cap_seq_offset = 0; - dev->touch_cap_seq_count = 0; - dev->touch_cap_seq_resync = false; - dev->jiffies_touch_cap = jiffies; - - for (;;) { - try_to_freeze(); - if (kthread_should_stop()) - break; - - if (!mutex_trylock(&dev->mutex)) { - schedule_timeout_uninterruptible(1); - continue; - } - cur_jiffies = jiffies; - if (dev->touch_cap_seq_resync) { - dev->jiffies_touch_cap = cur_jiffies; - dev->touch_cap_seq_offset = dev->touch_cap_seq_count + 1; - dev->touch_cap_seq_count = 0; - dev->cap_seq_resync = false; - } - denominator = dev->timeperframe_tch_cap.denominator; - numerator = dev->timeperframe_tch_cap.numerator; - - /* Calculate the number of jiffies since we started streaming */ - jiffies_since_start = cur_jiffies - dev->jiffies_touch_cap; - /* Get the number of buffers streamed since the start */ - buffers_since_start = (u64)jiffies_since_start * denominator + - (HZ * numerator) / 2; - do_div(buffers_since_start, HZ * numerator); - - /* - * After more than 0xf0000000 (rounded down to a multiple of - * 'jiffies-per-day' to ease jiffies_to_msecs calculation) - * jiffies have passed since we started streaming reset the - * counters and keep track of the sequence offset. - */ - if (jiffies_since_start > JIFFIES_RESYNC) { - dev->jiffies_touch_cap = cur_jiffies; - dev->cap_seq_offset = buffers_since_start; - buffers_since_start = 0; - } - dropped_bufs = buffers_since_start + dev->touch_cap_seq_offset - dev->touch_cap_seq_count; - dev->touch_cap_seq_count = buffers_since_start + dev->touch_cap_seq_offset; - - vivid_thread_tch_cap_tick(dev, dropped_bufs); - - /* - * Calculate the number of 'numerators' streamed - * since we started, including the current buffer. - */ - numerators_since_start = ++buffers_since_start * numerator; - - /* And the number of jiffies since we started */ - jiffies_since_start = jiffies - dev->jiffies_touch_cap; - - mutex_unlock(&dev->mutex); - - /* - * Calculate when that next buffer is supposed to start - * in jiffies since we started streaming. - */ - next_jiffies_since_start = numerators_since_start * HZ + - denominator / 2; - do_div(next_jiffies_since_start, denominator); - /* If it is in the past, then just schedule asap */ - if (next_jiffies_since_start < jiffies_since_start) - next_jiffies_since_start = jiffies_since_start; - - wait_jiffies = next_jiffies_since_start - jiffies_since_start; - schedule_timeout_interruptible(wait_jiffies ? wait_jiffies : 1); - } - dprintk(dev, 1, "Touch Capture Thread End\n"); - return 0; -} - -int vivid_start_generating_touch_cap(struct vivid_dev *dev) -{ - if (dev->kthread_touch_cap) { - dev->touch_cap_streaming = true; - return 0; - } - - dev->kthread_touch_cap = kthread_run(vivid_thread_touch_cap, dev, - "%s-tch-cap", dev->v4l2_dev.name); - - if (IS_ERR(dev->kthread_touch_cap)) { - int err = PTR_ERR(dev->kthread_touch_cap); - - dev->kthread_touch_cap = NULL; - v4l2_err(&dev->v4l2_dev, "kernel_thread() failed\n"); - return err; - } - dev->touch_cap_streaming = true; - dprintk(dev, 1, "returning from %s\n", __func__); - return 0; -} - -void vivid_stop_generating_touch_cap(struct vivid_dev *dev) -{ - if (!dev->kthread_touch_cap) - return; - - dev->touch_cap_streaming = false; - - while (!list_empty(&dev->touch_cap_active)) { - struct vivid_buffer *buf; - - buf = list_entry(dev->touch_cap_active.next, - struct vivid_buffer, list); - list_del(&buf->list); - v4l2_ctrl_request_complete(buf->vb.vb2_buf.req_obj.req, - &dev->ctrl_hdl_touch_cap); - vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); - dprintk(dev, 2, "touch_cap buffer %d done\n", - buf->vb.vb2_buf.index); - } - - kthread_stop(dev->kthread_touch_cap); - dev->kthread_touch_cap = NULL; -} diff --git a/drivers/media/platform/vivid/vivid-kthread-touch.h b/drivers/media/platform/vivid/vivid-kthread-touch.h deleted file mode 100644 index ecf79b46209e..000000000000 --- a/drivers/media/platform/vivid/vivid-kthread-touch.h +++ /dev/null @@ -1,13 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * vivid-kthread-cap.h - video/vbi capture thread support functions. - * - */ - -#ifndef _VIVID_KTHREAD_CAP_H_ -#define _VIVID_KTHREAD_CAP_H_ - -int vivid_start_generating_touch_cap(struct vivid_dev *dev); -void vivid_stop_generating_touch_cap(struct vivid_dev *dev); - -#endif diff --git a/drivers/media/platform/vivid/vivid-meta-cap.c b/drivers/media/platform/vivid/vivid-meta-cap.c deleted file mode 100644 index 780f96860a6d..000000000000 --- a/drivers/media/platform/vivid/vivid-meta-cap.c +++ /dev/null @@ -1,201 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * vivid-meta-cap.c - meta capture support functions. - */ - -#include -#include -#include -#include -#include - -#include "vivid-core.h" -#include "vivid-kthread-cap.h" -#include "vivid-meta-cap.h" - -static int meta_cap_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, - unsigned int *nplanes, unsigned int sizes[], - struct device *alloc_devs[]) -{ - struct vivid_dev *dev = vb2_get_drv_priv(vq); - unsigned int size = sizeof(struct vivid_uvc_meta_buf); - - if (!vivid_is_webcam(dev)) - return -EINVAL; - - if (*nplanes) { - if (sizes[0] < size) - return -EINVAL; - } else { - sizes[0] = size; - } - - if (vq->num_buffers + *nbuffers < 2) - *nbuffers = 2 - vq->num_buffers; - - *nplanes = 1; - return 0; -} - -static int meta_cap_buf_prepare(struct vb2_buffer *vb) -{ - struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); - unsigned int size = sizeof(struct vivid_uvc_meta_buf); - - dprintk(dev, 1, "%s\n", __func__); - - if (dev->buf_prepare_error) { - /* - * Error injection: test what happens if buf_prepare() returns - * an error. - */ - dev->buf_prepare_error = false; - return -EINVAL; - } - if (vb2_plane_size(vb, 0) < size) { - dprintk(dev, 1, "%s data will not fit into plane (%lu < %u)\n", - __func__, vb2_plane_size(vb, 0), size); - return -EINVAL; - } - vb2_set_plane_payload(vb, 0, size); - - return 0; -} - -static void meta_cap_buf_queue(struct vb2_buffer *vb) -{ - struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); - struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); - struct vivid_buffer *buf = container_of(vbuf, struct vivid_buffer, vb); - - dprintk(dev, 1, "%s\n", __func__); - - spin_lock(&dev->slock); - list_add_tail(&buf->list, &dev->meta_cap_active); - spin_unlock(&dev->slock); -} - -static int meta_cap_start_streaming(struct vb2_queue *vq, unsigned int count) -{ - struct vivid_dev *dev = vb2_get_drv_priv(vq); - int err; - - dprintk(dev, 1, "%s\n", __func__); - dev->meta_cap_seq_count = 0; - if (dev->start_streaming_error) { - dev->start_streaming_error = false; - err = -EINVAL; - } else { - err = vivid_start_generating_vid_cap(dev, - &dev->meta_cap_streaming); - } - if (err) { - struct vivid_buffer *buf, *tmp; - - list_for_each_entry_safe(buf, tmp, - &dev->meta_cap_active, list) { - list_del(&buf->list); - vb2_buffer_done(&buf->vb.vb2_buf, - VB2_BUF_STATE_QUEUED); - } - } - return err; -} - -/* abort streaming and wait for last buffer */ -static void meta_cap_stop_streaming(struct vb2_queue *vq) -{ - struct vivid_dev *dev = vb2_get_drv_priv(vq); - - dprintk(dev, 1, "%s\n", __func__); - vivid_stop_generating_vid_cap(dev, &dev->meta_cap_streaming); -} - -static void meta_cap_buf_request_complete(struct vb2_buffer *vb) -{ - struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); - - v4l2_ctrl_request_complete(vb->req_obj.req, &dev->ctrl_hdl_meta_cap); -} - -const struct vb2_ops vivid_meta_cap_qops = { - .queue_setup = meta_cap_queue_setup, - .buf_prepare = meta_cap_buf_prepare, - .buf_queue = meta_cap_buf_queue, - .start_streaming = meta_cap_start_streaming, - .stop_streaming = meta_cap_stop_streaming, - .buf_request_complete = meta_cap_buf_request_complete, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, -}; - -int vidioc_enum_fmt_meta_cap(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - struct vivid_dev *dev = video_drvdata(file); - - if (!vivid_is_webcam(dev)) - return -EINVAL; - - if (f->index > 0) - return -EINVAL; - - f->type = V4L2_BUF_TYPE_META_CAPTURE; - f->pixelformat = V4L2_META_FMT_UVC; - return 0; -} - -int vidioc_g_fmt_meta_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct vivid_dev *dev = video_drvdata(file); - struct v4l2_meta_format *meta = &f->fmt.meta; - - if (!vivid_is_webcam(dev) || !dev->has_meta_cap) - return -EINVAL; - - meta->dataformat = V4L2_META_FMT_UVC; - meta->buffersize = sizeof(struct vivid_uvc_meta_buf); - return 0; -} - -void vivid_meta_cap_fillbuff(struct vivid_dev *dev, - struct vivid_buffer *buf, u64 soe) -{ - struct vivid_uvc_meta_buf *meta = vb2_plane_vaddr(&buf->vb.vb2_buf, 0); - int buf_off = 0; - - buf->vb.sequence = dev->meta_cap_seq_count; - if (dev->field_cap == V4L2_FIELD_ALTERNATE) - buf->vb.sequence /= 2; - memset(meta, 1, vb2_plane_size(&buf->vb.vb2_buf, 0)); - - meta->ns = ktime_get_ns(); - meta->sof = buf->vb.sequence * 30; - meta->length = sizeof(*meta) - offsetof(struct vivid_uvc_meta_buf, length); - meta->flags = UVC_STREAM_EOH | UVC_STREAM_EOF; - - if ((buf->vb.sequence % 2) == 0) - meta->flags |= UVC_STREAM_FID; - - dprintk(dev, 2, "%s ns:%llu sof:%4d len:%u flags: 0x%02x", - __func__, meta->ns, meta->sof, meta->length, meta->flags); - if (dev->meta_pts) { - meta->flags |= UVC_STREAM_PTS; - meta->buf[0] = div_u64(soe, VIVID_META_CLOCK_UNIT); - buf_off = 4; - dprintk(dev, 2, " pts: %u\n", *(__u32 *)(meta->buf)); - } - - if (dev->meta_scr) { - meta->flags |= UVC_STREAM_SCR; - meta->buf[buf_off] = div_u64((soe + dev->cap_frame_eof_offset), - VIVID_META_CLOCK_UNIT); - - meta->buf[buf_off + 4] = (buf->vb.sequence * 30) % 1000; - dprintk(dev, 2, " stc: %u, sof counter: %u\n", - *(__u32 *)(meta->buf + buf_off), - *(__u16 *)(meta->buf + buf_off + 4)); - } - dprintk(dev, 2, "\n"); -} diff --git a/drivers/media/platform/vivid/vivid-meta-cap.h b/drivers/media/platform/vivid/vivid-meta-cap.h deleted file mode 100644 index 4670d00d1576..000000000000 --- a/drivers/media/platform/vivid/vivid-meta-cap.h +++ /dev/null @@ -1,29 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * vivid-meta-cap.h - meta capture support functions. - */ -#ifndef _VIVID_META_CAP_H_ -#define _VIVID_META_CAP_H_ - -#define VIVID_META_CLOCK_UNIT 10 /* 100 MHz */ - -struct vivid_uvc_meta_buf { - __u64 ns; - __u16 sof; - __u8 length; - __u8 flags; - __u8 buf[10]; /* PTS(4)+STC(4)+SOF(2) */ -} __packed; - -void vivid_meta_cap_fillbuff(struct vivid_dev *dev, - struct vivid_buffer *buf, u64 soe); - -int vidioc_enum_fmt_meta_cap(struct file *file, void *priv, - struct v4l2_fmtdesc *f); - -int vidioc_g_fmt_meta_cap(struct file *file, void *priv, - struct v4l2_format *f); - -extern const struct vb2_ops vivid_meta_cap_qops; - -#endif diff --git a/drivers/media/platform/vivid/vivid-meta-out.c b/drivers/media/platform/vivid/vivid-meta-out.c deleted file mode 100644 index ff8a039aba72..000000000000 --- a/drivers/media/platform/vivid/vivid-meta-out.c +++ /dev/null @@ -1,174 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * vivid-meta-out.c - meta output support functions. - */ - -#include -#include -#include -#include -#include - -#include "vivid-core.h" -#include "vivid-kthread-out.h" -#include "vivid-meta-out.h" - -static int meta_out_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, - unsigned int *nplanes, unsigned int sizes[], - struct device *alloc_devs[]) -{ - struct vivid_dev *dev = vb2_get_drv_priv(vq); - unsigned int size = sizeof(struct vivid_meta_out_buf); - - if (!vivid_is_webcam(dev)) - return -EINVAL; - - if (*nplanes) { - if (sizes[0] < size) - return -EINVAL; - } else { - sizes[0] = size; - } - - if (vq->num_buffers + *nbuffers < 2) - *nbuffers = 2 - vq->num_buffers; - - *nplanes = 1; - return 0; -} - -static int meta_out_buf_prepare(struct vb2_buffer *vb) -{ - struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); - unsigned int size = sizeof(struct vivid_meta_out_buf); - - dprintk(dev, 1, "%s\n", __func__); - - if (dev->buf_prepare_error) { - /* - * Error injection: test what happens if buf_prepare() returns - * an error. - */ - dev->buf_prepare_error = false; - return -EINVAL; - } - if (vb2_plane_size(vb, 0) < size) { - dprintk(dev, 1, "%s data will not fit into plane (%lu < %u)\n", - __func__, vb2_plane_size(vb, 0), size); - return -EINVAL; - } - vb2_set_plane_payload(vb, 0, size); - - return 0; -} - -static void meta_out_buf_queue(struct vb2_buffer *vb) -{ - struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); - struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); - struct vivid_buffer *buf = container_of(vbuf, struct vivid_buffer, vb); - - dprintk(dev, 1, "%s\n", __func__); - - spin_lock(&dev->slock); - list_add_tail(&buf->list, &dev->meta_out_active); - spin_unlock(&dev->slock); -} - -static int meta_out_start_streaming(struct vb2_queue *vq, unsigned int count) -{ - struct vivid_dev *dev = vb2_get_drv_priv(vq); - int err; - - dprintk(dev, 1, "%s\n", __func__); - dev->meta_out_seq_count = 0; - if (dev->start_streaming_error) { - dev->start_streaming_error = false; - err = -EINVAL; - } else { - err = vivid_start_generating_vid_out(dev, - &dev->meta_out_streaming); - } - if (err) { - struct vivid_buffer *buf, *tmp; - - list_for_each_entry_safe(buf, tmp, - &dev->meta_out_active, list) { - list_del(&buf->list); - vb2_buffer_done(&buf->vb.vb2_buf, - VB2_BUF_STATE_QUEUED); - } - } - return err; -} - -/* abort streaming and wait for last buffer */ -static void meta_out_stop_streaming(struct vb2_queue *vq) -{ - struct vivid_dev *dev = vb2_get_drv_priv(vq); - - dprintk(dev, 1, "%s\n", __func__); - vivid_stop_generating_vid_out(dev, &dev->meta_out_streaming); -} - -static void meta_out_buf_request_complete(struct vb2_buffer *vb) -{ - struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); - - v4l2_ctrl_request_complete(vb->req_obj.req, &dev->ctrl_hdl_meta_out); -} - -const struct vb2_ops vivid_meta_out_qops = { - .queue_setup = meta_out_queue_setup, - .buf_prepare = meta_out_buf_prepare, - .buf_queue = meta_out_buf_queue, - .start_streaming = meta_out_start_streaming, - .stop_streaming = meta_out_stop_streaming, - .buf_request_complete = meta_out_buf_request_complete, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, -}; - -int vidioc_enum_fmt_meta_out(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - struct vivid_dev *dev = video_drvdata(file); - - if (!vivid_is_webcam(dev)) - return -EINVAL; - - if (f->index > 0) - return -EINVAL; - - f->type = V4L2_BUF_TYPE_META_OUTPUT; - f->pixelformat = V4L2_META_FMT_VIVID; - return 0; -} - -int vidioc_g_fmt_meta_out(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct vivid_dev *dev = video_drvdata(file); - struct v4l2_meta_format *meta = &f->fmt.meta; - - if (!vivid_is_webcam(dev) || !dev->has_meta_out) - return -EINVAL; - - meta->dataformat = V4L2_META_FMT_VIVID; - meta->buffersize = sizeof(struct vivid_meta_out_buf); - return 0; -} - -void vivid_meta_out_process(struct vivid_dev *dev, - struct vivid_buffer *buf) -{ - struct vivid_meta_out_buf *meta = vb2_plane_vaddr(&buf->vb.vb2_buf, 0); - - tpg_s_brightness(&dev->tpg, meta->brightness); - tpg_s_contrast(&dev->tpg, meta->contrast); - tpg_s_saturation(&dev->tpg, meta->saturation); - tpg_s_hue(&dev->tpg, meta->hue); - dprintk(dev, 2, " %s brightness %u contrast %u saturation %u hue %d\n", - __func__, meta->brightness, meta->contrast, - meta->saturation, meta->hue); -} diff --git a/drivers/media/platform/vivid/vivid-meta-out.h b/drivers/media/platform/vivid/vivid-meta-out.h deleted file mode 100644 index 0c639b7c2842..000000000000 --- a/drivers/media/platform/vivid/vivid-meta-out.h +++ /dev/null @@ -1,25 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * vivid-meta-out.h - meta output support functions. - */ -#ifndef _VIVID_META_OUT_H_ -#define _VIVID_META_OUT_H_ - -struct vivid_meta_out_buf { - u16 brightness; - u16 contrast; - u16 saturation; - s16 hue; -}; - -void vivid_meta_out_process(struct vivid_dev *dev, struct vivid_buffer *buf); -int vidioc_enum_fmt_meta_out(struct file *file, void *priv, - struct v4l2_fmtdesc *f); -int vidioc_g_fmt_meta_out(struct file *file, void *priv, - struct v4l2_format *f); -int vidioc_s_fmt_meta_out(struct file *file, void *priv, - struct v4l2_format *f); - -extern const struct vb2_ops vivid_meta_out_qops; - -#endif diff --git a/drivers/media/platform/vivid/vivid-osd.c b/drivers/media/platform/vivid/vivid-osd.c deleted file mode 100644 index fbaec8acc161..000000000000 --- a/drivers/media/platform/vivid/vivid-osd.c +++ /dev/null @@ -1,388 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * vivid-osd.c - osd support for testing overlays. - * - * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "vivid-core.h" -#include "vivid-osd.h" - -#define MAX_OSD_WIDTH 720 -#define MAX_OSD_HEIGHT 576 - -/* - * Order: white, yellow, cyan, green, magenta, red, blue, black, - * and same again with the alpha bit set (if any) - */ -static const u16 rgb555[16] = { - 0x7fff, 0x7fe0, 0x03ff, 0x03e0, 0x7c1f, 0x7c00, 0x001f, 0x0000, - 0xffff, 0xffe0, 0x83ff, 0x83e0, 0xfc1f, 0xfc00, 0x801f, 0x8000 -}; - -static const u16 rgb565[16] = { - 0xffff, 0xffe0, 0x07ff, 0x07e0, 0xf81f, 0xf800, 0x001f, 0x0000, - 0xffff, 0xffe0, 0x07ff, 0x07e0, 0xf81f, 0xf800, 0x001f, 0x0000 -}; - -void vivid_clear_fb(struct vivid_dev *dev) -{ - void *p = dev->video_vbase; - const u16 *rgb = rgb555; - unsigned x, y; - - if (dev->fb_defined.green.length == 6) - rgb = rgb565; - - for (y = 0; y < dev->display_height; y++) { - u16 *d = p; - - for (x = 0; x < dev->display_width; x++) - d[x] = rgb[(y / 16 + x / 16) % 16]; - p += dev->display_byte_stride; - } -} - -/* --------------------------------------------------------------------- */ - -static int vivid_fb_ioctl(struct fb_info *info, unsigned cmd, unsigned long arg) -{ - struct vivid_dev *dev = (struct vivid_dev *)info->par; - - switch (cmd) { - case FBIOGET_VBLANK: { - struct fb_vblank vblank; - - memset(&vblank, 0, sizeof(vblank)); - vblank.flags = FB_VBLANK_HAVE_COUNT | FB_VBLANK_HAVE_VCOUNT | - FB_VBLANK_HAVE_VSYNC; - vblank.count = 0; - vblank.vcount = 0; - vblank.hcount = 0; - if (copy_to_user((void __user *)arg, &vblank, sizeof(vblank))) - return -EFAULT; - return 0; - } - - default: - dprintk(dev, 1, "Unknown ioctl %08x\n", cmd); - return -EINVAL; - } - return 0; -} - -/* Framebuffer device handling */ - -static int vivid_fb_set_var(struct vivid_dev *dev, struct fb_var_screeninfo *var) -{ - dprintk(dev, 1, "vivid_fb_set_var\n"); - - if (var->bits_per_pixel != 16) { - dprintk(dev, 1, "vivid_fb_set_var - Invalid bpp\n"); - return -EINVAL; - } - dev->display_byte_stride = var->xres * dev->bytes_per_pixel; - - return 0; -} - -static int vivid_fb_get_fix(struct vivid_dev *dev, struct fb_fix_screeninfo *fix) -{ - dprintk(dev, 1, "vivid_fb_get_fix\n"); - memset(fix, 0, sizeof(struct fb_fix_screeninfo)); - strscpy(fix->id, "vioverlay fb", sizeof(fix->id)); - fix->smem_start = dev->video_pbase; - fix->smem_len = dev->video_buffer_size; - fix->type = FB_TYPE_PACKED_PIXELS; - fix->visual = FB_VISUAL_TRUECOLOR; - fix->xpanstep = 1; - fix->ypanstep = 1; - fix->ywrapstep = 0; - fix->line_length = dev->display_byte_stride; - fix->accel = FB_ACCEL_NONE; - return 0; -} - -/* Check the requested display mode, returning -EINVAL if we can't - handle it. */ - -static int _vivid_fb_check_var(struct fb_var_screeninfo *var, struct vivid_dev *dev) -{ - dprintk(dev, 1, "vivid_fb_check_var\n"); - - var->bits_per_pixel = 16; - if (var->green.length == 5) { - var->red.offset = 10; - var->red.length = 5; - var->green.offset = 5; - var->green.length = 5; - var->blue.offset = 0; - var->blue.length = 5; - var->transp.offset = 15; - var->transp.length = 1; - } else { - var->red.offset = 11; - var->red.length = 5; - var->green.offset = 5; - var->green.length = 6; - var->blue.offset = 0; - var->blue.length = 5; - var->transp.offset = 0; - var->transp.length = 0; - } - var->xoffset = var->yoffset = 0; - var->left_margin = var->upper_margin = 0; - var->nonstd = 0; - - var->vmode &= ~FB_VMODE_MASK; - var->vmode |= FB_VMODE_NONINTERLACED; - - /* Dummy values */ - var->hsync_len = 24; - var->vsync_len = 2; - var->pixclock = 84316; - var->right_margin = 776; - var->lower_margin = 591; - return 0; -} - -static int vivid_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) -{ - struct vivid_dev *dev = (struct vivid_dev *) info->par; - - dprintk(dev, 1, "vivid_fb_check_var\n"); - return _vivid_fb_check_var(var, dev); -} - -static int vivid_fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) -{ - return 0; -} - -static int vivid_fb_set_par(struct fb_info *info) -{ - int rc = 0; - struct vivid_dev *dev = (struct vivid_dev *) info->par; - - dprintk(dev, 1, "vivid_fb_set_par\n"); - - rc = vivid_fb_set_var(dev, &info->var); - vivid_fb_get_fix(dev, &info->fix); - return rc; -} - -static int vivid_fb_setcolreg(unsigned regno, unsigned red, unsigned green, - unsigned blue, unsigned transp, - struct fb_info *info) -{ - u32 color, *palette; - - if (regno >= info->cmap.len) - return -EINVAL; - - color = ((transp & 0xFF00) << 16) | ((red & 0xFF00) << 8) | - (green & 0xFF00) | ((blue & 0xFF00) >> 8); - if (regno >= 16) - return -EINVAL; - - palette = info->pseudo_palette; - if (info->var.bits_per_pixel == 16) { - switch (info->var.green.length) { - case 6: - color = (red & 0xf800) | - ((green & 0xfc00) >> 5) | - ((blue & 0xf800) >> 11); - break; - case 5: - color = ((red & 0xf800) >> 1) | - ((green & 0xf800) >> 6) | - ((blue & 0xf800) >> 11) | - (transp ? 0x8000 : 0); - break; - } - } - palette[regno] = color; - return 0; -} - -/* We don't really support blanking. All this does is enable or - disable the OSD. */ -static int vivid_fb_blank(int blank_mode, struct fb_info *info) -{ - struct vivid_dev *dev = (struct vivid_dev *)info->par; - - dprintk(dev, 1, "Set blanking mode : %d\n", blank_mode); - switch (blank_mode) { - case FB_BLANK_UNBLANK: - break; - case FB_BLANK_NORMAL: - case FB_BLANK_HSYNC_SUSPEND: - case FB_BLANK_VSYNC_SUSPEND: - case FB_BLANK_POWERDOWN: - break; - } - return 0; -} - -static const struct fb_ops vivid_fb_ops = { - .owner = THIS_MODULE, - .fb_check_var = vivid_fb_check_var, - .fb_set_par = vivid_fb_set_par, - .fb_setcolreg = vivid_fb_setcolreg, - .fb_fillrect = cfb_fillrect, - .fb_copyarea = cfb_copyarea, - .fb_imageblit = cfb_imageblit, - .fb_cursor = NULL, - .fb_ioctl = vivid_fb_ioctl, - .fb_pan_display = vivid_fb_pan_display, - .fb_blank = vivid_fb_blank, -}; - -/* Initialization */ - - -/* Setup our initial video mode */ -static int vivid_fb_init_vidmode(struct vivid_dev *dev) -{ - struct v4l2_rect start_window; - - /* Color mode */ - - dev->bits_per_pixel = 16; - dev->bytes_per_pixel = dev->bits_per_pixel / 8; - - start_window.width = MAX_OSD_WIDTH; - start_window.left = 0; - - dev->display_byte_stride = start_window.width * dev->bytes_per_pixel; - - /* Vertical size & position */ - - start_window.height = MAX_OSD_HEIGHT; - start_window.top = 0; - - dev->display_width = start_window.width; - dev->display_height = start_window.height; - - /* Generate a valid fb_var_screeninfo */ - - dev->fb_defined.xres = dev->display_width; - dev->fb_defined.yres = dev->display_height; - dev->fb_defined.xres_virtual = dev->display_width; - dev->fb_defined.yres_virtual = dev->display_height; - dev->fb_defined.bits_per_pixel = dev->bits_per_pixel; - dev->fb_defined.vmode = FB_VMODE_NONINTERLACED; - dev->fb_defined.left_margin = start_window.left + 1; - dev->fb_defined.upper_margin = start_window.top + 1; - dev->fb_defined.accel_flags = FB_ACCEL_NONE; - dev->fb_defined.nonstd = 0; - /* set default to 1:5:5:5 */ - dev->fb_defined.green.length = 5; - - /* We've filled in the most data, let the usual mode check - routine fill in the rest. */ - _vivid_fb_check_var(&dev->fb_defined, dev); - - /* Generate valid fb_fix_screeninfo */ - - vivid_fb_get_fix(dev, &dev->fb_fix); - - /* Generate valid fb_info */ - - dev->fb_info.node = -1; - dev->fb_info.flags = FBINFO_FLAG_DEFAULT; - dev->fb_info.par = dev; - dev->fb_info.var = dev->fb_defined; - dev->fb_info.fix = dev->fb_fix; - dev->fb_info.screen_base = (u8 __iomem *)dev->video_vbase; - dev->fb_info.fbops = &vivid_fb_ops; - - /* Supply some monitor specs. Bogus values will do for now */ - dev->fb_info.monspecs.hfmin = 8000; - dev->fb_info.monspecs.hfmax = 70000; - dev->fb_info.monspecs.vfmin = 10; - dev->fb_info.monspecs.vfmax = 100; - - /* Allocate color map */ - if (fb_alloc_cmap(&dev->fb_info.cmap, 256, 1)) { - pr_err("abort, unable to alloc cmap\n"); - return -ENOMEM; - } - - /* Allocate the pseudo palette */ - dev->fb_info.pseudo_palette = kmalloc_array(16, sizeof(u32), GFP_KERNEL); - - return dev->fb_info.pseudo_palette ? 0 : -ENOMEM; -} - -/* Release any memory we've grabbed */ -void vivid_fb_release_buffers(struct vivid_dev *dev) -{ - if (dev->video_vbase == NULL) - return; - - /* Release cmap */ - if (dev->fb_info.cmap.len) - fb_dealloc_cmap(&dev->fb_info.cmap); - - /* Release pseudo palette */ - kfree(dev->fb_info.pseudo_palette); - kfree(dev->video_vbase); -} - -/* Initialize the specified card */ - -int vivid_fb_init(struct vivid_dev *dev) -{ - int ret; - - dev->video_buffer_size = MAX_OSD_HEIGHT * MAX_OSD_WIDTH * 2; - dev->video_vbase = kzalloc(dev->video_buffer_size, GFP_KERNEL | GFP_DMA32); - if (dev->video_vbase == NULL) - return -ENOMEM; - dev->video_pbase = virt_to_phys(dev->video_vbase); - - pr_info("Framebuffer at 0x%lx, mapped to 0x%p, size %dk\n", - dev->video_pbase, dev->video_vbase, - dev->video_buffer_size / 1024); - - /* Set the startup video mode information */ - ret = vivid_fb_init_vidmode(dev); - if (ret) { - vivid_fb_release_buffers(dev); - return ret; - } - - vivid_clear_fb(dev); - - /* Register the framebuffer */ - if (register_framebuffer(&dev->fb_info) < 0) { - vivid_fb_release_buffers(dev); - return -EINVAL; - } - - /* Set the card to the requested mode */ - vivid_fb_set_par(&dev->fb_info); - return 0; - -} diff --git a/drivers/media/platform/vivid/vivid-osd.h b/drivers/media/platform/vivid/vivid-osd.h deleted file mode 100644 index f9ac1af25dd3..000000000000 --- a/drivers/media/platform/vivid/vivid-osd.h +++ /dev/null @@ -1,15 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * vivid-osd.h - output overlay support functions. - * - * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - */ - -#ifndef _VIVID_OSD_H_ -#define _VIVID_OSD_H_ - -int vivid_fb_init(struct vivid_dev *dev); -void vivid_fb_release_buffers(struct vivid_dev *dev); -void vivid_clear_fb(struct vivid_dev *dev); - -#endif diff --git a/drivers/media/platform/vivid/vivid-radio-common.c b/drivers/media/platform/vivid/vivid-radio-common.c deleted file mode 100644 index 138c7bce68b1..000000000000 --- a/drivers/media/platform/vivid/vivid-radio-common.c +++ /dev/null @@ -1,177 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * vivid-radio-common.c - common radio rx/tx support functions. - * - * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - */ - -#include -#include -#include -#include - -#include "vivid-core.h" -#include "vivid-ctrls.h" -#include "vivid-radio-common.h" -#include "vivid-rds-gen.h" - -/* - * These functions are shared between the vivid receiver and transmitter - * since both use the same frequency bands. - */ - -const struct v4l2_frequency_band vivid_radio_bands[TOT_BANDS] = { - /* Band FM */ - { - .type = V4L2_TUNER_RADIO, - .index = 0, - .capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO | - V4L2_TUNER_CAP_FREQ_BANDS, - .rangelow = FM_FREQ_RANGE_LOW, - .rangehigh = FM_FREQ_RANGE_HIGH, - .modulation = V4L2_BAND_MODULATION_FM, - }, - /* Band AM */ - { - .type = V4L2_TUNER_RADIO, - .index = 1, - .capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_FREQ_BANDS, - .rangelow = AM_FREQ_RANGE_LOW, - .rangehigh = AM_FREQ_RANGE_HIGH, - .modulation = V4L2_BAND_MODULATION_AM, - }, - /* Band SW */ - { - .type = V4L2_TUNER_RADIO, - .index = 2, - .capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_FREQ_BANDS, - .rangelow = SW_FREQ_RANGE_LOW, - .rangehigh = SW_FREQ_RANGE_HIGH, - .modulation = V4L2_BAND_MODULATION_AM, - }, -}; - -/* - * Initialize the RDS generator. If we can loop, then the RDS generator - * is set up with the values from the RDS TX controls, otherwise it - * will fill in standard values using one of two alternates. - */ -void vivid_radio_rds_init(struct vivid_dev *dev) -{ - struct vivid_rds_gen *rds = &dev->rds_gen; - bool alt = dev->radio_rx_rds_use_alternates; - - /* Do nothing, blocks will be filled by the transmitter */ - if (dev->radio_rds_loop && !dev->radio_tx_rds_controls) - return; - - if (dev->radio_rds_loop) { - v4l2_ctrl_lock(dev->radio_tx_rds_pi); - rds->picode = dev->radio_tx_rds_pi->cur.val; - rds->pty = dev->radio_tx_rds_pty->cur.val; - rds->mono_stereo = dev->radio_tx_rds_mono_stereo->cur.val; - rds->art_head = dev->radio_tx_rds_art_head->cur.val; - rds->compressed = dev->radio_tx_rds_compressed->cur.val; - rds->dyn_pty = dev->radio_tx_rds_dyn_pty->cur.val; - rds->ta = dev->radio_tx_rds_ta->cur.val; - rds->tp = dev->radio_tx_rds_tp->cur.val; - rds->ms = dev->radio_tx_rds_ms->cur.val; - strscpy(rds->psname, - dev->radio_tx_rds_psname->p_cur.p_char, - sizeof(rds->psname)); - strscpy(rds->radiotext, - dev->radio_tx_rds_radiotext->p_cur.p_char + alt * 64, - sizeof(rds->radiotext)); - v4l2_ctrl_unlock(dev->radio_tx_rds_pi); - } else { - vivid_rds_gen_fill(rds, dev->radio_rx_freq, alt); - } - if (dev->radio_rx_rds_controls) { - v4l2_ctrl_s_ctrl(dev->radio_rx_rds_pty, rds->pty); - v4l2_ctrl_s_ctrl(dev->radio_rx_rds_ta, rds->ta); - v4l2_ctrl_s_ctrl(dev->radio_rx_rds_tp, rds->tp); - v4l2_ctrl_s_ctrl(dev->radio_rx_rds_ms, rds->ms); - v4l2_ctrl_s_ctrl_string(dev->radio_rx_rds_psname, rds->psname); - v4l2_ctrl_s_ctrl_string(dev->radio_rx_rds_radiotext, rds->radiotext); - if (!dev->radio_rds_loop) - dev->radio_rx_rds_use_alternates = !dev->radio_rx_rds_use_alternates; - } - vivid_rds_generate(rds); -} - -/* - * Calculate the emulated signal quality taking into account the frequency - * the transmitter is using. - */ -static void vivid_radio_calc_sig_qual(struct vivid_dev *dev) -{ - int mod = 16000; - int delta = 800; - int sig_qual, sig_qual_tx = mod; - - /* - * For SW and FM there is a channel every 1000 kHz, for AM there is one - * every 100 kHz. - */ - if (dev->radio_rx_freq <= AM_FREQ_RANGE_HIGH) { - mod /= 10; - delta /= 10; - } - sig_qual = (dev->radio_rx_freq + delta) % mod - delta; - if (dev->has_radio_tx) - sig_qual_tx = dev->radio_rx_freq - dev->radio_tx_freq; - if (abs(sig_qual_tx) <= abs(sig_qual)) { - sig_qual = sig_qual_tx; - /* - * Zero the internal rds buffer if we are going to loop - * rds blocks. - */ - if (!dev->radio_rds_loop && !dev->radio_tx_rds_controls) - memset(dev->rds_gen.data, 0, - sizeof(dev->rds_gen.data)); - dev->radio_rds_loop = dev->radio_rx_freq >= FM_FREQ_RANGE_LOW; - } else { - dev->radio_rds_loop = false; - } - if (dev->radio_rx_freq <= AM_FREQ_RANGE_HIGH) - sig_qual *= 10; - dev->radio_rx_sig_qual = sig_qual; -} - -int vivid_radio_g_frequency(struct file *file, const unsigned *pfreq, struct v4l2_frequency *vf) -{ - if (vf->tuner != 0) - return -EINVAL; - vf->frequency = *pfreq; - return 0; -} - -int vivid_radio_s_frequency(struct file *file, unsigned *pfreq, const struct v4l2_frequency *vf) -{ - struct vivid_dev *dev = video_drvdata(file); - unsigned freq; - unsigned band; - - if (vf->tuner != 0) - return -EINVAL; - - if (vf->frequency >= (FM_FREQ_RANGE_LOW + SW_FREQ_RANGE_HIGH) / 2) - band = BAND_FM; - else if (vf->frequency <= (AM_FREQ_RANGE_HIGH + SW_FREQ_RANGE_LOW) / 2) - band = BAND_AM; - else - band = BAND_SW; - - freq = clamp_t(u32, vf->frequency, vivid_radio_bands[band].rangelow, - vivid_radio_bands[band].rangehigh); - *pfreq = freq; - - /* - * For both receiver and transmitter recalculate the signal quality - * (since that depends on both frequencies) and re-init the rds - * generator. - */ - vivid_radio_calc_sig_qual(dev); - vivid_radio_rds_init(dev); - return 0; -} diff --git a/drivers/media/platform/vivid/vivid-radio-common.h b/drivers/media/platform/vivid/vivid-radio-common.h deleted file mode 100644 index 30a9900e5b2b..000000000000 --- a/drivers/media/platform/vivid/vivid-radio-common.h +++ /dev/null @@ -1,28 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * vivid-radio-common.h - common radio rx/tx support functions. - * - * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - */ - -#ifndef _VIVID_RADIO_COMMON_H_ -#define _VIVID_RADIO_COMMON_H_ - -/* The supported radio frequency ranges in kHz */ -#define FM_FREQ_RANGE_LOW (64000U * 16U) -#define FM_FREQ_RANGE_HIGH (108000U * 16U) -#define AM_FREQ_RANGE_LOW (520U * 16U) -#define AM_FREQ_RANGE_HIGH (1710U * 16U) -#define SW_FREQ_RANGE_LOW (2300U * 16U) -#define SW_FREQ_RANGE_HIGH (26100U * 16U) - -enum { BAND_FM, BAND_AM, BAND_SW, TOT_BANDS }; - -extern const struct v4l2_frequency_band vivid_radio_bands[TOT_BANDS]; - -int vivid_radio_g_frequency(struct file *file, const unsigned *freq, struct v4l2_frequency *vf); -int vivid_radio_s_frequency(struct file *file, unsigned *freq, const struct v4l2_frequency *vf); - -void vivid_radio_rds_init(struct vivid_dev *dev); - -#endif diff --git a/drivers/media/platform/vivid/vivid-radio-rx.c b/drivers/media/platform/vivid/vivid-radio-rx.c deleted file mode 100644 index 232cab508f48..000000000000 --- a/drivers/media/platform/vivid/vivid-radio-rx.c +++ /dev/null @@ -1,278 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * vivid-radio-rx.c - radio receiver support functions. - * - * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "vivid-core.h" -#include "vivid-ctrls.h" -#include "vivid-radio-common.h" -#include "vivid-rds-gen.h" -#include "vivid-radio-rx.h" - -ssize_t vivid_radio_rx_read(struct file *file, char __user *buf, - size_t size, loff_t *offset) -{ - struct vivid_dev *dev = video_drvdata(file); - struct v4l2_rds_data *data = dev->rds_gen.data; - bool use_alternates; - ktime_t timestamp; - unsigned blk; - int perc; - int i; - - if (dev->radio_rx_rds_controls) - return -EINVAL; - if (size < sizeof(*data)) - return 0; - size = sizeof(*data) * (size / sizeof(*data)); - - if (mutex_lock_interruptible(&dev->mutex)) - return -ERESTARTSYS; - if (dev->radio_rx_rds_owner && - file->private_data != dev->radio_rx_rds_owner) { - mutex_unlock(&dev->mutex); - return -EBUSY; - } - if (dev->radio_rx_rds_owner == NULL) { - vivid_radio_rds_init(dev); - dev->radio_rx_rds_owner = file->private_data; - } - -retry: - timestamp = ktime_sub(ktime_get(), dev->radio_rds_init_time); - blk = ktime_divns(timestamp, VIVID_RDS_NSEC_PER_BLK); - use_alternates = (blk % VIVID_RDS_GEN_BLOCKS) & 1; - - if (dev->radio_rx_rds_last_block == 0 || - dev->radio_rx_rds_use_alternates != use_alternates) { - dev->radio_rx_rds_use_alternates = use_alternates; - /* Re-init the RDS generator */ - vivid_radio_rds_init(dev); - } - if (blk >= dev->radio_rx_rds_last_block + VIVID_RDS_GEN_BLOCKS) - dev->radio_rx_rds_last_block = blk - VIVID_RDS_GEN_BLOCKS + 1; - - /* - * No data is available if there hasn't been time to get new data, - * or if the RDS receiver has been disabled, or if we use the data - * from the RDS transmitter and that RDS transmitter has been disabled, - * or if the signal quality is too weak. - */ - if (blk == dev->radio_rx_rds_last_block || !dev->radio_rx_rds_enabled || - (dev->radio_rds_loop && !(dev->radio_tx_subchans & V4L2_TUNER_SUB_RDS)) || - abs(dev->radio_rx_sig_qual) > 200) { - mutex_unlock(&dev->mutex); - if (file->f_flags & O_NONBLOCK) - return -EWOULDBLOCK; - if (msleep_interruptible(20) && signal_pending(current)) - return -EINTR; - if (mutex_lock_interruptible(&dev->mutex)) - return -ERESTARTSYS; - goto retry; - } - - /* abs(dev->radio_rx_sig_qual) <= 200, map that to a 0-50% range */ - perc = abs(dev->radio_rx_sig_qual) / 4; - - for (i = 0; i < size && blk > dev->radio_rx_rds_last_block; - dev->radio_rx_rds_last_block++) { - unsigned data_blk = dev->radio_rx_rds_last_block % VIVID_RDS_GEN_BLOCKS; - struct v4l2_rds_data rds = data[data_blk]; - - if (data_blk == 0 && dev->radio_rds_loop) - vivid_radio_rds_init(dev); - if (perc && prandom_u32_max(100) < perc) { - switch (prandom_u32_max(4)) { - case 0: - rds.block |= V4L2_RDS_BLOCK_CORRECTED; - break; - case 1: - rds.block |= V4L2_RDS_BLOCK_INVALID; - break; - case 2: - rds.block |= V4L2_RDS_BLOCK_ERROR; - rds.lsb = prandom_u32_max(256); - rds.msb = prandom_u32_max(256); - break; - case 3: /* Skip block altogether */ - if (i) - continue; - /* - * Must make sure at least one block is - * returned, otherwise the application - * might think that end-of-file occurred. - */ - break; - } - } - if (copy_to_user(buf + i, &rds, sizeof(rds))) { - i = -EFAULT; - break; - } - i += sizeof(rds); - } - mutex_unlock(&dev->mutex); - return i; -} - -__poll_t vivid_radio_rx_poll(struct file *file, struct poll_table_struct *wait) -{ - return EPOLLIN | EPOLLRDNORM | v4l2_ctrl_poll(file, wait); -} - -int vivid_radio_rx_enum_freq_bands(struct file *file, void *fh, struct v4l2_frequency_band *band) -{ - if (band->tuner != 0) - return -EINVAL; - - if (band->index >= TOT_BANDS) - return -EINVAL; - - *band = vivid_radio_bands[band->index]; - return 0; -} - -int vivid_radio_rx_s_hw_freq_seek(struct file *file, void *fh, const struct v4l2_hw_freq_seek *a) -{ - struct vivid_dev *dev = video_drvdata(file); - unsigned low, high; - unsigned freq; - unsigned spacing; - unsigned band; - - if (a->tuner) - return -EINVAL; - if (a->wrap_around && dev->radio_rx_hw_seek_mode == VIVID_HW_SEEK_BOUNDED) - return -EINVAL; - - if (!a->wrap_around && dev->radio_rx_hw_seek_mode == VIVID_HW_SEEK_WRAP) - return -EINVAL; - if (!a->rangelow ^ !a->rangehigh) - return -EINVAL; - - if (file->f_flags & O_NONBLOCK) - return -EWOULDBLOCK; - - if (a->rangelow) { - for (band = 0; band < TOT_BANDS; band++) - if (a->rangelow >= vivid_radio_bands[band].rangelow && - a->rangehigh <= vivid_radio_bands[band].rangehigh) - break; - if (band == TOT_BANDS) - return -EINVAL; - if (!dev->radio_rx_hw_seek_prog_lim && - (a->rangelow != vivid_radio_bands[band].rangelow || - a->rangehigh != vivid_radio_bands[band].rangehigh)) - return -EINVAL; - low = a->rangelow; - high = a->rangehigh; - } else { - for (band = 0; band < TOT_BANDS; band++) - if (dev->radio_rx_freq >= vivid_radio_bands[band].rangelow && - dev->radio_rx_freq <= vivid_radio_bands[band].rangehigh) - break; - if (band == TOT_BANDS) - return -EINVAL; - low = vivid_radio_bands[band].rangelow; - high = vivid_radio_bands[band].rangehigh; - } - spacing = band == BAND_AM ? 1600 : 16000; - freq = clamp(dev->radio_rx_freq, low, high); - - if (a->seek_upward) { - freq = spacing * (freq / spacing) + spacing; - if (freq > high) { - if (!a->wrap_around) - return -ENODATA; - freq = spacing * (low / spacing) + spacing; - if (freq >= dev->radio_rx_freq) - return -ENODATA; - } - } else { - freq = spacing * ((freq + spacing - 1) / spacing) - spacing; - if (freq < low) { - if (!a->wrap_around) - return -ENODATA; - freq = spacing * ((high + spacing - 1) / spacing) - spacing; - if (freq <= dev->radio_rx_freq) - return -ENODATA; - } - } - return 0; -} - -int vivid_radio_rx_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt) -{ - struct vivid_dev *dev = video_drvdata(file); - int delta = 800; - int sig_qual; - - if (vt->index > 0) - return -EINVAL; - - strscpy(vt->name, "AM/FM/SW Receiver", sizeof(vt->name)); - vt->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO | - V4L2_TUNER_CAP_FREQ_BANDS | V4L2_TUNER_CAP_RDS | - (dev->radio_rx_rds_controls ? - V4L2_TUNER_CAP_RDS_CONTROLS : - V4L2_TUNER_CAP_RDS_BLOCK_IO) | - (dev->radio_rx_hw_seek_prog_lim ? - V4L2_TUNER_CAP_HWSEEK_PROG_LIM : 0); - switch (dev->radio_rx_hw_seek_mode) { - case VIVID_HW_SEEK_BOUNDED: - vt->capability |= V4L2_TUNER_CAP_HWSEEK_BOUNDED; - break; - case VIVID_HW_SEEK_WRAP: - vt->capability |= V4L2_TUNER_CAP_HWSEEK_WRAP; - break; - case VIVID_HW_SEEK_BOTH: - vt->capability |= V4L2_TUNER_CAP_HWSEEK_WRAP | - V4L2_TUNER_CAP_HWSEEK_BOUNDED; - break; - } - vt->rangelow = AM_FREQ_RANGE_LOW; - vt->rangehigh = FM_FREQ_RANGE_HIGH; - sig_qual = dev->radio_rx_sig_qual; - vt->signal = abs(sig_qual) > delta ? 0 : - 0xffff - ((unsigned)abs(sig_qual) * 0xffff) / delta; - vt->afc = sig_qual > delta ? 0 : sig_qual; - if (abs(sig_qual) > delta) - vt->rxsubchans = 0; - else if (dev->radio_rx_freq < FM_FREQ_RANGE_LOW || vt->signal < 0x8000) - vt->rxsubchans = V4L2_TUNER_SUB_MONO; - else if (dev->radio_rds_loop && !(dev->radio_tx_subchans & V4L2_TUNER_SUB_STEREO)) - vt->rxsubchans = V4L2_TUNER_SUB_MONO; - else - vt->rxsubchans = V4L2_TUNER_SUB_STEREO; - if (dev->radio_rx_rds_enabled && - (!dev->radio_rds_loop || (dev->radio_tx_subchans & V4L2_TUNER_SUB_RDS)) && - dev->radio_rx_freq >= FM_FREQ_RANGE_LOW && vt->signal >= 0xc000) - vt->rxsubchans |= V4L2_TUNER_SUB_RDS; - if (dev->radio_rx_rds_controls) - vivid_radio_rds_init(dev); - vt->audmode = dev->radio_rx_audmode; - return 0; -} - -int vivid_radio_rx_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *vt) -{ - struct vivid_dev *dev = video_drvdata(file); - - if (vt->index) - return -EINVAL; - dev->radio_rx_audmode = vt->audmode >= V4L2_TUNER_MODE_STEREO; - return 0; -} diff --git a/drivers/media/platform/vivid/vivid-radio-rx.h b/drivers/media/platform/vivid/vivid-radio-rx.h deleted file mode 100644 index c9c7849f6f99..000000000000 --- a/drivers/media/platform/vivid/vivid-radio-rx.h +++ /dev/null @@ -1,19 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * vivid-radio-rx.h - radio receiver support functions. - * - * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - */ - -#ifndef _VIVID_RADIO_RX_H_ -#define _VIVID_RADIO_RX_H_ - -ssize_t vivid_radio_rx_read(struct file *, char __user *, size_t, loff_t *); -__poll_t vivid_radio_rx_poll(struct file *file, struct poll_table_struct *wait); - -int vivid_radio_rx_enum_freq_bands(struct file *file, void *fh, struct v4l2_frequency_band *band); -int vivid_radio_rx_s_hw_freq_seek(struct file *file, void *fh, const struct v4l2_hw_freq_seek *a); -int vivid_radio_rx_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt); -int vivid_radio_rx_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *vt); - -#endif diff --git a/drivers/media/platform/vivid/vivid-radio-tx.c b/drivers/media/platform/vivid/vivid-radio-tx.c deleted file mode 100644 index 049d40b948bb..000000000000 --- a/drivers/media/platform/vivid/vivid-radio-tx.c +++ /dev/null @@ -1,128 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * vivid-radio-tx.c - radio transmitter support functions. - * - * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "vivid-core.h" -#include "vivid-ctrls.h" -#include "vivid-radio-common.h" -#include "vivid-radio-tx.h" - -ssize_t vivid_radio_tx_write(struct file *file, const char __user *buf, - size_t size, loff_t *offset) -{ - struct vivid_dev *dev = video_drvdata(file); - struct v4l2_rds_data *data = dev->rds_gen.data; - ktime_t timestamp; - unsigned blk; - int i; - - if (dev->radio_tx_rds_controls) - return -EINVAL; - - if (size < sizeof(*data)) - return -EINVAL; - size = sizeof(*data) * (size / sizeof(*data)); - - if (mutex_lock_interruptible(&dev->mutex)) - return -ERESTARTSYS; - if (dev->radio_tx_rds_owner && - file->private_data != dev->radio_tx_rds_owner) { - mutex_unlock(&dev->mutex); - return -EBUSY; - } - dev->radio_tx_rds_owner = file->private_data; - -retry: - timestamp = ktime_sub(ktime_get(), dev->radio_rds_init_time); - blk = ktime_divns(timestamp, VIVID_RDS_NSEC_PER_BLK); - if (blk - VIVID_RDS_GEN_BLOCKS >= dev->radio_tx_rds_last_block) - dev->radio_tx_rds_last_block = blk - VIVID_RDS_GEN_BLOCKS + 1; - - /* - * No data is available if there hasn't been time to get new data, - * or if the RDS receiver has been disabled, or if we use the data - * from the RDS transmitter and that RDS transmitter has been disabled, - * or if the signal quality is too weak. - */ - if (blk == dev->radio_tx_rds_last_block || - !(dev->radio_tx_subchans & V4L2_TUNER_SUB_RDS)) { - mutex_unlock(&dev->mutex); - if (file->f_flags & O_NONBLOCK) - return -EWOULDBLOCK; - if (msleep_interruptible(20) && signal_pending(current)) - return -EINTR; - if (mutex_lock_interruptible(&dev->mutex)) - return -ERESTARTSYS; - goto retry; - } - - for (i = 0; i < size && blk > dev->radio_tx_rds_last_block; - dev->radio_tx_rds_last_block++) { - unsigned data_blk = dev->radio_tx_rds_last_block % VIVID_RDS_GEN_BLOCKS; - struct v4l2_rds_data rds; - - if (copy_from_user(&rds, buf + i, sizeof(rds))) { - i = -EFAULT; - break; - } - i += sizeof(rds); - if (!dev->radio_rds_loop) - continue; - if ((rds.block & V4L2_RDS_BLOCK_MSK) == V4L2_RDS_BLOCK_INVALID || - (rds.block & V4L2_RDS_BLOCK_ERROR)) - continue; - rds.block &= V4L2_RDS_BLOCK_MSK; - data[data_blk] = rds; - } - mutex_unlock(&dev->mutex); - return i; -} - -__poll_t vivid_radio_tx_poll(struct file *file, struct poll_table_struct *wait) -{ - return EPOLLOUT | EPOLLWRNORM | v4l2_ctrl_poll(file, wait); -} - -int vidioc_g_modulator(struct file *file, void *fh, struct v4l2_modulator *a) -{ - struct vivid_dev *dev = video_drvdata(file); - - if (a->index > 0) - return -EINVAL; - - strscpy(a->name, "AM/FM/SW Transmitter", sizeof(a->name)); - a->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO | - V4L2_TUNER_CAP_FREQ_BANDS | V4L2_TUNER_CAP_RDS | - (dev->radio_tx_rds_controls ? - V4L2_TUNER_CAP_RDS_CONTROLS : - V4L2_TUNER_CAP_RDS_BLOCK_IO); - a->rangelow = AM_FREQ_RANGE_LOW; - a->rangehigh = FM_FREQ_RANGE_HIGH; - a->txsubchans = dev->radio_tx_subchans; - return 0; -} - -int vidioc_s_modulator(struct file *file, void *fh, const struct v4l2_modulator *a) -{ - struct vivid_dev *dev = video_drvdata(file); - - if (a->index) - return -EINVAL; - if (a->txsubchans & ~0x13) - return -EINVAL; - dev->radio_tx_subchans = a->txsubchans; - return 0; -} diff --git a/drivers/media/platform/vivid/vivid-radio-tx.h b/drivers/media/platform/vivid/vivid-radio-tx.h deleted file mode 100644 index c2bf1e7e634a..000000000000 --- a/drivers/media/platform/vivid/vivid-radio-tx.h +++ /dev/null @@ -1,17 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * vivid-radio-tx.h - radio transmitter support functions. - * - * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - */ - -#ifndef _VIVID_RADIO_TX_H_ -#define _VIVID_RADIO_TX_H_ - -ssize_t vivid_radio_tx_write(struct file *, const char __user *, size_t, loff_t *); -__poll_t vivid_radio_tx_poll(struct file *file, struct poll_table_struct *wait); - -int vidioc_g_modulator(struct file *file, void *fh, struct v4l2_modulator *a); -int vidioc_s_modulator(struct file *file, void *fh, const struct v4l2_modulator *a); - -#endif diff --git a/drivers/media/platform/vivid/vivid-rds-gen.c b/drivers/media/platform/vivid/vivid-rds-gen.c deleted file mode 100644 index b5b104ee64c9..000000000000 --- a/drivers/media/platform/vivid/vivid-rds-gen.c +++ /dev/null @@ -1,157 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * vivid-rds-gen.c - rds (radio data system) generator support functions. - * - * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - */ - -#include -#include -#include -#include - -#include "vivid-rds-gen.h" - -static u8 vivid_get_di(const struct vivid_rds_gen *rds, unsigned grp) -{ - switch (grp) { - case 0: - return (rds->dyn_pty << 2) | (grp & 3); - case 1: - return (rds->compressed << 2) | (grp & 3); - case 2: - return (rds->art_head << 2) | (grp & 3); - case 3: - return (rds->mono_stereo << 2) | (grp & 3); - } - return 0; -} - -/* - * This RDS generator creates 57 RDS groups (one group == four RDS blocks). - * Groups 0-3, 22-25 and 44-47 (spaced 22 groups apart) are filled with a - * standard 0B group containing the PI code and PS name. - * - * Groups 4-19 and 26-41 use group 2A for the radio text. - * - * Group 56 contains the time (group 4A). - * - * All remaining groups use a filler group 15B block that just repeats - * the PI and PTY codes. - */ -void vivid_rds_generate(struct vivid_rds_gen *rds) -{ - struct v4l2_rds_data *data = rds->data; - unsigned grp; - unsigned idx; - struct tm tm; - unsigned date; - unsigned time; - int l; - - for (grp = 0; grp < VIVID_RDS_GEN_GROUPS; grp++, data += VIVID_RDS_GEN_BLKS_PER_GRP) { - data[0].lsb = rds->picode & 0xff; - data[0].msb = rds->picode >> 8; - data[0].block = V4L2_RDS_BLOCK_A | (V4L2_RDS_BLOCK_A << 3); - data[1].lsb = rds->pty << 5; - data[1].msb = (rds->pty >> 3) | (rds->tp << 2); - data[1].block = V4L2_RDS_BLOCK_B | (V4L2_RDS_BLOCK_B << 3); - data[3].block = V4L2_RDS_BLOCK_D | (V4L2_RDS_BLOCK_D << 3); - - switch (grp) { - case 0 ... 3: - case 22 ... 25: - case 44 ... 47: /* Group 0B */ - idx = (grp % 22) % 4; - data[1].lsb |= (rds->ta << 4) | (rds->ms << 3); - data[1].lsb |= vivid_get_di(rds, idx); - data[1].msb |= 1 << 3; - data[2].lsb = rds->picode & 0xff; - data[2].msb = rds->picode >> 8; - data[2].block = V4L2_RDS_BLOCK_C_ALT | (V4L2_RDS_BLOCK_C_ALT << 3); - data[3].lsb = rds->psname[2 * idx + 1]; - data[3].msb = rds->psname[2 * idx]; - break; - case 4 ... 19: - case 26 ... 41: /* Group 2A */ - idx = ((grp - 4) % 22) % 16; - data[1].lsb |= idx; - data[1].msb |= 4 << 3; - data[2].msb = rds->radiotext[4 * idx]; - data[2].lsb = rds->radiotext[4 * idx + 1]; - data[2].block = V4L2_RDS_BLOCK_C | (V4L2_RDS_BLOCK_C << 3); - data[3].msb = rds->radiotext[4 * idx + 2]; - data[3].lsb = rds->radiotext[4 * idx + 3]; - break; - case 56: - /* - * Group 4A - * - * Uses the algorithm from Annex G of the RDS standard - * EN 50067:1998 to convert a UTC date to an RDS Modified - * Julian Day. - */ - time64_to_tm(ktime_get_real_seconds(), 0, &tm); - l = tm.tm_mon <= 1; - date = 14956 + tm.tm_mday + ((tm.tm_year - l) * 1461) / 4 + - ((tm.tm_mon + 2 + l * 12) * 306001) / 10000; - time = (tm.tm_hour << 12) | - (tm.tm_min << 6) | - (sys_tz.tz_minuteswest >= 0 ? 0x20 : 0) | - (abs(sys_tz.tz_minuteswest) / 30); - data[1].lsb &= ~3; - data[1].lsb |= date >> 15; - data[1].msb |= 8 << 3; - data[2].lsb = (date << 1) & 0xfe; - data[2].lsb |= (time >> 16) & 1; - data[2].msb = (date >> 7) & 0xff; - data[2].block = V4L2_RDS_BLOCK_C | (V4L2_RDS_BLOCK_C << 3); - data[3].lsb = time & 0xff; - data[3].msb = (time >> 8) & 0xff; - break; - default: /* Group 15B */ - data[1].lsb |= (rds->ta << 4) | (rds->ms << 3); - data[1].lsb |= vivid_get_di(rds, grp % 22); - data[1].msb |= 0x1f << 3; - data[2].lsb = rds->picode & 0xff; - data[2].msb = rds->picode >> 8; - data[2].block = V4L2_RDS_BLOCK_C_ALT | (V4L2_RDS_BLOCK_C_ALT << 3); - data[3].lsb = rds->pty << 5; - data[3].lsb |= (rds->ta << 4) | (rds->ms << 3); - data[3].lsb |= vivid_get_di(rds, grp % 22); - data[3].msb |= rds->pty >> 3; - data[3].msb |= 0x1f << 3; - break; - } - } -} - -void vivid_rds_gen_fill(struct vivid_rds_gen *rds, unsigned freq, - bool alt) -{ - /* Alternate PTY between Info and Weather */ - if (rds->use_rbds) { - rds->picode = 0x2e75; /* 'KLNX' call sign */ - rds->pty = alt ? 29 : 2; - } else { - rds->picode = 0x8088; - rds->pty = alt ? 16 : 3; - } - rds->mono_stereo = true; - rds->art_head = false; - rds->compressed = false; - rds->dyn_pty = false; - rds->tp = true; - rds->ta = alt; - rds->ms = true; - snprintf(rds->psname, sizeof(rds->psname), "%6d.%1d", - freq / 16, ((freq & 0xf) * 10) / 16); - if (alt) - strscpy(rds->radiotext, - " The Radio Data System can switch between different Radio Texts ", - sizeof(rds->radiotext)); - else - strscpy(rds->radiotext, - "An example of Radio Text as transmitted by the Radio Data System", - sizeof(rds->radiotext)); -} diff --git a/drivers/media/platform/vivid/vivid-rds-gen.h b/drivers/media/platform/vivid/vivid-rds-gen.h deleted file mode 100644 index 35ac5742302b..000000000000 --- a/drivers/media/platform/vivid/vivid-rds-gen.h +++ /dev/null @@ -1,42 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * vivid-rds-gen.h - rds (radio data system) generator support functions. - * - * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - */ - -#ifndef _VIVID_RDS_GEN_H_ -#define _VIVID_RDS_GEN_H_ - -/* - * It takes almost exactly 5 seconds to transmit 57 RDS groups. - * Each group has 4 blocks and each block has a payload of 16 bits + a - * block identification. The driver will generate the contents of these - * 57 groups only when necessary and it will just be played continuously. - */ -#define VIVID_RDS_GEN_GROUPS 57 -#define VIVID_RDS_GEN_BLKS_PER_GRP 4 -#define VIVID_RDS_GEN_BLOCKS (VIVID_RDS_GEN_BLKS_PER_GRP * VIVID_RDS_GEN_GROUPS) -#define VIVID_RDS_NSEC_PER_BLK (u32)(5ull * NSEC_PER_SEC / VIVID_RDS_GEN_BLOCKS) - -struct vivid_rds_gen { - struct v4l2_rds_data data[VIVID_RDS_GEN_BLOCKS]; - bool use_rbds; - u16 picode; - u8 pty; - bool mono_stereo; - bool art_head; - bool compressed; - bool dyn_pty; - bool ta; - bool tp; - bool ms; - char psname[8 + 1]; - char radiotext[64 + 1]; -}; - -void vivid_rds_gen_fill(struct vivid_rds_gen *rds, unsigned freq, - bool use_alternate); -void vivid_rds_generate(struct vivid_rds_gen *rds); - -#endif diff --git a/drivers/media/platform/vivid/vivid-sdr-cap.c b/drivers/media/platform/vivid/vivid-sdr-cap.c deleted file mode 100644 index 2b7522e16efc..000000000000 --- a/drivers/media/platform/vivid/vivid-sdr-cap.c +++ /dev/null @@ -1,570 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * vivid-sdr-cap.c - software defined radio support functions. - * - * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "vivid-core.h" -#include "vivid-ctrls.h" -#include "vivid-sdr-cap.h" - -/* stream formats */ -struct vivid_format { - u32 pixelformat; - u32 buffersize; -}; - -/* format descriptions for capture and preview */ -static const struct vivid_format formats[] = { - { - .pixelformat = V4L2_SDR_FMT_CU8, - .buffersize = SDR_CAP_SAMPLES_PER_BUF * 2, - }, { - .pixelformat = V4L2_SDR_FMT_CS8, - .buffersize = SDR_CAP_SAMPLES_PER_BUF * 2, - }, -}; - -static const struct v4l2_frequency_band bands_adc[] = { - { - .tuner = 0, - .type = V4L2_TUNER_ADC, - .index = 0, - .capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS, - .rangelow = 300000, - .rangehigh = 300000, - }, - { - .tuner = 0, - .type = V4L2_TUNER_ADC, - .index = 1, - .capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS, - .rangelow = 900001, - .rangehigh = 2800000, - }, - { - .tuner = 0, - .type = V4L2_TUNER_ADC, - .index = 2, - .capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS, - .rangelow = 3200000, - .rangehigh = 3200000, - }, -}; - -/* ADC band midpoints */ -#define BAND_ADC_0 ((bands_adc[0].rangehigh + bands_adc[1].rangelow) / 2) -#define BAND_ADC_1 ((bands_adc[1].rangehigh + bands_adc[2].rangelow) / 2) - -static const struct v4l2_frequency_band bands_fm[] = { - { - .tuner = 1, - .type = V4L2_TUNER_RF, - .index = 0, - .capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS, - .rangelow = 50000000, - .rangehigh = 2000000000, - }, -}; - -static void vivid_thread_sdr_cap_tick(struct vivid_dev *dev) -{ - struct vivid_buffer *sdr_cap_buf = NULL; - - dprintk(dev, 1, "SDR Capture Thread Tick\n"); - - /* Drop a certain percentage of buffers. */ - if (dev->perc_dropped_buffers && - prandom_u32_max(100) < dev->perc_dropped_buffers) - return; - - spin_lock(&dev->slock); - if (!list_empty(&dev->sdr_cap_active)) { - sdr_cap_buf = list_entry(dev->sdr_cap_active.next, - struct vivid_buffer, list); - list_del(&sdr_cap_buf->list); - } - spin_unlock(&dev->slock); - - if (sdr_cap_buf) { - sdr_cap_buf->vb.sequence = dev->sdr_cap_seq_count; - v4l2_ctrl_request_setup(sdr_cap_buf->vb.vb2_buf.req_obj.req, - &dev->ctrl_hdl_sdr_cap); - v4l2_ctrl_request_complete(sdr_cap_buf->vb.vb2_buf.req_obj.req, - &dev->ctrl_hdl_sdr_cap); - vivid_sdr_cap_process(dev, sdr_cap_buf); - sdr_cap_buf->vb.vb2_buf.timestamp = - ktime_get_ns() + dev->time_wrap_offset; - vb2_buffer_done(&sdr_cap_buf->vb.vb2_buf, dev->dqbuf_error ? - VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE); - dev->dqbuf_error = false; - } -} - -static int vivid_thread_sdr_cap(void *data) -{ - struct vivid_dev *dev = data; - u64 samples_since_start; - u64 buffers_since_start; - u64 next_jiffies_since_start; - unsigned long jiffies_since_start; - unsigned long cur_jiffies; - unsigned wait_jiffies; - - dprintk(dev, 1, "SDR Capture Thread Start\n"); - - set_freezable(); - - /* Resets frame counters */ - dev->sdr_cap_seq_offset = 0; - if (dev->seq_wrap) - dev->sdr_cap_seq_offset = 0xffffff80U; - dev->jiffies_sdr_cap = jiffies; - dev->sdr_cap_seq_resync = false; - - for (;;) { - try_to_freeze(); - if (kthread_should_stop()) - break; - - if (!mutex_trylock(&dev->mutex)) { - schedule_timeout_uninterruptible(1); - continue; - } - - cur_jiffies = jiffies; - if (dev->sdr_cap_seq_resync) { - dev->jiffies_sdr_cap = cur_jiffies; - dev->sdr_cap_seq_offset = dev->sdr_cap_seq_count + 1; - dev->sdr_cap_seq_count = 0; - dev->sdr_cap_seq_resync = false; - } - /* Calculate the number of jiffies since we started streaming */ - jiffies_since_start = cur_jiffies - dev->jiffies_sdr_cap; - /* Get the number of buffers streamed since the start */ - buffers_since_start = - (u64)jiffies_since_start * dev->sdr_adc_freq + - (HZ * SDR_CAP_SAMPLES_PER_BUF) / 2; - do_div(buffers_since_start, HZ * SDR_CAP_SAMPLES_PER_BUF); - - /* - * After more than 0xf0000000 (rounded down to a multiple of - * 'jiffies-per-day' to ease jiffies_to_msecs calculation) - * jiffies have passed since we started streaming reset the - * counters and keep track of the sequence offset. - */ - if (jiffies_since_start > JIFFIES_RESYNC) { - dev->jiffies_sdr_cap = cur_jiffies; - dev->sdr_cap_seq_offset = buffers_since_start; - buffers_since_start = 0; - } - dev->sdr_cap_seq_count = - buffers_since_start + dev->sdr_cap_seq_offset; - - vivid_thread_sdr_cap_tick(dev); - mutex_unlock(&dev->mutex); - - /* - * Calculate the number of samples streamed since we started, - * not including the current buffer. - */ - samples_since_start = buffers_since_start * SDR_CAP_SAMPLES_PER_BUF; - - /* And the number of jiffies since we started */ - jiffies_since_start = jiffies - dev->jiffies_sdr_cap; - - /* Increase by the number of samples in one buffer */ - samples_since_start += SDR_CAP_SAMPLES_PER_BUF; - /* - * Calculate when that next buffer is supposed to start - * in jiffies since we started streaming. - */ - next_jiffies_since_start = samples_since_start * HZ + - dev->sdr_adc_freq / 2; - do_div(next_jiffies_since_start, dev->sdr_adc_freq); - /* If it is in the past, then just schedule asap */ - if (next_jiffies_since_start < jiffies_since_start) - next_jiffies_since_start = jiffies_since_start; - - wait_jiffies = next_jiffies_since_start - jiffies_since_start; - schedule_timeout_interruptible(wait_jiffies ? wait_jiffies : 1); - } - dprintk(dev, 1, "SDR Capture Thread End\n"); - return 0; -} - -static int sdr_cap_queue_setup(struct vb2_queue *vq, - unsigned *nbuffers, unsigned *nplanes, - unsigned sizes[], struct device *alloc_devs[]) -{ - /* 2 = max 16-bit sample returned */ - sizes[0] = SDR_CAP_SAMPLES_PER_BUF * 2; - *nplanes = 1; - return 0; -} - -static int sdr_cap_buf_prepare(struct vb2_buffer *vb) -{ - struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); - unsigned size = SDR_CAP_SAMPLES_PER_BUF * 2; - - dprintk(dev, 1, "%s\n", __func__); - - if (dev->buf_prepare_error) { - /* - * Error injection: test what happens if buf_prepare() returns - * an error. - */ - dev->buf_prepare_error = false; - return -EINVAL; - } - if (vb2_plane_size(vb, 0) < size) { - dprintk(dev, 1, "%s data will not fit into plane (%lu < %u)\n", - __func__, vb2_plane_size(vb, 0), size); - return -EINVAL; - } - vb2_set_plane_payload(vb, 0, size); - - return 0; -} - -static void sdr_cap_buf_queue(struct vb2_buffer *vb) -{ - struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); - struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); - struct vivid_buffer *buf = container_of(vbuf, struct vivid_buffer, vb); - - dprintk(dev, 1, "%s\n", __func__); - - spin_lock(&dev->slock); - list_add_tail(&buf->list, &dev->sdr_cap_active); - spin_unlock(&dev->slock); -} - -static int sdr_cap_start_streaming(struct vb2_queue *vq, unsigned count) -{ - struct vivid_dev *dev = vb2_get_drv_priv(vq); - int err = 0; - - dprintk(dev, 1, "%s\n", __func__); - dev->sdr_cap_seq_count = 0; - if (dev->start_streaming_error) { - dev->start_streaming_error = false; - err = -EINVAL; - } else if (dev->kthread_sdr_cap == NULL) { - dev->kthread_sdr_cap = kthread_run(vivid_thread_sdr_cap, dev, - "%s-sdr-cap", dev->v4l2_dev.name); - - if (IS_ERR(dev->kthread_sdr_cap)) { - v4l2_err(&dev->v4l2_dev, "kernel_thread() failed\n"); - err = PTR_ERR(dev->kthread_sdr_cap); - dev->kthread_sdr_cap = NULL; - } - } - if (err) { - struct vivid_buffer *buf, *tmp; - - list_for_each_entry_safe(buf, tmp, &dev->sdr_cap_active, list) { - list_del(&buf->list); - vb2_buffer_done(&buf->vb.vb2_buf, - VB2_BUF_STATE_QUEUED); - } - } - return err; -} - -/* abort streaming and wait for last buffer */ -static void sdr_cap_stop_streaming(struct vb2_queue *vq) -{ - struct vivid_dev *dev = vb2_get_drv_priv(vq); - - if (dev->kthread_sdr_cap == NULL) - return; - - while (!list_empty(&dev->sdr_cap_active)) { - struct vivid_buffer *buf; - - buf = list_entry(dev->sdr_cap_active.next, - struct vivid_buffer, list); - list_del(&buf->list); - v4l2_ctrl_request_complete(buf->vb.vb2_buf.req_obj.req, - &dev->ctrl_hdl_sdr_cap); - vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); - } - - /* shutdown control thread */ - kthread_stop(dev->kthread_sdr_cap); - dev->kthread_sdr_cap = NULL; -} - -static void sdr_cap_buf_request_complete(struct vb2_buffer *vb) -{ - struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); - - v4l2_ctrl_request_complete(vb->req_obj.req, &dev->ctrl_hdl_sdr_cap); -} - -const struct vb2_ops vivid_sdr_cap_qops = { - .queue_setup = sdr_cap_queue_setup, - .buf_prepare = sdr_cap_buf_prepare, - .buf_queue = sdr_cap_buf_queue, - .start_streaming = sdr_cap_start_streaming, - .stop_streaming = sdr_cap_stop_streaming, - .buf_request_complete = sdr_cap_buf_request_complete, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, -}; - -int vivid_sdr_enum_freq_bands(struct file *file, void *fh, - struct v4l2_frequency_band *band) -{ - switch (band->tuner) { - case 0: - if (band->index >= ARRAY_SIZE(bands_adc)) - return -EINVAL; - *band = bands_adc[band->index]; - return 0; - case 1: - if (band->index >= ARRAY_SIZE(bands_fm)) - return -EINVAL; - *band = bands_fm[band->index]; - return 0; - default: - return -EINVAL; - } -} - -int vivid_sdr_g_frequency(struct file *file, void *fh, - struct v4l2_frequency *vf) -{ - struct vivid_dev *dev = video_drvdata(file); - - switch (vf->tuner) { - case 0: - vf->frequency = dev->sdr_adc_freq; - vf->type = V4L2_TUNER_ADC; - return 0; - case 1: - vf->frequency = dev->sdr_fm_freq; - vf->type = V4L2_TUNER_RF; - return 0; - default: - return -EINVAL; - } -} - -int vivid_sdr_s_frequency(struct file *file, void *fh, - const struct v4l2_frequency *vf) -{ - struct vivid_dev *dev = video_drvdata(file); - unsigned freq = vf->frequency; - unsigned band; - - switch (vf->tuner) { - case 0: - if (vf->type != V4L2_TUNER_ADC) - return -EINVAL; - if (freq < BAND_ADC_0) - band = 0; - else if (freq < BAND_ADC_1) - band = 1; - else - band = 2; - - freq = clamp_t(unsigned, freq, - bands_adc[band].rangelow, - bands_adc[band].rangehigh); - - if (vb2_is_streaming(&dev->vb_sdr_cap_q) && - freq != dev->sdr_adc_freq) { - /* resync the thread's timings */ - dev->sdr_cap_seq_resync = true; - } - dev->sdr_adc_freq = freq; - return 0; - case 1: - if (vf->type != V4L2_TUNER_RF) - return -EINVAL; - dev->sdr_fm_freq = clamp_t(unsigned, freq, - bands_fm[0].rangelow, - bands_fm[0].rangehigh); - return 0; - default: - return -EINVAL; - } -} - -int vivid_sdr_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt) -{ - switch (vt->index) { - case 0: - strscpy(vt->name, "ADC", sizeof(vt->name)); - vt->type = V4L2_TUNER_ADC; - vt->capability = - V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS; - vt->rangelow = bands_adc[0].rangelow; - vt->rangehigh = bands_adc[2].rangehigh; - return 0; - case 1: - strscpy(vt->name, "RF", sizeof(vt->name)); - vt->type = V4L2_TUNER_RF; - vt->capability = - V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS; - vt->rangelow = bands_fm[0].rangelow; - vt->rangehigh = bands_fm[0].rangehigh; - return 0; - default: - return -EINVAL; - } -} - -int vivid_sdr_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *vt) -{ - if (vt->index > 1) - return -EINVAL; - return 0; -} - -int vidioc_enum_fmt_sdr_cap(struct file *file, void *fh, struct v4l2_fmtdesc *f) -{ - if (f->index >= ARRAY_SIZE(formats)) - return -EINVAL; - f->pixelformat = formats[f->index].pixelformat; - return 0; -} - -int vidioc_g_fmt_sdr_cap(struct file *file, void *fh, struct v4l2_format *f) -{ - struct vivid_dev *dev = video_drvdata(file); - - f->fmt.sdr.pixelformat = dev->sdr_pixelformat; - f->fmt.sdr.buffersize = dev->sdr_buffersize; - memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved)); - return 0; -} - -int vidioc_s_fmt_sdr_cap(struct file *file, void *fh, struct v4l2_format *f) -{ - struct vivid_dev *dev = video_drvdata(file); - struct vb2_queue *q = &dev->vb_sdr_cap_q; - int i; - - if (vb2_is_busy(q)) - return -EBUSY; - - memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved)); - for (i = 0; i < ARRAY_SIZE(formats); i++) { - if (formats[i].pixelformat == f->fmt.sdr.pixelformat) { - dev->sdr_pixelformat = formats[i].pixelformat; - dev->sdr_buffersize = formats[i].buffersize; - f->fmt.sdr.buffersize = formats[i].buffersize; - return 0; - } - } - dev->sdr_pixelformat = formats[0].pixelformat; - dev->sdr_buffersize = formats[0].buffersize; - f->fmt.sdr.pixelformat = formats[0].pixelformat; - f->fmt.sdr.buffersize = formats[0].buffersize; - return 0; -} - -int vidioc_try_fmt_sdr_cap(struct file *file, void *fh, struct v4l2_format *f) -{ - int i; - - memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved)); - for (i = 0; i < ARRAY_SIZE(formats); i++) { - if (formats[i].pixelformat == f->fmt.sdr.pixelformat) { - f->fmt.sdr.buffersize = formats[i].buffersize; - return 0; - } - } - f->fmt.sdr.pixelformat = formats[0].pixelformat; - f->fmt.sdr.buffersize = formats[0].buffersize; - return 0; -} - -#define FIXP_N (15) -#define FIXP_FRAC (1 << FIXP_N) -#define FIXP_2PI ((int)(2 * 3.141592653589 * FIXP_FRAC)) -#define M_100000PI (3.14159 * 100000) - -void vivid_sdr_cap_process(struct vivid_dev *dev, struct vivid_buffer *buf) -{ - u8 *vbuf = vb2_plane_vaddr(&buf->vb.vb2_buf, 0); - unsigned long i; - unsigned long plane_size = vb2_plane_size(&buf->vb.vb2_buf, 0); - s64 s64tmp; - s32 src_phase_step; - s32 mod_phase_step; - s32 fixp_i; - s32 fixp_q; - - /* calculate phase step */ - #define BEEP_FREQ 1000 /* 1kHz beep */ - src_phase_step = DIV_ROUND_CLOSEST(FIXP_2PI * BEEP_FREQ, - dev->sdr_adc_freq); - - for (i = 0; i < plane_size; i += 2) { - mod_phase_step = fixp_cos32_rad(dev->sdr_fixp_src_phase, - FIXP_2PI) >> (31 - FIXP_N); - - dev->sdr_fixp_src_phase += src_phase_step; - s64tmp = (s64) mod_phase_step * dev->sdr_fm_deviation; - dev->sdr_fixp_mod_phase += div_s64(s64tmp, M_100000PI); - - /* - * Transfer phase angle to [0, 2xPI] in order to avoid variable - * overflow and make it suitable for cosine implementation - * used, which does not support negative angles. - */ - dev->sdr_fixp_src_phase %= FIXP_2PI; - dev->sdr_fixp_mod_phase %= FIXP_2PI; - - if (dev->sdr_fixp_mod_phase < 0) - dev->sdr_fixp_mod_phase += FIXP_2PI; - - fixp_i = fixp_cos32_rad(dev->sdr_fixp_mod_phase, FIXP_2PI); - fixp_q = fixp_sin32_rad(dev->sdr_fixp_mod_phase, FIXP_2PI); - - /* Normalize fraction values represented with 32 bit precision - * to fixed point representation with FIXP_N bits */ - fixp_i >>= (31 - FIXP_N); - fixp_q >>= (31 - FIXP_N); - - switch (dev->sdr_pixelformat) { - case V4L2_SDR_FMT_CU8: - /* convert 'fixp float' to u8 [0, +255] */ - /* u8 = X * 127.5 + 127.5; X is float [-1.0, +1.0] */ - fixp_i = fixp_i * 1275 + FIXP_FRAC * 1275; - fixp_q = fixp_q * 1275 + FIXP_FRAC * 1275; - *vbuf++ = DIV_ROUND_CLOSEST(fixp_i, FIXP_FRAC * 10); - *vbuf++ = DIV_ROUND_CLOSEST(fixp_q, FIXP_FRAC * 10); - break; - case V4L2_SDR_FMT_CS8: - /* convert 'fixp float' to s8 [-128, +127] */ - /* s8 = X * 127.5 - 0.5; X is float [-1.0, +1.0] */ - fixp_i = fixp_i * 1275 - FIXP_FRAC * 5; - fixp_q = fixp_q * 1275 - FIXP_FRAC * 5; - *vbuf++ = DIV_ROUND_CLOSEST(fixp_i, FIXP_FRAC * 10); - *vbuf++ = DIV_ROUND_CLOSEST(fixp_q, FIXP_FRAC * 10); - break; - default: - break; - } - } -} diff --git a/drivers/media/platform/vivid/vivid-sdr-cap.h b/drivers/media/platform/vivid/vivid-sdr-cap.h deleted file mode 100644 index 813c9248e5a7..000000000000 --- a/drivers/media/platform/vivid/vivid-sdr-cap.h +++ /dev/null @@ -1,24 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * vivid-sdr-cap.h - software defined radio support functions. - * - * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - */ - -#ifndef _VIVID_SDR_CAP_H_ -#define _VIVID_SDR_CAP_H_ - -int vivid_sdr_enum_freq_bands(struct file *file, void *fh, struct v4l2_frequency_band *band); -int vivid_sdr_g_frequency(struct file *file, void *fh, struct v4l2_frequency *vf); -int vivid_sdr_s_frequency(struct file *file, void *fh, const struct v4l2_frequency *vf); -int vivid_sdr_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt); -int vivid_sdr_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *vt); -int vidioc_enum_fmt_sdr_cap(struct file *file, void *fh, struct v4l2_fmtdesc *f); -int vidioc_g_fmt_sdr_cap(struct file *file, void *fh, struct v4l2_format *f); -int vidioc_s_fmt_sdr_cap(struct file *file, void *fh, struct v4l2_format *f); -int vidioc_try_fmt_sdr_cap(struct file *file, void *fh, struct v4l2_format *f); -void vivid_sdr_cap_process(struct vivid_dev *dev, struct vivid_buffer *buf); - -extern const struct vb2_ops vivid_sdr_cap_qops; - -#endif diff --git a/drivers/media/platform/vivid/vivid-touch-cap.c b/drivers/media/platform/vivid/vivid-touch-cap.c deleted file mode 100644 index ebb00b128030..000000000000 --- a/drivers/media/platform/vivid/vivid-touch-cap.c +++ /dev/null @@ -1,341 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * vivid-touch-cap.c - touch support functions. - */ - -#include "vivid-core.h" -#include "vivid-kthread-touch.h" -#include "vivid-vid-common.h" -#include "vivid-touch-cap.h" - -static int touch_cap_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, - unsigned int *nplanes, unsigned int sizes[], - struct device *alloc_devs[]) -{ - struct vivid_dev *dev = vb2_get_drv_priv(vq); - struct v4l2_pix_format *f = &dev->tch_format; - unsigned int size = f->sizeimage; - - if (*nplanes) { - if (sizes[0] < size) - return -EINVAL; - } else { - sizes[0] = size; - } - - if (vq->num_buffers + *nbuffers < 2) - *nbuffers = 2 - vq->num_buffers; - - *nplanes = 1; - return 0; -} - -static int touch_cap_buf_prepare(struct vb2_buffer *vb) -{ - struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); - struct v4l2_pix_format *f = &dev->tch_format; - unsigned int size = f->sizeimage; - - if (dev->buf_prepare_error) { - /* - * Error injection: test what happens if buf_prepare() returns - * an error. - */ - dev->buf_prepare_error = false; - return -EINVAL; - } - if (vb2_plane_size(vb, 0) < size) { - dprintk(dev, 1, "%s data will not fit into plane (%lu < %u)\n", - __func__, vb2_plane_size(vb, 0), size); - return -EINVAL; - } - vb2_set_plane_payload(vb, 0, size); - - return 0; -} - -static void touch_cap_buf_queue(struct vb2_buffer *vb) -{ - struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); - struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); - struct vivid_buffer *buf = container_of(vbuf, struct vivid_buffer, vb); - - vbuf->field = V4L2_FIELD_NONE; - spin_lock(&dev->slock); - list_add_tail(&buf->list, &dev->touch_cap_active); - spin_unlock(&dev->slock); -} - -static int touch_cap_start_streaming(struct vb2_queue *vq, unsigned int count) -{ - struct vivid_dev *dev = vb2_get_drv_priv(vq); - int err; - - dev->touch_cap_seq_count = 0; - if (dev->start_streaming_error) { - dev->start_streaming_error = false; - err = -EINVAL; - } else { - err = vivid_start_generating_touch_cap(dev); - } - if (err) { - struct vivid_buffer *buf, *tmp; - - list_for_each_entry_safe(buf, tmp, - &dev->touch_cap_active, list) { - list_del(&buf->list); - vb2_buffer_done(&buf->vb.vb2_buf, - VB2_BUF_STATE_QUEUED); - } - } - return err; -} - -/* abort streaming and wait for last buffer */ -static void touch_cap_stop_streaming(struct vb2_queue *vq) -{ - struct vivid_dev *dev = vb2_get_drv_priv(vq); - - vivid_stop_generating_touch_cap(dev); -} - -static void touch_cap_buf_request_complete(struct vb2_buffer *vb) -{ - struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); - - v4l2_ctrl_request_complete(vb->req_obj.req, &dev->ctrl_hdl_touch_cap); -} - -const struct vb2_ops vivid_touch_cap_qops = { - .queue_setup = touch_cap_queue_setup, - .buf_prepare = touch_cap_buf_prepare, - .buf_queue = touch_cap_buf_queue, - .start_streaming = touch_cap_start_streaming, - .stop_streaming = touch_cap_stop_streaming, - .buf_request_complete = touch_cap_buf_request_complete, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, -}; - -int vivid_enum_fmt_tch(struct file *file, void *priv, struct v4l2_fmtdesc *f) -{ - if (f->index) - return -EINVAL; - - f->pixelformat = V4L2_TCH_FMT_DELTA_TD16; - return 0; -} - -int vivid_g_fmt_tch(struct file *file, void *priv, struct v4l2_format *f) -{ - struct vivid_dev *dev = video_drvdata(file); - - if (dev->multiplanar) - return -ENOTTY; - f->fmt.pix = dev->tch_format; - return 0; -} - -int vivid_g_fmt_tch_mplane(struct file *file, void *priv, struct v4l2_format *f) -{ - struct vivid_dev *dev = video_drvdata(file); - struct v4l2_format sp_fmt; - - if (!dev->multiplanar) - return -ENOTTY; - sp_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - sp_fmt.fmt.pix = dev->tch_format; - fmt_sp2mp(&sp_fmt, f); - return 0; -} - -int vivid_g_parm_tch(struct file *file, void *priv, - struct v4l2_streamparm *parm) -{ - struct vivid_dev *dev = video_drvdata(file); - - if (parm->type != (dev->multiplanar ? - V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE : - V4L2_BUF_TYPE_VIDEO_CAPTURE)) - return -EINVAL; - - parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; - parm->parm.capture.timeperframe = dev->timeperframe_tch_cap; - parm->parm.capture.readbuffers = 1; - return 0; -} - -int vivid_enum_input_tch(struct file *file, void *priv, struct v4l2_input *inp) -{ - if (inp->index) - return -EINVAL; - - inp->type = V4L2_INPUT_TYPE_TOUCH; - strscpy(inp->name, "Vivid Touch", sizeof(inp->name)); - inp->capabilities = 0; - return 0; -} - -int vivid_g_input_tch(struct file *file, void *priv, unsigned int *i) -{ - *i = 0; - return 0; -} - -int vivid_set_touch(struct vivid_dev *dev, unsigned int i) -{ - struct v4l2_pix_format *f = &dev->tch_format; - - if (i) - return -EINVAL; - - f->pixelformat = V4L2_TCH_FMT_DELTA_TD16; - f->width = VIVID_TCH_WIDTH; - f->height = VIVID_TCH_HEIGHT; - f->field = V4L2_FIELD_NONE; - f->colorspace = V4L2_COLORSPACE_RAW; - f->bytesperline = f->width * sizeof(s16); - f->sizeimage = f->width * f->height * sizeof(s16); - return 0; -} - -int vivid_s_input_tch(struct file *file, void *priv, unsigned int i) -{ - return vivid_set_touch(video_drvdata(file), i); -} - -static void vivid_fill_buff_noise(__s16 *tch_buf, int size) -{ - int i; - - /* Fill 10% of the values within range -3 and 3, zero the others */ - for (i = 0; i < size; i++) { - unsigned int rand = get_random_int(); - - if (rand % 10) - tch_buf[i] = 0; - else - tch_buf[i] = (rand / 10) % 7 - 3; - } -} - -static inline int get_random_pressure(void) -{ - return get_random_int() % VIVID_PRESSURE_LIMIT; -} - -static void vivid_tch_buf_set(struct v4l2_pix_format *f, - __s16 *tch_buf, - int index) -{ - unsigned int x = index % f->width; - unsigned int y = index / f->width; - unsigned int offset = VIVID_MIN_PRESSURE; - - tch_buf[index] = offset + get_random_pressure(); - offset /= 2; - if (x) - tch_buf[index - 1] = offset + get_random_pressure(); - if (x < f->width - 1) - tch_buf[index + 1] = offset + get_random_pressure(); - if (y) - tch_buf[index - f->width] = offset + get_random_pressure(); - if (y < f->height - 1) - tch_buf[index + f->width] = offset + get_random_pressure(); - offset /= 2; - if (x && y) - tch_buf[index - 1 - f->width] = offset + get_random_pressure(); - if (x < f->width - 1 && y) - tch_buf[index + 1 - f->width] = offset + get_random_pressure(); - if (x && y < f->height - 1) - tch_buf[index - 1 + f->width] = offset + get_random_pressure(); - if (x < f->width - 1 && y < f->height - 1) - tch_buf[index + 1 + f->width] = offset + get_random_pressure(); -} - -void vivid_fillbuff_tch(struct vivid_dev *dev, struct vivid_buffer *buf) -{ - struct v4l2_pix_format *f = &dev->tch_format; - int size = f->width * f->height; - int x, y, xstart, ystart, offset_x, offset_y; - unsigned int test_pattern, test_pat_idx, rand; - - __s16 *tch_buf = vb2_plane_vaddr(&buf->vb.vb2_buf, 0); - - buf->vb.sequence = dev->touch_cap_seq_count; - test_pattern = (buf->vb.sequence / TCH_SEQ_COUNT) % TEST_CASE_MAX; - test_pat_idx = buf->vb.sequence % TCH_SEQ_COUNT; - - vivid_fill_buff_noise(tch_buf, size); - - if (test_pat_idx >= TCH_PATTERN_COUNT) - return; - - if (test_pat_idx == 0) - dev->tch_pat_random = get_random_int(); - rand = dev->tch_pat_random; - - switch (test_pattern) { - case SINGLE_TAP: - if (test_pat_idx == 2) - vivid_tch_buf_set(f, tch_buf, rand % size); - break; - case DOUBLE_TAP: - if (test_pat_idx == 2 || test_pat_idx == 4) - vivid_tch_buf_set(f, tch_buf, rand % size); - break; - case TRIPLE_TAP: - if (test_pat_idx == 2 || test_pat_idx == 4 || test_pat_idx == 6) - vivid_tch_buf_set(f, tch_buf, rand % size); - break; - case MOVE_LEFT_TO_RIGHT: - vivid_tch_buf_set(f, tch_buf, - (rand % f->height) * f->width + - test_pat_idx * - (f->width / TCH_PATTERN_COUNT)); - break; - case ZOOM_IN: - x = f->width / 2; - y = f->height / 2; - offset_x = ((TCH_PATTERN_COUNT - 1 - test_pat_idx) * x) / - TCH_PATTERN_COUNT; - offset_y = ((TCH_PATTERN_COUNT - 1 - test_pat_idx) * y) / - TCH_PATTERN_COUNT; - vivid_tch_buf_set(f, tch_buf, - (x - offset_x) + f->width * (y - offset_y)); - vivid_tch_buf_set(f, tch_buf, - (x + offset_x) + f->width * (y + offset_y)); - break; - case ZOOM_OUT: - x = f->width / 2; - y = f->height / 2; - offset_x = (test_pat_idx * x) / TCH_PATTERN_COUNT; - offset_y = (test_pat_idx * y) / TCH_PATTERN_COUNT; - vivid_tch_buf_set(f, tch_buf, - (x - offset_x) + f->width * (y - offset_y)); - vivid_tch_buf_set(f, tch_buf, - (x + offset_x) + f->width * (y + offset_y)); - break; - case PALM_PRESS: - for (x = 0; x < f->width; x++) - for (y = f->height / 2; y < f->height; y++) - tch_buf[x + f->width * y] = VIVID_MIN_PRESSURE + - get_random_pressure(); - break; - case MULTIPLE_PRESS: - /* 16 pressure points */ - for (y = 0; y < 4; y++) { - for (x = 0; x < 4; x++) { - ystart = (y * f->height) / 4 + f->height / 8; - xstart = (x * f->width) / 4 + f->width / 8; - vivid_tch_buf_set(f, tch_buf, - ystart * f->width + xstart); - } - } - break; - } -#ifdef __BIG_ENDIAN__ - for (x = 0; x < size; x++) - tch_buf[x] = (__force s16)__cpu_to_le16((u16)tch_buf[x]); -#endif -} diff --git a/drivers/media/platform/vivid/vivid-touch-cap.h b/drivers/media/platform/vivid/vivid-touch-cap.h deleted file mode 100644 index 07e514046ae8..000000000000 --- a/drivers/media/platform/vivid/vivid-touch-cap.h +++ /dev/null @@ -1,39 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * vivid-touch-cap.h - touch support functions. - */ -#ifndef _VIVID_TOUCH_CAP_H_ -#define _VIVID_TOUCH_CAP_H_ - -#define VIVID_TCH_HEIGHT 12 -#define VIVID_TCH_WIDTH 21 -#define VIVID_MIN_PRESSURE 180 -#define VIVID_PRESSURE_LIMIT 40 -#define TCH_SEQ_COUNT 16 -#define TCH_PATTERN_COUNT 12 - -enum vivid_tch_test { - SINGLE_TAP, - DOUBLE_TAP, - TRIPLE_TAP, - MOVE_LEFT_TO_RIGHT, - ZOOM_IN, - ZOOM_OUT, - PALM_PRESS, - MULTIPLE_PRESS, - TEST_CASE_MAX -}; - -extern const struct vb2_ops vivid_touch_cap_qops; - -int vivid_enum_fmt_tch(struct file *file, void *priv, struct v4l2_fmtdesc *f); -int vivid_g_fmt_tch(struct file *file, void *priv, struct v4l2_format *f); -int vivid_g_fmt_tch_mplane(struct file *file, void *priv, struct v4l2_format *f); -int vivid_enum_input_tch(struct file *file, void *priv, struct v4l2_input *inp); -int vivid_g_input_tch(struct file *file, void *priv, unsigned int *i); -int vivid_s_input_tch(struct file *file, void *priv, unsigned int i); -void vivid_fillbuff_tch(struct vivid_dev *dev, struct vivid_buffer *buf); -int vivid_set_touch(struct vivid_dev *dev, unsigned int i); -int vivid_g_parm_tch(struct file *file, void *priv, - struct v4l2_streamparm *parm); -#endif diff --git a/drivers/media/platform/vivid/vivid-vbi-cap.c b/drivers/media/platform/vivid/vivid-vbi-cap.c deleted file mode 100644 index 1a9348eea781..000000000000 --- a/drivers/media/platform/vivid/vivid-vbi-cap.c +++ /dev/null @@ -1,365 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * vivid-vbi-cap.c - vbi capture support functions. - * - * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - */ - -#include -#include -#include -#include - -#include "vivid-core.h" -#include "vivid-kthread-cap.h" -#include "vivid-vbi-cap.h" -#include "vivid-vbi-gen.h" - -static void vivid_sliced_vbi_cap_fill(struct vivid_dev *dev, unsigned seqnr) -{ - struct vivid_vbi_gen_data *vbi_gen = &dev->vbi_gen; - bool is_60hz = dev->std_cap[dev->input] & V4L2_STD_525_60; - - vivid_vbi_gen_sliced(vbi_gen, is_60hz, seqnr); - - if (!is_60hz) { - if (dev->loop_video) { - if (dev->vbi_out_have_wss) { - vbi_gen->data[12].data[0] = dev->vbi_out_wss[0]; - vbi_gen->data[12].data[1] = dev->vbi_out_wss[1]; - } else { - vbi_gen->data[12].id = 0; - } - } else { - switch (tpg_g_video_aspect(&dev->tpg)) { - case TPG_VIDEO_ASPECT_14X9_CENTRE: - vbi_gen->data[12].data[0] = 0x01; - break; - case TPG_VIDEO_ASPECT_16X9_CENTRE: - vbi_gen->data[12].data[0] = 0x0b; - break; - case TPG_VIDEO_ASPECT_16X9_ANAMORPHIC: - vbi_gen->data[12].data[0] = 0x07; - break; - case TPG_VIDEO_ASPECT_4X3: - default: - vbi_gen->data[12].data[0] = 0x08; - break; - } - } - } else if (dev->loop_video && is_60hz) { - if (dev->vbi_out_have_cc[0]) { - vbi_gen->data[0].data[0] = dev->vbi_out_cc[0][0]; - vbi_gen->data[0].data[1] = dev->vbi_out_cc[0][1]; - } else { - vbi_gen->data[0].id = 0; - } - if (dev->vbi_out_have_cc[1]) { - vbi_gen->data[1].data[0] = dev->vbi_out_cc[1][0]; - vbi_gen->data[1].data[1] = dev->vbi_out_cc[1][1]; - } else { - vbi_gen->data[1].id = 0; - } - } -} - -static void vivid_g_fmt_vbi_cap(struct vivid_dev *dev, struct v4l2_vbi_format *vbi) -{ - bool is_60hz = dev->std_cap[dev->input] & V4L2_STD_525_60; - - vbi->sampling_rate = 27000000; - vbi->offset = 24; - vbi->samples_per_line = 1440; - vbi->sample_format = V4L2_PIX_FMT_GREY; - vbi->start[0] = is_60hz ? V4L2_VBI_ITU_525_F1_START + 9 : V4L2_VBI_ITU_625_F1_START + 5; - vbi->start[1] = is_60hz ? V4L2_VBI_ITU_525_F2_START + 9 : V4L2_VBI_ITU_625_F2_START + 5; - vbi->count[0] = vbi->count[1] = is_60hz ? 12 : 18; - vbi->flags = dev->vbi_cap_interlaced ? V4L2_VBI_INTERLACED : 0; - vbi->reserved[0] = 0; - vbi->reserved[1] = 0; -} - -void vivid_raw_vbi_cap_process(struct vivid_dev *dev, struct vivid_buffer *buf) -{ - struct v4l2_vbi_format vbi; - u8 *vbuf = vb2_plane_vaddr(&buf->vb.vb2_buf, 0); - - vivid_g_fmt_vbi_cap(dev, &vbi); - buf->vb.sequence = dev->vbi_cap_seq_count; - if (dev->field_cap == V4L2_FIELD_ALTERNATE) - buf->vb.sequence /= 2; - - vivid_sliced_vbi_cap_fill(dev, buf->vb.sequence); - - memset(vbuf, 0x10, vb2_plane_size(&buf->vb.vb2_buf, 0)); - - if (!VIVID_INVALID_SIGNAL(dev->std_signal_mode[dev->input])) - vivid_vbi_gen_raw(&dev->vbi_gen, &vbi, vbuf); -} - - -void vivid_sliced_vbi_cap_process(struct vivid_dev *dev, - struct vivid_buffer *buf) -{ - struct v4l2_sliced_vbi_data *vbuf = - vb2_plane_vaddr(&buf->vb.vb2_buf, 0); - - buf->vb.sequence = dev->vbi_cap_seq_count; - if (dev->field_cap == V4L2_FIELD_ALTERNATE) - buf->vb.sequence /= 2; - - vivid_sliced_vbi_cap_fill(dev, buf->vb.sequence); - - memset(vbuf, 0, vb2_plane_size(&buf->vb.vb2_buf, 0)); - if (!VIVID_INVALID_SIGNAL(dev->std_signal_mode[dev->input])) { - unsigned i; - - for (i = 0; i < 25; i++) - vbuf[i] = dev->vbi_gen.data[i]; - } -} - -static int vbi_cap_queue_setup(struct vb2_queue *vq, - unsigned *nbuffers, unsigned *nplanes, - unsigned sizes[], struct device *alloc_devs[]) -{ - struct vivid_dev *dev = vb2_get_drv_priv(vq); - bool is_60hz = dev->std_cap[dev->input] & V4L2_STD_525_60; - unsigned size = vq->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE ? - 36 * sizeof(struct v4l2_sliced_vbi_data) : - 1440 * 2 * (is_60hz ? 12 : 18); - - if (!vivid_is_sdtv_cap(dev)) - return -EINVAL; - - sizes[0] = size; - - if (vq->num_buffers + *nbuffers < 2) - *nbuffers = 2 - vq->num_buffers; - - *nplanes = 1; - return 0; -} - -static int vbi_cap_buf_prepare(struct vb2_buffer *vb) -{ - struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); - bool is_60hz = dev->std_cap[dev->input] & V4L2_STD_525_60; - unsigned size = vb->vb2_queue->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE ? - 36 * sizeof(struct v4l2_sliced_vbi_data) : - 1440 * 2 * (is_60hz ? 12 : 18); - - dprintk(dev, 1, "%s\n", __func__); - - if (dev->buf_prepare_error) { - /* - * Error injection: test what happens if buf_prepare() returns - * an error. - */ - dev->buf_prepare_error = false; - return -EINVAL; - } - if (vb2_plane_size(vb, 0) < size) { - dprintk(dev, 1, "%s data will not fit into plane (%lu < %u)\n", - __func__, vb2_plane_size(vb, 0), size); - return -EINVAL; - } - vb2_set_plane_payload(vb, 0, size); - - return 0; -} - -static void vbi_cap_buf_queue(struct vb2_buffer *vb) -{ - struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); - struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); - struct vivid_buffer *buf = container_of(vbuf, struct vivid_buffer, vb); - - dprintk(dev, 1, "%s\n", __func__); - - spin_lock(&dev->slock); - list_add_tail(&buf->list, &dev->vbi_cap_active); - spin_unlock(&dev->slock); -} - -static int vbi_cap_start_streaming(struct vb2_queue *vq, unsigned count) -{ - struct vivid_dev *dev = vb2_get_drv_priv(vq); - int err; - - dprintk(dev, 1, "%s\n", __func__); - dev->vbi_cap_seq_count = 0; - if (dev->start_streaming_error) { - dev->start_streaming_error = false; - err = -EINVAL; - } else { - err = vivid_start_generating_vid_cap(dev, &dev->vbi_cap_streaming); - } - if (err) { - struct vivid_buffer *buf, *tmp; - - list_for_each_entry_safe(buf, tmp, &dev->vbi_cap_active, list) { - list_del(&buf->list); - vb2_buffer_done(&buf->vb.vb2_buf, - VB2_BUF_STATE_QUEUED); - } - } - return err; -} - -/* abort streaming and wait for last buffer */ -static void vbi_cap_stop_streaming(struct vb2_queue *vq) -{ - struct vivid_dev *dev = vb2_get_drv_priv(vq); - - dprintk(dev, 1, "%s\n", __func__); - vivid_stop_generating_vid_cap(dev, &dev->vbi_cap_streaming); -} - -static void vbi_cap_buf_request_complete(struct vb2_buffer *vb) -{ - struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); - - v4l2_ctrl_request_complete(vb->req_obj.req, &dev->ctrl_hdl_vbi_cap); -} - -const struct vb2_ops vivid_vbi_cap_qops = { - .queue_setup = vbi_cap_queue_setup, - .buf_prepare = vbi_cap_buf_prepare, - .buf_queue = vbi_cap_buf_queue, - .start_streaming = vbi_cap_start_streaming, - .stop_streaming = vbi_cap_stop_streaming, - .buf_request_complete = vbi_cap_buf_request_complete, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, -}; - -int vidioc_g_fmt_vbi_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct vivid_dev *dev = video_drvdata(file); - struct v4l2_vbi_format *vbi = &f->fmt.vbi; - - if (!vivid_is_sdtv_cap(dev) || !dev->has_raw_vbi_cap) - return -EINVAL; - - vivid_g_fmt_vbi_cap(dev, vbi); - return 0; -} - -int vidioc_s_fmt_vbi_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct vivid_dev *dev = video_drvdata(file); - int ret = vidioc_g_fmt_vbi_cap(file, priv, f); - - if (ret) - return ret; - if (dev->stream_sliced_vbi_cap && vb2_is_busy(&dev->vb_vbi_cap_q)) - return -EBUSY; - dev->stream_sliced_vbi_cap = false; - dev->vbi_cap_dev.queue->type = V4L2_BUF_TYPE_VBI_CAPTURE; - return 0; -} - -void vivid_fill_service_lines(struct v4l2_sliced_vbi_format *vbi, u32 service_set) -{ - vbi->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36; - vbi->service_set = service_set; - memset(vbi->service_lines, 0, sizeof(vbi->service_lines)); - memset(vbi->reserved, 0, sizeof(vbi->reserved)); - - if (vbi->service_set == 0) - return; - - if (vbi->service_set & V4L2_SLICED_CAPTION_525) { - vbi->service_lines[0][21] = V4L2_SLICED_CAPTION_525; - vbi->service_lines[1][21] = V4L2_SLICED_CAPTION_525; - } - if (vbi->service_set & V4L2_SLICED_WSS_625) { - unsigned i; - - for (i = 7; i <= 18; i++) - vbi->service_lines[0][i] = - vbi->service_lines[1][i] = V4L2_SLICED_TELETEXT_B; - vbi->service_lines[0][23] = V4L2_SLICED_WSS_625; - } -} - -int vidioc_g_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) -{ - struct vivid_dev *dev = video_drvdata(file); - struct v4l2_sliced_vbi_format *vbi = &fmt->fmt.sliced; - - if (!vivid_is_sdtv_cap(dev) || !dev->has_sliced_vbi_cap) - return -EINVAL; - - vivid_fill_service_lines(vbi, dev->service_set_cap); - return 0; -} - -int vidioc_try_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) -{ - struct vivid_dev *dev = video_drvdata(file); - struct v4l2_sliced_vbi_format *vbi = &fmt->fmt.sliced; - bool is_60hz = dev->std_cap[dev->input] & V4L2_STD_525_60; - u32 service_set = vbi->service_set; - - if (!vivid_is_sdtv_cap(dev) || !dev->has_sliced_vbi_cap) - return -EINVAL; - - service_set &= is_60hz ? V4L2_SLICED_CAPTION_525 : - V4L2_SLICED_WSS_625 | V4L2_SLICED_TELETEXT_B; - vivid_fill_service_lines(vbi, service_set); - return 0; -} - -int vidioc_s_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) -{ - struct vivid_dev *dev = video_drvdata(file); - struct v4l2_sliced_vbi_format *vbi = &fmt->fmt.sliced; - int ret = vidioc_try_fmt_sliced_vbi_cap(file, fh, fmt); - - if (ret) - return ret; - if (!dev->stream_sliced_vbi_cap && vb2_is_busy(&dev->vb_vbi_cap_q)) - return -EBUSY; - dev->service_set_cap = vbi->service_set; - dev->stream_sliced_vbi_cap = true; - dev->vbi_cap_dev.queue->type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE; - return 0; -} - -int vidioc_g_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_sliced_vbi_cap *cap) -{ - struct vivid_dev *dev = video_drvdata(file); - struct video_device *vdev = video_devdata(file); - bool is_60hz; - - if (vdev->vfl_dir == VFL_DIR_RX) { - is_60hz = dev->std_cap[dev->input] & V4L2_STD_525_60; - if (!vivid_is_sdtv_cap(dev) || !dev->has_sliced_vbi_cap || - cap->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) - return -EINVAL; - } else { - is_60hz = dev->std_out & V4L2_STD_525_60; - if (!vivid_is_svid_out(dev) || !dev->has_sliced_vbi_out || - cap->type != V4L2_BUF_TYPE_SLICED_VBI_OUTPUT) - return -EINVAL; - } - - cap->service_set = is_60hz ? V4L2_SLICED_CAPTION_525 : - V4L2_SLICED_WSS_625 | V4L2_SLICED_TELETEXT_B; - if (is_60hz) { - cap->service_lines[0][21] = V4L2_SLICED_CAPTION_525; - cap->service_lines[1][21] = V4L2_SLICED_CAPTION_525; - } else { - unsigned i; - - for (i = 7; i <= 18; i++) - cap->service_lines[0][i] = - cap->service_lines[1][i] = V4L2_SLICED_TELETEXT_B; - cap->service_lines[0][23] = V4L2_SLICED_WSS_625; - } - return 0; -} diff --git a/drivers/media/platform/vivid/vivid-vbi-cap.h b/drivers/media/platform/vivid/vivid-vbi-cap.h deleted file mode 100644 index 91d2de01381c..000000000000 --- a/drivers/media/platform/vivid/vivid-vbi-cap.h +++ /dev/null @@ -1,28 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * vivid-vbi-cap.h - vbi capture support functions. - * - * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - */ - -#ifndef _VIVID_VBI_CAP_H_ -#define _VIVID_VBI_CAP_H_ - -void vivid_fill_time_of_day_packet(u8 *packet); -void vivid_raw_vbi_cap_process(struct vivid_dev *dev, struct vivid_buffer *buf); -void vivid_sliced_vbi_cap_process(struct vivid_dev *dev, struct vivid_buffer *buf); -void vivid_sliced_vbi_out_process(struct vivid_dev *dev, struct vivid_buffer *buf); -int vidioc_g_fmt_vbi_cap(struct file *file, void *priv, - struct v4l2_format *f); -int vidioc_s_fmt_vbi_cap(struct file *file, void *priv, - struct v4l2_format *f); -int vidioc_g_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt); -int vidioc_try_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt); -int vidioc_s_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt); -int vidioc_g_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_sliced_vbi_cap *cap); - -void vivid_fill_service_lines(struct v4l2_sliced_vbi_format *vbi, u32 service_set); - -extern const struct vb2_ops vivid_vbi_cap_qops; - -#endif diff --git a/drivers/media/platform/vivid/vivid-vbi-gen.c b/drivers/media/platform/vivid/vivid-vbi-gen.c deleted file mode 100644 index acc98445a1fa..000000000000 --- a/drivers/media/platform/vivid/vivid-vbi-gen.c +++ /dev/null @@ -1,311 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * vivid-vbi-gen.c - vbi generator support functions. - * - * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - */ - -#include -#include -#include -#include -#include - -#include "vivid-vbi-gen.h" - -static void wss_insert(u8 *wss, u32 val, unsigned size) -{ - while (size--) - *wss++ = (val & (1 << size)) ? 0xc0 : 0x10; -} - -static void vivid_vbi_gen_wss_raw(const struct v4l2_sliced_vbi_data *data, - u8 *buf, unsigned sampling_rate) -{ - const unsigned rate = 5000000; /* WSS has a 5 MHz transmission rate */ - u8 wss[29 + 24 + 24 + 24 + 18 + 18] = { 0 }; - const unsigned zero = 0x07; - const unsigned one = 0x38; - unsigned bit = 0; - u16 wss_data; - int i; - - wss_insert(wss + bit, 0x1f1c71c7, 29); bit += 29; - wss_insert(wss + bit, 0x1e3c1f, 24); bit += 24; - - wss_data = (data->data[1] << 8) | data->data[0]; - for (i = 0; i <= 13; i++, bit += 6) - wss_insert(wss + bit, (wss_data & (1 << i)) ? one : zero, 6); - - for (i = 0, bit = 0; bit < sizeof(wss); bit++) { - unsigned n = ((bit + 1) * sampling_rate) / rate; - - while (i < n) - buf[i++] = wss[bit]; - } -} - -static void vivid_vbi_gen_teletext_raw(const struct v4l2_sliced_vbi_data *data, - u8 *buf, unsigned sampling_rate) -{ - const unsigned rate = 6937500 / 10; /* Teletext has a 6.9375 MHz transmission rate */ - u8 teletext[45] = { 0x55, 0x55, 0x27 }; - unsigned bit = 0; - int i; - - memcpy(teletext + 3, data->data, sizeof(teletext) - 3); - /* prevents 32 bit overflow */ - sampling_rate /= 10; - - for (i = 0, bit = 0; bit < sizeof(teletext) * 8; bit++) { - unsigned n = ((bit + 1) * sampling_rate) / rate; - u8 val = (teletext[bit / 8] & (1 << (bit & 7))) ? 0xc0 : 0x10; - - while (i < n) - buf[i++] = val; - } -} - -static void cc_insert(u8 *cc, u8 ch) -{ - unsigned tot = 0; - unsigned i; - - for (i = 0; i < 7; i++) { - cc[2 * i] = cc[2 * i + 1] = (ch & (1 << i)) ? 1 : 0; - tot += cc[2 * i]; - } - cc[14] = cc[15] = !(tot & 1); -} - -#define CC_PREAMBLE_BITS (14 + 4 + 2) - -static void vivid_vbi_gen_cc_raw(const struct v4l2_sliced_vbi_data *data, - u8 *buf, unsigned sampling_rate) -{ - const unsigned rate = 1000000; /* CC has a 1 MHz transmission rate */ - - u8 cc[CC_PREAMBLE_BITS + 2 * 16] = { - /* Clock run-in: 7 cycles */ - 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, - /* 2 cycles of 0 */ - 0, 0, 0, 0, - /* Start bit of 1 (each bit is two cycles) */ - 1, 1 - }; - unsigned bit, i; - - cc_insert(cc + CC_PREAMBLE_BITS, data->data[0]); - cc_insert(cc + CC_PREAMBLE_BITS + 16, data->data[1]); - - for (i = 0, bit = 0; bit < sizeof(cc); bit++) { - unsigned n = ((bit + 1) * sampling_rate) / rate; - - while (i < n) - buf[i++] = cc[bit] ? 0xc0 : 0x10; - } -} - -void vivid_vbi_gen_raw(const struct vivid_vbi_gen_data *vbi, - const struct v4l2_vbi_format *vbi_fmt, u8 *buf) -{ - unsigned idx; - - for (idx = 0; idx < 25; idx++) { - const struct v4l2_sliced_vbi_data *data = vbi->data + idx; - unsigned start_2nd_field; - unsigned line = data->line; - u8 *linebuf = buf; - - start_2nd_field = (data->id & V4L2_SLICED_VBI_525) ? 263 : 313; - if (data->field) - line += start_2nd_field; - line -= vbi_fmt->start[data->field]; - - if (vbi_fmt->flags & V4L2_VBI_INTERLACED) - linebuf += (line * 2 + data->field) * - vbi_fmt->samples_per_line; - else - linebuf += (line + data->field * vbi_fmt->count[0]) * - vbi_fmt->samples_per_line; - if (data->id == V4L2_SLICED_CAPTION_525) - vivid_vbi_gen_cc_raw(data, linebuf, vbi_fmt->sampling_rate); - else if (data->id == V4L2_SLICED_WSS_625) - vivid_vbi_gen_wss_raw(data, linebuf, vbi_fmt->sampling_rate); - else if (data->id == V4L2_SLICED_TELETEXT_B) - vivid_vbi_gen_teletext_raw(data, linebuf, vbi_fmt->sampling_rate); - } -} - -static const u8 vivid_cc_sequence1[30] = { - 0x14, 0x20, /* Resume Caption Loading */ - 'H', 'e', - 'l', 'l', - 'o', ' ', - 'w', 'o', - 'r', 'l', - 'd', '!', - 0x14, 0x2f, /* End of Caption */ -}; - -static const u8 vivid_cc_sequence2[30] = { - 0x14, 0x20, /* Resume Caption Loading */ - 'C', 'l', - 'o', 's', - 'e', 'd', - ' ', 'c', - 'a', 'p', - 't', 'i', - 'o', 'n', - 's', ' ', - 't', 'e', - 's', 't', - 0x14, 0x2f, /* End of Caption */ -}; - -static u8 calc_parity(u8 val) -{ - unsigned i; - unsigned tot = 0; - - for (i = 0; i < 7; i++) - tot += (val & (1 << i)) ? 1 : 0; - return val | ((tot & 1) ? 0 : 0x80); -} - -static void vivid_vbi_gen_set_time_of_day(u8 *packet) -{ - struct tm tm; - u8 checksum, i; - - time64_to_tm(ktime_get_real_seconds(), 0, &tm); - packet[0] = calc_parity(0x07); - packet[1] = calc_parity(0x01); - packet[2] = calc_parity(0x40 | tm.tm_min); - packet[3] = calc_parity(0x40 | tm.tm_hour); - packet[4] = calc_parity(0x40 | tm.tm_mday); - if (tm.tm_mday == 1 && tm.tm_mon == 2 && - sys_tz.tz_minuteswest > tm.tm_min + tm.tm_hour * 60) - packet[4] = calc_parity(0x60 | tm.tm_mday); - packet[5] = calc_parity(0x40 | (1 + tm.tm_mon)); - packet[6] = calc_parity(0x40 | (1 + tm.tm_wday)); - packet[7] = calc_parity(0x40 | ((tm.tm_year - 90) & 0x3f)); - packet[8] = calc_parity(0x0f); - for (checksum = i = 0; i <= 8; i++) - checksum += packet[i] & 0x7f; - packet[9] = calc_parity(0x100 - checksum); - checksum = 0; - packet[10] = calc_parity(0x07); - packet[11] = calc_parity(0x04); - if (sys_tz.tz_minuteswest >= 0) - packet[12] = calc_parity(0x40 | ((sys_tz.tz_minuteswest / 60) & 0x1f)); - else - packet[12] = calc_parity(0x40 | ((24 + sys_tz.tz_minuteswest / 60) & 0x1f)); - packet[13] = calc_parity(0); - packet[14] = calc_parity(0x0f); - for (checksum = 0, i = 10; i <= 14; i++) - checksum += packet[i] & 0x7f; - packet[15] = calc_parity(0x100 - checksum); -} - -static const u8 hamming[16] = { - 0x15, 0x02, 0x49, 0x5e, 0x64, 0x73, 0x38, 0x2f, - 0xd0, 0xc7, 0x8c, 0x9b, 0xa1, 0xb6, 0xfd, 0xea -}; - -static void vivid_vbi_gen_teletext(u8 *packet, unsigned line, unsigned frame) -{ - unsigned offset = 2; - unsigned i; - - packet[0] = hamming[1 + ((line & 1) << 3)]; - packet[1] = hamming[line >> 1]; - memset(packet + 2, 0x20, 40); - if (line == 0) { - /* subcode */ - packet[2] = hamming[frame % 10]; - packet[3] = hamming[frame / 10]; - packet[4] = hamming[0]; - packet[5] = hamming[0]; - packet[6] = hamming[0]; - packet[7] = hamming[0]; - packet[8] = hamming[0]; - packet[9] = hamming[1]; - offset = 10; - } - packet += offset; - memcpy(packet, "Page: 100 Row: 10", 17); - packet[7] = '0' + frame / 10; - packet[8] = '0' + frame % 10; - packet[15] = '0' + line / 10; - packet[16] = '0' + line % 10; - for (i = 0; i < 42 - offset; i++) - packet[i] = calc_parity(packet[i]); -} - -void vivid_vbi_gen_sliced(struct vivid_vbi_gen_data *vbi, - bool is_60hz, unsigned seqnr) -{ - struct v4l2_sliced_vbi_data *data0 = vbi->data; - struct v4l2_sliced_vbi_data *data1 = vbi->data + 1; - unsigned frame = seqnr % 60; - - memset(vbi->data, 0, sizeof(vbi->data)); - - if (!is_60hz) { - unsigned i; - - for (i = 0; i <= 11; i++) { - data0->id = V4L2_SLICED_TELETEXT_B; - data0->line = 7 + i; - vivid_vbi_gen_teletext(data0->data, i, frame); - data0++; - } - data0->id = V4L2_SLICED_WSS_625; - data0->line = 23; - /* 4x3 video aspect ratio */ - data0->data[0] = 0x08; - data0++; - for (i = 0; i <= 11; i++) { - data0->id = V4L2_SLICED_TELETEXT_B; - data0->field = 1; - data0->line = 7 + i; - vivid_vbi_gen_teletext(data0->data, 12 + i, frame); - data0++; - } - return; - } - - data0->id = V4L2_SLICED_CAPTION_525; - data0->line = 21; - data1->id = V4L2_SLICED_CAPTION_525; - data1->field = 1; - data1->line = 21; - - if (frame < 15) { - data0->data[0] = calc_parity(vivid_cc_sequence1[2 * frame]); - data0->data[1] = calc_parity(vivid_cc_sequence1[2 * frame + 1]); - } else if (frame >= 30 && frame < 45) { - frame -= 30; - data0->data[0] = calc_parity(vivid_cc_sequence2[2 * frame]); - data0->data[1] = calc_parity(vivid_cc_sequence2[2 * frame + 1]); - } else { - data0->data[0] = calc_parity(0); - data0->data[1] = calc_parity(0); - } - - frame = seqnr % (30 * 60); - switch (frame) { - case 0: - vivid_vbi_gen_set_time_of_day(vbi->time_of_day_packet); - /* fall through */ - case 1 ... 7: - data1->data[0] = vbi->time_of_day_packet[frame * 2]; - data1->data[1] = vbi->time_of_day_packet[frame * 2 + 1]; - break; - default: - data1->data[0] = calc_parity(0); - data1->data[1] = calc_parity(0); - break; - } -} diff --git a/drivers/media/platform/vivid/vivid-vbi-gen.h b/drivers/media/platform/vivid/vivid-vbi-gen.h deleted file mode 100644 index 2657a7f5571c..000000000000 --- a/drivers/media/platform/vivid/vivid-vbi-gen.h +++ /dev/null @@ -1,21 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * vivid-vbi-gen.h - vbi generator support functions. - * - * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - */ - -#ifndef _VIVID_VBI_GEN_H_ -#define _VIVID_VBI_GEN_H_ - -struct vivid_vbi_gen_data { - struct v4l2_sliced_vbi_data data[25]; - u8 time_of_day_packet[16]; -}; - -void vivid_vbi_gen_sliced(struct vivid_vbi_gen_data *vbi, - bool is_60hz, unsigned seqnr); -void vivid_vbi_gen_raw(const struct vivid_vbi_gen_data *vbi, - const struct v4l2_vbi_format *vbi_fmt, u8 *buf); - -#endif diff --git a/drivers/media/platform/vivid/vivid-vbi-out.c b/drivers/media/platform/vivid/vivid-vbi-out.c deleted file mode 100644 index cd56476902a2..000000000000 --- a/drivers/media/platform/vivid/vivid-vbi-out.c +++ /dev/null @@ -1,250 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * vivid-vbi-out.c - vbi output support functions. - * - * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - */ - -#include -#include -#include -#include - -#include "vivid-core.h" -#include "vivid-kthread-out.h" -#include "vivid-vbi-out.h" -#include "vivid-vbi-cap.h" - -static int vbi_out_queue_setup(struct vb2_queue *vq, - unsigned *nbuffers, unsigned *nplanes, - unsigned sizes[], struct device *alloc_devs[]) -{ - struct vivid_dev *dev = vb2_get_drv_priv(vq); - bool is_60hz = dev->std_out & V4L2_STD_525_60; - unsigned size = vq->type == V4L2_BUF_TYPE_SLICED_VBI_OUTPUT ? - 36 * sizeof(struct v4l2_sliced_vbi_data) : - 1440 * 2 * (is_60hz ? 12 : 18); - - if (!vivid_is_svid_out(dev)) - return -EINVAL; - - sizes[0] = size; - - if (vq->num_buffers + *nbuffers < 2) - *nbuffers = 2 - vq->num_buffers; - - *nplanes = 1; - return 0; -} - -static int vbi_out_buf_prepare(struct vb2_buffer *vb) -{ - struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); - bool is_60hz = dev->std_out & V4L2_STD_525_60; - unsigned size = vb->vb2_queue->type == V4L2_BUF_TYPE_SLICED_VBI_OUTPUT ? - 36 * sizeof(struct v4l2_sliced_vbi_data) : - 1440 * 2 * (is_60hz ? 12 : 18); - - dprintk(dev, 1, "%s\n", __func__); - - if (dev->buf_prepare_error) { - /* - * Error injection: test what happens if buf_prepare() returns - * an error. - */ - dev->buf_prepare_error = false; - return -EINVAL; - } - if (vb2_plane_size(vb, 0) < size) { - dprintk(dev, 1, "%s data will not fit into plane (%lu < %u)\n", - __func__, vb2_plane_size(vb, 0), size); - return -EINVAL; - } - vb2_set_plane_payload(vb, 0, size); - - return 0; -} - -static void vbi_out_buf_queue(struct vb2_buffer *vb) -{ - struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); - struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); - struct vivid_buffer *buf = container_of(vbuf, struct vivid_buffer, vb); - - dprintk(dev, 1, "%s\n", __func__); - - spin_lock(&dev->slock); - list_add_tail(&buf->list, &dev->vbi_out_active); - spin_unlock(&dev->slock); -} - -static int vbi_out_start_streaming(struct vb2_queue *vq, unsigned count) -{ - struct vivid_dev *dev = vb2_get_drv_priv(vq); - int err; - - dprintk(dev, 1, "%s\n", __func__); - dev->vbi_out_seq_count = 0; - if (dev->start_streaming_error) { - dev->start_streaming_error = false; - err = -EINVAL; - } else { - err = vivid_start_generating_vid_out(dev, &dev->vbi_out_streaming); - } - if (err) { - struct vivid_buffer *buf, *tmp; - - list_for_each_entry_safe(buf, tmp, &dev->vbi_out_active, list) { - list_del(&buf->list); - vb2_buffer_done(&buf->vb.vb2_buf, - VB2_BUF_STATE_QUEUED); - } - } - return err; -} - -/* abort streaming and wait for last buffer */ -static void vbi_out_stop_streaming(struct vb2_queue *vq) -{ - struct vivid_dev *dev = vb2_get_drv_priv(vq); - - dprintk(dev, 1, "%s\n", __func__); - vivid_stop_generating_vid_out(dev, &dev->vbi_out_streaming); - dev->vbi_out_have_wss = false; - dev->vbi_out_have_cc[0] = false; - dev->vbi_out_have_cc[1] = false; -} - -static void vbi_out_buf_request_complete(struct vb2_buffer *vb) -{ - struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); - - v4l2_ctrl_request_complete(vb->req_obj.req, &dev->ctrl_hdl_vbi_out); -} - -const struct vb2_ops vivid_vbi_out_qops = { - .queue_setup = vbi_out_queue_setup, - .buf_prepare = vbi_out_buf_prepare, - .buf_queue = vbi_out_buf_queue, - .start_streaming = vbi_out_start_streaming, - .stop_streaming = vbi_out_stop_streaming, - .buf_request_complete = vbi_out_buf_request_complete, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, -}; - -int vidioc_g_fmt_vbi_out(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct vivid_dev *dev = video_drvdata(file); - struct v4l2_vbi_format *vbi = &f->fmt.vbi; - bool is_60hz = dev->std_out & V4L2_STD_525_60; - - if (!vivid_is_svid_out(dev) || !dev->has_raw_vbi_out) - return -EINVAL; - - vbi->sampling_rate = 25000000; - vbi->offset = 24; - vbi->samples_per_line = 1440; - vbi->sample_format = V4L2_PIX_FMT_GREY; - vbi->start[0] = is_60hz ? V4L2_VBI_ITU_525_F1_START + 9 : V4L2_VBI_ITU_625_F1_START + 5; - vbi->start[1] = is_60hz ? V4L2_VBI_ITU_525_F2_START + 9 : V4L2_VBI_ITU_625_F2_START + 5; - vbi->count[0] = vbi->count[1] = is_60hz ? 12 : 18; - vbi->flags = dev->vbi_cap_interlaced ? V4L2_VBI_INTERLACED : 0; - vbi->reserved[0] = 0; - vbi->reserved[1] = 0; - return 0; -} - -int vidioc_s_fmt_vbi_out(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct vivid_dev *dev = video_drvdata(file); - int ret = vidioc_g_fmt_vbi_out(file, priv, f); - - if (ret) - return ret; - if (vb2_is_busy(&dev->vb_vbi_out_q)) - return -EBUSY; - dev->stream_sliced_vbi_out = false; - dev->vbi_out_dev.queue->type = V4L2_BUF_TYPE_VBI_OUTPUT; - return 0; -} - -int vidioc_g_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt) -{ - struct vivid_dev *dev = video_drvdata(file); - struct v4l2_sliced_vbi_format *vbi = &fmt->fmt.sliced; - - if (!vivid_is_svid_out(dev) || !dev->has_sliced_vbi_out) - return -EINVAL; - - vivid_fill_service_lines(vbi, dev->service_set_out); - return 0; -} - -int vidioc_try_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt) -{ - struct vivid_dev *dev = video_drvdata(file); - struct v4l2_sliced_vbi_format *vbi = &fmt->fmt.sliced; - bool is_60hz = dev->std_out & V4L2_STD_525_60; - u32 service_set = vbi->service_set; - - if (!vivid_is_svid_out(dev) || !dev->has_sliced_vbi_out) - return -EINVAL; - - service_set &= is_60hz ? V4L2_SLICED_CAPTION_525 : - V4L2_SLICED_WSS_625 | V4L2_SLICED_TELETEXT_B; - vivid_fill_service_lines(vbi, service_set); - return 0; -} - -int vidioc_s_fmt_sliced_vbi_out(struct file *file, void *fh, - struct v4l2_format *fmt) -{ - struct vivid_dev *dev = video_drvdata(file); - struct v4l2_sliced_vbi_format *vbi = &fmt->fmt.sliced; - int ret = vidioc_try_fmt_sliced_vbi_out(file, fh, fmt); - - if (ret) - return ret; - if (vb2_is_busy(&dev->vb_vbi_out_q)) - return -EBUSY; - dev->service_set_out = vbi->service_set; - dev->stream_sliced_vbi_out = true; - dev->vbi_out_dev.queue->type = V4L2_BUF_TYPE_SLICED_VBI_OUTPUT; - return 0; -} - -void vivid_sliced_vbi_out_process(struct vivid_dev *dev, - struct vivid_buffer *buf) -{ - struct v4l2_sliced_vbi_data *vbi = - vb2_plane_vaddr(&buf->vb.vb2_buf, 0); - unsigned elems = - vb2_get_plane_payload(&buf->vb.vb2_buf, 0) / sizeof(*vbi); - - dev->vbi_out_have_cc[0] = false; - dev->vbi_out_have_cc[1] = false; - dev->vbi_out_have_wss = false; - while (elems--) { - switch (vbi->id) { - case V4L2_SLICED_CAPTION_525: - if ((dev->std_out & V4L2_STD_525_60) && vbi->line == 21) { - dev->vbi_out_have_cc[!!vbi->field] = true; - dev->vbi_out_cc[!!vbi->field][0] = vbi->data[0]; - dev->vbi_out_cc[!!vbi->field][1] = vbi->data[1]; - } - break; - case V4L2_SLICED_WSS_625: - if ((dev->std_out & V4L2_STD_625_50) && - vbi->field == 0 && vbi->line == 23) { - dev->vbi_out_have_wss = true; - dev->vbi_out_wss[0] = vbi->data[0]; - dev->vbi_out_wss[1] = vbi->data[1]; - } - break; - } - vbi++; - } -} diff --git a/drivers/media/platform/vivid/vivid-vbi-out.h b/drivers/media/platform/vivid/vivid-vbi-out.h deleted file mode 100644 index 76584940cdaf..000000000000 --- a/drivers/media/platform/vivid/vivid-vbi-out.h +++ /dev/null @@ -1,22 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * vivid-vbi-out.h - vbi output support functions. - * - * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - */ - -#ifndef _VIVID_VBI_OUT_H_ -#define _VIVID_VBI_OUT_H_ - -void vivid_sliced_vbi_out_process(struct vivid_dev *dev, struct vivid_buffer *buf); -int vidioc_g_fmt_vbi_out(struct file *file, void *priv, - struct v4l2_format *f); -int vidioc_s_fmt_vbi_out(struct file *file, void *priv, - struct v4l2_format *f); -int vidioc_g_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt); -int vidioc_try_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt); -int vidioc_s_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt); - -extern const struct vb2_ops vivid_vbi_out_qops; - -#endif diff --git a/drivers/media/platform/vivid/vivid-vid-cap.c b/drivers/media/platform/vivid/vivid-vid-cap.c deleted file mode 100644 index e94beef008c8..000000000000 --- a/drivers/media/platform/vivid/vivid-vid-cap.c +++ /dev/null @@ -1,1918 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * vivid-vid-cap.c - video capture support functions. - * - * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "vivid-core.h" -#include "vivid-vid-common.h" -#include "vivid-kthread-cap.h" -#include "vivid-vid-cap.h" - -static const struct vivid_fmt formats_ovl[] = { - { - .fourcc = V4L2_PIX_FMT_RGB565, /* gggbbbbb rrrrrggg */ - .vdownsampling = { 1 }, - .bit_depth = { 16 }, - .planes = 1, - .buffers = 1, - }, - { - .fourcc = V4L2_PIX_FMT_XRGB555, /* gggbbbbb arrrrrgg */ - .vdownsampling = { 1 }, - .bit_depth = { 16 }, - .planes = 1, - .buffers = 1, - }, - { - .fourcc = V4L2_PIX_FMT_ARGB555, /* gggbbbbb arrrrrgg */ - .vdownsampling = { 1 }, - .bit_depth = { 16 }, - .planes = 1, - .buffers = 1, - }, -}; - -/* The number of discrete webcam framesizes */ -#define VIVID_WEBCAM_SIZES 6 -/* The number of discrete webcam frameintervals */ -#define VIVID_WEBCAM_IVALS (VIVID_WEBCAM_SIZES * 2) - -/* Sizes must be in increasing order */ -static const struct v4l2_frmsize_discrete webcam_sizes[VIVID_WEBCAM_SIZES] = { - { 320, 180 }, - { 640, 360 }, - { 640, 480 }, - { 1280, 720 }, - { 1920, 1080 }, - { 3840, 2160 }, -}; - -/* - * Intervals must be in increasing order and there must be twice as many - * elements in this array as there are in webcam_sizes. - */ -static const struct v4l2_fract webcam_intervals[VIVID_WEBCAM_IVALS] = { - { 1, 1 }, - { 1, 2 }, - { 1, 4 }, - { 1, 5 }, - { 1, 10 }, - { 2, 25 }, - { 1, 15 }, - { 1, 25 }, - { 1, 30 }, - { 1, 40 }, - { 1, 50 }, - { 1, 60 }, -}; - -static int vid_cap_queue_setup(struct vb2_queue *vq, - unsigned *nbuffers, unsigned *nplanes, - unsigned sizes[], struct device *alloc_devs[]) -{ - struct vivid_dev *dev = vb2_get_drv_priv(vq); - unsigned buffers = tpg_g_buffers(&dev->tpg); - unsigned h = dev->fmt_cap_rect.height; - unsigned p; - - if (dev->field_cap == V4L2_FIELD_ALTERNATE) { - /* - * You cannot use read() with FIELD_ALTERNATE since the field - * information (TOP/BOTTOM) cannot be passed back to the user. - */ - if (vb2_fileio_is_active(vq)) - return -EINVAL; - } - - if (dev->queue_setup_error) { - /* - * Error injection: test what happens if queue_setup() returns - * an error. - */ - dev->queue_setup_error = false; - return -EINVAL; - } - if (*nplanes) { - /* - * Check if the number of requested planes match - * the number of buffers in the current format. You can't mix that. - */ - if (*nplanes != buffers) - return -EINVAL; - for (p = 0; p < buffers; p++) { - if (sizes[p] < tpg_g_line_width(&dev->tpg, p) * h + - dev->fmt_cap->data_offset[p]) - return -EINVAL; - } - } else { - for (p = 0; p < buffers; p++) - sizes[p] = (tpg_g_line_width(&dev->tpg, p) * h) / - dev->fmt_cap->vdownsampling[p] + - dev->fmt_cap->data_offset[p]; - } - - if (vq->num_buffers + *nbuffers < 2) - *nbuffers = 2 - vq->num_buffers; - - *nplanes = buffers; - - dprintk(dev, 1, "%s: count=%d\n", __func__, *nbuffers); - for (p = 0; p < buffers; p++) - dprintk(dev, 1, "%s: size[%u]=%u\n", __func__, p, sizes[p]); - - return 0; -} - -static int vid_cap_buf_prepare(struct vb2_buffer *vb) -{ - struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); - unsigned long size; - unsigned buffers = tpg_g_buffers(&dev->tpg); - unsigned p; - - dprintk(dev, 1, "%s\n", __func__); - - if (WARN_ON(NULL == dev->fmt_cap)) - return -EINVAL; - - if (dev->buf_prepare_error) { - /* - * Error injection: test what happens if buf_prepare() returns - * an error. - */ - dev->buf_prepare_error = false; - return -EINVAL; - } - for (p = 0; p < buffers; p++) { - size = (tpg_g_line_width(&dev->tpg, p) * - dev->fmt_cap_rect.height) / - dev->fmt_cap->vdownsampling[p] + - dev->fmt_cap->data_offset[p]; - - if (vb2_plane_size(vb, p) < size) { - dprintk(dev, 1, "%s data will not fit into plane %u (%lu < %lu)\n", - __func__, p, vb2_plane_size(vb, p), size); - return -EINVAL; - } - - vb2_set_plane_payload(vb, p, size); - vb->planes[p].data_offset = dev->fmt_cap->data_offset[p]; - } - - return 0; -} - -static void vid_cap_buf_finish(struct vb2_buffer *vb) -{ - struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); - struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); - struct v4l2_timecode *tc = &vbuf->timecode; - unsigned fps = 25; - unsigned seq = vbuf->sequence; - - if (!vivid_is_sdtv_cap(dev)) - return; - - /* - * Set the timecode. Rarely used, so it is interesting to - * test this. - */ - vbuf->flags |= V4L2_BUF_FLAG_TIMECODE; - if (dev->std_cap[dev->input] & V4L2_STD_525_60) - fps = 30; - tc->type = (fps == 30) ? V4L2_TC_TYPE_30FPS : V4L2_TC_TYPE_25FPS; - tc->flags = 0; - tc->frames = seq % fps; - tc->seconds = (seq / fps) % 60; - tc->minutes = (seq / (60 * fps)) % 60; - tc->hours = (seq / (60 * 60 * fps)) % 24; -} - -static void vid_cap_buf_queue(struct vb2_buffer *vb) -{ - struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); - struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); - struct vivid_buffer *buf = container_of(vbuf, struct vivid_buffer, vb); - - dprintk(dev, 1, "%s\n", __func__); - - spin_lock(&dev->slock); - list_add_tail(&buf->list, &dev->vid_cap_active); - spin_unlock(&dev->slock); -} - -static int vid_cap_start_streaming(struct vb2_queue *vq, unsigned count) -{ - struct vivid_dev *dev = vb2_get_drv_priv(vq); - unsigned i; - int err; - - if (vb2_is_streaming(&dev->vb_vid_out_q)) - dev->can_loop_video = vivid_vid_can_loop(dev); - - dev->vid_cap_seq_count = 0; - dprintk(dev, 1, "%s\n", __func__); - for (i = 0; i < VIDEO_MAX_FRAME; i++) - dev->must_blank[i] = tpg_g_perc_fill(&dev->tpg) < 100; - if (dev->start_streaming_error) { - dev->start_streaming_error = false; - err = -EINVAL; - } else { - err = vivid_start_generating_vid_cap(dev, &dev->vid_cap_streaming); - } - if (err) { - struct vivid_buffer *buf, *tmp; - - list_for_each_entry_safe(buf, tmp, &dev->vid_cap_active, list) { - list_del(&buf->list); - vb2_buffer_done(&buf->vb.vb2_buf, - VB2_BUF_STATE_QUEUED); - } - } - return err; -} - -/* abort streaming and wait for last buffer */ -static void vid_cap_stop_streaming(struct vb2_queue *vq) -{ - struct vivid_dev *dev = vb2_get_drv_priv(vq); - - dprintk(dev, 1, "%s\n", __func__); - vivid_stop_generating_vid_cap(dev, &dev->vid_cap_streaming); - dev->can_loop_video = false; -} - -static void vid_cap_buf_request_complete(struct vb2_buffer *vb) -{ - struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); - - v4l2_ctrl_request_complete(vb->req_obj.req, &dev->ctrl_hdl_vid_cap); -} - -const struct vb2_ops vivid_vid_cap_qops = { - .queue_setup = vid_cap_queue_setup, - .buf_prepare = vid_cap_buf_prepare, - .buf_finish = vid_cap_buf_finish, - .buf_queue = vid_cap_buf_queue, - .start_streaming = vid_cap_start_streaming, - .stop_streaming = vid_cap_stop_streaming, - .buf_request_complete = vid_cap_buf_request_complete, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, -}; - -/* - * Determine the 'picture' quality based on the current TV frequency: either - * COLOR for a good 'signal', GRAY (grayscale picture) for a slightly off - * signal or NOISE for no signal. - */ -void vivid_update_quality(struct vivid_dev *dev) -{ - unsigned freq_modulus; - - if (dev->loop_video && (vivid_is_svid_cap(dev) || vivid_is_hdmi_cap(dev))) { - /* - * The 'noise' will only be replaced by the actual video - * if the output video matches the input video settings. - */ - tpg_s_quality(&dev->tpg, TPG_QUAL_NOISE, 0); - return; - } - if (vivid_is_hdmi_cap(dev) && - VIVID_INVALID_SIGNAL(dev->dv_timings_signal_mode[dev->input])) { - tpg_s_quality(&dev->tpg, TPG_QUAL_NOISE, 0); - return; - } - if (vivid_is_sdtv_cap(dev) && - VIVID_INVALID_SIGNAL(dev->std_signal_mode[dev->input])) { - tpg_s_quality(&dev->tpg, TPG_QUAL_NOISE, 0); - return; - } - if (!vivid_is_tv_cap(dev)) { - tpg_s_quality(&dev->tpg, TPG_QUAL_COLOR, 0); - return; - } - - /* - * There is a fake channel every 6 MHz at 49.25, 55.25, etc. - * From +/- 0.25 MHz around the channel there is color, and from - * +/- 1 MHz there is grayscale (chroma is lost). - * Everywhere else it is just noise. - */ - freq_modulus = (dev->tv_freq - 676 /* (43.25-1) * 16 */) % (6 * 16); - if (freq_modulus > 2 * 16) { - tpg_s_quality(&dev->tpg, TPG_QUAL_NOISE, - next_pseudo_random32(dev->tv_freq ^ 0x55) & 0x3f); - return; - } - if (freq_modulus < 12 /*0.75 * 16*/ || freq_modulus > 20 /*1.25 * 16*/) - tpg_s_quality(&dev->tpg, TPG_QUAL_GRAY, 0); - else - tpg_s_quality(&dev->tpg, TPG_QUAL_COLOR, 0); -} - -/* - * Get the current picture quality and the associated afc value. - */ -static enum tpg_quality vivid_get_quality(struct vivid_dev *dev, s32 *afc) -{ - unsigned freq_modulus; - - if (afc) - *afc = 0; - if (tpg_g_quality(&dev->tpg) == TPG_QUAL_COLOR || - tpg_g_quality(&dev->tpg) == TPG_QUAL_NOISE) - return tpg_g_quality(&dev->tpg); - - /* - * There is a fake channel every 6 MHz at 49.25, 55.25, etc. - * From +/- 0.25 MHz around the channel there is color, and from - * +/- 1 MHz there is grayscale (chroma is lost). - * Everywhere else it is just gray. - */ - freq_modulus = (dev->tv_freq - 676 /* (43.25-1) * 16 */) % (6 * 16); - if (afc) - *afc = freq_modulus - 1 * 16; - return TPG_QUAL_GRAY; -} - -enum tpg_video_aspect vivid_get_video_aspect(const struct vivid_dev *dev) -{ - if (vivid_is_sdtv_cap(dev)) - return dev->std_aspect_ratio[dev->input]; - - if (vivid_is_hdmi_cap(dev)) - return dev->dv_timings_aspect_ratio[dev->input]; - - return TPG_VIDEO_ASPECT_IMAGE; -} - -static enum tpg_pixel_aspect vivid_get_pixel_aspect(const struct vivid_dev *dev) -{ - if (vivid_is_sdtv_cap(dev)) - return (dev->std_cap[dev->input] & V4L2_STD_525_60) ? - TPG_PIXEL_ASPECT_NTSC : TPG_PIXEL_ASPECT_PAL; - - if (vivid_is_hdmi_cap(dev) && - dev->src_rect.width == 720 && dev->src_rect.height <= 576) - return dev->src_rect.height == 480 ? - TPG_PIXEL_ASPECT_NTSC : TPG_PIXEL_ASPECT_PAL; - - return TPG_PIXEL_ASPECT_SQUARE; -} - -/* - * Called whenever the format has to be reset which can occur when - * changing inputs, standard, timings, etc. - */ -void vivid_update_format_cap(struct vivid_dev *dev, bool keep_controls) -{ - struct v4l2_bt_timings *bt = &dev->dv_timings_cap[dev->input].bt; - unsigned size; - u64 pixelclock; - - switch (dev->input_type[dev->input]) { - case WEBCAM: - default: - dev->src_rect.width = webcam_sizes[dev->webcam_size_idx].width; - dev->src_rect.height = webcam_sizes[dev->webcam_size_idx].height; - dev->timeperframe_vid_cap = webcam_intervals[dev->webcam_ival_idx]; - dev->field_cap = V4L2_FIELD_NONE; - tpg_s_rgb_range(&dev->tpg, V4L2_DV_RGB_RANGE_AUTO); - break; - case TV: - case SVID: - dev->field_cap = dev->tv_field_cap; - dev->src_rect.width = 720; - if (dev->std_cap[dev->input] & V4L2_STD_525_60) { - dev->src_rect.height = 480; - dev->timeperframe_vid_cap = (struct v4l2_fract) { 1001, 30000 }; - dev->service_set_cap = V4L2_SLICED_CAPTION_525; - } else { - dev->src_rect.height = 576; - dev->timeperframe_vid_cap = (struct v4l2_fract) { 1000, 25000 }; - dev->service_set_cap = V4L2_SLICED_WSS_625 | V4L2_SLICED_TELETEXT_B; - } - tpg_s_rgb_range(&dev->tpg, V4L2_DV_RGB_RANGE_AUTO); - break; - case HDMI: - dev->src_rect.width = bt->width; - dev->src_rect.height = bt->height; - size = V4L2_DV_BT_FRAME_WIDTH(bt) * V4L2_DV_BT_FRAME_HEIGHT(bt); - if (dev->reduced_fps && can_reduce_fps(bt)) { - pixelclock = div_u64(bt->pixelclock * 1000, 1001); - bt->flags |= V4L2_DV_FL_REDUCED_FPS; - } else { - pixelclock = bt->pixelclock; - bt->flags &= ~V4L2_DV_FL_REDUCED_FPS; - } - dev->timeperframe_vid_cap = (struct v4l2_fract) { - size / 100, (u32)pixelclock / 100 - }; - if (bt->interlaced) - dev->field_cap = V4L2_FIELD_ALTERNATE; - else - dev->field_cap = V4L2_FIELD_NONE; - - /* - * We can be called from within s_ctrl, in that case we can't - * set/get controls. Luckily we don't need to in that case. - */ - if (keep_controls || !dev->colorspace) - break; - if (bt->flags & V4L2_DV_FL_IS_CE_VIDEO) { - if (bt->width == 720 && bt->height <= 576) - v4l2_ctrl_s_ctrl(dev->colorspace, VIVID_CS_170M); - else - v4l2_ctrl_s_ctrl(dev->colorspace, VIVID_CS_709); - v4l2_ctrl_s_ctrl(dev->real_rgb_range_cap, 1); - } else { - v4l2_ctrl_s_ctrl(dev->colorspace, VIVID_CS_SRGB); - v4l2_ctrl_s_ctrl(dev->real_rgb_range_cap, 0); - } - tpg_s_rgb_range(&dev->tpg, v4l2_ctrl_g_ctrl(dev->rgb_range_cap)); - break; - } - vfree(dev->bitmap_cap); - dev->bitmap_cap = NULL; - vivid_update_quality(dev); - tpg_reset_source(&dev->tpg, dev->src_rect.width, dev->src_rect.height, dev->field_cap); - dev->crop_cap = dev->src_rect; - dev->crop_bounds_cap = dev->src_rect; - dev->compose_cap = dev->crop_cap; - if (V4L2_FIELD_HAS_T_OR_B(dev->field_cap)) - dev->compose_cap.height /= 2; - dev->fmt_cap_rect = dev->compose_cap; - tpg_s_video_aspect(&dev->tpg, vivid_get_video_aspect(dev)); - tpg_s_pixel_aspect(&dev->tpg, vivid_get_pixel_aspect(dev)); - tpg_update_mv_step(&dev->tpg); -} - -/* Map the field to something that is valid for the current input */ -static enum v4l2_field vivid_field_cap(struct vivid_dev *dev, enum v4l2_field field) -{ - if (vivid_is_sdtv_cap(dev)) { - switch (field) { - case V4L2_FIELD_INTERLACED_TB: - case V4L2_FIELD_INTERLACED_BT: - case V4L2_FIELD_SEQ_TB: - case V4L2_FIELD_SEQ_BT: - case V4L2_FIELD_TOP: - case V4L2_FIELD_BOTTOM: - case V4L2_FIELD_ALTERNATE: - return field; - case V4L2_FIELD_INTERLACED: - default: - return V4L2_FIELD_INTERLACED; - } - } - if (vivid_is_hdmi_cap(dev)) - return dev->dv_timings_cap[dev->input].bt.interlaced ? - V4L2_FIELD_ALTERNATE : V4L2_FIELD_NONE; - return V4L2_FIELD_NONE; -} - -static unsigned vivid_colorspace_cap(struct vivid_dev *dev) -{ - if (!dev->loop_video || vivid_is_webcam(dev) || vivid_is_tv_cap(dev)) - return tpg_g_colorspace(&dev->tpg); - return dev->colorspace_out; -} - -static unsigned vivid_xfer_func_cap(struct vivid_dev *dev) -{ - if (!dev->loop_video || vivid_is_webcam(dev) || vivid_is_tv_cap(dev)) - return tpg_g_xfer_func(&dev->tpg); - return dev->xfer_func_out; -} - -static unsigned vivid_ycbcr_enc_cap(struct vivid_dev *dev) -{ - if (!dev->loop_video || vivid_is_webcam(dev) || vivid_is_tv_cap(dev)) - return tpg_g_ycbcr_enc(&dev->tpg); - return dev->ycbcr_enc_out; -} - -static unsigned int vivid_hsv_enc_cap(struct vivid_dev *dev) -{ - if (!dev->loop_video || vivid_is_webcam(dev) || vivid_is_tv_cap(dev)) - return tpg_g_hsv_enc(&dev->tpg); - return dev->hsv_enc_out; -} - -static unsigned vivid_quantization_cap(struct vivid_dev *dev) -{ - if (!dev->loop_video || vivid_is_webcam(dev) || vivid_is_tv_cap(dev)) - return tpg_g_quantization(&dev->tpg); - return dev->quantization_out; -} - -int vivid_g_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct vivid_dev *dev = video_drvdata(file); - struct v4l2_pix_format_mplane *mp = &f->fmt.pix_mp; - unsigned p; - - mp->width = dev->fmt_cap_rect.width; - mp->height = dev->fmt_cap_rect.height; - mp->field = dev->field_cap; - mp->pixelformat = dev->fmt_cap->fourcc; - mp->colorspace = vivid_colorspace_cap(dev); - mp->xfer_func = vivid_xfer_func_cap(dev); - if (dev->fmt_cap->color_enc == TGP_COLOR_ENC_HSV) - mp->hsv_enc = vivid_hsv_enc_cap(dev); - else - mp->ycbcr_enc = vivid_ycbcr_enc_cap(dev); - mp->quantization = vivid_quantization_cap(dev); - mp->num_planes = dev->fmt_cap->buffers; - for (p = 0; p < mp->num_planes; p++) { - mp->plane_fmt[p].bytesperline = tpg_g_bytesperline(&dev->tpg, p); - mp->plane_fmt[p].sizeimage = - (tpg_g_line_width(&dev->tpg, p) * mp->height) / - dev->fmt_cap->vdownsampling[p] + - dev->fmt_cap->data_offset[p]; - } - return 0; -} - -int vivid_try_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct v4l2_pix_format_mplane *mp = &f->fmt.pix_mp; - struct v4l2_plane_pix_format *pfmt = mp->plane_fmt; - struct vivid_dev *dev = video_drvdata(file); - const struct vivid_fmt *fmt; - unsigned bytesperline, max_bpl; - unsigned factor = 1; - unsigned w, h; - unsigned p; - - fmt = vivid_get_format(dev, mp->pixelformat); - if (!fmt) { - dprintk(dev, 1, "Fourcc format (0x%08x) unknown.\n", - mp->pixelformat); - mp->pixelformat = V4L2_PIX_FMT_YUYV; - fmt = vivid_get_format(dev, mp->pixelformat); - } - - mp->field = vivid_field_cap(dev, mp->field); - if (vivid_is_webcam(dev)) { - const struct v4l2_frmsize_discrete *sz = - v4l2_find_nearest_size(webcam_sizes, - VIVID_WEBCAM_SIZES, width, - height, mp->width, mp->height); - - w = sz->width; - h = sz->height; - } else if (vivid_is_sdtv_cap(dev)) { - w = 720; - h = (dev->std_cap[dev->input] & V4L2_STD_525_60) ? 480 : 576; - } else { - w = dev->src_rect.width; - h = dev->src_rect.height; - } - if (V4L2_FIELD_HAS_T_OR_B(mp->field)) - factor = 2; - if (vivid_is_webcam(dev) || - (!dev->has_scaler_cap && !dev->has_crop_cap && !dev->has_compose_cap)) { - mp->width = w; - mp->height = h / factor; - } else { - struct v4l2_rect r = { 0, 0, mp->width, mp->height * factor }; - - v4l2_rect_set_min_size(&r, &vivid_min_rect); - v4l2_rect_set_max_size(&r, &vivid_max_rect); - if (dev->has_scaler_cap && !dev->has_compose_cap) { - struct v4l2_rect max_r = { 0, 0, MAX_ZOOM * w, MAX_ZOOM * h }; - - v4l2_rect_set_max_size(&r, &max_r); - } else if (!dev->has_scaler_cap && dev->has_crop_cap && !dev->has_compose_cap) { - v4l2_rect_set_max_size(&r, &dev->src_rect); - } else if (!dev->has_scaler_cap && !dev->has_crop_cap) { - v4l2_rect_set_min_size(&r, &dev->src_rect); - } - mp->width = r.width; - mp->height = r.height / factor; - } - - /* This driver supports custom bytesperline values */ - - mp->num_planes = fmt->buffers; - for (p = 0; p < fmt->buffers; p++) { - /* Calculate the minimum supported bytesperline value */ - bytesperline = (mp->width * fmt->bit_depth[p]) >> 3; - /* Calculate the maximum supported bytesperline value */ - max_bpl = (MAX_ZOOM * MAX_WIDTH * fmt->bit_depth[p]) >> 3; - - if (pfmt[p].bytesperline > max_bpl) - pfmt[p].bytesperline = max_bpl; - if (pfmt[p].bytesperline < bytesperline) - pfmt[p].bytesperline = bytesperline; - - pfmt[p].sizeimage = (pfmt[p].bytesperline * mp->height) / - fmt->vdownsampling[p] + fmt->data_offset[p]; - - memset(pfmt[p].reserved, 0, sizeof(pfmt[p].reserved)); - } - for (p = fmt->buffers; p < fmt->planes; p++) - pfmt[0].sizeimage += (pfmt[0].bytesperline * mp->height * - (fmt->bit_depth[p] / fmt->vdownsampling[p])) / - (fmt->bit_depth[0] / fmt->vdownsampling[0]); - - mp->colorspace = vivid_colorspace_cap(dev); - if (fmt->color_enc == TGP_COLOR_ENC_HSV) - mp->hsv_enc = vivid_hsv_enc_cap(dev); - else - mp->ycbcr_enc = vivid_ycbcr_enc_cap(dev); - mp->xfer_func = vivid_xfer_func_cap(dev); - mp->quantization = vivid_quantization_cap(dev); - memset(mp->reserved, 0, sizeof(mp->reserved)); - return 0; -} - -int vivid_s_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct v4l2_pix_format_mplane *mp = &f->fmt.pix_mp; - struct vivid_dev *dev = video_drvdata(file); - struct v4l2_rect *crop = &dev->crop_cap; - struct v4l2_rect *compose = &dev->compose_cap; - struct vb2_queue *q = &dev->vb_vid_cap_q; - int ret = vivid_try_fmt_vid_cap(file, priv, f); - unsigned factor = 1; - unsigned p; - unsigned i; - - if (ret < 0) - return ret; - - if (vb2_is_busy(q)) { - dprintk(dev, 1, "%s device busy\n", __func__); - return -EBUSY; - } - - if (dev->overlay_cap_owner && dev->fb_cap.fmt.pixelformat != mp->pixelformat) { - dprintk(dev, 1, "overlay is active, can't change pixelformat\n"); - return -EBUSY; - } - - dev->fmt_cap = vivid_get_format(dev, mp->pixelformat); - if (V4L2_FIELD_HAS_T_OR_B(mp->field)) - factor = 2; - - /* Note: the webcam input doesn't support scaling, cropping or composing */ - - if (!vivid_is_webcam(dev) && - (dev->has_scaler_cap || dev->has_crop_cap || dev->has_compose_cap)) { - struct v4l2_rect r = { 0, 0, mp->width, mp->height }; - - if (dev->has_scaler_cap) { - if (dev->has_compose_cap) - v4l2_rect_map_inside(compose, &r); - else - *compose = r; - if (dev->has_crop_cap && !dev->has_compose_cap) { - struct v4l2_rect min_r = { - 0, 0, - r.width / MAX_ZOOM, - factor * r.height / MAX_ZOOM - }; - struct v4l2_rect max_r = { - 0, 0, - r.width * MAX_ZOOM, - factor * r.height * MAX_ZOOM - }; - - v4l2_rect_set_min_size(crop, &min_r); - v4l2_rect_set_max_size(crop, &max_r); - v4l2_rect_map_inside(crop, &dev->crop_bounds_cap); - } else if (dev->has_crop_cap) { - struct v4l2_rect min_r = { - 0, 0, - compose->width / MAX_ZOOM, - factor * compose->height / MAX_ZOOM - }; - struct v4l2_rect max_r = { - 0, 0, - compose->width * MAX_ZOOM, - factor * compose->height * MAX_ZOOM - }; - - v4l2_rect_set_min_size(crop, &min_r); - v4l2_rect_set_max_size(crop, &max_r); - v4l2_rect_map_inside(crop, &dev->crop_bounds_cap); - } - } else if (dev->has_crop_cap && !dev->has_compose_cap) { - r.height *= factor; - v4l2_rect_set_size_to(crop, &r); - v4l2_rect_map_inside(crop, &dev->crop_bounds_cap); - r = *crop; - r.height /= factor; - v4l2_rect_set_size_to(compose, &r); - } else if (!dev->has_crop_cap) { - v4l2_rect_map_inside(compose, &r); - } else { - r.height *= factor; - v4l2_rect_set_max_size(crop, &r); - v4l2_rect_map_inside(crop, &dev->crop_bounds_cap); - compose->top *= factor; - compose->height *= factor; - v4l2_rect_set_size_to(compose, crop); - v4l2_rect_map_inside(compose, &r); - compose->top /= factor; - compose->height /= factor; - } - } else if (vivid_is_webcam(dev)) { - /* Guaranteed to be a match */ - for (i = 0; i < ARRAY_SIZE(webcam_sizes); i++) - if (webcam_sizes[i].width == mp->width && - webcam_sizes[i].height == mp->height) - break; - dev->webcam_size_idx = i; - if (dev->webcam_ival_idx >= 2 * (VIVID_WEBCAM_SIZES - i)) - dev->webcam_ival_idx = 2 * (VIVID_WEBCAM_SIZES - i) - 1; - vivid_update_format_cap(dev, false); - } else { - struct v4l2_rect r = { 0, 0, mp->width, mp->height }; - - v4l2_rect_set_size_to(compose, &r); - r.height *= factor; - v4l2_rect_set_size_to(crop, &r); - } - - dev->fmt_cap_rect.width = mp->width; - dev->fmt_cap_rect.height = mp->height; - tpg_s_buf_height(&dev->tpg, mp->height); - tpg_s_fourcc(&dev->tpg, dev->fmt_cap->fourcc); - for (p = 0; p < tpg_g_buffers(&dev->tpg); p++) - tpg_s_bytesperline(&dev->tpg, p, mp->plane_fmt[p].bytesperline); - dev->field_cap = mp->field; - if (dev->field_cap == V4L2_FIELD_ALTERNATE) - tpg_s_field(&dev->tpg, V4L2_FIELD_TOP, true); - else - tpg_s_field(&dev->tpg, dev->field_cap, false); - tpg_s_crop_compose(&dev->tpg, &dev->crop_cap, &dev->compose_cap); - if (vivid_is_sdtv_cap(dev)) - dev->tv_field_cap = mp->field; - tpg_update_mv_step(&dev->tpg); - return 0; -} - -int vidioc_g_fmt_vid_cap_mplane(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct vivid_dev *dev = video_drvdata(file); - - if (!dev->multiplanar) - return -ENOTTY; - return vivid_g_fmt_vid_cap(file, priv, f); -} - -int vidioc_try_fmt_vid_cap_mplane(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct vivid_dev *dev = video_drvdata(file); - - if (!dev->multiplanar) - return -ENOTTY; - return vivid_try_fmt_vid_cap(file, priv, f); -} - -int vidioc_s_fmt_vid_cap_mplane(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct vivid_dev *dev = video_drvdata(file); - - if (!dev->multiplanar) - return -ENOTTY; - return vivid_s_fmt_vid_cap(file, priv, f); -} - -int vidioc_g_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct vivid_dev *dev = video_drvdata(file); - - if (dev->multiplanar) - return -ENOTTY; - return fmt_sp2mp_func(file, priv, f, vivid_g_fmt_vid_cap); -} - -int vidioc_try_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct vivid_dev *dev = video_drvdata(file); - - if (dev->multiplanar) - return -ENOTTY; - return fmt_sp2mp_func(file, priv, f, vivid_try_fmt_vid_cap); -} - -int vidioc_s_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct vivid_dev *dev = video_drvdata(file); - - if (dev->multiplanar) - return -ENOTTY; - return fmt_sp2mp_func(file, priv, f, vivid_s_fmt_vid_cap); -} - -int vivid_vid_cap_g_selection(struct file *file, void *priv, - struct v4l2_selection *sel) -{ - struct vivid_dev *dev = video_drvdata(file); - - if (!dev->has_crop_cap && !dev->has_compose_cap) - return -ENOTTY; - if (sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - if (vivid_is_webcam(dev)) - return -ENODATA; - - sel->r.left = sel->r.top = 0; - switch (sel->target) { - case V4L2_SEL_TGT_CROP: - if (!dev->has_crop_cap) - return -EINVAL; - sel->r = dev->crop_cap; - break; - case V4L2_SEL_TGT_CROP_DEFAULT: - case V4L2_SEL_TGT_CROP_BOUNDS: - if (!dev->has_crop_cap) - return -EINVAL; - sel->r = dev->src_rect; - break; - case V4L2_SEL_TGT_COMPOSE_BOUNDS: - if (!dev->has_compose_cap) - return -EINVAL; - sel->r = vivid_max_rect; - break; - case V4L2_SEL_TGT_COMPOSE: - if (!dev->has_compose_cap) - return -EINVAL; - sel->r = dev->compose_cap; - break; - case V4L2_SEL_TGT_COMPOSE_DEFAULT: - if (!dev->has_compose_cap) - return -EINVAL; - sel->r = dev->fmt_cap_rect; - break; - default: - return -EINVAL; - } - return 0; -} - -int vivid_vid_cap_s_selection(struct file *file, void *fh, struct v4l2_selection *s) -{ - struct vivid_dev *dev = video_drvdata(file); - struct v4l2_rect *crop = &dev->crop_cap; - struct v4l2_rect *compose = &dev->compose_cap; - unsigned factor = V4L2_FIELD_HAS_T_OR_B(dev->field_cap) ? 2 : 1; - int ret; - - if (!dev->has_crop_cap && !dev->has_compose_cap) - return -ENOTTY; - if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - if (vivid_is_webcam(dev)) - return -ENODATA; - - switch (s->target) { - case V4L2_SEL_TGT_CROP: - if (!dev->has_crop_cap) - return -EINVAL; - ret = vivid_vid_adjust_sel(s->flags, &s->r); - if (ret) - return ret; - v4l2_rect_set_min_size(&s->r, &vivid_min_rect); - v4l2_rect_set_max_size(&s->r, &dev->src_rect); - v4l2_rect_map_inside(&s->r, &dev->crop_bounds_cap); - s->r.top /= factor; - s->r.height /= factor; - if (dev->has_scaler_cap) { - struct v4l2_rect fmt = dev->fmt_cap_rect; - struct v4l2_rect max_rect = { - 0, 0, - s->r.width * MAX_ZOOM, - s->r.height * MAX_ZOOM - }; - struct v4l2_rect min_rect = { - 0, 0, - s->r.width / MAX_ZOOM, - s->r.height / MAX_ZOOM - }; - - v4l2_rect_set_min_size(&fmt, &min_rect); - if (!dev->has_compose_cap) - v4l2_rect_set_max_size(&fmt, &max_rect); - if (!v4l2_rect_same_size(&dev->fmt_cap_rect, &fmt) && - vb2_is_busy(&dev->vb_vid_cap_q)) - return -EBUSY; - if (dev->has_compose_cap) { - v4l2_rect_set_min_size(compose, &min_rect); - v4l2_rect_set_max_size(compose, &max_rect); - } - dev->fmt_cap_rect = fmt; - tpg_s_buf_height(&dev->tpg, fmt.height); - } else if (dev->has_compose_cap) { - struct v4l2_rect fmt = dev->fmt_cap_rect; - - v4l2_rect_set_min_size(&fmt, &s->r); - if (!v4l2_rect_same_size(&dev->fmt_cap_rect, &fmt) && - vb2_is_busy(&dev->vb_vid_cap_q)) - return -EBUSY; - dev->fmt_cap_rect = fmt; - tpg_s_buf_height(&dev->tpg, fmt.height); - v4l2_rect_set_size_to(compose, &s->r); - v4l2_rect_map_inside(compose, &dev->fmt_cap_rect); - } else { - if (!v4l2_rect_same_size(&s->r, &dev->fmt_cap_rect) && - vb2_is_busy(&dev->vb_vid_cap_q)) - return -EBUSY; - v4l2_rect_set_size_to(&dev->fmt_cap_rect, &s->r); - v4l2_rect_set_size_to(compose, &s->r); - v4l2_rect_map_inside(compose, &dev->fmt_cap_rect); - tpg_s_buf_height(&dev->tpg, dev->fmt_cap_rect.height); - } - s->r.top *= factor; - s->r.height *= factor; - *crop = s->r; - break; - case V4L2_SEL_TGT_COMPOSE: - if (!dev->has_compose_cap) - return -EINVAL; - ret = vivid_vid_adjust_sel(s->flags, &s->r); - if (ret) - return ret; - v4l2_rect_set_min_size(&s->r, &vivid_min_rect); - v4l2_rect_set_max_size(&s->r, &dev->fmt_cap_rect); - if (dev->has_scaler_cap) { - struct v4l2_rect max_rect = { - 0, 0, - dev->src_rect.width * MAX_ZOOM, - (dev->src_rect.height / factor) * MAX_ZOOM - }; - - v4l2_rect_set_max_size(&s->r, &max_rect); - if (dev->has_crop_cap) { - struct v4l2_rect min_rect = { - 0, 0, - s->r.width / MAX_ZOOM, - (s->r.height * factor) / MAX_ZOOM - }; - struct v4l2_rect max_rect = { - 0, 0, - s->r.width * MAX_ZOOM, - (s->r.height * factor) * MAX_ZOOM - }; - - v4l2_rect_set_min_size(crop, &min_rect); - v4l2_rect_set_max_size(crop, &max_rect); - v4l2_rect_map_inside(crop, &dev->crop_bounds_cap); - } - } else if (dev->has_crop_cap) { - s->r.top *= factor; - s->r.height *= factor; - v4l2_rect_set_max_size(&s->r, &dev->src_rect); - v4l2_rect_set_size_to(crop, &s->r); - v4l2_rect_map_inside(crop, &dev->crop_bounds_cap); - s->r.top /= factor; - s->r.height /= factor; - } else { - v4l2_rect_set_size_to(&s->r, &dev->src_rect); - s->r.height /= factor; - } - v4l2_rect_map_inside(&s->r, &dev->fmt_cap_rect); - if (dev->bitmap_cap && (compose->width != s->r.width || - compose->height != s->r.height)) { - vfree(dev->bitmap_cap); - dev->bitmap_cap = NULL; - } - *compose = s->r; - break; - default: - return -EINVAL; - } - - tpg_s_crop_compose(&dev->tpg, crop, compose); - return 0; -} - -int vivid_vid_cap_g_pixelaspect(struct file *file, void *priv, - int type, struct v4l2_fract *f) -{ - struct vivid_dev *dev = video_drvdata(file); - - if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - switch (vivid_get_pixel_aspect(dev)) { - case TPG_PIXEL_ASPECT_NTSC: - f->numerator = 11; - f->denominator = 10; - break; - case TPG_PIXEL_ASPECT_PAL: - f->numerator = 54; - f->denominator = 59; - break; - default: - break; - } - return 0; -} - -int vidioc_enum_fmt_vid_overlay(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - struct vivid_dev *dev = video_drvdata(file); - const struct vivid_fmt *fmt; - - if (dev->multiplanar) - return -ENOTTY; - - if (f->index >= ARRAY_SIZE(formats_ovl)) - return -EINVAL; - - fmt = &formats_ovl[f->index]; - - f->pixelformat = fmt->fourcc; - return 0; -} - -int vidioc_g_fmt_vid_overlay(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct vivid_dev *dev = video_drvdata(file); - const struct v4l2_rect *compose = &dev->compose_cap; - struct v4l2_window *win = &f->fmt.win; - unsigned clipcount = win->clipcount; - - if (dev->multiplanar) - return -ENOTTY; - - win->w.top = dev->overlay_cap_top; - win->w.left = dev->overlay_cap_left; - win->w.width = compose->width; - win->w.height = compose->height; - win->field = dev->overlay_cap_field; - win->clipcount = dev->clipcount_cap; - if (clipcount > dev->clipcount_cap) - clipcount = dev->clipcount_cap; - if (dev->bitmap_cap == NULL) - win->bitmap = NULL; - else if (win->bitmap) { - if (copy_to_user(win->bitmap, dev->bitmap_cap, - ((compose->width + 7) / 8) * compose->height)) - return -EFAULT; - } - if (clipcount && win->clips) { - if (copy_to_user(win->clips, dev->clips_cap, - clipcount * sizeof(dev->clips_cap[0]))) - return -EFAULT; - } - return 0; -} - -int vidioc_try_fmt_vid_overlay(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct vivid_dev *dev = video_drvdata(file); - const struct v4l2_rect *compose = &dev->compose_cap; - struct v4l2_window *win = &f->fmt.win; - int i, j; - - if (dev->multiplanar) - return -ENOTTY; - - win->w.left = clamp_t(int, win->w.left, - -dev->fb_cap.fmt.width, dev->fb_cap.fmt.width); - win->w.top = clamp_t(int, win->w.top, - -dev->fb_cap.fmt.height, dev->fb_cap.fmt.height); - win->w.width = compose->width; - win->w.height = compose->height; - if (win->field != V4L2_FIELD_BOTTOM && win->field != V4L2_FIELD_TOP) - win->field = V4L2_FIELD_ANY; - win->chromakey = 0; - win->global_alpha = 0; - if (win->clipcount && !win->clips) - win->clipcount = 0; - if (win->clipcount > MAX_CLIPS) - win->clipcount = MAX_CLIPS; - if (win->clipcount) { - if (copy_from_user(dev->try_clips_cap, win->clips, - win->clipcount * sizeof(dev->clips_cap[0]))) - return -EFAULT; - for (i = 0; i < win->clipcount; i++) { - struct v4l2_rect *r = &dev->try_clips_cap[i].c; - - r->top = clamp_t(s32, r->top, 0, dev->fb_cap.fmt.height - 1); - r->height = clamp_t(s32, r->height, 1, dev->fb_cap.fmt.height - r->top); - r->left = clamp_t(u32, r->left, 0, dev->fb_cap.fmt.width - 1); - r->width = clamp_t(u32, r->width, 1, dev->fb_cap.fmt.width - r->left); - } - /* - * Yeah, so sue me, it's an O(n^2) algorithm. But n is a small - * number and it's typically a one-time deal. - */ - for (i = 0; i < win->clipcount - 1; i++) { - struct v4l2_rect *r1 = &dev->try_clips_cap[i].c; - - for (j = i + 1; j < win->clipcount; j++) { - struct v4l2_rect *r2 = &dev->try_clips_cap[j].c; - - if (v4l2_rect_overlap(r1, r2)) - return -EINVAL; - } - } - if (copy_to_user(win->clips, dev->try_clips_cap, - win->clipcount * sizeof(dev->clips_cap[0]))) - return -EFAULT; - } - return 0; -} - -int vidioc_s_fmt_vid_overlay(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct vivid_dev *dev = video_drvdata(file); - const struct v4l2_rect *compose = &dev->compose_cap; - struct v4l2_window *win = &f->fmt.win; - int ret = vidioc_try_fmt_vid_overlay(file, priv, f); - unsigned bitmap_size = ((compose->width + 7) / 8) * compose->height; - unsigned clips_size = win->clipcount * sizeof(dev->clips_cap[0]); - void *new_bitmap = NULL; - - if (ret) - return ret; - - if (win->bitmap) { - new_bitmap = vzalloc(bitmap_size); - - if (new_bitmap == NULL) - return -ENOMEM; - if (copy_from_user(new_bitmap, win->bitmap, bitmap_size)) { - vfree(new_bitmap); - return -EFAULT; - } - } - - dev->overlay_cap_top = win->w.top; - dev->overlay_cap_left = win->w.left; - dev->overlay_cap_field = win->field; - vfree(dev->bitmap_cap); - dev->bitmap_cap = new_bitmap; - dev->clipcount_cap = win->clipcount; - if (dev->clipcount_cap) - memcpy(dev->clips_cap, dev->try_clips_cap, clips_size); - return 0; -} - -int vivid_vid_cap_overlay(struct file *file, void *fh, unsigned i) -{ - struct vivid_dev *dev = video_drvdata(file); - - if (dev->multiplanar) - return -ENOTTY; - - if (i && dev->fb_vbase_cap == NULL) - return -EINVAL; - - if (i && dev->fb_cap.fmt.pixelformat != dev->fmt_cap->fourcc) { - dprintk(dev, 1, "mismatch between overlay and video capture pixelformats\n"); - return -EINVAL; - } - - if (dev->overlay_cap_owner && dev->overlay_cap_owner != fh) - return -EBUSY; - dev->overlay_cap_owner = i ? fh : NULL; - return 0; -} - -int vivid_vid_cap_g_fbuf(struct file *file, void *fh, - struct v4l2_framebuffer *a) -{ - struct vivid_dev *dev = video_drvdata(file); - - if (dev->multiplanar) - return -ENOTTY; - - *a = dev->fb_cap; - a->capability = V4L2_FBUF_CAP_BITMAP_CLIPPING | - V4L2_FBUF_CAP_LIST_CLIPPING; - a->flags = V4L2_FBUF_FLAG_PRIMARY; - a->fmt.field = V4L2_FIELD_NONE; - a->fmt.colorspace = V4L2_COLORSPACE_SRGB; - a->fmt.priv = 0; - return 0; -} - -int vivid_vid_cap_s_fbuf(struct file *file, void *fh, - const struct v4l2_framebuffer *a) -{ - struct vivid_dev *dev = video_drvdata(file); - const struct vivid_fmt *fmt; - - if (dev->multiplanar) - return -ENOTTY; - - if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RAWIO)) - return -EPERM; - - if (dev->overlay_cap_owner) - return -EBUSY; - - if (a->base == NULL) { - dev->fb_cap.base = NULL; - dev->fb_vbase_cap = NULL; - return 0; - } - - if (a->fmt.width < 48 || a->fmt.height < 32) - return -EINVAL; - fmt = vivid_get_format(dev, a->fmt.pixelformat); - if (!fmt || !fmt->can_do_overlay) - return -EINVAL; - if (a->fmt.bytesperline < (a->fmt.width * fmt->bit_depth[0]) / 8) - return -EINVAL; - if (a->fmt.height * a->fmt.bytesperline < a->fmt.sizeimage) - return -EINVAL; - - dev->fb_vbase_cap = phys_to_virt((unsigned long)a->base); - dev->fb_cap = *a; - dev->overlay_cap_left = clamp_t(int, dev->overlay_cap_left, - -dev->fb_cap.fmt.width, dev->fb_cap.fmt.width); - dev->overlay_cap_top = clamp_t(int, dev->overlay_cap_top, - -dev->fb_cap.fmt.height, dev->fb_cap.fmt.height); - return 0; -} - -static const struct v4l2_audio vivid_audio_inputs[] = { - { 0, "TV", V4L2_AUDCAP_STEREO }, - { 1, "Line-In", V4L2_AUDCAP_STEREO }, -}; - -int vidioc_enum_input(struct file *file, void *priv, - struct v4l2_input *inp) -{ - struct vivid_dev *dev = video_drvdata(file); - - if (inp->index >= dev->num_inputs) - return -EINVAL; - - inp->type = V4L2_INPUT_TYPE_CAMERA; - switch (dev->input_type[inp->index]) { - case WEBCAM: - snprintf(inp->name, sizeof(inp->name), "Webcam %u", - dev->input_name_counter[inp->index]); - inp->capabilities = 0; - break; - case TV: - snprintf(inp->name, sizeof(inp->name), "TV %u", - dev->input_name_counter[inp->index]); - inp->type = V4L2_INPUT_TYPE_TUNER; - inp->std = V4L2_STD_ALL; - if (dev->has_audio_inputs) - inp->audioset = (1 << ARRAY_SIZE(vivid_audio_inputs)) - 1; - inp->capabilities = V4L2_IN_CAP_STD; - break; - case SVID: - snprintf(inp->name, sizeof(inp->name), "S-Video %u", - dev->input_name_counter[inp->index]); - inp->std = V4L2_STD_ALL; - if (dev->has_audio_inputs) - inp->audioset = (1 << ARRAY_SIZE(vivid_audio_inputs)) - 1; - inp->capabilities = V4L2_IN_CAP_STD; - break; - case HDMI: - snprintf(inp->name, sizeof(inp->name), "HDMI %u", - dev->input_name_counter[inp->index]); - inp->capabilities = V4L2_IN_CAP_DV_TIMINGS; - if (dev->edid_blocks == 0 || - dev->dv_timings_signal_mode[dev->input] == NO_SIGNAL) - inp->status |= V4L2_IN_ST_NO_SIGNAL; - else if (dev->dv_timings_signal_mode[dev->input] == NO_LOCK || - dev->dv_timings_signal_mode[dev->input] == OUT_OF_RANGE) - inp->status |= V4L2_IN_ST_NO_H_LOCK; - break; - } - if (dev->sensor_hflip) - inp->status |= V4L2_IN_ST_HFLIP; - if (dev->sensor_vflip) - inp->status |= V4L2_IN_ST_VFLIP; - if (dev->input == inp->index && vivid_is_sdtv_cap(dev)) { - if (dev->std_signal_mode[dev->input] == NO_SIGNAL) { - inp->status |= V4L2_IN_ST_NO_SIGNAL; - } else if (dev->std_signal_mode[dev->input] == NO_LOCK) { - inp->status |= V4L2_IN_ST_NO_H_LOCK; - } else if (vivid_is_tv_cap(dev)) { - switch (tpg_g_quality(&dev->tpg)) { - case TPG_QUAL_GRAY: - inp->status |= V4L2_IN_ST_COLOR_KILL; - break; - case TPG_QUAL_NOISE: - inp->status |= V4L2_IN_ST_NO_H_LOCK; - break; - default: - break; - } - } - } - return 0; -} - -int vidioc_g_input(struct file *file, void *priv, unsigned *i) -{ - struct vivid_dev *dev = video_drvdata(file); - - *i = dev->input; - return 0; -} - -int vidioc_s_input(struct file *file, void *priv, unsigned i) -{ - struct vivid_dev *dev = video_drvdata(file); - struct v4l2_bt_timings *bt = &dev->dv_timings_cap[dev->input].bt; - unsigned brightness; - - if (i >= dev->num_inputs) - return -EINVAL; - - if (i == dev->input) - return 0; - - if (vb2_is_busy(&dev->vb_vid_cap_q) || - vb2_is_busy(&dev->vb_vbi_cap_q) || - vb2_is_busy(&dev->vb_meta_cap_q)) - return -EBUSY; - - dev->input = i; - dev->vid_cap_dev.tvnorms = 0; - if (dev->input_type[i] == TV || dev->input_type[i] == SVID) { - dev->tv_audio_input = (dev->input_type[i] == TV) ? 0 : 1; - dev->vid_cap_dev.tvnorms = V4L2_STD_ALL; - } - dev->vbi_cap_dev.tvnorms = dev->vid_cap_dev.tvnorms; - dev->meta_cap_dev.tvnorms = dev->vid_cap_dev.tvnorms; - vivid_update_format_cap(dev, false); - - if (dev->colorspace) { - switch (dev->input_type[i]) { - case WEBCAM: - v4l2_ctrl_s_ctrl(dev->colorspace, VIVID_CS_SRGB); - break; - case TV: - case SVID: - v4l2_ctrl_s_ctrl(dev->colorspace, VIVID_CS_170M); - break; - case HDMI: - if (bt->flags & V4L2_DV_FL_IS_CE_VIDEO) { - if (dev->src_rect.width == 720 && dev->src_rect.height <= 576) - v4l2_ctrl_s_ctrl(dev->colorspace, VIVID_CS_170M); - else - v4l2_ctrl_s_ctrl(dev->colorspace, VIVID_CS_709); - } else { - v4l2_ctrl_s_ctrl(dev->colorspace, VIVID_CS_SRGB); - } - break; - } - } - - /* - * Modify the brightness range depending on the input. - * This makes it easy to use vivid to test if applications can - * handle control range modifications and is also how this is - * typically used in practice as different inputs may be hooked - * up to different receivers with different control ranges. - */ - brightness = 128 * i + dev->input_brightness[i]; - v4l2_ctrl_modify_range(dev->brightness, - 128 * i, 255 + 128 * i, 1, 128 + 128 * i); - v4l2_ctrl_s_ctrl(dev->brightness, brightness); - - /* Restore per-input states. */ - v4l2_ctrl_activate(dev->ctrl_dv_timings_signal_mode, - vivid_is_hdmi_cap(dev)); - v4l2_ctrl_activate(dev->ctrl_dv_timings, vivid_is_hdmi_cap(dev) && - dev->dv_timings_signal_mode[dev->input] == - SELECTED_DV_TIMINGS); - v4l2_ctrl_activate(dev->ctrl_std_signal_mode, vivid_is_sdtv_cap(dev)); - v4l2_ctrl_activate(dev->ctrl_standard, vivid_is_sdtv_cap(dev) && - dev->std_signal_mode[dev->input]); - - if (vivid_is_hdmi_cap(dev)) { - v4l2_ctrl_s_ctrl(dev->ctrl_dv_timings_signal_mode, - dev->dv_timings_signal_mode[dev->input]); - v4l2_ctrl_s_ctrl(dev->ctrl_dv_timings, - dev->query_dv_timings[dev->input]); - } else if (vivid_is_sdtv_cap(dev)) { - v4l2_ctrl_s_ctrl(dev->ctrl_std_signal_mode, - dev->std_signal_mode[dev->input]); - v4l2_ctrl_s_ctrl(dev->ctrl_standard, - dev->std_signal_mode[dev->input]); - } - - return 0; -} - -int vidioc_enumaudio(struct file *file, void *fh, struct v4l2_audio *vin) -{ - if (vin->index >= ARRAY_SIZE(vivid_audio_inputs)) - return -EINVAL; - *vin = vivid_audio_inputs[vin->index]; - return 0; -} - -int vidioc_g_audio(struct file *file, void *fh, struct v4l2_audio *vin) -{ - struct vivid_dev *dev = video_drvdata(file); - - if (!vivid_is_sdtv_cap(dev)) - return -EINVAL; - *vin = vivid_audio_inputs[dev->tv_audio_input]; - return 0; -} - -int vidioc_s_audio(struct file *file, void *fh, const struct v4l2_audio *vin) -{ - struct vivid_dev *dev = video_drvdata(file); - - if (!vivid_is_sdtv_cap(dev)) - return -EINVAL; - if (vin->index >= ARRAY_SIZE(vivid_audio_inputs)) - return -EINVAL; - dev->tv_audio_input = vin->index; - return 0; -} - -int vivid_video_g_frequency(struct file *file, void *fh, struct v4l2_frequency *vf) -{ - struct vivid_dev *dev = video_drvdata(file); - - if (vf->tuner != 0) - return -EINVAL; - vf->frequency = dev->tv_freq; - return 0; -} - -int vivid_video_s_frequency(struct file *file, void *fh, const struct v4l2_frequency *vf) -{ - struct vivid_dev *dev = video_drvdata(file); - - if (vf->tuner != 0) - return -EINVAL; - dev->tv_freq = clamp_t(unsigned, vf->frequency, MIN_TV_FREQ, MAX_TV_FREQ); - if (vivid_is_tv_cap(dev)) - vivid_update_quality(dev); - return 0; -} - -int vivid_video_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *vt) -{ - struct vivid_dev *dev = video_drvdata(file); - - if (vt->index != 0) - return -EINVAL; - if (vt->audmode > V4L2_TUNER_MODE_LANG1_LANG2) - return -EINVAL; - dev->tv_audmode = vt->audmode; - return 0; -} - -int vivid_video_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt) -{ - struct vivid_dev *dev = video_drvdata(file); - enum tpg_quality qual; - - if (vt->index != 0) - return -EINVAL; - - vt->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO | - V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2; - vt->audmode = dev->tv_audmode; - vt->rangelow = MIN_TV_FREQ; - vt->rangehigh = MAX_TV_FREQ; - qual = vivid_get_quality(dev, &vt->afc); - if (qual == TPG_QUAL_COLOR) - vt->signal = 0xffff; - else if (qual == TPG_QUAL_GRAY) - vt->signal = 0x8000; - else - vt->signal = 0; - if (qual == TPG_QUAL_NOISE) { - vt->rxsubchans = 0; - } else if (qual == TPG_QUAL_GRAY) { - vt->rxsubchans = V4L2_TUNER_SUB_MONO; - } else { - unsigned int channel_nr = dev->tv_freq / (6 * 16); - unsigned int options = - (dev->std_cap[dev->input] & V4L2_STD_NTSC_M) ? 4 : 3; - - switch (channel_nr % options) { - case 0: - vt->rxsubchans = V4L2_TUNER_SUB_MONO; - break; - case 1: - vt->rxsubchans = V4L2_TUNER_SUB_STEREO; - break; - case 2: - if (dev->std_cap[dev->input] & V4L2_STD_NTSC_M) - vt->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_SAP; - else - vt->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; - break; - case 3: - vt->rxsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_SAP; - break; - } - } - strscpy(vt->name, "TV Tuner", sizeof(vt->name)); - return 0; -} - -/* Must remain in sync with the vivid_ctrl_standard_strings array */ -const v4l2_std_id vivid_standard[] = { - V4L2_STD_NTSC_M, - V4L2_STD_NTSC_M_JP, - V4L2_STD_NTSC_M_KR, - V4L2_STD_NTSC_443, - V4L2_STD_PAL_BG | V4L2_STD_PAL_H, - V4L2_STD_PAL_I, - V4L2_STD_PAL_DK, - V4L2_STD_PAL_M, - V4L2_STD_PAL_N, - V4L2_STD_PAL_Nc, - V4L2_STD_PAL_60, - V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H, - V4L2_STD_SECAM_DK, - V4L2_STD_SECAM_L, - V4L2_STD_SECAM_LC, - V4L2_STD_UNKNOWN -}; - -/* Must remain in sync with the vivid_standard array */ -const char * const vivid_ctrl_standard_strings[] = { - "NTSC-M", - "NTSC-M-JP", - "NTSC-M-KR", - "NTSC-443", - "PAL-BGH", - "PAL-I", - "PAL-DK", - "PAL-M", - "PAL-N", - "PAL-Nc", - "PAL-60", - "SECAM-BGH", - "SECAM-DK", - "SECAM-L", - "SECAM-Lc", - NULL, -}; - -int vidioc_querystd(struct file *file, void *priv, v4l2_std_id *id) -{ - struct vivid_dev *dev = video_drvdata(file); - unsigned int last = dev->query_std_last[dev->input]; - - if (!vivid_is_sdtv_cap(dev)) - return -ENODATA; - if (dev->std_signal_mode[dev->input] == NO_SIGNAL || - dev->std_signal_mode[dev->input] == NO_LOCK) { - *id = V4L2_STD_UNKNOWN; - return 0; - } - if (vivid_is_tv_cap(dev) && tpg_g_quality(&dev->tpg) == TPG_QUAL_NOISE) { - *id = V4L2_STD_UNKNOWN; - } else if (dev->std_signal_mode[dev->input] == CURRENT_STD) { - *id = dev->std_cap[dev->input]; - } else if (dev->std_signal_mode[dev->input] == SELECTED_STD) { - *id = dev->query_std[dev->input]; - } else { - *id = vivid_standard[last]; - dev->query_std_last[dev->input] = - (last + 1) % ARRAY_SIZE(vivid_standard); - } - - return 0; -} - -int vivid_vid_cap_s_std(struct file *file, void *priv, v4l2_std_id id) -{ - struct vivid_dev *dev = video_drvdata(file); - - if (!vivid_is_sdtv_cap(dev)) - return -ENODATA; - if (dev->std_cap[dev->input] == id) - return 0; - if (vb2_is_busy(&dev->vb_vid_cap_q) || vb2_is_busy(&dev->vb_vbi_cap_q)) - return -EBUSY; - dev->std_cap[dev->input] = id; - vivid_update_format_cap(dev, false); - return 0; -} - -static void find_aspect_ratio(u32 width, u32 height, - u32 *num, u32 *denom) -{ - if (!(height % 3) && ((height * 4 / 3) == width)) { - *num = 4; - *denom = 3; - } else if (!(height % 9) && ((height * 16 / 9) == width)) { - *num = 16; - *denom = 9; - } else if (!(height % 10) && ((height * 16 / 10) == width)) { - *num = 16; - *denom = 10; - } else if (!(height % 4) && ((height * 5 / 4) == width)) { - *num = 5; - *denom = 4; - } else if (!(height % 9) && ((height * 15 / 9) == width)) { - *num = 15; - *denom = 9; - } else { /* default to 16:9 */ - *num = 16; - *denom = 9; - } -} - -static bool valid_cvt_gtf_timings(struct v4l2_dv_timings *timings) -{ - struct v4l2_bt_timings *bt = &timings->bt; - u32 total_h_pixel; - u32 total_v_lines; - u32 h_freq; - - if (!v4l2_valid_dv_timings(timings, &vivid_dv_timings_cap, - NULL, NULL)) - return false; - - total_h_pixel = V4L2_DV_BT_FRAME_WIDTH(bt); - total_v_lines = V4L2_DV_BT_FRAME_HEIGHT(bt); - - h_freq = (u32)bt->pixelclock / total_h_pixel; - - if (bt->standards == 0 || (bt->standards & V4L2_DV_BT_STD_CVT)) { - if (v4l2_detect_cvt(total_v_lines, h_freq, bt->vsync, bt->width, - bt->polarities, bt->interlaced, timings)) - return true; - } - - if (bt->standards == 0 || (bt->standards & V4L2_DV_BT_STD_GTF)) { - struct v4l2_fract aspect_ratio; - - find_aspect_ratio(bt->width, bt->height, - &aspect_ratio.numerator, - &aspect_ratio.denominator); - if (v4l2_detect_gtf(total_v_lines, h_freq, bt->vsync, - bt->polarities, bt->interlaced, - aspect_ratio, timings)) - return true; - } - return false; -} - -int vivid_vid_cap_s_dv_timings(struct file *file, void *_fh, - struct v4l2_dv_timings *timings) -{ - struct vivid_dev *dev = video_drvdata(file); - - if (!vivid_is_hdmi_cap(dev)) - return -ENODATA; - if (!v4l2_find_dv_timings_cap(timings, &vivid_dv_timings_cap, - 0, NULL, NULL) && - !valid_cvt_gtf_timings(timings)) - return -EINVAL; - - if (v4l2_match_dv_timings(timings, &dev->dv_timings_cap[dev->input], - 0, false)) - return 0; - if (vb2_is_busy(&dev->vb_vid_cap_q)) - return -EBUSY; - - dev->dv_timings_cap[dev->input] = *timings; - vivid_update_format_cap(dev, false); - return 0; -} - -int vidioc_query_dv_timings(struct file *file, void *_fh, - struct v4l2_dv_timings *timings) -{ - struct vivid_dev *dev = video_drvdata(file); - unsigned int input = dev->input; - unsigned int last = dev->query_dv_timings_last[input]; - - if (!vivid_is_hdmi_cap(dev)) - return -ENODATA; - if (dev->dv_timings_signal_mode[input] == NO_SIGNAL || - dev->edid_blocks == 0) - return -ENOLINK; - if (dev->dv_timings_signal_mode[input] == NO_LOCK) - return -ENOLCK; - if (dev->dv_timings_signal_mode[input] == OUT_OF_RANGE) { - timings->bt.pixelclock = vivid_dv_timings_cap.bt.max_pixelclock * 2; - return -ERANGE; - } - if (dev->dv_timings_signal_mode[input] == CURRENT_DV_TIMINGS) { - *timings = dev->dv_timings_cap[input]; - } else if (dev->dv_timings_signal_mode[input] == - SELECTED_DV_TIMINGS) { - *timings = - v4l2_dv_timings_presets[dev->query_dv_timings[input]]; - } else { - *timings = - v4l2_dv_timings_presets[last]; - dev->query_dv_timings_last[input] = - (last + 1) % dev->query_dv_timings_size; - } - return 0; -} - -int vidioc_s_edid(struct file *file, void *_fh, - struct v4l2_edid *edid) -{ - struct vivid_dev *dev = video_drvdata(file); - u16 phys_addr; - u32 display_present = 0; - unsigned int i, j; - int ret; - - memset(edid->reserved, 0, sizeof(edid->reserved)); - if (edid->pad >= dev->num_inputs) - return -EINVAL; - if (dev->input_type[edid->pad] != HDMI || edid->start_block) - return -EINVAL; - if (edid->blocks == 0) { - dev->edid_blocks = 0; - v4l2_ctrl_s_ctrl(dev->ctrl_tx_edid_present, 0); - v4l2_ctrl_s_ctrl(dev->ctrl_tx_hotplug, 0); - phys_addr = CEC_PHYS_ADDR_INVALID; - goto set_phys_addr; - } - if (edid->blocks > dev->edid_max_blocks) { - edid->blocks = dev->edid_max_blocks; - return -E2BIG; - } - phys_addr = cec_get_edid_phys_addr(edid->edid, edid->blocks * 128, NULL); - ret = v4l2_phys_addr_validate(phys_addr, &phys_addr, NULL); - if (ret) - return ret; - - if (vb2_is_busy(&dev->vb_vid_cap_q)) - return -EBUSY; - - dev->edid_blocks = edid->blocks; - memcpy(dev->edid, edid->edid, edid->blocks * 128); - - for (i = 0, j = 0; i < dev->num_outputs; i++) - if (dev->output_type[i] == HDMI) - display_present |= - dev->display_present[i] << j++; - - v4l2_ctrl_s_ctrl(dev->ctrl_tx_edid_present, display_present); - v4l2_ctrl_s_ctrl(dev->ctrl_tx_hotplug, display_present); - -set_phys_addr: - /* TODO: a proper hotplug detect cycle should be emulated here */ - cec_s_phys_addr(dev->cec_rx_adap, phys_addr, false); - - for (i = 0; i < MAX_OUTPUTS && dev->cec_tx_adap[i]; i++) - cec_s_phys_addr(dev->cec_tx_adap[i], - dev->display_present[i] ? - v4l2_phys_addr_for_input(phys_addr, i + 1) : - CEC_PHYS_ADDR_INVALID, - false); - return 0; -} - -int vidioc_enum_framesizes(struct file *file, void *fh, - struct v4l2_frmsizeenum *fsize) -{ - struct vivid_dev *dev = video_drvdata(file); - - if (!vivid_is_webcam(dev) && !dev->has_scaler_cap) - return -EINVAL; - if (vivid_get_format(dev, fsize->pixel_format) == NULL) - return -EINVAL; - if (vivid_is_webcam(dev)) { - if (fsize->index >= ARRAY_SIZE(webcam_sizes)) - return -EINVAL; - fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; - fsize->discrete = webcam_sizes[fsize->index]; - return 0; - } - if (fsize->index) - return -EINVAL; - fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; - fsize->stepwise.min_width = MIN_WIDTH; - fsize->stepwise.max_width = MAX_WIDTH * MAX_ZOOM; - fsize->stepwise.step_width = 2; - fsize->stepwise.min_height = MIN_HEIGHT; - fsize->stepwise.max_height = MAX_HEIGHT * MAX_ZOOM; - fsize->stepwise.step_height = 2; - return 0; -} - -/* timeperframe is arbitrary and continuous */ -int vidioc_enum_frameintervals(struct file *file, void *priv, - struct v4l2_frmivalenum *fival) -{ - struct vivid_dev *dev = video_drvdata(file); - const struct vivid_fmt *fmt; - int i; - - fmt = vivid_get_format(dev, fival->pixel_format); - if (!fmt) - return -EINVAL; - - if (!vivid_is_webcam(dev)) { - if (fival->index) - return -EINVAL; - if (fival->width < MIN_WIDTH || fival->width > MAX_WIDTH * MAX_ZOOM) - return -EINVAL; - if (fival->height < MIN_HEIGHT || fival->height > MAX_HEIGHT * MAX_ZOOM) - return -EINVAL; - fival->type = V4L2_FRMIVAL_TYPE_DISCRETE; - fival->discrete = dev->timeperframe_vid_cap; - return 0; - } - - for (i = 0; i < ARRAY_SIZE(webcam_sizes); i++) - if (fival->width == webcam_sizes[i].width && - fival->height == webcam_sizes[i].height) - break; - if (i == ARRAY_SIZE(webcam_sizes)) - return -EINVAL; - if (fival->index >= 2 * (VIVID_WEBCAM_SIZES - i)) - return -EINVAL; - fival->type = V4L2_FRMIVAL_TYPE_DISCRETE; - fival->discrete = webcam_intervals[fival->index]; - return 0; -} - -int vivid_vid_cap_g_parm(struct file *file, void *priv, - struct v4l2_streamparm *parm) -{ - struct vivid_dev *dev = video_drvdata(file); - - if (parm->type != (dev->multiplanar ? - V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE : - V4L2_BUF_TYPE_VIDEO_CAPTURE)) - return -EINVAL; - - parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; - parm->parm.capture.timeperframe = dev->timeperframe_vid_cap; - parm->parm.capture.readbuffers = 1; - return 0; -} - -int vivid_vid_cap_s_parm(struct file *file, void *priv, - struct v4l2_streamparm *parm) -{ - struct vivid_dev *dev = video_drvdata(file); - unsigned ival_sz = 2 * (VIVID_WEBCAM_SIZES - dev->webcam_size_idx); - struct v4l2_fract tpf; - unsigned i; - - if (parm->type != (dev->multiplanar ? - V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE : - V4L2_BUF_TYPE_VIDEO_CAPTURE)) - return -EINVAL; - if (!vivid_is_webcam(dev)) - return vivid_vid_cap_g_parm(file, priv, parm); - - tpf = parm->parm.capture.timeperframe; - - if (tpf.denominator == 0) - tpf = webcam_intervals[ival_sz - 1]; - for (i = 0; i < ival_sz; i++) - if (V4L2_FRACT_COMPARE(tpf, >=, webcam_intervals[i])) - break; - if (i == ival_sz) - i = ival_sz - 1; - dev->webcam_ival_idx = i; - tpf = webcam_intervals[dev->webcam_ival_idx]; - - /* resync the thread's timings */ - dev->cap_seq_resync = true; - dev->timeperframe_vid_cap = tpf; - parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; - parm->parm.capture.timeperframe = tpf; - parm->parm.capture.readbuffers = 1; - return 0; -} diff --git a/drivers/media/platform/vivid/vivid-vid-cap.h b/drivers/media/platform/vivid/vivid-vid-cap.h deleted file mode 100644 index 1e422a59eeab..000000000000 --- a/drivers/media/platform/vivid/vivid-vid-cap.h +++ /dev/null @@ -1,59 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * vivid-vid-cap.h - video capture support functions. - * - * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - */ - -#ifndef _VIVID_VID_CAP_H_ -#define _VIVID_VID_CAP_H_ - -void vivid_update_quality(struct vivid_dev *dev); -void vivid_update_format_cap(struct vivid_dev *dev, bool keep_controls); -enum tpg_video_aspect vivid_get_video_aspect(const struct vivid_dev *dev); - -extern const v4l2_std_id vivid_standard[]; -extern const char * const vivid_ctrl_standard_strings[]; - -extern const struct vb2_ops vivid_vid_cap_qops; - -int vivid_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f); -int vivid_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f); -int vivid_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f); -int vidioc_g_fmt_vid_cap_mplane(struct file *file, void *priv, struct v4l2_format *f); -int vidioc_try_fmt_vid_cap_mplane(struct file *file, void *priv, struct v4l2_format *f); -int vidioc_s_fmt_vid_cap_mplane(struct file *file, void *priv, struct v4l2_format *f); -int vidioc_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f); -int vidioc_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f); -int vidioc_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f); -int vivid_vid_cap_g_selection(struct file *file, void *priv, struct v4l2_selection *sel); -int vivid_vid_cap_s_selection(struct file *file, void *fh, struct v4l2_selection *s); -int vivid_vid_cap_g_pixelaspect(struct file *file, void *priv, int type, struct v4l2_fract *f); -int vidioc_enum_fmt_vid_overlay(struct file *file, void *priv, struct v4l2_fmtdesc *f); -int vidioc_g_fmt_vid_overlay(struct file *file, void *priv, struct v4l2_format *f); -int vidioc_try_fmt_vid_overlay(struct file *file, void *priv, struct v4l2_format *f); -int vidioc_s_fmt_vid_overlay(struct file *file, void *priv, struct v4l2_format *f); -int vivid_vid_cap_overlay(struct file *file, void *fh, unsigned i); -int vivid_vid_cap_g_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *a); -int vivid_vid_cap_s_fbuf(struct file *file, void *fh, const struct v4l2_framebuffer *a); -int vidioc_enum_input(struct file *file, void *priv, struct v4l2_input *inp); -int vidioc_g_input(struct file *file, void *priv, unsigned *i); -int vidioc_s_input(struct file *file, void *priv, unsigned i); -int vidioc_enumaudio(struct file *file, void *fh, struct v4l2_audio *vin); -int vidioc_g_audio(struct file *file, void *fh, struct v4l2_audio *vin); -int vidioc_s_audio(struct file *file, void *fh, const struct v4l2_audio *vin); -int vivid_video_g_frequency(struct file *file, void *fh, struct v4l2_frequency *vf); -int vivid_video_s_frequency(struct file *file, void *fh, const struct v4l2_frequency *vf); -int vivid_video_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *vt); -int vivid_video_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt); -int vidioc_querystd(struct file *file, void *priv, v4l2_std_id *id); -int vivid_vid_cap_s_std(struct file *file, void *priv, v4l2_std_id id); -int vivid_vid_cap_s_dv_timings(struct file *file, void *_fh, struct v4l2_dv_timings *timings); -int vidioc_query_dv_timings(struct file *file, void *_fh, struct v4l2_dv_timings *timings); -int vidioc_s_edid(struct file *file, void *_fh, struct v4l2_edid *edid); -int vidioc_enum_framesizes(struct file *file, void *fh, struct v4l2_frmsizeenum *fsize); -int vidioc_enum_frameintervals(struct file *file, void *priv, struct v4l2_frmivalenum *fival); -int vivid_vid_cap_g_parm(struct file *file, void *priv, struct v4l2_streamparm *parm); -int vivid_vid_cap_s_parm(struct file *file, void *priv, struct v4l2_streamparm *parm); - -#endif diff --git a/drivers/media/platform/vivid/vivid-vid-common.c b/drivers/media/platform/vivid/vivid-vid-common.c deleted file mode 100644 index 76b0be670ebb..000000000000 --- a/drivers/media/platform/vivid/vivid-vid-common.c +++ /dev/null @@ -1,1035 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * vivid-vid-common.c - common video support functions. - * - * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "vivid-core.h" -#include "vivid-vid-common.h" - -const struct v4l2_dv_timings_cap vivid_dv_timings_cap = { - .type = V4L2_DV_BT_656_1120, - /* keep this initialization for compatibility with GCC < 4.4.6 */ - .reserved = { 0 }, - V4L2_INIT_BT_TIMINGS(16, MAX_WIDTH, 16, MAX_HEIGHT, 14000000, 775000000, - V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT | - V4L2_DV_BT_STD_CVT | V4L2_DV_BT_STD_GTF, - V4L2_DV_BT_CAP_PROGRESSIVE | V4L2_DV_BT_CAP_INTERLACED) -}; - -/* ------------------------------------------------------------------ - Basic structures - ------------------------------------------------------------------*/ - -struct vivid_fmt vivid_formats[] = { - { - .fourcc = V4L2_PIX_FMT_YUYV, - .vdownsampling = { 1 }, - .bit_depth = { 16 }, - .color_enc = TGP_COLOR_ENC_YCBCR, - .planes = 1, - .buffers = 1, - .data_offset = { PLANE0_DATA_OFFSET }, - }, - { - .fourcc = V4L2_PIX_FMT_UYVY, - .vdownsampling = { 1 }, - .bit_depth = { 16 }, - .color_enc = TGP_COLOR_ENC_YCBCR, - .planes = 1, - .buffers = 1, - }, - { - .fourcc = V4L2_PIX_FMT_YVYU, - .vdownsampling = { 1 }, - .bit_depth = { 16 }, - .color_enc = TGP_COLOR_ENC_YCBCR, - .planes = 1, - .buffers = 1, - }, - { - .fourcc = V4L2_PIX_FMT_VYUY, - .vdownsampling = { 1 }, - .bit_depth = { 16 }, - .color_enc = TGP_COLOR_ENC_YCBCR, - .planes = 1, - .buffers = 1, - }, - { - .fourcc = V4L2_PIX_FMT_YUV422P, - .vdownsampling = { 1, 1, 1 }, - .bit_depth = { 8, 4, 4 }, - .color_enc = TGP_COLOR_ENC_YCBCR, - .planes = 3, - .buffers = 1, - }, - { - .fourcc = V4L2_PIX_FMT_YUV420, - .vdownsampling = { 1, 2, 2 }, - .bit_depth = { 8, 4, 4 }, - .color_enc = TGP_COLOR_ENC_YCBCR, - .planes = 3, - .buffers = 1, - }, - { - .fourcc = V4L2_PIX_FMT_YVU420, - .vdownsampling = { 1, 2, 2 }, - .bit_depth = { 8, 4, 4 }, - .color_enc = TGP_COLOR_ENC_YCBCR, - .planes = 3, - .buffers = 1, - }, - { - .fourcc = V4L2_PIX_FMT_NV12, - .vdownsampling = { 1, 2 }, - .bit_depth = { 8, 8 }, - .color_enc = TGP_COLOR_ENC_YCBCR, - .planes = 2, - .buffers = 1, - }, - { - .fourcc = V4L2_PIX_FMT_NV21, - .vdownsampling = { 1, 2 }, - .bit_depth = { 8, 8 }, - .color_enc = TGP_COLOR_ENC_YCBCR, - .planes = 2, - .buffers = 1, - }, - { - .fourcc = V4L2_PIX_FMT_NV16, - .vdownsampling = { 1, 1 }, - .bit_depth = { 8, 8 }, - .color_enc = TGP_COLOR_ENC_YCBCR, - .planes = 2, - .buffers = 1, - }, - { - .fourcc = V4L2_PIX_FMT_NV61, - .vdownsampling = { 1, 1 }, - .bit_depth = { 8, 8 }, - .color_enc = TGP_COLOR_ENC_YCBCR, - .planes = 2, - .buffers = 1, - }, - { - .fourcc = V4L2_PIX_FMT_NV24, - .vdownsampling = { 1, 1 }, - .bit_depth = { 8, 16 }, - .color_enc = TGP_COLOR_ENC_YCBCR, - .planes = 2, - .buffers = 1, - }, - { - .fourcc = V4L2_PIX_FMT_NV42, - .vdownsampling = { 1, 1 }, - .bit_depth = { 8, 16 }, - .color_enc = TGP_COLOR_ENC_YCBCR, - .planes = 2, - .buffers = 1, - }, - { - .fourcc = V4L2_PIX_FMT_YUV555, /* uuuvvvvv ayyyyyuu */ - .vdownsampling = { 1 }, - .bit_depth = { 16 }, - .planes = 1, - .buffers = 1, - .alpha_mask = 0x8000, - }, - { - .fourcc = V4L2_PIX_FMT_YUV565, /* uuuvvvvv yyyyyuuu */ - .vdownsampling = { 1 }, - .bit_depth = { 16 }, - .planes = 1, - .buffers = 1, - }, - { - .fourcc = V4L2_PIX_FMT_YUV444, /* uuuuvvvv aaaayyyy */ - .vdownsampling = { 1 }, - .bit_depth = { 16 }, - .planes = 1, - .buffers = 1, - .alpha_mask = 0xf000, - }, - { - .fourcc = V4L2_PIX_FMT_YUV32, /* ayuv */ - .vdownsampling = { 1 }, - .bit_depth = { 32 }, - .planes = 1, - .buffers = 1, - .alpha_mask = 0x000000ff, - }, - { - .fourcc = V4L2_PIX_FMT_AYUV32, - .vdownsampling = { 1 }, - .bit_depth = { 32 }, - .planes = 1, - .buffers = 1, - .alpha_mask = 0x000000ff, - }, - { - .fourcc = V4L2_PIX_FMT_XYUV32, - .vdownsampling = { 1 }, - .bit_depth = { 32 }, - .planes = 1, - .buffers = 1, - }, - { - .fourcc = V4L2_PIX_FMT_VUYA32, - .vdownsampling = { 1 }, - .bit_depth = { 32 }, - .planes = 1, - .buffers = 1, - .alpha_mask = 0xff000000, - }, - { - .fourcc = V4L2_PIX_FMT_VUYX32, - .vdownsampling = { 1 }, - .bit_depth = { 32 }, - .planes = 1, - .buffers = 1, - }, - { - .fourcc = V4L2_PIX_FMT_GREY, - .vdownsampling = { 1 }, - .bit_depth = { 8 }, - .color_enc = TGP_COLOR_ENC_LUMA, - .planes = 1, - .buffers = 1, - }, - { - .fourcc = V4L2_PIX_FMT_Y10, - .vdownsampling = { 1 }, - .bit_depth = { 16 }, - .color_enc = TGP_COLOR_ENC_LUMA, - .planes = 1, - .buffers = 1, - }, - { - .fourcc = V4L2_PIX_FMT_Y12, - .vdownsampling = { 1 }, - .bit_depth = { 16 }, - .color_enc = TGP_COLOR_ENC_LUMA, - .planes = 1, - .buffers = 1, - }, - { - .fourcc = V4L2_PIX_FMT_Y16, - .vdownsampling = { 1 }, - .bit_depth = { 16 }, - .color_enc = TGP_COLOR_ENC_LUMA, - .planes = 1, - .buffers = 1, - }, - { - .fourcc = V4L2_PIX_FMT_Y16_BE, - .vdownsampling = { 1 }, - .bit_depth = { 16 }, - .color_enc = TGP_COLOR_ENC_LUMA, - .planes = 1, - .buffers = 1, - }, - { - .fourcc = V4L2_PIX_FMT_RGB332, /* rrrgggbb */ - .vdownsampling = { 1 }, - .bit_depth = { 8 }, - .planes = 1, - .buffers = 1, - }, - { - .fourcc = V4L2_PIX_FMT_RGB565, /* gggbbbbb rrrrrggg */ - .vdownsampling = { 1 }, - .bit_depth = { 16 }, - .planes = 1, - .buffers = 1, - .can_do_overlay = true, - }, - { - .fourcc = V4L2_PIX_FMT_RGB565X, /* rrrrrggg gggbbbbb */ - .vdownsampling = { 1 }, - .bit_depth = { 16 }, - .planes = 1, - .buffers = 1, - .can_do_overlay = true, - }, - { - .fourcc = V4L2_PIX_FMT_RGB444, /* ggggbbbb xxxxrrrr */ - .vdownsampling = { 1 }, - .bit_depth = { 16 }, - .planes = 1, - .buffers = 1, - }, - { - .fourcc = V4L2_PIX_FMT_XRGB444, /* ggggbbbb xxxxrrrr */ - .vdownsampling = { 1 }, - .bit_depth = { 16 }, - .planes = 1, - .buffers = 1, - }, - { - .fourcc = V4L2_PIX_FMT_ARGB444, /* ggggbbbb aaaarrrr */ - .vdownsampling = { 1 }, - .bit_depth = { 16 }, - .planes = 1, - .buffers = 1, - .alpha_mask = 0x00f0, - }, - { - .fourcc = V4L2_PIX_FMT_RGBX444, /* bbbbxxxx rrrrgggg */ - .vdownsampling = { 1 }, - .bit_depth = { 16 }, - .planes = 1, - .buffers = 1, - }, - { - .fourcc = V4L2_PIX_FMT_RGBA444, /* bbbbaaaa rrrrgggg */ - .vdownsampling = { 1 }, - .bit_depth = { 16 }, - .planes = 1, - .buffers = 1, - .alpha_mask = 0x00f0, - }, - { - .fourcc = V4L2_PIX_FMT_XBGR444, /* ggggrrrr xxxxbbbb */ - .vdownsampling = { 1 }, - .bit_depth = { 16 }, - .planes = 1, - .buffers = 1, - }, - { - .fourcc = V4L2_PIX_FMT_ABGR444, /* ggggrrrr aaaabbbb */ - .vdownsampling = { 1 }, - .bit_depth = { 16 }, - .planes = 1, - .buffers = 1, - .alpha_mask = 0x00f0, - }, - { - .fourcc = V4L2_PIX_FMT_BGRX444, /* rrrrxxxx bbbbgggg */ - .vdownsampling = { 1 }, - .bit_depth = { 16 }, - .planes = 1, - .buffers = 1, - }, - { - .fourcc = V4L2_PIX_FMT_BGRA444, /* rrrraaaa bbbbgggg */ - .vdownsampling = { 1 }, - .bit_depth = { 16 }, - .planes = 1, - .buffers = 1, - .alpha_mask = 0x00f0, - }, - { - .fourcc = V4L2_PIX_FMT_RGB555, /* gggbbbbb xrrrrrgg */ - .vdownsampling = { 1 }, - .bit_depth = { 16 }, - .planes = 1, - .buffers = 1, - .can_do_overlay = true, - }, - { - .fourcc = V4L2_PIX_FMT_XRGB555, /* gggbbbbb xrrrrrgg */ - .vdownsampling = { 1 }, - .bit_depth = { 16 }, - .planes = 1, - .buffers = 1, - .can_do_overlay = true, - }, - { - .fourcc = V4L2_PIX_FMT_ARGB555, /* gggbbbbb arrrrrgg */ - .vdownsampling = { 1 }, - .bit_depth = { 16 }, - .planes = 1, - .buffers = 1, - .can_do_overlay = true, - .alpha_mask = 0x8000, - }, - { - .fourcc = V4L2_PIX_FMT_RGBX555, /* ggbbbbbx rrrrrggg */ - .vdownsampling = { 1 }, - .bit_depth = { 16 }, - .planes = 1, - .buffers = 1, - .can_do_overlay = true, - }, - { - .fourcc = V4L2_PIX_FMT_RGBA555, /* ggbbbbba rrrrrggg */ - .vdownsampling = { 1 }, - .bit_depth = { 16 }, - .planes = 1, - .buffers = 1, - .can_do_overlay = true, - .alpha_mask = 0x8000, - }, - { - .fourcc = V4L2_PIX_FMT_XBGR555, /* gggrrrrr xbbbbbgg */ - .vdownsampling = { 1 }, - .bit_depth = { 16 }, - .planes = 1, - .buffers = 1, - .can_do_overlay = true, - }, - { - .fourcc = V4L2_PIX_FMT_ABGR555, /* gggrrrrr abbbbbgg */ - .vdownsampling = { 1 }, - .bit_depth = { 16 }, - .planes = 1, - .buffers = 1, - .can_do_overlay = true, - .alpha_mask = 0x8000, - }, - { - .fourcc = V4L2_PIX_FMT_BGRX555, /* ggrrrrrx bbbbbggg */ - .vdownsampling = { 1 }, - .bit_depth = { 16 }, - .planes = 1, - .buffers = 1, - .can_do_overlay = true, - }, - { - .fourcc = V4L2_PIX_FMT_BGRA555, /* ggrrrrra bbbbbggg */ - .vdownsampling = { 1 }, - .bit_depth = { 16 }, - .planes = 1, - .buffers = 1, - .can_do_overlay = true, - .alpha_mask = 0x8000, - }, - { - .fourcc = V4L2_PIX_FMT_RGB555X, /* xrrrrrgg gggbbbbb */ - .vdownsampling = { 1 }, - .bit_depth = { 16 }, - .planes = 1, - .buffers = 1, - }, - { - .fourcc = V4L2_PIX_FMT_XRGB555X, /* xrrrrrgg gggbbbbb */ - .vdownsampling = { 1 }, - .bit_depth = { 16 }, - .planes = 1, - .buffers = 1, - }, - { - .fourcc = V4L2_PIX_FMT_ARGB555X, /* arrrrrgg gggbbbbb */ - .vdownsampling = { 1 }, - .bit_depth = { 16 }, - .planes = 1, - .buffers = 1, - .alpha_mask = 0x0080, - }, - { - .fourcc = V4L2_PIX_FMT_RGB24, /* rgb */ - .vdownsampling = { 1 }, - .bit_depth = { 24 }, - .planes = 1, - .buffers = 1, - }, - { - .fourcc = V4L2_PIX_FMT_BGR24, /* bgr */ - .vdownsampling = { 1 }, - .bit_depth = { 24 }, - .planes = 1, - .buffers = 1, - }, - { - .fourcc = V4L2_PIX_FMT_BGR666, /* bbbbbbgg ggggrrrr rrxxxxxx */ - .vdownsampling = { 1 }, - .bit_depth = { 32 }, - .planes = 1, - .buffers = 1, - }, - { - .fourcc = V4L2_PIX_FMT_RGB32, /* xrgb */ - .vdownsampling = { 1 }, - .bit_depth = { 32 }, - .planes = 1, - .buffers = 1, - }, - { - .fourcc = V4L2_PIX_FMT_BGR32, /* bgrx */ - .vdownsampling = { 1 }, - .bit_depth = { 32 }, - .planes = 1, - .buffers = 1, - }, - { - .fourcc = V4L2_PIX_FMT_XRGB32, /* xrgb */ - .vdownsampling = { 1 }, - .bit_depth = { 32 }, - .planes = 1, - .buffers = 1, - }, - { - .fourcc = V4L2_PIX_FMT_XBGR32, /* bgrx */ - .vdownsampling = { 1 }, - .bit_depth = { 32 }, - .planes = 1, - .buffers = 1, - }, - { - .fourcc = V4L2_PIX_FMT_ARGB32, /* argb */ - .vdownsampling = { 1 }, - .bit_depth = { 32 }, - .planes = 1, - .buffers = 1, - .alpha_mask = 0x000000ff, - }, - { - .fourcc = V4L2_PIX_FMT_ABGR32, /* bgra */ - .vdownsampling = { 1 }, - .bit_depth = { 32 }, - .planes = 1, - .buffers = 1, - .alpha_mask = 0xff000000, - }, - { - .fourcc = V4L2_PIX_FMT_RGBX32, /* rgbx */ - .vdownsampling = { 1 }, - .bit_depth = { 32 }, - .planes = 1, - .buffers = 1, - }, - { - .fourcc = V4L2_PIX_FMT_BGRX32, /* xbgr */ - .vdownsampling = { 1 }, - .bit_depth = { 32 }, - .planes = 1, - .buffers = 1, - }, - { - .fourcc = V4L2_PIX_FMT_RGBA32, /* rgba */ - .vdownsampling = { 1 }, - .bit_depth = { 32 }, - .planes = 1, - .buffers = 1, - .alpha_mask = 0x000000ff, - }, - { - .fourcc = V4L2_PIX_FMT_BGRA32, /* abgr */ - .vdownsampling = { 1 }, - .bit_depth = { 32 }, - .planes = 1, - .buffers = 1, - .alpha_mask = 0xff000000, - }, - { - .fourcc = V4L2_PIX_FMT_SBGGR8, /* Bayer BG/GR */ - .vdownsampling = { 1 }, - .bit_depth = { 8 }, - .planes = 1, - .buffers = 1, - }, - { - .fourcc = V4L2_PIX_FMT_SGBRG8, /* Bayer GB/RG */ - .vdownsampling = { 1 }, - .bit_depth = { 8 }, - .planes = 1, - .buffers = 1, - }, - { - .fourcc = V4L2_PIX_FMT_SGRBG8, /* Bayer GR/BG */ - .vdownsampling = { 1 }, - .bit_depth = { 8 }, - .planes = 1, - .buffers = 1, - }, - { - .fourcc = V4L2_PIX_FMT_SRGGB8, /* Bayer RG/GB */ - .vdownsampling = { 1 }, - .bit_depth = { 8 }, - .planes = 1, - .buffers = 1, - }, - { - .fourcc = V4L2_PIX_FMT_SBGGR10, /* Bayer BG/GR */ - .vdownsampling = { 1 }, - .bit_depth = { 16 }, - .planes = 1, - .buffers = 1, - }, - { - .fourcc = V4L2_PIX_FMT_SGBRG10, /* Bayer GB/RG */ - .vdownsampling = { 1 }, - .bit_depth = { 16 }, - .planes = 1, - .buffers = 1, - }, - { - .fourcc = V4L2_PIX_FMT_SGRBG10, /* Bayer GR/BG */ - .vdownsampling = { 1 }, - .bit_depth = { 16 }, - .planes = 1, - .buffers = 1, - }, - { - .fourcc = V4L2_PIX_FMT_SRGGB10, /* Bayer RG/GB */ - .vdownsampling = { 1 }, - .bit_depth = { 16 }, - .planes = 1, - .buffers = 1, - }, - { - .fourcc = V4L2_PIX_FMT_SBGGR12, /* Bayer BG/GR */ - .vdownsampling = { 1 }, - .bit_depth = { 16 }, - .planes = 1, - .buffers = 1, - }, - { - .fourcc = V4L2_PIX_FMT_SGBRG12, /* Bayer GB/RG */ - .vdownsampling = { 1 }, - .bit_depth = { 16 }, - .planes = 1, - .buffers = 1, - }, - { - .fourcc = V4L2_PIX_FMT_SGRBG12, /* Bayer GR/BG */ - .vdownsampling = { 1 }, - .bit_depth = { 16 }, - .planes = 1, - .buffers = 1, - }, - { - .fourcc = V4L2_PIX_FMT_SRGGB12, /* Bayer RG/GB */ - .vdownsampling = { 1 }, - .bit_depth = { 16 }, - .planes = 1, - .buffers = 1, - }, - { - .fourcc = V4L2_PIX_FMT_SBGGR16, /* Bayer BG/GR */ - .vdownsampling = { 1 }, - .bit_depth = { 16 }, - .planes = 1, - .buffers = 1, - }, - { - .fourcc = V4L2_PIX_FMT_SGBRG16, /* Bayer GB/RG */ - .vdownsampling = { 1 }, - .bit_depth = { 16 }, - .planes = 1, - .buffers = 1, - }, - { - .fourcc = V4L2_PIX_FMT_SGRBG16, /* Bayer GR/BG */ - .vdownsampling = { 1 }, - .bit_depth = { 16 }, - .planes = 1, - .buffers = 1, - }, - { - .fourcc = V4L2_PIX_FMT_SRGGB16, /* Bayer RG/GB */ - .vdownsampling = { 1 }, - .bit_depth = { 16 }, - .planes = 1, - .buffers = 1, - }, - { - .fourcc = V4L2_PIX_FMT_HSV24, /* HSV 24bits */ - .color_enc = TGP_COLOR_ENC_HSV, - .vdownsampling = { 1 }, - .bit_depth = { 24 }, - .planes = 1, - .buffers = 1, - }, - { - .fourcc = V4L2_PIX_FMT_HSV32, /* HSV 32bits */ - .color_enc = TGP_COLOR_ENC_HSV, - .vdownsampling = { 1 }, - .bit_depth = { 32 }, - .planes = 1, - .buffers = 1, - }, - - /* Multiplanar formats */ - - { - .fourcc = V4L2_PIX_FMT_NV16M, - .vdownsampling = { 1, 1 }, - .bit_depth = { 8, 8 }, - .color_enc = TGP_COLOR_ENC_YCBCR, - .planes = 2, - .buffers = 2, - .data_offset = { PLANE0_DATA_OFFSET, 0 }, - }, - { - .fourcc = V4L2_PIX_FMT_NV61M, - .vdownsampling = { 1, 1 }, - .bit_depth = { 8, 8 }, - .color_enc = TGP_COLOR_ENC_YCBCR, - .planes = 2, - .buffers = 2, - .data_offset = { 0, PLANE0_DATA_OFFSET }, - }, - { - .fourcc = V4L2_PIX_FMT_YUV420M, - .vdownsampling = { 1, 2, 2 }, - .bit_depth = { 8, 4, 4 }, - .color_enc = TGP_COLOR_ENC_YCBCR, - .planes = 3, - .buffers = 3, - }, - { - .fourcc = V4L2_PIX_FMT_YVU420M, - .vdownsampling = { 1, 2, 2 }, - .bit_depth = { 8, 4, 4 }, - .color_enc = TGP_COLOR_ENC_YCBCR, - .planes = 3, - .buffers = 3, - }, - { - .fourcc = V4L2_PIX_FMT_NV12M, - .vdownsampling = { 1, 2 }, - .bit_depth = { 8, 8 }, - .color_enc = TGP_COLOR_ENC_YCBCR, - .planes = 2, - .buffers = 2, - }, - { - .fourcc = V4L2_PIX_FMT_NV21M, - .vdownsampling = { 1, 2 }, - .bit_depth = { 8, 8 }, - .color_enc = TGP_COLOR_ENC_YCBCR, - .planes = 2, - .buffers = 2, - }, - { - .fourcc = V4L2_PIX_FMT_YUV422M, - .vdownsampling = { 1, 1, 1 }, - .bit_depth = { 8, 4, 4 }, - .color_enc = TGP_COLOR_ENC_YCBCR, - .planes = 3, - .buffers = 3, - }, - { - .fourcc = V4L2_PIX_FMT_YVU422M, - .vdownsampling = { 1, 1, 1 }, - .bit_depth = { 8, 4, 4 }, - .color_enc = TGP_COLOR_ENC_YCBCR, - .planes = 3, - .buffers = 3, - }, - { - .fourcc = V4L2_PIX_FMT_YUV444M, - .vdownsampling = { 1, 1, 1 }, - .bit_depth = { 8, 8, 8 }, - .color_enc = TGP_COLOR_ENC_YCBCR, - .planes = 3, - .buffers = 3, - }, - { - .fourcc = V4L2_PIX_FMT_YVU444M, - .vdownsampling = { 1, 1, 1 }, - .bit_depth = { 8, 8, 8 }, - .color_enc = TGP_COLOR_ENC_YCBCR, - .planes = 3, - .buffers = 3, - }, -}; - -/* There are this many multiplanar formats in the list */ -#define VIVID_MPLANAR_FORMATS 10 - -const struct vivid_fmt *vivid_get_format(struct vivid_dev *dev, u32 pixelformat) -{ - const struct vivid_fmt *fmt; - unsigned k; - - for (k = 0; k < ARRAY_SIZE(vivid_formats); k++) { - fmt = &vivid_formats[k]; - if (fmt->fourcc == pixelformat) - if (fmt->buffers == 1 || dev->multiplanar) - return fmt; - } - - return NULL; -} - -bool vivid_vid_can_loop(struct vivid_dev *dev) -{ - if (dev->src_rect.width != dev->sink_rect.width || - dev->src_rect.height != dev->sink_rect.height) - return false; - if (dev->fmt_cap->fourcc != dev->fmt_out->fourcc) - return false; - if (dev->field_cap != dev->field_out) - return false; - /* - * While this can be supported, it is just too much work - * to actually implement. - */ - if (dev->field_cap == V4L2_FIELD_SEQ_TB || - dev->field_cap == V4L2_FIELD_SEQ_BT) - return false; - if (vivid_is_svid_cap(dev) && vivid_is_svid_out(dev)) { - if (!(dev->std_cap[dev->input] & V4L2_STD_525_60) != - !(dev->std_out & V4L2_STD_525_60)) - return false; - return true; - } - if (vivid_is_hdmi_cap(dev) && vivid_is_hdmi_out(dev)) - return true; - return false; -} - -void vivid_send_source_change(struct vivid_dev *dev, unsigned type) -{ - struct v4l2_event ev = { - .type = V4L2_EVENT_SOURCE_CHANGE, - .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION, - }; - unsigned i; - - for (i = 0; i < dev->num_inputs; i++) { - ev.id = i; - if (dev->input_type[i] == type) { - if (video_is_registered(&dev->vid_cap_dev) && dev->has_vid_cap) - v4l2_event_queue(&dev->vid_cap_dev, &ev); - if (video_is_registered(&dev->vbi_cap_dev) && dev->has_vbi_cap) - v4l2_event_queue(&dev->vbi_cap_dev, &ev); - } - } -} - -/* - * Conversion function that converts a single-planar format to a - * single-plane multiplanar format. - */ -void fmt_sp2mp(const struct v4l2_format *sp_fmt, struct v4l2_format *mp_fmt) -{ - struct v4l2_pix_format_mplane *mp = &mp_fmt->fmt.pix_mp; - struct v4l2_plane_pix_format *ppix = &mp->plane_fmt[0]; - const struct v4l2_pix_format *pix = &sp_fmt->fmt.pix; - bool is_out = sp_fmt->type == V4L2_BUF_TYPE_VIDEO_OUTPUT; - - memset(mp->reserved, 0, sizeof(mp->reserved)); - mp_fmt->type = is_out ? V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE : - V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; - mp->width = pix->width; - mp->height = pix->height; - mp->pixelformat = pix->pixelformat; - mp->field = pix->field; - mp->colorspace = pix->colorspace; - mp->xfer_func = pix->xfer_func; - /* Also copies hsv_enc */ - mp->ycbcr_enc = pix->ycbcr_enc; - mp->quantization = pix->quantization; - mp->num_planes = 1; - mp->flags = pix->flags; - ppix->sizeimage = pix->sizeimage; - ppix->bytesperline = pix->bytesperline; - memset(ppix->reserved, 0, sizeof(ppix->reserved)); -} - -int fmt_sp2mp_func(struct file *file, void *priv, - struct v4l2_format *f, fmtfunc func) -{ - struct v4l2_format fmt; - struct v4l2_pix_format_mplane *mp = &fmt.fmt.pix_mp; - struct v4l2_plane_pix_format *ppix = &mp->plane_fmt[0]; - struct v4l2_pix_format *pix = &f->fmt.pix; - int ret; - - /* Converts to a mplane format */ - fmt_sp2mp(f, &fmt); - /* Passes it to the generic mplane format function */ - ret = func(file, priv, &fmt); - /* Copies back the mplane data to the single plane format */ - pix->width = mp->width; - pix->height = mp->height; - pix->pixelformat = mp->pixelformat; - pix->field = mp->field; - pix->colorspace = mp->colorspace; - pix->xfer_func = mp->xfer_func; - /* Also copies hsv_enc */ - pix->ycbcr_enc = mp->ycbcr_enc; - pix->quantization = mp->quantization; - pix->sizeimage = ppix->sizeimage; - pix->bytesperline = ppix->bytesperline; - pix->flags = mp->flags; - return ret; -} - -int vivid_vid_adjust_sel(unsigned flags, struct v4l2_rect *r) -{ - unsigned w = r->width; - unsigned h = r->height; - - /* sanitize w and h in case someone passes ~0 as the value */ - w &= 0xffff; - h &= 0xffff; - if (!(flags & V4L2_SEL_FLAG_LE)) { - w++; - h++; - if (w < 2) - w = 2; - if (h < 2) - h = 2; - } - if (!(flags & V4L2_SEL_FLAG_GE)) { - if (w > MAX_WIDTH) - w = MAX_WIDTH; - if (h > MAX_HEIGHT) - h = MAX_HEIGHT; - } - w = w & ~1; - h = h & ~1; - if (w < 2 || h < 2) - return -ERANGE; - if (w > MAX_WIDTH || h > MAX_HEIGHT) - return -ERANGE; - if (r->top < 0) - r->top = 0; - if (r->left < 0) - r->left = 0; - /* sanitize left and top in case someone passes ~0 as the value */ - r->left &= 0xfffe; - r->top &= 0xfffe; - if (r->left + w > MAX_WIDTH) - r->left = MAX_WIDTH - w; - if (r->top + h > MAX_HEIGHT) - r->top = MAX_HEIGHT - h; - if ((flags & (V4L2_SEL_FLAG_GE | V4L2_SEL_FLAG_LE)) == - (V4L2_SEL_FLAG_GE | V4L2_SEL_FLAG_LE) && - (r->width != w || r->height != h)) - return -ERANGE; - r->width = w; - r->height = h; - return 0; -} - -int vivid_enum_fmt_vid(struct file *file, void *priv, - struct v4l2_fmtdesc *f) -{ - struct vivid_dev *dev = video_drvdata(file); - const struct vivid_fmt *fmt; - - if (f->index >= ARRAY_SIZE(vivid_formats) - - (dev->multiplanar ? 0 : VIVID_MPLANAR_FORMATS)) - return -EINVAL; - - fmt = &vivid_formats[f->index]; - - f->pixelformat = fmt->fourcc; - return 0; -} - -int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id) -{ - struct vivid_dev *dev = video_drvdata(file); - struct video_device *vdev = video_devdata(file); - - if (vdev->vfl_dir == VFL_DIR_RX) { - if (!vivid_is_sdtv_cap(dev)) - return -ENODATA; - *id = dev->std_cap[dev->input]; - } else { - if (!vivid_is_svid_out(dev)) - return -ENODATA; - *id = dev->std_out; - } - return 0; -} - -int vidioc_g_dv_timings(struct file *file, void *_fh, - struct v4l2_dv_timings *timings) -{ - struct vivid_dev *dev = video_drvdata(file); - struct video_device *vdev = video_devdata(file); - - if (vdev->vfl_dir == VFL_DIR_RX) { - if (!vivid_is_hdmi_cap(dev)) - return -ENODATA; - *timings = dev->dv_timings_cap[dev->input]; - } else { - if (!vivid_is_hdmi_out(dev)) - return -ENODATA; - *timings = dev->dv_timings_out; - } - return 0; -} - -int vidioc_enum_dv_timings(struct file *file, void *_fh, - struct v4l2_enum_dv_timings *timings) -{ - struct vivid_dev *dev = video_drvdata(file); - struct video_device *vdev = video_devdata(file); - - if (vdev->vfl_dir == VFL_DIR_RX) { - if (!vivid_is_hdmi_cap(dev)) - return -ENODATA; - } else { - if (!vivid_is_hdmi_out(dev)) - return -ENODATA; - } - return v4l2_enum_dv_timings_cap(timings, &vivid_dv_timings_cap, - NULL, NULL); -} - -int vidioc_dv_timings_cap(struct file *file, void *_fh, - struct v4l2_dv_timings_cap *cap) -{ - struct vivid_dev *dev = video_drvdata(file); - struct video_device *vdev = video_devdata(file); - - if (vdev->vfl_dir == VFL_DIR_RX) { - if (!vivid_is_hdmi_cap(dev)) - return -ENODATA; - } else { - if (!vivid_is_hdmi_out(dev)) - return -ENODATA; - } - *cap = vivid_dv_timings_cap; - return 0; -} - -int vidioc_g_edid(struct file *file, void *_fh, - struct v4l2_edid *edid) -{ - struct vivid_dev *dev = video_drvdata(file); - struct video_device *vdev = video_devdata(file); - struct cec_adapter *adap; - - memset(edid->reserved, 0, sizeof(edid->reserved)); - if (vdev->vfl_dir == VFL_DIR_RX) { - if (edid->pad >= dev->num_inputs) - return -EINVAL; - if (dev->input_type[edid->pad] != HDMI) - return -EINVAL; - adap = dev->cec_rx_adap; - } else { - unsigned int bus_idx; - - if (edid->pad >= dev->num_outputs) - return -EINVAL; - if (dev->output_type[edid->pad] != HDMI) - return -EINVAL; - if (!dev->display_present[edid->pad]) - return -ENODATA; - bus_idx = dev->cec_output2bus_map[edid->pad]; - adap = dev->cec_tx_adap[bus_idx]; - } - if (edid->start_block == 0 && edid->blocks == 0) { - edid->blocks = dev->edid_blocks; - return 0; - } - if (dev->edid_blocks == 0) - return -ENODATA; - if (edid->start_block >= dev->edid_blocks) - return -EINVAL; - if (edid->blocks > dev->edid_blocks - edid->start_block) - edid->blocks = dev->edid_blocks - edid->start_block; - if (adap) - v4l2_set_edid_phys_addr(dev->edid, dev->edid_blocks * 128, adap->phys_addr); - memcpy(edid->edid, dev->edid + edid->start_block * 128, edid->blocks * 128); - return 0; -} diff --git a/drivers/media/platform/vivid/vivid-vid-common.h b/drivers/media/platform/vivid/vivid-vid-common.h deleted file mode 100644 index d908d9725283..000000000000 --- a/drivers/media/platform/vivid/vivid-vid-common.h +++ /dev/null @@ -1,38 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * vivid-vid-common.h - common video support functions. - * - * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - */ - -#ifndef _VIVID_VID_COMMON_H_ -#define _VIVID_VID_COMMON_H_ - -typedef int (*fmtfunc)(struct file *file, void *priv, struct v4l2_format *f); - -/* - * Conversion function that converts a single-planar format to a - * single-plane multiplanar format. - */ -void fmt_sp2mp(const struct v4l2_format *sp_fmt, struct v4l2_format *mp_fmt); -int fmt_sp2mp_func(struct file *file, void *priv, - struct v4l2_format *f, fmtfunc func); - -extern const struct v4l2_dv_timings_cap vivid_dv_timings_cap; - -const struct vivid_fmt *vivid_get_format(struct vivid_dev *dev, u32 pixelformat); - -bool vivid_vid_can_loop(struct vivid_dev *dev); -void vivid_send_source_change(struct vivid_dev *dev, unsigned type); - -int vivid_vid_adjust_sel(unsigned flags, struct v4l2_rect *r); - -int vivid_enum_fmt_vid(struct file *file, void *priv, struct v4l2_fmtdesc *f); -int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id); -int vidioc_g_dv_timings(struct file *file, void *_fh, struct v4l2_dv_timings *timings); -int vidioc_enum_dv_timings(struct file *file, void *_fh, struct v4l2_enum_dv_timings *timings); -int vidioc_dv_timings_cap(struct file *file, void *_fh, struct v4l2_dv_timings_cap *cap); -int vidioc_g_edid(struct file *file, void *_fh, struct v4l2_edid *edid); -int vidioc_subscribe_event(struct v4l2_fh *fh, const struct v4l2_event_subscription *sub); - -#endif diff --git a/drivers/media/platform/vivid/vivid-vid-out.c b/drivers/media/platform/vivid/vivid-vid-out.c deleted file mode 100644 index ee3446e3217c..000000000000 --- a/drivers/media/platform/vivid/vivid-vid-out.c +++ /dev/null @@ -1,1210 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-only -/* - * vivid-vid-out.c - video output support functions. - * - * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "vivid-core.h" -#include "vivid-vid-common.h" -#include "vivid-kthread-out.h" -#include "vivid-vid-out.h" - -static int vid_out_queue_setup(struct vb2_queue *vq, - unsigned *nbuffers, unsigned *nplanes, - unsigned sizes[], struct device *alloc_devs[]) -{ - struct vivid_dev *dev = vb2_get_drv_priv(vq); - const struct vivid_fmt *vfmt = dev->fmt_out; - unsigned planes = vfmt->buffers; - unsigned h = dev->fmt_out_rect.height; - unsigned int size = dev->bytesperline_out[0] * h + vfmt->data_offset[0]; - unsigned p; - - for (p = vfmt->buffers; p < vfmt->planes; p++) - size += dev->bytesperline_out[p] * h / vfmt->vdownsampling[p] + - vfmt->data_offset[p]; - - if (dev->field_out == V4L2_FIELD_ALTERNATE) { - /* - * You cannot use write() with FIELD_ALTERNATE since the field - * information (TOP/BOTTOM) cannot be passed to the kernel. - */ - if (vb2_fileio_is_active(vq)) - return -EINVAL; - } - - if (dev->queue_setup_error) { - /* - * Error injection: test what happens if queue_setup() returns - * an error. - */ - dev->queue_setup_error = false; - return -EINVAL; - } - - if (*nplanes) { - /* - * Check if the number of requested planes match - * the number of planes in the current format. You can't mix that. - */ - if (*nplanes != planes) - return -EINVAL; - if (sizes[0] < size) - return -EINVAL; - for (p = 1; p < planes; p++) { - if (sizes[p] < dev->bytesperline_out[p] * h + - vfmt->data_offset[p]) - return -EINVAL; - } - } else { - for (p = 0; p < planes; p++) - sizes[p] = p ? dev->bytesperline_out[p] * h + - vfmt->data_offset[p] : size; - } - - if (vq->num_buffers + *nbuffers < 2) - *nbuffers = 2 - vq->num_buffers; - - *nplanes = planes; - - dprintk(dev, 1, "%s: count=%d\n", __func__, *nbuffers); - for (p = 0; p < planes; p++) - dprintk(dev, 1, "%s: size[%u]=%u\n", __func__, p, sizes[p]); - return 0; -} - -static int vid_out_buf_out_validate(struct vb2_buffer *vb) -{ - struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); - struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); - - dprintk(dev, 1, "%s\n", __func__); - - if (dev->field_out != V4L2_FIELD_ALTERNATE) - vbuf->field = dev->field_out; - else if (vbuf->field != V4L2_FIELD_TOP && - vbuf->field != V4L2_FIELD_BOTTOM) - return -EINVAL; - return 0; -} - -static int vid_out_buf_prepare(struct vb2_buffer *vb) -{ - struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); - const struct vivid_fmt *vfmt = dev->fmt_out; - unsigned int planes = vfmt->buffers; - unsigned int h = dev->fmt_out_rect.height; - unsigned int size = dev->bytesperline_out[0] * h; - unsigned p; - - for (p = vfmt->buffers; p < vfmt->planes; p++) - size += dev->bytesperline_out[p] * h / vfmt->vdownsampling[p]; - - dprintk(dev, 1, "%s\n", __func__); - - if (WARN_ON(NULL == dev->fmt_out)) - return -EINVAL; - - if (dev->buf_prepare_error) { - /* - * Error injection: test what happens if buf_prepare() returns - * an error. - */ - dev->buf_prepare_error = false; - return -EINVAL; - } - - for (p = 0; p < planes; p++) { - if (p) - size = dev->bytesperline_out[p] * h; - size += vb->planes[p].data_offset; - - if (vb2_get_plane_payload(vb, p) < size) { - dprintk(dev, 1, "%s the payload is too small for plane %u (%lu < %u)\n", - __func__, p, vb2_get_plane_payload(vb, p), size); - return -EINVAL; - } - } - - return 0; -} - -static void vid_out_buf_queue(struct vb2_buffer *vb) -{ - struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); - struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); - struct vivid_buffer *buf = container_of(vbuf, struct vivid_buffer, vb); - - dprintk(dev, 1, "%s\n", __func__); - - spin_lock(&dev->slock); - list_add_tail(&buf->list, &dev->vid_out_active); - spin_unlock(&dev->slock); -} - -static int vid_out_start_streaming(struct vb2_queue *vq, unsigned count) -{ - struct vivid_dev *dev = vb2_get_drv_priv(vq); - int err; - - if (vb2_is_streaming(&dev->vb_vid_cap_q)) - dev->can_loop_video = vivid_vid_can_loop(dev); - - dev->vid_out_seq_count = 0; - dprintk(dev, 1, "%s\n", __func__); - if (dev->start_streaming_error) { - dev->start_streaming_error = false; - err = -EINVAL; - } else { - err = vivid_start_generating_vid_out(dev, &dev->vid_out_streaming); - } - if (err) { - struct vivid_buffer *buf, *tmp; - - list_for_each_entry_safe(buf, tmp, &dev->vid_out_active, list) { - list_del(&buf->list); - vb2_buffer_done(&buf->vb.vb2_buf, - VB2_BUF_STATE_QUEUED); - } - } - return err; -} - -/* abort streaming and wait for last buffer */ -static void vid_out_stop_streaming(struct vb2_queue *vq) -{ - struct vivid_dev *dev = vb2_get_drv_priv(vq); - - dprintk(dev, 1, "%s\n", __func__); - vivid_stop_generating_vid_out(dev, &dev->vid_out_streaming); - dev->can_loop_video = false; -} - -static void vid_out_buf_request_complete(struct vb2_buffer *vb) -{ - struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); - - v4l2_ctrl_request_complete(vb->req_obj.req, &dev->ctrl_hdl_vid_out); -} - -const struct vb2_ops vivid_vid_out_qops = { - .queue_setup = vid_out_queue_setup, - .buf_out_validate = vid_out_buf_out_validate, - .buf_prepare = vid_out_buf_prepare, - .buf_queue = vid_out_buf_queue, - .start_streaming = vid_out_start_streaming, - .stop_streaming = vid_out_stop_streaming, - .buf_request_complete = vid_out_buf_request_complete, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, -}; - -/* - * Called whenever the format has to be reset which can occur when - * changing outputs, standard, timings, etc. - */ -void vivid_update_format_out(struct vivid_dev *dev) -{ - struct v4l2_bt_timings *bt = &dev->dv_timings_out.bt; - unsigned size, p; - u64 pixelclock; - - switch (dev->output_type[dev->output]) { - case SVID: - default: - dev->field_out = dev->tv_field_out; - dev->sink_rect.width = 720; - if (dev->std_out & V4L2_STD_525_60) { - dev->sink_rect.height = 480; - dev->timeperframe_vid_out = (struct v4l2_fract) { 1001, 30000 }; - dev->service_set_out = V4L2_SLICED_CAPTION_525; - } else { - dev->sink_rect.height = 576; - dev->timeperframe_vid_out = (struct v4l2_fract) { 1000, 25000 }; - dev->service_set_out = V4L2_SLICED_WSS_625 | V4L2_SLICED_TELETEXT_B; - } - dev->colorspace_out = V4L2_COLORSPACE_SMPTE170M; - break; - case HDMI: - dev->sink_rect.width = bt->width; - dev->sink_rect.height = bt->height; - size = V4L2_DV_BT_FRAME_WIDTH(bt) * V4L2_DV_BT_FRAME_HEIGHT(bt); - - if (can_reduce_fps(bt) && (bt->flags & V4L2_DV_FL_REDUCED_FPS)) - pixelclock = div_u64(bt->pixelclock * 1000, 1001); - else - pixelclock = bt->pixelclock; - - dev->timeperframe_vid_out = (struct v4l2_fract) { - size / 100, (u32)pixelclock / 100 - }; - if (bt->interlaced) - dev->field_out = V4L2_FIELD_ALTERNATE; - else - dev->field_out = V4L2_FIELD_NONE; - if (!dev->dvi_d_out && (bt->flags & V4L2_DV_FL_IS_CE_VIDEO)) { - if (bt->width == 720 && bt->height <= 576) - dev->colorspace_out = V4L2_COLORSPACE_SMPTE170M; - else - dev->colorspace_out = V4L2_COLORSPACE_REC709; - } else { - dev->colorspace_out = V4L2_COLORSPACE_SRGB; - } - break; - } - dev->xfer_func_out = V4L2_XFER_FUNC_DEFAULT; - dev->ycbcr_enc_out = V4L2_YCBCR_ENC_DEFAULT; - dev->hsv_enc_out = V4L2_HSV_ENC_180; - dev->quantization_out = V4L2_QUANTIZATION_DEFAULT; - dev->compose_out = dev->sink_rect; - dev->compose_bounds_out = dev->sink_rect; - dev->crop_out = dev->compose_out; - if (V4L2_FIELD_HAS_T_OR_B(dev->field_out)) - dev->crop_out.height /= 2; - dev->fmt_out_rect = dev->crop_out; - for (p = 0; p < dev->fmt_out->planes; p++) - dev->bytesperline_out[p] = - (dev->sink_rect.width * dev->fmt_out->bit_depth[p]) / 8; -} - -/* Map the field to something that is valid for the current output */ -static enum v4l2_field vivid_field_out(struct vivid_dev *dev, enum v4l2_field field) -{ - if (vivid_is_svid_out(dev)) { - switch (field) { - case V4L2_FIELD_INTERLACED_TB: - case V4L2_FIELD_INTERLACED_BT: - case V4L2_FIELD_SEQ_TB: - case V4L2_FIELD_SEQ_BT: - case V4L2_FIELD_ALTERNATE: - return field; - case V4L2_FIELD_INTERLACED: - default: - return V4L2_FIELD_INTERLACED; - } - } - if (vivid_is_hdmi_out(dev)) - return dev->dv_timings_out.bt.interlaced ? V4L2_FIELD_ALTERNATE : - V4L2_FIELD_NONE; - return V4L2_FIELD_NONE; -} - -static enum tpg_pixel_aspect vivid_get_pixel_aspect(const struct vivid_dev *dev) -{ - if (vivid_is_svid_out(dev)) - return (dev->std_out & V4L2_STD_525_60) ? - TPG_PIXEL_ASPECT_NTSC : TPG_PIXEL_ASPECT_PAL; - - if (vivid_is_hdmi_out(dev) && - dev->sink_rect.width == 720 && dev->sink_rect.height <= 576) - return dev->sink_rect.height == 480 ? - TPG_PIXEL_ASPECT_NTSC : TPG_PIXEL_ASPECT_PAL; - - return TPG_PIXEL_ASPECT_SQUARE; -} - -int vivid_g_fmt_vid_out(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct vivid_dev *dev = video_drvdata(file); - struct v4l2_pix_format_mplane *mp = &f->fmt.pix_mp; - const struct vivid_fmt *fmt = dev->fmt_out; - unsigned p; - - mp->width = dev->fmt_out_rect.width; - mp->height = dev->fmt_out_rect.height; - mp->field = dev->field_out; - mp->pixelformat = fmt->fourcc; - mp->colorspace = dev->colorspace_out; - mp->xfer_func = dev->xfer_func_out; - mp->ycbcr_enc = dev->ycbcr_enc_out; - mp->quantization = dev->quantization_out; - mp->num_planes = fmt->buffers; - for (p = 0; p < mp->num_planes; p++) { - mp->plane_fmt[p].bytesperline = dev->bytesperline_out[p]; - mp->plane_fmt[p].sizeimage = - mp->plane_fmt[p].bytesperline * mp->height + - fmt->data_offset[p]; - } - for (p = fmt->buffers; p < fmt->planes; p++) { - unsigned stride = dev->bytesperline_out[p]; - - mp->plane_fmt[0].sizeimage += - (stride * mp->height) / fmt->vdownsampling[p]; - } - return 0; -} - -int vivid_try_fmt_vid_out(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct vivid_dev *dev = video_drvdata(file); - struct v4l2_bt_timings *bt = &dev->dv_timings_out.bt; - struct v4l2_pix_format_mplane *mp = &f->fmt.pix_mp; - struct v4l2_plane_pix_format *pfmt = mp->plane_fmt; - const struct vivid_fmt *fmt; - unsigned bytesperline, max_bpl; - unsigned factor = 1; - unsigned w, h; - unsigned p; - - fmt = vivid_get_format(dev, mp->pixelformat); - if (!fmt) { - dprintk(dev, 1, "Fourcc format (0x%08x) unknown.\n", - mp->pixelformat); - mp->pixelformat = V4L2_PIX_FMT_YUYV; - fmt = vivid_get_format(dev, mp->pixelformat); - } - - mp->field = vivid_field_out(dev, mp->field); - if (vivid_is_svid_out(dev)) { - w = 720; - h = (dev->std_out & V4L2_STD_525_60) ? 480 : 576; - } else { - w = dev->sink_rect.width; - h = dev->sink_rect.height; - } - if (V4L2_FIELD_HAS_T_OR_B(mp->field)) - factor = 2; - if (!dev->has_scaler_out && !dev->has_crop_out && !dev->has_compose_out) { - mp->width = w; - mp->height = h / factor; - } else { - struct v4l2_rect r = { 0, 0, mp->width, mp->height * factor }; - - v4l2_rect_set_min_size(&r, &vivid_min_rect); - v4l2_rect_set_max_size(&r, &vivid_max_rect); - if (dev->has_scaler_out && !dev->has_crop_out) { - struct v4l2_rect max_r = { 0, 0, MAX_ZOOM * w, MAX_ZOOM * h }; - - v4l2_rect_set_max_size(&r, &max_r); - } else if (!dev->has_scaler_out && dev->has_compose_out && !dev->has_crop_out) { - v4l2_rect_set_max_size(&r, &dev->sink_rect); - } else if (!dev->has_scaler_out && !dev->has_compose_out) { - v4l2_rect_set_min_size(&r, &dev->sink_rect); - } - mp->width = r.width; - mp->height = r.height / factor; - } - - /* This driver supports custom bytesperline values */ - - mp->num_planes = fmt->buffers; - for (p = 0; p < fmt->buffers; p++) { - /* Calculate the minimum supported bytesperline value */ - bytesperline = (mp->width * fmt->bit_depth[p]) >> 3; - /* Calculate the maximum supported bytesperline value */ - max_bpl = (MAX_ZOOM * MAX_WIDTH * fmt->bit_depth[p]) >> 3; - - if (pfmt[p].bytesperline > max_bpl) - pfmt[p].bytesperline = max_bpl; - if (pfmt[p].bytesperline < bytesperline) - pfmt[p].bytesperline = bytesperline; - - pfmt[p].sizeimage = (pfmt[p].bytesperline * mp->height) / - fmt->vdownsampling[p] + fmt->data_offset[p]; - - memset(pfmt[p].reserved, 0, sizeof(pfmt[p].reserved)); - } - for (p = fmt->buffers; p < fmt->planes; p++) - pfmt[0].sizeimage += (pfmt[0].bytesperline * mp->height * - (fmt->bit_depth[p] / fmt->vdownsampling[p])) / - (fmt->bit_depth[0] / fmt->vdownsampling[0]); - - mp->xfer_func = V4L2_XFER_FUNC_DEFAULT; - mp->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; - mp->quantization = V4L2_QUANTIZATION_DEFAULT; - if (vivid_is_svid_out(dev)) { - mp->colorspace = V4L2_COLORSPACE_SMPTE170M; - } else if (dev->dvi_d_out || !(bt->flags & V4L2_DV_FL_IS_CE_VIDEO)) { - mp->colorspace = V4L2_COLORSPACE_SRGB; - if (dev->dvi_d_out) - mp->quantization = V4L2_QUANTIZATION_LIM_RANGE; - } else if (bt->width == 720 && bt->height <= 576) { - mp->colorspace = V4L2_COLORSPACE_SMPTE170M; - } else if (mp->colorspace != V4L2_COLORSPACE_SMPTE170M && - mp->colorspace != V4L2_COLORSPACE_REC709 && - mp->colorspace != V4L2_COLORSPACE_OPRGB && - mp->colorspace != V4L2_COLORSPACE_BT2020 && - mp->colorspace != V4L2_COLORSPACE_SRGB) { - mp->colorspace = V4L2_COLORSPACE_REC709; - } - memset(mp->reserved, 0, sizeof(mp->reserved)); - return 0; -} - -int vivid_s_fmt_vid_out(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct v4l2_pix_format_mplane *mp = &f->fmt.pix_mp; - struct vivid_dev *dev = video_drvdata(file); - struct v4l2_rect *crop = &dev->crop_out; - struct v4l2_rect *compose = &dev->compose_out; - struct vb2_queue *q = &dev->vb_vid_out_q; - int ret = vivid_try_fmt_vid_out(file, priv, f); - unsigned factor = 1; - unsigned p; - - if (ret < 0) - return ret; - - if (vb2_is_busy(q) && - (vivid_is_svid_out(dev) || - mp->width != dev->fmt_out_rect.width || - mp->height != dev->fmt_out_rect.height || - mp->pixelformat != dev->fmt_out->fourcc || - mp->field != dev->field_out)) { - dprintk(dev, 1, "%s device busy\n", __func__); - return -EBUSY; - } - - /* - * Allow for changing the colorspace on the fly. Useful for testing - * purposes, and it is something that HDMI transmitters are able - * to do. - */ - if (vb2_is_busy(q)) - goto set_colorspace; - - dev->fmt_out = vivid_get_format(dev, mp->pixelformat); - if (V4L2_FIELD_HAS_T_OR_B(mp->field)) - factor = 2; - - if (dev->has_scaler_out || dev->has_crop_out || dev->has_compose_out) { - struct v4l2_rect r = { 0, 0, mp->width, mp->height }; - - if (dev->has_scaler_out) { - if (dev->has_crop_out) - v4l2_rect_map_inside(crop, &r); - else - *crop = r; - if (dev->has_compose_out && !dev->has_crop_out) { - struct v4l2_rect min_r = { - 0, 0, - r.width / MAX_ZOOM, - factor * r.height / MAX_ZOOM - }; - struct v4l2_rect max_r = { - 0, 0, - r.width * MAX_ZOOM, - factor * r.height * MAX_ZOOM - }; - - v4l2_rect_set_min_size(compose, &min_r); - v4l2_rect_set_max_size(compose, &max_r); - v4l2_rect_map_inside(compose, &dev->compose_bounds_out); - } else if (dev->has_compose_out) { - struct v4l2_rect min_r = { - 0, 0, - crop->width / MAX_ZOOM, - factor * crop->height / MAX_ZOOM - }; - struct v4l2_rect max_r = { - 0, 0, - crop->width * MAX_ZOOM, - factor * crop->height * MAX_ZOOM - }; - - v4l2_rect_set_min_size(compose, &min_r); - v4l2_rect_set_max_size(compose, &max_r); - v4l2_rect_map_inside(compose, &dev->compose_bounds_out); - } - } else if (dev->has_compose_out && !dev->has_crop_out) { - v4l2_rect_set_size_to(crop, &r); - r.height *= factor; - v4l2_rect_set_size_to(compose, &r); - v4l2_rect_map_inside(compose, &dev->compose_bounds_out); - } else if (!dev->has_compose_out) { - v4l2_rect_map_inside(crop, &r); - r.height /= factor; - v4l2_rect_set_size_to(compose, &r); - } else { - r.height *= factor; - v4l2_rect_set_max_size(compose, &r); - v4l2_rect_map_inside(compose, &dev->compose_bounds_out); - crop->top *= factor; - crop->height *= factor; - v4l2_rect_set_size_to(crop, compose); - v4l2_rect_map_inside(crop, &r); - crop->top /= factor; - crop->height /= factor; - } - } else { - struct v4l2_rect r = { 0, 0, mp->width, mp->height }; - - v4l2_rect_set_size_to(crop, &r); - r.height /= factor; - v4l2_rect_set_size_to(compose, &r); - } - - dev->fmt_out_rect.width = mp->width; - dev->fmt_out_rect.height = mp->height; - for (p = 0; p < mp->num_planes; p++) - dev->bytesperline_out[p] = mp->plane_fmt[p].bytesperline; - for (p = dev->fmt_out->buffers; p < dev->fmt_out->planes; p++) - dev->bytesperline_out[p] = - (dev->bytesperline_out[0] * dev->fmt_out->bit_depth[p]) / - dev->fmt_out->bit_depth[0]; - dev->field_out = mp->field; - if (vivid_is_svid_out(dev)) - dev->tv_field_out = mp->field; - -set_colorspace: - dev->colorspace_out = mp->colorspace; - dev->xfer_func_out = mp->xfer_func; - dev->ycbcr_enc_out = mp->ycbcr_enc; - dev->quantization_out = mp->quantization; - if (dev->loop_video) { - vivid_send_source_change(dev, SVID); - vivid_send_source_change(dev, HDMI); - } - return 0; -} - -int vidioc_g_fmt_vid_out_mplane(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct vivid_dev *dev = video_drvdata(file); - - if (!dev->multiplanar) - return -ENOTTY; - return vivid_g_fmt_vid_out(file, priv, f); -} - -int vidioc_try_fmt_vid_out_mplane(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct vivid_dev *dev = video_drvdata(file); - - if (!dev->multiplanar) - return -ENOTTY; - return vivid_try_fmt_vid_out(file, priv, f); -} - -int vidioc_s_fmt_vid_out_mplane(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct vivid_dev *dev = video_drvdata(file); - - if (!dev->multiplanar) - return -ENOTTY; - return vivid_s_fmt_vid_out(file, priv, f); -} - -int vidioc_g_fmt_vid_out(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct vivid_dev *dev = video_drvdata(file); - - if (dev->multiplanar) - return -ENOTTY; - return fmt_sp2mp_func(file, priv, f, vivid_g_fmt_vid_out); -} - -int vidioc_try_fmt_vid_out(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct vivid_dev *dev = video_drvdata(file); - - if (dev->multiplanar) - return -ENOTTY; - return fmt_sp2mp_func(file, priv, f, vivid_try_fmt_vid_out); -} - -int vidioc_s_fmt_vid_out(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct vivid_dev *dev = video_drvdata(file); - - if (dev->multiplanar) - return -ENOTTY; - return fmt_sp2mp_func(file, priv, f, vivid_s_fmt_vid_out); -} - -int vivid_vid_out_g_selection(struct file *file, void *priv, - struct v4l2_selection *sel) -{ - struct vivid_dev *dev = video_drvdata(file); - - if (!dev->has_crop_out && !dev->has_compose_out) - return -ENOTTY; - if (sel->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) - return -EINVAL; - - sel->r.left = sel->r.top = 0; - switch (sel->target) { - case V4L2_SEL_TGT_CROP: - if (!dev->has_crop_out) - return -EINVAL; - sel->r = dev->crop_out; - break; - case V4L2_SEL_TGT_CROP_DEFAULT: - if (!dev->has_crop_out) - return -EINVAL; - sel->r = dev->fmt_out_rect; - break; - case V4L2_SEL_TGT_CROP_BOUNDS: - if (!dev->has_crop_out) - return -EINVAL; - sel->r = vivid_max_rect; - break; - case V4L2_SEL_TGT_COMPOSE: - if (!dev->has_compose_out) - return -EINVAL; - sel->r = dev->compose_out; - break; - case V4L2_SEL_TGT_COMPOSE_DEFAULT: - case V4L2_SEL_TGT_COMPOSE_BOUNDS: - if (!dev->has_compose_out) - return -EINVAL; - sel->r = dev->sink_rect; - break; - default: - return -EINVAL; - } - return 0; -} - -int vivid_vid_out_s_selection(struct file *file, void *fh, struct v4l2_selection *s) -{ - struct vivid_dev *dev = video_drvdata(file); - struct v4l2_rect *crop = &dev->crop_out; - struct v4l2_rect *compose = &dev->compose_out; - unsigned factor = V4L2_FIELD_HAS_T_OR_B(dev->field_out) ? 2 : 1; - int ret; - - if (!dev->has_crop_out && !dev->has_compose_out) - return -ENOTTY; - if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) - return -EINVAL; - - switch (s->target) { - case V4L2_SEL_TGT_CROP: - if (!dev->has_crop_out) - return -EINVAL; - ret = vivid_vid_adjust_sel(s->flags, &s->r); - if (ret) - return ret; - v4l2_rect_set_min_size(&s->r, &vivid_min_rect); - v4l2_rect_set_max_size(&s->r, &dev->fmt_out_rect); - if (dev->has_scaler_out) { - struct v4l2_rect max_rect = { - 0, 0, - dev->sink_rect.width * MAX_ZOOM, - (dev->sink_rect.height / factor) * MAX_ZOOM - }; - - v4l2_rect_set_max_size(&s->r, &max_rect); - if (dev->has_compose_out) { - struct v4l2_rect min_rect = { - 0, 0, - s->r.width / MAX_ZOOM, - (s->r.height * factor) / MAX_ZOOM - }; - struct v4l2_rect max_rect = { - 0, 0, - s->r.width * MAX_ZOOM, - (s->r.height * factor) * MAX_ZOOM - }; - - v4l2_rect_set_min_size(compose, &min_rect); - v4l2_rect_set_max_size(compose, &max_rect); - v4l2_rect_map_inside(compose, &dev->compose_bounds_out); - } - } else if (dev->has_compose_out) { - s->r.top *= factor; - s->r.height *= factor; - v4l2_rect_set_max_size(&s->r, &dev->sink_rect); - v4l2_rect_set_size_to(compose, &s->r); - v4l2_rect_map_inside(compose, &dev->compose_bounds_out); - s->r.top /= factor; - s->r.height /= factor; - } else { - v4l2_rect_set_size_to(&s->r, &dev->sink_rect); - s->r.height /= factor; - } - v4l2_rect_map_inside(&s->r, &dev->fmt_out_rect); - *crop = s->r; - break; - case V4L2_SEL_TGT_COMPOSE: - if (!dev->has_compose_out) - return -EINVAL; - ret = vivid_vid_adjust_sel(s->flags, &s->r); - if (ret) - return ret; - v4l2_rect_set_min_size(&s->r, &vivid_min_rect); - v4l2_rect_set_max_size(&s->r, &dev->sink_rect); - v4l2_rect_map_inside(&s->r, &dev->compose_bounds_out); - s->r.top /= factor; - s->r.height /= factor; - if (dev->has_scaler_out) { - struct v4l2_rect fmt = dev->fmt_out_rect; - struct v4l2_rect max_rect = { - 0, 0, - s->r.width * MAX_ZOOM, - s->r.height * MAX_ZOOM - }; - struct v4l2_rect min_rect = { - 0, 0, - s->r.width / MAX_ZOOM, - s->r.height / MAX_ZOOM - }; - - v4l2_rect_set_min_size(&fmt, &min_rect); - if (!dev->has_crop_out) - v4l2_rect_set_max_size(&fmt, &max_rect); - if (!v4l2_rect_same_size(&dev->fmt_out_rect, &fmt) && - vb2_is_busy(&dev->vb_vid_out_q)) - return -EBUSY; - if (dev->has_crop_out) { - v4l2_rect_set_min_size(crop, &min_rect); - v4l2_rect_set_max_size(crop, &max_rect); - } - dev->fmt_out_rect = fmt; - } else if (dev->has_crop_out) { - struct v4l2_rect fmt = dev->fmt_out_rect; - - v4l2_rect_set_min_size(&fmt, &s->r); - if (!v4l2_rect_same_size(&dev->fmt_out_rect, &fmt) && - vb2_is_busy(&dev->vb_vid_out_q)) - return -EBUSY; - dev->fmt_out_rect = fmt; - v4l2_rect_set_size_to(crop, &s->r); - v4l2_rect_map_inside(crop, &dev->fmt_out_rect); - } else { - if (!v4l2_rect_same_size(&s->r, &dev->fmt_out_rect) && - vb2_is_busy(&dev->vb_vid_out_q)) - return -EBUSY; - v4l2_rect_set_size_to(&dev->fmt_out_rect, &s->r); - v4l2_rect_set_size_to(crop, &s->r); - crop->height /= factor; - v4l2_rect_map_inside(crop, &dev->fmt_out_rect); - } - s->r.top *= factor; - s->r.height *= factor; - if (dev->bitmap_out && (compose->width != s->r.width || - compose->height != s->r.height)) { - vfree(dev->bitmap_out); - dev->bitmap_out = NULL; - } - *compose = s->r; - break; - default: - return -EINVAL; - } - - return 0; -} - -int vivid_vid_out_g_pixelaspect(struct file *file, void *priv, - int type, struct v4l2_fract *f) -{ - struct vivid_dev *dev = video_drvdata(file); - - if (type != V4L2_BUF_TYPE_VIDEO_OUTPUT) - return -EINVAL; - - switch (vivid_get_pixel_aspect(dev)) { - case TPG_PIXEL_ASPECT_NTSC: - f->numerator = 11; - f->denominator = 10; - break; - case TPG_PIXEL_ASPECT_PAL: - f->numerator = 54; - f->denominator = 59; - break; - default: - break; - } - return 0; -} - -int vidioc_g_fmt_vid_out_overlay(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct vivid_dev *dev = video_drvdata(file); - const struct v4l2_rect *compose = &dev->compose_out; - struct v4l2_window *win = &f->fmt.win; - unsigned clipcount = win->clipcount; - - if (!dev->has_fb) - return -EINVAL; - win->w.top = dev->overlay_out_top; - win->w.left = dev->overlay_out_left; - win->w.width = compose->width; - win->w.height = compose->height; - win->clipcount = dev->clipcount_out; - win->field = V4L2_FIELD_ANY; - win->chromakey = dev->chromakey_out; - win->global_alpha = dev->global_alpha_out; - if (clipcount > dev->clipcount_out) - clipcount = dev->clipcount_out; - if (dev->bitmap_out == NULL) - win->bitmap = NULL; - else if (win->bitmap) { - if (copy_to_user(win->bitmap, dev->bitmap_out, - ((dev->compose_out.width + 7) / 8) * dev->compose_out.height)) - return -EFAULT; - } - if (clipcount && win->clips) { - if (copy_to_user(win->clips, dev->clips_out, - clipcount * sizeof(dev->clips_out[0]))) - return -EFAULT; - } - return 0; -} - -int vidioc_try_fmt_vid_out_overlay(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct vivid_dev *dev = video_drvdata(file); - const struct v4l2_rect *compose = &dev->compose_out; - struct v4l2_window *win = &f->fmt.win; - int i, j; - - if (!dev->has_fb) - return -EINVAL; - win->w.left = clamp_t(int, win->w.left, - -dev->display_width, dev->display_width); - win->w.top = clamp_t(int, win->w.top, - -dev->display_height, dev->display_height); - win->w.width = compose->width; - win->w.height = compose->height; - /* - * It makes no sense for an OSD to overlay only top or bottom fields, - * so always set this to ANY. - */ - win->field = V4L2_FIELD_ANY; - if (win->clipcount && !win->clips) - win->clipcount = 0; - if (win->clipcount > MAX_CLIPS) - win->clipcount = MAX_CLIPS; - if (win->clipcount) { - if (copy_from_user(dev->try_clips_out, win->clips, - win->clipcount * sizeof(dev->clips_out[0]))) - return -EFAULT; - for (i = 0; i < win->clipcount; i++) { - struct v4l2_rect *r = &dev->try_clips_out[i].c; - - r->top = clamp_t(s32, r->top, 0, dev->display_height - 1); - r->height = clamp_t(s32, r->height, 1, dev->display_height - r->top); - r->left = clamp_t(u32, r->left, 0, dev->display_width - 1); - r->width = clamp_t(u32, r->width, 1, dev->display_width - r->left); - } - /* - * Yeah, so sue me, it's an O(n^2) algorithm. But n is a small - * number and it's typically a one-time deal. - */ - for (i = 0; i < win->clipcount - 1; i++) { - struct v4l2_rect *r1 = &dev->try_clips_out[i].c; - - for (j = i + 1; j < win->clipcount; j++) { - struct v4l2_rect *r2 = &dev->try_clips_out[j].c; - - if (v4l2_rect_overlap(r1, r2)) - return -EINVAL; - } - } - if (copy_to_user(win->clips, dev->try_clips_out, - win->clipcount * sizeof(dev->clips_out[0]))) - return -EFAULT; - } - return 0; -} - -int vidioc_s_fmt_vid_out_overlay(struct file *file, void *priv, - struct v4l2_format *f) -{ - struct vivid_dev *dev = video_drvdata(file); - const struct v4l2_rect *compose = &dev->compose_out; - struct v4l2_window *win = &f->fmt.win; - int ret = vidioc_try_fmt_vid_out_overlay(file, priv, f); - unsigned bitmap_size = ((compose->width + 7) / 8) * compose->height; - unsigned clips_size = win->clipcount * sizeof(dev->clips_out[0]); - void *new_bitmap = NULL; - - if (ret) - return ret; - - if (win->bitmap) { - new_bitmap = vzalloc(bitmap_size); - - if (!new_bitmap) - return -ENOMEM; - if (copy_from_user(new_bitmap, win->bitmap, bitmap_size)) { - vfree(new_bitmap); - return -EFAULT; - } - } - - dev->overlay_out_top = win->w.top; - dev->overlay_out_left = win->w.left; - vfree(dev->bitmap_out); - dev->bitmap_out = new_bitmap; - dev->clipcount_out = win->clipcount; - if (dev->clipcount_out) - memcpy(dev->clips_out, dev->try_clips_out, clips_size); - dev->chromakey_out = win->chromakey; - dev->global_alpha_out = win->global_alpha; - return ret; -} - -int vivid_vid_out_overlay(struct file *file, void *fh, unsigned i) -{ - struct vivid_dev *dev = video_drvdata(file); - - if (i && !dev->fmt_out->can_do_overlay) { - dprintk(dev, 1, "unsupported output format for output overlay\n"); - return -EINVAL; - } - - dev->overlay_out_enabled = i; - return 0; -} - -int vivid_vid_out_g_fbuf(struct file *file, void *fh, - struct v4l2_framebuffer *a) -{ - struct vivid_dev *dev = video_drvdata(file); - - a->capability = V4L2_FBUF_CAP_EXTERNOVERLAY | - V4L2_FBUF_CAP_BITMAP_CLIPPING | - V4L2_FBUF_CAP_LIST_CLIPPING | - V4L2_FBUF_CAP_CHROMAKEY | - V4L2_FBUF_CAP_SRC_CHROMAKEY | - V4L2_FBUF_CAP_GLOBAL_ALPHA | - V4L2_FBUF_CAP_LOCAL_ALPHA | - V4L2_FBUF_CAP_LOCAL_INV_ALPHA; - a->flags = V4L2_FBUF_FLAG_OVERLAY | dev->fbuf_out_flags; - a->base = (void *)dev->video_pbase; - a->fmt.width = dev->display_width; - a->fmt.height = dev->display_height; - if (dev->fb_defined.green.length == 5) - a->fmt.pixelformat = V4L2_PIX_FMT_ARGB555; - else - a->fmt.pixelformat = V4L2_PIX_FMT_RGB565; - a->fmt.bytesperline = dev->display_byte_stride; - a->fmt.sizeimage = a->fmt.height * a->fmt.bytesperline; - a->fmt.field = V4L2_FIELD_NONE; - a->fmt.colorspace = V4L2_COLORSPACE_SRGB; - a->fmt.priv = 0; - return 0; -} - -int vivid_vid_out_s_fbuf(struct file *file, void *fh, - const struct v4l2_framebuffer *a) -{ - struct vivid_dev *dev = video_drvdata(file); - const unsigned chroma_flags = V4L2_FBUF_FLAG_CHROMAKEY | - V4L2_FBUF_FLAG_SRC_CHROMAKEY; - const unsigned alpha_flags = V4L2_FBUF_FLAG_GLOBAL_ALPHA | - V4L2_FBUF_FLAG_LOCAL_ALPHA | - V4L2_FBUF_FLAG_LOCAL_INV_ALPHA; - - - if ((a->flags & chroma_flags) == chroma_flags) - return -EINVAL; - switch (a->flags & alpha_flags) { - case 0: - case V4L2_FBUF_FLAG_GLOBAL_ALPHA: - case V4L2_FBUF_FLAG_LOCAL_ALPHA: - case V4L2_FBUF_FLAG_LOCAL_INV_ALPHA: - break; - default: - return -EINVAL; - } - dev->fbuf_out_flags &= ~(chroma_flags | alpha_flags); - dev->fbuf_out_flags = a->flags & (chroma_flags | alpha_flags); - return 0; -} - -static const struct v4l2_audioout vivid_audio_outputs[] = { - { 0, "Line-Out 1" }, - { 1, "Line-Out 2" }, -}; - -int vidioc_enum_output(struct file *file, void *priv, - struct v4l2_output *out) -{ - struct vivid_dev *dev = video_drvdata(file); - - if (out->index >= dev->num_outputs) - return -EINVAL; - - out->type = V4L2_OUTPUT_TYPE_ANALOG; - switch (dev->output_type[out->index]) { - case SVID: - snprintf(out->name, sizeof(out->name), "S-Video %u", - dev->output_name_counter[out->index]); - out->std = V4L2_STD_ALL; - if (dev->has_audio_outputs) - out->audioset = (1 << ARRAY_SIZE(vivid_audio_outputs)) - 1; - out->capabilities = V4L2_OUT_CAP_STD; - break; - case HDMI: - snprintf(out->name, sizeof(out->name), "HDMI %u", - dev->output_name_counter[out->index]); - out->capabilities = V4L2_OUT_CAP_DV_TIMINGS; - break; - } - return 0; -} - -int vidioc_g_output(struct file *file, void *priv, unsigned *o) -{ - struct vivid_dev *dev = video_drvdata(file); - - *o = dev->output; - return 0; -} - -int vidioc_s_output(struct file *file, void *priv, unsigned o) -{ - struct vivid_dev *dev = video_drvdata(file); - - if (o >= dev->num_outputs) - return -EINVAL; - - if (o == dev->output) - return 0; - - if (vb2_is_busy(&dev->vb_vid_out_q) || - vb2_is_busy(&dev->vb_vbi_out_q) || - vb2_is_busy(&dev->vb_meta_out_q)) - return -EBUSY; - - dev->output = o; - dev->tv_audio_output = 0; - if (dev->output_type[o] == SVID) - dev->vid_out_dev.tvnorms = V4L2_STD_ALL; - else - dev->vid_out_dev.tvnorms = 0; - - dev->vbi_out_dev.tvnorms = dev->vid_out_dev.tvnorms; - dev->meta_out_dev.tvnorms = dev->vid_out_dev.tvnorms; - vivid_update_format_out(dev); - - v4l2_ctrl_activate(dev->ctrl_display_present, vivid_is_hdmi_out(dev)); - if (vivid_is_hdmi_out(dev)) - v4l2_ctrl_s_ctrl(dev->ctrl_display_present, - dev->display_present[dev->output]); - - return 0; -} - -int vidioc_enumaudout(struct file *file, void *fh, struct v4l2_audioout *vout) -{ - if (vout->index >= ARRAY_SIZE(vivid_audio_outputs)) - return -EINVAL; - *vout = vivid_audio_outputs[vout->index]; - return 0; -} - -int vidioc_g_audout(struct file *file, void *fh, struct v4l2_audioout *vout) -{ - struct vivid_dev *dev = video_drvdata(file); - - if (!vivid_is_svid_out(dev)) - return -EINVAL; - *vout = vivid_audio_outputs[dev->tv_audio_output]; - return 0; -} - -int vidioc_s_audout(struct file *file, void *fh, const struct v4l2_audioout *vout) -{ - struct vivid_dev *dev = video_drvdata(file); - - if (!vivid_is_svid_out(dev)) - return -EINVAL; - if (vout->index >= ARRAY_SIZE(vivid_audio_outputs)) - return -EINVAL; - dev->tv_audio_output = vout->index; - return 0; -} - -int vivid_vid_out_s_std(struct file *file, void *priv, v4l2_std_id id) -{ - struct vivid_dev *dev = video_drvdata(file); - - if (!vivid_is_svid_out(dev)) - return -ENODATA; - if (dev->std_out == id) - return 0; - if (vb2_is_busy(&dev->vb_vid_out_q) || vb2_is_busy(&dev->vb_vbi_out_q)) - return -EBUSY; - dev->std_out = id; - vivid_update_format_out(dev); - return 0; -} - -static bool valid_cvt_gtf_timings(struct v4l2_dv_timings *timings) -{ - struct v4l2_bt_timings *bt = &timings->bt; - - if ((bt->standards & (V4L2_DV_BT_STD_CVT | V4L2_DV_BT_STD_GTF)) && - v4l2_valid_dv_timings(timings, &vivid_dv_timings_cap, NULL, NULL)) - return true; - - return false; -} - -int vivid_vid_out_s_dv_timings(struct file *file, void *_fh, - struct v4l2_dv_timings *timings) -{ - struct vivid_dev *dev = video_drvdata(file); - if (!vivid_is_hdmi_out(dev)) - return -ENODATA; - if (!v4l2_find_dv_timings_cap(timings, &vivid_dv_timings_cap, - 0, NULL, NULL) && - !valid_cvt_gtf_timings(timings)) - return -EINVAL; - if (v4l2_match_dv_timings(timings, &dev->dv_timings_out, 0, true)) - return 0; - if (vb2_is_busy(&dev->vb_vid_out_q)) - return -EBUSY; - dev->dv_timings_out = *timings; - vivid_update_format_out(dev); - return 0; -} - -int vivid_vid_out_g_parm(struct file *file, void *priv, - struct v4l2_streamparm *parm) -{ - struct vivid_dev *dev = video_drvdata(file); - - if (parm->type != (dev->multiplanar ? - V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE : - V4L2_BUF_TYPE_VIDEO_OUTPUT)) - return -EINVAL; - - parm->parm.output.capability = V4L2_CAP_TIMEPERFRAME; - parm->parm.output.timeperframe = dev->timeperframe_vid_out; - parm->parm.output.writebuffers = 1; - - return 0; -} - -int vidioc_subscribe_event(struct v4l2_fh *fh, - const struct v4l2_event_subscription *sub) -{ - switch (sub->type) { - case V4L2_EVENT_SOURCE_CHANGE: - if (fh->vdev->vfl_dir == VFL_DIR_RX) - return v4l2_src_change_event_subscribe(fh, sub); - break; - default: - return v4l2_ctrl_subscribe_event(fh, sub); - } - return -EINVAL; -} diff --git a/drivers/media/platform/vivid/vivid-vid-out.h b/drivers/media/platform/vivid/vivid-vid-out.h deleted file mode 100644 index 8d56314f4ea1..000000000000 --- a/drivers/media/platform/vivid/vivid-vid-out.h +++ /dev/null @@ -1,44 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-only */ -/* - * vivid-vid-out.h - video output support functions. - * - * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - */ - -#ifndef _VIVID_VID_OUT_H_ -#define _VIVID_VID_OUT_H_ - -extern const struct vb2_ops vivid_vid_out_qops; - -void vivid_update_format_out(struct vivid_dev *dev); - -int vivid_g_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f); -int vivid_try_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f); -int vivid_s_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f); -int vidioc_g_fmt_vid_out_mplane(struct file *file, void *priv, struct v4l2_format *f); -int vidioc_try_fmt_vid_out_mplane(struct file *file, void *priv, struct v4l2_format *f); -int vidioc_s_fmt_vid_out_mplane(struct file *file, void *priv, struct v4l2_format *f); -int vidioc_g_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f); -int vidioc_try_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f); -int vidioc_s_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f); -int vivid_vid_out_g_selection(struct file *file, void *priv, struct v4l2_selection *sel); -int vivid_vid_out_s_selection(struct file *file, void *fh, struct v4l2_selection *s); -int vivid_vid_out_g_pixelaspect(struct file *file, void *priv, int type, struct v4l2_fract *f); -int vidioc_enum_fmt_vid_out_overlay(struct file *file, void *priv, struct v4l2_fmtdesc *f); -int vidioc_g_fmt_vid_out_overlay(struct file *file, void *priv, struct v4l2_format *f); -int vidioc_try_fmt_vid_out_overlay(struct file *file, void *priv, struct v4l2_format *f); -int vidioc_s_fmt_vid_out_overlay(struct file *file, void *priv, struct v4l2_format *f); -int vivid_vid_out_overlay(struct file *file, void *fh, unsigned i); -int vivid_vid_out_g_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *a); -int vivid_vid_out_s_fbuf(struct file *file, void *fh, const struct v4l2_framebuffer *a); -int vidioc_enum_output(struct file *file, void *priv, struct v4l2_output *out); -int vidioc_g_output(struct file *file, void *priv, unsigned *i); -int vidioc_s_output(struct file *file, void *priv, unsigned i); -int vidioc_enumaudout(struct file *file, void *fh, struct v4l2_audioout *vout); -int vidioc_g_audout(struct file *file, void *fh, struct v4l2_audioout *vout); -int vidioc_s_audout(struct file *file, void *fh, const struct v4l2_audioout *vout); -int vivid_vid_out_s_std(struct file *file, void *priv, v4l2_std_id id); -int vivid_vid_out_s_dv_timings(struct file *file, void *_fh, struct v4l2_dv_timings *timings); -int vivid_vid_out_g_parm(struct file *file, void *priv, struct v4l2_streamparm *parm); - -#endif diff --git a/drivers/media/test_drivers/Kconfig b/drivers/media/test_drivers/Kconfig new file mode 100644 index 000000000000..258a4d36c0d3 --- /dev/null +++ b/drivers/media/test_drivers/Kconfig @@ -0,0 +1,28 @@ +# SPDX-License-Identifier: GPL-2.0-only + +if MEDIA_TEST_SUPPORT + +menuconfig V4L_TEST_DRIVERS + bool "V4L test drivers" + depends on MEDIA_CAMERA_SUPPORT + +if V4L_TEST_DRIVERS + +source "drivers/media/test_drivers/vimc/Kconfig" + +source "drivers/media/test_drivers/vivid/Kconfig" + +config VIDEO_VIM2M + tristate "Virtual Memory-to-Memory Driver" + depends on VIDEO_DEV && VIDEO_V4L2 + select VIDEOBUF2_VMALLOC + select V4L2_MEM2MEM_DEV + help + This is a virtual test device for the memory-to-memory driver + framework. + +source "drivers/media/test_drivers/vicodec/Kconfig" + +endif #V4L_TEST_DRIVERS + +endif #MEDIA_TEST_SUPPORT diff --git a/drivers/media/test_drivers/Makefile b/drivers/media/test_drivers/Makefile new file mode 100644 index 000000000000..74410d3a9f2d --- /dev/null +++ b/drivers/media/test_drivers/Makefile @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Makefile for the test drivers. +# + +obj-$(CONFIG_VIDEO_VIMC) += vimc/ +obj-$(CONFIG_VIDEO_VIVID) += vivid/ +obj-$(CONFIG_VIDEO_VIM2M) += vim2m.o +obj-$(CONFIG_VIDEO_VICODEC) += vicodec/ diff --git a/drivers/media/test_drivers/vicodec/Kconfig b/drivers/media/test_drivers/vicodec/Kconfig new file mode 100644 index 000000000000..89456665cb16 --- /dev/null +++ b/drivers/media/test_drivers/vicodec/Kconfig @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: GPL-2.0-only +config VIDEO_VICODEC + tristate "Virtual Codec Driver" + depends on VIDEO_DEV && VIDEO_V4L2 + select VIDEOBUF2_VMALLOC + select V4L2_MEM2MEM_DEV + help + Driver for a Virtual Codec + + This driver can be compared to the vim2m driver for emulating + a video device node that exposes an emulated hardware codec. + + When in doubt, say N. diff --git a/drivers/media/test_drivers/vicodec/Makefile b/drivers/media/test_drivers/vicodec/Makefile new file mode 100644 index 000000000000..01bf7e9308a6 --- /dev/null +++ b/drivers/media/test_drivers/vicodec/Makefile @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 +vicodec-objs := vicodec-core.o codec-fwht.o codec-v4l2-fwht.o + +obj-$(CONFIG_VIDEO_VICODEC) += vicodec.o diff --git a/drivers/media/test_drivers/vicodec/codec-fwht.c b/drivers/media/test_drivers/vicodec/codec-fwht.c new file mode 100644 index 000000000000..31faf319e508 --- /dev/null +++ b/drivers/media/test_drivers/vicodec/codec-fwht.c @@ -0,0 +1,958 @@ +// SPDX-License-Identifier: LGPL-2.1+ +/* + * Copyright 2016 Tom aan de Wiel + * Copyright 2018 Cisco Systems, Inc. and/or its affiliates. All rights reserved. + * + * 8x8 Fast Walsh Hadamard Transform in sequency order based on the paper: + * + * A Recursive Algorithm for Sequency-Ordered Fast Walsh Transforms, + * R.D. Brown, 1977 + */ + +#include +#include +#include "codec-fwht.h" + +#define OVERFLOW_BIT BIT(14) + +/* + * Note: bit 0 of the header must always be 0. Otherwise it cannot + * be guaranteed that the magic 8 byte sequence (see below) can + * never occur in the rlc output. + */ +#define PFRAME_BIT BIT(15) +#define DUPS_MASK 0x1ffe + +#define PBLOCK 0 +#define IBLOCK 1 + +#define ALL_ZEROS 15 + +static const uint8_t zigzag[64] = { + 0, + 1, 8, + 2, 9, 16, + 3, 10, 17, 24, + 4, 11, 18, 25, 32, + 5, 12, 19, 26, 33, 40, + 6, 13, 20, 27, 34, 41, 48, + 7, 14, 21, 28, 35, 42, 49, 56, + 15, 22, 29, 36, 43, 50, 57, + 23, 30, 37, 44, 51, 58, + 31, 38, 45, 52, 59, + 39, 46, 53, 60, + 47, 54, 61, + 55, 62, + 63, +}; + +/* + * noinline_for_stack to work around + * https://bugs.llvm.org/show_bug.cgi?id=38809 + */ +static int noinline_for_stack +rlc(const s16 *in, __be16 *output, int blocktype) +{ + s16 block[8 * 8]; + s16 *wp = block; + int i = 0; + int x, y; + int ret = 0; + + /* read in block from framebuffer */ + int lastzero_run = 0; + int to_encode; + + for (y = 0; y < 8; y++) { + for (x = 0; x < 8; x++) { + *wp = in[x + y * 8]; + wp++; + } + } + + /* keep track of amount of trailing zeros */ + for (i = 63; i >= 0 && !block[zigzag[i]]; i--) + lastzero_run++; + + *output++ = (blocktype == PBLOCK ? htons(PFRAME_BIT) : 0); + ret++; + + to_encode = 8 * 8 - (lastzero_run > 14 ? lastzero_run : 0); + + i = 0; + while (i < to_encode) { + int cnt = 0; + int tmp; + + /* count leading zeros */ + while ((tmp = block[zigzag[i]]) == 0 && cnt < 14) { + cnt++; + i++; + if (i == to_encode) { + cnt--; + break; + } + } + /* 4 bits for run, 12 for coefficient (quantization by 4) */ + *output++ = htons((cnt | tmp << 4)); + i++; + ret++; + } + if (lastzero_run > 14) { + *output = htons(ALL_ZEROS | 0); + ret++; + } + + return ret; +} + +/* + * This function will worst-case increase rlc_in by 65*2 bytes: + * one s16 value for the header and 8 * 8 coefficients of type s16. + */ +static noinline_for_stack u16 +derlc(const __be16 **rlc_in, s16 *dwht_out, const __be16 *end_of_input) +{ + /* header */ + const __be16 *input = *rlc_in; + u16 stat; + int dec_count = 0; + s16 block[8 * 8 + 16]; + s16 *wp = block; + int i; + + if (input > end_of_input) + return OVERFLOW_BIT; + stat = ntohs(*input++); + + /* + * Now de-compress, it expands one byte to up to 15 bytes + * (or fills the remainder of the 64 bytes with zeroes if it + * is the last byte to expand). + * + * So block has to be 8 * 8 + 16 bytes, the '+ 16' is to + * allow for overflow if the incoming data was malformed. + */ + while (dec_count < 8 * 8) { + s16 in; + int length; + int coeff; + + if (input > end_of_input) + return OVERFLOW_BIT; + in = ntohs(*input++); + length = in & 0xf; + coeff = in >> 4; + + /* fill remainder with zeros */ + if (length == 15) { + for (i = 0; i < 64 - dec_count; i++) + *wp++ = 0; + break; + } + + for (i = 0; i < length; i++) + *wp++ = 0; + *wp++ = coeff; + dec_count += length + 1; + } + + wp = block; + + for (i = 0; i < 64; i++) { + int pos = zigzag[i]; + int y = pos / 8; + int x = pos % 8; + + dwht_out[x + y * 8] = *wp++; + } + *rlc_in = input; + return stat; +} + +static const int quant_table[] = { + 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 3, + 2, 2, 2, 2, 2, 2, 3, 6, + 2, 2, 2, 2, 2, 3, 6, 6, + 2, 2, 2, 2, 3, 6, 6, 6, + 2, 2, 2, 3, 6, 6, 6, 6, + 2, 2, 3, 6, 6, 6, 6, 8, +}; + +static const int quant_table_p[] = { + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 6, + 3, 3, 3, 3, 3, 3, 6, 6, + 3, 3, 3, 3, 3, 6, 6, 9, + 3, 3, 3, 3, 6, 6, 9, 9, + 3, 3, 3, 6, 6, 9, 9, 10, +}; + +static void quantize_intra(s16 *coeff, s16 *de_coeff, u16 qp) +{ + const int *quant = quant_table; + int i, j; + + for (j = 0; j < 8; j++) { + for (i = 0; i < 8; i++, quant++, coeff++, de_coeff++) { + *coeff >>= *quant; + if (*coeff >= -qp && *coeff <= qp) + *coeff = *de_coeff = 0; + else + *de_coeff = *coeff << *quant; + } + } +} + +static void dequantize_intra(s16 *coeff) +{ + const int *quant = quant_table; + int i, j; + + for (j = 0; j < 8; j++) + for (i = 0; i < 8; i++, quant++, coeff++) + *coeff <<= *quant; +} + +static void quantize_inter(s16 *coeff, s16 *de_coeff, u16 qp) +{ + const int *quant = quant_table_p; + int i, j; + + for (j = 0; j < 8; j++) { + for (i = 0; i < 8; i++, quant++, coeff++, de_coeff++) { + *coeff >>= *quant; + if (*coeff >= -qp && *coeff <= qp) + *coeff = *de_coeff = 0; + else + *de_coeff = *coeff << *quant; + } + } +} + +static void dequantize_inter(s16 *coeff) +{ + const int *quant = quant_table_p; + int i, j; + + for (j = 0; j < 8; j++) + for (i = 0; i < 8; i++, quant++, coeff++) + *coeff <<= *quant; +} + +static void noinline_for_stack fwht(const u8 *block, s16 *output_block, + unsigned int stride, + unsigned int input_step, bool intra) +{ + /* we'll need more than 8 bits for the transformed coefficients */ + s32 workspace1[8], workspace2[8]; + const u8 *tmp = block; + s16 *out = output_block; + int add = intra ? 256 : 0; + unsigned int i; + + /* stage 1 */ + for (i = 0; i < 8; i++, tmp += stride, out += 8) { + switch (input_step) { + case 1: + workspace1[0] = tmp[0] + tmp[1] - add; + workspace1[1] = tmp[0] - tmp[1]; + + workspace1[2] = tmp[2] + tmp[3] - add; + workspace1[3] = tmp[2] - tmp[3]; + + workspace1[4] = tmp[4] + tmp[5] - add; + workspace1[5] = tmp[4] - tmp[5]; + + workspace1[6] = tmp[6] + tmp[7] - add; + workspace1[7] = tmp[6] - tmp[7]; + break; + case 2: + workspace1[0] = tmp[0] + tmp[2] - add; + workspace1[1] = tmp[0] - tmp[2]; + + workspace1[2] = tmp[4] + tmp[6] - add; + workspace1[3] = tmp[4] - tmp[6]; + + workspace1[4] = tmp[8] + tmp[10] - add; + workspace1[5] = tmp[8] - tmp[10]; + + workspace1[6] = tmp[12] + tmp[14] - add; + workspace1[7] = tmp[12] - tmp[14]; + break; + case 3: + workspace1[0] = tmp[0] + tmp[3] - add; + workspace1[1] = tmp[0] - tmp[3]; + + workspace1[2] = tmp[6] + tmp[9] - add; + workspace1[3] = tmp[6] - tmp[9]; + + workspace1[4] = tmp[12] + tmp[15] - add; + workspace1[5] = tmp[12] - tmp[15]; + + workspace1[6] = tmp[18] + tmp[21] - add; + workspace1[7] = tmp[18] - tmp[21]; + break; + default: + workspace1[0] = tmp[0] + tmp[4] - add; + workspace1[1] = tmp[0] - tmp[4]; + + workspace1[2] = tmp[8] + tmp[12] - add; + workspace1[3] = tmp[8] - tmp[12]; + + workspace1[4] = tmp[16] + tmp[20] - add; + workspace1[5] = tmp[16] - tmp[20]; + + workspace1[6] = tmp[24] + tmp[28] - add; + workspace1[7] = tmp[24] - tmp[28]; + break; + } + + /* stage 2 */ + workspace2[0] = workspace1[0] + workspace1[2]; + workspace2[1] = workspace1[0] - workspace1[2]; + workspace2[2] = workspace1[1] - workspace1[3]; + workspace2[3] = workspace1[1] + workspace1[3]; + + workspace2[4] = workspace1[4] + workspace1[6]; + workspace2[5] = workspace1[4] - workspace1[6]; + workspace2[6] = workspace1[5] - workspace1[7]; + workspace2[7] = workspace1[5] + workspace1[7]; + + /* stage 3 */ + out[0] = workspace2[0] + workspace2[4]; + out[1] = workspace2[0] - workspace2[4]; + out[2] = workspace2[1] - workspace2[5]; + out[3] = workspace2[1] + workspace2[5]; + out[4] = workspace2[2] + workspace2[6]; + out[5] = workspace2[2] - workspace2[6]; + out[6] = workspace2[3] - workspace2[7]; + out[7] = workspace2[3] + workspace2[7]; + } + + out = output_block; + + for (i = 0; i < 8; i++, out++) { + /* stage 1 */ + workspace1[0] = out[0] + out[1 * 8]; + workspace1[1] = out[0] - out[1 * 8]; + + workspace1[2] = out[2 * 8] + out[3 * 8]; + workspace1[3] = out[2 * 8] - out[3 * 8]; + + workspace1[4] = out[4 * 8] + out[5 * 8]; + workspace1[5] = out[4 * 8] - out[5 * 8]; + + workspace1[6] = out[6 * 8] + out[7 * 8]; + workspace1[7] = out[6 * 8] - out[7 * 8]; + + /* stage 2 */ + workspace2[0] = workspace1[0] + workspace1[2]; + workspace2[1] = workspace1[0] - workspace1[2]; + workspace2[2] = workspace1[1] - workspace1[3]; + workspace2[3] = workspace1[1] + workspace1[3]; + + workspace2[4] = workspace1[4] + workspace1[6]; + workspace2[5] = workspace1[4] - workspace1[6]; + workspace2[6] = workspace1[5] - workspace1[7]; + workspace2[7] = workspace1[5] + workspace1[7]; + /* stage 3 */ + out[0 * 8] = workspace2[0] + workspace2[4]; + out[1 * 8] = workspace2[0] - workspace2[4]; + out[2 * 8] = workspace2[1] - workspace2[5]; + out[3 * 8] = workspace2[1] + workspace2[5]; + out[4 * 8] = workspace2[2] + workspace2[6]; + out[5 * 8] = workspace2[2] - workspace2[6]; + out[6 * 8] = workspace2[3] - workspace2[7]; + out[7 * 8] = workspace2[3] + workspace2[7]; + } +} + +/* + * Not the nicest way of doing it, but P-blocks get twice the range of + * that of the I-blocks. Therefore we need a type bigger than 8 bits. + * Furthermore values can be negative... This is just a version that + * works with 16 signed data + */ +static void noinline_for_stack +fwht16(const s16 *block, s16 *output_block, int stride, int intra) +{ + /* we'll need more than 8 bits for the transformed coefficients */ + s32 workspace1[8], workspace2[8]; + const s16 *tmp = block; + s16 *out = output_block; + int i; + + for (i = 0; i < 8; i++, tmp += stride, out += 8) { + /* stage 1 */ + workspace1[0] = tmp[0] + tmp[1]; + workspace1[1] = tmp[0] - tmp[1]; + + workspace1[2] = tmp[2] + tmp[3]; + workspace1[3] = tmp[2] - tmp[3]; + + workspace1[4] = tmp[4] + tmp[5]; + workspace1[5] = tmp[4] - tmp[5]; + + workspace1[6] = tmp[6] + tmp[7]; + workspace1[7] = tmp[6] - tmp[7]; + + /* stage 2 */ + workspace2[0] = workspace1[0] + workspace1[2]; + workspace2[1] = workspace1[0] - workspace1[2]; + workspace2[2] = workspace1[1] - workspace1[3]; + workspace2[3] = workspace1[1] + workspace1[3]; + + workspace2[4] = workspace1[4] + workspace1[6]; + workspace2[5] = workspace1[4] - workspace1[6]; + workspace2[6] = workspace1[5] - workspace1[7]; + workspace2[7] = workspace1[5] + workspace1[7]; + + /* stage 3 */ + out[0] = workspace2[0] + workspace2[4]; + out[1] = workspace2[0] - workspace2[4]; + out[2] = workspace2[1] - workspace2[5]; + out[3] = workspace2[1] + workspace2[5]; + out[4] = workspace2[2] + workspace2[6]; + out[5] = workspace2[2] - workspace2[6]; + out[6] = workspace2[3] - workspace2[7]; + out[7] = workspace2[3] + workspace2[7]; + } + + out = output_block; + + for (i = 0; i < 8; i++, out++) { + /* stage 1 */ + workspace1[0] = out[0] + out[1*8]; + workspace1[1] = out[0] - out[1*8]; + + workspace1[2] = out[2*8] + out[3*8]; + workspace1[3] = out[2*8] - out[3*8]; + + workspace1[4] = out[4*8] + out[5*8]; + workspace1[5] = out[4*8] - out[5*8]; + + workspace1[6] = out[6*8] + out[7*8]; + workspace1[7] = out[6*8] - out[7*8]; + + /* stage 2 */ + workspace2[0] = workspace1[0] + workspace1[2]; + workspace2[1] = workspace1[0] - workspace1[2]; + workspace2[2] = workspace1[1] - workspace1[3]; + workspace2[3] = workspace1[1] + workspace1[3]; + + workspace2[4] = workspace1[4] + workspace1[6]; + workspace2[5] = workspace1[4] - workspace1[6]; + workspace2[6] = workspace1[5] - workspace1[7]; + workspace2[7] = workspace1[5] + workspace1[7]; + + /* stage 3 */ + out[0*8] = workspace2[0] + workspace2[4]; + out[1*8] = workspace2[0] - workspace2[4]; + out[2*8] = workspace2[1] - workspace2[5]; + out[3*8] = workspace2[1] + workspace2[5]; + out[4*8] = workspace2[2] + workspace2[6]; + out[5*8] = workspace2[2] - workspace2[6]; + out[6*8] = workspace2[3] - workspace2[7]; + out[7*8] = workspace2[3] + workspace2[7]; + } +} + +static noinline_for_stack void +ifwht(const s16 *block, s16 *output_block, int intra) +{ + /* + * we'll need more than 8 bits for the transformed coefficients + * use native unit of cpu + */ + int workspace1[8], workspace2[8]; + int inter = intra ? 0 : 1; + const s16 *tmp = block; + s16 *out = output_block; + int i; + + for (i = 0; i < 8; i++, tmp += 8, out += 8) { + /* stage 1 */ + workspace1[0] = tmp[0] + tmp[1]; + workspace1[1] = tmp[0] - tmp[1]; + + workspace1[2] = tmp[2] + tmp[3]; + workspace1[3] = tmp[2] - tmp[3]; + + workspace1[4] = tmp[4] + tmp[5]; + workspace1[5] = tmp[4] - tmp[5]; + + workspace1[6] = tmp[6] + tmp[7]; + workspace1[7] = tmp[6] - tmp[7]; + + /* stage 2 */ + workspace2[0] = workspace1[0] + workspace1[2]; + workspace2[1] = workspace1[0] - workspace1[2]; + workspace2[2] = workspace1[1] - workspace1[3]; + workspace2[3] = workspace1[1] + workspace1[3]; + + workspace2[4] = workspace1[4] + workspace1[6]; + workspace2[5] = workspace1[4] - workspace1[6]; + workspace2[6] = workspace1[5] - workspace1[7]; + workspace2[7] = workspace1[5] + workspace1[7]; + + /* stage 3 */ + out[0] = workspace2[0] + workspace2[4]; + out[1] = workspace2[0] - workspace2[4]; + out[2] = workspace2[1] - workspace2[5]; + out[3] = workspace2[1] + workspace2[5]; + out[4] = workspace2[2] + workspace2[6]; + out[5] = workspace2[2] - workspace2[6]; + out[6] = workspace2[3] - workspace2[7]; + out[7] = workspace2[3] + workspace2[7]; + } + + out = output_block; + + for (i = 0; i < 8; i++, out++) { + /* stage 1 */ + workspace1[0] = out[0] + out[1 * 8]; + workspace1[1] = out[0] - out[1 * 8]; + + workspace1[2] = out[2 * 8] + out[3 * 8]; + workspace1[3] = out[2 * 8] - out[3 * 8]; + + workspace1[4] = out[4 * 8] + out[5 * 8]; + workspace1[5] = out[4 * 8] - out[5 * 8]; + + workspace1[6] = out[6 * 8] + out[7 * 8]; + workspace1[7] = out[6 * 8] - out[7 * 8]; + + /* stage 2 */ + workspace2[0] = workspace1[0] + workspace1[2]; + workspace2[1] = workspace1[0] - workspace1[2]; + workspace2[2] = workspace1[1] - workspace1[3]; + workspace2[3] = workspace1[1] + workspace1[3]; + + workspace2[4] = workspace1[4] + workspace1[6]; + workspace2[5] = workspace1[4] - workspace1[6]; + workspace2[6] = workspace1[5] - workspace1[7]; + workspace2[7] = workspace1[5] + workspace1[7]; + + /* stage 3 */ + if (inter) { + int d; + + out[0 * 8] = workspace2[0] + workspace2[4]; + out[1 * 8] = workspace2[0] - workspace2[4]; + out[2 * 8] = workspace2[1] - workspace2[5]; + out[3 * 8] = workspace2[1] + workspace2[5]; + out[4 * 8] = workspace2[2] + workspace2[6]; + out[5 * 8] = workspace2[2] - workspace2[6]; + out[6 * 8] = workspace2[3] - workspace2[7]; + out[7 * 8] = workspace2[3] + workspace2[7]; + + for (d = 0; d < 8; d++) + out[8 * d] >>= 6; + } else { + int d; + + out[0 * 8] = workspace2[0] + workspace2[4]; + out[1 * 8] = workspace2[0] - workspace2[4]; + out[2 * 8] = workspace2[1] - workspace2[5]; + out[3 * 8] = workspace2[1] + workspace2[5]; + out[4 * 8] = workspace2[2] + workspace2[6]; + out[5 * 8] = workspace2[2] - workspace2[6]; + out[6 * 8] = workspace2[3] - workspace2[7]; + out[7 * 8] = workspace2[3] + workspace2[7]; + + for (d = 0; d < 8; d++) { + out[8 * d] >>= 6; + out[8 * d] += 128; + } + } + } +} + +static void fill_encoder_block(const u8 *input, s16 *dst, + unsigned int stride, unsigned int input_step) +{ + int i, j; + + for (i = 0; i < 8; i++) { + for (j = 0; j < 8; j++, input += input_step) + *dst++ = *input; + input += stride - 8 * input_step; + } +} + +static int var_intra(const s16 *input) +{ + int32_t mean = 0; + int32_t ret = 0; + const s16 *tmp = input; + int i; + + for (i = 0; i < 8 * 8; i++, tmp++) + mean += *tmp; + mean /= 64; + tmp = input; + for (i = 0; i < 8 * 8; i++, tmp++) + ret += (*tmp - mean) < 0 ? -(*tmp - mean) : (*tmp - mean); + return ret; +} + +static int var_inter(const s16 *old, const s16 *new) +{ + int32_t ret = 0; + int i; + + for (i = 0; i < 8 * 8; i++, old++, new++) + ret += (*old - *new) < 0 ? -(*old - *new) : (*old - *new); + return ret; +} + +static noinline_for_stack int +decide_blocktype(const u8 *cur, const u8 *reference, s16 *deltablock, + unsigned int stride, unsigned int input_step) +{ + s16 tmp[64]; + s16 old[64]; + s16 *work = tmp; + unsigned int k, l; + int vari; + int vard; + + fill_encoder_block(cur, tmp, stride, input_step); + fill_encoder_block(reference, old, 8, 1); + vari = var_intra(tmp); + + for (k = 0; k < 8; k++) { + for (l = 0; l < 8; l++) { + *deltablock = *work - *reference; + deltablock++; + work++; + reference++; + } + } + deltablock -= 64; + vard = var_inter(old, tmp); + return vari <= vard ? IBLOCK : PBLOCK; +} + +static void fill_decoder_block(u8 *dst, const s16 *input, int stride, + unsigned int dst_step) +{ + int i, j; + + for (i = 0; i < 8; i++) { + for (j = 0; j < 8; j++, input++, dst += dst_step) { + if (*input < 0) + *dst = 0; + else if (*input > 255) + *dst = 255; + else + *dst = *input; + } + dst += stride - (8 * dst_step); + } +} + +static void add_deltas(s16 *deltas, const u8 *ref, int stride, + unsigned int ref_step) +{ + int k, l; + + for (k = 0; k < 8; k++) { + for (l = 0; l < 8; l++) { + *deltas += *ref; + ref += ref_step; + /* + * Due to quantizing, it might possible that the + * decoded coefficients are slightly out of range + */ + if (*deltas < 0) + *deltas = 0; + else if (*deltas > 255) + *deltas = 255; + deltas++; + } + ref += stride - (8 * ref_step); + } +} + +static u32 encode_plane(u8 *input, u8 *refp, __be16 **rlco, __be16 *rlco_max, + struct fwht_cframe *cf, u32 height, u32 width, + u32 stride, unsigned int input_step, + bool is_intra, bool next_is_intra) +{ + u8 *input_start = input; + __be16 *rlco_start = *rlco; + s16 deltablock[64]; + __be16 pframe_bit = htons(PFRAME_BIT); + u32 encoding = 0; + unsigned int last_size = 0; + unsigned int i, j; + + width = round_up(width, 8); + height = round_up(height, 8); + + for (j = 0; j < height / 8; j++) { + input = input_start + j * 8 * stride; + for (i = 0; i < width / 8; i++) { + /* intra code, first frame is always intra coded. */ + int blocktype = IBLOCK; + unsigned int size; + + if (!is_intra) + blocktype = decide_blocktype(input, refp, + deltablock, stride, input_step); + if (blocktype == IBLOCK) { + fwht(input, cf->coeffs, stride, input_step, 1); + quantize_intra(cf->coeffs, cf->de_coeffs, + cf->i_frame_qp); + } else { + /* inter code */ + encoding |= FWHT_FRAME_PCODED; + fwht16(deltablock, cf->coeffs, 8, 0); + quantize_inter(cf->coeffs, cf->de_coeffs, + cf->p_frame_qp); + } + if (!next_is_intra) { + ifwht(cf->de_coeffs, cf->de_fwht, blocktype); + + if (blocktype == PBLOCK) + add_deltas(cf->de_fwht, refp, 8, 1); + fill_decoder_block(refp, cf->de_fwht, 8, 1); + } + + input += 8 * input_step; + refp += 8 * 8; + + size = rlc(cf->coeffs, *rlco, blocktype); + if (last_size == size && + !memcmp(*rlco + 1, *rlco - size + 1, 2 * size - 2)) { + __be16 *last_rlco = *rlco - size; + s16 hdr = ntohs(*last_rlco); + + if (!((*last_rlco ^ **rlco) & pframe_bit) && + (hdr & DUPS_MASK) < DUPS_MASK) + *last_rlco = htons(hdr + 2); + else + *rlco += size; + } else { + *rlco += size; + } + if (*rlco >= rlco_max) { + encoding |= FWHT_FRAME_UNENCODED; + goto exit_loop; + } + last_size = size; + } + } + +exit_loop: + if (encoding & FWHT_FRAME_UNENCODED) { + u8 *out = (u8 *)rlco_start; + u8 *p; + + input = input_start; + /* + * The compressed stream should never contain the magic + * header, so when we copy the YUV data we replace 0xff + * by 0xfe. Since YUV is limited range such values + * shouldn't appear anyway. + */ + for (j = 0; j < height; j++) { + for (i = 0, p = input; i < width; i++, p += input_step) + *out++ = (*p == 0xff) ? 0xfe : *p; + input += stride; + } + *rlco = (__be16 *)out; + encoding &= ~FWHT_FRAME_PCODED; + } + return encoding; +} + +u32 fwht_encode_frame(struct fwht_raw_frame *frm, + struct fwht_raw_frame *ref_frm, + struct fwht_cframe *cf, + bool is_intra, bool next_is_intra, + unsigned int width, unsigned int height, + unsigned int stride, unsigned int chroma_stride) +{ + unsigned int size = height * width; + __be16 *rlco = cf->rlc_data; + __be16 *rlco_max; + u32 encoding; + + rlco_max = rlco + size / 2 - 256; + encoding = encode_plane(frm->luma, ref_frm->luma, &rlco, rlco_max, cf, + height, width, stride, + frm->luma_alpha_step, is_intra, next_is_intra); + if (encoding & FWHT_FRAME_UNENCODED) + encoding |= FWHT_LUMA_UNENCODED; + encoding &= ~FWHT_FRAME_UNENCODED; + + if (frm->components_num >= 3) { + u32 chroma_h = height / frm->height_div; + u32 chroma_w = width / frm->width_div; + unsigned int chroma_size = chroma_h * chroma_w; + + rlco_max = rlco + chroma_size / 2 - 256; + encoding |= encode_plane(frm->cb, ref_frm->cb, &rlco, rlco_max, + cf, chroma_h, chroma_w, + chroma_stride, frm->chroma_step, + is_intra, next_is_intra); + if (encoding & FWHT_FRAME_UNENCODED) + encoding |= FWHT_CB_UNENCODED; + encoding &= ~FWHT_FRAME_UNENCODED; + rlco_max = rlco + chroma_size / 2 - 256; + encoding |= encode_plane(frm->cr, ref_frm->cr, &rlco, rlco_max, + cf, chroma_h, chroma_w, + chroma_stride, frm->chroma_step, + is_intra, next_is_intra); + if (encoding & FWHT_FRAME_UNENCODED) + encoding |= FWHT_CR_UNENCODED; + encoding &= ~FWHT_FRAME_UNENCODED; + } + + if (frm->components_num == 4) { + rlco_max = rlco + size / 2 - 256; + encoding |= encode_plane(frm->alpha, ref_frm->alpha, &rlco, + rlco_max, cf, height, width, + stride, frm->luma_alpha_step, + is_intra, next_is_intra); + if (encoding & FWHT_FRAME_UNENCODED) + encoding |= FWHT_ALPHA_UNENCODED; + encoding &= ~FWHT_FRAME_UNENCODED; + } + + cf->size = (rlco - cf->rlc_data) * sizeof(*rlco); + return encoding; +} + +static bool decode_plane(struct fwht_cframe *cf, const __be16 **rlco, + u32 height, u32 width, const u8 *ref, u32 ref_stride, + unsigned int ref_step, u8 *dst, + unsigned int dst_stride, unsigned int dst_step, + bool uncompressed, const __be16 *end_of_rlco_buf) +{ + unsigned int copies = 0; + s16 copy[8 * 8]; + u16 stat; + unsigned int i, j; + bool is_intra = !ref; + + width = round_up(width, 8); + height = round_up(height, 8); + + if (uncompressed) { + int i; + + if (end_of_rlco_buf + 1 < *rlco + width * height / 2) + return false; + for (i = 0; i < height; i++) { + memcpy(dst, *rlco, width); + dst += dst_stride; + *rlco += width / 2; + } + return true; + } + + /* + * When decoding each macroblock the rlco pointer will be increased + * by 65 * 2 bytes worst-case. + * To avoid overflow the buffer has to be 65/64th of the actual raw + * image size, just in case someone feeds it malicious data. + */ + for (j = 0; j < height / 8; j++) { + for (i = 0; i < width / 8; i++) { + const u8 *refp = ref + j * 8 * ref_stride + + i * 8 * ref_step; + u8 *dstp = dst + j * 8 * dst_stride + i * 8 * dst_step; + + if (copies) { + memcpy(cf->de_fwht, copy, sizeof(copy)); + if ((stat & PFRAME_BIT) && !is_intra) + add_deltas(cf->de_fwht, refp, + ref_stride, ref_step); + fill_decoder_block(dstp, cf->de_fwht, + dst_stride, dst_step); + copies--; + continue; + } + + stat = derlc(rlco, cf->coeffs, end_of_rlco_buf); + if (stat & OVERFLOW_BIT) + return false; + if ((stat & PFRAME_BIT) && !is_intra) + dequantize_inter(cf->coeffs); + else + dequantize_intra(cf->coeffs); + + ifwht(cf->coeffs, cf->de_fwht, + ((stat & PFRAME_BIT) && !is_intra) ? 0 : 1); + + copies = (stat & DUPS_MASK) >> 1; + if (copies) + memcpy(copy, cf->de_fwht, sizeof(copy)); + if ((stat & PFRAME_BIT) && !is_intra) + add_deltas(cf->de_fwht, refp, + ref_stride, ref_step); + fill_decoder_block(dstp, cf->de_fwht, dst_stride, + dst_step); + } + } + return true; +} + +bool fwht_decode_frame(struct fwht_cframe *cf, u32 hdr_flags, + unsigned int components_num, unsigned int width, + unsigned int height, const struct fwht_raw_frame *ref, + unsigned int ref_stride, unsigned int ref_chroma_stride, + struct fwht_raw_frame *dst, unsigned int dst_stride, + unsigned int dst_chroma_stride) +{ + const __be16 *rlco = cf->rlc_data; + const __be16 *end_of_rlco_buf = cf->rlc_data + + (cf->size / sizeof(*rlco)) - 1; + + if (!decode_plane(cf, &rlco, height, width, ref->luma, ref_stride, + ref->luma_alpha_step, dst->luma, dst_stride, + dst->luma_alpha_step, + hdr_flags & FWHT_FL_LUMA_IS_UNCOMPRESSED, + end_of_rlco_buf)) + return false; + + if (components_num >= 3) { + u32 h = height; + u32 w = width; + + if (!(hdr_flags & FWHT_FL_CHROMA_FULL_HEIGHT)) + h /= 2; + if (!(hdr_flags & FWHT_FL_CHROMA_FULL_WIDTH)) + w /= 2; + + if (!decode_plane(cf, &rlco, h, w, ref->cb, ref_chroma_stride, + ref->chroma_step, dst->cb, dst_chroma_stride, + dst->chroma_step, + hdr_flags & FWHT_FL_CB_IS_UNCOMPRESSED, + end_of_rlco_buf)) + return false; + if (!decode_plane(cf, &rlco, h, w, ref->cr, ref_chroma_stride, + ref->chroma_step, dst->cr, dst_chroma_stride, + dst->chroma_step, + hdr_flags & FWHT_FL_CR_IS_UNCOMPRESSED, + end_of_rlco_buf)) + return false; + } + + if (components_num == 4) + if (!decode_plane(cf, &rlco, height, width, ref->alpha, ref_stride, + ref->luma_alpha_step, dst->alpha, dst_stride, + dst->luma_alpha_step, + hdr_flags & FWHT_FL_ALPHA_IS_UNCOMPRESSED, + end_of_rlco_buf)) + return false; + return true; +} diff --git a/drivers/media/test_drivers/vicodec/codec-fwht.h b/drivers/media/test_drivers/vicodec/codec-fwht.h new file mode 100644 index 000000000000..b6fec2b1cbca --- /dev/null +++ b/drivers/media/test_drivers/vicodec/codec-fwht.h @@ -0,0 +1,150 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ +/* + * Copyright 2016 Tom aan de Wiel + * Copyright 2018 Cisco Systems, Inc. and/or its affiliates. All rights reserved. + */ + +#ifndef CODEC_FWHT_H +#define CODEC_FWHT_H + +#include +#include +#include + +/* + * The compressed format consists of a fwht_cframe_hdr struct followed by the + * compressed frame data. The header contains the size of that data. + * Each Y, Cb and Cr plane is compressed separately. If the compressed + * size of each plane becomes larger than the uncompressed size, then + * that plane is stored uncompressed and the corresponding bit is set + * in the flags field of the header. + * + * Each compressed plane consists of macroblocks and each macroblock + * is run-length-encoded. Each macroblock starts with a 16 bit value. + * Bit 15 indicates if this is a P-coded macroblock (1) or not (0). + * P-coded macroblocks contain a delta against the previous frame. + * + * Bits 1-12 contain a number. If non-zero, then this same macroblock + * repeats that number of times. This results in a high degree of + * compression for generated images like colorbars. + * + * Following this macroblock header the MB coefficients are run-length + * encoded: the top 12 bits contain the coefficient, the bottom 4 bits + * tell how many times this coefficient occurs. The value 0xf indicates + * that the remainder of the macroblock should be filled with zeroes. + * + * All 16 and 32 bit values are stored in big-endian (network) order. + * + * Each fwht_cframe_hdr starts with an 8 byte magic header that is + * guaranteed not to occur in the compressed frame data. This header + * can be used to sync to the next frame. + * + * This codec uses the Fast Walsh Hadamard Transform. Tom aan de Wiel + * developed this as part of a university project, specifically for use + * with this driver. His project report can be found here: + * + * https://hverkuil.home.xs4all.nl/fwht.pdf + */ + +/* + * This is a sequence of 8 bytes with the low 4 bits set to 0xf. + * + * This sequence cannot occur in the encoded data + * + * Note that these two magic values are symmetrical so endian issues here. + */ +#define FWHT_MAGIC1 0x4f4f4f4f +#define FWHT_MAGIC2 0xffffffff + +#define FWHT_VERSION 3 + +/* Set if this is an interlaced format */ +#define FWHT_FL_IS_INTERLACED BIT(0) +/* Set if this is a bottom-first (NTSC) interlaced format */ +#define FWHT_FL_IS_BOTTOM_FIRST BIT(1) +/* Set if each 'frame' contains just one field */ +#define FWHT_FL_IS_ALTERNATE BIT(2) +/* + * If FWHT_FL_IS_ALTERNATE was set, then this is set if this + * 'frame' is the bottom field, else it is the top field. + */ +#define FWHT_FL_IS_BOTTOM_FIELD BIT(3) +/* Set if this frame is uncompressed */ +#define FWHT_FL_LUMA_IS_UNCOMPRESSED BIT(4) +#define FWHT_FL_CB_IS_UNCOMPRESSED BIT(5) +#define FWHT_FL_CR_IS_UNCOMPRESSED BIT(6) +#define FWHT_FL_CHROMA_FULL_HEIGHT BIT(7) +#define FWHT_FL_CHROMA_FULL_WIDTH BIT(8) +#define FWHT_FL_ALPHA_IS_UNCOMPRESSED BIT(9) +#define FWHT_FL_I_FRAME BIT(10) + +/* A 4-values flag - the number of components - 1 */ +#define FWHT_FL_COMPONENTS_NUM_MSK GENMASK(18, 16) +#define FWHT_FL_COMPONENTS_NUM_OFFSET 16 + +#define FWHT_FL_PIXENC_MSK GENMASK(20, 19) +#define FWHT_FL_PIXENC_OFFSET 19 +#define FWHT_FL_PIXENC_YUV (1 << FWHT_FL_PIXENC_OFFSET) +#define FWHT_FL_PIXENC_RGB (2 << FWHT_FL_PIXENC_OFFSET) +#define FWHT_FL_PIXENC_HSV (3 << FWHT_FL_PIXENC_OFFSET) + +/* + * A macro to calculate the needed padding in order to make sure + * both luma and chroma components resolutions are rounded up to + * a multiple of 8 + */ +#define vic_round_dim(dim, div) (round_up((dim) / (div), 8) * (div)) + +struct fwht_cframe_hdr { + u32 magic1; + u32 magic2; + __be32 version; + __be32 width, height; + __be32 flags; + __be32 colorspace; + __be32 xfer_func; + __be32 ycbcr_enc; + __be32 quantization; + __be32 size; +}; + +struct fwht_cframe { + u16 i_frame_qp; + u16 p_frame_qp; + __be16 *rlc_data; + s16 coeffs[8 * 8]; + s16 de_coeffs[8 * 8]; + s16 de_fwht[8 * 8]; + u32 size; +}; + +struct fwht_raw_frame { + unsigned int width_div; + unsigned int height_div; + unsigned int luma_alpha_step; + unsigned int chroma_step; + unsigned int components_num; + u8 *buf; + u8 *luma, *cb, *cr, *alpha; +}; + +#define FWHT_FRAME_PCODED BIT(0) +#define FWHT_FRAME_UNENCODED BIT(1) +#define FWHT_LUMA_UNENCODED BIT(2) +#define FWHT_CB_UNENCODED BIT(3) +#define FWHT_CR_UNENCODED BIT(4) +#define FWHT_ALPHA_UNENCODED BIT(5) + +u32 fwht_encode_frame(struct fwht_raw_frame *frm, + struct fwht_raw_frame *ref_frm, + struct fwht_cframe *cf, + bool is_intra, bool next_is_intra, + unsigned int width, unsigned int height, + unsigned int stride, unsigned int chroma_stride); +bool fwht_decode_frame(struct fwht_cframe *cf, u32 hdr_flags, + unsigned int components_num, unsigned int width, + unsigned int height, const struct fwht_raw_frame *ref, + unsigned int ref_stride, unsigned int ref_chroma_stride, + struct fwht_raw_frame *dst, unsigned int dst_stride, + unsigned int dst_chroma_stride); +#endif diff --git a/drivers/media/test_drivers/vicodec/codec-v4l2-fwht.c b/drivers/media/test_drivers/vicodec/codec-v4l2-fwht.c new file mode 100644 index 000000000000..b6e39fbd8ad5 --- /dev/null +++ b/drivers/media/test_drivers/vicodec/codec-v4l2-fwht.c @@ -0,0 +1,367 @@ +// SPDX-License-Identifier: LGPL-2.1 +/* + * A V4L2 frontend for the FWHT codec + * + * Copyright 2018 Cisco Systems, Inc. and/or its affiliates. All rights reserved. + */ + +#include +#include +#include +#include "codec-v4l2-fwht.h" + +static const struct v4l2_fwht_pixfmt_info v4l2_fwht_pixfmts[] = { + { V4L2_PIX_FMT_YUV420, 1, 3, 2, 1, 1, 2, 2, 3, 3, FWHT_FL_PIXENC_YUV}, + { V4L2_PIX_FMT_YVU420, 1, 3, 2, 1, 1, 2, 2, 3, 3, FWHT_FL_PIXENC_YUV}, + { V4L2_PIX_FMT_YUV422P, 1, 2, 1, 1, 1, 2, 1, 3, 3, FWHT_FL_PIXENC_YUV}, + { V4L2_PIX_FMT_NV12, 1, 3, 2, 1, 2, 2, 2, 3, 2, FWHT_FL_PIXENC_YUV}, + { V4L2_PIX_FMT_NV21, 1, 3, 2, 1, 2, 2, 2, 3, 2, FWHT_FL_PIXENC_YUV}, + { V4L2_PIX_FMT_NV16, 1, 2, 1, 1, 2, 2, 1, 3, 2, FWHT_FL_PIXENC_YUV}, + { V4L2_PIX_FMT_NV61, 1, 2, 1, 1, 2, 2, 1, 3, 2, FWHT_FL_PIXENC_YUV}, + { V4L2_PIX_FMT_NV24, 1, 3, 1, 1, 2, 1, 1, 3, 2, FWHT_FL_PIXENC_YUV}, + { V4L2_PIX_FMT_NV42, 1, 3, 1, 1, 2, 1, 1, 3, 2, FWHT_FL_PIXENC_YUV}, + { V4L2_PIX_FMT_YUYV, 2, 2, 1, 2, 4, 2, 1, 3, 1, FWHT_FL_PIXENC_YUV}, + { V4L2_PIX_FMT_YVYU, 2, 2, 1, 2, 4, 2, 1, 3, 1, FWHT_FL_PIXENC_YUV}, + { V4L2_PIX_FMT_UYVY, 2, 2, 1, 2, 4, 2, 1, 3, 1, FWHT_FL_PIXENC_YUV}, + { V4L2_PIX_FMT_VYUY, 2, 2, 1, 2, 4, 2, 1, 3, 1, FWHT_FL_PIXENC_YUV}, + { V4L2_PIX_FMT_BGR24, 3, 3, 1, 3, 3, 1, 1, 3, 1, FWHT_FL_PIXENC_RGB}, + { V4L2_PIX_FMT_RGB24, 3, 3, 1, 3, 3, 1, 1, 3, 1, FWHT_FL_PIXENC_RGB}, + { V4L2_PIX_FMT_HSV24, 3, 3, 1, 3, 3, 1, 1, 3, 1, FWHT_FL_PIXENC_HSV}, + { V4L2_PIX_FMT_BGR32, 4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB}, + { V4L2_PIX_FMT_XBGR32, 4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB}, + { V4L2_PIX_FMT_ABGR32, 4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB}, + { V4L2_PIX_FMT_RGB32, 4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB}, + { V4L2_PIX_FMT_XRGB32, 4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB}, + { V4L2_PIX_FMT_ARGB32, 4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB}, + { V4L2_PIX_FMT_BGRX32, 4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB}, + { V4L2_PIX_FMT_BGRA32, 4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB}, + { V4L2_PIX_FMT_RGBX32, 4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB}, + { V4L2_PIX_FMT_RGBA32, 4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_RGB}, + { V4L2_PIX_FMT_HSV32, 4, 4, 1, 4, 4, 1, 1, 4, 1, FWHT_FL_PIXENC_HSV}, + { V4L2_PIX_FMT_GREY, 1, 1, 1, 1, 0, 1, 1, 1, 1, FWHT_FL_PIXENC_RGB}, +}; + +bool v4l2_fwht_validate_fmt(const struct v4l2_fwht_pixfmt_info *info, + u32 width_div, u32 height_div, u32 components_num, + u32 pixenc) +{ + if (info->width_div == width_div && + info->height_div == height_div && + (!pixenc || info->pixenc == pixenc) && + info->components_num == components_num) + return true; + return false; +} + +const struct v4l2_fwht_pixfmt_info *v4l2_fwht_find_nth_fmt(u32 width_div, + u32 height_div, + u32 components_num, + u32 pixenc, + unsigned int start_idx) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(v4l2_fwht_pixfmts); i++) { + bool is_valid = v4l2_fwht_validate_fmt(&v4l2_fwht_pixfmts[i], + width_div, height_div, + components_num, pixenc); + if (is_valid) { + if (start_idx == 0) + return v4l2_fwht_pixfmts + i; + start_idx--; + } + } + return NULL; +} + +const struct v4l2_fwht_pixfmt_info *v4l2_fwht_find_pixfmt(u32 pixelformat) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(v4l2_fwht_pixfmts); i++) + if (v4l2_fwht_pixfmts[i].id == pixelformat) + return v4l2_fwht_pixfmts + i; + return NULL; +} + +const struct v4l2_fwht_pixfmt_info *v4l2_fwht_get_pixfmt(u32 idx) +{ + if (idx >= ARRAY_SIZE(v4l2_fwht_pixfmts)) + return NULL; + return v4l2_fwht_pixfmts + idx; +} + +static int prepare_raw_frame(struct fwht_raw_frame *rf, + const struct v4l2_fwht_pixfmt_info *info, u8 *buf, + unsigned int size) +{ + rf->luma = buf; + rf->width_div = info->width_div; + rf->height_div = info->height_div; + rf->luma_alpha_step = info->luma_alpha_step; + rf->chroma_step = info->chroma_step; + rf->alpha = NULL; + rf->components_num = info->components_num; + + /* + * The buffer is NULL if it is the reference + * frame of an I-frame in the stateless decoder + */ + if (!buf) { + rf->luma = NULL; + rf->cb = NULL; + rf->cr = NULL; + rf->alpha = NULL; + return 0; + } + switch (info->id) { + case V4L2_PIX_FMT_GREY: + rf->cb = NULL; + rf->cr = NULL; + break; + case V4L2_PIX_FMT_YUV420: + rf->cb = rf->luma + size; + rf->cr = rf->cb + size / 4; + break; + case V4L2_PIX_FMT_YVU420: + rf->cr = rf->luma + size; + rf->cb = rf->cr + size / 4; + break; + case V4L2_PIX_FMT_YUV422P: + rf->cb = rf->luma + size; + rf->cr = rf->cb + size / 2; + break; + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV16: + case V4L2_PIX_FMT_NV24: + rf->cb = rf->luma + size; + rf->cr = rf->cb + 1; + break; + case V4L2_PIX_FMT_NV21: + case V4L2_PIX_FMT_NV61: + case V4L2_PIX_FMT_NV42: + rf->cr = rf->luma + size; + rf->cb = rf->cr + 1; + break; + case V4L2_PIX_FMT_YUYV: + rf->cb = rf->luma + 1; + rf->cr = rf->cb + 2; + break; + case V4L2_PIX_FMT_YVYU: + rf->cr = rf->luma + 1; + rf->cb = rf->cr + 2; + break; + case V4L2_PIX_FMT_UYVY: + rf->cb = rf->luma; + rf->cr = rf->cb + 2; + rf->luma++; + break; + case V4L2_PIX_FMT_VYUY: + rf->cr = rf->luma; + rf->cb = rf->cr + 2; + rf->luma++; + break; + case V4L2_PIX_FMT_RGB24: + case V4L2_PIX_FMT_HSV24: + rf->cr = rf->luma; + rf->cb = rf->cr + 2; + rf->luma++; + break; + case V4L2_PIX_FMT_BGR24: + rf->cb = rf->luma; + rf->cr = rf->cb + 2; + rf->luma++; + break; + case V4L2_PIX_FMT_RGB32: + case V4L2_PIX_FMT_XRGB32: + case V4L2_PIX_FMT_HSV32: + case V4L2_PIX_FMT_ARGB32: + rf->alpha = rf->luma; + rf->cr = rf->luma + 1; + rf->cb = rf->cr + 2; + rf->luma += 2; + break; + case V4L2_PIX_FMT_BGR32: + case V4L2_PIX_FMT_XBGR32: + case V4L2_PIX_FMT_ABGR32: + rf->cb = rf->luma; + rf->cr = rf->cb + 2; + rf->luma++; + rf->alpha = rf->cr + 1; + break; + case V4L2_PIX_FMT_BGRX32: + case V4L2_PIX_FMT_BGRA32: + rf->alpha = rf->luma; + rf->cb = rf->luma + 1; + rf->cr = rf->cb + 2; + rf->luma += 2; + break; + case V4L2_PIX_FMT_RGBX32: + case V4L2_PIX_FMT_RGBA32: + rf->alpha = rf->luma + 3; + rf->cr = rf->luma; + rf->cb = rf->cr + 2; + rf->luma++; + break; + default: + return -EINVAL; + } + return 0; +} + +int v4l2_fwht_encode(struct v4l2_fwht_state *state, u8 *p_in, u8 *p_out) +{ + unsigned int size = state->stride * state->coded_height; + unsigned int chroma_stride = state->stride; + const struct v4l2_fwht_pixfmt_info *info = state->info; + struct fwht_cframe_hdr *p_hdr; + struct fwht_cframe cf; + struct fwht_raw_frame rf; + u32 encoding; + u32 flags = 0; + + if (!info) + return -EINVAL; + + if (prepare_raw_frame(&rf, info, p_in, size)) + return -EINVAL; + + if (info->planes_num == 3) + chroma_stride /= 2; + + if (info->id == V4L2_PIX_FMT_NV24 || + info->id == V4L2_PIX_FMT_NV42) + chroma_stride *= 2; + + cf.i_frame_qp = state->i_frame_qp; + cf.p_frame_qp = state->p_frame_qp; + cf.rlc_data = (__be16 *)(p_out + sizeof(*p_hdr)); + + encoding = fwht_encode_frame(&rf, &state->ref_frame, &cf, + !state->gop_cnt, + state->gop_cnt == state->gop_size - 1, + state->visible_width, + state->visible_height, + state->stride, chroma_stride); + if (!(encoding & FWHT_FRAME_PCODED)) + state->gop_cnt = 0; + if (++state->gop_cnt >= state->gop_size) + state->gop_cnt = 0; + + p_hdr = (struct fwht_cframe_hdr *)p_out; + p_hdr->magic1 = FWHT_MAGIC1; + p_hdr->magic2 = FWHT_MAGIC2; + p_hdr->version = htonl(FWHT_VERSION); + p_hdr->width = htonl(state->visible_width); + p_hdr->height = htonl(state->visible_height); + flags |= (info->components_num - 1) << FWHT_FL_COMPONENTS_NUM_OFFSET; + flags |= info->pixenc; + if (encoding & FWHT_LUMA_UNENCODED) + flags |= FWHT_FL_LUMA_IS_UNCOMPRESSED; + if (encoding & FWHT_CB_UNENCODED) + flags |= FWHT_FL_CB_IS_UNCOMPRESSED; + if (encoding & FWHT_CR_UNENCODED) + flags |= FWHT_FL_CR_IS_UNCOMPRESSED; + if (encoding & FWHT_ALPHA_UNENCODED) + flags |= FWHT_FL_ALPHA_IS_UNCOMPRESSED; + if (!(encoding & FWHT_FRAME_PCODED)) + flags |= FWHT_FL_I_FRAME; + if (rf.height_div == 1) + flags |= FWHT_FL_CHROMA_FULL_HEIGHT; + if (rf.width_div == 1) + flags |= FWHT_FL_CHROMA_FULL_WIDTH; + p_hdr->flags = htonl(flags); + p_hdr->colorspace = htonl(state->colorspace); + p_hdr->xfer_func = htonl(state->xfer_func); + p_hdr->ycbcr_enc = htonl(state->ycbcr_enc); + p_hdr->quantization = htonl(state->quantization); + p_hdr->size = htonl(cf.size); + return cf.size + sizeof(*p_hdr); +} + +int v4l2_fwht_decode(struct v4l2_fwht_state *state, u8 *p_in, u8 *p_out) +{ + u32 flags; + struct fwht_cframe cf; + unsigned int components_num = 3; + unsigned int version; + const struct v4l2_fwht_pixfmt_info *info; + unsigned int hdr_width_div, hdr_height_div; + struct fwht_raw_frame dst_rf; + unsigned int dst_chroma_stride = state->stride; + unsigned int ref_chroma_stride = state->ref_stride; + unsigned int dst_size = state->stride * state->coded_height; + unsigned int ref_size; + + if (!state->info) + return -EINVAL; + + info = state->info; + + version = ntohl(state->header.version); + if (!version || version > FWHT_VERSION) { + pr_err("version %d is not supported, current version is %d\n", + version, FWHT_VERSION); + return -EINVAL; + } + + if (state->header.magic1 != FWHT_MAGIC1 || + state->header.magic2 != FWHT_MAGIC2) + return -EINVAL; + + /* TODO: support resolution changes */ + if (ntohl(state->header.width) != state->visible_width || + ntohl(state->header.height) != state->visible_height) + return -EINVAL; + + flags = ntohl(state->header.flags); + + if (version >= 2) { + if ((flags & FWHT_FL_PIXENC_MSK) != info->pixenc) + return -EINVAL; + components_num = 1 + ((flags & FWHT_FL_COMPONENTS_NUM_MSK) >> + FWHT_FL_COMPONENTS_NUM_OFFSET); + } + + if (components_num != info->components_num) + return -EINVAL; + + state->colorspace = ntohl(state->header.colorspace); + state->xfer_func = ntohl(state->header.xfer_func); + state->ycbcr_enc = ntohl(state->header.ycbcr_enc); + state->quantization = ntohl(state->header.quantization); + cf.rlc_data = (__be16 *)p_in; + cf.size = ntohl(state->header.size); + + hdr_width_div = (flags & FWHT_FL_CHROMA_FULL_WIDTH) ? 1 : 2; + hdr_height_div = (flags & FWHT_FL_CHROMA_FULL_HEIGHT) ? 1 : 2; + if (hdr_width_div != info->width_div || + hdr_height_div != info->height_div) + return -EINVAL; + + if (prepare_raw_frame(&dst_rf, info, p_out, dst_size)) + return -EINVAL; + if (info->planes_num == 3) { + dst_chroma_stride /= 2; + ref_chroma_stride /= 2; + } + if (info->id == V4L2_PIX_FMT_NV24 || + info->id == V4L2_PIX_FMT_NV42) { + dst_chroma_stride *= 2; + ref_chroma_stride *= 2; + } + + + ref_size = state->ref_stride * state->coded_height; + + if (prepare_raw_frame(&state->ref_frame, info, state->ref_frame.buf, + ref_size)) + return -EINVAL; + + if (!fwht_decode_frame(&cf, flags, components_num, + state->visible_width, state->visible_height, + &state->ref_frame, state->ref_stride, ref_chroma_stride, + &dst_rf, state->stride, dst_chroma_stride)) + return -EINVAL; + return 0; +} diff --git a/drivers/media/test_drivers/vicodec/codec-v4l2-fwht.h b/drivers/media/test_drivers/vicodec/codec-v4l2-fwht.h new file mode 100644 index 000000000000..1a0d2a9f931a --- /dev/null +++ b/drivers/media/test_drivers/vicodec/codec-v4l2-fwht.h @@ -0,0 +1,64 @@ +/* SPDX-License-Identifier: LGPL-2.1 */ +/* + * Copyright 2018 Cisco Systems, Inc. and/or its affiliates. All rights reserved. + */ + +#ifndef CODEC_V4L2_FWHT_H +#define CODEC_V4L2_FWHT_H + +#include "codec-fwht.h" + +struct v4l2_fwht_pixfmt_info { + u32 id; + unsigned int bytesperline_mult; + unsigned int sizeimage_mult; + unsigned int sizeimage_div; + unsigned int luma_alpha_step; + unsigned int chroma_step; + /* Chroma plane subsampling */ + unsigned int width_div; + unsigned int height_div; + unsigned int components_num; + unsigned int planes_num; + unsigned int pixenc; +}; + +struct v4l2_fwht_state { + const struct v4l2_fwht_pixfmt_info *info; + unsigned int visible_width; + unsigned int visible_height; + unsigned int coded_width; + unsigned int coded_height; + unsigned int stride; + unsigned int ref_stride; + unsigned int gop_size; + unsigned int gop_cnt; + u16 i_frame_qp; + u16 p_frame_qp; + + enum v4l2_colorspace colorspace; + enum v4l2_ycbcr_encoding ycbcr_enc; + enum v4l2_xfer_func xfer_func; + enum v4l2_quantization quantization; + + struct fwht_raw_frame ref_frame; + struct fwht_cframe_hdr header; + u8 *compressed_frame; + u64 ref_frame_ts; +}; + +const struct v4l2_fwht_pixfmt_info *v4l2_fwht_find_pixfmt(u32 pixelformat); +const struct v4l2_fwht_pixfmt_info *v4l2_fwht_get_pixfmt(u32 idx); +bool v4l2_fwht_validate_fmt(const struct v4l2_fwht_pixfmt_info *info, + u32 width_div, u32 height_div, u32 components_num, + u32 pixenc); +const struct v4l2_fwht_pixfmt_info *v4l2_fwht_find_nth_fmt(u32 width_div, + u32 height_div, + u32 components_num, + u32 pixenc, + unsigned int start_idx); + +int v4l2_fwht_encode(struct v4l2_fwht_state *state, u8 *p_in, u8 *p_out); +int v4l2_fwht_decode(struct v4l2_fwht_state *state, u8 *p_in, u8 *p_out); + +#endif diff --git a/drivers/media/test_drivers/vicodec/vicodec-core.c b/drivers/media/test_drivers/vicodec/vicodec-core.c new file mode 100644 index 000000000000..30ced1c21387 --- /dev/null +++ b/drivers/media/test_drivers/vicodec/vicodec-core.c @@ -0,0 +1,2238 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * A virtual codec example device. + * + * Copyright 2018 Cisco Systems, Inc. and/or its affiliates. All rights reserved. + * + * This is a virtual codec device driver for testing the codec framework. + * It simulates a device that uses memory buffers for both source and + * destination and encodes or decodes the data. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "codec-v4l2-fwht.h" + +MODULE_DESCRIPTION("Virtual codec device"); +MODULE_AUTHOR("Hans Verkuil "); +MODULE_LICENSE("GPL v2"); + +static bool multiplanar; +module_param(multiplanar, bool, 0444); +MODULE_PARM_DESC(multiplanar, + " use multi-planar API instead of single-planar API"); + +static unsigned int debug; +module_param(debug, uint, 0644); +MODULE_PARM_DESC(debug, " activates debug info"); + +#define VICODEC_NAME "vicodec" +#define MAX_WIDTH 4096U +#define MIN_WIDTH 640U +#define MAX_HEIGHT 2160U +#define MIN_HEIGHT 360U + +#define dprintk(dev, fmt, arg...) \ + v4l2_dbg(1, debug, &dev->v4l2_dev, "%s: " fmt, __func__, ## arg) + + +struct pixfmt_info { + u32 id; + unsigned int bytesperline_mult; + unsigned int sizeimage_mult; + unsigned int sizeimage_div; + unsigned int luma_step; + unsigned int chroma_step; + /* Chroma plane subsampling */ + unsigned int width_div; + unsigned int height_div; +}; + +static const struct v4l2_fwht_pixfmt_info pixfmt_fwht = { + V4L2_PIX_FMT_FWHT, 0, 3, 1, 1, 1, 1, 1, 0, 1 +}; + +static const struct v4l2_fwht_pixfmt_info pixfmt_stateless_fwht = { + V4L2_PIX_FMT_FWHT_STATELESS, 0, 3, 1, 1, 1, 1, 1, 0, 1 +}; + +static void vicodec_dev_release(struct device *dev) +{ +} + +static struct platform_device vicodec_pdev = { + .name = VICODEC_NAME, + .dev.release = vicodec_dev_release, +}; + +/* Per-queue, driver-specific private data */ +struct vicodec_q_data { + unsigned int coded_width; + unsigned int coded_height; + unsigned int visible_width; + unsigned int visible_height; + unsigned int sizeimage; + unsigned int vb2_sizeimage; + unsigned int sequence; + const struct v4l2_fwht_pixfmt_info *info; +}; + +enum { + V4L2_M2M_SRC = 0, + V4L2_M2M_DST = 1, +}; + +struct vicodec_dev_instance { + struct video_device vfd; + struct mutex mutex; + spinlock_t lock; + struct v4l2_m2m_dev *m2m_dev; +}; + +struct vicodec_dev { + struct v4l2_device v4l2_dev; + struct vicodec_dev_instance stateful_enc; + struct vicodec_dev_instance stateful_dec; + struct vicodec_dev_instance stateless_dec; +#ifdef CONFIG_MEDIA_CONTROLLER + struct media_device mdev; +#endif + +}; + +struct vicodec_ctx { + struct v4l2_fh fh; + struct vicodec_dev *dev; + bool is_enc; + bool is_stateless; + spinlock_t *lock; + + struct v4l2_ctrl_handler hdl; + + /* Source and destination queue data */ + struct vicodec_q_data q_data[2]; + struct v4l2_fwht_state state; + + u32 cur_buf_offset; + u32 comp_max_size; + u32 comp_size; + u32 header_size; + u32 comp_magic_cnt; + bool comp_has_frame; + bool comp_has_next_frame; + bool first_source_change_sent; + bool source_changed; +}; + +static const struct v4l2_event vicodec_eos_event = { + .type = V4L2_EVENT_EOS +}; + +static inline struct vicodec_ctx *file2ctx(struct file *file) +{ + return container_of(file->private_data, struct vicodec_ctx, fh); +} + +static struct vicodec_q_data *get_q_data(struct vicodec_ctx *ctx, + enum v4l2_buf_type type) +{ + switch (type) { + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + return &ctx->q_data[V4L2_M2M_SRC]; + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + return &ctx->q_data[V4L2_M2M_DST]; + default: + break; + } + return NULL; +} + +static void copy_cap_to_ref(const u8 *cap, const struct v4l2_fwht_pixfmt_info *info, + struct v4l2_fwht_state *state) +{ + int plane_idx; + u8 *p_ref = state->ref_frame.buf; + unsigned int cap_stride = state->stride; + unsigned int ref_stride = state->ref_stride; + + for (plane_idx = 0; plane_idx < info->planes_num; plane_idx++) { + int i; + unsigned int h_div = (plane_idx == 1 || plane_idx == 2) ? + info->height_div : 1; + const u8 *row_cap = cap; + u8 *row_ref = p_ref; + + if (info->planes_num == 3 && plane_idx == 1) { + cap_stride /= 2; + ref_stride /= 2; + } + + if (plane_idx == 1 && + (info->id == V4L2_PIX_FMT_NV24 || + info->id == V4L2_PIX_FMT_NV42)) { + cap_stride *= 2; + ref_stride *= 2; + } + + for (i = 0; i < state->visible_height / h_div; i++) { + memcpy(row_ref, row_cap, ref_stride); + row_ref += ref_stride; + row_cap += cap_stride; + } + cap += cap_stride * (state->coded_height / h_div); + p_ref += ref_stride * (state->coded_height / h_div); + } +} + +static bool validate_by_version(unsigned int flags, unsigned int version) +{ + if (!version || version > FWHT_VERSION) + return false; + + if (version >= 2) { + unsigned int components_num = 1 + + ((flags & FWHT_FL_COMPONENTS_NUM_MSK) >> + FWHT_FL_COMPONENTS_NUM_OFFSET); + unsigned int pixenc = flags & FWHT_FL_PIXENC_MSK; + + if (components_num == 0 || components_num > 4 || !pixenc) + return false; + } + return true; +} + +static bool validate_stateless_params_flags(const struct v4l2_ctrl_fwht_params *params, + const struct v4l2_fwht_pixfmt_info *cur_info) +{ + unsigned int width_div = + (params->flags & FWHT_FL_CHROMA_FULL_WIDTH) ? 1 : 2; + unsigned int height_div = + (params->flags & FWHT_FL_CHROMA_FULL_HEIGHT) ? 1 : 2; + unsigned int components_num = 3; + unsigned int pixenc = 0; + + if (params->version < 3) + return false; + + components_num = 1 + ((params->flags & FWHT_FL_COMPONENTS_NUM_MSK) >> + FWHT_FL_COMPONENTS_NUM_OFFSET); + pixenc = (params->flags & FWHT_FL_PIXENC_MSK); + if (v4l2_fwht_validate_fmt(cur_info, width_div, height_div, + components_num, pixenc)) + return true; + return false; +} + + +static void update_state_from_header(struct vicodec_ctx *ctx) +{ + const struct fwht_cframe_hdr *p_hdr = &ctx->state.header; + + ctx->state.visible_width = ntohl(p_hdr->width); + ctx->state.visible_height = ntohl(p_hdr->height); + ctx->state.colorspace = ntohl(p_hdr->colorspace); + ctx->state.xfer_func = ntohl(p_hdr->xfer_func); + ctx->state.ycbcr_enc = ntohl(p_hdr->ycbcr_enc); + ctx->state.quantization = ntohl(p_hdr->quantization); +} + +static int device_process(struct vicodec_ctx *ctx, + struct vb2_v4l2_buffer *src_vb, + struct vb2_v4l2_buffer *dst_vb) +{ + struct vicodec_dev *dev = ctx->dev; + struct v4l2_fwht_state *state = &ctx->state; + u8 *p_src, *p_dst; + int ret = 0; + + if (ctx->is_enc || ctx->is_stateless) + p_src = vb2_plane_vaddr(&src_vb->vb2_buf, 0); + else + p_src = state->compressed_frame; + + if (ctx->is_stateless) { + struct media_request *src_req = src_vb->vb2_buf.req_obj.req; + + ret = v4l2_ctrl_request_setup(src_req, &ctx->hdl); + if (ret) + return ret; + update_state_from_header(ctx); + + ctx->state.header.size = + htonl(vb2_get_plane_payload(&src_vb->vb2_buf, 0)); + /* + * set the reference buffer from the reference timestamp + * only if this is a P-frame + */ + if (!(ntohl(ctx->state.header.flags) & FWHT_FL_I_FRAME)) { + struct vb2_buffer *ref_vb2_buf; + int ref_buf_idx; + struct vb2_queue *vq_cap = + v4l2_m2m_get_vq(ctx->fh.m2m_ctx, + V4L2_BUF_TYPE_VIDEO_CAPTURE); + + ref_buf_idx = vb2_find_timestamp(vq_cap, + ctx->state.ref_frame_ts, 0); + if (ref_buf_idx < 0) + return -EINVAL; + + ref_vb2_buf = vq_cap->bufs[ref_buf_idx]; + if (ref_vb2_buf->state == VB2_BUF_STATE_ERROR) + ret = -EINVAL; + ctx->state.ref_frame.buf = + vb2_plane_vaddr(ref_vb2_buf, 0); + } else { + ctx->state.ref_frame.buf = NULL; + } + } + p_dst = vb2_plane_vaddr(&dst_vb->vb2_buf, 0); + if (!p_src || !p_dst) { + v4l2_err(&dev->v4l2_dev, + "Acquiring kernel pointers to buffers failed\n"); + return -EFAULT; + } + + if (ctx->is_enc) { + struct vicodec_q_data *q_src; + int comp_sz_or_errcode; + + q_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); + state->info = q_src->info; + comp_sz_or_errcode = v4l2_fwht_encode(state, p_src, p_dst); + if (comp_sz_or_errcode < 0) + return comp_sz_or_errcode; + vb2_set_plane_payload(&dst_vb->vb2_buf, 0, comp_sz_or_errcode); + } else { + struct vicodec_q_data *q_dst; + unsigned int comp_frame_size = ntohl(ctx->state.header.size); + + q_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + if (comp_frame_size > ctx->comp_max_size) + return -EINVAL; + state->info = q_dst->info; + ret = v4l2_fwht_decode(state, p_src, p_dst); + if (ret < 0) + return ret; + if (!ctx->is_stateless) + copy_cap_to_ref(p_dst, ctx->state.info, &ctx->state); + + vb2_set_plane_payload(&dst_vb->vb2_buf, 0, q_dst->sizeimage); + if (ntohl(ctx->state.header.flags) & FWHT_FL_I_FRAME) + dst_vb->flags |= V4L2_BUF_FLAG_KEYFRAME; + else + dst_vb->flags |= V4L2_BUF_FLAG_PFRAME; + } + return ret; +} + +/* + * mem2mem callbacks + */ +static enum vb2_buffer_state get_next_header(struct vicodec_ctx *ctx, + u8 **pp, u32 sz) +{ + static const u8 magic[] = { + 0x4f, 0x4f, 0x4f, 0x4f, 0xff, 0xff, 0xff, 0xff + }; + u8 *p = *pp; + u32 state; + u8 *header = (u8 *)&ctx->state.header; + + state = VB2_BUF_STATE_DONE; + + if (!ctx->header_size) { + state = VB2_BUF_STATE_ERROR; + for (; p < *pp + sz; p++) { + u32 copy; + + p = memchr(p, magic[ctx->comp_magic_cnt], + *pp + sz - p); + if (!p) { + ctx->comp_magic_cnt = 0; + p = *pp + sz; + break; + } + copy = sizeof(magic) - ctx->comp_magic_cnt; + if (*pp + sz - p < copy) + copy = *pp + sz - p; + + memcpy(header + ctx->comp_magic_cnt, p, copy); + ctx->comp_magic_cnt += copy; + if (!memcmp(header, magic, ctx->comp_magic_cnt)) { + p += copy; + state = VB2_BUF_STATE_DONE; + break; + } + ctx->comp_magic_cnt = 0; + } + if (ctx->comp_magic_cnt < sizeof(magic)) { + *pp = p; + return state; + } + ctx->header_size = sizeof(magic); + } + + if (ctx->header_size < sizeof(struct fwht_cframe_hdr)) { + u32 copy = sizeof(struct fwht_cframe_hdr) - ctx->header_size; + + if (*pp + sz - p < copy) + copy = *pp + sz - p; + + memcpy(header + ctx->header_size, p, copy); + p += copy; + ctx->header_size += copy; + } + *pp = p; + return state; +} + +/* device_run() - prepares and starts the device */ +static void device_run(void *priv) +{ + struct vicodec_ctx *ctx = priv; + struct vicodec_dev *dev = ctx->dev; + struct vb2_v4l2_buffer *src_buf, *dst_buf; + struct vicodec_q_data *q_src, *q_dst; + u32 state; + struct media_request *src_req; + + src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); + dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); + src_req = src_buf->vb2_buf.req_obj.req; + + q_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); + q_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + + state = VB2_BUF_STATE_DONE; + if (device_process(ctx, src_buf, dst_buf)) + state = VB2_BUF_STATE_ERROR; + else + dst_buf->sequence = q_dst->sequence++; + dst_buf->flags &= ~V4L2_BUF_FLAG_LAST; + v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, false); + + spin_lock(ctx->lock); + if (!ctx->comp_has_next_frame && + v4l2_m2m_is_last_draining_src_buf(ctx->fh.m2m_ctx, src_buf)) { + dst_buf->flags |= V4L2_BUF_FLAG_LAST; + v4l2_event_queue_fh(&ctx->fh, &vicodec_eos_event); + v4l2_m2m_mark_stopped(ctx->fh.m2m_ctx); + } + if (ctx->is_enc || ctx->is_stateless) { + src_buf->sequence = q_src->sequence++; + src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); + v4l2_m2m_buf_done(src_buf, state); + } else if (vb2_get_plane_payload(&src_buf->vb2_buf, 0) == ctx->cur_buf_offset) { + src_buf->sequence = q_src->sequence++; + src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); + v4l2_m2m_buf_done(src_buf, state); + ctx->cur_buf_offset = 0; + ctx->comp_has_next_frame = false; + } + v4l2_m2m_buf_done(dst_buf, state); + + ctx->comp_size = 0; + ctx->header_size = 0; + ctx->comp_magic_cnt = 0; + ctx->comp_has_frame = false; + spin_unlock(ctx->lock); + if (ctx->is_stateless && src_req) + v4l2_ctrl_request_complete(src_req, &ctx->hdl); + + if (ctx->is_enc) + v4l2_m2m_job_finish(dev->stateful_enc.m2m_dev, ctx->fh.m2m_ctx); + else if (ctx->is_stateless) + v4l2_m2m_job_finish(dev->stateless_dec.m2m_dev, + ctx->fh.m2m_ctx); + else + v4l2_m2m_job_finish(dev->stateful_dec.m2m_dev, ctx->fh.m2m_ctx); +} + +static void job_remove_src_buf(struct vicodec_ctx *ctx, u32 state) +{ + struct vb2_v4l2_buffer *src_buf; + struct vicodec_q_data *q_src; + + q_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); + spin_lock(ctx->lock); + src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); + src_buf->sequence = q_src->sequence++; + v4l2_m2m_buf_done(src_buf, state); + ctx->cur_buf_offset = 0; + spin_unlock(ctx->lock); +} + +static const struct v4l2_fwht_pixfmt_info * +info_from_header(const struct fwht_cframe_hdr *p_hdr) +{ + unsigned int flags = ntohl(p_hdr->flags); + unsigned int width_div = (flags & FWHT_FL_CHROMA_FULL_WIDTH) ? 1 : 2; + unsigned int height_div = (flags & FWHT_FL_CHROMA_FULL_HEIGHT) ? 1 : 2; + unsigned int components_num = 3; + unsigned int pixenc = 0; + unsigned int version = ntohl(p_hdr->version); + + if (version >= 2) { + components_num = 1 + ((flags & FWHT_FL_COMPONENTS_NUM_MSK) >> + FWHT_FL_COMPONENTS_NUM_OFFSET); + pixenc = (flags & FWHT_FL_PIXENC_MSK); + } + return v4l2_fwht_find_nth_fmt(width_div, height_div, + components_num, pixenc, 0); +} + +static bool is_header_valid(const struct fwht_cframe_hdr *p_hdr) +{ + const struct v4l2_fwht_pixfmt_info *info; + unsigned int w = ntohl(p_hdr->width); + unsigned int h = ntohl(p_hdr->height); + unsigned int version = ntohl(p_hdr->version); + unsigned int flags = ntohl(p_hdr->flags); + + if (w < MIN_WIDTH || w > MAX_WIDTH || h < MIN_HEIGHT || h > MAX_HEIGHT) + return false; + + if (!validate_by_version(flags, version)) + return false; + + info = info_from_header(p_hdr); + if (!info) + return false; + return true; +} + +static void update_capture_data_from_header(struct vicodec_ctx *ctx) +{ + struct vicodec_q_data *q_dst = get_q_data(ctx, + V4L2_BUF_TYPE_VIDEO_CAPTURE); + const struct fwht_cframe_hdr *p_hdr = &ctx->state.header; + const struct v4l2_fwht_pixfmt_info *info = info_from_header(p_hdr); + unsigned int flags = ntohl(p_hdr->flags); + unsigned int hdr_width_div = (flags & FWHT_FL_CHROMA_FULL_WIDTH) ? 1 : 2; + unsigned int hdr_height_div = (flags & FWHT_FL_CHROMA_FULL_HEIGHT) ? 1 : 2; + + /* + * This function should not be used by a stateless codec since + * it changes values in q_data that are not request specific + */ + WARN_ON(ctx->is_stateless); + + q_dst->info = info; + q_dst->visible_width = ntohl(p_hdr->width); + q_dst->visible_height = ntohl(p_hdr->height); + q_dst->coded_width = vic_round_dim(q_dst->visible_width, hdr_width_div); + q_dst->coded_height = vic_round_dim(q_dst->visible_height, + hdr_height_div); + + q_dst->sizeimage = q_dst->coded_width * q_dst->coded_height * + q_dst->info->sizeimage_mult / q_dst->info->sizeimage_div; + ctx->state.colorspace = ntohl(p_hdr->colorspace); + + ctx->state.xfer_func = ntohl(p_hdr->xfer_func); + ctx->state.ycbcr_enc = ntohl(p_hdr->ycbcr_enc); + ctx->state.quantization = ntohl(p_hdr->quantization); +} + +static void set_last_buffer(struct vb2_v4l2_buffer *dst_buf, + const struct vb2_v4l2_buffer *src_buf, + struct vicodec_ctx *ctx) +{ + struct vicodec_q_data *q_dst = get_q_data(ctx, + V4L2_BUF_TYPE_VIDEO_CAPTURE); + + vb2_set_plane_payload(&dst_buf->vb2_buf, 0, 0); + dst_buf->sequence = q_dst->sequence++; + + v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, !ctx->is_enc); + dst_buf->flags |= V4L2_BUF_FLAG_LAST; + v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE); +} + +static int job_ready(void *priv) +{ + static const u8 magic[] = { + 0x4f, 0x4f, 0x4f, 0x4f, 0xff, 0xff, 0xff, 0xff + }; + struct vicodec_ctx *ctx = priv; + struct vb2_v4l2_buffer *src_buf; + u8 *p_src; + u8 *p; + u32 sz; + u32 state; + struct vicodec_q_data *q_dst = get_q_data(ctx, + V4L2_BUF_TYPE_VIDEO_CAPTURE); + unsigned int flags; + unsigned int hdr_width_div; + unsigned int hdr_height_div; + unsigned int max_to_copy; + unsigned int comp_frame_size; + + if (ctx->source_changed) + return 0; + if (ctx->is_stateless || ctx->is_enc || ctx->comp_has_frame) + return 1; + +restart: + ctx->comp_has_next_frame = false; + src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); + if (!src_buf) + return 0; + p_src = vb2_plane_vaddr(&src_buf->vb2_buf, 0); + sz = vb2_get_plane_payload(&src_buf->vb2_buf, 0); + p = p_src + ctx->cur_buf_offset; + + state = VB2_BUF_STATE_DONE; + + if (ctx->header_size < sizeof(struct fwht_cframe_hdr)) { + state = get_next_header(ctx, &p, p_src + sz - p); + if (ctx->header_size < sizeof(struct fwht_cframe_hdr)) { + if (v4l2_m2m_is_last_draining_src_buf(ctx->fh.m2m_ctx, + src_buf)) + return 1; + job_remove_src_buf(ctx, state); + goto restart; + } + } + + comp_frame_size = ntohl(ctx->state.header.size); + + /* + * The current scanned frame might be the first frame of a new + * resolution so its size might be larger than ctx->comp_max_size. + * In that case it is copied up to the current buffer capacity and + * the copy will continue after allocating new large enough buffer + * when restreaming + */ + max_to_copy = min(comp_frame_size, ctx->comp_max_size); + + if (ctx->comp_size < max_to_copy) { + u32 copy = max_to_copy - ctx->comp_size; + + if (copy > p_src + sz - p) + copy = p_src + sz - p; + + memcpy(ctx->state.compressed_frame + ctx->comp_size, + p, copy); + p += copy; + ctx->comp_size += copy; + if (ctx->comp_size < max_to_copy) { + if (v4l2_m2m_is_last_draining_src_buf(ctx->fh.m2m_ctx, + src_buf)) + return 1; + job_remove_src_buf(ctx, state); + goto restart; + } + } + ctx->cur_buf_offset = p - p_src; + if (ctx->comp_size == comp_frame_size) + ctx->comp_has_frame = true; + ctx->comp_has_next_frame = false; + if (ctx->comp_has_frame && sz - ctx->cur_buf_offset >= + sizeof(struct fwht_cframe_hdr)) { + struct fwht_cframe_hdr *p_hdr = (struct fwht_cframe_hdr *)p; + u32 frame_size = ntohl(p_hdr->size); + u32 remaining = sz - ctx->cur_buf_offset - sizeof(*p_hdr); + + if (!memcmp(p, magic, sizeof(magic))) + ctx->comp_has_next_frame = remaining >= frame_size; + } + /* + * if the header is invalid the device_run will just drop the frame + * with an error + */ + if (!is_header_valid(&ctx->state.header) && ctx->comp_has_frame) + return 1; + flags = ntohl(ctx->state.header.flags); + hdr_width_div = (flags & FWHT_FL_CHROMA_FULL_WIDTH) ? 1 : 2; + hdr_height_div = (flags & FWHT_FL_CHROMA_FULL_HEIGHT) ? 1 : 2; + + if (ntohl(ctx->state.header.width) != q_dst->visible_width || + ntohl(ctx->state.header.height) != q_dst->visible_height || + !q_dst->info || + hdr_width_div != q_dst->info->width_div || + hdr_height_div != q_dst->info->height_div) { + static const struct v4l2_event rs_event = { + .type = V4L2_EVENT_SOURCE_CHANGE, + .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION, + }; + + struct vb2_v4l2_buffer *dst_buf = + v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); + + update_capture_data_from_header(ctx); + v4l2_event_queue_fh(&ctx->fh, &rs_event); + set_last_buffer(dst_buf, src_buf, ctx); + ctx->source_changed = true; + return 0; + } + return 1; +} + +/* + * video ioctls + */ + +static const struct v4l2_fwht_pixfmt_info *find_fmt(u32 fmt) +{ + const struct v4l2_fwht_pixfmt_info *info = + v4l2_fwht_find_pixfmt(fmt); + + if (!info) + info = v4l2_fwht_get_pixfmt(0); + return info; +} + +static int vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + strscpy(cap->driver, VICODEC_NAME, sizeof(cap->driver)); + strscpy(cap->card, VICODEC_NAME, sizeof(cap->card)); + snprintf(cap->bus_info, sizeof(cap->bus_info), + "platform:%s", VICODEC_NAME); + return 0; +} + +static int enum_fmt(struct v4l2_fmtdesc *f, struct vicodec_ctx *ctx, + bool is_out) +{ + bool is_uncomp = (ctx->is_enc && is_out) || (!ctx->is_enc && !is_out); + + if (V4L2_TYPE_IS_MULTIPLANAR(f->type) && !multiplanar) + return -EINVAL; + if (!V4L2_TYPE_IS_MULTIPLANAR(f->type) && multiplanar) + return -EINVAL; + + if (is_uncomp) { + const struct v4l2_fwht_pixfmt_info *info = + get_q_data(ctx, f->type)->info; + + if (ctx->is_enc || + !vb2_is_streaming(&ctx->fh.m2m_ctx->cap_q_ctx.q)) + info = v4l2_fwht_get_pixfmt(f->index); + else + info = v4l2_fwht_find_nth_fmt(info->width_div, + info->height_div, + info->components_num, + info->pixenc, + f->index); + if (!info) + return -EINVAL; + f->pixelformat = info->id; + } else { + if (f->index) + return -EINVAL; + f->pixelformat = ctx->is_stateless ? + V4L2_PIX_FMT_FWHT_STATELESS : V4L2_PIX_FMT_FWHT; + if (!ctx->is_enc && !ctx->is_stateless) + f->flags = V4L2_FMT_FLAG_DYN_RESOLUTION | + V4L2_FMT_FLAG_CONTINUOUS_BYTESTREAM; + } + return 0; +} + +static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + struct vicodec_ctx *ctx = file2ctx(file); + + return enum_fmt(f, ctx, false); +} + +static int vidioc_enum_fmt_vid_out(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + struct vicodec_ctx *ctx = file2ctx(file); + + return enum_fmt(f, ctx, true); +} + +static int vidioc_g_fmt(struct vicodec_ctx *ctx, struct v4l2_format *f) +{ + struct vb2_queue *vq; + struct vicodec_q_data *q_data; + struct v4l2_pix_format_mplane *pix_mp; + struct v4l2_pix_format *pix; + const struct v4l2_fwht_pixfmt_info *info; + + vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); + if (!vq) + return -EINVAL; + + q_data = get_q_data(ctx, f->type); + info = q_data->info; + + switch (f->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + if (multiplanar) + return -EINVAL; + pix = &f->fmt.pix; + pix->width = q_data->coded_width; + pix->height = q_data->coded_height; + pix->field = V4L2_FIELD_NONE; + pix->pixelformat = info->id; + pix->bytesperline = q_data->coded_width * + info->bytesperline_mult; + pix->sizeimage = q_data->sizeimage; + pix->colorspace = ctx->state.colorspace; + pix->xfer_func = ctx->state.xfer_func; + pix->ycbcr_enc = ctx->state.ycbcr_enc; + pix->quantization = ctx->state.quantization; + break; + + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + if (!multiplanar) + return -EINVAL; + pix_mp = &f->fmt.pix_mp; + pix_mp->width = q_data->coded_width; + pix_mp->height = q_data->coded_height; + pix_mp->field = V4L2_FIELD_NONE; + pix_mp->pixelformat = info->id; + pix_mp->num_planes = 1; + pix_mp->plane_fmt[0].bytesperline = + q_data->coded_width * info->bytesperline_mult; + pix_mp->plane_fmt[0].sizeimage = q_data->sizeimage; + pix_mp->colorspace = ctx->state.colorspace; + pix_mp->xfer_func = ctx->state.xfer_func; + pix_mp->ycbcr_enc = ctx->state.ycbcr_enc; + pix_mp->quantization = ctx->state.quantization; + memset(pix_mp->reserved, 0, sizeof(pix_mp->reserved)); + memset(pix_mp->plane_fmt[0].reserved, 0, + sizeof(pix_mp->plane_fmt[0].reserved)); + break; + default: + return -EINVAL; + } + return 0; +} + +static int vidioc_g_fmt_vid_out(struct file *file, void *priv, + struct v4l2_format *f) +{ + return vidioc_g_fmt(file2ctx(file), f); +} + +static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + return vidioc_g_fmt(file2ctx(file), f); +} + +static int vidioc_try_fmt(struct vicodec_ctx *ctx, struct v4l2_format *f) +{ + struct v4l2_pix_format_mplane *pix_mp; + struct v4l2_pix_format *pix; + struct v4l2_plane_pix_format *plane; + const struct v4l2_fwht_pixfmt_info *info = ctx->is_stateless ? + &pixfmt_stateless_fwht : &pixfmt_fwht; + + switch (f->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + pix = &f->fmt.pix; + if (pix->pixelformat != V4L2_PIX_FMT_FWHT && + pix->pixelformat != V4L2_PIX_FMT_FWHT_STATELESS) + info = find_fmt(pix->pixelformat); + + pix->width = clamp(pix->width, MIN_WIDTH, MAX_WIDTH); + pix->width = vic_round_dim(pix->width, info->width_div); + + pix->height = clamp(pix->height, MIN_HEIGHT, MAX_HEIGHT); + pix->height = vic_round_dim(pix->height, info->height_div); + + pix->field = V4L2_FIELD_NONE; + pix->bytesperline = + pix->width * info->bytesperline_mult; + pix->sizeimage = pix->width * pix->height * + info->sizeimage_mult / info->sizeimage_div; + if (pix->pixelformat == V4L2_PIX_FMT_FWHT) + pix->sizeimage += sizeof(struct fwht_cframe_hdr); + break; + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + pix_mp = &f->fmt.pix_mp; + plane = pix_mp->plane_fmt; + if (pix_mp->pixelformat != V4L2_PIX_FMT_FWHT && + pix_mp->pixelformat != V4L2_PIX_FMT_FWHT_STATELESS) + info = find_fmt(pix_mp->pixelformat); + pix_mp->num_planes = 1; + + pix_mp->width = clamp(pix_mp->width, MIN_WIDTH, MAX_WIDTH); + pix_mp->width = vic_round_dim(pix_mp->width, info->width_div); + + pix_mp->height = clamp(pix_mp->height, MIN_HEIGHT, MAX_HEIGHT); + pix_mp->height = vic_round_dim(pix_mp->height, + info->height_div); + + pix_mp->field = V4L2_FIELD_NONE; + plane->bytesperline = + pix_mp->width * info->bytesperline_mult; + plane->sizeimage = pix_mp->width * pix_mp->height * + info->sizeimage_mult / info->sizeimage_div; + if (pix_mp->pixelformat == V4L2_PIX_FMT_FWHT) + plane->sizeimage += sizeof(struct fwht_cframe_hdr); + memset(pix_mp->reserved, 0, sizeof(pix_mp->reserved)); + memset(plane->reserved, 0, sizeof(plane->reserved)); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct vicodec_ctx *ctx = file2ctx(file); + struct v4l2_pix_format_mplane *pix_mp; + struct v4l2_pix_format *pix; + + switch (f->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + if (multiplanar) + return -EINVAL; + pix = &f->fmt.pix; + pix->pixelformat = ctx->is_enc ? V4L2_PIX_FMT_FWHT : + find_fmt(f->fmt.pix.pixelformat)->id; + pix->colorspace = ctx->state.colorspace; + pix->xfer_func = ctx->state.xfer_func; + pix->ycbcr_enc = ctx->state.ycbcr_enc; + pix->quantization = ctx->state.quantization; + break; + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + if (!multiplanar) + return -EINVAL; + pix_mp = &f->fmt.pix_mp; + pix_mp->pixelformat = ctx->is_enc ? V4L2_PIX_FMT_FWHT : + find_fmt(pix_mp->pixelformat)->id; + pix_mp->colorspace = ctx->state.colorspace; + pix_mp->xfer_func = ctx->state.xfer_func; + pix_mp->ycbcr_enc = ctx->state.ycbcr_enc; + pix_mp->quantization = ctx->state.quantization; + break; + default: + return -EINVAL; + } + + return vidioc_try_fmt(ctx, f); +} + +static int vidioc_try_fmt_vid_out(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct vicodec_ctx *ctx = file2ctx(file); + struct v4l2_pix_format_mplane *pix_mp; + struct v4l2_pix_format *pix; + + switch (f->type) { + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + if (multiplanar) + return -EINVAL; + pix = &f->fmt.pix; + if (ctx->is_enc) + pix->pixelformat = find_fmt(pix->pixelformat)->id; + else if (ctx->is_stateless) + pix->pixelformat = V4L2_PIX_FMT_FWHT_STATELESS; + else + pix->pixelformat = V4L2_PIX_FMT_FWHT; + if (!pix->colorspace) + pix->colorspace = V4L2_COLORSPACE_REC709; + break; + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + if (!multiplanar) + return -EINVAL; + pix_mp = &f->fmt.pix_mp; + if (ctx->is_enc) + pix_mp->pixelformat = find_fmt(pix_mp->pixelformat)->id; + else if (ctx->is_stateless) + pix_mp->pixelformat = V4L2_PIX_FMT_FWHT_STATELESS; + else + pix_mp->pixelformat = V4L2_PIX_FMT_FWHT; + if (!pix_mp->colorspace) + pix_mp->colorspace = V4L2_COLORSPACE_REC709; + break; + default: + return -EINVAL; + } + + return vidioc_try_fmt(ctx, f); +} + +static int vidioc_s_fmt(struct vicodec_ctx *ctx, struct v4l2_format *f) +{ + struct vicodec_q_data *q_data; + struct vb2_queue *vq; + bool fmt_changed = true; + struct v4l2_pix_format_mplane *pix_mp; + struct v4l2_pix_format *pix; + + vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); + if (!vq) + return -EINVAL; + + q_data = get_q_data(ctx, f->type); + if (!q_data) + return -EINVAL; + + switch (f->type) { + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + pix = &f->fmt.pix; + if (ctx->is_enc && V4L2_TYPE_IS_OUTPUT(f->type)) + fmt_changed = + !q_data->info || + q_data->info->id != pix->pixelformat || + q_data->coded_width != pix->width || + q_data->coded_height != pix->height; + + if (vb2_is_busy(vq) && fmt_changed) + return -EBUSY; + + if (pix->pixelformat == V4L2_PIX_FMT_FWHT) + q_data->info = &pixfmt_fwht; + else if (pix->pixelformat == V4L2_PIX_FMT_FWHT_STATELESS) + q_data->info = &pixfmt_stateless_fwht; + else + q_data->info = find_fmt(pix->pixelformat); + q_data->coded_width = pix->width; + q_data->coded_height = pix->height; + q_data->sizeimage = pix->sizeimage; + break; + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + pix_mp = &f->fmt.pix_mp; + if (ctx->is_enc && V4L2_TYPE_IS_OUTPUT(f->type)) + fmt_changed = + !q_data->info || + q_data->info->id != pix_mp->pixelformat || + q_data->coded_width != pix_mp->width || + q_data->coded_height != pix_mp->height; + + if (vb2_is_busy(vq) && fmt_changed) + return -EBUSY; + + if (pix_mp->pixelformat == V4L2_PIX_FMT_FWHT) + q_data->info = &pixfmt_fwht; + else if (pix_mp->pixelformat == V4L2_PIX_FMT_FWHT_STATELESS) + q_data->info = &pixfmt_stateless_fwht; + else + q_data->info = find_fmt(pix_mp->pixelformat); + q_data->coded_width = pix_mp->width; + q_data->coded_height = pix_mp->height; + q_data->sizeimage = pix_mp->plane_fmt[0].sizeimage; + break; + default: + return -EINVAL; + } + + dprintk(ctx->dev, + "Setting format for type %d, coded wxh: %dx%d, fourcc: 0x%08x\n", + f->type, q_data->coded_width, q_data->coded_height, + q_data->info->id); + + return 0; +} + +static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + int ret; + + ret = vidioc_try_fmt_vid_cap(file, priv, f); + if (ret) + return ret; + + return vidioc_s_fmt(file2ctx(file), f); +} + +static int vidioc_s_fmt_vid_out(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct vicodec_ctx *ctx = file2ctx(file); + struct vicodec_q_data *q_data; + struct vicodec_q_data *q_data_cap; + struct v4l2_pix_format *pix; + struct v4l2_pix_format_mplane *pix_mp; + u32 coded_w = 0, coded_h = 0; + unsigned int size = 0; + int ret; + + q_data = get_q_data(ctx, f->type); + q_data_cap = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + + ret = vidioc_try_fmt_vid_out(file, priv, f); + if (ret) + return ret; + + if (ctx->is_enc) { + struct vb2_queue *vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); + struct vb2_queue *vq_cap = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, + V4L2_BUF_TYPE_VIDEO_CAPTURE); + const struct v4l2_fwht_pixfmt_info *info = ctx->is_stateless ? + &pixfmt_stateless_fwht : &pixfmt_fwht; + + if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { + coded_w = f->fmt.pix.width; + coded_h = f->fmt.pix.height; + } else { + coded_w = f->fmt.pix_mp.width; + coded_h = f->fmt.pix_mp.height; + } + if (vb2_is_busy(vq) && (coded_w != q_data->coded_width || + coded_h != q_data->coded_height)) + return -EBUSY; + size = coded_w * coded_h * + info->sizeimage_mult / info->sizeimage_div; + if (!ctx->is_stateless) + size += sizeof(struct fwht_cframe_hdr); + + if (vb2_is_busy(vq_cap) && size > q_data_cap->sizeimage) + return -EBUSY; + } + + ret = vidioc_s_fmt(file2ctx(file), f); + if (!ret) { + if (ctx->is_enc) { + q_data->visible_width = coded_w; + q_data->visible_height = coded_h; + q_data_cap->coded_width = coded_w; + q_data_cap->coded_height = coded_h; + q_data_cap->sizeimage = size; + } + + switch (f->type) { + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + pix = &f->fmt.pix; + ctx->state.colorspace = pix->colorspace; + ctx->state.xfer_func = pix->xfer_func; + ctx->state.ycbcr_enc = pix->ycbcr_enc; + ctx->state.quantization = pix->quantization; + break; + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: + pix_mp = &f->fmt.pix_mp; + ctx->state.colorspace = pix_mp->colorspace; + ctx->state.xfer_func = pix_mp->xfer_func; + ctx->state.ycbcr_enc = pix_mp->ycbcr_enc; + ctx->state.quantization = pix_mp->quantization; + break; + default: + break; + } + } + return ret; +} + +static int vidioc_g_selection(struct file *file, void *priv, + struct v4l2_selection *s) +{ + struct vicodec_ctx *ctx = file2ctx(file); + struct vicodec_q_data *q_data; + + q_data = get_q_data(ctx, s->type); + if (!q_data) + return -EINVAL; + /* + * encoder supports only cropping on the OUTPUT buffer + * decoder supports only composing on the CAPTURE buffer + */ + if (ctx->is_enc && s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { + switch (s->target) { + case V4L2_SEL_TGT_CROP: + s->r.left = 0; + s->r.top = 0; + s->r.width = q_data->visible_width; + s->r.height = q_data->visible_height; + return 0; + case V4L2_SEL_TGT_CROP_DEFAULT: + case V4L2_SEL_TGT_CROP_BOUNDS: + s->r.left = 0; + s->r.top = 0; + s->r.width = q_data->coded_width; + s->r.height = q_data->coded_height; + return 0; + } + } else if (!ctx->is_enc && s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { + switch (s->target) { + case V4L2_SEL_TGT_COMPOSE: + s->r.left = 0; + s->r.top = 0; + s->r.width = q_data->visible_width; + s->r.height = q_data->visible_height; + return 0; + case V4L2_SEL_TGT_COMPOSE_DEFAULT: + case V4L2_SEL_TGT_COMPOSE_BOUNDS: + s->r.left = 0; + s->r.top = 0; + s->r.width = q_data->coded_width; + s->r.height = q_data->coded_height; + return 0; + } + } + return -EINVAL; +} + +static int vidioc_s_selection(struct file *file, void *priv, + struct v4l2_selection *s) +{ + struct vicodec_ctx *ctx = file2ctx(file); + struct vicodec_q_data *q_data; + + if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) + return -EINVAL; + + q_data = get_q_data(ctx, s->type); + if (!q_data) + return -EINVAL; + + if (!ctx->is_enc || s->target != V4L2_SEL_TGT_CROP) + return -EINVAL; + + s->r.left = 0; + s->r.top = 0; + q_data->visible_width = clamp(s->r.width, MIN_WIDTH, + q_data->coded_width); + s->r.width = q_data->visible_width; + q_data->visible_height = clamp(s->r.height, MIN_HEIGHT, + q_data->coded_height); + s->r.height = q_data->visible_height; + return 0; +} + +static int vicodec_encoder_cmd(struct file *file, void *fh, + struct v4l2_encoder_cmd *ec) +{ + struct vicodec_ctx *ctx = file2ctx(file); + int ret; + + ret = v4l2_m2m_ioctl_try_encoder_cmd(file, fh, ec); + if (ret < 0) + return ret; + + if (!vb2_is_streaming(&ctx->fh.m2m_ctx->cap_q_ctx.q) || + !vb2_is_streaming(&ctx->fh.m2m_ctx->out_q_ctx.q)) + return 0; + + ret = v4l2_m2m_ioctl_encoder_cmd(file, fh, ec); + if (ret < 0) + return ret; + + if (ec->cmd == V4L2_ENC_CMD_STOP && + v4l2_m2m_has_stopped(ctx->fh.m2m_ctx)) + v4l2_event_queue_fh(&ctx->fh, &vicodec_eos_event); + + if (ec->cmd == V4L2_ENC_CMD_START && + v4l2_m2m_has_stopped(ctx->fh.m2m_ctx)) + vb2_clear_last_buffer_dequeued(&ctx->fh.m2m_ctx->cap_q_ctx.q); + + return 0; +} + +static int vicodec_decoder_cmd(struct file *file, void *fh, + struct v4l2_decoder_cmd *dc) +{ + struct vicodec_ctx *ctx = file2ctx(file); + int ret; + + ret = v4l2_m2m_ioctl_try_decoder_cmd(file, fh, dc); + if (ret < 0) + return ret; + + if (!vb2_is_streaming(&ctx->fh.m2m_ctx->cap_q_ctx.q) || + !vb2_is_streaming(&ctx->fh.m2m_ctx->out_q_ctx.q)) + return 0; + + ret = v4l2_m2m_ioctl_decoder_cmd(file, fh, dc); + if (ret < 0) + return ret; + + if (dc->cmd == V4L2_DEC_CMD_STOP && + v4l2_m2m_has_stopped(ctx->fh.m2m_ctx)) + v4l2_event_queue_fh(&ctx->fh, &vicodec_eos_event); + + if (dc->cmd == V4L2_DEC_CMD_START && + v4l2_m2m_has_stopped(ctx->fh.m2m_ctx)) + vb2_clear_last_buffer_dequeued(&ctx->fh.m2m_ctx->cap_q_ctx.q); + + return 0; +} + +static int vicodec_enum_framesizes(struct file *file, void *fh, + struct v4l2_frmsizeenum *fsize) +{ + switch (fsize->pixel_format) { + case V4L2_PIX_FMT_FWHT_STATELESS: + break; + case V4L2_PIX_FMT_FWHT: + break; + default: + if (find_fmt(fsize->pixel_format)->id == fsize->pixel_format) + break; + return -EINVAL; + } + + if (fsize->index) + return -EINVAL; + + fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; + + fsize->stepwise.min_width = MIN_WIDTH; + fsize->stepwise.max_width = MAX_WIDTH; + fsize->stepwise.step_width = 8; + fsize->stepwise.min_height = MIN_HEIGHT; + fsize->stepwise.max_height = MAX_HEIGHT; + fsize->stepwise.step_height = 8; + + return 0; +} + +static int vicodec_subscribe_event(struct v4l2_fh *fh, + const struct v4l2_event_subscription *sub) +{ + struct vicodec_ctx *ctx = container_of(fh, struct vicodec_ctx, fh); + + switch (sub->type) { + case V4L2_EVENT_SOURCE_CHANGE: + if (ctx->is_enc) + return -EINVAL; + /* fall through */ + case V4L2_EVENT_EOS: + if (ctx->is_stateless) + return -EINVAL; + return v4l2_event_subscribe(fh, sub, 0, NULL); + default: + return v4l2_ctrl_subscribe_event(fh, sub); + } +} + +static const struct v4l2_ioctl_ops vicodec_ioctl_ops = { + .vidioc_querycap = vidioc_querycap, + + .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, + .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, + + .vidioc_g_fmt_vid_cap_mplane = vidioc_g_fmt_vid_cap, + .vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt_vid_cap, + .vidioc_s_fmt_vid_cap_mplane = vidioc_s_fmt_vid_cap, + + .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out, + .vidioc_g_fmt_vid_out = vidioc_g_fmt_vid_out, + .vidioc_try_fmt_vid_out = vidioc_try_fmt_vid_out, + .vidioc_s_fmt_vid_out = vidioc_s_fmt_vid_out, + + .vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt_vid_out, + .vidioc_try_fmt_vid_out_mplane = vidioc_try_fmt_vid_out, + .vidioc_s_fmt_vid_out_mplane = vidioc_s_fmt_vid_out, + + .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, + .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, + .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, + .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, + .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf, + .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs, + .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, + + .vidioc_streamon = v4l2_m2m_ioctl_streamon, + .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, + + .vidioc_g_selection = vidioc_g_selection, + .vidioc_s_selection = vidioc_s_selection, + + .vidioc_try_encoder_cmd = v4l2_m2m_ioctl_try_encoder_cmd, + .vidioc_encoder_cmd = vicodec_encoder_cmd, + .vidioc_try_decoder_cmd = v4l2_m2m_ioctl_try_decoder_cmd, + .vidioc_decoder_cmd = vicodec_decoder_cmd, + .vidioc_enum_framesizes = vicodec_enum_framesizes, + + .vidioc_subscribe_event = vicodec_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, +}; + + +/* + * Queue operations + */ + +static int vicodec_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, + unsigned int *nplanes, unsigned int sizes[], + struct device *alloc_devs[]) +{ + struct vicodec_ctx *ctx = vb2_get_drv_priv(vq); + struct vicodec_q_data *q_data = get_q_data(ctx, vq->type); + unsigned int size = q_data->sizeimage; + + if (*nplanes) + return sizes[0] < size ? -EINVAL : 0; + + *nplanes = 1; + sizes[0] = size; + q_data->vb2_sizeimage = size; + return 0; +} + +static int vicodec_buf_out_validate(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + + vbuf->field = V4L2_FIELD_NONE; + return 0; +} + +static int vicodec_buf_prepare(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct vicodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + struct vicodec_q_data *q_data; + + dprintk(ctx->dev, "type: %d\n", vb->vb2_queue->type); + + q_data = get_q_data(ctx, vb->vb2_queue->type); + if (V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) { + if (vbuf->field == V4L2_FIELD_ANY) + vbuf->field = V4L2_FIELD_NONE; + if (vbuf->field != V4L2_FIELD_NONE) { + dprintk(ctx->dev, "%s field isn't supported\n", + __func__); + return -EINVAL; + } + } + + if (vb2_plane_size(vb, 0) < q_data->vb2_sizeimage) { + dprintk(ctx->dev, + "%s data will not fit into plane (%lu < %lu)\n", + __func__, vb2_plane_size(vb, 0), + (long)q_data->vb2_sizeimage); + return -EINVAL; + } + + return 0; +} + +static void vicodec_buf_queue(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct vicodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + unsigned int sz = vb2_get_plane_payload(&vbuf->vb2_buf, 0); + u8 *p_src = vb2_plane_vaddr(&vbuf->vb2_buf, 0); + u8 *p = p_src; + struct vb2_queue *vq_out = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, + V4L2_BUF_TYPE_VIDEO_OUTPUT); + struct vb2_queue *vq_cap = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, + V4L2_BUF_TYPE_VIDEO_CAPTURE); + bool header_valid = false; + static const struct v4l2_event rs_event = { + .type = V4L2_EVENT_SOURCE_CHANGE, + .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION, + }; + + if (!V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type) && + vb2_is_streaming(vb->vb2_queue) && + v4l2_m2m_dst_buf_is_last(ctx->fh.m2m_ctx)) { + unsigned int i; + + for (i = 0; i < vb->num_planes; i++) + vb->planes[i].bytesused = 0; + + vbuf->field = V4L2_FIELD_NONE; + vbuf->sequence = + get_q_data(ctx, vb->vb2_queue->type)->sequence++; + + v4l2_m2m_last_buffer_done(ctx->fh.m2m_ctx, vbuf); + v4l2_event_queue_fh(&ctx->fh, &vicodec_eos_event); + return; + } + + /* buf_queue handles only the first source change event */ + if (ctx->first_source_change_sent) { + v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); + return; + } + + /* + * if both queues are streaming, the source change event is + * handled in job_ready + */ + if (vb2_is_streaming(vq_cap) && vb2_is_streaming(vq_out)) { + v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); + return; + } + + /* + * source change event is relevant only for the stateful decoder + * in the compressed stream + */ + if (ctx->is_stateless || ctx->is_enc || + !V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) { + v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); + return; + } + + do { + enum vb2_buffer_state state = + get_next_header(ctx, &p, p_src + sz - p); + + if (ctx->header_size < sizeof(struct fwht_cframe_hdr)) { + v4l2_m2m_buf_done(vbuf, state); + return; + } + header_valid = is_header_valid(&ctx->state.header); + /* + * p points right after the end of the header in the + * buffer. If the header is invalid we set p to point + * to the next byte after the start of the header + */ + if (!header_valid) { + p = p - sizeof(struct fwht_cframe_hdr) + 1; + if (p < p_src) + p = p_src; + ctx->header_size = 0; + ctx->comp_magic_cnt = 0; + } + + } while (!header_valid); + + ctx->cur_buf_offset = p - p_src; + update_capture_data_from_header(ctx); + ctx->first_source_change_sent = true; + v4l2_event_queue_fh(&ctx->fh, &rs_event); + v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); +} + +static void vicodec_return_bufs(struct vb2_queue *q, u32 state) +{ + struct vicodec_ctx *ctx = vb2_get_drv_priv(q); + struct vb2_v4l2_buffer *vbuf; + + for (;;) { + if (V4L2_TYPE_IS_OUTPUT(q->type)) + vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); + else + vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); + if (vbuf == NULL) + return; + v4l2_ctrl_request_complete(vbuf->vb2_buf.req_obj.req, + &ctx->hdl); + spin_lock(ctx->lock); + v4l2_m2m_buf_done(vbuf, state); + spin_unlock(ctx->lock); + } +} + +static unsigned int total_frame_size(struct vicodec_q_data *q_data) +{ + unsigned int size; + unsigned int chroma_div; + + if (!q_data->info) { + WARN_ON(1); + return 0; + } + size = q_data->coded_width * q_data->coded_height; + chroma_div = q_data->info->width_div * q_data->info->height_div; + + if (q_data->info->components_num == 4) + return 2 * size + 2 * (size / chroma_div); + else if (q_data->info->components_num == 3) + return size + 2 * (size / chroma_div); + return size; +} + +static int vicodec_start_streaming(struct vb2_queue *q, + unsigned int count) +{ + struct vicodec_ctx *ctx = vb2_get_drv_priv(q); + struct vicodec_q_data *q_data = get_q_data(ctx, q->type); + struct v4l2_fwht_state *state = &ctx->state; + const struct v4l2_fwht_pixfmt_info *info = q_data->info; + unsigned int size = q_data->coded_width * q_data->coded_height; + unsigned int chroma_div; + unsigned int total_planes_size; + u8 *new_comp_frame = NULL; + + chroma_div = info->width_div * info->height_div; + q_data->sequence = 0; + + v4l2_m2m_update_start_streaming_state(ctx->fh.m2m_ctx, q); + + state->gop_cnt = 0; + + if ((V4L2_TYPE_IS_OUTPUT(q->type) && !ctx->is_enc) || + (!V4L2_TYPE_IS_OUTPUT(q->type) && ctx->is_enc)) + return 0; + + if (info->id == V4L2_PIX_FMT_FWHT || + info->id == V4L2_PIX_FMT_FWHT_STATELESS) { + vicodec_return_bufs(q, VB2_BUF_STATE_QUEUED); + return -EINVAL; + } + total_planes_size = total_frame_size(q_data); + ctx->comp_max_size = total_planes_size; + + state->visible_width = q_data->visible_width; + state->visible_height = q_data->visible_height; + state->coded_width = q_data->coded_width; + state->coded_height = q_data->coded_height; + state->stride = q_data->coded_width * + info->bytesperline_mult; + + if (ctx->is_stateless) { + state->ref_stride = state->stride; + return 0; + } + state->ref_stride = q_data->coded_width * info->luma_alpha_step; + + state->ref_frame.buf = kvmalloc(total_planes_size, GFP_KERNEL); + state->ref_frame.luma = state->ref_frame.buf; + new_comp_frame = kvmalloc(ctx->comp_max_size, GFP_KERNEL); + + if (!state->ref_frame.luma || !new_comp_frame) { + kvfree(state->ref_frame.luma); + kvfree(new_comp_frame); + vicodec_return_bufs(q, VB2_BUF_STATE_QUEUED); + return -ENOMEM; + } + /* + * if state->compressed_frame was already allocated then + * it contain data of the first frame of the new resolution + */ + if (state->compressed_frame) { + if (ctx->comp_size > ctx->comp_max_size) + ctx->comp_size = ctx->comp_max_size; + + memcpy(new_comp_frame, + state->compressed_frame, ctx->comp_size); + } + + kvfree(state->compressed_frame); + state->compressed_frame = new_comp_frame; + + if (info->components_num < 3) { + state->ref_frame.cb = NULL; + state->ref_frame.cr = NULL; + state->ref_frame.alpha = NULL; + return 0; + } + + state->ref_frame.cb = state->ref_frame.luma + size; + state->ref_frame.cr = state->ref_frame.cb + size / chroma_div; + + if (info->components_num == 4) + state->ref_frame.alpha = + state->ref_frame.cr + size / chroma_div; + else + state->ref_frame.alpha = NULL; + + return 0; +} + +static void vicodec_stop_streaming(struct vb2_queue *q) +{ + struct vicodec_ctx *ctx = vb2_get_drv_priv(q); + + vicodec_return_bufs(q, VB2_BUF_STATE_ERROR); + + v4l2_m2m_update_stop_streaming_state(ctx->fh.m2m_ctx, q); + + if (V4L2_TYPE_IS_OUTPUT(q->type) && + v4l2_m2m_has_stopped(ctx->fh.m2m_ctx)) + v4l2_event_queue_fh(&ctx->fh, &vicodec_eos_event); + + if (!ctx->is_enc && V4L2_TYPE_IS_OUTPUT(q->type)) + ctx->first_source_change_sent = false; + + if ((!V4L2_TYPE_IS_OUTPUT(q->type) && !ctx->is_enc) || + (V4L2_TYPE_IS_OUTPUT(q->type) && ctx->is_enc)) { + if (!ctx->is_stateless) + kvfree(ctx->state.ref_frame.buf); + ctx->state.ref_frame.buf = NULL; + ctx->state.ref_frame.luma = NULL; + ctx->comp_max_size = 0; + ctx->source_changed = false; + } + if (V4L2_TYPE_IS_OUTPUT(q->type) && !ctx->is_enc) { + ctx->cur_buf_offset = 0; + ctx->comp_size = 0; + ctx->header_size = 0; + ctx->comp_magic_cnt = 0; + ctx->comp_has_frame = 0; + ctx->comp_has_next_frame = 0; + } +} + +static void vicodec_buf_request_complete(struct vb2_buffer *vb) +{ + struct vicodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + + v4l2_ctrl_request_complete(vb->req_obj.req, &ctx->hdl); +} + + +static const struct vb2_ops vicodec_qops = { + .queue_setup = vicodec_queue_setup, + .buf_out_validate = vicodec_buf_out_validate, + .buf_prepare = vicodec_buf_prepare, + .buf_queue = vicodec_buf_queue, + .buf_request_complete = vicodec_buf_request_complete, + .start_streaming = vicodec_start_streaming, + .stop_streaming = vicodec_stop_streaming, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, +}; + +static int queue_init(void *priv, struct vb2_queue *src_vq, + struct vb2_queue *dst_vq) +{ + struct vicodec_ctx *ctx = priv; + int ret; + + src_vq->type = (multiplanar ? + V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE : + V4L2_BUF_TYPE_VIDEO_OUTPUT); + src_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; + src_vq->drv_priv = ctx; + src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); + src_vq->ops = &vicodec_qops; + src_vq->mem_ops = &vb2_vmalloc_memops; + src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; + if (ctx->is_enc) + src_vq->lock = &ctx->dev->stateful_enc.mutex; + else if (ctx->is_stateless) + src_vq->lock = &ctx->dev->stateless_dec.mutex; + else + src_vq->lock = &ctx->dev->stateful_dec.mutex; + src_vq->supports_requests = ctx->is_stateless; + src_vq->requires_requests = ctx->is_stateless; + ret = vb2_queue_init(src_vq); + if (ret) + return ret; + + dst_vq->type = (multiplanar ? + V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE : + V4L2_BUF_TYPE_VIDEO_CAPTURE); + dst_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; + dst_vq->drv_priv = ctx; + dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); + dst_vq->ops = &vicodec_qops; + dst_vq->mem_ops = &vb2_vmalloc_memops; + dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; + dst_vq->lock = src_vq->lock; + + return vb2_queue_init(dst_vq); +} + +static int vicodec_try_ctrl(struct v4l2_ctrl *ctrl) +{ + struct vicodec_ctx *ctx = container_of(ctrl->handler, + struct vicodec_ctx, hdl); + const struct v4l2_ctrl_fwht_params *params; + struct vicodec_q_data *q_dst = get_q_data(ctx, + V4L2_BUF_TYPE_VIDEO_CAPTURE); + + switch (ctrl->id) { + case V4L2_CID_MPEG_VIDEO_FWHT_PARAMS: + if (!q_dst->info) + return -EINVAL; + params = ctrl->p_new.p_fwht_params; + if (params->width > q_dst->coded_width || + params->width < MIN_WIDTH || + params->height > q_dst->coded_height || + params->height < MIN_HEIGHT) + return -EINVAL; + if (!validate_by_version(params->flags, params->version)) + return -EINVAL; + if (!validate_stateless_params_flags(params, q_dst->info)) + return -EINVAL; + return 0; + default: + return 0; + } + return 0; +} + +static void update_header_from_stateless_params(struct vicodec_ctx *ctx, + const struct v4l2_ctrl_fwht_params *params) +{ + struct fwht_cframe_hdr *p_hdr = &ctx->state.header; + + p_hdr->magic1 = FWHT_MAGIC1; + p_hdr->magic2 = FWHT_MAGIC2; + p_hdr->version = htonl(params->version); + p_hdr->width = htonl(params->width); + p_hdr->height = htonl(params->height); + p_hdr->flags = htonl(params->flags); + p_hdr->colorspace = htonl(params->colorspace); + p_hdr->xfer_func = htonl(params->xfer_func); + p_hdr->ycbcr_enc = htonl(params->ycbcr_enc); + p_hdr->quantization = htonl(params->quantization); +} + +static int vicodec_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct vicodec_ctx *ctx = container_of(ctrl->handler, + struct vicodec_ctx, hdl); + const struct v4l2_ctrl_fwht_params *params; + + switch (ctrl->id) { + case V4L2_CID_MPEG_VIDEO_GOP_SIZE: + ctx->state.gop_size = ctrl->val; + return 0; + case V4L2_CID_FWHT_I_FRAME_QP: + ctx->state.i_frame_qp = ctrl->val; + return 0; + case V4L2_CID_FWHT_P_FRAME_QP: + ctx->state.p_frame_qp = ctrl->val; + return 0; + case V4L2_CID_MPEG_VIDEO_FWHT_PARAMS: + params = ctrl->p_new.p_fwht_params; + update_header_from_stateless_params(ctx, params); + ctx->state.ref_frame_ts = params->backward_ref_ts; + return 0; + } + return -EINVAL; +} + +static const struct v4l2_ctrl_ops vicodec_ctrl_ops = { + .s_ctrl = vicodec_s_ctrl, + .try_ctrl = vicodec_try_ctrl, +}; + +static const struct v4l2_ctrl_config vicodec_ctrl_stateless_state = { + .ops = &vicodec_ctrl_ops, + .id = V4L2_CID_MPEG_VIDEO_FWHT_PARAMS, + .elem_size = sizeof(struct v4l2_ctrl_fwht_params), +}; + +/* + * File operations + */ +static int vicodec_open(struct file *file) +{ + const struct v4l2_fwht_pixfmt_info *info = v4l2_fwht_get_pixfmt(0); + struct video_device *vfd = video_devdata(file); + struct vicodec_dev *dev = video_drvdata(file); + struct vicodec_ctx *ctx = NULL; + struct v4l2_ctrl_handler *hdl; + unsigned int raw_size; + unsigned int comp_size; + int rc = 0; + + if (mutex_lock_interruptible(vfd->lock)) + return -ERESTARTSYS; + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) { + rc = -ENOMEM; + goto open_unlock; + } + + if (vfd == &dev->stateful_enc.vfd) + ctx->is_enc = true; + else if (vfd == &dev->stateless_dec.vfd) + ctx->is_stateless = true; + + v4l2_fh_init(&ctx->fh, video_devdata(file)); + file->private_data = &ctx->fh; + ctx->dev = dev; + hdl = &ctx->hdl; + v4l2_ctrl_handler_init(hdl, 5); + v4l2_ctrl_new_std(hdl, &vicodec_ctrl_ops, V4L2_CID_MPEG_VIDEO_GOP_SIZE, + 1, 16, 1, 10); + v4l2_ctrl_new_std(hdl, &vicodec_ctrl_ops, V4L2_CID_FWHT_I_FRAME_QP, + 1, 31, 1, 20); + v4l2_ctrl_new_std(hdl, &vicodec_ctrl_ops, V4L2_CID_FWHT_P_FRAME_QP, + 1, 31, 1, 20); + if (ctx->is_enc) + v4l2_ctrl_new_std(hdl, &vicodec_ctrl_ops, + V4L2_CID_MIN_BUFFERS_FOR_OUTPUT, 1, 1, 1, 1); + if (ctx->is_stateless) + v4l2_ctrl_new_custom(hdl, &vicodec_ctrl_stateless_state, NULL); + if (hdl->error) { + rc = hdl->error; + v4l2_ctrl_handler_free(hdl); + kfree(ctx); + goto open_unlock; + } + ctx->fh.ctrl_handler = hdl; + v4l2_ctrl_handler_setup(hdl); + + if (ctx->is_enc) + ctx->q_data[V4L2_M2M_SRC].info = info; + else if (ctx->is_stateless) + ctx->q_data[V4L2_M2M_SRC].info = &pixfmt_stateless_fwht; + else + ctx->q_data[V4L2_M2M_SRC].info = &pixfmt_fwht; + ctx->q_data[V4L2_M2M_SRC].coded_width = 1280; + ctx->q_data[V4L2_M2M_SRC].coded_height = 720; + ctx->q_data[V4L2_M2M_SRC].visible_width = 1280; + ctx->q_data[V4L2_M2M_SRC].visible_height = 720; + raw_size = 1280 * 720 * info->sizeimage_mult / info->sizeimage_div; + comp_size = 1280 * 720 * pixfmt_fwht.sizeimage_mult / + pixfmt_fwht.sizeimage_div; + if (ctx->is_enc) + ctx->q_data[V4L2_M2M_SRC].sizeimage = raw_size; + else if (ctx->is_stateless) + ctx->q_data[V4L2_M2M_SRC].sizeimage = comp_size; + else + ctx->q_data[V4L2_M2M_SRC].sizeimage = + comp_size + sizeof(struct fwht_cframe_hdr); + ctx->q_data[V4L2_M2M_DST] = ctx->q_data[V4L2_M2M_SRC]; + if (ctx->is_enc) { + ctx->q_data[V4L2_M2M_DST].info = &pixfmt_fwht; + ctx->q_data[V4L2_M2M_DST].sizeimage = + comp_size + sizeof(struct fwht_cframe_hdr); + } else { + ctx->q_data[V4L2_M2M_DST].info = info; + ctx->q_data[V4L2_M2M_DST].sizeimage = raw_size; + } + + ctx->state.colorspace = V4L2_COLORSPACE_REC709; + + if (ctx->is_enc) { + ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->stateful_enc.m2m_dev, + ctx, &queue_init); + ctx->lock = &dev->stateful_enc.lock; + } else if (ctx->is_stateless) { + ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->stateless_dec.m2m_dev, + ctx, &queue_init); + ctx->lock = &dev->stateless_dec.lock; + } else { + ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->stateful_dec.m2m_dev, + ctx, &queue_init); + ctx->lock = &dev->stateful_dec.lock; + } + + if (IS_ERR(ctx->fh.m2m_ctx)) { + rc = PTR_ERR(ctx->fh.m2m_ctx); + + v4l2_ctrl_handler_free(hdl); + v4l2_fh_exit(&ctx->fh); + kfree(ctx); + goto open_unlock; + } + + v4l2_fh_add(&ctx->fh); + +open_unlock: + mutex_unlock(vfd->lock); + return rc; +} + +static int vicodec_release(struct file *file) +{ + struct video_device *vfd = video_devdata(file); + struct vicodec_ctx *ctx = file2ctx(file); + + mutex_lock(vfd->lock); + v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); + mutex_unlock(vfd->lock); + v4l2_fh_del(&ctx->fh); + v4l2_fh_exit(&ctx->fh); + v4l2_ctrl_handler_free(&ctx->hdl); + kvfree(ctx->state.compressed_frame); + kfree(ctx); + + return 0; +} + +static int vicodec_request_validate(struct media_request *req) +{ + struct media_request_object *obj; + struct v4l2_ctrl_handler *parent_hdl, *hdl; + struct vicodec_ctx *ctx = NULL; + struct v4l2_ctrl *ctrl; + unsigned int count; + + list_for_each_entry(obj, &req->objects, list) { + struct vb2_buffer *vb; + + if (vb2_request_object_is_buffer(obj)) { + vb = container_of(obj, struct vb2_buffer, req_obj); + ctx = vb2_get_drv_priv(vb->vb2_queue); + + break; + } + } + + if (!ctx) { + pr_err("No buffer was provided with the request\n"); + return -ENOENT; + } + + count = vb2_request_buffer_cnt(req); + if (!count) { + v4l2_info(&ctx->dev->v4l2_dev, + "No buffer was provided with the request\n"); + return -ENOENT; + } else if (count > 1) { + v4l2_info(&ctx->dev->v4l2_dev, + "More than one buffer was provided with the request\n"); + return -EINVAL; + } + + parent_hdl = &ctx->hdl; + + hdl = v4l2_ctrl_request_hdl_find(req, parent_hdl); + if (!hdl) { + v4l2_info(&ctx->dev->v4l2_dev, "Missing codec control\n"); + return -ENOENT; + } + ctrl = v4l2_ctrl_request_hdl_ctrl_find(hdl, + vicodec_ctrl_stateless_state.id); + if (!ctrl) { + v4l2_info(&ctx->dev->v4l2_dev, + "Missing required codec control\n"); + return -ENOENT; + } + + return vb2_request_validate(req); +} + +static const struct v4l2_file_operations vicodec_fops = { + .owner = THIS_MODULE, + .open = vicodec_open, + .release = vicodec_release, + .poll = v4l2_m2m_fop_poll, + .unlocked_ioctl = video_ioctl2, + .mmap = v4l2_m2m_fop_mmap, +}; + +static const struct video_device vicodec_videodev = { + .name = VICODEC_NAME, + .vfl_dir = VFL_DIR_M2M, + .fops = &vicodec_fops, + .ioctl_ops = &vicodec_ioctl_ops, + .minor = -1, + .release = video_device_release_empty, +}; + +static const struct media_device_ops vicodec_m2m_media_ops = { + .req_validate = vicodec_request_validate, + .req_queue = v4l2_m2m_request_queue, +}; + +static const struct v4l2_m2m_ops m2m_ops = { + .device_run = device_run, + .job_ready = job_ready, +}; + +static int register_instance(struct vicodec_dev *dev, + struct vicodec_dev_instance *dev_instance, + const char *name, bool is_enc) +{ + struct video_device *vfd; + int ret; + + spin_lock_init(&dev_instance->lock); + mutex_init(&dev_instance->mutex); + dev_instance->m2m_dev = v4l2_m2m_init(&m2m_ops); + if (IS_ERR(dev_instance->m2m_dev)) { + v4l2_err(&dev->v4l2_dev, "Failed to init vicodec enc device\n"); + return PTR_ERR(dev_instance->m2m_dev); + } + + dev_instance->vfd = vicodec_videodev; + vfd = &dev_instance->vfd; + vfd->lock = &dev_instance->mutex; + vfd->v4l2_dev = &dev->v4l2_dev; + strscpy(vfd->name, name, sizeof(vfd->name)); + vfd->device_caps = V4L2_CAP_STREAMING | + (multiplanar ? V4L2_CAP_VIDEO_M2M_MPLANE : V4L2_CAP_VIDEO_M2M); + if (is_enc) { + v4l2_disable_ioctl(vfd, VIDIOC_DECODER_CMD); + v4l2_disable_ioctl(vfd, VIDIOC_TRY_DECODER_CMD); + } else { + v4l2_disable_ioctl(vfd, VIDIOC_ENCODER_CMD); + v4l2_disable_ioctl(vfd, VIDIOC_TRY_ENCODER_CMD); + } + video_set_drvdata(vfd, dev); + + ret = video_register_device(vfd, VFL_TYPE_VIDEO, 0); + if (ret) { + v4l2_err(&dev->v4l2_dev, "Failed to register video device '%s'\n", name); + v4l2_m2m_release(dev_instance->m2m_dev); + return ret; + } + v4l2_info(&dev->v4l2_dev, "Device '%s' registered as /dev/video%d\n", + name, vfd->num); + return 0; +} + +static void vicodec_v4l2_dev_release(struct v4l2_device *v4l2_dev) +{ + struct vicodec_dev *dev = container_of(v4l2_dev, struct vicodec_dev, v4l2_dev); + + v4l2_device_unregister(&dev->v4l2_dev); + v4l2_m2m_release(dev->stateful_enc.m2m_dev); + v4l2_m2m_release(dev->stateful_dec.m2m_dev); + v4l2_m2m_release(dev->stateless_dec.m2m_dev); +#ifdef CONFIG_MEDIA_CONTROLLER + media_device_cleanup(&dev->mdev); +#endif + kfree(dev); +} + +static int vicodec_probe(struct platform_device *pdev) +{ + struct vicodec_dev *dev; + int ret; + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) + return -ENOMEM; + + ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); + if (ret) + goto free_dev; + + dev->v4l2_dev.release = vicodec_v4l2_dev_release; + +#ifdef CONFIG_MEDIA_CONTROLLER + dev->mdev.dev = &pdev->dev; + strscpy(dev->mdev.model, "vicodec", sizeof(dev->mdev.model)); + strscpy(dev->mdev.bus_info, "platform:vicodec", + sizeof(dev->mdev.bus_info)); + media_device_init(&dev->mdev); + dev->mdev.ops = &vicodec_m2m_media_ops; + dev->v4l2_dev.mdev = &dev->mdev; +#endif + + platform_set_drvdata(pdev, dev); + + if (register_instance(dev, &dev->stateful_enc, + "stateful-encoder", true)) + goto unreg_dev; + + if (register_instance(dev, &dev->stateful_dec, + "stateful-decoder", false)) + goto unreg_sf_enc; + + if (register_instance(dev, &dev->stateless_dec, + "stateless-decoder", false)) + goto unreg_sf_dec; + +#ifdef CONFIG_MEDIA_CONTROLLER + ret = v4l2_m2m_register_media_controller(dev->stateful_enc.m2m_dev, + &dev->stateful_enc.vfd, + MEDIA_ENT_F_PROC_VIDEO_ENCODER); + if (ret) { + v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem media controller for enc\n"); + goto unreg_m2m; + } + + ret = v4l2_m2m_register_media_controller(dev->stateful_dec.m2m_dev, + &dev->stateful_dec.vfd, + MEDIA_ENT_F_PROC_VIDEO_DECODER); + if (ret) { + v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem media controller for dec\n"); + goto unreg_m2m_sf_enc_mc; + } + + ret = v4l2_m2m_register_media_controller(dev->stateless_dec.m2m_dev, + &dev->stateless_dec.vfd, + MEDIA_ENT_F_PROC_VIDEO_DECODER); + if (ret) { + v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem media controller for stateless dec\n"); + goto unreg_m2m_sf_dec_mc; + } + + ret = media_device_register(&dev->mdev); + if (ret) { + v4l2_err(&dev->v4l2_dev, "Failed to register mem2mem media device\n"); + goto unreg_m2m_sl_dec_mc; + } +#endif + return 0; + +#ifdef CONFIG_MEDIA_CONTROLLER +unreg_m2m_sl_dec_mc: + v4l2_m2m_unregister_media_controller(dev->stateless_dec.m2m_dev); +unreg_m2m_sf_dec_mc: + v4l2_m2m_unregister_media_controller(dev->stateful_dec.m2m_dev); +unreg_m2m_sf_enc_mc: + v4l2_m2m_unregister_media_controller(dev->stateful_enc.m2m_dev); +unreg_m2m: + video_unregister_device(&dev->stateless_dec.vfd); + v4l2_m2m_release(dev->stateless_dec.m2m_dev); +#endif +unreg_sf_dec: + video_unregister_device(&dev->stateful_dec.vfd); + v4l2_m2m_release(dev->stateful_dec.m2m_dev); +unreg_sf_enc: + video_unregister_device(&dev->stateful_enc.vfd); + v4l2_m2m_release(dev->stateful_enc.m2m_dev); +unreg_dev: + v4l2_device_unregister(&dev->v4l2_dev); +free_dev: + kfree(dev); + + return ret; +} + +static int vicodec_remove(struct platform_device *pdev) +{ + struct vicodec_dev *dev = platform_get_drvdata(pdev); + + v4l2_info(&dev->v4l2_dev, "Removing " VICODEC_NAME); + +#ifdef CONFIG_MEDIA_CONTROLLER + media_device_unregister(&dev->mdev); + v4l2_m2m_unregister_media_controller(dev->stateful_enc.m2m_dev); + v4l2_m2m_unregister_media_controller(dev->stateful_dec.m2m_dev); + v4l2_m2m_unregister_media_controller(dev->stateless_dec.m2m_dev); +#endif + + video_unregister_device(&dev->stateful_enc.vfd); + video_unregister_device(&dev->stateful_dec.vfd); + video_unregister_device(&dev->stateless_dec.vfd); + v4l2_device_put(&dev->v4l2_dev); + + return 0; +} + +static struct platform_driver vicodec_pdrv = { + .probe = vicodec_probe, + .remove = vicodec_remove, + .driver = { + .name = VICODEC_NAME, + }, +}; + +static void __exit vicodec_exit(void) +{ + platform_driver_unregister(&vicodec_pdrv); + platform_device_unregister(&vicodec_pdev); +} + +static int __init vicodec_init(void) +{ + int ret; + + ret = platform_device_register(&vicodec_pdev); + if (ret) + return ret; + + ret = platform_driver_register(&vicodec_pdrv); + if (ret) + platform_device_unregister(&vicodec_pdev); + + return ret; +} + +module_init(vicodec_init); +module_exit(vicodec_exit); diff --git a/drivers/media/test_drivers/vim2m.c b/drivers/media/test_drivers/vim2m.c new file mode 100644 index 000000000000..ac6717fbb764 --- /dev/null +++ b/drivers/media/test_drivers/vim2m.c @@ -0,0 +1,1441 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * A virtual v4l2-mem2mem example device. + * + * This is a virtual device driver for testing mem-to-mem videobuf framework. + * It simulates a device that uses memory buffers for both source and + * destination, processes the data and issues an "irq" (simulated by a delayed + * workqueue). + * The device is capable of multi-instance, multi-buffer-per-transaction + * operation (via the mem2mem framework). + * + * Copyright (c) 2009-2010 Samsung Electronics Co., Ltd. + * Pawel Osciak, + * Marek Szyprowski, + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the + * License, or (at your option) any later version + */ +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +MODULE_DESCRIPTION("Virtual device for mem2mem framework testing"); +MODULE_AUTHOR("Pawel Osciak, "); +MODULE_LICENSE("GPL"); +MODULE_VERSION("0.2"); +MODULE_ALIAS("mem2mem_testdev"); + +static unsigned int debug; +module_param(debug, uint, 0644); +MODULE_PARM_DESC(debug, "debug level"); + +/* Default transaction time in msec */ +static unsigned int default_transtime = 40; /* Max 25 fps */ +module_param(default_transtime, uint, 0644); +MODULE_PARM_DESC(default_transtime, "default transaction time in ms"); + +#define MIN_W 32 +#define MIN_H 32 +#define MAX_W 640 +#define MAX_H 480 + +/* Pixel alignment for non-bayer formats */ +#define WIDTH_ALIGN 2 +#define HEIGHT_ALIGN 1 + +/* Pixel alignment for bayer formats */ +#define BAYER_WIDTH_ALIGN 2 +#define BAYER_HEIGHT_ALIGN 2 + +/* Flags that indicate a format can be used for capture/output */ +#define MEM2MEM_CAPTURE BIT(0) +#define MEM2MEM_OUTPUT BIT(1) + +#define MEM2MEM_NAME "vim2m" + +/* Per queue */ +#define MEM2MEM_DEF_NUM_BUFS VIDEO_MAX_FRAME +/* In bytes, per queue */ +#define MEM2MEM_VID_MEM_LIMIT (16 * 1024 * 1024) + +/* Flags that indicate processing mode */ +#define MEM2MEM_HFLIP BIT(0) +#define MEM2MEM_VFLIP BIT(1) + +#define dprintk(dev, lvl, fmt, arg...) \ + v4l2_dbg(lvl, debug, &(dev)->v4l2_dev, "%s: " fmt, __func__, ## arg) + +static void vim2m_dev_release(struct device *dev) +{} + +static struct platform_device vim2m_pdev = { + .name = MEM2MEM_NAME, + .dev.release = vim2m_dev_release, +}; + +struct vim2m_fmt { + u32 fourcc; + int depth; + /* Types the format can be used for */ + u32 types; +}; + +static struct vim2m_fmt formats[] = { + { + .fourcc = V4L2_PIX_FMT_RGB565, /* rrrrrggg gggbbbbb */ + .depth = 16, + .types = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT, + }, { + .fourcc = V4L2_PIX_FMT_RGB565X, /* gggbbbbb rrrrrggg */ + .depth = 16, + .types = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT, + }, { + .fourcc = V4L2_PIX_FMT_RGB24, + .depth = 24, + .types = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT, + }, { + .fourcc = V4L2_PIX_FMT_BGR24, + .depth = 24, + .types = MEM2MEM_CAPTURE | MEM2MEM_OUTPUT, + }, { + .fourcc = V4L2_PIX_FMT_YUYV, + .depth = 16, + .types = MEM2MEM_CAPTURE, + }, { + .fourcc = V4L2_PIX_FMT_SBGGR8, + .depth = 8, + .types = MEM2MEM_CAPTURE, + }, { + .fourcc = V4L2_PIX_FMT_SGBRG8, + .depth = 8, + .types = MEM2MEM_CAPTURE, + }, { + .fourcc = V4L2_PIX_FMT_SGRBG8, + .depth = 8, + .types = MEM2MEM_CAPTURE, + }, { + .fourcc = V4L2_PIX_FMT_SRGGB8, + .depth = 8, + .types = MEM2MEM_CAPTURE, + }, +}; + +#define NUM_FORMATS ARRAY_SIZE(formats) + +/* Per-queue, driver-specific private data */ +struct vim2m_q_data { + unsigned int width; + unsigned int height; + unsigned int sizeimage; + unsigned int sequence; + struct vim2m_fmt *fmt; +}; + +enum { + V4L2_M2M_SRC = 0, + V4L2_M2M_DST = 1, +}; + +#define V4L2_CID_TRANS_TIME_MSEC (V4L2_CID_USER_BASE + 0x1000) +#define V4L2_CID_TRANS_NUM_BUFS (V4L2_CID_USER_BASE + 0x1001) + +static struct vim2m_fmt *find_format(u32 fourcc) +{ + struct vim2m_fmt *fmt; + unsigned int k; + + for (k = 0; k < NUM_FORMATS; k++) { + fmt = &formats[k]; + if (fmt->fourcc == fourcc) + break; + } + + if (k == NUM_FORMATS) + return NULL; + + return &formats[k]; +} + +static void get_alignment(u32 fourcc, + unsigned int *walign, unsigned int *halign) +{ + switch (fourcc) { + case V4L2_PIX_FMT_SBGGR8: + case V4L2_PIX_FMT_SGBRG8: + case V4L2_PIX_FMT_SGRBG8: + case V4L2_PIX_FMT_SRGGB8: + *walign = BAYER_WIDTH_ALIGN; + *halign = BAYER_HEIGHT_ALIGN; + return; + default: + *walign = WIDTH_ALIGN; + *halign = HEIGHT_ALIGN; + return; + } +} + +struct vim2m_dev { + struct v4l2_device v4l2_dev; + struct video_device vfd; +#ifdef CONFIG_MEDIA_CONTROLLER + struct media_device mdev; +#endif + + atomic_t num_inst; + struct mutex dev_mutex; + + struct v4l2_m2m_dev *m2m_dev; +}; + +struct vim2m_ctx { + struct v4l2_fh fh; + struct vim2m_dev *dev; + + struct v4l2_ctrl_handler hdl; + + /* Processed buffers in this transaction */ + u8 num_processed; + + /* Transaction length (i.e. how many buffers per transaction) */ + u32 translen; + /* Transaction time (i.e. simulated processing time) in milliseconds */ + u32 transtime; + + struct mutex vb_mutex; + struct delayed_work work_run; + spinlock_t irqlock; + + /* Abort requested by m2m */ + int aborting; + + /* Processing mode */ + int mode; + + enum v4l2_colorspace colorspace; + enum v4l2_ycbcr_encoding ycbcr_enc; + enum v4l2_xfer_func xfer_func; + enum v4l2_quantization quant; + + /* Source and destination queue data */ + struct vim2m_q_data q_data[2]; +}; + +static inline struct vim2m_ctx *file2ctx(struct file *file) +{ + return container_of(file->private_data, struct vim2m_ctx, fh); +} + +static struct vim2m_q_data *get_q_data(struct vim2m_ctx *ctx, + enum v4l2_buf_type type) +{ + switch (type) { + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + return &ctx->q_data[V4L2_M2M_SRC]; + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + return &ctx->q_data[V4L2_M2M_DST]; + default: + return NULL; + } +} + +static const char *type_name(enum v4l2_buf_type type) +{ + switch (type) { + case V4L2_BUF_TYPE_VIDEO_OUTPUT: + return "Output"; + case V4L2_BUF_TYPE_VIDEO_CAPTURE: + return "Capture"; + default: + return "Invalid"; + } +} + +#define CLIP(__color) \ + (u8)(((__color) > 0xff) ? 0xff : (((__color) < 0) ? 0 : (__color))) + +static void copy_line(struct vim2m_q_data *q_data_out, + u8 *src, u8 *dst, bool reverse) +{ + int x, depth = q_data_out->fmt->depth >> 3; + + if (!reverse) { + memcpy(dst, src, q_data_out->width * depth); + } else { + for (x = 0; x < q_data_out->width >> 1; x++) { + memcpy(dst, src, depth); + memcpy(dst + depth, src - depth, depth); + src -= depth << 1; + dst += depth << 1; + } + return; + } +} + +static void copy_two_pixels(struct vim2m_q_data *q_data_in, + struct vim2m_q_data *q_data_out, + u8 *src[2], u8 **dst, int ypos, bool reverse) +{ + struct vim2m_fmt *out = q_data_out->fmt; + struct vim2m_fmt *in = q_data_in->fmt; + u8 _r[2], _g[2], _b[2], *r, *g, *b; + int i; + + /* Step 1: read two consecutive pixels from src pointer */ + + r = _r; + g = _g; + b = _b; + + switch (in->fourcc) { + case V4L2_PIX_FMT_RGB565: /* rrrrrggg gggbbbbb */ + for (i = 0; i < 2; i++) { + u16 pix = le16_to_cpu(*(__le16 *)(src[i])); + + *r++ = (u8)(((pix & 0xf800) >> 11) << 3) | 0x07; + *g++ = (u8)((((pix & 0x07e0) >> 5)) << 2) | 0x03; + *b++ = (u8)((pix & 0x1f) << 3) | 0x07; + } + break; + case V4L2_PIX_FMT_RGB565X: /* gggbbbbb rrrrrggg */ + for (i = 0; i < 2; i++) { + u16 pix = be16_to_cpu(*(__be16 *)(src[i])); + + *r++ = (u8)(((pix & 0xf800) >> 11) << 3) | 0x07; + *g++ = (u8)((((pix & 0x07e0) >> 5)) << 2) | 0x03; + *b++ = (u8)((pix & 0x1f) << 3) | 0x07; + } + break; + default: + case V4L2_PIX_FMT_RGB24: + for (i = 0; i < 2; i++) { + *r++ = src[i][0]; + *g++ = src[i][1]; + *b++ = src[i][2]; + } + break; + case V4L2_PIX_FMT_BGR24: + for (i = 0; i < 2; i++) { + *b++ = src[i][0]; + *g++ = src[i][1]; + *r++ = src[i][2]; + } + break; + } + + /* Step 2: store two consecutive points, reversing them if needed */ + + r = _r; + g = _g; + b = _b; + + switch (out->fourcc) { + case V4L2_PIX_FMT_RGB565: /* rrrrrggg gggbbbbb */ + for (i = 0; i < 2; i++) { + u16 pix; + __le16 *dst_pix = (__le16 *)*dst; + + pix = ((*r << 8) & 0xf800) | ((*g << 3) & 0x07e0) | + (*b >> 3); + + *dst_pix = cpu_to_le16(pix); + + *dst += 2; + } + return; + case V4L2_PIX_FMT_RGB565X: /* gggbbbbb rrrrrggg */ + for (i = 0; i < 2; i++) { + u16 pix; + __be16 *dst_pix = (__be16 *)*dst; + + pix = ((*r << 8) & 0xf800) | ((*g << 3) & 0x07e0) | + (*b >> 3); + + *dst_pix = cpu_to_be16(pix); + + *dst += 2; + } + return; + case V4L2_PIX_FMT_RGB24: + for (i = 0; i < 2; i++) { + *(*dst)++ = *r++; + *(*dst)++ = *g++; + *(*dst)++ = *b++; + } + return; + case V4L2_PIX_FMT_BGR24: + for (i = 0; i < 2; i++) { + *(*dst)++ = *b++; + *(*dst)++ = *g++; + *(*dst)++ = *r++; + } + return; + case V4L2_PIX_FMT_YUYV: + default: + { + u8 y, y1, u, v; + + y = ((8453 * (*r) + 16594 * (*g) + 3223 * (*b) + + 524288) >> 15); + u = ((-4878 * (*r) - 9578 * (*g) + 14456 * (*b) + + 4210688) >> 15); + v = ((14456 * (*r++) - 12105 * (*g++) - 2351 * (*b++) + + 4210688) >> 15); + y1 = ((8453 * (*r) + 16594 * (*g) + 3223 * (*b) + + 524288) >> 15); + + *(*dst)++ = y; + *(*dst)++ = u; + + *(*dst)++ = y1; + *(*dst)++ = v; + return; + } + case V4L2_PIX_FMT_SBGGR8: + if (!(ypos & 1)) { + *(*dst)++ = *b; + *(*dst)++ = *++g; + } else { + *(*dst)++ = *g; + *(*dst)++ = *++r; + } + return; + case V4L2_PIX_FMT_SGBRG8: + if (!(ypos & 1)) { + *(*dst)++ = *g; + *(*dst)++ = *++b; + } else { + *(*dst)++ = *r; + *(*dst)++ = *++g; + } + return; + case V4L2_PIX_FMT_SGRBG8: + if (!(ypos & 1)) { + *(*dst)++ = *g; + *(*dst)++ = *++r; + } else { + *(*dst)++ = *b; + *(*dst)++ = *++g; + } + return; + case V4L2_PIX_FMT_SRGGB8: + if (!(ypos & 1)) { + *(*dst)++ = *r; + *(*dst)++ = *++g; + } else { + *(*dst)++ = *g; + *(*dst)++ = *++b; + } + return; + } +} + +static int device_process(struct vim2m_ctx *ctx, + struct vb2_v4l2_buffer *in_vb, + struct vb2_v4l2_buffer *out_vb) +{ + struct vim2m_dev *dev = ctx->dev; + struct vim2m_q_data *q_data_in, *q_data_out; + u8 *p_in, *p_line, *p_in_x[2], *p, *p_out; + unsigned int width, height, bytesperline, bytes_per_pixel; + unsigned int x, y, y_in, y_out, x_int, x_fract, x_err, x_offset; + int start, end, step; + + q_data_in = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT); + if (!q_data_in) + return 0; + bytesperline = (q_data_in->width * q_data_in->fmt->depth) >> 3; + bytes_per_pixel = q_data_in->fmt->depth >> 3; + + q_data_out = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + if (!q_data_out) + return 0; + + /* As we're doing scaling, use the output dimensions here */ + height = q_data_out->height; + width = q_data_out->width; + + p_in = vb2_plane_vaddr(&in_vb->vb2_buf, 0); + p_out = vb2_plane_vaddr(&out_vb->vb2_buf, 0); + if (!p_in || !p_out) { + v4l2_err(&dev->v4l2_dev, + "Acquiring kernel pointers to buffers failed\n"); + return -EFAULT; + } + + out_vb->sequence = q_data_out->sequence++; + in_vb->sequence = q_data_in->sequence++; + v4l2_m2m_buf_copy_metadata(in_vb, out_vb, true); + + if (ctx->mode & MEM2MEM_VFLIP) { + start = height - 1; + end = -1; + step = -1; + } else { + start = 0; + end = height; + step = 1; + } + y_out = 0; + + /* + * When format and resolution are identical, + * we can use a faster copy logic + */ + if (q_data_in->fmt->fourcc == q_data_out->fmt->fourcc && + q_data_in->width == q_data_out->width && + q_data_in->height == q_data_out->height) { + for (y = start; y != end; y += step, y_out++) { + p = p_in + (y * bytesperline); + if (ctx->mode & MEM2MEM_HFLIP) + p += bytesperline - (q_data_in->fmt->depth >> 3); + + copy_line(q_data_out, p, p_out, + ctx->mode & MEM2MEM_HFLIP); + + p_out += bytesperline; + } + return 0; + } + + /* Slower algorithm with format conversion, hflip, vflip and scaler */ + + /* To speed scaler up, use Bresenham for X dimension */ + x_int = q_data_in->width / q_data_out->width; + x_fract = q_data_in->width % q_data_out->width; + + for (y = start; y != end; y += step, y_out++) { + y_in = (y * q_data_in->height) / q_data_out->height; + x_offset = 0; + x_err = 0; + + p_line = p_in + (y_in * bytesperline); + if (ctx->mode & MEM2MEM_HFLIP) + p_line += bytesperline - (q_data_in->fmt->depth >> 3); + p_in_x[0] = p_line; + + for (x = 0; x < width >> 1; x++) { + x_offset += x_int; + x_err += x_fract; + if (x_err > width) { + x_offset++; + x_err -= width; + } + + if (ctx->mode & MEM2MEM_HFLIP) + p_in_x[1] = p_line - x_offset * bytes_per_pixel; + else + p_in_x[1] = p_line + x_offset * bytes_per_pixel; + + copy_two_pixels(q_data_in, q_data_out, + p_in_x, &p_out, y_out, + ctx->mode & MEM2MEM_HFLIP); + + /* Calculate the next p_in_x0 */ + x_offset += x_int; + x_err += x_fract; + if (x_err > width) { + x_offset++; + x_err -= width; + } + + if (ctx->mode & MEM2MEM_HFLIP) + p_in_x[0] = p_line - x_offset * bytes_per_pixel; + else + p_in_x[0] = p_line + x_offset * bytes_per_pixel; + } + } + + return 0; +} + +/* + * mem2mem callbacks + */ + +/* + * job_ready() - check whether an instance is ready to be scheduled to run + */ +static int job_ready(void *priv) +{ + struct vim2m_ctx *ctx = priv; + + if (v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) < ctx->translen + || v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx) < ctx->translen) { + dprintk(ctx->dev, 1, "Not enough buffers available\n"); + return 0; + } + + return 1; +} + +static void job_abort(void *priv) +{ + struct vim2m_ctx *ctx = priv; + + /* Will cancel the transaction in the next interrupt handler */ + ctx->aborting = 1; +} + +/* device_run() - prepares and starts the device + * + * This simulates all the immediate preparations required before starting + * a device. This will be called by the framework when it decides to schedule + * a particular instance. + */ +static void device_run(void *priv) +{ + struct vim2m_ctx *ctx = priv; + struct vb2_v4l2_buffer *src_buf, *dst_buf; + + src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); + dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); + + /* Apply request controls if any */ + v4l2_ctrl_request_setup(src_buf->vb2_buf.req_obj.req, + &ctx->hdl); + + device_process(ctx, src_buf, dst_buf); + + /* Complete request controls if any */ + v4l2_ctrl_request_complete(src_buf->vb2_buf.req_obj.req, + &ctx->hdl); + + /* Run delayed work, which simulates a hardware irq */ + schedule_delayed_work(&ctx->work_run, msecs_to_jiffies(ctx->transtime)); +} + +static void device_work(struct work_struct *w) +{ + struct vim2m_ctx *curr_ctx; + struct vim2m_dev *vim2m_dev; + struct vb2_v4l2_buffer *src_vb, *dst_vb; + unsigned long flags; + + curr_ctx = container_of(w, struct vim2m_ctx, work_run.work); + + if (!curr_ctx) { + pr_err("Instance released before the end of transaction\n"); + return; + } + + vim2m_dev = curr_ctx->dev; + + src_vb = v4l2_m2m_src_buf_remove(curr_ctx->fh.m2m_ctx); + dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->fh.m2m_ctx); + + curr_ctx->num_processed++; + + spin_lock_irqsave(&curr_ctx->irqlock, flags); + v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_DONE); + v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_DONE); + spin_unlock_irqrestore(&curr_ctx->irqlock, flags); + + if (curr_ctx->num_processed == curr_ctx->translen + || curr_ctx->aborting) { + dprintk(curr_ctx->dev, 2, "Finishing capture buffer fill\n"); + curr_ctx->num_processed = 0; + v4l2_m2m_job_finish(vim2m_dev->m2m_dev, curr_ctx->fh.m2m_ctx); + } else { + device_run(curr_ctx); + } +} + +/* + * video ioctls + */ +static int vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + strscpy(cap->driver, MEM2MEM_NAME, sizeof(cap->driver)); + strscpy(cap->card, MEM2MEM_NAME, sizeof(cap->card)); + snprintf(cap->bus_info, sizeof(cap->bus_info), + "platform:%s", MEM2MEM_NAME); + return 0; +} + +static int enum_fmt(struct v4l2_fmtdesc *f, u32 type) +{ + int i, num; + struct vim2m_fmt *fmt; + + num = 0; + + for (i = 0; i < NUM_FORMATS; ++i) { + if (formats[i].types & type) { + /* index-th format of type type found ? */ + if (num == f->index) + break; + /* + * Correct type but haven't reached our index yet, + * just increment per-type index + */ + ++num; + } + } + + if (i < NUM_FORMATS) { + /* Format found */ + fmt = &formats[i]; + f->pixelformat = fmt->fourcc; + return 0; + } + + /* Format not found */ + return -EINVAL; +} + +static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + return enum_fmt(f, MEM2MEM_CAPTURE); +} + +static int vidioc_enum_fmt_vid_out(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + return enum_fmt(f, MEM2MEM_OUTPUT); +} + +static int vidioc_enum_framesizes(struct file *file, void *priv, + struct v4l2_frmsizeenum *fsize) +{ + if (fsize->index != 0) + return -EINVAL; + + if (!find_format(fsize->pixel_format)) + return -EINVAL; + + fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; + fsize->stepwise.min_width = MIN_W; + fsize->stepwise.min_height = MIN_H; + fsize->stepwise.max_width = MAX_W; + fsize->stepwise.max_height = MAX_H; + + get_alignment(fsize->pixel_format, + &fsize->stepwise.step_width, + &fsize->stepwise.step_height); + return 0; +} + +static int vidioc_g_fmt(struct vim2m_ctx *ctx, struct v4l2_format *f) +{ + struct vb2_queue *vq; + struct vim2m_q_data *q_data; + + vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); + if (!vq) + return -EINVAL; + + q_data = get_q_data(ctx, f->type); + if (!q_data) + return -EINVAL; + + f->fmt.pix.width = q_data->width; + f->fmt.pix.height = q_data->height; + f->fmt.pix.field = V4L2_FIELD_NONE; + f->fmt.pix.pixelformat = q_data->fmt->fourcc; + f->fmt.pix.bytesperline = (q_data->width * q_data->fmt->depth) >> 3; + f->fmt.pix.sizeimage = q_data->sizeimage; + f->fmt.pix.colorspace = ctx->colorspace; + f->fmt.pix.xfer_func = ctx->xfer_func; + f->fmt.pix.ycbcr_enc = ctx->ycbcr_enc; + f->fmt.pix.quantization = ctx->quant; + + return 0; +} + +static int vidioc_g_fmt_vid_out(struct file *file, void *priv, + struct v4l2_format *f) +{ + return vidioc_g_fmt(file2ctx(file), f); +} + +static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + return vidioc_g_fmt(file2ctx(file), f); +} + +static int vidioc_try_fmt(struct v4l2_format *f, struct vim2m_fmt *fmt) +{ + int walign, halign; + /* + * V4L2 specification specifies the driver corrects the + * format struct if any of the dimensions is unsupported + */ + if (f->fmt.pix.height < MIN_H) + f->fmt.pix.height = MIN_H; + else if (f->fmt.pix.height > MAX_H) + f->fmt.pix.height = MAX_H; + + if (f->fmt.pix.width < MIN_W) + f->fmt.pix.width = MIN_W; + else if (f->fmt.pix.width > MAX_W) + f->fmt.pix.width = MAX_W; + + get_alignment(f->fmt.pix.pixelformat, &walign, &halign); + f->fmt.pix.width &= ~(walign - 1); + f->fmt.pix.height &= ~(halign - 1); + f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3; + f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; + f->fmt.pix.field = V4L2_FIELD_NONE; + + return 0; +} + +static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct vim2m_fmt *fmt; + struct vim2m_ctx *ctx = file2ctx(file); + + fmt = find_format(f->fmt.pix.pixelformat); + if (!fmt) { + f->fmt.pix.pixelformat = formats[0].fourcc; + fmt = find_format(f->fmt.pix.pixelformat); + } + if (!(fmt->types & MEM2MEM_CAPTURE)) { + v4l2_err(&ctx->dev->v4l2_dev, + "Fourcc format (0x%08x) invalid.\n", + f->fmt.pix.pixelformat); + return -EINVAL; + } + f->fmt.pix.colorspace = ctx->colorspace; + f->fmt.pix.xfer_func = ctx->xfer_func; + f->fmt.pix.ycbcr_enc = ctx->ycbcr_enc; + f->fmt.pix.quantization = ctx->quant; + + return vidioc_try_fmt(f, fmt); +} + +static int vidioc_try_fmt_vid_out(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct vim2m_fmt *fmt; + struct vim2m_ctx *ctx = file2ctx(file); + + fmt = find_format(f->fmt.pix.pixelformat); + if (!fmt) { + f->fmt.pix.pixelformat = formats[0].fourcc; + fmt = find_format(f->fmt.pix.pixelformat); + } + if (!(fmt->types & MEM2MEM_OUTPUT)) { + v4l2_err(&ctx->dev->v4l2_dev, + "Fourcc format (0x%08x) invalid.\n", + f->fmt.pix.pixelformat); + return -EINVAL; + } + if (!f->fmt.pix.colorspace) + f->fmt.pix.colorspace = V4L2_COLORSPACE_REC709; + + return vidioc_try_fmt(f, fmt); +} + +static int vidioc_s_fmt(struct vim2m_ctx *ctx, struct v4l2_format *f) +{ + struct vim2m_q_data *q_data; + struct vb2_queue *vq; + + vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); + if (!vq) + return -EINVAL; + + q_data = get_q_data(ctx, f->type); + if (!q_data) + return -EINVAL; + + if (vb2_is_busy(vq)) { + v4l2_err(&ctx->dev->v4l2_dev, "%s queue busy\n", __func__); + return -EBUSY; + } + + q_data->fmt = find_format(f->fmt.pix.pixelformat); + q_data->width = f->fmt.pix.width; + q_data->height = f->fmt.pix.height; + q_data->sizeimage = q_data->width * q_data->height + * q_data->fmt->depth >> 3; + + dprintk(ctx->dev, 1, + "Format for type %s: %dx%d (%d bpp), fmt: %c%c%c%c\n", + type_name(f->type), q_data->width, q_data->height, + q_data->fmt->depth, + (q_data->fmt->fourcc & 0xff), + (q_data->fmt->fourcc >> 8) & 0xff, + (q_data->fmt->fourcc >> 16) & 0xff, + (q_data->fmt->fourcc >> 24) & 0xff); + + return 0; +} + +static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + int ret; + + ret = vidioc_try_fmt_vid_cap(file, priv, f); + if (ret) + return ret; + + return vidioc_s_fmt(file2ctx(file), f); +} + +static int vidioc_s_fmt_vid_out(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct vim2m_ctx *ctx = file2ctx(file); + int ret; + + ret = vidioc_try_fmt_vid_out(file, priv, f); + if (ret) + return ret; + + ret = vidioc_s_fmt(file2ctx(file), f); + if (!ret) { + ctx->colorspace = f->fmt.pix.colorspace; + ctx->xfer_func = f->fmt.pix.xfer_func; + ctx->ycbcr_enc = f->fmt.pix.ycbcr_enc; + ctx->quant = f->fmt.pix.quantization; + } + return ret; +} + +static int vim2m_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct vim2m_ctx *ctx = + container_of(ctrl->handler, struct vim2m_ctx, hdl); + + switch (ctrl->id) { + case V4L2_CID_HFLIP: + if (ctrl->val) + ctx->mode |= MEM2MEM_HFLIP; + else + ctx->mode &= ~MEM2MEM_HFLIP; + break; + + case V4L2_CID_VFLIP: + if (ctrl->val) + ctx->mode |= MEM2MEM_VFLIP; + else + ctx->mode &= ~MEM2MEM_VFLIP; + break; + + case V4L2_CID_TRANS_TIME_MSEC: + ctx->transtime = ctrl->val; + if (ctx->transtime < 1) + ctx->transtime = 1; + break; + + case V4L2_CID_TRANS_NUM_BUFS: + ctx->translen = ctrl->val; + break; + + default: + v4l2_err(&ctx->dev->v4l2_dev, "Invalid control\n"); + return -EINVAL; + } + + return 0; +} + +static const struct v4l2_ctrl_ops vim2m_ctrl_ops = { + .s_ctrl = vim2m_s_ctrl, +}; + +static const struct v4l2_ioctl_ops vim2m_ioctl_ops = { + .vidioc_querycap = vidioc_querycap, + + .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, + .vidioc_enum_framesizes = vidioc_enum_framesizes, + .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, + + .vidioc_enum_fmt_vid_out = vidioc_enum_fmt_vid_out, + .vidioc_g_fmt_vid_out = vidioc_g_fmt_vid_out, + .vidioc_try_fmt_vid_out = vidioc_try_fmt_vid_out, + .vidioc_s_fmt_vid_out = vidioc_s_fmt_vid_out, + + .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, + .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, + .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, + .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, + .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf, + .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs, + .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, + + .vidioc_streamon = v4l2_m2m_ioctl_streamon, + .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, + + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, +}; + +/* + * Queue operations + */ + +static int vim2m_queue_setup(struct vb2_queue *vq, + unsigned int *nbuffers, + unsigned int *nplanes, + unsigned int sizes[], + struct device *alloc_devs[]) +{ + struct vim2m_ctx *ctx = vb2_get_drv_priv(vq); + struct vim2m_q_data *q_data; + unsigned int size, count = *nbuffers; + + q_data = get_q_data(ctx, vq->type); + if (!q_data) + return -EINVAL; + + size = q_data->width * q_data->height * q_data->fmt->depth >> 3; + + while (size * count > MEM2MEM_VID_MEM_LIMIT) + (count)--; + *nbuffers = count; + + if (*nplanes) + return sizes[0] < size ? -EINVAL : 0; + + *nplanes = 1; + sizes[0] = size; + + dprintk(ctx->dev, 1, "%s: get %d buffer(s) of size %d each.\n", + type_name(vq->type), count, size); + + return 0; +} + +static int vim2m_buf_out_validate(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct vim2m_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + + if (vbuf->field == V4L2_FIELD_ANY) + vbuf->field = V4L2_FIELD_NONE; + if (vbuf->field != V4L2_FIELD_NONE) { + dprintk(ctx->dev, 1, "%s field isn't supported\n", __func__); + return -EINVAL; + } + + return 0; +} + +static int vim2m_buf_prepare(struct vb2_buffer *vb) +{ + struct vim2m_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + struct vim2m_q_data *q_data; + + dprintk(ctx->dev, 2, "type: %s\n", type_name(vb->vb2_queue->type)); + + q_data = get_q_data(ctx, vb->vb2_queue->type); + if (!q_data) + return -EINVAL; + if (vb2_plane_size(vb, 0) < q_data->sizeimage) { + dprintk(ctx->dev, 1, + "%s data will not fit into plane (%lu < %lu)\n", + __func__, vb2_plane_size(vb, 0), + (long)q_data->sizeimage); + return -EINVAL; + } + + vb2_set_plane_payload(vb, 0, q_data->sizeimage); + + return 0; +} + +static void vim2m_buf_queue(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct vim2m_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + + v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); +} + +static int vim2m_start_streaming(struct vb2_queue *q, unsigned int count) +{ + struct vim2m_ctx *ctx = vb2_get_drv_priv(q); + struct vim2m_q_data *q_data = get_q_data(ctx, q->type); + + if (!q_data) + return -EINVAL; + + if (V4L2_TYPE_IS_OUTPUT(q->type)) + ctx->aborting = 0; + + q_data->sequence = 0; + return 0; +} + +static void vim2m_stop_streaming(struct vb2_queue *q) +{ + struct vim2m_ctx *ctx = vb2_get_drv_priv(q); + struct vb2_v4l2_buffer *vbuf; + unsigned long flags; + + cancel_delayed_work_sync(&ctx->work_run); + + for (;;) { + if (V4L2_TYPE_IS_OUTPUT(q->type)) + vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); + else + vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); + if (!vbuf) + return; + v4l2_ctrl_request_complete(vbuf->vb2_buf.req_obj.req, + &ctx->hdl); + spin_lock_irqsave(&ctx->irqlock, flags); + v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR); + spin_unlock_irqrestore(&ctx->irqlock, flags); + } +} + +static void vim2m_buf_request_complete(struct vb2_buffer *vb) +{ + struct vim2m_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + + v4l2_ctrl_request_complete(vb->req_obj.req, &ctx->hdl); +} + +static const struct vb2_ops vim2m_qops = { + .queue_setup = vim2m_queue_setup, + .buf_out_validate = vim2m_buf_out_validate, + .buf_prepare = vim2m_buf_prepare, + .buf_queue = vim2m_buf_queue, + .start_streaming = vim2m_start_streaming, + .stop_streaming = vim2m_stop_streaming, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, + .buf_request_complete = vim2m_buf_request_complete, +}; + +static int queue_init(void *priv, struct vb2_queue *src_vq, + struct vb2_queue *dst_vq) +{ + struct vim2m_ctx *ctx = priv; + int ret; + + src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + src_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; + src_vq->drv_priv = ctx; + src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); + src_vq->ops = &vim2m_qops; + src_vq->mem_ops = &vb2_vmalloc_memops; + src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; + src_vq->lock = &ctx->vb_mutex; + src_vq->supports_requests = true; + + ret = vb2_queue_init(src_vq); + if (ret) + return ret; + + dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + dst_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; + dst_vq->drv_priv = ctx; + dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); + dst_vq->ops = &vim2m_qops; + dst_vq->mem_ops = &vb2_vmalloc_memops; + dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; + dst_vq->lock = &ctx->vb_mutex; + + return vb2_queue_init(dst_vq); +} + +static struct v4l2_ctrl_config vim2m_ctrl_trans_time_msec = { + .ops = &vim2m_ctrl_ops, + .id = V4L2_CID_TRANS_TIME_MSEC, + .name = "Transaction Time (msec)", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = 1, + .max = 10001, + .step = 1, +}; + +static const struct v4l2_ctrl_config vim2m_ctrl_trans_num_bufs = { + .ops = &vim2m_ctrl_ops, + .id = V4L2_CID_TRANS_NUM_BUFS, + .name = "Buffers Per Transaction", + .type = V4L2_CTRL_TYPE_INTEGER, + .def = 1, + .min = 1, + .max = MEM2MEM_DEF_NUM_BUFS, + .step = 1, +}; + +/* + * File operations + */ +static int vim2m_open(struct file *file) +{ + struct vim2m_dev *dev = video_drvdata(file); + struct vim2m_ctx *ctx = NULL; + struct v4l2_ctrl_handler *hdl; + int rc = 0; + + if (mutex_lock_interruptible(&dev->dev_mutex)) + return -ERESTARTSYS; + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) { + rc = -ENOMEM; + goto open_unlock; + } + + v4l2_fh_init(&ctx->fh, video_devdata(file)); + file->private_data = &ctx->fh; + ctx->dev = dev; + hdl = &ctx->hdl; + v4l2_ctrl_handler_init(hdl, 4); + v4l2_ctrl_new_std(hdl, &vim2m_ctrl_ops, V4L2_CID_HFLIP, 0, 1, 1, 0); + v4l2_ctrl_new_std(hdl, &vim2m_ctrl_ops, V4L2_CID_VFLIP, 0, 1, 1, 0); + + vim2m_ctrl_trans_time_msec.def = default_transtime; + v4l2_ctrl_new_custom(hdl, &vim2m_ctrl_trans_time_msec, NULL); + v4l2_ctrl_new_custom(hdl, &vim2m_ctrl_trans_num_bufs, NULL); + if (hdl->error) { + rc = hdl->error; + v4l2_ctrl_handler_free(hdl); + kfree(ctx); + goto open_unlock; + } + ctx->fh.ctrl_handler = hdl; + v4l2_ctrl_handler_setup(hdl); + + ctx->q_data[V4L2_M2M_SRC].fmt = &formats[0]; + ctx->q_data[V4L2_M2M_SRC].width = 640; + ctx->q_data[V4L2_M2M_SRC].height = 480; + ctx->q_data[V4L2_M2M_SRC].sizeimage = + ctx->q_data[V4L2_M2M_SRC].width * + ctx->q_data[V4L2_M2M_SRC].height * + (ctx->q_data[V4L2_M2M_SRC].fmt->depth >> 3); + ctx->q_data[V4L2_M2M_DST] = ctx->q_data[V4L2_M2M_SRC]; + ctx->colorspace = V4L2_COLORSPACE_REC709; + + ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, &queue_init); + + mutex_init(&ctx->vb_mutex); + spin_lock_init(&ctx->irqlock); + INIT_DELAYED_WORK(&ctx->work_run, device_work); + + if (IS_ERR(ctx->fh.m2m_ctx)) { + rc = PTR_ERR(ctx->fh.m2m_ctx); + + v4l2_ctrl_handler_free(hdl); + v4l2_fh_exit(&ctx->fh); + kfree(ctx); + goto open_unlock; + } + + v4l2_fh_add(&ctx->fh); + atomic_inc(&dev->num_inst); + + dprintk(dev, 1, "Created instance: %p, m2m_ctx: %p\n", + ctx, ctx->fh.m2m_ctx); + +open_unlock: + mutex_unlock(&dev->dev_mutex); + return rc; +} + +static int vim2m_release(struct file *file) +{ + struct vim2m_dev *dev = video_drvdata(file); + struct vim2m_ctx *ctx = file2ctx(file); + + dprintk(dev, 1, "Releasing instance %p\n", ctx); + + v4l2_fh_del(&ctx->fh); + v4l2_fh_exit(&ctx->fh); + v4l2_ctrl_handler_free(&ctx->hdl); + mutex_lock(&dev->dev_mutex); + v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); + mutex_unlock(&dev->dev_mutex); + kfree(ctx); + + atomic_dec(&dev->num_inst); + + return 0; +} + +static void vim2m_device_release(struct video_device *vdev) +{ + struct vim2m_dev *dev = container_of(vdev, struct vim2m_dev, vfd); + + v4l2_device_unregister(&dev->v4l2_dev); + v4l2_m2m_release(dev->m2m_dev); +#ifdef CONFIG_MEDIA_CONTROLLER + media_device_cleanup(&dev->mdev); +#endif + kfree(dev); +} + +static const struct v4l2_file_operations vim2m_fops = { + .owner = THIS_MODULE, + .open = vim2m_open, + .release = vim2m_release, + .poll = v4l2_m2m_fop_poll, + .unlocked_ioctl = video_ioctl2, + .mmap = v4l2_m2m_fop_mmap, +}; + +static const struct video_device vim2m_videodev = { + .name = MEM2MEM_NAME, + .vfl_dir = VFL_DIR_M2M, + .fops = &vim2m_fops, + .ioctl_ops = &vim2m_ioctl_ops, + .minor = -1, + .release = vim2m_device_release, + .device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING, +}; + +static const struct v4l2_m2m_ops m2m_ops = { + .device_run = device_run, + .job_ready = job_ready, + .job_abort = job_abort, +}; + +static const struct media_device_ops m2m_media_ops = { + .req_validate = vb2_request_validate, + .req_queue = v4l2_m2m_request_queue, +}; + +static int vim2m_probe(struct platform_device *pdev) +{ + struct vim2m_dev *dev; + struct video_device *vfd; + int ret; + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) + return -ENOMEM; + + ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); + if (ret) + goto error_free; + + atomic_set(&dev->num_inst, 0); + mutex_init(&dev->dev_mutex); + + dev->vfd = vim2m_videodev; + vfd = &dev->vfd; + vfd->lock = &dev->dev_mutex; + vfd->v4l2_dev = &dev->v4l2_dev; + + ret = video_register_device(vfd, VFL_TYPE_VIDEO, 0); + if (ret) { + v4l2_err(&dev->v4l2_dev, "Failed to register video device\n"); + goto error_v4l2; + } + + video_set_drvdata(vfd, dev); + v4l2_info(&dev->v4l2_dev, + "Device registered as /dev/video%d\n", vfd->num); + + platform_set_drvdata(pdev, dev); + + dev->m2m_dev = v4l2_m2m_init(&m2m_ops); + if (IS_ERR(dev->m2m_dev)) { + v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem device\n"); + ret = PTR_ERR(dev->m2m_dev); + dev->m2m_dev = NULL; + goto error_dev; + } + +#ifdef CONFIG_MEDIA_CONTROLLER + dev->mdev.dev = &pdev->dev; + strscpy(dev->mdev.model, "vim2m", sizeof(dev->mdev.model)); + strscpy(dev->mdev.bus_info, "platform:vim2m", + sizeof(dev->mdev.bus_info)); + media_device_init(&dev->mdev); + dev->mdev.ops = &m2m_media_ops; + dev->v4l2_dev.mdev = &dev->mdev; + + ret = v4l2_m2m_register_media_controller(dev->m2m_dev, vfd, + MEDIA_ENT_F_PROC_VIDEO_SCALER); + if (ret) { + v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem media controller\n"); + goto error_dev; + } + + ret = media_device_register(&dev->mdev); + if (ret) { + v4l2_err(&dev->v4l2_dev, "Failed to register mem2mem media device\n"); + goto error_m2m_mc; + } +#endif + return 0; + +#ifdef CONFIG_MEDIA_CONTROLLER +error_m2m_mc: + v4l2_m2m_unregister_media_controller(dev->m2m_dev); +#endif +error_dev: + video_unregister_device(&dev->vfd); + /* vim2m_device_release called by video_unregister_device to release various objects */ + return ret; +error_v4l2: + v4l2_device_unregister(&dev->v4l2_dev); +error_free: + kfree(dev); + + return ret; +} + +static int vim2m_remove(struct platform_device *pdev) +{ + struct vim2m_dev *dev = platform_get_drvdata(pdev); + + v4l2_info(&dev->v4l2_dev, "Removing " MEM2MEM_NAME); + +#ifdef CONFIG_MEDIA_CONTROLLER + media_device_unregister(&dev->mdev); + v4l2_m2m_unregister_media_controller(dev->m2m_dev); +#endif + video_unregister_device(&dev->vfd); + + return 0; +} + +static struct platform_driver vim2m_pdrv = { + .probe = vim2m_probe, + .remove = vim2m_remove, + .driver = { + .name = MEM2MEM_NAME, + }, +}; + +static void __exit vim2m_exit(void) +{ + platform_driver_unregister(&vim2m_pdrv); + platform_device_unregister(&vim2m_pdev); +} + +static int __init vim2m_init(void) +{ + int ret; + + ret = platform_device_register(&vim2m_pdev); + if (ret) + return ret; + + ret = platform_driver_register(&vim2m_pdrv); + if (ret) + platform_device_unregister(&vim2m_pdev); + + return ret; +} + +module_init(vim2m_init); +module_exit(vim2m_exit); diff --git a/drivers/media/test_drivers/vimc/Kconfig b/drivers/media/test_drivers/vimc/Kconfig new file mode 100644 index 000000000000..bd221d3e1a4a --- /dev/null +++ b/drivers/media/test_drivers/vimc/Kconfig @@ -0,0 +1,15 @@ +# SPDX-License-Identifier: GPL-2.0-only +config VIDEO_VIMC + tristate "Virtual Media Controller Driver (VIMC)" + depends on VIDEO_DEV && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API + select VIDEOBUF2_VMALLOC + select VIDEO_V4L2_TPG + help + Skeleton driver for Virtual Media Controller + + This driver can be compared to the vivid driver for emulating + a media node that exposes a complex media topology. The topology + is hard coded for now but is meant to be highly configurable in + the future. + + When in doubt, say N. diff --git a/drivers/media/test_drivers/vimc/Makefile b/drivers/media/test_drivers/vimc/Makefile new file mode 100644 index 000000000000..a53b2b532e9f --- /dev/null +++ b/drivers/media/test_drivers/vimc/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0 +vimc-y := vimc-core.o vimc-common.o vimc-streamer.o vimc-capture.o \ + vimc-debayer.o vimc-scaler.o vimc-sensor.o + +obj-$(CONFIG_VIDEO_VIMC) += vimc.o + diff --git a/drivers/media/test_drivers/vimc/vimc-capture.c b/drivers/media/test_drivers/vimc/vimc-capture.c new file mode 100644 index 000000000000..23e740c1c5c0 --- /dev/null +++ b/drivers/media/test_drivers/vimc/vimc-capture.c @@ -0,0 +1,480 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * vimc-capture.c Virtual Media Controller Driver + * + * Copyright (C) 2015-2017 Helen Koike + */ + +#include +#include +#include + +#include "vimc-common.h" +#include "vimc-streamer.h" + +struct vimc_cap_device { + struct vimc_ent_device ved; + struct video_device vdev; + struct v4l2_pix_format format; + struct vb2_queue queue; + struct list_head buf_list; + /* + * NOTE: in a real driver, a spin lock must be used to access the + * queue because the frames are generated from a hardware interruption + * and the isr is not allowed to sleep. + * Even if it is not necessary a spinlock in the vimc driver, we + * use it here as a code reference + */ + spinlock_t qlock; + struct mutex lock; + u32 sequence; + struct vimc_stream stream; + struct media_pad pad; +}; + +static const struct v4l2_pix_format fmt_default = { + .width = 640, + .height = 480, + .pixelformat = V4L2_PIX_FMT_RGB24, + .field = V4L2_FIELD_NONE, + .colorspace = V4L2_COLORSPACE_DEFAULT, +}; + +struct vimc_cap_buffer { + /* + * struct vb2_v4l2_buffer must be the first element + * the videobuf2 framework will allocate this struct based on + * buf_struct_size and use the first sizeof(struct vb2_buffer) bytes of + * memory as a vb2_buffer + */ + struct vb2_v4l2_buffer vb2; + struct list_head list; +}; + +static int vimc_cap_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + strscpy(cap->driver, VIMC_PDEV_NAME, sizeof(cap->driver)); + strscpy(cap->card, KBUILD_MODNAME, sizeof(cap->card)); + snprintf(cap->bus_info, sizeof(cap->bus_info), + "platform:%s", VIMC_PDEV_NAME); + + return 0; +} + +static void vimc_cap_get_format(struct vimc_ent_device *ved, + struct v4l2_pix_format *fmt) +{ + struct vimc_cap_device *vcap = container_of(ved, struct vimc_cap_device, + ved); + + *fmt = vcap->format; +} + +static int vimc_cap_g_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct vimc_cap_device *vcap = video_drvdata(file); + + f->fmt.pix = vcap->format; + + return 0; +} + +static int vimc_cap_try_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct v4l2_pix_format *format = &f->fmt.pix; + const struct vimc_pix_map *vpix; + + format->width = clamp_t(u32, format->width, VIMC_FRAME_MIN_WIDTH, + VIMC_FRAME_MAX_WIDTH) & ~1; + format->height = clamp_t(u32, format->height, VIMC_FRAME_MIN_HEIGHT, + VIMC_FRAME_MAX_HEIGHT) & ~1; + + /* Don't accept a pixelformat that is not on the table */ + vpix = vimc_pix_map_by_pixelformat(format->pixelformat); + if (!vpix) { + format->pixelformat = fmt_default.pixelformat; + vpix = vimc_pix_map_by_pixelformat(format->pixelformat); + } + /* TODO: Add support for custom bytesperline values */ + format->bytesperline = format->width * vpix->bpp; + format->sizeimage = format->bytesperline * format->height; + + if (format->field == V4L2_FIELD_ANY) + format->field = fmt_default.field; + + vimc_colorimetry_clamp(format); + + return 0; +} + +static int vimc_cap_s_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct vimc_cap_device *vcap = video_drvdata(file); + int ret; + + /* Do not change the format while stream is on */ + if (vb2_is_busy(&vcap->queue)) + return -EBUSY; + + ret = vimc_cap_try_fmt_vid_cap(file, priv, f); + if (ret) + return ret; + + dev_dbg(vcap->ved.dev, "%s: format update: " + "old:%dx%d (0x%x, %d, %d, %d, %d) " + "new:%dx%d (0x%x, %d, %d, %d, %d)\n", vcap->vdev.name, + /* old */ + vcap->format.width, vcap->format.height, + vcap->format.pixelformat, vcap->format.colorspace, + vcap->format.quantization, vcap->format.xfer_func, + vcap->format.ycbcr_enc, + /* new */ + f->fmt.pix.width, f->fmt.pix.height, + f->fmt.pix.pixelformat, f->fmt.pix.colorspace, + f->fmt.pix.quantization, f->fmt.pix.xfer_func, + f->fmt.pix.ycbcr_enc); + + vcap->format = f->fmt.pix; + + return 0; +} + +static int vimc_cap_enum_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + const struct vimc_pix_map *vpix = vimc_pix_map_by_index(f->index); + + if (!vpix) + return -EINVAL; + + f->pixelformat = vpix->pixelformat; + + return 0; +} + +static int vimc_cap_enum_framesizes(struct file *file, void *fh, + struct v4l2_frmsizeenum *fsize) +{ + const struct vimc_pix_map *vpix; + + if (fsize->index) + return -EINVAL; + + /* Only accept code in the pix map table */ + vpix = vimc_pix_map_by_code(fsize->pixel_format); + if (!vpix) + return -EINVAL; + + fsize->type = V4L2_FRMSIZE_TYPE_CONTINUOUS; + fsize->stepwise.min_width = VIMC_FRAME_MIN_WIDTH; + fsize->stepwise.max_width = VIMC_FRAME_MAX_WIDTH; + fsize->stepwise.min_height = VIMC_FRAME_MIN_HEIGHT; + fsize->stepwise.max_height = VIMC_FRAME_MAX_HEIGHT; + fsize->stepwise.step_width = 1; + fsize->stepwise.step_height = 1; + + return 0; +} + +static const struct v4l2_file_operations vimc_cap_fops = { + .owner = THIS_MODULE, + .open = v4l2_fh_open, + .release = vb2_fop_release, + .read = vb2_fop_read, + .poll = vb2_fop_poll, + .unlocked_ioctl = video_ioctl2, + .mmap = vb2_fop_mmap, +}; + +static const struct v4l2_ioctl_ops vimc_cap_ioctl_ops = { + .vidioc_querycap = vimc_cap_querycap, + + .vidioc_g_fmt_vid_cap = vimc_cap_g_fmt_vid_cap, + .vidioc_s_fmt_vid_cap = vimc_cap_s_fmt_vid_cap, + .vidioc_try_fmt_vid_cap = vimc_cap_try_fmt_vid_cap, + .vidioc_enum_fmt_vid_cap = vimc_cap_enum_fmt_vid_cap, + .vidioc_enum_framesizes = vimc_cap_enum_framesizes, + + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_expbuf = vb2_ioctl_expbuf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, +}; + +static void vimc_cap_return_all_buffers(struct vimc_cap_device *vcap, + enum vb2_buffer_state state) +{ + struct vimc_cap_buffer *vbuf, *node; + + spin_lock(&vcap->qlock); + + list_for_each_entry_safe(vbuf, node, &vcap->buf_list, list) { + list_del(&vbuf->list); + vb2_buffer_done(&vbuf->vb2.vb2_buf, state); + } + + spin_unlock(&vcap->qlock); +} + +static int vimc_cap_start_streaming(struct vb2_queue *vq, unsigned int count) +{ + struct vimc_cap_device *vcap = vb2_get_drv_priv(vq); + struct media_entity *entity = &vcap->vdev.entity; + int ret; + + vcap->sequence = 0; + + /* Start the media pipeline */ + ret = media_pipeline_start(entity, &vcap->stream.pipe); + if (ret) { + vimc_cap_return_all_buffers(vcap, VB2_BUF_STATE_QUEUED); + return ret; + } + + ret = vimc_streamer_s_stream(&vcap->stream, &vcap->ved, 1); + if (ret) { + media_pipeline_stop(entity); + vimc_cap_return_all_buffers(vcap, VB2_BUF_STATE_QUEUED); + return ret; + } + + return 0; +} + +/* + * Stop the stream engine. Any remaining buffers in the stream queue are + * dequeued and passed on to the vb2 framework marked as STATE_ERROR. + */ +static void vimc_cap_stop_streaming(struct vb2_queue *vq) +{ + struct vimc_cap_device *vcap = vb2_get_drv_priv(vq); + + vimc_streamer_s_stream(&vcap->stream, &vcap->ved, 0); + + /* Stop the media pipeline */ + media_pipeline_stop(&vcap->vdev.entity); + + /* Release all active buffers */ + vimc_cap_return_all_buffers(vcap, VB2_BUF_STATE_ERROR); +} + +static void vimc_cap_buf_queue(struct vb2_buffer *vb2_buf) +{ + struct vimc_cap_device *vcap = vb2_get_drv_priv(vb2_buf->vb2_queue); + struct vimc_cap_buffer *buf = container_of(vb2_buf, + struct vimc_cap_buffer, + vb2.vb2_buf); + + spin_lock(&vcap->qlock); + list_add_tail(&buf->list, &vcap->buf_list); + spin_unlock(&vcap->qlock); +} + +static int vimc_cap_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, + unsigned int *nplanes, unsigned int sizes[], + struct device *alloc_devs[]) +{ + struct vimc_cap_device *vcap = vb2_get_drv_priv(vq); + + if (*nplanes) + return sizes[0] < vcap->format.sizeimage ? -EINVAL : 0; + /* We don't support multiplanes for now */ + *nplanes = 1; + sizes[0] = vcap->format.sizeimage; + + return 0; +} + +static int vimc_cap_buffer_prepare(struct vb2_buffer *vb) +{ + struct vimc_cap_device *vcap = vb2_get_drv_priv(vb->vb2_queue); + unsigned long size = vcap->format.sizeimage; + + if (vb2_plane_size(vb, 0) < size) { + dev_err(vcap->ved.dev, "%s: buffer too small (%lu < %lu)\n", + vcap->vdev.name, vb2_plane_size(vb, 0), size); + return -EINVAL; + } + return 0; +} + +static const struct vb2_ops vimc_cap_qops = { + .start_streaming = vimc_cap_start_streaming, + .stop_streaming = vimc_cap_stop_streaming, + .buf_queue = vimc_cap_buf_queue, + .queue_setup = vimc_cap_queue_setup, + .buf_prepare = vimc_cap_buffer_prepare, + /* + * Since q->lock is set we can use the standard + * vb2_ops_wait_prepare/finish helper functions. + */ + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, +}; + +static const struct media_entity_operations vimc_cap_mops = { + .link_validate = vimc_vdev_link_validate, +}; + +void vimc_cap_release(struct vimc_ent_device *ved) +{ + struct vimc_cap_device *vcap = + container_of(ved, struct vimc_cap_device, ved); + + media_entity_cleanup(vcap->ved.ent); + kfree(vcap); +} + +void vimc_cap_unregister(struct vimc_ent_device *ved) +{ + struct vimc_cap_device *vcap = + container_of(ved, struct vimc_cap_device, ved); + + vb2_queue_release(&vcap->queue); + video_unregister_device(&vcap->vdev); +} + +static void *vimc_cap_process_frame(struct vimc_ent_device *ved, + const void *frame) +{ + struct vimc_cap_device *vcap = container_of(ved, struct vimc_cap_device, + ved); + struct vimc_cap_buffer *vimc_buf; + void *vbuf; + + spin_lock(&vcap->qlock); + + /* Get the first entry of the list */ + vimc_buf = list_first_entry_or_null(&vcap->buf_list, + typeof(*vimc_buf), list); + if (!vimc_buf) { + spin_unlock(&vcap->qlock); + return ERR_PTR(-EAGAIN); + } + + /* Remove this entry from the list */ + list_del(&vimc_buf->list); + + spin_unlock(&vcap->qlock); + + /* Fill the buffer */ + vimc_buf->vb2.vb2_buf.timestamp = ktime_get_ns(); + vimc_buf->vb2.sequence = vcap->sequence++; + vimc_buf->vb2.field = vcap->format.field; + + vbuf = vb2_plane_vaddr(&vimc_buf->vb2.vb2_buf, 0); + + memcpy(vbuf, frame, vcap->format.sizeimage); + + /* Set it as ready */ + vb2_set_plane_payload(&vimc_buf->vb2.vb2_buf, 0, + vcap->format.sizeimage); + vb2_buffer_done(&vimc_buf->vb2.vb2_buf, VB2_BUF_STATE_DONE); + return NULL; +} + +struct vimc_ent_device *vimc_cap_add(struct vimc_device *vimc, + const char *vcfg_name) +{ + struct v4l2_device *v4l2_dev = &vimc->v4l2_dev; + const struct vimc_pix_map *vpix; + struct vimc_cap_device *vcap; + struct video_device *vdev; + struct vb2_queue *q; + int ret; + + /* Allocate the vimc_cap_device struct */ + vcap = kzalloc(sizeof(*vcap), GFP_KERNEL); + if (!vcap) + return NULL; + + /* Initialize the media entity */ + vcap->vdev.entity.name = vcfg_name; + vcap->vdev.entity.function = MEDIA_ENT_F_IO_V4L; + vcap->pad.flags = MEDIA_PAD_FL_SINK; + ret = media_entity_pads_init(&vcap->vdev.entity, + 1, &vcap->pad); + if (ret) + goto err_free_vcap; + + /* Initialize the lock */ + mutex_init(&vcap->lock); + + /* Initialize the vb2 queue */ + q = &vcap->queue; + q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + q->io_modes = VB2_MMAP | VB2_DMABUF | VB2_USERPTR; + q->drv_priv = vcap; + q->buf_struct_size = sizeof(struct vimc_cap_buffer); + q->ops = &vimc_cap_qops; + q->mem_ops = &vb2_vmalloc_memops; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->min_buffers_needed = 2; + q->lock = &vcap->lock; + + ret = vb2_queue_init(q); + if (ret) { + dev_err(vimc->mdev.dev, "%s: vb2 queue init failed (err=%d)\n", + vcfg_name, ret); + goto err_clean_m_ent; + } + + /* Initialize buffer list and its lock */ + INIT_LIST_HEAD(&vcap->buf_list); + spin_lock_init(&vcap->qlock); + + /* Set default frame format */ + vcap->format = fmt_default; + vpix = vimc_pix_map_by_pixelformat(vcap->format.pixelformat); + vcap->format.bytesperline = vcap->format.width * vpix->bpp; + vcap->format.sizeimage = vcap->format.bytesperline * + vcap->format.height; + + /* Fill the vimc_ent_device struct */ + vcap->ved.ent = &vcap->vdev.entity; + vcap->ved.process_frame = vimc_cap_process_frame; + vcap->ved.vdev_get_format = vimc_cap_get_format; + vcap->ved.dev = vimc->mdev.dev; + + /* Initialize the video_device struct */ + vdev = &vcap->vdev; + vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; + vdev->entity.ops = &vimc_cap_mops; + vdev->release = video_device_release_empty; + vdev->fops = &vimc_cap_fops; + vdev->ioctl_ops = &vimc_cap_ioctl_ops; + vdev->lock = &vcap->lock; + vdev->queue = q; + vdev->v4l2_dev = v4l2_dev; + vdev->vfl_dir = VFL_DIR_RX; + strscpy(vdev->name, vcfg_name, sizeof(vdev->name)); + video_set_drvdata(vdev, &vcap->ved); + + /* Register the video_device with the v4l2 and the media framework */ + ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); + if (ret) { + dev_err(vimc->mdev.dev, "%s: video register failed (err=%d)\n", + vcap->vdev.name, ret); + goto err_release_queue; + } + + return &vcap->ved; + +err_release_queue: + vb2_queue_release(q); +err_clean_m_ent: + media_entity_cleanup(&vcap->vdev.entity); +err_free_vcap: + kfree(vcap); + + return NULL; +} diff --git a/drivers/media/test_drivers/vimc/vimc-common.c b/drivers/media/test_drivers/vimc/vimc-common.c new file mode 100644 index 000000000000..c95c17c048f2 --- /dev/null +++ b/drivers/media/test_drivers/vimc/vimc-common.c @@ -0,0 +1,369 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * vimc-common.c Virtual Media Controller Driver + * + * Copyright (C) 2015-2017 Helen Koike + */ + +#include +#include + +#include "vimc-common.h" + +/* + * NOTE: non-bayer formats need to come first (necessary for enum_mbus_code + * in the scaler) + */ +static const struct vimc_pix_map vimc_pix_map_list[] = { + /* TODO: add all missing formats */ + + /* RGB formats */ + { + .code = MEDIA_BUS_FMT_BGR888_1X24, + .pixelformat = V4L2_PIX_FMT_BGR24, + .bpp = 3, + .bayer = false, + }, + { + .code = MEDIA_BUS_FMT_RGB888_1X24, + .pixelformat = V4L2_PIX_FMT_RGB24, + .bpp = 3, + .bayer = false, + }, + { + .code = MEDIA_BUS_FMT_ARGB8888_1X32, + .pixelformat = V4L2_PIX_FMT_ARGB32, + .bpp = 4, + .bayer = false, + }, + + /* Bayer formats */ + { + .code = MEDIA_BUS_FMT_SBGGR8_1X8, + .pixelformat = V4L2_PIX_FMT_SBGGR8, + .bpp = 1, + .bayer = true, + }, + { + .code = MEDIA_BUS_FMT_SGBRG8_1X8, + .pixelformat = V4L2_PIX_FMT_SGBRG8, + .bpp = 1, + .bayer = true, + }, + { + .code = MEDIA_BUS_FMT_SGRBG8_1X8, + .pixelformat = V4L2_PIX_FMT_SGRBG8, + .bpp = 1, + .bayer = true, + }, + { + .code = MEDIA_BUS_FMT_SRGGB8_1X8, + .pixelformat = V4L2_PIX_FMT_SRGGB8, + .bpp = 1, + .bayer = true, + }, + { + .code = MEDIA_BUS_FMT_SBGGR10_1X10, + .pixelformat = V4L2_PIX_FMT_SBGGR10, + .bpp = 2, + .bayer = true, + }, + { + .code = MEDIA_BUS_FMT_SGBRG10_1X10, + .pixelformat = V4L2_PIX_FMT_SGBRG10, + .bpp = 2, + .bayer = true, + }, + { + .code = MEDIA_BUS_FMT_SGRBG10_1X10, + .pixelformat = V4L2_PIX_FMT_SGRBG10, + .bpp = 2, + .bayer = true, + }, + { + .code = MEDIA_BUS_FMT_SRGGB10_1X10, + .pixelformat = V4L2_PIX_FMT_SRGGB10, + .bpp = 2, + .bayer = true, + }, + + /* 10bit raw bayer a-law compressed to 8 bits */ + { + .code = MEDIA_BUS_FMT_SBGGR10_ALAW8_1X8, + .pixelformat = V4L2_PIX_FMT_SBGGR10ALAW8, + .bpp = 1, + .bayer = true, + }, + { + .code = MEDIA_BUS_FMT_SGBRG10_ALAW8_1X8, + .pixelformat = V4L2_PIX_FMT_SGBRG10ALAW8, + .bpp = 1, + .bayer = true, + }, + { + .code = MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8, + .pixelformat = V4L2_PIX_FMT_SGRBG10ALAW8, + .bpp = 1, + .bayer = true, + }, + { + .code = MEDIA_BUS_FMT_SRGGB10_ALAW8_1X8, + .pixelformat = V4L2_PIX_FMT_SRGGB10ALAW8, + .bpp = 1, + .bayer = true, + }, + + /* 10bit raw bayer DPCM compressed to 8 bits */ + { + .code = MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8, + .pixelformat = V4L2_PIX_FMT_SBGGR10DPCM8, + .bpp = 1, + .bayer = true, + }, + { + .code = MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8, + .pixelformat = V4L2_PIX_FMT_SGBRG10DPCM8, + .bpp = 1, + .bayer = true, + }, + { + .code = MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8, + .pixelformat = V4L2_PIX_FMT_SGRBG10DPCM8, + .bpp = 1, + .bayer = true, + }, + { + .code = MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8, + .pixelformat = V4L2_PIX_FMT_SRGGB10DPCM8, + .bpp = 1, + .bayer = true, + }, + { + .code = MEDIA_BUS_FMT_SBGGR12_1X12, + .pixelformat = V4L2_PIX_FMT_SBGGR12, + .bpp = 2, + .bayer = true, + }, + { + .code = MEDIA_BUS_FMT_SGBRG12_1X12, + .pixelformat = V4L2_PIX_FMT_SGBRG12, + .bpp = 2, + .bayer = true, + }, + { + .code = MEDIA_BUS_FMT_SGRBG12_1X12, + .pixelformat = V4L2_PIX_FMT_SGRBG12, + .bpp = 2, + .bayer = true, + }, + { + .code = MEDIA_BUS_FMT_SRGGB12_1X12, + .pixelformat = V4L2_PIX_FMT_SRGGB12, + .bpp = 2, + .bayer = true, + }, +}; + +bool vimc_is_source(struct media_entity *ent) +{ + unsigned int i; + + for (i = 0; i < ent->num_pads; i++) + if (ent->pads[i].flags & MEDIA_PAD_FL_SINK) + return false; + return true; +} + +const struct vimc_pix_map *vimc_pix_map_by_index(unsigned int i) +{ + if (i >= ARRAY_SIZE(vimc_pix_map_list)) + return NULL; + + return &vimc_pix_map_list[i]; +} + +const struct vimc_pix_map *vimc_pix_map_by_code(u32 code) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(vimc_pix_map_list); i++) { + if (vimc_pix_map_list[i].code == code) + return &vimc_pix_map_list[i]; + } + return NULL; +} + +const struct vimc_pix_map *vimc_pix_map_by_pixelformat(u32 pixelformat) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(vimc_pix_map_list); i++) { + if (vimc_pix_map_list[i].pixelformat == pixelformat) + return &vimc_pix_map_list[i]; + } + return NULL; +} + +static int vimc_get_pix_format(struct media_pad *pad, + struct v4l2_pix_format *fmt) +{ + if (is_media_entity_v4l2_subdev(pad->entity)) { + struct v4l2_subdev *sd = + media_entity_to_v4l2_subdev(pad->entity); + struct v4l2_subdev_format sd_fmt; + const struct vimc_pix_map *pix_map; + int ret; + + sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; + sd_fmt.pad = pad->index; + + ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &sd_fmt); + if (ret) + return ret; + + v4l2_fill_pix_format(fmt, &sd_fmt.format); + pix_map = vimc_pix_map_by_code(sd_fmt.format.code); + fmt->pixelformat = pix_map->pixelformat; + } else if (is_media_entity_v4l2_video_device(pad->entity)) { + struct video_device *vdev = container_of(pad->entity, + struct video_device, + entity); + struct vimc_ent_device *ved = video_get_drvdata(vdev); + + if (!ved->vdev_get_format) + return -ENOIOCTLCMD; + + ved->vdev_get_format(ved, fmt); + } else { + return -EINVAL; + } + + return 0; +} + +int vimc_vdev_link_validate(struct media_link *link) +{ + struct v4l2_pix_format source_fmt, sink_fmt; + int ret; + + ret = vimc_get_pix_format(link->source, &source_fmt); + if (ret) + return ret; + + ret = vimc_get_pix_format(link->sink, &sink_fmt); + if (ret) + return ret; + + pr_info("vimc link validate: " + "%s:src:%dx%d (0x%x, %d, %d, %d, %d) " + "%s:snk:%dx%d (0x%x, %d, %d, %d, %d)\n", + /* src */ + link->source->entity->name, + source_fmt.width, source_fmt.height, + source_fmt.pixelformat, source_fmt.colorspace, + source_fmt.quantization, source_fmt.xfer_func, + source_fmt.ycbcr_enc, + /* sink */ + link->sink->entity->name, + sink_fmt.width, sink_fmt.height, + sink_fmt.pixelformat, sink_fmt.colorspace, + sink_fmt.quantization, sink_fmt.xfer_func, + sink_fmt.ycbcr_enc); + + /* The width, height and pixelformat must match. */ + if (source_fmt.width != sink_fmt.width || + source_fmt.height != sink_fmt.height || + source_fmt.pixelformat != sink_fmt.pixelformat) + return -EPIPE; + + /* + * The field order must match, or the sink field order must be NONE + * to support interlaced hardware connected to bridges that support + * progressive formats only. + */ + if (source_fmt.field != sink_fmt.field && + sink_fmt.field != V4L2_FIELD_NONE) + return -EPIPE; + + /* + * If colorspace is DEFAULT, then assume all the colorimetry is also + * DEFAULT, return 0 to skip comparing the other colorimetry parameters + */ + if (source_fmt.colorspace == V4L2_COLORSPACE_DEFAULT || + sink_fmt.colorspace == V4L2_COLORSPACE_DEFAULT) + return 0; + + /* Colorspace must match. */ + if (source_fmt.colorspace != sink_fmt.colorspace) + return -EPIPE; + + /* Colorimetry must match if they are not set to DEFAULT */ + if (source_fmt.ycbcr_enc != V4L2_YCBCR_ENC_DEFAULT && + sink_fmt.ycbcr_enc != V4L2_YCBCR_ENC_DEFAULT && + source_fmt.ycbcr_enc != sink_fmt.ycbcr_enc) + return -EPIPE; + + if (source_fmt.quantization != V4L2_QUANTIZATION_DEFAULT && + sink_fmt.quantization != V4L2_QUANTIZATION_DEFAULT && + source_fmt.quantization != sink_fmt.quantization) + return -EPIPE; + + if (source_fmt.xfer_func != V4L2_XFER_FUNC_DEFAULT && + sink_fmt.xfer_func != V4L2_XFER_FUNC_DEFAULT && + source_fmt.xfer_func != sink_fmt.xfer_func) + return -EPIPE; + + return 0; +} + +static const struct media_entity_operations vimc_ent_sd_mops = { + .link_validate = v4l2_subdev_link_validate, +}; + +int vimc_ent_sd_register(struct vimc_ent_device *ved, + struct v4l2_subdev *sd, + struct v4l2_device *v4l2_dev, + const char *const name, + u32 function, + u16 num_pads, + struct media_pad *pads, + const struct v4l2_subdev_ops *sd_ops) +{ + int ret; + + /* Fill the vimc_ent_device struct */ + ved->ent = &sd->entity; + + /* Initialize the subdev */ + v4l2_subdev_init(sd, sd_ops); + sd->entity.function = function; + sd->entity.ops = &vimc_ent_sd_mops; + sd->owner = THIS_MODULE; + strscpy(sd->name, name, sizeof(sd->name)); + v4l2_set_subdevdata(sd, ved); + + /* Expose this subdev to user space */ + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + if (sd->ctrl_handler) + sd->flags |= V4L2_SUBDEV_FL_HAS_EVENTS; + + /* Initialize the media entity */ + ret = media_entity_pads_init(&sd->entity, num_pads, pads); + if (ret) + return ret; + + /* Register the subdev with the v4l2 and the media framework */ + ret = v4l2_device_register_subdev(v4l2_dev, sd); + if (ret) { + dev_err(v4l2_dev->dev, + "%s: subdev register failed (err=%d)\n", + name, ret); + goto err_clean_m_ent; + } + + return 0; + +err_clean_m_ent: + media_entity_cleanup(&sd->entity); + return ret; +} diff --git a/drivers/media/test_drivers/vimc/vimc-common.h b/drivers/media/test_drivers/vimc/vimc-common.h new file mode 100644 index 000000000000..616d5a6b0754 --- /dev/null +++ b/drivers/media/test_drivers/vimc/vimc-common.h @@ -0,0 +1,224 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * vimc-common.h Virtual Media Controller Driver + * + * Copyright (C) 2015-2017 Helen Koike + */ + +#ifndef _VIMC_COMMON_H_ +#define _VIMC_COMMON_H_ + +#include +#include +#include +#include + +#define VIMC_PDEV_NAME "vimc" + +/* VIMC-specific controls */ +#define VIMC_CID_VIMC_BASE (0x00f00000 | 0xf000) +#define VIMC_CID_VIMC_CLASS (0x00f00000 | 1) +#define VIMC_CID_TEST_PATTERN (VIMC_CID_VIMC_BASE + 0) +#define VIMC_CID_MEAN_WIN_SIZE (VIMC_CID_VIMC_BASE + 1) + +#define VIMC_FRAME_MAX_WIDTH 4096 +#define VIMC_FRAME_MAX_HEIGHT 2160 +#define VIMC_FRAME_MIN_WIDTH 16 +#define VIMC_FRAME_MIN_HEIGHT 16 + +#define VIMC_FRAME_INDEX(lin, col, width, bpp) ((lin * width + col) * bpp) + +/* Source and sink pad checks */ +#define VIMC_IS_SRC(pad) (pad) +#define VIMC_IS_SINK(pad) (!(pad)) + +/** + * struct vimc_colorimetry_clamp - Adjust colorimetry parameters + * + * @fmt: the pointer to struct v4l2_pix_format or + * struct v4l2_mbus_framefmt + * + * Entities must check if colorimetry given by the userspace is valid, if not + * then set them as DEFAULT + */ +#define vimc_colorimetry_clamp(fmt) \ +do { \ + if ((fmt)->colorspace == V4L2_COLORSPACE_DEFAULT \ + || (fmt)->colorspace > V4L2_COLORSPACE_DCI_P3) { \ + (fmt)->colorspace = V4L2_COLORSPACE_DEFAULT; \ + (fmt)->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; \ + (fmt)->quantization = V4L2_QUANTIZATION_DEFAULT; \ + (fmt)->xfer_func = V4L2_XFER_FUNC_DEFAULT; \ + } \ + if ((fmt)->ycbcr_enc > V4L2_YCBCR_ENC_SMPTE240M) \ + (fmt)->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; \ + if ((fmt)->quantization > V4L2_QUANTIZATION_LIM_RANGE) \ + (fmt)->quantization = V4L2_QUANTIZATION_DEFAULT; \ + if ((fmt)->xfer_func > V4L2_XFER_FUNC_SMPTE2084) \ + (fmt)->xfer_func = V4L2_XFER_FUNC_DEFAULT; \ +} while (0) + +/** + * struct vimc_pix_map - maps media bus code with v4l2 pixel format + * + * @code: media bus format code defined by MEDIA_BUS_FMT_* macros + * @bbp: number of bytes each pixel occupies + * @pixelformat: pixel format devined by V4L2_PIX_FMT_* macros + * + * Struct which matches the MEDIA_BUS_FMT_* codes with the corresponding + * V4L2_PIX_FMT_* fourcc pixelformat and its bytes per pixel (bpp) + */ +struct vimc_pix_map { + unsigned int code; + unsigned int bpp; + u32 pixelformat; + bool bayer; +}; + +/** + * struct vimc_ent_device - core struct that represents an entity in the + * topology + * + * @dev: a pointer of the device struct of the driver + * @ent: the pointer to struct media_entity for the node + * @process_frame: callback send a frame to that node + * @vdev_get_format: callback that returns the current format a pad, used + * only when is_media_entity_v4l2_video_device(ent) returns + * true + * + * Each node of the topology must create a vimc_ent_device struct. Depending on + * the node it will be of an instance of v4l2_subdev or video_device struct + * where both contains a struct media_entity. + * Those structures should embedded the vimc_ent_device struct through + * v4l2_set_subdevdata() and video_set_drvdata() respectivaly, allowing the + * vimc_ent_device struct to be retrieved from the corresponding struct + * media_entity + */ +struct vimc_ent_device { + struct device *dev; + struct media_entity *ent; + void * (*process_frame)(struct vimc_ent_device *ved, + const void *frame); + void (*vdev_get_format)(struct vimc_ent_device *ved, + struct v4l2_pix_format *fmt); +}; + +/** + * struct vimc_device - main device for vimc driver + * + * @pipe_cfg pointer to the vimc pipeline configuration structure + * @ent_devs array of vimc_ent_device pointers + * @mdev the associated media_device parent + * @v4l2_dev Internal v4l2 parent device + */ +struct vimc_device { + const struct vimc_pipeline_config *pipe_cfg; + struct vimc_ent_device **ent_devs; + struct media_device mdev; + struct v4l2_device v4l2_dev; +}; + +/** + * struct vimc_ent_config Structure which describes individual + * configuration for each entity + * + * @name entity name + * @ved pointer to vimc_ent_device (a node in the + * topology) + * @add initializes and registers + * vim entity - called from vimc-core + * @unregister unregisters vimc entity - called from vimc-core + * @release releases vimc entity - called from the v4l2_dev + * release callback + */ +struct vimc_ent_config { + const char *name; + struct vimc_ent_device *(*add)(struct vimc_device *vimc, + const char *vcfg_name); + void (*unregister)(struct vimc_ent_device *ved); + void (*release)(struct vimc_ent_device *ved); +}; + +/** + * vimc_is_source - returns true if the entity has only source pads + * + * @ent: pointer to &struct media_entity + * + */ +bool vimc_is_source(struct media_entity *ent); + +/* prototypes for vimc_ent_config hooks */ +struct vimc_ent_device *vimc_cap_add(struct vimc_device *vimc, + const char *vcfg_name); +void vimc_cap_unregister(struct vimc_ent_device *ved); +void vimc_cap_release(struct vimc_ent_device *ved); + +struct vimc_ent_device *vimc_deb_add(struct vimc_device *vimc, + const char *vcfg_name); +void vimc_deb_release(struct vimc_ent_device *ved); + +struct vimc_ent_device *vimc_sca_add(struct vimc_device *vimc, + const char *vcfg_name); +void vimc_sca_release(struct vimc_ent_device *ved); + +struct vimc_ent_device *vimc_sen_add(struct vimc_device *vimc, + const char *vcfg_name); +void vimc_sen_release(struct vimc_ent_device *ved); + +/** + * vimc_pix_map_by_index - get vimc_pix_map struct by its index + * + * @i: index of the vimc_pix_map struct in vimc_pix_map_list + */ +const struct vimc_pix_map *vimc_pix_map_by_index(unsigned int i); + +/** + * vimc_pix_map_by_code - get vimc_pix_map struct by media bus code + * + * @code: media bus format code defined by MEDIA_BUS_FMT_* macros + */ +const struct vimc_pix_map *vimc_pix_map_by_code(u32 code); + +/** + * vimc_pix_map_by_pixelformat - get vimc_pix_map struct by v4l2 pixel format + * + * @pixelformat: pixel format devined by V4L2_PIX_FMT_* macros + */ +const struct vimc_pix_map *vimc_pix_map_by_pixelformat(u32 pixelformat); + +/** + * vimc_ent_sd_register - initialize and register a subdev node + * + * @ved: the vimc_ent_device struct to be initialize + * @sd: the v4l2_subdev struct to be initialize and registered + * @v4l2_dev: the v4l2 device to register the v4l2_subdev + * @name: name of the sub-device. Please notice that the name must be + * unique. + * @function: media entity function defined by MEDIA_ENT_F_* macros + * @num_pads: number of pads to initialize + * @pads: the array of pads of the entity, the caller should set the + flags of the pads + * @sd_ops: pointer to &struct v4l2_subdev_ops. + * + * Helper function initialize and register the struct vimc_ent_device and struct + * v4l2_subdev which represents a subdev node in the topology + */ +int vimc_ent_sd_register(struct vimc_ent_device *ved, + struct v4l2_subdev *sd, + struct v4l2_device *v4l2_dev, + const char *const name, + u32 function, + u16 num_pads, + struct media_pad *pads, + const struct v4l2_subdev_ops *sd_ops); + +/** + * vimc_vdev_link_validate - validates a media link + * + * @link: pointer to &struct media_link + * + * This function calls validates if a media link is valid for streaming. + */ +int vimc_vdev_link_validate(struct media_link *link); + +#endif diff --git a/drivers/media/test_drivers/vimc/vimc-core.c b/drivers/media/test_drivers/vimc/vimc-core.c new file mode 100644 index 000000000000..339126e565dc --- /dev/null +++ b/drivers/media/test_drivers/vimc/vimc-core.c @@ -0,0 +1,381 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * vimc-core.c Virtual Media Controller Driver + * + * Copyright (C) 2015-2017 Helen Koike + */ + +#include +#include +#include +#include +#include + +#include "vimc-common.h" + +#define VIMC_MDEV_MODEL_NAME "VIMC MDEV" + +#define VIMC_ENT_LINK(src, srcpad, sink, sinkpad, link_flags) { \ + .src_ent = src, \ + .src_pad = srcpad, \ + .sink_ent = sink, \ + .sink_pad = sinkpad, \ + .flags = link_flags, \ +} + +/* Structure which describes links between entities */ +struct vimc_ent_link { + unsigned int src_ent; + u16 src_pad; + unsigned int sink_ent; + u16 sink_pad; + u32 flags; +}; + +/* Structure which describes the whole topology */ +struct vimc_pipeline_config { + const struct vimc_ent_config *ents; + size_t num_ents; + const struct vimc_ent_link *links; + size_t num_links; +}; + +/* -------------------------------------------------------------------------- + * Topology Configuration + */ + +static struct vimc_ent_config ent_config[] = { + { + .name = "Sensor A", + .add = vimc_sen_add, + .release = vimc_sen_release, + }, + { + .name = "Sensor B", + .add = vimc_sen_add, + .release = vimc_sen_release, + }, + { + .name = "Debayer A", + .add = vimc_deb_add, + .release = vimc_deb_release, + }, + { + .name = "Debayer B", + .add = vimc_deb_add, + .release = vimc_deb_release, + }, + { + .name = "Raw Capture 0", + .add = vimc_cap_add, + .unregister = vimc_cap_unregister, + .release = vimc_cap_release, + }, + { + .name = "Raw Capture 1", + .add = vimc_cap_add, + .unregister = vimc_cap_unregister, + .release = vimc_cap_release, + }, + { + /* TODO: change this to vimc-input when it is implemented */ + .name = "RGB/YUV Input", + .add = vimc_sen_add, + .release = vimc_sen_release, + }, + { + .name = "Scaler", + .add = vimc_sca_add, + .release = vimc_sca_release, + }, + { + .name = "RGB/YUV Capture", + .add = vimc_cap_add, + .unregister = vimc_cap_unregister, + .release = vimc_cap_release, + }, +}; + +static const struct vimc_ent_link ent_links[] = { + /* Link: Sensor A (Pad 0)->(Pad 0) Debayer A */ + VIMC_ENT_LINK(0, 0, 2, 0, MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE), + /* Link: Sensor A (Pad 0)->(Pad 0) Raw Capture 0 */ + VIMC_ENT_LINK(0, 0, 4, 0, MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE), + /* Link: Sensor B (Pad 0)->(Pad 0) Debayer B */ + VIMC_ENT_LINK(1, 0, 3, 0, MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE), + /* Link: Sensor B (Pad 0)->(Pad 0) Raw Capture 1 */ + VIMC_ENT_LINK(1, 0, 5, 0, MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE), + /* Link: Debayer A (Pad 1)->(Pad 0) Scaler */ + VIMC_ENT_LINK(2, 1, 7, 0, MEDIA_LNK_FL_ENABLED), + /* Link: Debayer B (Pad 1)->(Pad 0) Scaler */ + VIMC_ENT_LINK(3, 1, 7, 0, 0), + /* Link: RGB/YUV Input (Pad 0)->(Pad 0) Scaler */ + VIMC_ENT_LINK(6, 0, 7, 0, 0), + /* Link: Scaler (Pad 1)->(Pad 0) RGB/YUV Capture */ + VIMC_ENT_LINK(7, 1, 8, 0, MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE), +}; + +static struct vimc_pipeline_config pipe_cfg = { + .ents = ent_config, + .num_ents = ARRAY_SIZE(ent_config), + .links = ent_links, + .num_links = ARRAY_SIZE(ent_links) +}; + +/* -------------------------------------------------------------------------- */ + +static void vimc_rm_links(struct vimc_device *vimc) +{ + unsigned int i; + + for (i = 0; i < vimc->pipe_cfg->num_ents; i++) + media_entity_remove_links(vimc->ent_devs[i]->ent); +} + +static int vimc_create_links(struct vimc_device *vimc) +{ + unsigned int i; + int ret; + + /* Initialize the links between entities */ + for (i = 0; i < vimc->pipe_cfg->num_links; i++) { + const struct vimc_ent_link *link = &vimc->pipe_cfg->links[i]; + + struct vimc_ent_device *ved_src = + vimc->ent_devs[link->src_ent]; + struct vimc_ent_device *ved_sink = + vimc->ent_devs[link->sink_ent]; + + ret = media_create_pad_link(ved_src->ent, link->src_pad, + ved_sink->ent, link->sink_pad, + link->flags); + if (ret) + goto err_rm_links; + } + + return 0; + +err_rm_links: + vimc_rm_links(vimc); + return ret; +} + +static int vimc_add_subdevs(struct vimc_device *vimc) +{ + unsigned int i; + + for (i = 0; i < vimc->pipe_cfg->num_ents; i++) { + dev_dbg(vimc->mdev.dev, "new entity for %s\n", + vimc->pipe_cfg->ents[i].name); + vimc->ent_devs[i] = vimc->pipe_cfg->ents[i].add(vimc, + vimc->pipe_cfg->ents[i].name); + if (!vimc->ent_devs[i]) { + dev_err(vimc->mdev.dev, "add new entity for %s\n", + vimc->pipe_cfg->ents[i].name); + return -EINVAL; + } + } + return 0; +} + +static void vimc_release_subdevs(struct vimc_device *vimc) +{ + unsigned int i; + + for (i = 0; i < vimc->pipe_cfg->num_ents; i++) + if (vimc->ent_devs[i]) + vimc->pipe_cfg->ents[i].release(vimc->ent_devs[i]); +} + +static void vimc_unregister_subdevs(struct vimc_device *vimc) +{ + unsigned int i; + + for (i = 0; i < vimc->pipe_cfg->num_ents; i++) + if (vimc->ent_devs[i] && vimc->pipe_cfg->ents[i].unregister) + vimc->pipe_cfg->ents[i].unregister(vimc->ent_devs[i]); +} + +static void vimc_v4l2_dev_release(struct v4l2_device *v4l2_dev) +{ + struct vimc_device *vimc = + container_of(v4l2_dev, struct vimc_device, v4l2_dev); + + vimc_release_subdevs(vimc); + media_device_cleanup(&vimc->mdev); + kfree(vimc->ent_devs); + kfree(vimc); +} + +static int vimc_register_devices(struct vimc_device *vimc) +{ + int ret; + + /* Register the v4l2 struct */ + ret = v4l2_device_register(vimc->mdev.dev, &vimc->v4l2_dev); + if (ret) { + dev_err(vimc->mdev.dev, + "v4l2 device register failed (err=%d)\n", ret); + return ret; + } + /* allocate ent_devs */ + vimc->ent_devs = kcalloc(vimc->pipe_cfg->num_ents, + sizeof(*vimc->ent_devs), GFP_KERNEL); + if (!vimc->ent_devs) { + ret = -ENOMEM; + goto err_v4l2_unregister; + } + + /* Invoke entity config hooks to initialize and register subdevs */ + ret = vimc_add_subdevs(vimc); + if (ret) + /* remove sundevs that got added */ + goto err_rm_subdevs; + + /* Initialize links */ + ret = vimc_create_links(vimc); + if (ret) + goto err_rm_subdevs; + + /* Register the media device */ + ret = media_device_register(&vimc->mdev); + if (ret) { + dev_err(vimc->mdev.dev, + "media device register failed (err=%d)\n", ret); + goto err_rm_subdevs; + } + + /* Expose all subdev's nodes*/ + ret = v4l2_device_register_subdev_nodes(&vimc->v4l2_dev); + if (ret) { + dev_err(vimc->mdev.dev, + "vimc subdev nodes registration failed (err=%d)\n", + ret); + goto err_mdev_unregister; + } + + return 0; + +err_mdev_unregister: + media_device_unregister(&vimc->mdev); +err_rm_subdevs: + vimc_unregister_subdevs(vimc); + vimc_release_subdevs(vimc); + kfree(vimc->ent_devs); +err_v4l2_unregister: + v4l2_device_unregister(&vimc->v4l2_dev); + + return ret; +} + +static void vimc_unregister(struct vimc_device *vimc) +{ + vimc_unregister_subdevs(vimc); + media_device_unregister(&vimc->mdev); + v4l2_device_unregister(&vimc->v4l2_dev); +} + +static int vimc_probe(struct platform_device *pdev) +{ + struct vimc_device *vimc; + int ret; + + dev_dbg(&pdev->dev, "probe"); + + vimc = kzalloc(sizeof(*vimc), GFP_KERNEL); + if (!vimc) + return -ENOMEM; + + vimc->pipe_cfg = &pipe_cfg; + + /* Link the media device within the v4l2_device */ + vimc->v4l2_dev.mdev = &vimc->mdev; + + /* Initialize media device */ + strscpy(vimc->mdev.model, VIMC_MDEV_MODEL_NAME, + sizeof(vimc->mdev.model)); + snprintf(vimc->mdev.bus_info, sizeof(vimc->mdev.bus_info), + "platform:%s", VIMC_PDEV_NAME); + vimc->mdev.dev = &pdev->dev; + media_device_init(&vimc->mdev); + + ret = vimc_register_devices(vimc); + if (ret) { + media_device_cleanup(&vimc->mdev); + kfree(vimc); + return ret; + } + /* + * the release cb is set only after successful registration. + * if the registration fails, we release directly from probe + */ + + vimc->v4l2_dev.release = vimc_v4l2_dev_release; + platform_set_drvdata(pdev, vimc); + return 0; +} + +static int vimc_remove(struct platform_device *pdev) +{ + struct vimc_device *vimc = platform_get_drvdata(pdev); + + dev_dbg(&pdev->dev, "remove"); + + vimc_unregister(vimc); + v4l2_device_put(&vimc->v4l2_dev); + + return 0; +} + +static void vimc_dev_release(struct device *dev) +{ +} + +static struct platform_device vimc_pdev = { + .name = VIMC_PDEV_NAME, + .dev.release = vimc_dev_release, +}; + +static struct platform_driver vimc_pdrv = { + .probe = vimc_probe, + .remove = vimc_remove, + .driver = { + .name = VIMC_PDEV_NAME, + }, +}; + +static int __init vimc_init(void) +{ + int ret; + + ret = platform_device_register(&vimc_pdev); + if (ret) { + dev_err(&vimc_pdev.dev, + "platform device registration failed (err=%d)\n", ret); + return ret; + } + + ret = platform_driver_register(&vimc_pdrv); + if (ret) { + dev_err(&vimc_pdev.dev, + "platform driver registration failed (err=%d)\n", ret); + platform_driver_unregister(&vimc_pdrv); + return ret; + } + + return 0; +} + +static void __exit vimc_exit(void) +{ + platform_driver_unregister(&vimc_pdrv); + + platform_device_unregister(&vimc_pdev); +} + +module_init(vimc_init); +module_exit(vimc_exit); + +MODULE_DESCRIPTION("Virtual Media Controller Driver (VIMC)"); +MODULE_AUTHOR("Helen Fornazier "); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/test_drivers/vimc/vimc-debayer.c b/drivers/media/test_drivers/vimc/vimc-debayer.c new file mode 100644 index 000000000000..baf6bf9f65b5 --- /dev/null +++ b/drivers/media/test_drivers/vimc/vimc-debayer.c @@ -0,0 +1,581 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * vimc-debayer.c Virtual Media Controller Driver + * + * Copyright (C) 2015-2017 Helen Koike + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "vimc-common.h" + +enum vimc_deb_rgb_colors { + VIMC_DEB_RED = 0, + VIMC_DEB_GREEN = 1, + VIMC_DEB_BLUE = 2, +}; + +struct vimc_deb_pix_map { + u32 code; + enum vimc_deb_rgb_colors order[2][2]; +}; + +struct vimc_deb_device { + struct vimc_ent_device ved; + struct v4l2_subdev sd; + /* The active format */ + struct v4l2_mbus_framefmt sink_fmt; + u32 src_code; + void (*set_rgb_src)(struct vimc_deb_device *vdeb, unsigned int lin, + unsigned int col, unsigned int rgb[3]); + /* Values calculated when the stream starts */ + u8 *src_frame; + const struct vimc_deb_pix_map *sink_pix_map; + unsigned int sink_bpp; + unsigned int mean_win_size; + struct v4l2_ctrl_handler hdl; + struct media_pad pads[2]; +}; + +static const struct v4l2_mbus_framefmt sink_fmt_default = { + .width = 640, + .height = 480, + .code = MEDIA_BUS_FMT_SRGGB8_1X8, + .field = V4L2_FIELD_NONE, + .colorspace = V4L2_COLORSPACE_DEFAULT, +}; + +static const struct vimc_deb_pix_map vimc_deb_pix_map_list[] = { + { + .code = MEDIA_BUS_FMT_SBGGR8_1X8, + .order = { { VIMC_DEB_BLUE, VIMC_DEB_GREEN }, + { VIMC_DEB_GREEN, VIMC_DEB_RED } } + }, + { + .code = MEDIA_BUS_FMT_SGBRG8_1X8, + .order = { { VIMC_DEB_GREEN, VIMC_DEB_BLUE }, + { VIMC_DEB_RED, VIMC_DEB_GREEN } } + }, + { + .code = MEDIA_BUS_FMT_SGRBG8_1X8, + .order = { { VIMC_DEB_GREEN, VIMC_DEB_RED }, + { VIMC_DEB_BLUE, VIMC_DEB_GREEN } } + }, + { + .code = MEDIA_BUS_FMT_SRGGB8_1X8, + .order = { { VIMC_DEB_RED, VIMC_DEB_GREEN }, + { VIMC_DEB_GREEN, VIMC_DEB_BLUE } } + }, + { + .code = MEDIA_BUS_FMT_SBGGR10_1X10, + .order = { { VIMC_DEB_BLUE, VIMC_DEB_GREEN }, + { VIMC_DEB_GREEN, VIMC_DEB_RED } } + }, + { + .code = MEDIA_BUS_FMT_SGBRG10_1X10, + .order = { { VIMC_DEB_GREEN, VIMC_DEB_BLUE }, + { VIMC_DEB_RED, VIMC_DEB_GREEN } } + }, + { + .code = MEDIA_BUS_FMT_SGRBG10_1X10, + .order = { { VIMC_DEB_GREEN, VIMC_DEB_RED }, + { VIMC_DEB_BLUE, VIMC_DEB_GREEN } } + }, + { + .code = MEDIA_BUS_FMT_SRGGB10_1X10, + .order = { { VIMC_DEB_RED, VIMC_DEB_GREEN }, + { VIMC_DEB_GREEN, VIMC_DEB_BLUE } } + }, + { + .code = MEDIA_BUS_FMT_SBGGR12_1X12, + .order = { { VIMC_DEB_BLUE, VIMC_DEB_GREEN }, + { VIMC_DEB_GREEN, VIMC_DEB_RED } } + }, + { + .code = MEDIA_BUS_FMT_SGBRG12_1X12, + .order = { { VIMC_DEB_GREEN, VIMC_DEB_BLUE }, + { VIMC_DEB_RED, VIMC_DEB_GREEN } } + }, + { + .code = MEDIA_BUS_FMT_SGRBG12_1X12, + .order = { { VIMC_DEB_GREEN, VIMC_DEB_RED }, + { VIMC_DEB_BLUE, VIMC_DEB_GREEN } } + }, + { + .code = MEDIA_BUS_FMT_SRGGB12_1X12, + .order = { { VIMC_DEB_RED, VIMC_DEB_GREEN }, + { VIMC_DEB_GREEN, VIMC_DEB_BLUE } } + }, +}; + +static const struct vimc_deb_pix_map *vimc_deb_pix_map_by_code(u32 code) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(vimc_deb_pix_map_list); i++) + if (vimc_deb_pix_map_list[i].code == code) + return &vimc_deb_pix_map_list[i]; + + return NULL; +} + +static int vimc_deb_init_cfg(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg) +{ + struct vimc_deb_device *vdeb = v4l2_get_subdevdata(sd); + struct v4l2_mbus_framefmt *mf; + unsigned int i; + + mf = v4l2_subdev_get_try_format(sd, cfg, 0); + *mf = sink_fmt_default; + + for (i = 1; i < sd->entity.num_pads; i++) { + mf = v4l2_subdev_get_try_format(sd, cfg, i); + *mf = sink_fmt_default; + mf->code = vdeb->src_code; + } + + return 0; +} + +static int vimc_deb_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) +{ + /* We only support one format for source pads */ + if (VIMC_IS_SRC(code->pad)) { + struct vimc_deb_device *vdeb = v4l2_get_subdevdata(sd); + + if (code->index) + return -EINVAL; + + code->code = vdeb->src_code; + } else { + if (code->index >= ARRAY_SIZE(vimc_deb_pix_map_list)) + return -EINVAL; + + code->code = vimc_deb_pix_map_list[code->index].code; + } + + return 0; +} + +static int vimc_deb_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_frame_size_enum *fse) +{ + struct vimc_deb_device *vdeb = v4l2_get_subdevdata(sd); + + if (fse->index) + return -EINVAL; + + if (VIMC_IS_SINK(fse->pad)) { + const struct vimc_deb_pix_map *vpix = + vimc_deb_pix_map_by_code(fse->code); + + if (!vpix) + return -EINVAL; + } else if (fse->code != vdeb->src_code) { + return -EINVAL; + } + + fse->min_width = VIMC_FRAME_MIN_WIDTH; + fse->max_width = VIMC_FRAME_MAX_WIDTH; + fse->min_height = VIMC_FRAME_MIN_HEIGHT; + fse->max_height = VIMC_FRAME_MAX_HEIGHT; + + return 0; +} + +static int vimc_deb_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *fmt) +{ + struct vimc_deb_device *vdeb = v4l2_get_subdevdata(sd); + + /* Get the current sink format */ + fmt->format = fmt->which == V4L2_SUBDEV_FORMAT_TRY ? + *v4l2_subdev_get_try_format(sd, cfg, 0) : + vdeb->sink_fmt; + + /* Set the right code for the source pad */ + if (VIMC_IS_SRC(fmt->pad)) + fmt->format.code = vdeb->src_code; + + return 0; +} + +static void vimc_deb_adjust_sink_fmt(struct v4l2_mbus_framefmt *fmt) +{ + const struct vimc_deb_pix_map *vpix; + + /* Don't accept a code that is not on the debayer table */ + vpix = vimc_deb_pix_map_by_code(fmt->code); + if (!vpix) + fmt->code = sink_fmt_default.code; + + fmt->width = clamp_t(u32, fmt->width, VIMC_FRAME_MIN_WIDTH, + VIMC_FRAME_MAX_WIDTH) & ~1; + fmt->height = clamp_t(u32, fmt->height, VIMC_FRAME_MIN_HEIGHT, + VIMC_FRAME_MAX_HEIGHT) & ~1; + + if (fmt->field == V4L2_FIELD_ANY) + fmt->field = sink_fmt_default.field; + + vimc_colorimetry_clamp(fmt); +} + +static int vimc_deb_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *fmt) +{ + struct vimc_deb_device *vdeb = v4l2_get_subdevdata(sd); + struct v4l2_mbus_framefmt *sink_fmt; + + if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { + /* Do not change the format while stream is on */ + if (vdeb->src_frame) + return -EBUSY; + + sink_fmt = &vdeb->sink_fmt; + } else { + sink_fmt = v4l2_subdev_get_try_format(sd, cfg, 0); + } + + /* + * Do not change the format of the source pad, + * it is propagated from the sink + */ + if (VIMC_IS_SRC(fmt->pad)) { + fmt->format = *sink_fmt; + /* TODO: Add support for other formats */ + fmt->format.code = vdeb->src_code; + } else { + /* Set the new format in the sink pad */ + vimc_deb_adjust_sink_fmt(&fmt->format); + + dev_dbg(vdeb->ved.dev, "%s: sink format update: " + "old:%dx%d (0x%x, %d, %d, %d, %d) " + "new:%dx%d (0x%x, %d, %d, %d, %d)\n", vdeb->sd.name, + /* old */ + sink_fmt->width, sink_fmt->height, sink_fmt->code, + sink_fmt->colorspace, sink_fmt->quantization, + sink_fmt->xfer_func, sink_fmt->ycbcr_enc, + /* new */ + fmt->format.width, fmt->format.height, fmt->format.code, + fmt->format.colorspace, fmt->format.quantization, + fmt->format.xfer_func, fmt->format.ycbcr_enc); + + *sink_fmt = fmt->format; + } + + return 0; +} + +static const struct v4l2_subdev_pad_ops vimc_deb_pad_ops = { + .init_cfg = vimc_deb_init_cfg, + .enum_mbus_code = vimc_deb_enum_mbus_code, + .enum_frame_size = vimc_deb_enum_frame_size, + .get_fmt = vimc_deb_get_fmt, + .set_fmt = vimc_deb_set_fmt, +}; + +static void vimc_deb_set_rgb_mbus_fmt_rgb888_1x24(struct vimc_deb_device *vdeb, + unsigned int lin, + unsigned int col, + unsigned int rgb[3]) +{ + unsigned int i, index; + + index = VIMC_FRAME_INDEX(lin, col, vdeb->sink_fmt.width, 3); + for (i = 0; i < 3; i++) + vdeb->src_frame[index + i] = rgb[i]; +} + +static int vimc_deb_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct vimc_deb_device *vdeb = v4l2_get_subdevdata(sd); + + if (enable) { + const struct vimc_pix_map *vpix; + unsigned int frame_size; + + if (vdeb->src_frame) + return 0; + + /* Calculate the frame size of the source pad */ + vpix = vimc_pix_map_by_code(vdeb->src_code); + frame_size = vdeb->sink_fmt.width * vdeb->sink_fmt.height * + vpix->bpp; + + /* Save the bytes per pixel of the sink */ + vpix = vimc_pix_map_by_code(vdeb->sink_fmt.code); + vdeb->sink_bpp = vpix->bpp; + + /* Get the corresponding pixel map from the table */ + vdeb->sink_pix_map = + vimc_deb_pix_map_by_code(vdeb->sink_fmt.code); + + /* + * Allocate the frame buffer. Use vmalloc to be able to + * allocate a large amount of memory + */ + vdeb->src_frame = vmalloc(frame_size); + if (!vdeb->src_frame) + return -ENOMEM; + + } else { + if (!vdeb->src_frame) + return 0; + + vfree(vdeb->src_frame); + vdeb->src_frame = NULL; + } + + return 0; +} + +static const struct v4l2_subdev_core_ops vimc_deb_core_ops = { + .log_status = v4l2_ctrl_subdev_log_status, + .subscribe_event = v4l2_ctrl_subdev_subscribe_event, + .unsubscribe_event = v4l2_event_subdev_unsubscribe, +}; + +static const struct v4l2_subdev_video_ops vimc_deb_video_ops = { + .s_stream = vimc_deb_s_stream, +}; + +static const struct v4l2_subdev_ops vimc_deb_ops = { + .core = &vimc_deb_core_ops, + .pad = &vimc_deb_pad_ops, + .video = &vimc_deb_video_ops, +}; + +static unsigned int vimc_deb_get_val(const u8 *bytes, + const unsigned int n_bytes) +{ + unsigned int i; + unsigned int acc = 0; + + for (i = 0; i < n_bytes; i++) + acc = acc + (bytes[i] << (8 * i)); + + return acc; +} + +static void vimc_deb_calc_rgb_sink(struct vimc_deb_device *vdeb, + const u8 *frame, + const unsigned int lin, + const unsigned int col, + unsigned int rgb[3]) +{ + unsigned int i, seek, wlin, wcol; + unsigned int n_rgb[3] = {0, 0, 0}; + + for (i = 0; i < 3; i++) + rgb[i] = 0; + + /* + * Calculate how many we need to subtract to get to the pixel in + * the top left corner of the mean window (considering the current + * pixel as the center) + */ + seek = vdeb->mean_win_size / 2; + + /* Sum the values of the colors in the mean window */ + + dev_dbg(vdeb->ved.dev, + "deb: %s: --- Calc pixel %dx%d, window mean %d, seek %d ---\n", + vdeb->sd.name, lin, col, vdeb->sink_fmt.height, seek); + + /* + * Iterate through all the lines in the mean window, start + * with zero if the pixel is outside the frame and don't pass + * the height when the pixel is in the bottom border of the + * frame + */ + for (wlin = seek > lin ? 0 : lin - seek; + wlin < lin + seek + 1 && wlin < vdeb->sink_fmt.height; + wlin++) { + + /* + * Iterate through all the columns in the mean window, start + * with zero if the pixel is outside the frame and don't pass + * the width when the pixel is in the right border of the + * frame + */ + for (wcol = seek > col ? 0 : col - seek; + wcol < col + seek + 1 && wcol < vdeb->sink_fmt.width; + wcol++) { + enum vimc_deb_rgb_colors color; + unsigned int index; + + /* Check which color this pixel is */ + color = vdeb->sink_pix_map->order[wlin % 2][wcol % 2]; + + index = VIMC_FRAME_INDEX(wlin, wcol, + vdeb->sink_fmt.width, + vdeb->sink_bpp); + + dev_dbg(vdeb->ved.dev, + "deb: %s: RGB CALC: frame index %d, win pos %dx%d, color %d\n", + vdeb->sd.name, index, wlin, wcol, color); + + /* Get its value */ + rgb[color] = rgb[color] + + vimc_deb_get_val(&frame[index], vdeb->sink_bpp); + + /* Save how many values we already added */ + n_rgb[color]++; + + dev_dbg(vdeb->ved.dev, "deb: %s: RGB CALC: val %d, n %d\n", + vdeb->sd.name, rgb[color], n_rgb[color]); + } + } + + /* Calculate the mean */ + for (i = 0; i < 3; i++) { + dev_dbg(vdeb->ved.dev, + "deb: %s: PRE CALC: %dx%d Color %d, val %d, n %d\n", + vdeb->sd.name, lin, col, i, rgb[i], n_rgb[i]); + + if (n_rgb[i]) + rgb[i] = rgb[i] / n_rgb[i]; + + dev_dbg(vdeb->ved.dev, + "deb: %s: FINAL CALC: %dx%d Color %d, val %d\n", + vdeb->sd.name, lin, col, i, rgb[i]); + } +} + +static void *vimc_deb_process_frame(struct vimc_ent_device *ved, + const void *sink_frame) +{ + struct vimc_deb_device *vdeb = container_of(ved, struct vimc_deb_device, + ved); + unsigned int rgb[3]; + unsigned int i, j; + + /* If the stream in this node is not active, just return */ + if (!vdeb->src_frame) + return ERR_PTR(-EINVAL); + + for (i = 0; i < vdeb->sink_fmt.height; i++) + for (j = 0; j < vdeb->sink_fmt.width; j++) { + vimc_deb_calc_rgb_sink(vdeb, sink_frame, i, j, rgb); + vdeb->set_rgb_src(vdeb, i, j, rgb); + } + + return vdeb->src_frame; +} + +static int vimc_deb_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct vimc_deb_device *vdeb = + container_of(ctrl->handler, struct vimc_deb_device, hdl); + + switch (ctrl->id) { + case VIMC_CID_MEAN_WIN_SIZE: + vdeb->mean_win_size = ctrl->val; + break; + default: + return -EINVAL; + } + return 0; +} + +static const struct v4l2_ctrl_ops vimc_deb_ctrl_ops = { + .s_ctrl = vimc_deb_s_ctrl, +}; + +void vimc_deb_release(struct vimc_ent_device *ved) +{ + struct vimc_deb_device *vdeb = + container_of(ved, struct vimc_deb_device, ved); + + v4l2_ctrl_handler_free(&vdeb->hdl); + media_entity_cleanup(vdeb->ved.ent); + kfree(vdeb); +} + +static const struct v4l2_ctrl_config vimc_deb_ctrl_class = { + .flags = V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_WRITE_ONLY, + .id = VIMC_CID_VIMC_CLASS, + .name = "VIMC Controls", + .type = V4L2_CTRL_TYPE_CTRL_CLASS, +}; + +static const struct v4l2_ctrl_config vimc_deb_ctrl_mean_win_size = { + .ops = &vimc_deb_ctrl_ops, + .id = VIMC_CID_MEAN_WIN_SIZE, + .name = "Debayer Mean Window Size", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = 1, + .max = 25, + .step = 2, + .def = 3, +}; + +struct vimc_ent_device *vimc_deb_add(struct vimc_device *vimc, + const char *vcfg_name) +{ + struct v4l2_device *v4l2_dev = &vimc->v4l2_dev; + struct vimc_deb_device *vdeb; + int ret; + + /* Allocate the vdeb struct */ + vdeb = kzalloc(sizeof(*vdeb), GFP_KERNEL); + if (!vdeb) + return NULL; + + /* Create controls: */ + v4l2_ctrl_handler_init(&vdeb->hdl, 2); + v4l2_ctrl_new_custom(&vdeb->hdl, &vimc_deb_ctrl_class, NULL); + v4l2_ctrl_new_custom(&vdeb->hdl, &vimc_deb_ctrl_mean_win_size, NULL); + vdeb->sd.ctrl_handler = &vdeb->hdl; + if (vdeb->hdl.error) { + ret = vdeb->hdl.error; + goto err_free_vdeb; + } + + /* Initialize ved and sd */ + vdeb->pads[0].flags = MEDIA_PAD_FL_SINK; + vdeb->pads[1].flags = MEDIA_PAD_FL_SOURCE; + + ret = vimc_ent_sd_register(&vdeb->ved, &vdeb->sd, v4l2_dev, + vcfg_name, + MEDIA_ENT_F_PROC_VIDEO_PIXEL_ENC_CONV, 2, + vdeb->pads, &vimc_deb_ops); + if (ret) + goto err_free_hdl; + + vdeb->ved.process_frame = vimc_deb_process_frame; + vdeb->ved.dev = vimc->mdev.dev; + vdeb->mean_win_size = vimc_deb_ctrl_mean_win_size.def; + + /* Initialize the frame format */ + vdeb->sink_fmt = sink_fmt_default; + /* + * TODO: Add support for more output formats, we only support + * RGB888 for now + * NOTE: the src format is always the same as the sink, except + * for the code + */ + vdeb->src_code = MEDIA_BUS_FMT_RGB888_1X24; + vdeb->set_rgb_src = vimc_deb_set_rgb_mbus_fmt_rgb888_1x24; + + return &vdeb->ved; + +err_free_hdl: + v4l2_ctrl_handler_free(&vdeb->hdl); +err_free_vdeb: + kfree(vdeb); + + return NULL; +} diff --git a/drivers/media/test_drivers/vimc/vimc-scaler.c b/drivers/media/test_drivers/vimc/vimc-scaler.c new file mode 100644 index 000000000000..7521439747c5 --- /dev/null +++ b/drivers/media/test_drivers/vimc/vimc-scaler.c @@ -0,0 +1,511 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * vimc-scaler.c Virtual Media Controller Driver + * + * Copyright (C) 2015-2017 Helen Koike + */ + +#include +#include +#include +#include +#include + +#include "vimc-common.h" + +static unsigned int sca_mult = 3; +module_param(sca_mult, uint, 0000); +MODULE_PARM_DESC(sca_mult, " the image size multiplier"); + +#define MAX_ZOOM 8 + +#define VIMC_SCA_FMT_WIDTH_DEFAULT 640 +#define VIMC_SCA_FMT_HEIGHT_DEFAULT 480 + +struct vimc_sca_device { + struct vimc_ent_device ved; + struct v4l2_subdev sd; + /* NOTE: the source fmt is the same as the sink + * with the width and hight multiplied by mult + */ + struct v4l2_mbus_framefmt sink_fmt; + struct v4l2_rect crop_rect; + /* Values calculated when the stream starts */ + u8 *src_frame; + unsigned int src_line_size; + unsigned int bpp; + struct media_pad pads[2]; +}; + +static const struct v4l2_mbus_framefmt sink_fmt_default = { + .width = VIMC_SCA_FMT_WIDTH_DEFAULT, + .height = VIMC_SCA_FMT_HEIGHT_DEFAULT, + .code = MEDIA_BUS_FMT_RGB888_1X24, + .field = V4L2_FIELD_NONE, + .colorspace = V4L2_COLORSPACE_DEFAULT, +}; + +static const struct v4l2_rect crop_rect_default = { + .width = VIMC_SCA_FMT_WIDTH_DEFAULT, + .height = VIMC_SCA_FMT_HEIGHT_DEFAULT, + .top = 0, + .left = 0, +}; + +static const struct v4l2_rect crop_rect_min = { + .width = VIMC_FRAME_MIN_WIDTH, + .height = VIMC_FRAME_MIN_HEIGHT, + .top = 0, + .left = 0, +}; + +static struct v4l2_rect +vimc_sca_get_crop_bound_sink(const struct v4l2_mbus_framefmt *sink_fmt) +{ + /* Get the crop bounds to clamp the crop rectangle correctly */ + struct v4l2_rect r = { + .left = 0, + .top = 0, + .width = sink_fmt->width, + .height = sink_fmt->height, + }; + return r; +} + +static void vimc_sca_adjust_sink_crop(struct v4l2_rect *r, + const struct v4l2_mbus_framefmt *sink_fmt) +{ + const struct v4l2_rect sink_rect = + vimc_sca_get_crop_bound_sink(sink_fmt); + + /* Disallow rectangles smaller than the minimal one. */ + v4l2_rect_set_min_size(r, &crop_rect_min); + v4l2_rect_map_inside(r, &sink_rect); +} + +static int vimc_sca_init_cfg(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg) +{ + struct v4l2_mbus_framefmt *mf; + struct v4l2_rect *r; + unsigned int i; + + mf = v4l2_subdev_get_try_format(sd, cfg, 0); + *mf = sink_fmt_default; + + r = v4l2_subdev_get_try_crop(sd, cfg, 0); + *r = crop_rect_default; + + for (i = 1; i < sd->entity.num_pads; i++) { + mf = v4l2_subdev_get_try_format(sd, cfg, i); + *mf = sink_fmt_default; + mf->width = mf->width * sca_mult; + mf->height = mf->height * sca_mult; + } + + return 0; +} + +static int vimc_sca_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) +{ + const struct vimc_pix_map *vpix = vimc_pix_map_by_index(code->index); + + /* We don't support bayer format */ + if (!vpix || vpix->bayer) + return -EINVAL; + + code->code = vpix->code; + + return 0; +} + +static int vimc_sca_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_frame_size_enum *fse) +{ + const struct vimc_pix_map *vpix; + + if (fse->index) + return -EINVAL; + + /* Only accept code in the pix map table in non bayer format */ + vpix = vimc_pix_map_by_code(fse->code); + if (!vpix || vpix->bayer) + return -EINVAL; + + fse->min_width = VIMC_FRAME_MIN_WIDTH; + fse->min_height = VIMC_FRAME_MIN_HEIGHT; + + if (VIMC_IS_SINK(fse->pad)) { + fse->max_width = VIMC_FRAME_MAX_WIDTH; + fse->max_height = VIMC_FRAME_MAX_HEIGHT; + } else { + fse->max_width = VIMC_FRAME_MAX_WIDTH * MAX_ZOOM; + fse->max_height = VIMC_FRAME_MAX_HEIGHT * MAX_ZOOM; + } + + return 0; +} + +static int vimc_sca_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) +{ + struct vimc_sca_device *vsca = v4l2_get_subdevdata(sd); + struct v4l2_rect *crop_rect; + + /* Get the current sink format */ + if (format->which == V4L2_SUBDEV_FORMAT_TRY) { + format->format = *v4l2_subdev_get_try_format(sd, cfg, 0); + crop_rect = v4l2_subdev_get_try_crop(sd, cfg, 0); + } else { + format->format = vsca->sink_fmt; + crop_rect = &vsca->crop_rect; + } + + /* Scale the frame size for the source pad */ + if (VIMC_IS_SRC(format->pad)) { + format->format.width = crop_rect->width * sca_mult; + format->format.height = crop_rect->height * sca_mult; + } + + return 0; +} + +static void vimc_sca_adjust_sink_fmt(struct v4l2_mbus_framefmt *fmt) +{ + const struct vimc_pix_map *vpix; + + /* Only accept code in the pix map table in non bayer format */ + vpix = vimc_pix_map_by_code(fmt->code); + if (!vpix || vpix->bayer) + fmt->code = sink_fmt_default.code; + + fmt->width = clamp_t(u32, fmt->width, VIMC_FRAME_MIN_WIDTH, + VIMC_FRAME_MAX_WIDTH) & ~1; + fmt->height = clamp_t(u32, fmt->height, VIMC_FRAME_MIN_HEIGHT, + VIMC_FRAME_MAX_HEIGHT) & ~1; + + if (fmt->field == V4L2_FIELD_ANY) + fmt->field = sink_fmt_default.field; + + vimc_colorimetry_clamp(fmt); +} + +static int vimc_sca_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *fmt) +{ + struct vimc_sca_device *vsca = v4l2_get_subdevdata(sd); + struct v4l2_mbus_framefmt *sink_fmt; + struct v4l2_rect *crop_rect; + + if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { + /* Do not change the format while stream is on */ + if (vsca->src_frame) + return -EBUSY; + + sink_fmt = &vsca->sink_fmt; + crop_rect = &vsca->crop_rect; + } else { + sink_fmt = v4l2_subdev_get_try_format(sd, cfg, 0); + crop_rect = v4l2_subdev_get_try_crop(sd, cfg, 0); + } + + /* + * Do not change the format of the source pad, + * it is propagated from the sink + */ + if (VIMC_IS_SRC(fmt->pad)) { + fmt->format = *sink_fmt; + fmt->format.width = crop_rect->width * sca_mult; + fmt->format.height = crop_rect->height * sca_mult; + } else { + /* Set the new format in the sink pad */ + vimc_sca_adjust_sink_fmt(&fmt->format); + + dev_dbg(vsca->ved.dev, "%s: sink format update: " + "old:%dx%d (0x%x, %d, %d, %d, %d) " + "new:%dx%d (0x%x, %d, %d, %d, %d)\n", vsca->sd.name, + /* old */ + sink_fmt->width, sink_fmt->height, sink_fmt->code, + sink_fmt->colorspace, sink_fmt->quantization, + sink_fmt->xfer_func, sink_fmt->ycbcr_enc, + /* new */ + fmt->format.width, fmt->format.height, fmt->format.code, + fmt->format.colorspace, fmt->format.quantization, + fmt->format.xfer_func, fmt->format.ycbcr_enc); + + *sink_fmt = fmt->format; + + /* Do the crop, but respect the current bounds */ + vimc_sca_adjust_sink_crop(crop_rect, sink_fmt); + } + + return 0; +} + +static int vimc_sca_get_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_selection *sel) +{ + struct vimc_sca_device *vsca = v4l2_get_subdevdata(sd); + struct v4l2_mbus_framefmt *sink_fmt; + struct v4l2_rect *crop_rect; + + if (VIMC_IS_SRC(sel->pad)) + return -EINVAL; + + if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) { + sink_fmt = &vsca->sink_fmt; + crop_rect = &vsca->crop_rect; + } else { + sink_fmt = v4l2_subdev_get_try_format(sd, cfg, 0); + crop_rect = v4l2_subdev_get_try_crop(sd, cfg, 0); + } + + switch (sel->target) { + case V4L2_SEL_TGT_CROP: + sel->r = *crop_rect; + break; + case V4L2_SEL_TGT_CROP_BOUNDS: + sel->r = vimc_sca_get_crop_bound_sink(sink_fmt); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int vimc_sca_set_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_selection *sel) +{ + struct vimc_sca_device *vsca = v4l2_get_subdevdata(sd); + struct v4l2_mbus_framefmt *sink_fmt; + struct v4l2_rect *crop_rect; + + if (VIMC_IS_SRC(sel->pad)) + return -EINVAL; + + if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) { + /* Do not change the format while stream is on */ + if (vsca->src_frame) + return -EBUSY; + + crop_rect = &vsca->crop_rect; + sink_fmt = &vsca->sink_fmt; + } else { + crop_rect = v4l2_subdev_get_try_crop(sd, cfg, 0); + sink_fmt = v4l2_subdev_get_try_format(sd, cfg, 0); + } + + switch (sel->target) { + case V4L2_SEL_TGT_CROP: + /* Do the crop, but respect the current bounds */ + vimc_sca_adjust_sink_crop(&sel->r, sink_fmt); + *crop_rect = sel->r; + break; + default: + return -EINVAL; + } + + return 0; +} + +static const struct v4l2_subdev_pad_ops vimc_sca_pad_ops = { + .init_cfg = vimc_sca_init_cfg, + .enum_mbus_code = vimc_sca_enum_mbus_code, + .enum_frame_size = vimc_sca_enum_frame_size, + .get_fmt = vimc_sca_get_fmt, + .set_fmt = vimc_sca_set_fmt, + .get_selection = vimc_sca_get_selection, + .set_selection = vimc_sca_set_selection, +}; + +static int vimc_sca_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct vimc_sca_device *vsca = v4l2_get_subdevdata(sd); + + if (enable) { + const struct vimc_pix_map *vpix; + unsigned int frame_size; + + if (vsca->src_frame) + return 0; + + /* Save the bytes per pixel of the sink */ + vpix = vimc_pix_map_by_code(vsca->sink_fmt.code); + vsca->bpp = vpix->bpp; + + /* Calculate the width in bytes of the src frame */ + vsca->src_line_size = vsca->crop_rect.width * + sca_mult * vsca->bpp; + + /* Calculate the frame size of the source pad */ + frame_size = vsca->src_line_size * vsca->crop_rect.height * + sca_mult; + + /* Allocate the frame buffer. Use vmalloc to be able to + * allocate a large amount of memory + */ + vsca->src_frame = vmalloc(frame_size); + if (!vsca->src_frame) + return -ENOMEM; + + } else { + if (!vsca->src_frame) + return 0; + + vfree(vsca->src_frame); + vsca->src_frame = NULL; + } + + return 0; +} + +static const struct v4l2_subdev_video_ops vimc_sca_video_ops = { + .s_stream = vimc_sca_s_stream, +}; + +static const struct v4l2_subdev_ops vimc_sca_ops = { + .pad = &vimc_sca_pad_ops, + .video = &vimc_sca_video_ops, +}; + +static void vimc_sca_fill_pix(u8 *const ptr, + const u8 *const pixel, + const unsigned int bpp) +{ + unsigned int i; + + /* copy the pixel to the pointer */ + for (i = 0; i < bpp; i++) + ptr[i] = pixel[i]; +} + +static void vimc_sca_scale_pix(const struct vimc_sca_device *const vsca, + unsigned int lin, unsigned int col, + const u8 *const sink_frame) +{ + const struct v4l2_rect crop_rect = vsca->crop_rect; + unsigned int i, j, index; + const u8 *pixel; + + /* Point to the pixel value in position (lin, col) in the sink frame */ + index = VIMC_FRAME_INDEX(lin, col, + vsca->sink_fmt.width, + vsca->bpp); + pixel = &sink_frame[index]; + + dev_dbg(vsca->ved.dev, + "sca: %s: --- scale_pix sink pos %dx%d, index %d ---\n", + vsca->sd.name, lin, col, index); + + /* point to the place we are going to put the first pixel + * in the scaled src frame + */ + lin -= crop_rect.top; + col -= crop_rect.left; + index = VIMC_FRAME_INDEX(lin * sca_mult, col * sca_mult, + crop_rect.width * sca_mult, vsca->bpp); + + dev_dbg(vsca->ved.dev, "sca: %s: scale_pix src pos %dx%d, index %d\n", + vsca->sd.name, lin * sca_mult, col * sca_mult, index); + + /* Repeat this pixel mult times */ + for (i = 0; i < sca_mult; i++) { + /* Iterate through each beginning of a + * pixel repetition in a line + */ + for (j = 0; j < sca_mult * vsca->bpp; j += vsca->bpp) { + dev_dbg(vsca->ved.dev, + "sca: %s: sca: scale_pix src pos %d\n", + vsca->sd.name, index + j); + + /* copy the pixel to the position index + j */ + vimc_sca_fill_pix(&vsca->src_frame[index + j], + pixel, vsca->bpp); + } + + /* move the index to the next line */ + index += vsca->src_line_size; + } +} + +static void vimc_sca_fill_src_frame(const struct vimc_sca_device *const vsca, + const u8 *const sink_frame) +{ + const struct v4l2_rect r = vsca->crop_rect; + unsigned int i, j; + + /* Scale each pixel from the original sink frame */ + /* TODO: implement scale down, only scale up is supported for now */ + for (i = r.top; i < r.top + r.height; i++) + for (j = r.left; j < r.left + r.width; j++) + vimc_sca_scale_pix(vsca, i, j, sink_frame); +} + +static void *vimc_sca_process_frame(struct vimc_ent_device *ved, + const void *sink_frame) +{ + struct vimc_sca_device *vsca = container_of(ved, struct vimc_sca_device, + ved); + + /* If the stream in this node is not active, just return */ + if (!vsca->src_frame) + return ERR_PTR(-EINVAL); + + vimc_sca_fill_src_frame(vsca, sink_frame); + + return vsca->src_frame; +}; + +void vimc_sca_release(struct vimc_ent_device *ved) +{ + struct vimc_sca_device *vsca = + container_of(ved, struct vimc_sca_device, ved); + + media_entity_cleanup(vsca->ved.ent); + kfree(vsca); +} + +struct vimc_ent_device *vimc_sca_add(struct vimc_device *vimc, + const char *vcfg_name) +{ + struct v4l2_device *v4l2_dev = &vimc->v4l2_dev; + struct vimc_sca_device *vsca; + int ret; + + /* Allocate the vsca struct */ + vsca = kzalloc(sizeof(*vsca), GFP_KERNEL); + if (!vsca) + return NULL; + + /* Initialize ved and sd */ + vsca->pads[0].flags = MEDIA_PAD_FL_SINK; + vsca->pads[1].flags = MEDIA_PAD_FL_SOURCE; + + ret = vimc_ent_sd_register(&vsca->ved, &vsca->sd, v4l2_dev, + vcfg_name, + MEDIA_ENT_F_PROC_VIDEO_SCALER, 2, + vsca->pads, &vimc_sca_ops); + if (ret) { + kfree(vsca); + return NULL; + } + + vsca->ved.process_frame = vimc_sca_process_frame; + vsca->ved.dev = vimc->mdev.dev; + + /* Initialize the frame format */ + vsca->sink_fmt = sink_fmt_default; + + /* Initialize the crop selection */ + vsca->crop_rect = crop_rect_default; + + return &vsca->ved; +} diff --git a/drivers/media/test_drivers/vimc/vimc-sensor.c b/drivers/media/test_drivers/vimc/vimc-sensor.c new file mode 100644 index 000000000000..92daee58209e --- /dev/null +++ b/drivers/media/test_drivers/vimc/vimc-sensor.c @@ -0,0 +1,376 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * vimc-sensor.c Virtual Media Controller Driver + * + * Copyright (C) 2015-2017 Helen Koike + */ + +#include +#include +#include +#include +#include +#include + +#include "vimc-common.h" + +struct vimc_sen_device { + struct vimc_ent_device ved; + struct v4l2_subdev sd; + struct tpg_data tpg; + u8 *frame; + /* The active format */ + struct v4l2_mbus_framefmt mbus_format; + struct v4l2_ctrl_handler hdl; + struct media_pad pad; +}; + +static const struct v4l2_mbus_framefmt fmt_default = { + .width = 640, + .height = 480, + .code = MEDIA_BUS_FMT_RGB888_1X24, + .field = V4L2_FIELD_NONE, + .colorspace = V4L2_COLORSPACE_DEFAULT, +}; + +static int vimc_sen_init_cfg(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg) +{ + unsigned int i; + + for (i = 0; i < sd->entity.num_pads; i++) { + struct v4l2_mbus_framefmt *mf; + + mf = v4l2_subdev_get_try_format(sd, cfg, i); + *mf = fmt_default; + } + + return 0; +} + +static int vimc_sen_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) +{ + const struct vimc_pix_map *vpix = vimc_pix_map_by_index(code->index); + + if (!vpix) + return -EINVAL; + + code->code = vpix->code; + + return 0; +} + +static int vimc_sen_enum_frame_size(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_frame_size_enum *fse) +{ + const struct vimc_pix_map *vpix; + + if (fse->index) + return -EINVAL; + + /* Only accept code in the pix map table */ + vpix = vimc_pix_map_by_code(fse->code); + if (!vpix) + return -EINVAL; + + fse->min_width = VIMC_FRAME_MIN_WIDTH; + fse->max_width = VIMC_FRAME_MAX_WIDTH; + fse->min_height = VIMC_FRAME_MIN_HEIGHT; + fse->max_height = VIMC_FRAME_MAX_HEIGHT; + + return 0; +} + +static int vimc_sen_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *fmt) +{ + struct vimc_sen_device *vsen = + container_of(sd, struct vimc_sen_device, sd); + + fmt->format = fmt->which == V4L2_SUBDEV_FORMAT_TRY ? + *v4l2_subdev_get_try_format(sd, cfg, fmt->pad) : + vsen->mbus_format; + + return 0; +} + +static void vimc_sen_tpg_s_format(struct vimc_sen_device *vsen) +{ + const struct vimc_pix_map *vpix = + vimc_pix_map_by_code(vsen->mbus_format.code); + + tpg_reset_source(&vsen->tpg, vsen->mbus_format.width, + vsen->mbus_format.height, vsen->mbus_format.field); + tpg_s_bytesperline(&vsen->tpg, 0, vsen->mbus_format.width * vpix->bpp); + tpg_s_buf_height(&vsen->tpg, vsen->mbus_format.height); + tpg_s_fourcc(&vsen->tpg, vpix->pixelformat); + /* TODO: add support for V4L2_FIELD_ALTERNATE */ + tpg_s_field(&vsen->tpg, vsen->mbus_format.field, false); + tpg_s_colorspace(&vsen->tpg, vsen->mbus_format.colorspace); + tpg_s_ycbcr_enc(&vsen->tpg, vsen->mbus_format.ycbcr_enc); + tpg_s_quantization(&vsen->tpg, vsen->mbus_format.quantization); + tpg_s_xfer_func(&vsen->tpg, vsen->mbus_format.xfer_func); +} + +static void vimc_sen_adjust_fmt(struct v4l2_mbus_framefmt *fmt) +{ + const struct vimc_pix_map *vpix; + + /* Only accept code in the pix map table */ + vpix = vimc_pix_map_by_code(fmt->code); + if (!vpix) + fmt->code = fmt_default.code; + + fmt->width = clamp_t(u32, fmt->width, VIMC_FRAME_MIN_WIDTH, + VIMC_FRAME_MAX_WIDTH) & ~1; + fmt->height = clamp_t(u32, fmt->height, VIMC_FRAME_MIN_HEIGHT, + VIMC_FRAME_MAX_HEIGHT) & ~1; + + /* TODO: add support for V4L2_FIELD_ALTERNATE */ + if (fmt->field == V4L2_FIELD_ANY || fmt->field == V4L2_FIELD_ALTERNATE) + fmt->field = fmt_default.field; + + vimc_colorimetry_clamp(fmt); +} + +static int vimc_sen_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *fmt) +{ + struct vimc_sen_device *vsen = v4l2_get_subdevdata(sd); + struct v4l2_mbus_framefmt *mf; + + if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { + /* Do not change the format while stream is on */ + if (vsen->frame) + return -EBUSY; + + mf = &vsen->mbus_format; + } else { + mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad); + } + + /* Set the new format */ + vimc_sen_adjust_fmt(&fmt->format); + + dev_dbg(vsen->ved.dev, "%s: format update: " + "old:%dx%d (0x%x, %d, %d, %d, %d) " + "new:%dx%d (0x%x, %d, %d, %d, %d)\n", vsen->sd.name, + /* old */ + mf->width, mf->height, mf->code, + mf->colorspace, mf->quantization, + mf->xfer_func, mf->ycbcr_enc, + /* new */ + fmt->format.width, fmt->format.height, fmt->format.code, + fmt->format.colorspace, fmt->format.quantization, + fmt->format.xfer_func, fmt->format.ycbcr_enc); + + *mf = fmt->format; + + return 0; +} + +static const struct v4l2_subdev_pad_ops vimc_sen_pad_ops = { + .init_cfg = vimc_sen_init_cfg, + .enum_mbus_code = vimc_sen_enum_mbus_code, + .enum_frame_size = vimc_sen_enum_frame_size, + .get_fmt = vimc_sen_get_fmt, + .set_fmt = vimc_sen_set_fmt, +}; + +static void *vimc_sen_process_frame(struct vimc_ent_device *ved, + const void *sink_frame) +{ + struct vimc_sen_device *vsen = container_of(ved, struct vimc_sen_device, + ved); + + tpg_fill_plane_buffer(&vsen->tpg, 0, 0, vsen->frame); + return vsen->frame; +} + +static int vimc_sen_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct vimc_sen_device *vsen = + container_of(sd, struct vimc_sen_device, sd); + + if (enable) { + const struct vimc_pix_map *vpix; + unsigned int frame_size; + + /* Calculate the frame size */ + vpix = vimc_pix_map_by_code(vsen->mbus_format.code); + frame_size = vsen->mbus_format.width * vpix->bpp * + vsen->mbus_format.height; + + /* + * Allocate the frame buffer. Use vmalloc to be able to + * allocate a large amount of memory + */ + vsen->frame = vmalloc(frame_size); + if (!vsen->frame) + return -ENOMEM; + + /* configure the test pattern generator */ + vimc_sen_tpg_s_format(vsen); + + } else { + + vfree(vsen->frame); + vsen->frame = NULL; + } + + return 0; +} + +static const struct v4l2_subdev_core_ops vimc_sen_core_ops = { + .log_status = v4l2_ctrl_subdev_log_status, + .subscribe_event = v4l2_ctrl_subdev_subscribe_event, + .unsubscribe_event = v4l2_event_subdev_unsubscribe, +}; + +static const struct v4l2_subdev_video_ops vimc_sen_video_ops = { + .s_stream = vimc_sen_s_stream, +}; + +static const struct v4l2_subdev_ops vimc_sen_ops = { + .core = &vimc_sen_core_ops, + .pad = &vimc_sen_pad_ops, + .video = &vimc_sen_video_ops, +}; + +static int vimc_sen_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct vimc_sen_device *vsen = + container_of(ctrl->handler, struct vimc_sen_device, hdl); + + switch (ctrl->id) { + case VIMC_CID_TEST_PATTERN: + tpg_s_pattern(&vsen->tpg, ctrl->val); + break; + case V4L2_CID_HFLIP: + tpg_s_hflip(&vsen->tpg, ctrl->val); + break; + case V4L2_CID_VFLIP: + tpg_s_vflip(&vsen->tpg, ctrl->val); + break; + case V4L2_CID_BRIGHTNESS: + tpg_s_brightness(&vsen->tpg, ctrl->val); + break; + case V4L2_CID_CONTRAST: + tpg_s_contrast(&vsen->tpg, ctrl->val); + break; + case V4L2_CID_HUE: + tpg_s_hue(&vsen->tpg, ctrl->val); + break; + case V4L2_CID_SATURATION: + tpg_s_saturation(&vsen->tpg, ctrl->val); + break; + default: + return -EINVAL; + } + return 0; +} + +static const struct v4l2_ctrl_ops vimc_sen_ctrl_ops = { + .s_ctrl = vimc_sen_s_ctrl, +}; + +void vimc_sen_release(struct vimc_ent_device *ved) +{ + struct vimc_sen_device *vsen = + container_of(ved, struct vimc_sen_device, ved); + + v4l2_ctrl_handler_free(&vsen->hdl); + tpg_free(&vsen->tpg); + media_entity_cleanup(vsen->ved.ent); + kfree(vsen); +} + +/* Image Processing Controls */ +static const struct v4l2_ctrl_config vimc_sen_ctrl_class = { + .flags = V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_WRITE_ONLY, + .id = VIMC_CID_VIMC_CLASS, + .name = "VIMC Controls", + .type = V4L2_CTRL_TYPE_CTRL_CLASS, +}; + +static const struct v4l2_ctrl_config vimc_sen_ctrl_test_pattern = { + .ops = &vimc_sen_ctrl_ops, + .id = VIMC_CID_TEST_PATTERN, + .name = "Test Pattern", + .type = V4L2_CTRL_TYPE_MENU, + .max = TPG_PAT_NOISE, + .qmenu = tpg_pattern_strings, +}; + +struct vimc_ent_device *vimc_sen_add(struct vimc_device *vimc, + const char *vcfg_name) +{ + struct v4l2_device *v4l2_dev = &vimc->v4l2_dev; + struct vimc_sen_device *vsen; + int ret; + + /* Allocate the vsen struct */ + vsen = kzalloc(sizeof(*vsen), GFP_KERNEL); + if (!vsen) + return NULL; + + v4l2_ctrl_handler_init(&vsen->hdl, 4); + + v4l2_ctrl_new_custom(&vsen->hdl, &vimc_sen_ctrl_class, NULL); + v4l2_ctrl_new_custom(&vsen->hdl, &vimc_sen_ctrl_test_pattern, NULL); + v4l2_ctrl_new_std(&vsen->hdl, &vimc_sen_ctrl_ops, + V4L2_CID_VFLIP, 0, 1, 1, 0); + v4l2_ctrl_new_std(&vsen->hdl, &vimc_sen_ctrl_ops, + V4L2_CID_HFLIP, 0, 1, 1, 0); + v4l2_ctrl_new_std(&vsen->hdl, &vimc_sen_ctrl_ops, + V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); + v4l2_ctrl_new_std(&vsen->hdl, &vimc_sen_ctrl_ops, + V4L2_CID_CONTRAST, 0, 255, 1, 128); + v4l2_ctrl_new_std(&vsen->hdl, &vimc_sen_ctrl_ops, + V4L2_CID_HUE, -128, 127, 1, 0); + v4l2_ctrl_new_std(&vsen->hdl, &vimc_sen_ctrl_ops, + V4L2_CID_SATURATION, 0, 255, 1, 128); + vsen->sd.ctrl_handler = &vsen->hdl; + if (vsen->hdl.error) { + ret = vsen->hdl.error; + goto err_free_vsen; + } + + /* Initialize the test pattern generator */ + tpg_init(&vsen->tpg, vsen->mbus_format.width, + vsen->mbus_format.height); + ret = tpg_alloc(&vsen->tpg, VIMC_FRAME_MAX_WIDTH); + if (ret) + goto err_free_hdl; + + /* Initialize ved and sd */ + vsen->pad.flags = MEDIA_PAD_FL_SOURCE; + ret = vimc_ent_sd_register(&vsen->ved, &vsen->sd, v4l2_dev, + vcfg_name, + MEDIA_ENT_F_CAM_SENSOR, 1, &vsen->pad, + &vimc_sen_ops); + if (ret) + goto err_free_tpg; + + vsen->ved.process_frame = vimc_sen_process_frame; + vsen->ved.dev = vimc->mdev.dev; + + /* Initialize the frame format */ + vsen->mbus_format = fmt_default; + + return &vsen->ved; + +err_free_tpg: + tpg_free(&vsen->tpg); +err_free_hdl: + v4l2_ctrl_handler_free(&vsen->hdl); +err_free_vsen: + kfree(vsen); + + return NULL; +} diff --git a/drivers/media/test_drivers/vimc/vimc-streamer.c b/drivers/media/test_drivers/vimc/vimc-streamer.c new file mode 100644 index 000000000000..65feb3c596db --- /dev/null +++ b/drivers/media/test_drivers/vimc/vimc-streamer.c @@ -0,0 +1,238 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * vimc-streamer.c Virtual Media Controller Driver + * + * Copyright (C) 2018 Lucas A. M. Magalhães + * + */ + +#include +#include +#include + +#include "vimc-streamer.h" + +/** + * vimc_get_source_entity - get the entity connected with the first sink pad + * + * @ent: reference media_entity + * + * Helper function that returns the media entity containing the source pad + * linked with the first sink pad from the given media entity pad list. + * + * Return: The source pad or NULL, if it wasn't found. + */ +static struct media_entity *vimc_get_source_entity(struct media_entity *ent) +{ + struct media_pad *pad; + int i; + + for (i = 0; i < ent->num_pads; i++) { + if (ent->pads[i].flags & MEDIA_PAD_FL_SOURCE) + continue; + pad = media_entity_remote_pad(&ent->pads[i]); + return pad ? pad->entity : NULL; + } + return NULL; +} + +/** + * vimc_streamer_pipeline_terminate - Disable stream in all ved in stream + * + * @stream: the pointer to the stream structure with the pipeline to be + * disabled. + * + * Calls s_stream to disable the stream in each entity of the pipeline + * + */ +static void vimc_streamer_pipeline_terminate(struct vimc_stream *stream) +{ + struct vimc_ent_device *ved; + struct v4l2_subdev *sd; + + while (stream->pipe_size) { + stream->pipe_size--; + ved = stream->ved_pipeline[stream->pipe_size]; + stream->ved_pipeline[stream->pipe_size] = NULL; + + if (!is_media_entity_v4l2_subdev(ved->ent)) + continue; + + sd = media_entity_to_v4l2_subdev(ved->ent); + v4l2_subdev_call(sd, video, s_stream, 0); + } +} + +/** + * vimc_streamer_pipeline_init - Initializes the stream structure + * + * @stream: the pointer to the stream structure to be initialized + * @ved: the pointer to the vimc entity initializing the stream + * + * Initializes the stream structure. Walks through the entity graph to + * construct the pipeline used later on the streamer thread. + * Calls vimc_streamer_s_stream() to enable stream in all entities of + * the pipeline. + * + * Return: 0 if success, error code otherwise. + */ +static int vimc_streamer_pipeline_init(struct vimc_stream *stream, + struct vimc_ent_device *ved) +{ + struct media_entity *entity; + struct video_device *vdev; + struct v4l2_subdev *sd; + int ret = 0; + + stream->pipe_size = 0; + while (stream->pipe_size < VIMC_STREAMER_PIPELINE_MAX_SIZE) { + if (!ved) { + vimc_streamer_pipeline_terminate(stream); + return -EINVAL; + } + stream->ved_pipeline[stream->pipe_size++] = ved; + + if (is_media_entity_v4l2_subdev(ved->ent)) { + sd = media_entity_to_v4l2_subdev(ved->ent); + ret = v4l2_subdev_call(sd, video, s_stream, 1); + if (ret && ret != -ENOIOCTLCMD) { + dev_err(ved->dev, "subdev_call error %s\n", + ved->ent->name); + vimc_streamer_pipeline_terminate(stream); + return ret; + } + } + + entity = vimc_get_source_entity(ved->ent); + /* Check if the end of the pipeline was reached */ + if (!entity) { + /* the first entity of the pipe should be source only */ + if (!vimc_is_source(ved->ent)) { + dev_err(ved->dev, + "first entity in the pipe '%s' is not a source\n", + ved->ent->name); + vimc_streamer_pipeline_terminate(stream); + return -EPIPE; + } + return 0; + } + + /* Get the next device in the pipeline */ + if (is_media_entity_v4l2_subdev(entity)) { + sd = media_entity_to_v4l2_subdev(entity); + ved = v4l2_get_subdevdata(sd); + } else { + vdev = container_of(entity, + struct video_device, + entity); + ved = video_get_drvdata(vdev); + } + } + + vimc_streamer_pipeline_terminate(stream); + return -EINVAL; +} + +/** + * vimc_streamer_thread - Process frames through the pipeline + * + * @data: vimc_stream struct of the current stream + * + * From the source to the sink, gets a frame from each subdevice and send to + * the next one of the pipeline at a fixed framerate. + * + * Return: + * Always zero (created as ``int`` instead of ``void`` to comply with + * kthread API). + */ +static int vimc_streamer_thread(void *data) +{ + struct vimc_stream *stream = data; + u8 *frame = NULL; + int i; + + set_freezable(); + + for (;;) { + try_to_freeze(); + if (kthread_should_stop()) + break; + + for (i = stream->pipe_size - 1; i >= 0; i--) { + frame = stream->ved_pipeline[i]->process_frame( + stream->ved_pipeline[i], frame); + if (!frame || IS_ERR(frame)) + break; + } + //wait for 60hz + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(HZ / 60); + } + + return 0; +} + +/** + * vimc_streamer_s_stream - Start/stop the streaming on the media pipeline + * + * @stream: the pointer to the stream structure of the current stream + * @ved: pointer to the vimc entity of the entity of the stream + * @enable: flag to determine if stream should start/stop + * + * When starting, check if there is no ``stream->kthread`` allocated. This + * should indicate that a stream is already running. Then, it initializes the + * pipeline, creates and runs a kthread to consume buffers through the pipeline. + * When stopping, analogously check if there is a stream running, stop the + * thread and terminates the pipeline. + * + * Return: 0 if success, error code otherwise. + */ +int vimc_streamer_s_stream(struct vimc_stream *stream, + struct vimc_ent_device *ved, + int enable) +{ + int ret; + + if (!stream || !ved) + return -EINVAL; + + if (enable) { + if (stream->kthread) + return 0; + + ret = vimc_streamer_pipeline_init(stream, ved); + if (ret) + return ret; + + stream->kthread = kthread_run(vimc_streamer_thread, stream, + "vimc-streamer thread"); + + if (IS_ERR(stream->kthread)) { + ret = PTR_ERR(stream->kthread); + dev_err(ved->dev, "kthread_run failed with %d\n", ret); + vimc_streamer_pipeline_terminate(stream); + stream->kthread = NULL; + return ret; + } + + } else { + if (!stream->kthread) + return 0; + + ret = kthread_stop(stream->kthread); + /* + * kthread_stop returns -EINTR in cases when streamon was + * immediately followed by streamoff, and the thread didn't had + * a chance to run. Ignore errors to stop the stream in the + * pipeline. + */ + if (ret) + dev_dbg(ved->dev, "kthread_stop returned '%d'\n", ret); + + stream->kthread = NULL; + + vimc_streamer_pipeline_terminate(stream); + } + + return 0; +} diff --git a/drivers/media/test_drivers/vimc/vimc-streamer.h b/drivers/media/test_drivers/vimc/vimc-streamer.h new file mode 100644 index 000000000000..fe3c51f15fad --- /dev/null +++ b/drivers/media/test_drivers/vimc/vimc-streamer.h @@ -0,0 +1,44 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * vimc-streamer.h Virtual Media Controller Driver + * + * Copyright (C) 2018 Lucas A. M. Magalhães + * + */ + +#ifndef _VIMC_STREAMER_H_ +#define _VIMC_STREAMER_H_ + +#include + +#include "vimc-common.h" + +#define VIMC_STREAMER_PIPELINE_MAX_SIZE 16 + +/** + * struct vimc_stream - struct that represents a stream in the pipeline + * + * @pipe: the media pipeline object associated with this stream + * @ved_pipeline: array containing all the entities participating in the + * stream. The order is from a video device (usually a capture device) where + * stream_on was called, to the entity generating the first base image to be + * processed in the pipeline. + * @pipe_size: size of @ved_pipeline + * @kthread: thread that generates the frames of the stream. + * + * When the user call stream_on in a video device, struct vimc_stream is + * used to keep track of all entities and subdevices that generates and + * process frames for the stream. + */ +struct vimc_stream { + struct media_pipeline pipe; + struct vimc_ent_device *ved_pipeline[VIMC_STREAMER_PIPELINE_MAX_SIZE]; + unsigned int pipe_size; + struct task_struct *kthread; +}; + +int vimc_streamer_s_stream(struct vimc_stream *stream, + struct vimc_ent_device *ved, + int enable); + +#endif //_VIMC_STREAMER_H_ diff --git a/drivers/media/test_drivers/vivid/Kconfig b/drivers/media/test_drivers/vivid/Kconfig new file mode 100644 index 000000000000..e2ff06edfa93 --- /dev/null +++ b/drivers/media/test_drivers/vivid/Kconfig @@ -0,0 +1,41 @@ +# SPDX-License-Identifier: GPL-2.0-only +config VIDEO_VIVID + tristate "Virtual Video Test Driver" + depends on VIDEO_DEV && VIDEO_V4L2 && !SPARC32 && !SPARC64 && FB + depends on HAS_DMA + select FONT_SUPPORT + select FONT_8x16 + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + select VIDEOBUF2_VMALLOC + select VIDEOBUF2_DMA_CONTIG + select VIDEO_V4L2_TPG + help + Enables a virtual video driver. This driver emulates a webcam, + TV, S-Video and HDMI capture hardware, including VBI support for + the SDTV inputs. Also video output, VBI output, radio receivers, + transmitters and software defined radio capture is emulated. + + It is highly configurable and is ideal for testing applications. + Error injection is supported to test rare errors that are hard + to reproduce in real hardware. + + Say Y here if you want to test video apps or debug V4L devices. + When in doubt, say N. + +config VIDEO_VIVID_CEC + bool "Enable CEC emulation support" + depends on VIDEO_VIVID + select CEC_CORE + help + When selected the vivid module will emulate the optional + HDMI CEC feature. + +config VIDEO_VIVID_MAX_DEVS + int "Maximum number of devices" + depends on VIDEO_VIVID + default "64" + help + This allows you to specify the maximum number of devices supported + by the vivid driver. diff --git a/drivers/media/test_drivers/vivid/Makefile b/drivers/media/test_drivers/vivid/Makefile new file mode 100644 index 000000000000..b12ad0152a3e --- /dev/null +++ b/drivers/media/test_drivers/vivid/Makefile @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0 +vivid-objs := vivid-core.o vivid-ctrls.o vivid-vid-common.o vivid-vbi-gen.o \ + vivid-vid-cap.o vivid-vid-out.o vivid-kthread-cap.o vivid-kthread-out.o \ + vivid-radio-rx.o vivid-radio-tx.o vivid-radio-common.o \ + vivid-rds-gen.o vivid-sdr-cap.o vivid-vbi-cap.o vivid-vbi-out.o \ + vivid-osd.o vivid-meta-cap.o vivid-meta-out.o \ + vivid-kthread-touch.o vivid-touch-cap.o +ifeq ($(CONFIG_VIDEO_VIVID_CEC),y) + vivid-objs += vivid-cec.o +endif + +obj-$(CONFIG_VIDEO_VIVID) += vivid.o diff --git a/drivers/media/test_drivers/vivid/vivid-cec.c b/drivers/media/test_drivers/vivid/vivid-cec.c new file mode 100644 index 000000000000..4d2413e87730 --- /dev/null +++ b/drivers/media/test_drivers/vivid/vivid-cec.c @@ -0,0 +1,286 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * vivid-cec.c - A Virtual Video Test Driver, cec emulation + * + * Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved. + */ + +#include + +#include "vivid-core.h" +#include "vivid-cec.h" + +#define CEC_TIM_START_BIT_TOTAL 4500 +#define CEC_TIM_START_BIT_LOW 3700 +#define CEC_TIM_START_BIT_HIGH 800 +#define CEC_TIM_DATA_BIT_TOTAL 2400 +#define CEC_TIM_DATA_BIT_0_LOW 1500 +#define CEC_TIM_DATA_BIT_0_HIGH 900 +#define CEC_TIM_DATA_BIT_1_LOW 600 +#define CEC_TIM_DATA_BIT_1_HIGH 1800 + +void vivid_cec_bus_free_work(struct vivid_dev *dev) +{ + spin_lock(&dev->cec_slock); + while (!list_empty(&dev->cec_work_list)) { + struct vivid_cec_work *cw = + list_first_entry(&dev->cec_work_list, + struct vivid_cec_work, list); + + spin_unlock(&dev->cec_slock); + cancel_delayed_work_sync(&cw->work); + spin_lock(&dev->cec_slock); + list_del(&cw->list); + cec_transmit_attempt_done(cw->adap, CEC_TX_STATUS_LOW_DRIVE); + kfree(cw); + } + spin_unlock(&dev->cec_slock); +} + +static bool vivid_cec_find_dest_adap(struct vivid_dev *dev, + struct cec_adapter *adap, u8 dest) +{ + unsigned int i; + + if (dest >= 0xf) + return false; + + if (adap != dev->cec_rx_adap && dev->cec_rx_adap && + dev->cec_rx_adap->is_configured && + cec_has_log_addr(dev->cec_rx_adap, dest)) + return true; + + for (i = 0; i < MAX_OUTPUTS && dev->cec_tx_adap[i]; i++) { + if (adap == dev->cec_tx_adap[i]) + continue; + if (!dev->cec_tx_adap[i]->is_configured) + continue; + if (cec_has_log_addr(dev->cec_tx_adap[i], dest)) + return true; + } + return false; +} + +static void vivid_cec_pin_adap_events(struct cec_adapter *adap, ktime_t ts, + const struct cec_msg *msg, bool nacked) +{ + unsigned int len = nacked ? 1 : msg->len; + unsigned int i; + bool bit; + + if (adap == NULL) + return; + + /* + * Suffix ULL on constant 10 makes the expression + * CEC_TIM_START_BIT_TOTAL + 10ULL * len * CEC_TIM_DATA_BIT_TOTAL + * to be evaluated using 64-bit unsigned arithmetic (u64), which + * is what ktime_sub_us expects as second argument. + */ + ts = ktime_sub_us(ts, CEC_TIM_START_BIT_TOTAL + + 10ULL * len * CEC_TIM_DATA_BIT_TOTAL); + cec_queue_pin_cec_event(adap, false, false, ts); + ts = ktime_add_us(ts, CEC_TIM_START_BIT_LOW); + cec_queue_pin_cec_event(adap, true, false, ts); + ts = ktime_add_us(ts, CEC_TIM_START_BIT_HIGH); + + for (i = 0; i < 10 * len; i++) { + switch (i % 10) { + case 0 ... 7: + bit = msg->msg[i / 10] & (0x80 >> (i % 10)); + break; + case 8: /* EOM */ + bit = i / 10 == msg->len - 1; + break; + case 9: /* ACK */ + bit = cec_msg_is_broadcast(msg) ^ nacked; + break; + } + cec_queue_pin_cec_event(adap, false, false, ts); + if (bit) + ts = ktime_add_us(ts, CEC_TIM_DATA_BIT_1_LOW); + else + ts = ktime_add_us(ts, CEC_TIM_DATA_BIT_0_LOW); + cec_queue_pin_cec_event(adap, true, false, ts); + if (bit) + ts = ktime_add_us(ts, CEC_TIM_DATA_BIT_1_HIGH); + else + ts = ktime_add_us(ts, CEC_TIM_DATA_BIT_0_HIGH); + } +} + +static void vivid_cec_pin_events(struct vivid_dev *dev, + const struct cec_msg *msg, bool nacked) +{ + ktime_t ts = ktime_get(); + unsigned int i; + + vivid_cec_pin_adap_events(dev->cec_rx_adap, ts, msg, nacked); + for (i = 0; i < MAX_OUTPUTS; i++) + vivid_cec_pin_adap_events(dev->cec_tx_adap[i], ts, msg, nacked); +} + +static void vivid_cec_xfer_done_worker(struct work_struct *work) +{ + struct vivid_cec_work *cw = + container_of(work, struct vivid_cec_work, work.work); + struct vivid_dev *dev = cw->dev; + struct cec_adapter *adap = cw->adap; + u8 dest = cec_msg_destination(&cw->msg); + bool valid_dest; + unsigned int i; + + valid_dest = cec_msg_is_broadcast(&cw->msg); + if (!valid_dest) + valid_dest = vivid_cec_find_dest_adap(dev, adap, dest); + + cw->tx_status = valid_dest ? CEC_TX_STATUS_OK : CEC_TX_STATUS_NACK; + spin_lock(&dev->cec_slock); + dev->cec_xfer_time_jiffies = 0; + dev->cec_xfer_start_jiffies = 0; + list_del(&cw->list); + spin_unlock(&dev->cec_slock); + vivid_cec_pin_events(dev, &cw->msg, !valid_dest); + cec_transmit_attempt_done(cw->adap, cw->tx_status); + + /* Broadcast message */ + if (adap != dev->cec_rx_adap) + cec_received_msg(dev->cec_rx_adap, &cw->msg); + for (i = 0; i < MAX_OUTPUTS && dev->cec_tx_adap[i]; i++) + if (adap != dev->cec_tx_adap[i]) + cec_received_msg(dev->cec_tx_adap[i], &cw->msg); + kfree(cw); +} + +static void vivid_cec_xfer_try_worker(struct work_struct *work) +{ + struct vivid_cec_work *cw = + container_of(work, struct vivid_cec_work, work.work); + struct vivid_dev *dev = cw->dev; + + spin_lock(&dev->cec_slock); + if (dev->cec_xfer_time_jiffies) { + list_del(&cw->list); + spin_unlock(&dev->cec_slock); + cec_transmit_attempt_done(cw->adap, CEC_TX_STATUS_ARB_LOST); + kfree(cw); + } else { + INIT_DELAYED_WORK(&cw->work, vivid_cec_xfer_done_worker); + dev->cec_xfer_start_jiffies = jiffies; + dev->cec_xfer_time_jiffies = usecs_to_jiffies(cw->usecs); + spin_unlock(&dev->cec_slock); + schedule_delayed_work(&cw->work, dev->cec_xfer_time_jiffies); + } +} + +static int vivid_cec_adap_enable(struct cec_adapter *adap, bool enable) +{ + adap->cec_pin_is_high = true; + return 0; +} + +static int vivid_cec_adap_log_addr(struct cec_adapter *adap, u8 log_addr) +{ + return 0; +} + +/* + * One data bit takes 2400 us, each byte needs 10 bits so that's 24000 us + * per byte. + */ +#define USECS_PER_BYTE 24000 + +static int vivid_cec_adap_transmit(struct cec_adapter *adap, u8 attempts, + u32 signal_free_time, struct cec_msg *msg) +{ + struct vivid_dev *dev = cec_get_drvdata(adap); + struct vivid_cec_work *cw = kzalloc(sizeof(*cw), GFP_KERNEL); + long delta_jiffies = 0; + + if (cw == NULL) + return -ENOMEM; + cw->dev = dev; + cw->adap = adap; + cw->usecs = CEC_FREE_TIME_TO_USEC(signal_free_time) + + msg->len * USECS_PER_BYTE; + cw->msg = *msg; + + spin_lock(&dev->cec_slock); + list_add(&cw->list, &dev->cec_work_list); + if (dev->cec_xfer_time_jiffies == 0) { + INIT_DELAYED_WORK(&cw->work, vivid_cec_xfer_done_worker); + dev->cec_xfer_start_jiffies = jiffies; + dev->cec_xfer_time_jiffies = usecs_to_jiffies(cw->usecs); + delta_jiffies = dev->cec_xfer_time_jiffies; + } else { + INIT_DELAYED_WORK(&cw->work, vivid_cec_xfer_try_worker); + delta_jiffies = dev->cec_xfer_start_jiffies + + dev->cec_xfer_time_jiffies - jiffies; + } + spin_unlock(&dev->cec_slock); + schedule_delayed_work(&cw->work, delta_jiffies < 0 ? 0 : delta_jiffies); + return 0; +} + +static int vivid_received(struct cec_adapter *adap, struct cec_msg *msg) +{ + struct vivid_dev *dev = cec_get_drvdata(adap); + struct cec_msg reply; + u8 dest = cec_msg_destination(msg); + u8 disp_ctl; + char osd[14]; + + if (cec_msg_is_broadcast(msg)) + dest = adap->log_addrs.log_addr[0]; + cec_msg_init(&reply, dest, cec_msg_initiator(msg)); + + switch (cec_msg_opcode(msg)) { + case CEC_MSG_SET_OSD_STRING: + if (!cec_is_sink(adap)) + return -ENOMSG; + cec_ops_set_osd_string(msg, &disp_ctl, osd); + switch (disp_ctl) { + case CEC_OP_DISP_CTL_DEFAULT: + strscpy(dev->osd, osd, sizeof(dev->osd)); + dev->osd_jiffies = jiffies; + break; + case CEC_OP_DISP_CTL_UNTIL_CLEARED: + strscpy(dev->osd, osd, sizeof(dev->osd)); + dev->osd_jiffies = 0; + break; + case CEC_OP_DISP_CTL_CLEAR: + dev->osd[0] = 0; + dev->osd_jiffies = 0; + break; + default: + cec_msg_feature_abort(&reply, cec_msg_opcode(msg), + CEC_OP_ABORT_INVALID_OP); + cec_transmit_msg(adap, &reply, false); + break; + } + break; + default: + return -ENOMSG; + } + return 0; +} + +static const struct cec_adap_ops vivid_cec_adap_ops = { + .adap_enable = vivid_cec_adap_enable, + .adap_log_addr = vivid_cec_adap_log_addr, + .adap_transmit = vivid_cec_adap_transmit, + .received = vivid_received, +}; + +struct cec_adapter *vivid_cec_alloc_adap(struct vivid_dev *dev, + unsigned int idx, + bool is_source) +{ + u32 caps = CEC_CAP_DEFAULTS | CEC_CAP_MONITOR_ALL | CEC_CAP_MONITOR_PIN; + char name[32]; + + snprintf(name, sizeof(name), "vivid-%03d-vid-%s%d", + dev->inst, is_source ? "out" : "cap", idx); + return cec_allocate_adapter(&vivid_cec_adap_ops, dev, + name, caps, 1); +} diff --git a/drivers/media/test_drivers/vivid/vivid-cec.h b/drivers/media/test_drivers/vivid/vivid-cec.h new file mode 100644 index 000000000000..7524ed48a914 --- /dev/null +++ b/drivers/media/test_drivers/vivid/vivid-cec.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * vivid-cec.h - A Virtual Video Test Driver, cec emulation + * + * Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved. + */ + +#ifdef CONFIG_VIDEO_VIVID_CEC +struct cec_adapter *vivid_cec_alloc_adap(struct vivid_dev *dev, + unsigned int idx, + bool is_source); +void vivid_cec_bus_free_work(struct vivid_dev *dev); + +#else + +static inline void vivid_cec_bus_free_work(struct vivid_dev *dev) +{ +} + +#endif diff --git a/drivers/media/test_drivers/vivid/vivid-core.c b/drivers/media/test_drivers/vivid/vivid-core.c new file mode 100644 index 000000000000..6c740e3e6999 --- /dev/null +++ b/drivers/media/test_drivers/vivid/vivid-core.c @@ -0,0 +1,2006 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * vivid-core.c - A Virtual Video Test Driver, core initialization + * + * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "vivid-core.h" +#include "vivid-vid-common.h" +#include "vivid-vid-cap.h" +#include "vivid-vid-out.h" +#include "vivid-radio-common.h" +#include "vivid-radio-rx.h" +#include "vivid-radio-tx.h" +#include "vivid-sdr-cap.h" +#include "vivid-vbi-cap.h" +#include "vivid-vbi-out.h" +#include "vivid-osd.h" +#include "vivid-cec.h" +#include "vivid-ctrls.h" +#include "vivid-meta-cap.h" +#include "vivid-meta-out.h" +#include "vivid-touch-cap.h" + +#define VIVID_MODULE_NAME "vivid" + +/* The maximum number of vivid devices */ +#define VIVID_MAX_DEVS CONFIG_VIDEO_VIVID_MAX_DEVS + +MODULE_DESCRIPTION("Virtual Video Test Driver"); +MODULE_AUTHOR("Hans Verkuil"); +MODULE_LICENSE("GPL"); + +static unsigned n_devs = 1; +module_param(n_devs, uint, 0444); +MODULE_PARM_DESC(n_devs, " number of driver instances to create"); + +static int vid_cap_nr[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 }; +module_param_array(vid_cap_nr, int, NULL, 0444); +MODULE_PARM_DESC(vid_cap_nr, " videoX start number, -1 is autodetect"); + +static int vid_out_nr[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 }; +module_param_array(vid_out_nr, int, NULL, 0444); +MODULE_PARM_DESC(vid_out_nr, " videoX start number, -1 is autodetect"); + +static int vbi_cap_nr[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 }; +module_param_array(vbi_cap_nr, int, NULL, 0444); +MODULE_PARM_DESC(vbi_cap_nr, " vbiX start number, -1 is autodetect"); + +static int vbi_out_nr[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 }; +module_param_array(vbi_out_nr, int, NULL, 0444); +MODULE_PARM_DESC(vbi_out_nr, " vbiX start number, -1 is autodetect"); + +static int sdr_cap_nr[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 }; +module_param_array(sdr_cap_nr, int, NULL, 0444); +MODULE_PARM_DESC(sdr_cap_nr, " swradioX start number, -1 is autodetect"); + +static int radio_rx_nr[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 }; +module_param_array(radio_rx_nr, int, NULL, 0444); +MODULE_PARM_DESC(radio_rx_nr, " radioX start number, -1 is autodetect"); + +static int radio_tx_nr[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 }; +module_param_array(radio_tx_nr, int, NULL, 0444); +MODULE_PARM_DESC(radio_tx_nr, " radioX start number, -1 is autodetect"); + +static int meta_cap_nr[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 }; +module_param_array(meta_cap_nr, int, NULL, 0444); +MODULE_PARM_DESC(meta_cap_nr, " videoX start number, -1 is autodetect"); + +static int meta_out_nr[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 }; +module_param_array(meta_out_nr, int, NULL, 0444); +MODULE_PARM_DESC(meta_out_nr, " videoX start number, -1 is autodetect"); + +static int touch_cap_nr[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 }; +module_param_array(touch_cap_nr, int, NULL, 0444); +MODULE_PARM_DESC(touch_cap_nr, " v4l-touchX start number, -1 is autodetect"); + +static int ccs_cap_mode[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 }; +module_param_array(ccs_cap_mode, int, NULL, 0444); +MODULE_PARM_DESC(ccs_cap_mode, " capture crop/compose/scale mode:\n" + "\t\t bit 0=crop, 1=compose, 2=scale,\n" + "\t\t -1=user-controlled (default)"); + +static int ccs_out_mode[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 }; +module_param_array(ccs_out_mode, int, NULL, 0444); +MODULE_PARM_DESC(ccs_out_mode, " output crop/compose/scale mode:\n" + "\t\t bit 0=crop, 1=compose, 2=scale,\n" + "\t\t -1=user-controlled (default)"); + +static unsigned multiplanar[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = 1 }; +module_param_array(multiplanar, uint, NULL, 0444); +MODULE_PARM_DESC(multiplanar, " 1 (default) creates a single planar device, 2 creates a multiplanar device."); + +/* + * Default: video + vbi-cap (raw and sliced) + radio rx + radio tx + sdr + + * vbi-out + vid-out + meta-cap + */ +static unsigned int node_types[VIVID_MAX_DEVS] = { + [0 ... (VIVID_MAX_DEVS - 1)] = 0xe1d3d +}; +module_param_array(node_types, uint, NULL, 0444); +MODULE_PARM_DESC(node_types, " node types, default is 0xe1d3d. Bitmask with the following meaning:\n" + "\t\t bit 0: Video Capture node\n" + "\t\t bit 2-3: VBI Capture node: 0 = none, 1 = raw vbi, 2 = sliced vbi, 3 = both\n" + "\t\t bit 4: Radio Receiver node\n" + "\t\t bit 5: Software Defined Radio Receiver node\n" + "\t\t bit 8: Video Output node\n" + "\t\t bit 10-11: VBI Output node: 0 = none, 1 = raw vbi, 2 = sliced vbi, 3 = both\n" + "\t\t bit 12: Radio Transmitter node\n" + "\t\t bit 16: Framebuffer for testing overlays\n" + "\t\t bit 17: Metadata Capture node\n" + "\t\t bit 18: Metadata Output node\n" + "\t\t bit 19: Touch Capture node\n"); + +/* Default: 4 inputs */ +static unsigned num_inputs[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = 4 }; +module_param_array(num_inputs, uint, NULL, 0444); +MODULE_PARM_DESC(num_inputs, " number of inputs, default is 4"); + +/* Default: input 0 = WEBCAM, 1 = TV, 2 = SVID, 3 = HDMI */ +static unsigned input_types[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = 0xe4 }; +module_param_array(input_types, uint, NULL, 0444); +MODULE_PARM_DESC(input_types, " input types, default is 0xe4. Two bits per input,\n" + "\t\t bits 0-1 == input 0, bits 31-30 == input 15.\n" + "\t\t Type 0 == webcam, 1 == TV, 2 == S-Video, 3 == HDMI"); + +/* Default: 2 outputs */ +static unsigned num_outputs[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = 2 }; +module_param_array(num_outputs, uint, NULL, 0444); +MODULE_PARM_DESC(num_outputs, " number of outputs, default is 2"); + +/* Default: output 0 = SVID, 1 = HDMI */ +static unsigned output_types[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = 2 }; +module_param_array(output_types, uint, NULL, 0444); +MODULE_PARM_DESC(output_types, " output types, default is 0x02. One bit per output,\n" + "\t\t bit 0 == output 0, bit 15 == output 15.\n" + "\t\t Type 0 == S-Video, 1 == HDMI"); + +unsigned vivid_debug; +module_param(vivid_debug, uint, 0644); +MODULE_PARM_DESC(vivid_debug, " activates debug info"); + +static bool no_error_inj; +module_param(no_error_inj, bool, 0444); +MODULE_PARM_DESC(no_error_inj, " if set disable the error injecting controls"); + +static unsigned int allocators[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = 0 }; +module_param_array(allocators, uint, NULL, 0444); +MODULE_PARM_DESC(allocators, " memory allocator selection, default is 0.\n" + "\t\t 0 == vmalloc\n" + "\t\t 1 == dma-contig"); + +static struct vivid_dev *vivid_devs[VIVID_MAX_DEVS]; + +const struct v4l2_rect vivid_min_rect = { + 0, 0, MIN_WIDTH, MIN_HEIGHT +}; + +const struct v4l2_rect vivid_max_rect = { + 0, 0, MAX_WIDTH * MAX_ZOOM, MAX_HEIGHT * MAX_ZOOM +}; + +static const u8 vivid_hdmi_edid[256] = { + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x31, 0xd8, 0x34, 0x12, 0x00, 0x00, 0x00, 0x00, + 0x22, 0x1a, 0x01, 0x03, 0x80, 0x60, 0x36, 0x78, + 0x0f, 0xee, 0x91, 0xa3, 0x54, 0x4c, 0x99, 0x26, + 0x0f, 0x50, 0x54, 0x2f, 0xcf, 0x00, 0x31, 0x59, + 0x45, 0x59, 0x81, 0x80, 0x81, 0x40, 0x90, 0x40, + 0x95, 0x00, 0xa9, 0x40, 0xb3, 0x00, 0x08, 0xe8, + 0x00, 0x30, 0xf2, 0x70, 0x5a, 0x80, 0xb0, 0x58, + 0x8a, 0x00, 0xc0, 0x1c, 0x32, 0x00, 0x00, 0x1e, + 0x00, 0x00, 0x00, 0xfd, 0x00, 0x18, 0x55, 0x18, + 0x87, 0x3c, 0x00, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x76, + 0x69, 0x76, 0x69, 0x64, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x10, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x7b, + + 0x02, 0x03, 0x3f, 0xf0, 0x51, 0x61, 0x60, 0x5f, + 0x5e, 0x5d, 0x10, 0x1f, 0x04, 0x13, 0x22, 0x21, + 0x20, 0x05, 0x14, 0x02, 0x11, 0x01, 0x23, 0x09, + 0x07, 0x07, 0x83, 0x01, 0x00, 0x00, 0x6d, 0x03, + 0x0c, 0x00, 0x10, 0x00, 0x00, 0x3c, 0x21, 0x00, + 0x60, 0x01, 0x02, 0x03, 0x67, 0xd8, 0x5d, 0xc4, + 0x01, 0x78, 0x00, 0x00, 0xe2, 0x00, 0xea, 0xe3, + 0x05, 0x00, 0x00, 0xe3, 0x06, 0x01, 0x00, 0x4d, + 0xd0, 0x00, 0xa0, 0xf0, 0x70, 0x3e, 0x80, 0x30, + 0x20, 0x35, 0x00, 0xc0, 0x1c, 0x32, 0x00, 0x00, + 0x1e, 0x1a, 0x36, 0x80, 0xa0, 0x70, 0x38, 0x1f, + 0x40, 0x30, 0x20, 0x35, 0x00, 0xc0, 0x1c, 0x32, + 0x00, 0x00, 0x1a, 0x1a, 0x1d, 0x00, 0x80, 0x51, + 0xd0, 0x1c, 0x20, 0x40, 0x80, 0x35, 0x00, 0xc0, + 0x1c, 0x32, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, +}; + +static int vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct vivid_dev *dev = video_drvdata(file); + + strscpy(cap->driver, "vivid", sizeof(cap->driver)); + strscpy(cap->card, "vivid", sizeof(cap->card)); + snprintf(cap->bus_info, sizeof(cap->bus_info), + "platform:%s", dev->v4l2_dev.name); + + cap->capabilities = dev->vid_cap_caps | dev->vid_out_caps | + dev->vbi_cap_caps | dev->vbi_out_caps | + dev->radio_rx_caps | dev->radio_tx_caps | + dev->sdr_cap_caps | dev->meta_cap_caps | + dev->meta_out_caps | dev->touch_cap_caps | + V4L2_CAP_DEVICE_CAPS; + return 0; +} + +static int vidioc_s_hw_freq_seek(struct file *file, void *fh, const struct v4l2_hw_freq_seek *a) +{ + struct video_device *vdev = video_devdata(file); + + if (vdev->vfl_type == VFL_TYPE_RADIO) + return vivid_radio_rx_s_hw_freq_seek(file, fh, a); + return -ENOTTY; +} + +static int vidioc_enum_freq_bands(struct file *file, void *fh, struct v4l2_frequency_band *band) +{ + struct video_device *vdev = video_devdata(file); + + if (vdev->vfl_type == VFL_TYPE_RADIO) + return vivid_radio_rx_enum_freq_bands(file, fh, band); + if (vdev->vfl_type == VFL_TYPE_SDR) + return vivid_sdr_enum_freq_bands(file, fh, band); + return -ENOTTY; +} + +static int vidioc_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt) +{ + struct video_device *vdev = video_devdata(file); + + if (vdev->vfl_type == VFL_TYPE_RADIO) + return vivid_radio_rx_g_tuner(file, fh, vt); + if (vdev->vfl_type == VFL_TYPE_SDR) + return vivid_sdr_g_tuner(file, fh, vt); + return vivid_video_g_tuner(file, fh, vt); +} + +static int vidioc_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *vt) +{ + struct video_device *vdev = video_devdata(file); + + if (vdev->vfl_type == VFL_TYPE_RADIO) + return vivid_radio_rx_s_tuner(file, fh, vt); + if (vdev->vfl_type == VFL_TYPE_SDR) + return vivid_sdr_s_tuner(file, fh, vt); + return vivid_video_s_tuner(file, fh, vt); +} + +static int vidioc_g_frequency(struct file *file, void *fh, struct v4l2_frequency *vf) +{ + struct vivid_dev *dev = video_drvdata(file); + struct video_device *vdev = video_devdata(file); + + if (vdev->vfl_type == VFL_TYPE_RADIO) + return vivid_radio_g_frequency(file, + vdev->vfl_dir == VFL_DIR_RX ? + &dev->radio_rx_freq : &dev->radio_tx_freq, vf); + if (vdev->vfl_type == VFL_TYPE_SDR) + return vivid_sdr_g_frequency(file, fh, vf); + return vivid_video_g_frequency(file, fh, vf); +} + +static int vidioc_s_frequency(struct file *file, void *fh, const struct v4l2_frequency *vf) +{ + struct vivid_dev *dev = video_drvdata(file); + struct video_device *vdev = video_devdata(file); + + if (vdev->vfl_type == VFL_TYPE_RADIO) + return vivid_radio_s_frequency(file, + vdev->vfl_dir == VFL_DIR_RX ? + &dev->radio_rx_freq : &dev->radio_tx_freq, vf); + if (vdev->vfl_type == VFL_TYPE_SDR) + return vivid_sdr_s_frequency(file, fh, vf); + return vivid_video_s_frequency(file, fh, vf); +} + +static int vidioc_overlay(struct file *file, void *fh, unsigned i) +{ + struct video_device *vdev = video_devdata(file); + + if (vdev->vfl_dir == VFL_DIR_RX) + return vivid_vid_cap_overlay(file, fh, i); + return vivid_vid_out_overlay(file, fh, i); +} + +static int vidioc_g_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *a) +{ + struct video_device *vdev = video_devdata(file); + + if (vdev->vfl_dir == VFL_DIR_RX) + return vivid_vid_cap_g_fbuf(file, fh, a); + return vivid_vid_out_g_fbuf(file, fh, a); +} + +static int vidioc_s_fbuf(struct file *file, void *fh, const struct v4l2_framebuffer *a) +{ + struct video_device *vdev = video_devdata(file); + + if (vdev->vfl_dir == VFL_DIR_RX) + return vivid_vid_cap_s_fbuf(file, fh, a); + return vivid_vid_out_s_fbuf(file, fh, a); +} + +static int vidioc_s_std(struct file *file, void *fh, v4l2_std_id id) +{ + struct video_device *vdev = video_devdata(file); + + if (vdev->vfl_dir == VFL_DIR_RX) + return vivid_vid_cap_s_std(file, fh, id); + return vivid_vid_out_s_std(file, fh, id); +} + +static int vidioc_s_dv_timings(struct file *file, void *fh, struct v4l2_dv_timings *timings) +{ + struct video_device *vdev = video_devdata(file); + + if (vdev->vfl_dir == VFL_DIR_RX) + return vivid_vid_cap_s_dv_timings(file, fh, timings); + return vivid_vid_out_s_dv_timings(file, fh, timings); +} + +static int vidioc_g_pixelaspect(struct file *file, void *fh, + int type, struct v4l2_fract *f) +{ + struct video_device *vdev = video_devdata(file); + + if (vdev->vfl_dir == VFL_DIR_RX) + return vivid_vid_cap_g_pixelaspect(file, fh, type, f); + return vivid_vid_out_g_pixelaspect(file, fh, type, f); +} + +static int vidioc_g_selection(struct file *file, void *fh, + struct v4l2_selection *sel) +{ + struct video_device *vdev = video_devdata(file); + + if (vdev->vfl_dir == VFL_DIR_RX) + return vivid_vid_cap_g_selection(file, fh, sel); + return vivid_vid_out_g_selection(file, fh, sel); +} + +static int vidioc_s_selection(struct file *file, void *fh, + struct v4l2_selection *sel) +{ + struct video_device *vdev = video_devdata(file); + + if (vdev->vfl_dir == VFL_DIR_RX) + return vivid_vid_cap_s_selection(file, fh, sel); + return vivid_vid_out_s_selection(file, fh, sel); +} + +static int vidioc_g_parm(struct file *file, void *fh, + struct v4l2_streamparm *parm) +{ + struct video_device *vdev = video_devdata(file); + + if (vdev->vfl_type == VFL_TYPE_TOUCH) + return vivid_g_parm_tch(file, fh, parm); + if (vdev->vfl_dir == VFL_DIR_RX) + return vivid_vid_cap_g_parm(file, fh, parm); + return vivid_vid_out_g_parm(file, fh, parm); +} + +static int vidioc_s_parm(struct file *file, void *fh, + struct v4l2_streamparm *parm) +{ + struct video_device *vdev = video_devdata(file); + + if (vdev->vfl_dir == VFL_DIR_RX) + return vivid_vid_cap_s_parm(file, fh, parm); + return -ENOTTY; +} + +static int vidioc_log_status(struct file *file, void *fh) +{ + struct vivid_dev *dev = video_drvdata(file); + struct video_device *vdev = video_devdata(file); + + v4l2_ctrl_log_status(file, fh); + if (vdev->vfl_dir == VFL_DIR_RX && vdev->vfl_type == VFL_TYPE_VIDEO) + tpg_log_status(&dev->tpg); + return 0; +} + +static ssize_t vivid_radio_read(struct file *file, char __user *buf, + size_t size, loff_t *offset) +{ + struct video_device *vdev = video_devdata(file); + + if (vdev->vfl_dir == VFL_DIR_TX) + return -EINVAL; + return vivid_radio_rx_read(file, buf, size, offset); +} + +static ssize_t vivid_radio_write(struct file *file, const char __user *buf, + size_t size, loff_t *offset) +{ + struct video_device *vdev = video_devdata(file); + + if (vdev->vfl_dir == VFL_DIR_RX) + return -EINVAL; + return vivid_radio_tx_write(file, buf, size, offset); +} + +static __poll_t vivid_radio_poll(struct file *file, struct poll_table_struct *wait) +{ + struct video_device *vdev = video_devdata(file); + + if (vdev->vfl_dir == VFL_DIR_RX) + return vivid_radio_rx_poll(file, wait); + return vivid_radio_tx_poll(file, wait); +} + +static int vivid_enum_input(struct file *file, void *priv, + struct v4l2_input *inp) +{ + struct video_device *vdev = video_devdata(file); + + if (vdev->vfl_type == VFL_TYPE_TOUCH) + return vivid_enum_input_tch(file, priv, inp); + return vidioc_enum_input(file, priv, inp); +} + +static int vivid_g_input(struct file *file, void *priv, unsigned int *i) +{ + struct video_device *vdev = video_devdata(file); + + if (vdev->vfl_type == VFL_TYPE_TOUCH) + return vivid_g_input_tch(file, priv, i); + return vidioc_g_input(file, priv, i); +} + +static int vivid_s_input(struct file *file, void *priv, unsigned int i) +{ + struct video_device *vdev = video_devdata(file); + + if (vdev->vfl_type == VFL_TYPE_TOUCH) + return vivid_s_input_tch(file, priv, i); + return vidioc_s_input(file, priv, i); +} + +static int vivid_enum_fmt_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + struct video_device *vdev = video_devdata(file); + + if (vdev->vfl_type == VFL_TYPE_TOUCH) + return vivid_enum_fmt_tch(file, priv, f); + return vivid_enum_fmt_vid(file, priv, f); +} + +static int vivid_g_fmt_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct video_device *vdev = video_devdata(file); + + if (vdev->vfl_type == VFL_TYPE_TOUCH) + return vivid_g_fmt_tch(file, priv, f); + return vidioc_g_fmt_vid_cap(file, priv, f); +} + +static int vivid_try_fmt_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct video_device *vdev = video_devdata(file); + + if (vdev->vfl_type == VFL_TYPE_TOUCH) + return vivid_g_fmt_tch(file, priv, f); + return vidioc_try_fmt_vid_cap(file, priv, f); +} + +static int vivid_s_fmt_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct video_device *vdev = video_devdata(file); + + if (vdev->vfl_type == VFL_TYPE_TOUCH) + return vivid_g_fmt_tch(file, priv, f); + return vidioc_s_fmt_vid_cap(file, priv, f); +} + +static int vivid_g_fmt_cap_mplane(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct video_device *vdev = video_devdata(file); + + if (vdev->vfl_type == VFL_TYPE_TOUCH) + return vivid_g_fmt_tch_mplane(file, priv, f); + return vidioc_g_fmt_vid_cap_mplane(file, priv, f); +} + +static int vivid_try_fmt_cap_mplane(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct video_device *vdev = video_devdata(file); + + if (vdev->vfl_type == VFL_TYPE_TOUCH) + return vivid_g_fmt_tch_mplane(file, priv, f); + return vidioc_try_fmt_vid_cap_mplane(file, priv, f); +} + +static int vivid_s_fmt_cap_mplane(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct video_device *vdev = video_devdata(file); + + if (vdev->vfl_type == VFL_TYPE_TOUCH) + return vivid_g_fmt_tch_mplane(file, priv, f); + return vidioc_s_fmt_vid_cap_mplane(file, priv, f); +} + +static bool vivid_is_in_use(struct video_device *vdev) +{ + unsigned long flags; + bool res; + + spin_lock_irqsave(&vdev->fh_lock, flags); + res = !list_empty(&vdev->fh_list); + spin_unlock_irqrestore(&vdev->fh_lock, flags); + return res; +} + +static bool vivid_is_last_user(struct vivid_dev *dev) +{ + unsigned uses = vivid_is_in_use(&dev->vid_cap_dev) + + vivid_is_in_use(&dev->vid_out_dev) + + vivid_is_in_use(&dev->vbi_cap_dev) + + vivid_is_in_use(&dev->vbi_out_dev) + + vivid_is_in_use(&dev->sdr_cap_dev) + + vivid_is_in_use(&dev->radio_rx_dev) + + vivid_is_in_use(&dev->radio_tx_dev) + + vivid_is_in_use(&dev->meta_cap_dev) + + vivid_is_in_use(&dev->meta_out_dev) + + vivid_is_in_use(&dev->touch_cap_dev); + + return uses == 1; +} + +static int vivid_fop_release(struct file *file) +{ + struct vivid_dev *dev = video_drvdata(file); + struct video_device *vdev = video_devdata(file); + + mutex_lock(&dev->mutex); + if (!no_error_inj && v4l2_fh_is_singular_file(file) && + !video_is_registered(vdev) && vivid_is_last_user(dev)) { + /* + * I am the last user of this driver, and a disconnect + * was forced (since this video_device is unregistered), + * so re-register all video_device's again. + */ + v4l2_info(&dev->v4l2_dev, "reconnect\n"); + set_bit(V4L2_FL_REGISTERED, &dev->vid_cap_dev.flags); + set_bit(V4L2_FL_REGISTERED, &dev->vid_out_dev.flags); + set_bit(V4L2_FL_REGISTERED, &dev->vbi_cap_dev.flags); + set_bit(V4L2_FL_REGISTERED, &dev->vbi_out_dev.flags); + set_bit(V4L2_FL_REGISTERED, &dev->sdr_cap_dev.flags); + set_bit(V4L2_FL_REGISTERED, &dev->radio_rx_dev.flags); + set_bit(V4L2_FL_REGISTERED, &dev->radio_tx_dev.flags); + set_bit(V4L2_FL_REGISTERED, &dev->meta_cap_dev.flags); + set_bit(V4L2_FL_REGISTERED, &dev->meta_out_dev.flags); + set_bit(V4L2_FL_REGISTERED, &dev->touch_cap_dev.flags); + } + mutex_unlock(&dev->mutex); + if (file->private_data == dev->overlay_cap_owner) + dev->overlay_cap_owner = NULL; + if (file->private_data == dev->radio_rx_rds_owner) { + dev->radio_rx_rds_last_block = 0; + dev->radio_rx_rds_owner = NULL; + } + if (file->private_data == dev->radio_tx_rds_owner) { + dev->radio_tx_rds_last_block = 0; + dev->radio_tx_rds_owner = NULL; + } + if (vdev->queue) + return vb2_fop_release(file); + return v4l2_fh_release(file); +} + +static const struct v4l2_file_operations vivid_fops = { + .owner = THIS_MODULE, + .open = v4l2_fh_open, + .release = vivid_fop_release, + .read = vb2_fop_read, + .write = vb2_fop_write, + .poll = vb2_fop_poll, + .unlocked_ioctl = video_ioctl2, + .mmap = vb2_fop_mmap, +}; + +static const struct v4l2_file_operations vivid_radio_fops = { + .owner = THIS_MODULE, + .open = v4l2_fh_open, + .release = vivid_fop_release, + .read = vivid_radio_read, + .write = vivid_radio_write, + .poll = vivid_radio_poll, + .unlocked_ioctl = video_ioctl2, +}; + +static const struct v4l2_ioctl_ops vivid_ioctl_ops = { + .vidioc_querycap = vidioc_querycap, + + .vidioc_enum_fmt_vid_cap = vivid_enum_fmt_cap, + .vidioc_g_fmt_vid_cap = vivid_g_fmt_cap, + .vidioc_try_fmt_vid_cap = vivid_try_fmt_cap, + .vidioc_s_fmt_vid_cap = vivid_s_fmt_cap, + .vidioc_g_fmt_vid_cap_mplane = vivid_g_fmt_cap_mplane, + .vidioc_try_fmt_vid_cap_mplane = vivid_try_fmt_cap_mplane, + .vidioc_s_fmt_vid_cap_mplane = vivid_s_fmt_cap_mplane, + + .vidioc_enum_fmt_vid_out = vivid_enum_fmt_vid, + .vidioc_g_fmt_vid_out = vidioc_g_fmt_vid_out, + .vidioc_try_fmt_vid_out = vidioc_try_fmt_vid_out, + .vidioc_s_fmt_vid_out = vidioc_s_fmt_vid_out, + .vidioc_g_fmt_vid_out_mplane = vidioc_g_fmt_vid_out_mplane, + .vidioc_try_fmt_vid_out_mplane = vidioc_try_fmt_vid_out_mplane, + .vidioc_s_fmt_vid_out_mplane = vidioc_s_fmt_vid_out_mplane, + + .vidioc_g_selection = vidioc_g_selection, + .vidioc_s_selection = vidioc_s_selection, + .vidioc_g_pixelaspect = vidioc_g_pixelaspect, + + .vidioc_g_fmt_vbi_cap = vidioc_g_fmt_vbi_cap, + .vidioc_try_fmt_vbi_cap = vidioc_g_fmt_vbi_cap, + .vidioc_s_fmt_vbi_cap = vidioc_s_fmt_vbi_cap, + + .vidioc_g_fmt_sliced_vbi_cap = vidioc_g_fmt_sliced_vbi_cap, + .vidioc_try_fmt_sliced_vbi_cap = vidioc_try_fmt_sliced_vbi_cap, + .vidioc_s_fmt_sliced_vbi_cap = vidioc_s_fmt_sliced_vbi_cap, + .vidioc_g_sliced_vbi_cap = vidioc_g_sliced_vbi_cap, + + .vidioc_g_fmt_vbi_out = vidioc_g_fmt_vbi_out, + .vidioc_try_fmt_vbi_out = vidioc_g_fmt_vbi_out, + .vidioc_s_fmt_vbi_out = vidioc_s_fmt_vbi_out, + + .vidioc_g_fmt_sliced_vbi_out = vidioc_g_fmt_sliced_vbi_out, + .vidioc_try_fmt_sliced_vbi_out = vidioc_try_fmt_sliced_vbi_out, + .vidioc_s_fmt_sliced_vbi_out = vidioc_s_fmt_sliced_vbi_out, + + .vidioc_enum_fmt_sdr_cap = vidioc_enum_fmt_sdr_cap, + .vidioc_g_fmt_sdr_cap = vidioc_g_fmt_sdr_cap, + .vidioc_try_fmt_sdr_cap = vidioc_try_fmt_sdr_cap, + .vidioc_s_fmt_sdr_cap = vidioc_s_fmt_sdr_cap, + + .vidioc_overlay = vidioc_overlay, + .vidioc_enum_framesizes = vidioc_enum_framesizes, + .vidioc_enum_frameintervals = vidioc_enum_frameintervals, + .vidioc_g_parm = vidioc_g_parm, + .vidioc_s_parm = vidioc_s_parm, + + .vidioc_enum_fmt_vid_overlay = vidioc_enum_fmt_vid_overlay, + .vidioc_g_fmt_vid_overlay = vidioc_g_fmt_vid_overlay, + .vidioc_try_fmt_vid_overlay = vidioc_try_fmt_vid_overlay, + .vidioc_s_fmt_vid_overlay = vidioc_s_fmt_vid_overlay, + .vidioc_g_fmt_vid_out_overlay = vidioc_g_fmt_vid_out_overlay, + .vidioc_try_fmt_vid_out_overlay = vidioc_try_fmt_vid_out_overlay, + .vidioc_s_fmt_vid_out_overlay = vidioc_s_fmt_vid_out_overlay, + .vidioc_g_fbuf = vidioc_g_fbuf, + .vidioc_s_fbuf = vidioc_s_fbuf, + + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_expbuf = vb2_ioctl_expbuf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, + + .vidioc_enum_input = vivid_enum_input, + .vidioc_g_input = vivid_g_input, + .vidioc_s_input = vivid_s_input, + .vidioc_s_audio = vidioc_s_audio, + .vidioc_g_audio = vidioc_g_audio, + .vidioc_enumaudio = vidioc_enumaudio, + .vidioc_s_frequency = vidioc_s_frequency, + .vidioc_g_frequency = vidioc_g_frequency, + .vidioc_s_tuner = vidioc_s_tuner, + .vidioc_g_tuner = vidioc_g_tuner, + .vidioc_s_modulator = vidioc_s_modulator, + .vidioc_g_modulator = vidioc_g_modulator, + .vidioc_s_hw_freq_seek = vidioc_s_hw_freq_seek, + .vidioc_enum_freq_bands = vidioc_enum_freq_bands, + + .vidioc_enum_output = vidioc_enum_output, + .vidioc_g_output = vidioc_g_output, + .vidioc_s_output = vidioc_s_output, + .vidioc_s_audout = vidioc_s_audout, + .vidioc_g_audout = vidioc_g_audout, + .vidioc_enumaudout = vidioc_enumaudout, + + .vidioc_querystd = vidioc_querystd, + .vidioc_g_std = vidioc_g_std, + .vidioc_s_std = vidioc_s_std, + .vidioc_s_dv_timings = vidioc_s_dv_timings, + .vidioc_g_dv_timings = vidioc_g_dv_timings, + .vidioc_query_dv_timings = vidioc_query_dv_timings, + .vidioc_enum_dv_timings = vidioc_enum_dv_timings, + .vidioc_dv_timings_cap = vidioc_dv_timings_cap, + .vidioc_g_edid = vidioc_g_edid, + .vidioc_s_edid = vidioc_s_edid, + + .vidioc_log_status = vidioc_log_status, + .vidioc_subscribe_event = vidioc_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, + + .vidioc_enum_fmt_meta_cap = vidioc_enum_fmt_meta_cap, + .vidioc_g_fmt_meta_cap = vidioc_g_fmt_meta_cap, + .vidioc_s_fmt_meta_cap = vidioc_g_fmt_meta_cap, + .vidioc_try_fmt_meta_cap = vidioc_g_fmt_meta_cap, + + .vidioc_enum_fmt_meta_out = vidioc_enum_fmt_meta_out, + .vidioc_g_fmt_meta_out = vidioc_g_fmt_meta_out, + .vidioc_s_fmt_meta_out = vidioc_g_fmt_meta_out, + .vidioc_try_fmt_meta_out = vidioc_g_fmt_meta_out, +}; + +/* ----------------------------------------------------------------- + Initialization and module stuff + ------------------------------------------------------------------*/ + +static void vivid_dev_release(struct v4l2_device *v4l2_dev) +{ + struct vivid_dev *dev = container_of(v4l2_dev, struct vivid_dev, v4l2_dev); + + vivid_free_controls(dev); + v4l2_device_unregister(&dev->v4l2_dev); +#ifdef CONFIG_MEDIA_CONTROLLER + media_device_cleanup(&dev->mdev); +#endif + vfree(dev->scaled_line); + vfree(dev->blended_line); + vfree(dev->edid); + vfree(dev->bitmap_cap); + vfree(dev->bitmap_out); + tpg_free(&dev->tpg); + kfree(dev->query_dv_timings_qmenu); + kfree(dev->query_dv_timings_qmenu_strings); + kfree(dev); +} + +#ifdef CONFIG_MEDIA_CONTROLLER +static int vivid_req_validate(struct media_request *req) +{ + struct vivid_dev *dev = container_of(req->mdev, struct vivid_dev, mdev); + + if (dev->req_validate_error) { + dev->req_validate_error = false; + return -EINVAL; + } + return vb2_request_validate(req); +} + +static const struct media_device_ops vivid_media_ops = { + .req_validate = vivid_req_validate, + .req_queue = vb2_request_queue, +}; +#endif + +static int vivid_create_queue(struct vivid_dev *dev, + struct vb2_queue *q, + u32 buf_type, + unsigned int min_buffers_needed, + const struct vb2_ops *ops) +{ + if (buf_type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->multiplanar) + buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + else if (buf_type == V4L2_BUF_TYPE_VIDEO_OUTPUT && dev->multiplanar) + buf_type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + else if (buf_type == V4L2_BUF_TYPE_VBI_CAPTURE && !dev->has_raw_vbi_cap) + buf_type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE; + else if (buf_type == V4L2_BUF_TYPE_VBI_OUTPUT && !dev->has_raw_vbi_out) + buf_type = V4L2_BUF_TYPE_SLICED_VBI_OUTPUT; + + q->type = buf_type; + q->io_modes = VB2_MMAP | VB2_DMABUF; + q->io_modes |= V4L2_TYPE_IS_OUTPUT(buf_type) ? VB2_WRITE : VB2_READ; + if (allocators[dev->inst] != 1) + q->io_modes |= VB2_USERPTR; + q->drv_priv = dev; + q->buf_struct_size = sizeof(struct vivid_buffer); + q->ops = ops; + q->mem_ops = allocators[dev->inst] == 1 ? &vb2_dma_contig_memops : + &vb2_vmalloc_memops; + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + q->min_buffers_needed = min_buffers_needed; + q->lock = &dev->mutex; + q->dev = dev->v4l2_dev.dev; + q->supports_requests = true; + + return vb2_queue_init(q); +} + +static int vivid_create_instance(struct platform_device *pdev, int inst) +{ + static const struct v4l2_dv_timings def_dv_timings = + V4L2_DV_BT_CEA_1280X720P60; + unsigned in_type_counter[4] = { 0, 0, 0, 0 }; + unsigned out_type_counter[4] = { 0, 0, 0, 0 }; + int ccs_cap = ccs_cap_mode[inst]; + int ccs_out = ccs_out_mode[inst]; + bool has_tuner; + bool has_modulator; + struct vivid_dev *dev; + struct video_device *vfd; + unsigned node_type = node_types[inst]; + v4l2_std_id tvnorms_cap = 0, tvnorms_out = 0; + int ret; + int i; +#ifdef CONFIG_VIDEO_VIVID_CEC + unsigned int cec_tx_bus_cnt = 0; +#endif + + /* allocate main vivid state structure */ + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) + return -ENOMEM; + + dev->inst = inst; + +#ifdef CONFIG_MEDIA_CONTROLLER + dev->v4l2_dev.mdev = &dev->mdev; + + /* Initialize media device */ + strscpy(dev->mdev.model, VIVID_MODULE_NAME, sizeof(dev->mdev.model)); + snprintf(dev->mdev.bus_info, sizeof(dev->mdev.bus_info), + "platform:%s-%03d", VIVID_MODULE_NAME, inst); + dev->mdev.dev = &pdev->dev; + media_device_init(&dev->mdev); + dev->mdev.ops = &vivid_media_ops; +#endif + + /* register v4l2_device */ + snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name), + "%s-%03d", VIVID_MODULE_NAME, inst); + ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); + if (ret) { + kfree(dev); + return ret; + } + dev->v4l2_dev.release = vivid_dev_release; + + /* start detecting feature set */ + + /* do we use single- or multi-planar? */ + dev->multiplanar = multiplanar[inst] > 1; + v4l2_info(&dev->v4l2_dev, "using %splanar format API\n", + dev->multiplanar ? "multi" : "single "); + + /* how many inputs do we have and of what type? */ + dev->num_inputs = num_inputs[inst]; + if (dev->num_inputs < 1) + dev->num_inputs = 1; + if (dev->num_inputs >= MAX_INPUTS) + dev->num_inputs = MAX_INPUTS; + for (i = 0; i < dev->num_inputs; i++) { + dev->input_type[i] = (input_types[inst] >> (i * 2)) & 0x3; + dev->input_name_counter[i] = in_type_counter[dev->input_type[i]]++; + } + dev->has_audio_inputs = in_type_counter[TV] && in_type_counter[SVID]; + if (in_type_counter[HDMI] == 16) { + /* The CEC physical address only allows for max 15 inputs */ + in_type_counter[HDMI]--; + dev->num_inputs--; + } + dev->num_hdmi_inputs = in_type_counter[HDMI]; + + /* how many outputs do we have and of what type? */ + dev->num_outputs = num_outputs[inst]; + if (dev->num_outputs < 1) + dev->num_outputs = 1; + if (dev->num_outputs >= MAX_OUTPUTS) + dev->num_outputs = MAX_OUTPUTS; + for (i = 0; i < dev->num_outputs; i++) { + dev->output_type[i] = ((output_types[inst] >> i) & 1) ? HDMI : SVID; + dev->output_name_counter[i] = out_type_counter[dev->output_type[i]]++; + dev->display_present[i] = true; + } + dev->has_audio_outputs = out_type_counter[SVID]; + if (out_type_counter[HDMI] == 16) { + /* + * The CEC physical address only allows for max 15 inputs, + * so outputs are also limited to 15 to allow for easy + * CEC output to input mapping. + */ + out_type_counter[HDMI]--; + dev->num_outputs--; + } + dev->num_hdmi_outputs = out_type_counter[HDMI]; + + /* do we create a video capture device? */ + dev->has_vid_cap = node_type & 0x0001; + + /* do we create a vbi capture device? */ + if (in_type_counter[TV] || in_type_counter[SVID]) { + dev->has_raw_vbi_cap = node_type & 0x0004; + dev->has_sliced_vbi_cap = node_type & 0x0008; + dev->has_vbi_cap = dev->has_raw_vbi_cap | dev->has_sliced_vbi_cap; + } + + /* do we create a meta capture device */ + dev->has_meta_cap = node_type & 0x20000; + + /* sanity checks */ + if ((in_type_counter[WEBCAM] || in_type_counter[HDMI]) && + !dev->has_vid_cap && !dev->has_meta_cap) { + v4l2_warn(&dev->v4l2_dev, + "Webcam or HDMI input without video or metadata nodes\n"); + kfree(dev); + return -EINVAL; + } + if ((in_type_counter[TV] || in_type_counter[SVID]) && + !dev->has_vid_cap && !dev->has_vbi_cap && !dev->has_meta_cap) { + v4l2_warn(&dev->v4l2_dev, + "TV or S-Video input without video, VBI or metadata nodes\n"); + kfree(dev); + return -EINVAL; + } + + /* do we create a video output device? */ + dev->has_vid_out = node_type & 0x0100; + + /* do we create a vbi output device? */ + if (out_type_counter[SVID]) { + dev->has_raw_vbi_out = node_type & 0x0400; + dev->has_sliced_vbi_out = node_type & 0x0800; + dev->has_vbi_out = dev->has_raw_vbi_out | dev->has_sliced_vbi_out; + } + + /* do we create a metadata output device */ + dev->has_meta_out = node_type & 0x40000; + + /* sanity checks */ + if (out_type_counter[SVID] && + !dev->has_vid_out && !dev->has_vbi_out && !dev->has_meta_out) { + v4l2_warn(&dev->v4l2_dev, + "S-Video output without video, VBI or metadata nodes\n"); + kfree(dev); + return -EINVAL; + } + if (out_type_counter[HDMI] && !dev->has_vid_out && !dev->has_meta_out) { + v4l2_warn(&dev->v4l2_dev, + "HDMI output without video or metadata nodes\n"); + kfree(dev); + return -EINVAL; + } + + /* do we create a radio receiver device? */ + dev->has_radio_rx = node_type & 0x0010; + + /* do we create a radio transmitter device? */ + dev->has_radio_tx = node_type & 0x1000; + + /* do we create a software defined radio capture device? */ + dev->has_sdr_cap = node_type & 0x0020; + + /* do we have a TV tuner? */ + dev->has_tv_tuner = in_type_counter[TV]; + + /* do we have a tuner? */ + has_tuner = ((dev->has_vid_cap || dev->has_vbi_cap) && in_type_counter[TV]) || + dev->has_radio_rx || dev->has_sdr_cap; + + /* do we have a modulator? */ + has_modulator = dev->has_radio_tx; + + if (dev->has_vid_cap) + /* do we have a framebuffer for overlay testing? */ + dev->has_fb = node_type & 0x10000; + + /* can we do crop/compose/scaling while capturing? */ + if (no_error_inj && ccs_cap == -1) + ccs_cap = 7; + + /* if ccs_cap == -1, then the user can select it using controls */ + if (ccs_cap != -1) { + dev->has_crop_cap = ccs_cap & 1; + dev->has_compose_cap = ccs_cap & 2; + dev->has_scaler_cap = ccs_cap & 4; + v4l2_info(&dev->v4l2_dev, "Capture Crop: %c Compose: %c Scaler: %c\n", + dev->has_crop_cap ? 'Y' : 'N', + dev->has_compose_cap ? 'Y' : 'N', + dev->has_scaler_cap ? 'Y' : 'N'); + } + + /* can we do crop/compose/scaling with video output? */ + if (no_error_inj && ccs_out == -1) + ccs_out = 7; + + /* if ccs_out == -1, then the user can select it using controls */ + if (ccs_out != -1) { + dev->has_crop_out = ccs_out & 1; + dev->has_compose_out = ccs_out & 2; + dev->has_scaler_out = ccs_out & 4; + v4l2_info(&dev->v4l2_dev, "Output Crop: %c Compose: %c Scaler: %c\n", + dev->has_crop_out ? 'Y' : 'N', + dev->has_compose_out ? 'Y' : 'N', + dev->has_scaler_out ? 'Y' : 'N'); + } + + /* do we create a touch capture device */ + dev->has_touch_cap = node_type & 0x80000; + + /* end detecting feature set */ + + if (dev->has_vid_cap) { + /* set up the capabilities of the video capture device */ + dev->vid_cap_caps = dev->multiplanar ? + V4L2_CAP_VIDEO_CAPTURE_MPLANE : + V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OVERLAY; + dev->vid_cap_caps |= V4L2_CAP_STREAMING | V4L2_CAP_READWRITE; + if (dev->has_audio_inputs) + dev->vid_cap_caps |= V4L2_CAP_AUDIO; + if (dev->has_tv_tuner) + dev->vid_cap_caps |= V4L2_CAP_TUNER; + } + if (dev->has_vid_out) { + /* set up the capabilities of the video output device */ + dev->vid_out_caps = dev->multiplanar ? + V4L2_CAP_VIDEO_OUTPUT_MPLANE : + V4L2_CAP_VIDEO_OUTPUT; + if (dev->has_fb) + dev->vid_out_caps |= V4L2_CAP_VIDEO_OUTPUT_OVERLAY; + dev->vid_out_caps |= V4L2_CAP_STREAMING | V4L2_CAP_READWRITE; + if (dev->has_audio_outputs) + dev->vid_out_caps |= V4L2_CAP_AUDIO; + } + if (dev->has_vbi_cap) { + /* set up the capabilities of the vbi capture device */ + dev->vbi_cap_caps = (dev->has_raw_vbi_cap ? V4L2_CAP_VBI_CAPTURE : 0) | + (dev->has_sliced_vbi_cap ? V4L2_CAP_SLICED_VBI_CAPTURE : 0); + dev->vbi_cap_caps |= V4L2_CAP_STREAMING | V4L2_CAP_READWRITE; + if (dev->has_audio_inputs) + dev->vbi_cap_caps |= V4L2_CAP_AUDIO; + if (dev->has_tv_tuner) + dev->vbi_cap_caps |= V4L2_CAP_TUNER; + } + if (dev->has_vbi_out) { + /* set up the capabilities of the vbi output device */ + dev->vbi_out_caps = (dev->has_raw_vbi_out ? V4L2_CAP_VBI_OUTPUT : 0) | + (dev->has_sliced_vbi_out ? V4L2_CAP_SLICED_VBI_OUTPUT : 0); + dev->vbi_out_caps |= V4L2_CAP_STREAMING | V4L2_CAP_READWRITE; + if (dev->has_audio_outputs) + dev->vbi_out_caps |= V4L2_CAP_AUDIO; + } + if (dev->has_sdr_cap) { + /* set up the capabilities of the sdr capture device */ + dev->sdr_cap_caps = V4L2_CAP_SDR_CAPTURE | V4L2_CAP_TUNER; + dev->sdr_cap_caps |= V4L2_CAP_STREAMING | V4L2_CAP_READWRITE; + } + /* set up the capabilities of the radio receiver device */ + if (dev->has_radio_rx) + dev->radio_rx_caps = V4L2_CAP_RADIO | V4L2_CAP_RDS_CAPTURE | + V4L2_CAP_HW_FREQ_SEEK | V4L2_CAP_TUNER | + V4L2_CAP_READWRITE; + /* set up the capabilities of the radio transmitter device */ + if (dev->has_radio_tx) + dev->radio_tx_caps = V4L2_CAP_RDS_OUTPUT | V4L2_CAP_MODULATOR | + V4L2_CAP_READWRITE; + + /* set up the capabilities of meta capture device */ + if (dev->has_meta_cap) { + dev->meta_cap_caps = V4L2_CAP_META_CAPTURE | + V4L2_CAP_STREAMING | V4L2_CAP_READWRITE; + if (dev->has_audio_inputs) + dev->meta_cap_caps |= V4L2_CAP_AUDIO; + if (dev->has_tv_tuner) + dev->meta_cap_caps |= V4L2_CAP_TUNER; + } + /* set up the capabilities of meta output device */ + if (dev->has_meta_out) { + dev->meta_out_caps = V4L2_CAP_META_OUTPUT | + V4L2_CAP_STREAMING | V4L2_CAP_READWRITE; + if (dev->has_audio_outputs) + dev->meta_out_caps |= V4L2_CAP_AUDIO; + } + /* set up the capabilities of the touch capture device */ + if (dev->has_touch_cap) { + dev->touch_cap_caps = V4L2_CAP_TOUCH | V4L2_CAP_STREAMING | + V4L2_CAP_READWRITE; + dev->touch_cap_caps |= dev->multiplanar ? + V4L2_CAP_VIDEO_CAPTURE_MPLANE : V4L2_CAP_VIDEO_CAPTURE; + } + + ret = -ENOMEM; + /* initialize the test pattern generator */ + tpg_init(&dev->tpg, 640, 360); + if (tpg_alloc(&dev->tpg, MAX_ZOOM * MAX_WIDTH)) + goto free_dev; + dev->scaled_line = vzalloc(array_size(MAX_WIDTH, MAX_ZOOM)); + if (!dev->scaled_line) + goto free_dev; + dev->blended_line = vzalloc(array_size(MAX_WIDTH, MAX_ZOOM)); + if (!dev->blended_line) + goto free_dev; + + /* load the edid */ + dev->edid = vmalloc(256 * 128); + if (!dev->edid) + goto free_dev; + + while (v4l2_dv_timings_presets[dev->query_dv_timings_size].bt.width) + dev->query_dv_timings_size++; + + /* + * Create a char pointer array that points to the names of all the + * preset timings + */ + dev->query_dv_timings_qmenu = kmalloc_array(dev->query_dv_timings_size, + sizeof(char *), GFP_KERNEL); + /* + * Create a string array containing the names of all the preset + * timings. Each name is max 31 chars long (+ terminating 0). + */ + dev->query_dv_timings_qmenu_strings = + kmalloc_array(dev->query_dv_timings_size, 32, GFP_KERNEL); + + if (!dev->query_dv_timings_qmenu || + !dev->query_dv_timings_qmenu_strings) + goto free_dev; + + for (i = 0; i < dev->query_dv_timings_size; i++) { + const struct v4l2_bt_timings *bt = &v4l2_dv_timings_presets[i].bt; + char *p = dev->query_dv_timings_qmenu_strings + i * 32; + u32 htot, vtot; + + dev->query_dv_timings_qmenu[i] = p; + + htot = V4L2_DV_BT_FRAME_WIDTH(bt); + vtot = V4L2_DV_BT_FRAME_HEIGHT(bt); + snprintf(p, 32, "%ux%u%s%u", + bt->width, bt->height, bt->interlaced ? "i" : "p", + (u32)bt->pixelclock / (htot * vtot)); + } + + /* disable invalid ioctls based on the feature set */ + if (!dev->has_audio_inputs) { + v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_S_AUDIO); + v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_G_AUDIO); + v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_ENUMAUDIO); + v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_S_AUDIO); + v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_G_AUDIO); + v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_ENUMAUDIO); + v4l2_disable_ioctl(&dev->meta_cap_dev, VIDIOC_S_AUDIO); + v4l2_disable_ioctl(&dev->meta_cap_dev, VIDIOC_G_AUDIO); + v4l2_disable_ioctl(&dev->meta_cap_dev, VIDIOC_ENUMAUDIO); + } + if (!dev->has_audio_outputs) { + v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_S_AUDOUT); + v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_G_AUDOUT); + v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_ENUMAUDOUT); + v4l2_disable_ioctl(&dev->vbi_out_dev, VIDIOC_S_AUDOUT); + v4l2_disable_ioctl(&dev->vbi_out_dev, VIDIOC_G_AUDOUT); + v4l2_disable_ioctl(&dev->vbi_out_dev, VIDIOC_ENUMAUDOUT); + v4l2_disable_ioctl(&dev->meta_out_dev, VIDIOC_S_AUDOUT); + v4l2_disable_ioctl(&dev->meta_out_dev, VIDIOC_G_AUDOUT); + v4l2_disable_ioctl(&dev->meta_out_dev, VIDIOC_ENUMAUDOUT); + } + if (!in_type_counter[TV] && !in_type_counter[SVID]) { + v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_S_STD); + v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_G_STD); + v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_ENUMSTD); + v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_QUERYSTD); + } + if (!out_type_counter[SVID]) { + v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_S_STD); + v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_G_STD); + v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_ENUMSTD); + } + if (!has_tuner && !has_modulator) { + v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_S_FREQUENCY); + v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_G_FREQUENCY); + v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_S_FREQUENCY); + v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_G_FREQUENCY); + v4l2_disable_ioctl(&dev->meta_cap_dev, VIDIOC_S_FREQUENCY); + v4l2_disable_ioctl(&dev->meta_cap_dev, VIDIOC_G_FREQUENCY); + } + if (!has_tuner) { + v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_S_TUNER); + v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_G_TUNER); + v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_S_TUNER); + v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_G_TUNER); + v4l2_disable_ioctl(&dev->meta_cap_dev, VIDIOC_S_TUNER); + v4l2_disable_ioctl(&dev->meta_cap_dev, VIDIOC_G_TUNER); + } + if (in_type_counter[HDMI] == 0) { + v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_S_EDID); + v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_G_EDID); + v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_DV_TIMINGS_CAP); + v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_G_DV_TIMINGS); + v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_S_DV_TIMINGS); + v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_ENUM_DV_TIMINGS); + v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_QUERY_DV_TIMINGS); + } + if (out_type_counter[HDMI] == 0) { + v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_G_EDID); + v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_DV_TIMINGS_CAP); + v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_G_DV_TIMINGS); + v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_S_DV_TIMINGS); + v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_ENUM_DV_TIMINGS); + } + if (!dev->has_fb) { + v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_G_FBUF); + v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_S_FBUF); + v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_OVERLAY); + } + v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_S_HW_FREQ_SEEK); + v4l2_disable_ioctl(&dev->vbi_cap_dev, VIDIOC_S_HW_FREQ_SEEK); + v4l2_disable_ioctl(&dev->sdr_cap_dev, VIDIOC_S_HW_FREQ_SEEK); + v4l2_disable_ioctl(&dev->meta_cap_dev, VIDIOC_S_HW_FREQ_SEEK); + v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_S_FREQUENCY); + v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_G_FREQUENCY); + v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_ENUM_FRAMESIZES); + v4l2_disable_ioctl(&dev->vid_out_dev, VIDIOC_ENUM_FRAMEINTERVALS); + v4l2_disable_ioctl(&dev->vbi_out_dev, VIDIOC_S_FREQUENCY); + v4l2_disable_ioctl(&dev->vbi_out_dev, VIDIOC_G_FREQUENCY); + v4l2_disable_ioctl(&dev->meta_out_dev, VIDIOC_S_FREQUENCY); + v4l2_disable_ioctl(&dev->meta_out_dev, VIDIOC_G_FREQUENCY); + v4l2_disable_ioctl(&dev->touch_cap_dev, VIDIOC_S_PARM); + v4l2_disable_ioctl(&dev->touch_cap_dev, VIDIOC_ENUM_FRAMESIZES); + v4l2_disable_ioctl(&dev->touch_cap_dev, VIDIOC_ENUM_FRAMEINTERVALS); + + /* configure internal data */ + dev->fmt_cap = &vivid_formats[0]; + dev->fmt_out = &vivid_formats[0]; + if (!dev->multiplanar) + vivid_formats[0].data_offset[0] = 0; + dev->webcam_size_idx = 1; + dev->webcam_ival_idx = 3; + tpg_s_fourcc(&dev->tpg, dev->fmt_cap->fourcc); + dev->std_out = V4L2_STD_PAL; + if (dev->input_type[0] == TV || dev->input_type[0] == SVID) + tvnorms_cap = V4L2_STD_ALL; + if (dev->output_type[0] == SVID) + tvnorms_out = V4L2_STD_ALL; + for (i = 0; i < MAX_INPUTS; i++) { + dev->dv_timings_cap[i] = def_dv_timings; + dev->std_cap[i] = V4L2_STD_PAL; + } + dev->dv_timings_out = def_dv_timings; + dev->tv_freq = 2804 /* 175.25 * 16 */; + dev->tv_audmode = V4L2_TUNER_MODE_STEREO; + dev->tv_field_cap = V4L2_FIELD_INTERLACED; + dev->tv_field_out = V4L2_FIELD_INTERLACED; + dev->radio_rx_freq = 95000 * 16; + dev->radio_rx_audmode = V4L2_TUNER_MODE_STEREO; + if (dev->has_radio_tx) { + dev->radio_tx_freq = 95500 * 16; + dev->radio_rds_loop = false; + } + dev->radio_tx_subchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_RDS; + dev->sdr_adc_freq = 300000; + dev->sdr_fm_freq = 50000000; + dev->sdr_pixelformat = V4L2_SDR_FMT_CU8; + dev->sdr_buffersize = SDR_CAP_SAMPLES_PER_BUF * 2; + + dev->edid_max_blocks = dev->edid_blocks = 2; + memcpy(dev->edid, vivid_hdmi_edid, sizeof(vivid_hdmi_edid)); + dev->radio_rds_init_time = ktime_get(); + + /* create all controls */ + ret = vivid_create_controls(dev, ccs_cap == -1, ccs_out == -1, no_error_inj, + in_type_counter[TV] || in_type_counter[SVID] || + out_type_counter[SVID], + in_type_counter[HDMI] || out_type_counter[HDMI]); + if (ret) + goto unreg_dev; + + /* enable/disable interface specific controls */ + if (dev->num_outputs && dev->output_type[0] != HDMI) + v4l2_ctrl_activate(dev->ctrl_display_present, false); + if (dev->num_inputs && dev->input_type[0] != HDMI) { + v4l2_ctrl_activate(dev->ctrl_dv_timings_signal_mode, false); + v4l2_ctrl_activate(dev->ctrl_dv_timings, false); + } else if (dev->num_inputs && dev->input_type[0] == HDMI) { + v4l2_ctrl_activate(dev->ctrl_std_signal_mode, false); + v4l2_ctrl_activate(dev->ctrl_standard, false); + } + + /* + * update the capture and output formats to do a proper initial + * configuration. + */ + vivid_update_format_cap(dev, false); + vivid_update_format_out(dev); + + /* initialize overlay */ + dev->fb_cap.fmt.width = dev->src_rect.width; + dev->fb_cap.fmt.height = dev->src_rect.height; + dev->fb_cap.fmt.pixelformat = dev->fmt_cap->fourcc; + dev->fb_cap.fmt.bytesperline = dev->src_rect.width * tpg_g_twopixelsize(&dev->tpg, 0) / 2; + dev->fb_cap.fmt.sizeimage = dev->src_rect.height * dev->fb_cap.fmt.bytesperline; + + /* update touch configuration */ + dev->timeperframe_tch_cap.numerator = 1; + dev->timeperframe_tch_cap.denominator = 10; + vivid_set_touch(dev, 0); + + /* initialize locks */ + spin_lock_init(&dev->slock); + mutex_init(&dev->mutex); + + /* init dma queues */ + INIT_LIST_HEAD(&dev->vid_cap_active); + INIT_LIST_HEAD(&dev->vid_out_active); + INIT_LIST_HEAD(&dev->vbi_cap_active); + INIT_LIST_HEAD(&dev->vbi_out_active); + INIT_LIST_HEAD(&dev->sdr_cap_active); + INIT_LIST_HEAD(&dev->meta_cap_active); + INIT_LIST_HEAD(&dev->meta_out_active); + INIT_LIST_HEAD(&dev->touch_cap_active); + + INIT_LIST_HEAD(&dev->cec_work_list); + spin_lock_init(&dev->cec_slock); + /* + * Same as create_singlethread_workqueue, but now I can use the + * string formatting of alloc_ordered_workqueue. + */ + dev->cec_workqueue = + alloc_ordered_workqueue("vivid-%03d-cec", WQ_MEM_RECLAIM, inst); + if (!dev->cec_workqueue) { + ret = -ENOMEM; + goto unreg_dev; + } + + if (allocators[inst] == 1) + dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); + + /* start creating the vb2 queues */ + if (dev->has_vid_cap) { + /* initialize vid_cap queue */ + ret = vivid_create_queue(dev, &dev->vb_vid_cap_q, + V4L2_BUF_TYPE_VIDEO_CAPTURE, 2, + &vivid_vid_cap_qops); + if (ret) + goto unreg_dev; + } + + if (dev->has_vid_out) { + /* initialize vid_out queue */ + ret = vivid_create_queue(dev, &dev->vb_vid_out_q, + V4L2_BUF_TYPE_VIDEO_OUTPUT, 2, + &vivid_vid_out_qops); + if (ret) + goto unreg_dev; + } + + if (dev->has_vbi_cap) { + /* initialize vbi_cap queue */ + ret = vivid_create_queue(dev, &dev->vb_vbi_cap_q, + V4L2_BUF_TYPE_VBI_CAPTURE, 2, + &vivid_vbi_cap_qops); + if (ret) + goto unreg_dev; + } + + if (dev->has_vbi_out) { + /* initialize vbi_out queue */ + ret = vivid_create_queue(dev, &dev->vb_vbi_out_q, + V4L2_BUF_TYPE_VBI_OUTPUT, 2, + &vivid_vbi_out_qops); + if (ret) + goto unreg_dev; + } + + if (dev->has_sdr_cap) { + /* initialize sdr_cap queue */ + ret = vivid_create_queue(dev, &dev->vb_sdr_cap_q, + V4L2_BUF_TYPE_SDR_CAPTURE, 8, + &vivid_sdr_cap_qops); + if (ret) + goto unreg_dev; + } + + if (dev->has_meta_cap) { + /* initialize meta_cap queue */ + ret = vivid_create_queue(dev, &dev->vb_meta_cap_q, + V4L2_BUF_TYPE_META_CAPTURE, 2, + &vivid_meta_cap_qops); + if (ret) + goto unreg_dev; + } + + if (dev->has_meta_out) { + /* initialize meta_out queue */ + ret = vivid_create_queue(dev, &dev->vb_meta_out_q, + V4L2_BUF_TYPE_META_OUTPUT, 1, + &vivid_meta_out_qops); + if (ret) + goto unreg_dev; + } + + if (dev->has_touch_cap) { + /* initialize touch_cap queue */ + ret = vivid_create_queue(dev, &dev->vb_touch_cap_q, + V4L2_BUF_TYPE_VIDEO_CAPTURE, 1, + &vivid_touch_cap_qops); + if (ret) + goto unreg_dev; + } + + if (dev->has_fb) { + /* Create framebuffer for testing capture/output overlay */ + ret = vivid_fb_init(dev); + if (ret) + goto unreg_dev; + v4l2_info(&dev->v4l2_dev, "Framebuffer device registered as fb%d\n", + dev->fb_info.node); + } + +#ifdef CONFIG_VIDEO_VIVID_CEC + if (dev->has_vid_cap && in_type_counter[HDMI]) { + struct cec_adapter *adap; + + adap = vivid_cec_alloc_adap(dev, 0, false); + ret = PTR_ERR_OR_ZERO(adap); + if (ret < 0) + goto unreg_dev; + dev->cec_rx_adap = adap; + } + + if (dev->has_vid_out) { + for (i = 0; i < dev->num_outputs; i++) { + struct cec_adapter *adap; + + if (dev->output_type[i] != HDMI) + continue; + + dev->cec_output2bus_map[i] = cec_tx_bus_cnt; + adap = vivid_cec_alloc_adap(dev, cec_tx_bus_cnt, true); + ret = PTR_ERR_OR_ZERO(adap); + if (ret < 0) { + for (i = 0; i < dev->num_outputs; i++) + cec_delete_adapter(dev->cec_tx_adap[i]); + goto unreg_dev; + } + + dev->cec_tx_adap[cec_tx_bus_cnt] = adap; + cec_tx_bus_cnt++; + } + } +#endif + + v4l2_ctrl_handler_setup(&dev->ctrl_hdl_vid_cap); + v4l2_ctrl_handler_setup(&dev->ctrl_hdl_vid_out); + v4l2_ctrl_handler_setup(&dev->ctrl_hdl_vbi_cap); + v4l2_ctrl_handler_setup(&dev->ctrl_hdl_vbi_out); + v4l2_ctrl_handler_setup(&dev->ctrl_hdl_radio_rx); + v4l2_ctrl_handler_setup(&dev->ctrl_hdl_radio_tx); + v4l2_ctrl_handler_setup(&dev->ctrl_hdl_sdr_cap); + v4l2_ctrl_handler_setup(&dev->ctrl_hdl_meta_cap); + v4l2_ctrl_handler_setup(&dev->ctrl_hdl_meta_out); + v4l2_ctrl_handler_setup(&dev->ctrl_hdl_touch_cap); + + /* finally start creating the device nodes */ + if (dev->has_vid_cap) { + vfd = &dev->vid_cap_dev; + snprintf(vfd->name, sizeof(vfd->name), + "vivid-%03d-vid-cap", inst); + vfd->fops = &vivid_fops; + vfd->ioctl_ops = &vivid_ioctl_ops; + vfd->device_caps = dev->vid_cap_caps; + vfd->release = video_device_release_empty; + vfd->v4l2_dev = &dev->v4l2_dev; + vfd->queue = &dev->vb_vid_cap_q; + vfd->tvnorms = tvnorms_cap; + + /* + * Provide a mutex to v4l2 core. It will be used to protect + * all fops and v4l2 ioctls. + */ + vfd->lock = &dev->mutex; + video_set_drvdata(vfd, dev); + +#ifdef CONFIG_MEDIA_CONTROLLER + dev->vid_cap_pad.flags = MEDIA_PAD_FL_SINK; + ret = media_entity_pads_init(&vfd->entity, 1, &dev->vid_cap_pad); + if (ret) + goto unreg_dev; +#endif + +#ifdef CONFIG_VIDEO_VIVID_CEC + if (in_type_counter[HDMI]) { + ret = cec_register_adapter(dev->cec_rx_adap, &pdev->dev); + if (ret < 0) { + cec_delete_adapter(dev->cec_rx_adap); + dev->cec_rx_adap = NULL; + goto unreg_dev; + } + cec_s_phys_addr(dev->cec_rx_adap, 0, false); + v4l2_info(&dev->v4l2_dev, "CEC adapter %s registered for HDMI input 0\n", + dev_name(&dev->cec_rx_adap->devnode.dev)); + } +#endif + + ret = video_register_device(vfd, VFL_TYPE_VIDEO, vid_cap_nr[inst]); + if (ret < 0) + goto unreg_dev; + v4l2_info(&dev->v4l2_dev, "V4L2 capture device registered as %s\n", + video_device_node_name(vfd)); + } + + if (dev->has_vid_out) { + vfd = &dev->vid_out_dev; + snprintf(vfd->name, sizeof(vfd->name), + "vivid-%03d-vid-out", inst); + vfd->vfl_dir = VFL_DIR_TX; + vfd->fops = &vivid_fops; + vfd->ioctl_ops = &vivid_ioctl_ops; + vfd->device_caps = dev->vid_out_caps; + vfd->release = video_device_release_empty; + vfd->v4l2_dev = &dev->v4l2_dev; + vfd->queue = &dev->vb_vid_out_q; + vfd->tvnorms = tvnorms_out; + + /* + * Provide a mutex to v4l2 core. It will be used to protect + * all fops and v4l2 ioctls. + */ + vfd->lock = &dev->mutex; + video_set_drvdata(vfd, dev); + +#ifdef CONFIG_MEDIA_CONTROLLER + dev->vid_out_pad.flags = MEDIA_PAD_FL_SOURCE; + ret = media_entity_pads_init(&vfd->entity, 1, &dev->vid_out_pad); + if (ret) + goto unreg_dev; +#endif + +#ifdef CONFIG_VIDEO_VIVID_CEC + for (i = 0; i < cec_tx_bus_cnt; i++) { + ret = cec_register_adapter(dev->cec_tx_adap[i], &pdev->dev); + if (ret < 0) { + for (; i < cec_tx_bus_cnt; i++) { + cec_delete_adapter(dev->cec_tx_adap[i]); + dev->cec_tx_adap[i] = NULL; + } + goto unreg_dev; + } + v4l2_info(&dev->v4l2_dev, "CEC adapter %s registered for HDMI output %d\n", + dev_name(&dev->cec_tx_adap[i]->devnode.dev), i); + if (i < out_type_counter[HDMI]) + cec_s_phys_addr(dev->cec_tx_adap[i], (i + 1) << 12, false); + else + cec_s_phys_addr(dev->cec_tx_adap[i], 0x1000, false); + } +#endif + + ret = video_register_device(vfd, VFL_TYPE_VIDEO, vid_out_nr[inst]); + if (ret < 0) + goto unreg_dev; + v4l2_info(&dev->v4l2_dev, "V4L2 output device registered as %s\n", + video_device_node_name(vfd)); + } + + if (dev->has_vbi_cap) { + vfd = &dev->vbi_cap_dev; + snprintf(vfd->name, sizeof(vfd->name), + "vivid-%03d-vbi-cap", inst); + vfd->fops = &vivid_fops; + vfd->ioctl_ops = &vivid_ioctl_ops; + vfd->device_caps = dev->vbi_cap_caps; + vfd->release = video_device_release_empty; + vfd->v4l2_dev = &dev->v4l2_dev; + vfd->queue = &dev->vb_vbi_cap_q; + vfd->lock = &dev->mutex; + vfd->tvnorms = tvnorms_cap; + video_set_drvdata(vfd, dev); + +#ifdef CONFIG_MEDIA_CONTROLLER + dev->vbi_cap_pad.flags = MEDIA_PAD_FL_SINK; + ret = media_entity_pads_init(&vfd->entity, 1, &dev->vbi_cap_pad); + if (ret) + goto unreg_dev; +#endif + + ret = video_register_device(vfd, VFL_TYPE_VBI, vbi_cap_nr[inst]); + if (ret < 0) + goto unreg_dev; + v4l2_info(&dev->v4l2_dev, "V4L2 capture device registered as %s, supports %s VBI\n", + video_device_node_name(vfd), + (dev->has_raw_vbi_cap && dev->has_sliced_vbi_cap) ? + "raw and sliced" : + (dev->has_raw_vbi_cap ? "raw" : "sliced")); + } + + if (dev->has_vbi_out) { + vfd = &dev->vbi_out_dev; + snprintf(vfd->name, sizeof(vfd->name), + "vivid-%03d-vbi-out", inst); + vfd->vfl_dir = VFL_DIR_TX; + vfd->fops = &vivid_fops; + vfd->ioctl_ops = &vivid_ioctl_ops; + vfd->device_caps = dev->vbi_out_caps; + vfd->release = video_device_release_empty; + vfd->v4l2_dev = &dev->v4l2_dev; + vfd->queue = &dev->vb_vbi_out_q; + vfd->lock = &dev->mutex; + vfd->tvnorms = tvnorms_out; + video_set_drvdata(vfd, dev); + +#ifdef CONFIG_MEDIA_CONTROLLER + dev->vbi_out_pad.flags = MEDIA_PAD_FL_SOURCE; + ret = media_entity_pads_init(&vfd->entity, 1, &dev->vbi_out_pad); + if (ret) + goto unreg_dev; +#endif + + ret = video_register_device(vfd, VFL_TYPE_VBI, vbi_out_nr[inst]); + if (ret < 0) + goto unreg_dev; + v4l2_info(&dev->v4l2_dev, "V4L2 output device registered as %s, supports %s VBI\n", + video_device_node_name(vfd), + (dev->has_raw_vbi_out && dev->has_sliced_vbi_out) ? + "raw and sliced" : + (dev->has_raw_vbi_out ? "raw" : "sliced")); + } + + if (dev->has_sdr_cap) { + vfd = &dev->sdr_cap_dev; + snprintf(vfd->name, sizeof(vfd->name), + "vivid-%03d-sdr-cap", inst); + vfd->fops = &vivid_fops; + vfd->ioctl_ops = &vivid_ioctl_ops; + vfd->device_caps = dev->sdr_cap_caps; + vfd->release = video_device_release_empty; + vfd->v4l2_dev = &dev->v4l2_dev; + vfd->queue = &dev->vb_sdr_cap_q; + vfd->lock = &dev->mutex; + video_set_drvdata(vfd, dev); + +#ifdef CONFIG_MEDIA_CONTROLLER + dev->sdr_cap_pad.flags = MEDIA_PAD_FL_SINK; + ret = media_entity_pads_init(&vfd->entity, 1, &dev->sdr_cap_pad); + if (ret) + goto unreg_dev; +#endif + + ret = video_register_device(vfd, VFL_TYPE_SDR, sdr_cap_nr[inst]); + if (ret < 0) + goto unreg_dev; + v4l2_info(&dev->v4l2_dev, "V4L2 capture device registered as %s\n", + video_device_node_name(vfd)); + } + + if (dev->has_radio_rx) { + vfd = &dev->radio_rx_dev; + snprintf(vfd->name, sizeof(vfd->name), + "vivid-%03d-rad-rx", inst); + vfd->fops = &vivid_radio_fops; + vfd->ioctl_ops = &vivid_ioctl_ops; + vfd->device_caps = dev->radio_rx_caps; + vfd->release = video_device_release_empty; + vfd->v4l2_dev = &dev->v4l2_dev; + vfd->lock = &dev->mutex; + video_set_drvdata(vfd, dev); + + ret = video_register_device(vfd, VFL_TYPE_RADIO, radio_rx_nr[inst]); + if (ret < 0) + goto unreg_dev; + v4l2_info(&dev->v4l2_dev, "V4L2 receiver device registered as %s\n", + video_device_node_name(vfd)); + } + + if (dev->has_radio_tx) { + vfd = &dev->radio_tx_dev; + snprintf(vfd->name, sizeof(vfd->name), + "vivid-%03d-rad-tx", inst); + vfd->vfl_dir = VFL_DIR_TX; + vfd->fops = &vivid_radio_fops; + vfd->ioctl_ops = &vivid_ioctl_ops; + vfd->device_caps = dev->radio_tx_caps; + vfd->release = video_device_release_empty; + vfd->v4l2_dev = &dev->v4l2_dev; + vfd->lock = &dev->mutex; + video_set_drvdata(vfd, dev); + + ret = video_register_device(vfd, VFL_TYPE_RADIO, radio_tx_nr[inst]); + if (ret < 0) + goto unreg_dev; + v4l2_info(&dev->v4l2_dev, "V4L2 transmitter device registered as %s\n", + video_device_node_name(vfd)); + } + + if (dev->has_meta_cap) { + vfd = &dev->meta_cap_dev; + snprintf(vfd->name, sizeof(vfd->name), + "vivid-%03d-meta-cap", inst); + vfd->fops = &vivid_fops; + vfd->ioctl_ops = &vivid_ioctl_ops; + vfd->device_caps = dev->meta_cap_caps; + vfd->release = video_device_release_empty; + vfd->v4l2_dev = &dev->v4l2_dev; + vfd->queue = &dev->vb_meta_cap_q; + vfd->lock = &dev->mutex; + vfd->tvnorms = tvnorms_cap; + video_set_drvdata(vfd, dev); +#ifdef CONFIG_MEDIA_CONTROLLER + dev->meta_cap_pad.flags = MEDIA_PAD_FL_SINK; + ret = media_entity_pads_init(&vfd->entity, 1, + &dev->meta_cap_pad); + if (ret) + goto unreg_dev; +#endif + ret = video_register_device(vfd, VFL_TYPE_VIDEO, + meta_cap_nr[inst]); + if (ret < 0) + goto unreg_dev; + v4l2_info(&dev->v4l2_dev, + "V4L2 metadata capture device registered as %s\n", + video_device_node_name(vfd)); + } + + if (dev->has_meta_out) { + vfd = &dev->meta_out_dev; + snprintf(vfd->name, sizeof(vfd->name), + "vivid-%03d-meta-out", inst); + vfd->vfl_dir = VFL_DIR_TX; + vfd->fops = &vivid_fops; + vfd->ioctl_ops = &vivid_ioctl_ops; + vfd->device_caps = dev->meta_out_caps; + vfd->release = video_device_release_empty; + vfd->v4l2_dev = &dev->v4l2_dev; + vfd->queue = &dev->vb_meta_out_q; + vfd->lock = &dev->mutex; + vfd->tvnorms = tvnorms_out; + video_set_drvdata(vfd, dev); +#ifdef CONFIG_MEDIA_CONTROLLER + dev->meta_out_pad.flags = MEDIA_PAD_FL_SOURCE; + ret = media_entity_pads_init(&vfd->entity, 1, + &dev->meta_out_pad); + if (ret) + goto unreg_dev; +#endif + ret = video_register_device(vfd, VFL_TYPE_VIDEO, + meta_out_nr[inst]); + if (ret < 0) + goto unreg_dev; + v4l2_info(&dev->v4l2_dev, + "V4L2 metadata output device registered as %s\n", + video_device_node_name(vfd)); + } + + if (dev->has_touch_cap) { + vfd = &dev->touch_cap_dev; + snprintf(vfd->name, sizeof(vfd->name), + "vivid-%03d-touch-cap", inst); + vfd->fops = &vivid_fops; + vfd->ioctl_ops = &vivid_ioctl_ops; + vfd->device_caps = dev->touch_cap_caps; + vfd->release = video_device_release_empty; + vfd->v4l2_dev = &dev->v4l2_dev; + vfd->queue = &dev->vb_touch_cap_q; + vfd->tvnorms = tvnorms_cap; + vfd->lock = &dev->mutex; + video_set_drvdata(vfd, dev); +#ifdef CONFIG_MEDIA_CONTROLLER + dev->touch_cap_pad.flags = MEDIA_PAD_FL_SINK; + ret = media_entity_pads_init(&vfd->entity, 1, + &dev->touch_cap_pad); + if (ret) + goto unreg_dev; +#endif + ret = video_register_device(vfd, VFL_TYPE_TOUCH, + touch_cap_nr[inst]); + if (ret < 0) + goto unreg_dev; + v4l2_info(&dev->v4l2_dev, + "V4L2 touch capture device registered as %s\n", + video_device_node_name(vfd)); + } + +#ifdef CONFIG_MEDIA_CONTROLLER + /* Register the media device */ + ret = media_device_register(&dev->mdev); + if (ret) { + dev_err(dev->mdev.dev, + "media device register failed (err=%d)\n", ret); + goto unreg_dev; + } +#endif + + /* Now that everything is fine, let's add it to device list */ + vivid_devs[inst] = dev; + + return 0; + +unreg_dev: + video_unregister_device(&dev->touch_cap_dev); + video_unregister_device(&dev->meta_out_dev); + video_unregister_device(&dev->meta_cap_dev); + video_unregister_device(&dev->radio_tx_dev); + video_unregister_device(&dev->radio_rx_dev); + video_unregister_device(&dev->sdr_cap_dev); + video_unregister_device(&dev->vbi_out_dev); + video_unregister_device(&dev->vbi_cap_dev); + video_unregister_device(&dev->vid_out_dev); + video_unregister_device(&dev->vid_cap_dev); + cec_unregister_adapter(dev->cec_rx_adap); + for (i = 0; i < MAX_OUTPUTS; i++) + cec_unregister_adapter(dev->cec_tx_adap[i]); + if (dev->cec_workqueue) { + vivid_cec_bus_free_work(dev); + destroy_workqueue(dev->cec_workqueue); + } +free_dev: + v4l2_device_put(&dev->v4l2_dev); + return ret; +} + +/* This routine allocates from 1 to n_devs virtual drivers. + + The real maximum number of virtual drivers will depend on how many drivers + will succeed. This is limited to the maximum number of devices that + videodev supports, which is equal to VIDEO_NUM_DEVICES. + */ +static int vivid_probe(struct platform_device *pdev) +{ + const struct font_desc *font = find_font("VGA8x16"); + int ret = 0, i; + + if (font == NULL) { + pr_err("vivid: could not find font\n"); + return -ENODEV; + } + + tpg_set_font(font->data); + + n_devs = clamp_t(unsigned, n_devs, 1, VIVID_MAX_DEVS); + + for (i = 0; i < n_devs; i++) { + ret = vivid_create_instance(pdev, i); + if (ret) { + /* If some instantiations succeeded, keep driver */ + if (i) + ret = 0; + break; + } + } + + if (ret < 0) { + pr_err("vivid: error %d while loading driver\n", ret); + return ret; + } + + /* n_devs will reflect the actual number of allocated devices */ + n_devs = i; + + return ret; +} + +static int vivid_remove(struct platform_device *pdev) +{ + struct vivid_dev *dev; + unsigned int i, j; + + for (i = 0; i < n_devs; i++) { + dev = vivid_devs[i]; + if (!dev) + continue; + +#ifdef CONFIG_MEDIA_CONTROLLER + media_device_unregister(&dev->mdev); +#endif + + if (dev->has_vid_cap) { + v4l2_info(&dev->v4l2_dev, "unregistering %s\n", + video_device_node_name(&dev->vid_cap_dev)); + video_unregister_device(&dev->vid_cap_dev); + } + if (dev->has_vid_out) { + v4l2_info(&dev->v4l2_dev, "unregistering %s\n", + video_device_node_name(&dev->vid_out_dev)); + video_unregister_device(&dev->vid_out_dev); + } + if (dev->has_vbi_cap) { + v4l2_info(&dev->v4l2_dev, "unregistering %s\n", + video_device_node_name(&dev->vbi_cap_dev)); + video_unregister_device(&dev->vbi_cap_dev); + } + if (dev->has_vbi_out) { + v4l2_info(&dev->v4l2_dev, "unregistering %s\n", + video_device_node_name(&dev->vbi_out_dev)); + video_unregister_device(&dev->vbi_out_dev); + } + if (dev->has_sdr_cap) { + v4l2_info(&dev->v4l2_dev, "unregistering %s\n", + video_device_node_name(&dev->sdr_cap_dev)); + video_unregister_device(&dev->sdr_cap_dev); + } + if (dev->has_radio_rx) { + v4l2_info(&dev->v4l2_dev, "unregistering %s\n", + video_device_node_name(&dev->radio_rx_dev)); + video_unregister_device(&dev->radio_rx_dev); + } + if (dev->has_radio_tx) { + v4l2_info(&dev->v4l2_dev, "unregistering %s\n", + video_device_node_name(&dev->radio_tx_dev)); + video_unregister_device(&dev->radio_tx_dev); + } + if (dev->has_fb) { + v4l2_info(&dev->v4l2_dev, "unregistering fb%d\n", + dev->fb_info.node); + unregister_framebuffer(&dev->fb_info); + vivid_fb_release_buffers(dev); + } + if (dev->has_meta_cap) { + v4l2_info(&dev->v4l2_dev, "unregistering %s\n", + video_device_node_name(&dev->meta_cap_dev)); + video_unregister_device(&dev->meta_cap_dev); + } + if (dev->has_meta_out) { + v4l2_info(&dev->v4l2_dev, "unregistering %s\n", + video_device_node_name(&dev->meta_out_dev)); + video_unregister_device(&dev->meta_out_dev); + } + if (dev->has_touch_cap) { + v4l2_info(&dev->v4l2_dev, "unregistering %s\n", + video_device_node_name(&dev->touch_cap_dev)); + video_unregister_device(&dev->touch_cap_dev); + } + cec_unregister_adapter(dev->cec_rx_adap); + for (j = 0; j < MAX_OUTPUTS; j++) + cec_unregister_adapter(dev->cec_tx_adap[j]); + if (dev->cec_workqueue) { + vivid_cec_bus_free_work(dev); + destroy_workqueue(dev->cec_workqueue); + } + v4l2_device_put(&dev->v4l2_dev); + vivid_devs[i] = NULL; + } + return 0; +} + +static void vivid_pdev_release(struct device *dev) +{ +} + +static struct platform_device vivid_pdev = { + .name = "vivid", + .dev.release = vivid_pdev_release, +}; + +static struct platform_driver vivid_pdrv = { + .probe = vivid_probe, + .remove = vivid_remove, + .driver = { + .name = "vivid", + }, +}; + +static int __init vivid_init(void) +{ + int ret; + + ret = platform_device_register(&vivid_pdev); + if (ret) + return ret; + + ret = platform_driver_register(&vivid_pdrv); + if (ret) + platform_device_unregister(&vivid_pdev); + + return ret; +} + +static void __exit vivid_exit(void) +{ + platform_driver_unregister(&vivid_pdrv); + platform_device_unregister(&vivid_pdev); +} + +module_init(vivid_init); +module_exit(vivid_exit); diff --git a/drivers/media/test_drivers/vivid/vivid-core.h b/drivers/media/test_drivers/vivid/vivid-core.h new file mode 100644 index 000000000000..99e69b8f770f --- /dev/null +++ b/drivers/media/test_drivers/vivid/vivid-core.h @@ -0,0 +1,612 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * vivid-core.h - core datastructures + * + * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. + */ + +#ifndef _VIVID_CORE_H_ +#define _VIVID_CORE_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "vivid-rds-gen.h" +#include "vivid-vbi-gen.h" + +#define dprintk(dev, level, fmt, arg...) \ + v4l2_dbg(level, vivid_debug, &dev->v4l2_dev, fmt, ## arg) + +/* The maximum number of clip rectangles */ +#define MAX_CLIPS 16 +/* The maximum number of inputs */ +#define MAX_INPUTS 16 +/* The maximum number of outputs */ +#define MAX_OUTPUTS 16 +/* The maximum up or down scaling factor is 4 */ +#define MAX_ZOOM 4 +/* The maximum image width/height are set to 4K DMT */ +#define MAX_WIDTH 4096 +#define MAX_HEIGHT 2160 +/* The minimum image width/height */ +#define MIN_WIDTH 16 +#define MIN_HEIGHT 16 +/* The data_offset of plane 0 for the multiplanar formats */ +#define PLANE0_DATA_OFFSET 128 + +/* The supported TV frequency range in MHz */ +#define MIN_TV_FREQ (44U * 16U) +#define MAX_TV_FREQ (958U * 16U) + +/* The number of samples returned in every SDR buffer */ +#define SDR_CAP_SAMPLES_PER_BUF 0x4000 + +/* used by the threads to know when to resync internal counters */ +#define JIFFIES_PER_DAY (3600U * 24U * HZ) +#define JIFFIES_RESYNC (JIFFIES_PER_DAY * (0xf0000000U / JIFFIES_PER_DAY)) + +extern const struct v4l2_rect vivid_min_rect; +extern const struct v4l2_rect vivid_max_rect; +extern unsigned vivid_debug; + +struct vivid_fmt { + u32 fourcc; /* v4l2 format id */ + enum tgp_color_enc color_enc; + bool can_do_overlay; + u8 vdownsampling[TPG_MAX_PLANES]; + u32 alpha_mask; + u8 planes; + u8 buffers; + u32 data_offset[TPG_MAX_PLANES]; + u32 bit_depth[TPG_MAX_PLANES]; +}; + +extern struct vivid_fmt vivid_formats[]; + +/* buffer for one video frame */ +struct vivid_buffer { + /* common v4l buffer stuff -- must be first */ + struct vb2_v4l2_buffer vb; + struct list_head list; +}; + +enum vivid_input { + WEBCAM, + TV, + SVID, + HDMI, +}; + +enum vivid_signal_mode { + CURRENT_DV_TIMINGS, + CURRENT_STD = CURRENT_DV_TIMINGS, + NO_SIGNAL, + NO_LOCK, + OUT_OF_RANGE, + SELECTED_DV_TIMINGS, + SELECTED_STD = SELECTED_DV_TIMINGS, + CYCLE_DV_TIMINGS, + CYCLE_STD = CYCLE_DV_TIMINGS, + CUSTOM_DV_TIMINGS, +}; + +enum vivid_colorspace { + VIVID_CS_170M, + VIVID_CS_709, + VIVID_CS_SRGB, + VIVID_CS_OPRGB, + VIVID_CS_2020, + VIVID_CS_DCI_P3, + VIVID_CS_240M, + VIVID_CS_SYS_M, + VIVID_CS_SYS_BG, +}; + +#define VIVID_INVALID_SIGNAL(mode) \ + ((mode) == NO_SIGNAL || (mode) == NO_LOCK || (mode) == OUT_OF_RANGE) + +struct vivid_cec_work { + struct list_head list; + struct delayed_work work; + struct cec_adapter *adap; + struct vivid_dev *dev; + unsigned int usecs; + unsigned int timeout_ms; + u8 tx_status; + struct cec_msg msg; +}; + +struct vivid_dev { + unsigned inst; + struct v4l2_device v4l2_dev; +#ifdef CONFIG_MEDIA_CONTROLLER + struct media_device mdev; + struct media_pad vid_cap_pad; + struct media_pad vid_out_pad; + struct media_pad vbi_cap_pad; + struct media_pad vbi_out_pad; + struct media_pad sdr_cap_pad; + struct media_pad meta_cap_pad; + struct media_pad meta_out_pad; + struct media_pad touch_cap_pad; +#endif + struct v4l2_ctrl_handler ctrl_hdl_user_gen; + struct v4l2_ctrl_handler ctrl_hdl_user_vid; + struct v4l2_ctrl_handler ctrl_hdl_user_aud; + struct v4l2_ctrl_handler ctrl_hdl_streaming; + struct v4l2_ctrl_handler ctrl_hdl_sdtv_cap; + struct v4l2_ctrl_handler ctrl_hdl_loop_cap; + struct v4l2_ctrl_handler ctrl_hdl_fb; + struct video_device vid_cap_dev; + struct v4l2_ctrl_handler ctrl_hdl_vid_cap; + struct video_device vid_out_dev; + struct v4l2_ctrl_handler ctrl_hdl_vid_out; + struct video_device vbi_cap_dev; + struct v4l2_ctrl_handler ctrl_hdl_vbi_cap; + struct video_device vbi_out_dev; + struct v4l2_ctrl_handler ctrl_hdl_vbi_out; + struct video_device radio_rx_dev; + struct v4l2_ctrl_handler ctrl_hdl_radio_rx; + struct video_device radio_tx_dev; + struct v4l2_ctrl_handler ctrl_hdl_radio_tx; + struct video_device sdr_cap_dev; + struct v4l2_ctrl_handler ctrl_hdl_sdr_cap; + struct video_device meta_cap_dev; + struct v4l2_ctrl_handler ctrl_hdl_meta_cap; + struct video_device meta_out_dev; + struct v4l2_ctrl_handler ctrl_hdl_meta_out; + struct video_device touch_cap_dev; + struct v4l2_ctrl_handler ctrl_hdl_touch_cap; + + spinlock_t slock; + struct mutex mutex; + + /* capabilities */ + u32 vid_cap_caps; + u32 vid_out_caps; + u32 vbi_cap_caps; + u32 vbi_out_caps; + u32 sdr_cap_caps; + u32 radio_rx_caps; + u32 radio_tx_caps; + u32 meta_cap_caps; + u32 meta_out_caps; + u32 touch_cap_caps; + + /* supported features */ + bool multiplanar; + unsigned num_inputs; + unsigned int num_hdmi_inputs; + u8 input_type[MAX_INPUTS]; + u8 input_name_counter[MAX_INPUTS]; + unsigned num_outputs; + unsigned int num_hdmi_outputs; + u8 output_type[MAX_OUTPUTS]; + u8 output_name_counter[MAX_OUTPUTS]; + bool has_audio_inputs; + bool has_audio_outputs; + bool has_vid_cap; + bool has_vid_out; + bool has_vbi_cap; + bool has_raw_vbi_cap; + bool has_sliced_vbi_cap; + bool has_vbi_out; + bool has_raw_vbi_out; + bool has_sliced_vbi_out; + bool has_radio_rx; + bool has_radio_tx; + bool has_sdr_cap; + bool has_fb; + bool has_meta_cap; + bool has_meta_out; + bool has_tv_tuner; + bool has_touch_cap; + + bool can_loop_video; + + /* controls */ + struct v4l2_ctrl *brightness; + struct v4l2_ctrl *contrast; + struct v4l2_ctrl *saturation; + struct v4l2_ctrl *hue; + struct { + /* autogain/gain cluster */ + struct v4l2_ctrl *autogain; + struct v4l2_ctrl *gain; + }; + struct v4l2_ctrl *volume; + struct v4l2_ctrl *mute; + struct v4l2_ctrl *alpha; + struct v4l2_ctrl *button; + struct v4l2_ctrl *boolean; + struct v4l2_ctrl *int32; + struct v4l2_ctrl *int64; + struct v4l2_ctrl *menu; + struct v4l2_ctrl *string; + struct v4l2_ctrl *bitmask; + struct v4l2_ctrl *int_menu; + struct v4l2_ctrl *test_pattern; + struct v4l2_ctrl *colorspace; + struct v4l2_ctrl *rgb_range_cap; + struct v4l2_ctrl *real_rgb_range_cap; + struct { + /* std_signal_mode/standard cluster */ + struct v4l2_ctrl *ctrl_std_signal_mode; + struct v4l2_ctrl *ctrl_standard; + }; + struct { + /* dv_timings_signal_mode/timings cluster */ + struct v4l2_ctrl *ctrl_dv_timings_signal_mode; + struct v4l2_ctrl *ctrl_dv_timings; + }; + struct v4l2_ctrl *ctrl_display_present; + struct v4l2_ctrl *ctrl_has_crop_cap; + struct v4l2_ctrl *ctrl_has_compose_cap; + struct v4l2_ctrl *ctrl_has_scaler_cap; + struct v4l2_ctrl *ctrl_has_crop_out; + struct v4l2_ctrl *ctrl_has_compose_out; + struct v4l2_ctrl *ctrl_has_scaler_out; + struct v4l2_ctrl *ctrl_tx_mode; + struct v4l2_ctrl *ctrl_tx_rgb_range; + struct v4l2_ctrl *ctrl_tx_edid_present; + struct v4l2_ctrl *ctrl_tx_hotplug; + struct v4l2_ctrl *ctrl_tx_rxsense; + + struct v4l2_ctrl *ctrl_rx_power_present; + + struct v4l2_ctrl *radio_tx_rds_pi; + struct v4l2_ctrl *radio_tx_rds_pty; + struct v4l2_ctrl *radio_tx_rds_mono_stereo; + struct v4l2_ctrl *radio_tx_rds_art_head; + struct v4l2_ctrl *radio_tx_rds_compressed; + struct v4l2_ctrl *radio_tx_rds_dyn_pty; + struct v4l2_ctrl *radio_tx_rds_ta; + struct v4l2_ctrl *radio_tx_rds_tp; + struct v4l2_ctrl *radio_tx_rds_ms; + struct v4l2_ctrl *radio_tx_rds_psname; + struct v4l2_ctrl *radio_tx_rds_radiotext; + + struct v4l2_ctrl *radio_rx_rds_pty; + struct v4l2_ctrl *radio_rx_rds_ta; + struct v4l2_ctrl *radio_rx_rds_tp; + struct v4l2_ctrl *radio_rx_rds_ms; + struct v4l2_ctrl *radio_rx_rds_psname; + struct v4l2_ctrl *radio_rx_rds_radiotext; + + unsigned input_brightness[MAX_INPUTS]; + unsigned osd_mode; + unsigned button_pressed; + bool sensor_hflip; + bool sensor_vflip; + bool hflip; + bool vflip; + bool vbi_cap_interlaced; + bool loop_video; + bool reduced_fps; + + /* Framebuffer */ + unsigned long video_pbase; + void *video_vbase; + u32 video_buffer_size; + int display_width; + int display_height; + int display_byte_stride; + int bits_per_pixel; + int bytes_per_pixel; + struct fb_info fb_info; + struct fb_var_screeninfo fb_defined; + struct fb_fix_screeninfo fb_fix; + + /* Error injection */ + bool queue_setup_error; + bool buf_prepare_error; + bool start_streaming_error; + bool dqbuf_error; + bool req_validate_error; + bool seq_wrap; + bool time_wrap; + u64 time_wrap_offset; + unsigned perc_dropped_buffers; + enum vivid_signal_mode std_signal_mode[MAX_INPUTS]; + unsigned int query_std_last[MAX_INPUTS]; + v4l2_std_id query_std[MAX_INPUTS]; + enum tpg_video_aspect std_aspect_ratio[MAX_INPUTS]; + + enum vivid_signal_mode dv_timings_signal_mode[MAX_INPUTS]; + char **query_dv_timings_qmenu; + char *query_dv_timings_qmenu_strings; + unsigned query_dv_timings_size; + unsigned int query_dv_timings_last[MAX_INPUTS]; + unsigned int query_dv_timings[MAX_INPUTS]; + enum tpg_video_aspect dv_timings_aspect_ratio[MAX_INPUTS]; + + /* Input */ + unsigned input; + v4l2_std_id std_cap[MAX_INPUTS]; + struct v4l2_dv_timings dv_timings_cap[MAX_INPUTS]; + int dv_timings_cap_sel[MAX_INPUTS]; + u32 service_set_cap; + struct vivid_vbi_gen_data vbi_gen; + u8 *edid; + unsigned edid_blocks; + unsigned edid_max_blocks; + unsigned webcam_size_idx; + unsigned webcam_ival_idx; + unsigned tv_freq; + unsigned tv_audmode; + unsigned tv_field_cap; + unsigned tv_audio_input; + + u32 power_present; + + /* Capture Overlay */ + struct v4l2_framebuffer fb_cap; + struct v4l2_fh *overlay_cap_owner; + void *fb_vbase_cap; + int overlay_cap_top, overlay_cap_left; + enum v4l2_field overlay_cap_field; + void *bitmap_cap; + struct v4l2_clip clips_cap[MAX_CLIPS]; + struct v4l2_clip try_clips_cap[MAX_CLIPS]; + unsigned clipcount_cap; + + /* Output */ + unsigned output; + v4l2_std_id std_out; + struct v4l2_dv_timings dv_timings_out; + u32 colorspace_out; + u32 ycbcr_enc_out; + u32 hsv_enc_out; + u32 quantization_out; + u32 xfer_func_out; + u32 service_set_out; + unsigned bytesperline_out[TPG_MAX_PLANES]; + unsigned tv_field_out; + unsigned tv_audio_output; + bool vbi_out_have_wss; + u8 vbi_out_wss[2]; + bool vbi_out_have_cc[2]; + u8 vbi_out_cc[2][2]; + bool dvi_d_out; + u8 *scaled_line; + u8 *blended_line; + unsigned cur_scaled_line; + bool display_present[MAX_OUTPUTS]; + + /* Output Overlay */ + void *fb_vbase_out; + bool overlay_out_enabled; + int overlay_out_top, overlay_out_left; + void *bitmap_out; + struct v4l2_clip clips_out[MAX_CLIPS]; + struct v4l2_clip try_clips_out[MAX_CLIPS]; + unsigned clipcount_out; + unsigned fbuf_out_flags; + u32 chromakey_out; + u8 global_alpha_out; + + /* video capture */ + struct tpg_data tpg; + unsigned ms_vid_cap; + bool must_blank[VIDEO_MAX_FRAME]; + + const struct vivid_fmt *fmt_cap; + struct v4l2_fract timeperframe_vid_cap; + enum v4l2_field field_cap; + struct v4l2_rect src_rect; + struct v4l2_rect fmt_cap_rect; + struct v4l2_rect crop_cap; + struct v4l2_rect compose_cap; + struct v4l2_rect crop_bounds_cap; + struct vb2_queue vb_vid_cap_q; + struct list_head vid_cap_active; + struct vb2_queue vb_vbi_cap_q; + struct list_head vbi_cap_active; + struct vb2_queue vb_meta_cap_q; + struct list_head meta_cap_active; + struct vb2_queue vb_touch_cap_q; + struct list_head touch_cap_active; + + /* thread for generating video capture stream */ + struct task_struct *kthread_vid_cap; + unsigned long jiffies_vid_cap; + u64 cap_stream_start; + u64 cap_frame_period; + u64 cap_frame_eof_offset; + u32 cap_seq_offset; + u32 cap_seq_count; + bool cap_seq_resync; + u32 vid_cap_seq_start; + u32 vid_cap_seq_count; + bool vid_cap_streaming; + u32 vbi_cap_seq_start; + u32 vbi_cap_seq_count; + bool vbi_cap_streaming; + bool stream_sliced_vbi_cap; + u32 meta_cap_seq_start; + u32 meta_cap_seq_count; + bool meta_cap_streaming; + + /* Touch capture */ + struct task_struct *kthread_touch_cap; + unsigned long jiffies_touch_cap; + u64 touch_cap_stream_start; + u32 touch_cap_seq_offset; + bool touch_cap_seq_resync; + u32 touch_cap_seq_start; + u32 touch_cap_seq_count; + bool touch_cap_streaming; + struct v4l2_fract timeperframe_tch_cap; + struct v4l2_pix_format tch_format; + int tch_pat_random; + + /* video output */ + const struct vivid_fmt *fmt_out; + struct v4l2_fract timeperframe_vid_out; + enum v4l2_field field_out; + struct v4l2_rect sink_rect; + struct v4l2_rect fmt_out_rect; + struct v4l2_rect crop_out; + struct v4l2_rect compose_out; + struct v4l2_rect compose_bounds_out; + struct vb2_queue vb_vid_out_q; + struct list_head vid_out_active; + struct vb2_queue vb_vbi_out_q; + struct list_head vbi_out_active; + struct vb2_queue vb_meta_out_q; + struct list_head meta_out_active; + + /* video loop precalculated rectangles */ + + /* + * Intersection between what the output side composes and the capture side + * crops. I.e., what actually needs to be copied from the output buffer to + * the capture buffer. + */ + struct v4l2_rect loop_vid_copy; + /* The part of the output buffer that (after scaling) corresponds to loop_vid_copy. */ + struct v4l2_rect loop_vid_out; + /* The part of the capture buffer that (after scaling) corresponds to loop_vid_copy. */ + struct v4l2_rect loop_vid_cap; + /* + * The intersection of the framebuffer, the overlay output window and + * loop_vid_copy. I.e., the part of the framebuffer that actually should be + * blended with the compose_out rectangle. This uses the framebuffer origin. + */ + struct v4l2_rect loop_fb_copy; + /* The same as loop_fb_copy but with compose_out origin. */ + struct v4l2_rect loop_vid_overlay; + /* + * The part of the capture buffer that (after scaling) corresponds + * to loop_vid_overlay. + */ + struct v4l2_rect loop_vid_overlay_cap; + + /* thread for generating video output stream */ + struct task_struct *kthread_vid_out; + unsigned long jiffies_vid_out; + u32 out_seq_offset; + u32 out_seq_count; + bool out_seq_resync; + u32 vid_out_seq_start; + u32 vid_out_seq_count; + bool vid_out_streaming; + u32 vbi_out_seq_start; + u32 vbi_out_seq_count; + bool vbi_out_streaming; + bool stream_sliced_vbi_out; + u32 meta_out_seq_start; + u32 meta_out_seq_count; + bool meta_out_streaming; + + /* SDR capture */ + struct vb2_queue vb_sdr_cap_q; + struct list_head sdr_cap_active; + u32 sdr_pixelformat; /* v4l2 format id */ + unsigned sdr_buffersize; + unsigned sdr_adc_freq; + unsigned sdr_fm_freq; + unsigned sdr_fm_deviation; + int sdr_fixp_src_phase; + int sdr_fixp_mod_phase; + + bool tstamp_src_is_soe; + bool has_crop_cap; + bool has_compose_cap; + bool has_scaler_cap; + bool has_crop_out; + bool has_compose_out; + bool has_scaler_out; + + /* thread for generating SDR stream */ + struct task_struct *kthread_sdr_cap; + unsigned long jiffies_sdr_cap; + u32 sdr_cap_seq_offset; + u32 sdr_cap_seq_count; + bool sdr_cap_seq_resync; + + /* RDS generator */ + struct vivid_rds_gen rds_gen; + + /* Radio receiver */ + unsigned radio_rx_freq; + unsigned radio_rx_audmode; + int radio_rx_sig_qual; + unsigned radio_rx_hw_seek_mode; + bool radio_rx_hw_seek_prog_lim; + bool radio_rx_rds_controls; + bool radio_rx_rds_enabled; + unsigned radio_rx_rds_use_alternates; + unsigned radio_rx_rds_last_block; + struct v4l2_fh *radio_rx_rds_owner; + + /* Radio transmitter */ + unsigned radio_tx_freq; + unsigned radio_tx_subchans; + bool radio_tx_rds_controls; + unsigned radio_tx_rds_last_block; + struct v4l2_fh *radio_tx_rds_owner; + + /* Shared between radio receiver and transmitter */ + bool radio_rds_loop; + ktime_t radio_rds_init_time; + + /* CEC */ + struct cec_adapter *cec_rx_adap; + struct cec_adapter *cec_tx_adap[MAX_OUTPUTS]; + struct workqueue_struct *cec_workqueue; + spinlock_t cec_slock; + struct list_head cec_work_list; + unsigned int cec_xfer_time_jiffies; + unsigned long cec_xfer_start_jiffies; + u8 cec_output2bus_map[MAX_OUTPUTS]; + + /* CEC OSD String */ + char osd[14]; + unsigned long osd_jiffies; + + bool meta_pts; + bool meta_scr; +}; + +static inline bool vivid_is_webcam(const struct vivid_dev *dev) +{ + return dev->input_type[dev->input] == WEBCAM; +} + +static inline bool vivid_is_tv_cap(const struct vivid_dev *dev) +{ + return dev->input_type[dev->input] == TV; +} + +static inline bool vivid_is_svid_cap(const struct vivid_dev *dev) +{ + return dev->input_type[dev->input] == SVID; +} + +static inline bool vivid_is_hdmi_cap(const struct vivid_dev *dev) +{ + return dev->input_type[dev->input] == HDMI; +} + +static inline bool vivid_is_sdtv_cap(const struct vivid_dev *dev) +{ + return vivid_is_tv_cap(dev) || vivid_is_svid_cap(dev); +} + +static inline bool vivid_is_svid_out(const struct vivid_dev *dev) +{ + return dev->output_type[dev->output] == SVID; +} + +static inline bool vivid_is_hdmi_out(const struct vivid_dev *dev) +{ + return dev->output_type[dev->output] == HDMI; +} + +#endif diff --git a/drivers/media/test_drivers/vivid/vivid-ctrls.c b/drivers/media/test_drivers/vivid/vivid-ctrls.c new file mode 100644 index 000000000000..334130568dcb --- /dev/null +++ b/drivers/media/test_drivers/vivid/vivid-ctrls.c @@ -0,0 +1,1939 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * vivid-ctrls.c - control support functions. + * + * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. + */ + +#include +#include +#include +#include +#include + +#include "vivid-core.h" +#include "vivid-vid-cap.h" +#include "vivid-vid-out.h" +#include "vivid-vid-common.h" +#include "vivid-radio-common.h" +#include "vivid-osd.h" +#include "vivid-ctrls.h" +#include "vivid-cec.h" + +#define VIVID_CID_CUSTOM_BASE (V4L2_CID_USER_BASE | 0xf000) +#define VIVID_CID_BUTTON (VIVID_CID_CUSTOM_BASE + 0) +#define VIVID_CID_BOOLEAN (VIVID_CID_CUSTOM_BASE + 1) +#define VIVID_CID_INTEGER (VIVID_CID_CUSTOM_BASE + 2) +#define VIVID_CID_INTEGER64 (VIVID_CID_CUSTOM_BASE + 3) +#define VIVID_CID_MENU (VIVID_CID_CUSTOM_BASE + 4) +#define VIVID_CID_STRING (VIVID_CID_CUSTOM_BASE + 5) +#define VIVID_CID_BITMASK (VIVID_CID_CUSTOM_BASE + 6) +#define VIVID_CID_INTMENU (VIVID_CID_CUSTOM_BASE + 7) +#define VIVID_CID_U32_ARRAY (VIVID_CID_CUSTOM_BASE + 8) +#define VIVID_CID_U16_MATRIX (VIVID_CID_CUSTOM_BASE + 9) +#define VIVID_CID_U8_4D_ARRAY (VIVID_CID_CUSTOM_BASE + 10) +#define VIVID_CID_AREA (VIVID_CID_CUSTOM_BASE + 11) + +#define VIVID_CID_VIVID_BASE (0x00f00000 | 0xf000) +#define VIVID_CID_VIVID_CLASS (0x00f00000 | 1) +#define VIVID_CID_TEST_PATTERN (VIVID_CID_VIVID_BASE + 0) +#define VIVID_CID_OSD_TEXT_MODE (VIVID_CID_VIVID_BASE + 1) +#define VIVID_CID_HOR_MOVEMENT (VIVID_CID_VIVID_BASE + 2) +#define VIVID_CID_VERT_MOVEMENT (VIVID_CID_VIVID_BASE + 3) +#define VIVID_CID_SHOW_BORDER (VIVID_CID_VIVID_BASE + 4) +#define VIVID_CID_SHOW_SQUARE (VIVID_CID_VIVID_BASE + 5) +#define VIVID_CID_INSERT_SAV (VIVID_CID_VIVID_BASE + 6) +#define VIVID_CID_INSERT_EAV (VIVID_CID_VIVID_BASE + 7) +#define VIVID_CID_VBI_CAP_INTERLACED (VIVID_CID_VIVID_BASE + 8) + +#define VIVID_CID_HFLIP (VIVID_CID_VIVID_BASE + 20) +#define VIVID_CID_VFLIP (VIVID_CID_VIVID_BASE + 21) +#define VIVID_CID_STD_ASPECT_RATIO (VIVID_CID_VIVID_BASE + 22) +#define VIVID_CID_DV_TIMINGS_ASPECT_RATIO (VIVID_CID_VIVID_BASE + 23) +#define VIVID_CID_TSTAMP_SRC (VIVID_CID_VIVID_BASE + 24) +#define VIVID_CID_COLORSPACE (VIVID_CID_VIVID_BASE + 25) +#define VIVID_CID_XFER_FUNC (VIVID_CID_VIVID_BASE + 26) +#define VIVID_CID_YCBCR_ENC (VIVID_CID_VIVID_BASE + 27) +#define VIVID_CID_QUANTIZATION (VIVID_CID_VIVID_BASE + 28) +#define VIVID_CID_LIMITED_RGB_RANGE (VIVID_CID_VIVID_BASE + 29) +#define VIVID_CID_ALPHA_MODE (VIVID_CID_VIVID_BASE + 30) +#define VIVID_CID_HAS_CROP_CAP (VIVID_CID_VIVID_BASE + 31) +#define VIVID_CID_HAS_COMPOSE_CAP (VIVID_CID_VIVID_BASE + 32) +#define VIVID_CID_HAS_SCALER_CAP (VIVID_CID_VIVID_BASE + 33) +#define VIVID_CID_HAS_CROP_OUT (VIVID_CID_VIVID_BASE + 34) +#define VIVID_CID_HAS_COMPOSE_OUT (VIVID_CID_VIVID_BASE + 35) +#define VIVID_CID_HAS_SCALER_OUT (VIVID_CID_VIVID_BASE + 36) +#define VIVID_CID_LOOP_VIDEO (VIVID_CID_VIVID_BASE + 37) +#define VIVID_CID_SEQ_WRAP (VIVID_CID_VIVID_BASE + 38) +#define VIVID_CID_TIME_WRAP (VIVID_CID_VIVID_BASE + 39) +#define VIVID_CID_MAX_EDID_BLOCKS (VIVID_CID_VIVID_BASE + 40) +#define VIVID_CID_PERCENTAGE_FILL (VIVID_CID_VIVID_BASE + 41) +#define VIVID_CID_REDUCED_FPS (VIVID_CID_VIVID_BASE + 42) +#define VIVID_CID_HSV_ENC (VIVID_CID_VIVID_BASE + 43) +#define VIVID_CID_DISPLAY_PRESENT (VIVID_CID_VIVID_BASE + 44) + +#define VIVID_CID_STD_SIGNAL_MODE (VIVID_CID_VIVID_BASE + 60) +#define VIVID_CID_STANDARD (VIVID_CID_VIVID_BASE + 61) +#define VIVID_CID_DV_TIMINGS_SIGNAL_MODE (VIVID_CID_VIVID_BASE + 62) +#define VIVID_CID_DV_TIMINGS (VIVID_CID_VIVID_BASE + 63) +#define VIVID_CID_PERC_DROPPED (VIVID_CID_VIVID_BASE + 64) +#define VIVID_CID_DISCONNECT (VIVID_CID_VIVID_BASE + 65) +#define VIVID_CID_DQBUF_ERROR (VIVID_CID_VIVID_BASE + 66) +#define VIVID_CID_QUEUE_SETUP_ERROR (VIVID_CID_VIVID_BASE + 67) +#define VIVID_CID_BUF_PREPARE_ERROR (VIVID_CID_VIVID_BASE + 68) +#define VIVID_CID_START_STR_ERROR (VIVID_CID_VIVID_BASE + 69) +#define VIVID_CID_QUEUE_ERROR (VIVID_CID_VIVID_BASE + 70) +#define VIVID_CID_CLEAR_FB (VIVID_CID_VIVID_BASE + 71) +#define VIVID_CID_REQ_VALIDATE_ERROR (VIVID_CID_VIVID_BASE + 72) + +#define VIVID_CID_RADIO_SEEK_MODE (VIVID_CID_VIVID_BASE + 90) +#define VIVID_CID_RADIO_SEEK_PROG_LIM (VIVID_CID_VIVID_BASE + 91) +#define VIVID_CID_RADIO_RX_RDS_RBDS (VIVID_CID_VIVID_BASE + 92) +#define VIVID_CID_RADIO_RX_RDS_BLOCKIO (VIVID_CID_VIVID_BASE + 93) + +#define VIVID_CID_RADIO_TX_RDS_BLOCKIO (VIVID_CID_VIVID_BASE + 94) + +#define VIVID_CID_SDR_CAP_FM_DEVIATION (VIVID_CID_VIVID_BASE + 110) + +#define VIVID_CID_META_CAP_GENERATE_PTS (VIVID_CID_VIVID_BASE + 111) +#define VIVID_CID_META_CAP_GENERATE_SCR (VIVID_CID_VIVID_BASE + 112) + +/* General User Controls */ + +static int vivid_user_gen_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_user_gen); + + switch (ctrl->id) { + case VIVID_CID_DISCONNECT: + v4l2_info(&dev->v4l2_dev, "disconnect\n"); + clear_bit(V4L2_FL_REGISTERED, &dev->vid_cap_dev.flags); + clear_bit(V4L2_FL_REGISTERED, &dev->vid_out_dev.flags); + clear_bit(V4L2_FL_REGISTERED, &dev->vbi_cap_dev.flags); + clear_bit(V4L2_FL_REGISTERED, &dev->vbi_out_dev.flags); + clear_bit(V4L2_FL_REGISTERED, &dev->sdr_cap_dev.flags); + clear_bit(V4L2_FL_REGISTERED, &dev->radio_rx_dev.flags); + clear_bit(V4L2_FL_REGISTERED, &dev->radio_tx_dev.flags); + clear_bit(V4L2_FL_REGISTERED, &dev->meta_cap_dev.flags); + break; + case VIVID_CID_BUTTON: + dev->button_pressed = 30; + break; + } + return 0; +} + +static const struct v4l2_ctrl_ops vivid_user_gen_ctrl_ops = { + .s_ctrl = vivid_user_gen_s_ctrl, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_button = { + .ops = &vivid_user_gen_ctrl_ops, + .id = VIVID_CID_BUTTON, + .name = "Button", + .type = V4L2_CTRL_TYPE_BUTTON, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_boolean = { + .ops = &vivid_user_gen_ctrl_ops, + .id = VIVID_CID_BOOLEAN, + .name = "Boolean", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .min = 0, + .max = 1, + .step = 1, + .def = 1, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_int32 = { + .ops = &vivid_user_gen_ctrl_ops, + .id = VIVID_CID_INTEGER, + .name = "Integer 32 Bits", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = 0xffffffff80000000ULL, + .max = 0x7fffffff, + .step = 1, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_int64 = { + .ops = &vivid_user_gen_ctrl_ops, + .id = VIVID_CID_INTEGER64, + .name = "Integer 64 Bits", + .type = V4L2_CTRL_TYPE_INTEGER64, + .min = 0x8000000000000000ULL, + .max = 0x7fffffffffffffffLL, + .step = 1, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_u32_array = { + .ops = &vivid_user_gen_ctrl_ops, + .id = VIVID_CID_U32_ARRAY, + .name = "U32 1 Element Array", + .type = V4L2_CTRL_TYPE_U32, + .def = 0x18, + .min = 0x10, + .max = 0x20000, + .step = 1, + .dims = { 1 }, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_u16_matrix = { + .ops = &vivid_user_gen_ctrl_ops, + .id = VIVID_CID_U16_MATRIX, + .name = "U16 8x16 Matrix", + .type = V4L2_CTRL_TYPE_U16, + .def = 0x18, + .min = 0x10, + .max = 0x2000, + .step = 1, + .dims = { 8, 16 }, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_u8_4d_array = { + .ops = &vivid_user_gen_ctrl_ops, + .id = VIVID_CID_U8_4D_ARRAY, + .name = "U8 2x3x4x5 Array", + .type = V4L2_CTRL_TYPE_U8, + .def = 0x18, + .min = 0x10, + .max = 0x20, + .step = 1, + .dims = { 2, 3, 4, 5 }, +}; + +static const char * const vivid_ctrl_menu_strings[] = { + "Menu Item 0 (Skipped)", + "Menu Item 1", + "Menu Item 2 (Skipped)", + "Menu Item 3", + "Menu Item 4", + "Menu Item 5 (Skipped)", + NULL, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_menu = { + .ops = &vivid_user_gen_ctrl_ops, + .id = VIVID_CID_MENU, + .name = "Menu", + .type = V4L2_CTRL_TYPE_MENU, + .min = 1, + .max = 4, + .def = 3, + .menu_skip_mask = 0x04, + .qmenu = vivid_ctrl_menu_strings, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_string = { + .ops = &vivid_user_gen_ctrl_ops, + .id = VIVID_CID_STRING, + .name = "String", + .type = V4L2_CTRL_TYPE_STRING, + .min = 2, + .max = 4, + .step = 1, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_bitmask = { + .ops = &vivid_user_gen_ctrl_ops, + .id = VIVID_CID_BITMASK, + .name = "Bitmask", + .type = V4L2_CTRL_TYPE_BITMASK, + .def = 0x80002000, + .min = 0, + .max = 0x80402010, + .step = 0, +}; + +static const s64 vivid_ctrl_int_menu_values[] = { + 1, 1, 2, 3, 5, 8, 13, 21, 42, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_int_menu = { + .ops = &vivid_user_gen_ctrl_ops, + .id = VIVID_CID_INTMENU, + .name = "Integer Menu", + .type = V4L2_CTRL_TYPE_INTEGER_MENU, + .min = 1, + .max = 8, + .def = 4, + .menu_skip_mask = 0x02, + .qmenu_int = vivid_ctrl_int_menu_values, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_disconnect = { + .ops = &vivid_user_gen_ctrl_ops, + .id = VIVID_CID_DISCONNECT, + .name = "Disconnect", + .type = V4L2_CTRL_TYPE_BUTTON, +}; + +static const struct v4l2_area area = { + .width = 1000, + .height = 2000, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_area = { + .ops = &vivid_user_gen_ctrl_ops, + .id = VIVID_CID_AREA, + .name = "Area", + .type = V4L2_CTRL_TYPE_AREA, + .p_def.p_const = &area, +}; + +/* Framebuffer Controls */ + +static int vivid_fb_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct vivid_dev *dev = container_of(ctrl->handler, + struct vivid_dev, ctrl_hdl_fb); + + switch (ctrl->id) { + case VIVID_CID_CLEAR_FB: + vivid_clear_fb(dev); + break; + } + return 0; +} + +static const struct v4l2_ctrl_ops vivid_fb_ctrl_ops = { + .s_ctrl = vivid_fb_s_ctrl, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_clear_fb = { + .ops = &vivid_fb_ctrl_ops, + .id = VIVID_CID_CLEAR_FB, + .name = "Clear Framebuffer", + .type = V4L2_CTRL_TYPE_BUTTON, +}; + + +/* Video User Controls */ + +static int vivid_user_vid_g_volatile_ctrl(struct v4l2_ctrl *ctrl) +{ + struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_user_vid); + + switch (ctrl->id) { + case V4L2_CID_AUTOGAIN: + dev->gain->val = (jiffies_to_msecs(jiffies) / 1000) & 0xff; + break; + } + return 0; +} + +static int vivid_user_vid_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_user_vid); + + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + dev->input_brightness[dev->input] = ctrl->val - dev->input * 128; + tpg_s_brightness(&dev->tpg, dev->input_brightness[dev->input]); + break; + case V4L2_CID_CONTRAST: + tpg_s_contrast(&dev->tpg, ctrl->val); + break; + case V4L2_CID_SATURATION: + tpg_s_saturation(&dev->tpg, ctrl->val); + break; + case V4L2_CID_HUE: + tpg_s_hue(&dev->tpg, ctrl->val); + break; + case V4L2_CID_HFLIP: + dev->hflip = ctrl->val; + tpg_s_hflip(&dev->tpg, dev->sensor_hflip ^ dev->hflip); + break; + case V4L2_CID_VFLIP: + dev->vflip = ctrl->val; + tpg_s_vflip(&dev->tpg, dev->sensor_vflip ^ dev->vflip); + break; + case V4L2_CID_ALPHA_COMPONENT: + tpg_s_alpha_component(&dev->tpg, ctrl->val); + break; + } + return 0; +} + +static const struct v4l2_ctrl_ops vivid_user_vid_ctrl_ops = { + .g_volatile_ctrl = vivid_user_vid_g_volatile_ctrl, + .s_ctrl = vivid_user_vid_s_ctrl, +}; + + +/* Video Capture Controls */ + +static int vivid_vid_cap_s_ctrl(struct v4l2_ctrl *ctrl) +{ + static const u32 colorspaces[] = { + V4L2_COLORSPACE_SMPTE170M, + V4L2_COLORSPACE_REC709, + V4L2_COLORSPACE_SRGB, + V4L2_COLORSPACE_OPRGB, + V4L2_COLORSPACE_BT2020, + V4L2_COLORSPACE_DCI_P3, + V4L2_COLORSPACE_SMPTE240M, + V4L2_COLORSPACE_470_SYSTEM_M, + V4L2_COLORSPACE_470_SYSTEM_BG, + }; + struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_vid_cap); + unsigned int i, j; + + switch (ctrl->id) { + case VIVID_CID_TEST_PATTERN: + vivid_update_quality(dev); + tpg_s_pattern(&dev->tpg, ctrl->val); + break; + case VIVID_CID_COLORSPACE: + tpg_s_colorspace(&dev->tpg, colorspaces[ctrl->val]); + vivid_send_source_change(dev, TV); + vivid_send_source_change(dev, SVID); + vivid_send_source_change(dev, HDMI); + vivid_send_source_change(dev, WEBCAM); + break; + case VIVID_CID_XFER_FUNC: + tpg_s_xfer_func(&dev->tpg, ctrl->val); + vivid_send_source_change(dev, TV); + vivid_send_source_change(dev, SVID); + vivid_send_source_change(dev, HDMI); + vivid_send_source_change(dev, WEBCAM); + break; + case VIVID_CID_YCBCR_ENC: + tpg_s_ycbcr_enc(&dev->tpg, ctrl->val); + vivid_send_source_change(dev, TV); + vivid_send_source_change(dev, SVID); + vivid_send_source_change(dev, HDMI); + vivid_send_source_change(dev, WEBCAM); + break; + case VIVID_CID_HSV_ENC: + tpg_s_hsv_enc(&dev->tpg, ctrl->val ? V4L2_HSV_ENC_256 : + V4L2_HSV_ENC_180); + vivid_send_source_change(dev, TV); + vivid_send_source_change(dev, SVID); + vivid_send_source_change(dev, HDMI); + vivid_send_source_change(dev, WEBCAM); + break; + case VIVID_CID_QUANTIZATION: + tpg_s_quantization(&dev->tpg, ctrl->val); + vivid_send_source_change(dev, TV); + vivid_send_source_change(dev, SVID); + vivid_send_source_change(dev, HDMI); + vivid_send_source_change(dev, WEBCAM); + break; + case V4L2_CID_DV_RX_RGB_RANGE: + if (!vivid_is_hdmi_cap(dev)) + break; + tpg_s_rgb_range(&dev->tpg, ctrl->val); + break; + case VIVID_CID_LIMITED_RGB_RANGE: + tpg_s_real_rgb_range(&dev->tpg, ctrl->val ? + V4L2_DV_RGB_RANGE_LIMITED : V4L2_DV_RGB_RANGE_FULL); + break; + case VIVID_CID_ALPHA_MODE: + tpg_s_alpha_mode(&dev->tpg, ctrl->val); + break; + case VIVID_CID_HOR_MOVEMENT: + tpg_s_mv_hor_mode(&dev->tpg, ctrl->val); + break; + case VIVID_CID_VERT_MOVEMENT: + tpg_s_mv_vert_mode(&dev->tpg, ctrl->val); + break; + case VIVID_CID_OSD_TEXT_MODE: + dev->osd_mode = ctrl->val; + break; + case VIVID_CID_PERCENTAGE_FILL: + tpg_s_perc_fill(&dev->tpg, ctrl->val); + for (i = 0; i < VIDEO_MAX_FRAME; i++) + dev->must_blank[i] = ctrl->val < 100; + break; + case VIVID_CID_INSERT_SAV: + tpg_s_insert_sav(&dev->tpg, ctrl->val); + break; + case VIVID_CID_INSERT_EAV: + tpg_s_insert_eav(&dev->tpg, ctrl->val); + break; + case VIVID_CID_HFLIP: + dev->sensor_hflip = ctrl->val; + tpg_s_hflip(&dev->tpg, dev->sensor_hflip ^ dev->hflip); + break; + case VIVID_CID_VFLIP: + dev->sensor_vflip = ctrl->val; + tpg_s_vflip(&dev->tpg, dev->sensor_vflip ^ dev->vflip); + break; + case VIVID_CID_REDUCED_FPS: + dev->reduced_fps = ctrl->val; + vivid_update_format_cap(dev, true); + break; + case VIVID_CID_HAS_CROP_CAP: + dev->has_crop_cap = ctrl->val; + vivid_update_format_cap(dev, true); + break; + case VIVID_CID_HAS_COMPOSE_CAP: + dev->has_compose_cap = ctrl->val; + vivid_update_format_cap(dev, true); + break; + case VIVID_CID_HAS_SCALER_CAP: + dev->has_scaler_cap = ctrl->val; + vivid_update_format_cap(dev, true); + break; + case VIVID_CID_SHOW_BORDER: + tpg_s_show_border(&dev->tpg, ctrl->val); + break; + case VIVID_CID_SHOW_SQUARE: + tpg_s_show_square(&dev->tpg, ctrl->val); + break; + case VIVID_CID_STD_ASPECT_RATIO: + dev->std_aspect_ratio[dev->input] = ctrl->val; + tpg_s_video_aspect(&dev->tpg, vivid_get_video_aspect(dev)); + break; + case VIVID_CID_DV_TIMINGS_SIGNAL_MODE: + dev->dv_timings_signal_mode[dev->input] = + dev->ctrl_dv_timings_signal_mode->val; + dev->query_dv_timings[dev->input] = dev->ctrl_dv_timings->val; + + dev->power_present = 0; + for (i = 0, j = 0; + i < ARRAY_SIZE(dev->dv_timings_signal_mode); + i++) + if (dev->input_type[i] == HDMI) { + if (dev->dv_timings_signal_mode[i] != NO_SIGNAL) + dev->power_present |= (1 << j); + j++; + } + __v4l2_ctrl_s_ctrl(dev->ctrl_rx_power_present, + dev->power_present); + + v4l2_ctrl_activate(dev->ctrl_dv_timings, + dev->dv_timings_signal_mode[dev->input] == + SELECTED_DV_TIMINGS); + + vivid_update_quality(dev); + vivid_send_source_change(dev, HDMI); + break; + case VIVID_CID_DV_TIMINGS_ASPECT_RATIO: + dev->dv_timings_aspect_ratio[dev->input] = ctrl->val; + tpg_s_video_aspect(&dev->tpg, vivid_get_video_aspect(dev)); + break; + case VIVID_CID_TSTAMP_SRC: + dev->tstamp_src_is_soe = ctrl->val; + dev->vb_vid_cap_q.timestamp_flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK; + if (dev->tstamp_src_is_soe) + dev->vb_vid_cap_q.timestamp_flags |= V4L2_BUF_FLAG_TSTAMP_SRC_SOE; + break; + case VIVID_CID_MAX_EDID_BLOCKS: + dev->edid_max_blocks = ctrl->val; + if (dev->edid_blocks > dev->edid_max_blocks) + dev->edid_blocks = dev->edid_max_blocks; + break; + } + return 0; +} + +static const struct v4l2_ctrl_ops vivid_vid_cap_ctrl_ops = { + .s_ctrl = vivid_vid_cap_s_ctrl, +}; + +static const char * const vivid_ctrl_hor_movement_strings[] = { + "Move Left Fast", + "Move Left", + "Move Left Slow", + "No Movement", + "Move Right Slow", + "Move Right", + "Move Right Fast", + NULL, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_hor_movement = { + .ops = &vivid_vid_cap_ctrl_ops, + .id = VIVID_CID_HOR_MOVEMENT, + .name = "Horizontal Movement", + .type = V4L2_CTRL_TYPE_MENU, + .max = TPG_MOVE_POS_FAST, + .def = TPG_MOVE_NONE, + .qmenu = vivid_ctrl_hor_movement_strings, +}; + +static const char * const vivid_ctrl_vert_movement_strings[] = { + "Move Up Fast", + "Move Up", + "Move Up Slow", + "No Movement", + "Move Down Slow", + "Move Down", + "Move Down Fast", + NULL, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_vert_movement = { + .ops = &vivid_vid_cap_ctrl_ops, + .id = VIVID_CID_VERT_MOVEMENT, + .name = "Vertical Movement", + .type = V4L2_CTRL_TYPE_MENU, + .max = TPG_MOVE_POS_FAST, + .def = TPG_MOVE_NONE, + .qmenu = vivid_ctrl_vert_movement_strings, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_show_border = { + .ops = &vivid_vid_cap_ctrl_ops, + .id = VIVID_CID_SHOW_BORDER, + .name = "Show Border", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .max = 1, + .step = 1, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_show_square = { + .ops = &vivid_vid_cap_ctrl_ops, + .id = VIVID_CID_SHOW_SQUARE, + .name = "Show Square", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .max = 1, + .step = 1, +}; + +static const char * const vivid_ctrl_osd_mode_strings[] = { + "All", + "Counters Only", + "None", + NULL, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_osd_mode = { + .ops = &vivid_vid_cap_ctrl_ops, + .id = VIVID_CID_OSD_TEXT_MODE, + .name = "OSD Text Mode", + .type = V4L2_CTRL_TYPE_MENU, + .max = ARRAY_SIZE(vivid_ctrl_osd_mode_strings) - 2, + .qmenu = vivid_ctrl_osd_mode_strings, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_perc_fill = { + .ops = &vivid_vid_cap_ctrl_ops, + .id = VIVID_CID_PERCENTAGE_FILL, + .name = "Fill Percentage of Frame", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = 0, + .max = 100, + .def = 100, + .step = 1, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_insert_sav = { + .ops = &vivid_vid_cap_ctrl_ops, + .id = VIVID_CID_INSERT_SAV, + .name = "Insert SAV Code in Image", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .max = 1, + .step = 1, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_insert_eav = { + .ops = &vivid_vid_cap_ctrl_ops, + .id = VIVID_CID_INSERT_EAV, + .name = "Insert EAV Code in Image", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .max = 1, + .step = 1, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_hflip = { + .ops = &vivid_vid_cap_ctrl_ops, + .id = VIVID_CID_HFLIP, + .name = "Sensor Flipped Horizontally", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .max = 1, + .step = 1, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_vflip = { + .ops = &vivid_vid_cap_ctrl_ops, + .id = VIVID_CID_VFLIP, + .name = "Sensor Flipped Vertically", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .max = 1, + .step = 1, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_reduced_fps = { + .ops = &vivid_vid_cap_ctrl_ops, + .id = VIVID_CID_REDUCED_FPS, + .name = "Reduced Framerate", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .max = 1, + .step = 1, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_has_crop_cap = { + .ops = &vivid_vid_cap_ctrl_ops, + .id = VIVID_CID_HAS_CROP_CAP, + .name = "Enable Capture Cropping", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .max = 1, + .def = 1, + .step = 1, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_has_compose_cap = { + .ops = &vivid_vid_cap_ctrl_ops, + .id = VIVID_CID_HAS_COMPOSE_CAP, + .name = "Enable Capture Composing", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .max = 1, + .def = 1, + .step = 1, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_has_scaler_cap = { + .ops = &vivid_vid_cap_ctrl_ops, + .id = VIVID_CID_HAS_SCALER_CAP, + .name = "Enable Capture Scaler", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .max = 1, + .def = 1, + .step = 1, +}; + +static const char * const vivid_ctrl_tstamp_src_strings[] = { + "End of Frame", + "Start of Exposure", + NULL, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_tstamp_src = { + .ops = &vivid_vid_cap_ctrl_ops, + .id = VIVID_CID_TSTAMP_SRC, + .name = "Timestamp Source", + .type = V4L2_CTRL_TYPE_MENU, + .max = ARRAY_SIZE(vivid_ctrl_tstamp_src_strings) - 2, + .qmenu = vivid_ctrl_tstamp_src_strings, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_std_aspect_ratio = { + .ops = &vivid_vid_cap_ctrl_ops, + .id = VIVID_CID_STD_ASPECT_RATIO, + .name = "Standard Aspect Ratio", + .type = V4L2_CTRL_TYPE_MENU, + .min = 1, + .max = 4, + .def = 1, + .qmenu = tpg_aspect_strings, +}; + +static const char * const vivid_ctrl_dv_timings_signal_mode_strings[] = { + "Current DV Timings", + "No Signal", + "No Lock", + "Out of Range", + "Selected DV Timings", + "Cycle Through All DV Timings", + "Custom DV Timings", + NULL, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_dv_timings_signal_mode = { + .ops = &vivid_vid_cap_ctrl_ops, + .id = VIVID_CID_DV_TIMINGS_SIGNAL_MODE, + .name = "DV Timings Signal Mode", + .type = V4L2_CTRL_TYPE_MENU, + .max = 5, + .qmenu = vivid_ctrl_dv_timings_signal_mode_strings, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_dv_timings_aspect_ratio = { + .ops = &vivid_vid_cap_ctrl_ops, + .id = VIVID_CID_DV_TIMINGS_ASPECT_RATIO, + .name = "DV Timings Aspect Ratio", + .type = V4L2_CTRL_TYPE_MENU, + .max = 3, + .qmenu = tpg_aspect_strings, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_max_edid_blocks = { + .ops = &vivid_vid_cap_ctrl_ops, + .id = VIVID_CID_MAX_EDID_BLOCKS, + .name = "Maximum EDID Blocks", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = 1, + .max = 256, + .def = 2, + .step = 1, +}; + +static const char * const vivid_ctrl_colorspace_strings[] = { + "SMPTE 170M", + "Rec. 709", + "sRGB", + "opRGB", + "BT.2020", + "DCI-P3", + "SMPTE 240M", + "470 System M", + "470 System BG", + NULL, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_colorspace = { + .ops = &vivid_vid_cap_ctrl_ops, + .id = VIVID_CID_COLORSPACE, + .name = "Colorspace", + .type = V4L2_CTRL_TYPE_MENU, + .max = ARRAY_SIZE(vivid_ctrl_colorspace_strings) - 2, + .def = 2, + .qmenu = vivid_ctrl_colorspace_strings, +}; + +static const char * const vivid_ctrl_xfer_func_strings[] = { + "Default", + "Rec. 709", + "sRGB", + "opRGB", + "SMPTE 240M", + "None", + "DCI-P3", + "SMPTE 2084", + NULL, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_xfer_func = { + .ops = &vivid_vid_cap_ctrl_ops, + .id = VIVID_CID_XFER_FUNC, + .name = "Transfer Function", + .type = V4L2_CTRL_TYPE_MENU, + .max = ARRAY_SIZE(vivid_ctrl_xfer_func_strings) - 2, + .qmenu = vivid_ctrl_xfer_func_strings, +}; + +static const char * const vivid_ctrl_ycbcr_enc_strings[] = { + "Default", + "ITU-R 601", + "Rec. 709", + "xvYCC 601", + "xvYCC 709", + "", + "BT.2020", + "BT.2020 Constant Luminance", + "SMPTE 240M", + NULL, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_ycbcr_enc = { + .ops = &vivid_vid_cap_ctrl_ops, + .id = VIVID_CID_YCBCR_ENC, + .name = "Y'CbCr Encoding", + .type = V4L2_CTRL_TYPE_MENU, + .menu_skip_mask = 1 << 5, + .max = ARRAY_SIZE(vivid_ctrl_ycbcr_enc_strings) - 2, + .qmenu = vivid_ctrl_ycbcr_enc_strings, +}; + +static const char * const vivid_ctrl_hsv_enc_strings[] = { + "Hue 0-179", + "Hue 0-256", + NULL, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_hsv_enc = { + .ops = &vivid_vid_cap_ctrl_ops, + .id = VIVID_CID_HSV_ENC, + .name = "HSV Encoding", + .type = V4L2_CTRL_TYPE_MENU, + .max = ARRAY_SIZE(vivid_ctrl_hsv_enc_strings) - 2, + .qmenu = vivid_ctrl_hsv_enc_strings, +}; + +static const char * const vivid_ctrl_quantization_strings[] = { + "Default", + "Full Range", + "Limited Range", + NULL, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_quantization = { + .ops = &vivid_vid_cap_ctrl_ops, + .id = VIVID_CID_QUANTIZATION, + .name = "Quantization", + .type = V4L2_CTRL_TYPE_MENU, + .max = ARRAY_SIZE(vivid_ctrl_quantization_strings) - 2, + .qmenu = vivid_ctrl_quantization_strings, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_alpha_mode = { + .ops = &vivid_vid_cap_ctrl_ops, + .id = VIVID_CID_ALPHA_MODE, + .name = "Apply Alpha To Red Only", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .max = 1, + .step = 1, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_limited_rgb_range = { + .ops = &vivid_vid_cap_ctrl_ops, + .id = VIVID_CID_LIMITED_RGB_RANGE, + .name = "Limited RGB Range (16-235)", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .max = 1, + .step = 1, +}; + + +/* Video Loop Control */ + +static int vivid_loop_cap_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_loop_cap); + + switch (ctrl->id) { + case VIVID_CID_LOOP_VIDEO: + dev->loop_video = ctrl->val; + vivid_update_quality(dev); + vivid_send_source_change(dev, SVID); + vivid_send_source_change(dev, HDMI); + break; + } + return 0; +} + +static const struct v4l2_ctrl_ops vivid_loop_cap_ctrl_ops = { + .s_ctrl = vivid_loop_cap_s_ctrl, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_loop_video = { + .ops = &vivid_loop_cap_ctrl_ops, + .id = VIVID_CID_LOOP_VIDEO, + .name = "Loop Video", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .max = 1, + .step = 1, +}; + + +/* VBI Capture Control */ + +static int vivid_vbi_cap_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_vbi_cap); + + switch (ctrl->id) { + case VIVID_CID_VBI_CAP_INTERLACED: + dev->vbi_cap_interlaced = ctrl->val; + break; + } + return 0; +} + +static const struct v4l2_ctrl_ops vivid_vbi_cap_ctrl_ops = { + .s_ctrl = vivid_vbi_cap_s_ctrl, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_vbi_cap_interlaced = { + .ops = &vivid_vbi_cap_ctrl_ops, + .id = VIVID_CID_VBI_CAP_INTERLACED, + .name = "Interlaced VBI Format", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .max = 1, + .step = 1, +}; + + +/* Video Output Controls */ + +static int vivid_vid_out_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_vid_out); + struct v4l2_bt_timings *bt = &dev->dv_timings_out.bt; + u32 display_present = 0; + unsigned int i, j, bus_idx; + + switch (ctrl->id) { + case VIVID_CID_HAS_CROP_OUT: + dev->has_crop_out = ctrl->val; + vivid_update_format_out(dev); + break; + case VIVID_CID_HAS_COMPOSE_OUT: + dev->has_compose_out = ctrl->val; + vivid_update_format_out(dev); + break; + case VIVID_CID_HAS_SCALER_OUT: + dev->has_scaler_out = ctrl->val; + vivid_update_format_out(dev); + break; + case V4L2_CID_DV_TX_MODE: + dev->dvi_d_out = ctrl->val == V4L2_DV_TX_MODE_DVI_D; + if (!vivid_is_hdmi_out(dev)) + break; + if (!dev->dvi_d_out && (bt->flags & V4L2_DV_FL_IS_CE_VIDEO)) { + if (bt->width == 720 && bt->height <= 576) + dev->colorspace_out = V4L2_COLORSPACE_SMPTE170M; + else + dev->colorspace_out = V4L2_COLORSPACE_REC709; + dev->quantization_out = V4L2_QUANTIZATION_DEFAULT; + } else { + dev->colorspace_out = V4L2_COLORSPACE_SRGB; + dev->quantization_out = dev->dvi_d_out ? + V4L2_QUANTIZATION_LIM_RANGE : + V4L2_QUANTIZATION_DEFAULT; + } + if (dev->loop_video) + vivid_send_source_change(dev, HDMI); + break; + case VIVID_CID_DISPLAY_PRESENT: + if (dev->output_type[dev->output] != HDMI) + break; + + dev->display_present[dev->output] = ctrl->val; + for (i = 0, j = 0; i < dev->num_outputs; i++) + if (dev->output_type[i] == HDMI) + display_present |= + dev->display_present[i] << j++; + + __v4l2_ctrl_s_ctrl(dev->ctrl_tx_rxsense, display_present); + + if (dev->edid_blocks) { + __v4l2_ctrl_s_ctrl(dev->ctrl_tx_edid_present, + display_present); + __v4l2_ctrl_s_ctrl(dev->ctrl_tx_hotplug, + display_present); + } + + bus_idx = dev->cec_output2bus_map[dev->output]; + if (!dev->cec_tx_adap[bus_idx]) + break; + + if (ctrl->val && dev->edid_blocks) + cec_s_phys_addr(dev->cec_tx_adap[bus_idx], + dev->cec_tx_adap[bus_idx]->phys_addr, + false); + else + cec_phys_addr_invalidate(dev->cec_tx_adap[bus_idx]); + + break; + } + return 0; +} + +static const struct v4l2_ctrl_ops vivid_vid_out_ctrl_ops = { + .s_ctrl = vivid_vid_out_s_ctrl, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_has_crop_out = { + .ops = &vivid_vid_out_ctrl_ops, + .id = VIVID_CID_HAS_CROP_OUT, + .name = "Enable Output Cropping", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .max = 1, + .def = 1, + .step = 1, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_has_compose_out = { + .ops = &vivid_vid_out_ctrl_ops, + .id = VIVID_CID_HAS_COMPOSE_OUT, + .name = "Enable Output Composing", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .max = 1, + .def = 1, + .step = 1, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_has_scaler_out = { + .ops = &vivid_vid_out_ctrl_ops, + .id = VIVID_CID_HAS_SCALER_OUT, + .name = "Enable Output Scaler", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .max = 1, + .def = 1, + .step = 1, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_display_present = { + .ops = &vivid_vid_out_ctrl_ops, + .id = VIVID_CID_DISPLAY_PRESENT, + .name = "Display Present", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .max = 1, + .def = 1, + .step = 1, +}; + +/* Streaming Controls */ + +static int vivid_streaming_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_streaming); + u64 rem; + + switch (ctrl->id) { + case VIVID_CID_DQBUF_ERROR: + dev->dqbuf_error = true; + break; + case VIVID_CID_PERC_DROPPED: + dev->perc_dropped_buffers = ctrl->val; + break; + case VIVID_CID_QUEUE_SETUP_ERROR: + dev->queue_setup_error = true; + break; + case VIVID_CID_BUF_PREPARE_ERROR: + dev->buf_prepare_error = true; + break; + case VIVID_CID_START_STR_ERROR: + dev->start_streaming_error = true; + break; + case VIVID_CID_REQ_VALIDATE_ERROR: + dev->req_validate_error = true; + break; + case VIVID_CID_QUEUE_ERROR: + if (vb2_start_streaming_called(&dev->vb_vid_cap_q)) + vb2_queue_error(&dev->vb_vid_cap_q); + if (vb2_start_streaming_called(&dev->vb_vbi_cap_q)) + vb2_queue_error(&dev->vb_vbi_cap_q); + if (vb2_start_streaming_called(&dev->vb_vid_out_q)) + vb2_queue_error(&dev->vb_vid_out_q); + if (vb2_start_streaming_called(&dev->vb_vbi_out_q)) + vb2_queue_error(&dev->vb_vbi_out_q); + if (vb2_start_streaming_called(&dev->vb_sdr_cap_q)) + vb2_queue_error(&dev->vb_sdr_cap_q); + break; + case VIVID_CID_SEQ_WRAP: + dev->seq_wrap = ctrl->val; + break; + case VIVID_CID_TIME_WRAP: + dev->time_wrap = ctrl->val; + if (ctrl->val == 0) { + dev->time_wrap_offset = 0; + break; + } + /* + * We want to set the time 16 seconds before the 32 bit tv_sec + * value of struct timeval would wrap around. So first we + * calculate ktime_get_ns() % ((1 << 32) * NSEC_PER_SEC), and + * then we set the offset to ((1 << 32) - 16) * NSEC_PER_SEC). + */ + div64_u64_rem(ktime_get_ns(), + 0x100000000ULL * NSEC_PER_SEC, &rem); + dev->time_wrap_offset = + (0x100000000ULL - 16) * NSEC_PER_SEC - rem; + break; + } + return 0; +} + +static const struct v4l2_ctrl_ops vivid_streaming_ctrl_ops = { + .s_ctrl = vivid_streaming_s_ctrl, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_dqbuf_error = { + .ops = &vivid_streaming_ctrl_ops, + .id = VIVID_CID_DQBUF_ERROR, + .name = "Inject V4L2_BUF_FLAG_ERROR", + .type = V4L2_CTRL_TYPE_BUTTON, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_perc_dropped = { + .ops = &vivid_streaming_ctrl_ops, + .id = VIVID_CID_PERC_DROPPED, + .name = "Percentage of Dropped Buffers", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = 0, + .max = 100, + .step = 1, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_queue_setup_error = { + .ops = &vivid_streaming_ctrl_ops, + .id = VIVID_CID_QUEUE_SETUP_ERROR, + .name = "Inject VIDIOC_REQBUFS Error", + .type = V4L2_CTRL_TYPE_BUTTON, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_buf_prepare_error = { + .ops = &vivid_streaming_ctrl_ops, + .id = VIVID_CID_BUF_PREPARE_ERROR, + .name = "Inject VIDIOC_QBUF Error", + .type = V4L2_CTRL_TYPE_BUTTON, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_start_streaming_error = { + .ops = &vivid_streaming_ctrl_ops, + .id = VIVID_CID_START_STR_ERROR, + .name = "Inject VIDIOC_STREAMON Error", + .type = V4L2_CTRL_TYPE_BUTTON, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_queue_error = { + .ops = &vivid_streaming_ctrl_ops, + .id = VIVID_CID_QUEUE_ERROR, + .name = "Inject Fatal Streaming Error", + .type = V4L2_CTRL_TYPE_BUTTON, +}; + +#ifdef CONFIG_MEDIA_CONTROLLER +static const struct v4l2_ctrl_config vivid_ctrl_req_validate_error = { + .ops = &vivid_streaming_ctrl_ops, + .id = VIVID_CID_REQ_VALIDATE_ERROR, + .name = "Inject req_validate() Error", + .type = V4L2_CTRL_TYPE_BUTTON, +}; +#endif + +static const struct v4l2_ctrl_config vivid_ctrl_seq_wrap = { + .ops = &vivid_streaming_ctrl_ops, + .id = VIVID_CID_SEQ_WRAP, + .name = "Wrap Sequence Number", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .max = 1, + .step = 1, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_time_wrap = { + .ops = &vivid_streaming_ctrl_ops, + .id = VIVID_CID_TIME_WRAP, + .name = "Wrap Timestamp", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .max = 1, + .step = 1, +}; + + +/* SDTV Capture Controls */ + +static int vivid_sdtv_cap_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_sdtv_cap); + + switch (ctrl->id) { + case VIVID_CID_STD_SIGNAL_MODE: + dev->std_signal_mode[dev->input] = + dev->ctrl_std_signal_mode->val; + if (dev->std_signal_mode[dev->input] == SELECTED_STD) + dev->query_std[dev->input] = + vivid_standard[dev->ctrl_standard->val]; + v4l2_ctrl_activate(dev->ctrl_standard, + dev->std_signal_mode[dev->input] == + SELECTED_STD); + vivid_update_quality(dev); + vivid_send_source_change(dev, TV); + vivid_send_source_change(dev, SVID); + break; + } + return 0; +} + +static const struct v4l2_ctrl_ops vivid_sdtv_cap_ctrl_ops = { + .s_ctrl = vivid_sdtv_cap_s_ctrl, +}; + +static const char * const vivid_ctrl_std_signal_mode_strings[] = { + "Current Standard", + "No Signal", + "No Lock", + "", + "Selected Standard", + "Cycle Through All Standards", + NULL, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_std_signal_mode = { + .ops = &vivid_sdtv_cap_ctrl_ops, + .id = VIVID_CID_STD_SIGNAL_MODE, + .name = "Standard Signal Mode", + .type = V4L2_CTRL_TYPE_MENU, + .max = ARRAY_SIZE(vivid_ctrl_std_signal_mode_strings) - 2, + .menu_skip_mask = 1 << 3, + .qmenu = vivid_ctrl_std_signal_mode_strings, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_standard = { + .ops = &vivid_sdtv_cap_ctrl_ops, + .id = VIVID_CID_STANDARD, + .name = "Standard", + .type = V4L2_CTRL_TYPE_MENU, + .max = 14, + .qmenu = vivid_ctrl_standard_strings, +}; + + + +/* Radio Receiver Controls */ + +static int vivid_radio_rx_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_radio_rx); + + switch (ctrl->id) { + case VIVID_CID_RADIO_SEEK_MODE: + dev->radio_rx_hw_seek_mode = ctrl->val; + break; + case VIVID_CID_RADIO_SEEK_PROG_LIM: + dev->radio_rx_hw_seek_prog_lim = ctrl->val; + break; + case VIVID_CID_RADIO_RX_RDS_RBDS: + dev->rds_gen.use_rbds = ctrl->val; + break; + case VIVID_CID_RADIO_RX_RDS_BLOCKIO: + dev->radio_rx_rds_controls = ctrl->val; + dev->radio_rx_caps &= ~V4L2_CAP_READWRITE; + dev->radio_rx_rds_use_alternates = false; + if (!dev->radio_rx_rds_controls) { + dev->radio_rx_caps |= V4L2_CAP_READWRITE; + __v4l2_ctrl_s_ctrl(dev->radio_rx_rds_pty, 0); + __v4l2_ctrl_s_ctrl(dev->radio_rx_rds_ta, 0); + __v4l2_ctrl_s_ctrl(dev->radio_rx_rds_tp, 0); + __v4l2_ctrl_s_ctrl(dev->radio_rx_rds_ms, 0); + __v4l2_ctrl_s_ctrl_string(dev->radio_rx_rds_psname, ""); + __v4l2_ctrl_s_ctrl_string(dev->radio_rx_rds_radiotext, ""); + } + v4l2_ctrl_activate(dev->radio_rx_rds_pty, dev->radio_rx_rds_controls); + v4l2_ctrl_activate(dev->radio_rx_rds_psname, dev->radio_rx_rds_controls); + v4l2_ctrl_activate(dev->radio_rx_rds_radiotext, dev->radio_rx_rds_controls); + v4l2_ctrl_activate(dev->radio_rx_rds_ta, dev->radio_rx_rds_controls); + v4l2_ctrl_activate(dev->radio_rx_rds_tp, dev->radio_rx_rds_controls); + v4l2_ctrl_activate(dev->radio_rx_rds_ms, dev->radio_rx_rds_controls); + dev->radio_rx_dev.device_caps = dev->radio_rx_caps; + break; + case V4L2_CID_RDS_RECEPTION: + dev->radio_rx_rds_enabled = ctrl->val; + break; + } + return 0; +} + +static const struct v4l2_ctrl_ops vivid_radio_rx_ctrl_ops = { + .s_ctrl = vivid_radio_rx_s_ctrl, +}; + +static const char * const vivid_ctrl_radio_rds_mode_strings[] = { + "Block I/O", + "Controls", + NULL, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_radio_rx_rds_blockio = { + .ops = &vivid_radio_rx_ctrl_ops, + .id = VIVID_CID_RADIO_RX_RDS_BLOCKIO, + .name = "RDS Rx I/O Mode", + .type = V4L2_CTRL_TYPE_MENU, + .qmenu = vivid_ctrl_radio_rds_mode_strings, + .max = 1, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_radio_rx_rds_rbds = { + .ops = &vivid_radio_rx_ctrl_ops, + .id = VIVID_CID_RADIO_RX_RDS_RBDS, + .name = "Generate RBDS Instead of RDS", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .max = 1, + .step = 1, +}; + +static const char * const vivid_ctrl_radio_hw_seek_mode_strings[] = { + "Bounded", + "Wrap Around", + "Both", + NULL, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_radio_hw_seek_mode = { + .ops = &vivid_radio_rx_ctrl_ops, + .id = VIVID_CID_RADIO_SEEK_MODE, + .name = "Radio HW Seek Mode", + .type = V4L2_CTRL_TYPE_MENU, + .max = 2, + .qmenu = vivid_ctrl_radio_hw_seek_mode_strings, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_radio_hw_seek_prog_lim = { + .ops = &vivid_radio_rx_ctrl_ops, + .id = VIVID_CID_RADIO_SEEK_PROG_LIM, + .name = "Radio Programmable HW Seek", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .max = 1, + .step = 1, +}; + + +/* Radio Transmitter Controls */ + +static int vivid_radio_tx_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_radio_tx); + + switch (ctrl->id) { + case VIVID_CID_RADIO_TX_RDS_BLOCKIO: + dev->radio_tx_rds_controls = ctrl->val; + dev->radio_tx_caps &= ~V4L2_CAP_READWRITE; + if (!dev->radio_tx_rds_controls) + dev->radio_tx_caps |= V4L2_CAP_READWRITE; + dev->radio_tx_dev.device_caps = dev->radio_tx_caps; + break; + case V4L2_CID_RDS_TX_PTY: + if (dev->radio_rx_rds_controls) + v4l2_ctrl_s_ctrl(dev->radio_rx_rds_pty, ctrl->val); + break; + case V4L2_CID_RDS_TX_PS_NAME: + if (dev->radio_rx_rds_controls) + v4l2_ctrl_s_ctrl_string(dev->radio_rx_rds_psname, ctrl->p_new.p_char); + break; + case V4L2_CID_RDS_TX_RADIO_TEXT: + if (dev->radio_rx_rds_controls) + v4l2_ctrl_s_ctrl_string(dev->radio_rx_rds_radiotext, ctrl->p_new.p_char); + break; + case V4L2_CID_RDS_TX_TRAFFIC_ANNOUNCEMENT: + if (dev->radio_rx_rds_controls) + v4l2_ctrl_s_ctrl(dev->radio_rx_rds_ta, ctrl->val); + break; + case V4L2_CID_RDS_TX_TRAFFIC_PROGRAM: + if (dev->radio_rx_rds_controls) + v4l2_ctrl_s_ctrl(dev->radio_rx_rds_tp, ctrl->val); + break; + case V4L2_CID_RDS_TX_MUSIC_SPEECH: + if (dev->radio_rx_rds_controls) + v4l2_ctrl_s_ctrl(dev->radio_rx_rds_ms, ctrl->val); + break; + } + return 0; +} + +static const struct v4l2_ctrl_ops vivid_radio_tx_ctrl_ops = { + .s_ctrl = vivid_radio_tx_s_ctrl, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_radio_tx_rds_blockio = { + .ops = &vivid_radio_tx_ctrl_ops, + .id = VIVID_CID_RADIO_TX_RDS_BLOCKIO, + .name = "RDS Tx I/O Mode", + .type = V4L2_CTRL_TYPE_MENU, + .qmenu = vivid_ctrl_radio_rds_mode_strings, + .max = 1, + .def = 1, +}; + + +/* SDR Capture Controls */ + +static int vivid_sdr_cap_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_sdr_cap); + + switch (ctrl->id) { + case VIVID_CID_SDR_CAP_FM_DEVIATION: + dev->sdr_fm_deviation = ctrl->val; + break; + } + return 0; +} + +static const struct v4l2_ctrl_ops vivid_sdr_cap_ctrl_ops = { + .s_ctrl = vivid_sdr_cap_s_ctrl, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_sdr_cap_fm_deviation = { + .ops = &vivid_sdr_cap_ctrl_ops, + .id = VIVID_CID_SDR_CAP_FM_DEVIATION, + .name = "FM Deviation", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = 100, + .max = 200000, + .def = 75000, + .step = 1, +}; + +/* Metadata Capture Control */ + +static int vivid_meta_cap_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, + ctrl_hdl_meta_cap); + + switch (ctrl->id) { + case VIVID_CID_META_CAP_GENERATE_PTS: + dev->meta_pts = ctrl->val; + break; + case VIVID_CID_META_CAP_GENERATE_SCR: + dev->meta_scr = ctrl->val; + break; + } + return 0; +} + +static const struct v4l2_ctrl_ops vivid_meta_cap_ctrl_ops = { + .s_ctrl = vivid_meta_cap_s_ctrl, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_meta_has_pts = { + .ops = &vivid_meta_cap_ctrl_ops, + .id = VIVID_CID_META_CAP_GENERATE_PTS, + .name = "Generate PTS", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .max = 1, + .def = 1, + .step = 1, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_meta_has_src_clk = { + .ops = &vivid_meta_cap_ctrl_ops, + .id = VIVID_CID_META_CAP_GENERATE_SCR, + .name = "Generate SCR", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .max = 1, + .def = 1, + .step = 1, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_class = { + .ops = &vivid_user_gen_ctrl_ops, + .flags = V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_WRITE_ONLY, + .id = VIVID_CID_VIVID_CLASS, + .name = "Vivid Controls", + .type = V4L2_CTRL_TYPE_CTRL_CLASS, +}; + +int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap, + bool show_ccs_out, bool no_error_inj, + bool has_sdtv, bool has_hdmi) +{ + struct v4l2_ctrl_handler *hdl_user_gen = &dev->ctrl_hdl_user_gen; + struct v4l2_ctrl_handler *hdl_user_vid = &dev->ctrl_hdl_user_vid; + struct v4l2_ctrl_handler *hdl_user_aud = &dev->ctrl_hdl_user_aud; + struct v4l2_ctrl_handler *hdl_streaming = &dev->ctrl_hdl_streaming; + struct v4l2_ctrl_handler *hdl_sdtv_cap = &dev->ctrl_hdl_sdtv_cap; + struct v4l2_ctrl_handler *hdl_loop_cap = &dev->ctrl_hdl_loop_cap; + struct v4l2_ctrl_handler *hdl_fb = &dev->ctrl_hdl_fb; + struct v4l2_ctrl_handler *hdl_vid_cap = &dev->ctrl_hdl_vid_cap; + struct v4l2_ctrl_handler *hdl_vid_out = &dev->ctrl_hdl_vid_out; + struct v4l2_ctrl_handler *hdl_vbi_cap = &dev->ctrl_hdl_vbi_cap; + struct v4l2_ctrl_handler *hdl_vbi_out = &dev->ctrl_hdl_vbi_out; + struct v4l2_ctrl_handler *hdl_radio_rx = &dev->ctrl_hdl_radio_rx; + struct v4l2_ctrl_handler *hdl_radio_tx = &dev->ctrl_hdl_radio_tx; + struct v4l2_ctrl_handler *hdl_sdr_cap = &dev->ctrl_hdl_sdr_cap; + struct v4l2_ctrl_handler *hdl_meta_cap = &dev->ctrl_hdl_meta_cap; + struct v4l2_ctrl_handler *hdl_meta_out = &dev->ctrl_hdl_meta_out; + struct v4l2_ctrl_handler *hdl_tch_cap = &dev->ctrl_hdl_touch_cap; + + struct v4l2_ctrl_config vivid_ctrl_dv_timings = { + .ops = &vivid_vid_cap_ctrl_ops, + .id = VIVID_CID_DV_TIMINGS, + .name = "DV Timings", + .type = V4L2_CTRL_TYPE_MENU, + }; + int i; + + v4l2_ctrl_handler_init(hdl_user_gen, 10); + v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_class, NULL); + v4l2_ctrl_handler_init(hdl_user_vid, 9); + v4l2_ctrl_new_custom(hdl_user_vid, &vivid_ctrl_class, NULL); + v4l2_ctrl_handler_init(hdl_user_aud, 2); + v4l2_ctrl_new_custom(hdl_user_aud, &vivid_ctrl_class, NULL); + v4l2_ctrl_handler_init(hdl_streaming, 8); + v4l2_ctrl_new_custom(hdl_streaming, &vivid_ctrl_class, NULL); + v4l2_ctrl_handler_init(hdl_sdtv_cap, 2); + v4l2_ctrl_new_custom(hdl_sdtv_cap, &vivid_ctrl_class, NULL); + v4l2_ctrl_handler_init(hdl_loop_cap, 1); + v4l2_ctrl_new_custom(hdl_loop_cap, &vivid_ctrl_class, NULL); + v4l2_ctrl_handler_init(hdl_fb, 1); + v4l2_ctrl_new_custom(hdl_fb, &vivid_ctrl_class, NULL); + v4l2_ctrl_handler_init(hdl_vid_cap, 55); + v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_class, NULL); + v4l2_ctrl_handler_init(hdl_vid_out, 26); + if (!no_error_inj || dev->has_fb || dev->num_hdmi_outputs) + v4l2_ctrl_new_custom(hdl_vid_out, &vivid_ctrl_class, NULL); + v4l2_ctrl_handler_init(hdl_vbi_cap, 21); + v4l2_ctrl_new_custom(hdl_vbi_cap, &vivid_ctrl_class, NULL); + v4l2_ctrl_handler_init(hdl_vbi_out, 19); + if (!no_error_inj) + v4l2_ctrl_new_custom(hdl_vbi_out, &vivid_ctrl_class, NULL); + v4l2_ctrl_handler_init(hdl_radio_rx, 17); + v4l2_ctrl_new_custom(hdl_radio_rx, &vivid_ctrl_class, NULL); + v4l2_ctrl_handler_init(hdl_radio_tx, 17); + v4l2_ctrl_new_custom(hdl_radio_tx, &vivid_ctrl_class, NULL); + v4l2_ctrl_handler_init(hdl_sdr_cap, 19); + v4l2_ctrl_new_custom(hdl_sdr_cap, &vivid_ctrl_class, NULL); + v4l2_ctrl_handler_init(hdl_meta_cap, 2); + v4l2_ctrl_new_custom(hdl_meta_cap, &vivid_ctrl_class, NULL); + v4l2_ctrl_handler_init(hdl_meta_out, 2); + v4l2_ctrl_new_custom(hdl_meta_out, &vivid_ctrl_class, NULL); + v4l2_ctrl_handler_init(hdl_tch_cap, 2); + v4l2_ctrl_new_custom(hdl_tch_cap, &vivid_ctrl_class, NULL); + + /* User Controls */ + dev->volume = v4l2_ctrl_new_std(hdl_user_aud, NULL, + V4L2_CID_AUDIO_VOLUME, 0, 255, 1, 200); + dev->mute = v4l2_ctrl_new_std(hdl_user_aud, NULL, + V4L2_CID_AUDIO_MUTE, 0, 1, 1, 0); + if (dev->has_vid_cap) { + dev->brightness = v4l2_ctrl_new_std(hdl_user_vid, &vivid_user_vid_ctrl_ops, + V4L2_CID_BRIGHTNESS, 0, 255, 1, 128); + for (i = 0; i < MAX_INPUTS; i++) + dev->input_brightness[i] = 128; + dev->contrast = v4l2_ctrl_new_std(hdl_user_vid, &vivid_user_vid_ctrl_ops, + V4L2_CID_CONTRAST, 0, 255, 1, 128); + dev->saturation = v4l2_ctrl_new_std(hdl_user_vid, &vivid_user_vid_ctrl_ops, + V4L2_CID_SATURATION, 0, 255, 1, 128); + dev->hue = v4l2_ctrl_new_std(hdl_user_vid, &vivid_user_vid_ctrl_ops, + V4L2_CID_HUE, -128, 128, 1, 0); + v4l2_ctrl_new_std(hdl_user_vid, &vivid_user_vid_ctrl_ops, + V4L2_CID_HFLIP, 0, 1, 1, 0); + v4l2_ctrl_new_std(hdl_user_vid, &vivid_user_vid_ctrl_ops, + V4L2_CID_VFLIP, 0, 1, 1, 0); + dev->autogain = v4l2_ctrl_new_std(hdl_user_vid, &vivid_user_vid_ctrl_ops, + V4L2_CID_AUTOGAIN, 0, 1, 1, 1); + dev->gain = v4l2_ctrl_new_std(hdl_user_vid, &vivid_user_vid_ctrl_ops, + V4L2_CID_GAIN, 0, 255, 1, 100); + dev->alpha = v4l2_ctrl_new_std(hdl_user_vid, &vivid_user_vid_ctrl_ops, + V4L2_CID_ALPHA_COMPONENT, 0, 255, 1, 0); + } + dev->button = v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_button, NULL); + dev->int32 = v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_int32, NULL); + dev->int64 = v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_int64, NULL); + dev->boolean = v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_boolean, NULL); + dev->menu = v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_menu, NULL); + dev->string = v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_string, NULL); + dev->bitmask = v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_bitmask, NULL); + dev->int_menu = v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_int_menu, NULL); + v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_area, NULL); + v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_u32_array, NULL); + v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_u16_matrix, NULL); + v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_u8_4d_array, NULL); + + if (dev->has_vid_cap) { + /* Image Processing Controls */ + struct v4l2_ctrl_config vivid_ctrl_test_pattern = { + .ops = &vivid_vid_cap_ctrl_ops, + .id = VIVID_CID_TEST_PATTERN, + .name = "Test Pattern", + .type = V4L2_CTRL_TYPE_MENU, + .max = TPG_PAT_NOISE, + .qmenu = tpg_pattern_strings, + }; + + dev->test_pattern = v4l2_ctrl_new_custom(hdl_vid_cap, + &vivid_ctrl_test_pattern, NULL); + v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_perc_fill, NULL); + v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_hor_movement, NULL); + v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_vert_movement, NULL); + v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_osd_mode, NULL); + v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_show_border, NULL); + v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_show_square, NULL); + v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_hflip, NULL); + v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_vflip, NULL); + v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_insert_sav, NULL); + v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_insert_eav, NULL); + v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_reduced_fps, NULL); + if (show_ccs_cap) { + dev->ctrl_has_crop_cap = v4l2_ctrl_new_custom(hdl_vid_cap, + &vivid_ctrl_has_crop_cap, NULL); + dev->ctrl_has_compose_cap = v4l2_ctrl_new_custom(hdl_vid_cap, + &vivid_ctrl_has_compose_cap, NULL); + dev->ctrl_has_scaler_cap = v4l2_ctrl_new_custom(hdl_vid_cap, + &vivid_ctrl_has_scaler_cap, NULL); + } + + v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_tstamp_src, NULL); + dev->colorspace = v4l2_ctrl_new_custom(hdl_vid_cap, + &vivid_ctrl_colorspace, NULL); + v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_xfer_func, NULL); + v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_ycbcr_enc, NULL); + v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_hsv_enc, NULL); + v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_quantization, NULL); + v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_alpha_mode, NULL); + } + + if (dev->has_vid_out && show_ccs_out) { + dev->ctrl_has_crop_out = v4l2_ctrl_new_custom(hdl_vid_out, + &vivid_ctrl_has_crop_out, NULL); + dev->ctrl_has_compose_out = v4l2_ctrl_new_custom(hdl_vid_out, + &vivid_ctrl_has_compose_out, NULL); + dev->ctrl_has_scaler_out = v4l2_ctrl_new_custom(hdl_vid_out, + &vivid_ctrl_has_scaler_out, NULL); + } + + /* + * Testing this driver with v4l2-compliance will trigger the error + * injection controls, and after that nothing will work as expected. + * So we have a module option to drop these error injecting controls + * allowing us to run v4l2_compliance again. + */ + if (!no_error_inj) { + v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_disconnect, NULL); + v4l2_ctrl_new_custom(hdl_streaming, &vivid_ctrl_dqbuf_error, NULL); + v4l2_ctrl_new_custom(hdl_streaming, &vivid_ctrl_perc_dropped, NULL); + v4l2_ctrl_new_custom(hdl_streaming, &vivid_ctrl_queue_setup_error, NULL); + v4l2_ctrl_new_custom(hdl_streaming, &vivid_ctrl_buf_prepare_error, NULL); + v4l2_ctrl_new_custom(hdl_streaming, &vivid_ctrl_start_streaming_error, NULL); + v4l2_ctrl_new_custom(hdl_streaming, &vivid_ctrl_queue_error, NULL); +#ifdef CONFIG_MEDIA_CONTROLLER + v4l2_ctrl_new_custom(hdl_streaming, &vivid_ctrl_req_validate_error, NULL); +#endif + v4l2_ctrl_new_custom(hdl_streaming, &vivid_ctrl_seq_wrap, NULL); + v4l2_ctrl_new_custom(hdl_streaming, &vivid_ctrl_time_wrap, NULL); + } + + if (has_sdtv && (dev->has_vid_cap || dev->has_vbi_cap)) { + if (dev->has_vid_cap) + v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_std_aspect_ratio, NULL); + dev->ctrl_std_signal_mode = v4l2_ctrl_new_custom(hdl_sdtv_cap, + &vivid_ctrl_std_signal_mode, NULL); + dev->ctrl_standard = v4l2_ctrl_new_custom(hdl_sdtv_cap, + &vivid_ctrl_standard, NULL); + if (dev->ctrl_std_signal_mode) + v4l2_ctrl_cluster(2, &dev->ctrl_std_signal_mode); + if (dev->has_raw_vbi_cap) + v4l2_ctrl_new_custom(hdl_vbi_cap, &vivid_ctrl_vbi_cap_interlaced, NULL); + } + + if (dev->num_hdmi_inputs) { + s64 hdmi_input_mask = GENMASK(dev->num_hdmi_inputs - 1, 0); + + dev->ctrl_dv_timings_signal_mode = v4l2_ctrl_new_custom(hdl_vid_cap, + &vivid_ctrl_dv_timings_signal_mode, NULL); + + vivid_ctrl_dv_timings.max = dev->query_dv_timings_size - 1; + vivid_ctrl_dv_timings.qmenu = + (const char * const *)dev->query_dv_timings_qmenu; + dev->ctrl_dv_timings = v4l2_ctrl_new_custom(hdl_vid_cap, + &vivid_ctrl_dv_timings, NULL); + if (dev->ctrl_dv_timings_signal_mode) + v4l2_ctrl_cluster(2, &dev->ctrl_dv_timings_signal_mode); + + v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_dv_timings_aspect_ratio, NULL); + v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_max_edid_blocks, NULL); + dev->real_rgb_range_cap = v4l2_ctrl_new_custom(hdl_vid_cap, + &vivid_ctrl_limited_rgb_range, NULL); + dev->rgb_range_cap = v4l2_ctrl_new_std_menu(hdl_vid_cap, + &vivid_vid_cap_ctrl_ops, + V4L2_CID_DV_RX_RGB_RANGE, V4L2_DV_RGB_RANGE_FULL, + 0, V4L2_DV_RGB_RANGE_AUTO); + dev->ctrl_rx_power_present = v4l2_ctrl_new_std(hdl_vid_cap, + NULL, V4L2_CID_DV_RX_POWER_PRESENT, 0, hdmi_input_mask, + 0, hdmi_input_mask); + + } + if (dev->num_hdmi_outputs) { + s64 hdmi_output_mask = GENMASK(dev->num_hdmi_outputs - 1, 0); + + /* + * We aren't doing anything with this at the moment, but + * HDMI outputs typically have this controls. + */ + dev->ctrl_tx_rgb_range = v4l2_ctrl_new_std_menu(hdl_vid_out, NULL, + V4L2_CID_DV_TX_RGB_RANGE, V4L2_DV_RGB_RANGE_FULL, + 0, V4L2_DV_RGB_RANGE_AUTO); + dev->ctrl_tx_mode = v4l2_ctrl_new_std_menu(hdl_vid_out, NULL, + V4L2_CID_DV_TX_MODE, V4L2_DV_TX_MODE_HDMI, + 0, V4L2_DV_TX_MODE_HDMI); + dev->ctrl_display_present = v4l2_ctrl_new_custom(hdl_vid_out, + &vivid_ctrl_display_present, NULL); + dev->ctrl_tx_hotplug = v4l2_ctrl_new_std(hdl_vid_out, + NULL, V4L2_CID_DV_TX_HOTPLUG, 0, hdmi_output_mask, + 0, hdmi_output_mask); + dev->ctrl_tx_rxsense = v4l2_ctrl_new_std(hdl_vid_out, + NULL, V4L2_CID_DV_TX_RXSENSE, 0, hdmi_output_mask, + 0, hdmi_output_mask); + dev->ctrl_tx_edid_present = v4l2_ctrl_new_std(hdl_vid_out, + NULL, V4L2_CID_DV_TX_EDID_PRESENT, 0, hdmi_output_mask, + 0, hdmi_output_mask); + } + if ((dev->has_vid_cap && dev->has_vid_out) || + (dev->has_vbi_cap && dev->has_vbi_out)) + v4l2_ctrl_new_custom(hdl_loop_cap, &vivid_ctrl_loop_video, NULL); + + if (dev->has_fb) + v4l2_ctrl_new_custom(hdl_fb, &vivid_ctrl_clear_fb, NULL); + + if (dev->has_radio_rx) { + v4l2_ctrl_new_custom(hdl_radio_rx, &vivid_ctrl_radio_hw_seek_mode, NULL); + v4l2_ctrl_new_custom(hdl_radio_rx, &vivid_ctrl_radio_hw_seek_prog_lim, NULL); + v4l2_ctrl_new_custom(hdl_radio_rx, &vivid_ctrl_radio_rx_rds_blockio, NULL); + v4l2_ctrl_new_custom(hdl_radio_rx, &vivid_ctrl_radio_rx_rds_rbds, NULL); + v4l2_ctrl_new_std(hdl_radio_rx, &vivid_radio_rx_ctrl_ops, + V4L2_CID_RDS_RECEPTION, 0, 1, 1, 1); + dev->radio_rx_rds_pty = v4l2_ctrl_new_std(hdl_radio_rx, + &vivid_radio_rx_ctrl_ops, + V4L2_CID_RDS_RX_PTY, 0, 31, 1, 0); + dev->radio_rx_rds_psname = v4l2_ctrl_new_std(hdl_radio_rx, + &vivid_radio_rx_ctrl_ops, + V4L2_CID_RDS_RX_PS_NAME, 0, 8, 8, 0); + dev->radio_rx_rds_radiotext = v4l2_ctrl_new_std(hdl_radio_rx, + &vivid_radio_rx_ctrl_ops, + V4L2_CID_RDS_RX_RADIO_TEXT, 0, 64, 64, 0); + dev->radio_rx_rds_ta = v4l2_ctrl_new_std(hdl_radio_rx, + &vivid_radio_rx_ctrl_ops, + V4L2_CID_RDS_RX_TRAFFIC_ANNOUNCEMENT, 0, 1, 1, 0); + dev->radio_rx_rds_tp = v4l2_ctrl_new_std(hdl_radio_rx, + &vivid_radio_rx_ctrl_ops, + V4L2_CID_RDS_RX_TRAFFIC_PROGRAM, 0, 1, 1, 0); + dev->radio_rx_rds_ms = v4l2_ctrl_new_std(hdl_radio_rx, + &vivid_radio_rx_ctrl_ops, + V4L2_CID_RDS_RX_MUSIC_SPEECH, 0, 1, 1, 1); + } + if (dev->has_radio_tx) { + v4l2_ctrl_new_custom(hdl_radio_tx, + &vivid_ctrl_radio_tx_rds_blockio, NULL); + dev->radio_tx_rds_pi = v4l2_ctrl_new_std(hdl_radio_tx, + &vivid_radio_tx_ctrl_ops, + V4L2_CID_RDS_TX_PI, 0, 0xffff, 1, 0x8088); + dev->radio_tx_rds_pty = v4l2_ctrl_new_std(hdl_radio_tx, + &vivid_radio_tx_ctrl_ops, + V4L2_CID_RDS_TX_PTY, 0, 31, 1, 3); + dev->radio_tx_rds_psname = v4l2_ctrl_new_std(hdl_radio_tx, + &vivid_radio_tx_ctrl_ops, + V4L2_CID_RDS_TX_PS_NAME, 0, 8, 8, 0); + if (dev->radio_tx_rds_psname) + v4l2_ctrl_s_ctrl_string(dev->radio_tx_rds_psname, "VIVID-TX"); + dev->radio_tx_rds_radiotext = v4l2_ctrl_new_std(hdl_radio_tx, + &vivid_radio_tx_ctrl_ops, + V4L2_CID_RDS_TX_RADIO_TEXT, 0, 64 * 2, 64, 0); + if (dev->radio_tx_rds_radiotext) + v4l2_ctrl_s_ctrl_string(dev->radio_tx_rds_radiotext, + "This is a VIVID default Radio Text template text, change at will"); + dev->radio_tx_rds_mono_stereo = v4l2_ctrl_new_std(hdl_radio_tx, + &vivid_radio_tx_ctrl_ops, + V4L2_CID_RDS_TX_MONO_STEREO, 0, 1, 1, 1); + dev->radio_tx_rds_art_head = v4l2_ctrl_new_std(hdl_radio_tx, + &vivid_radio_tx_ctrl_ops, + V4L2_CID_RDS_TX_ARTIFICIAL_HEAD, 0, 1, 1, 0); + dev->radio_tx_rds_compressed = v4l2_ctrl_new_std(hdl_radio_tx, + &vivid_radio_tx_ctrl_ops, + V4L2_CID_RDS_TX_COMPRESSED, 0, 1, 1, 0); + dev->radio_tx_rds_dyn_pty = v4l2_ctrl_new_std(hdl_radio_tx, + &vivid_radio_tx_ctrl_ops, + V4L2_CID_RDS_TX_DYNAMIC_PTY, 0, 1, 1, 0); + dev->radio_tx_rds_ta = v4l2_ctrl_new_std(hdl_radio_tx, + &vivid_radio_tx_ctrl_ops, + V4L2_CID_RDS_TX_TRAFFIC_ANNOUNCEMENT, 0, 1, 1, 0); + dev->radio_tx_rds_tp = v4l2_ctrl_new_std(hdl_radio_tx, + &vivid_radio_tx_ctrl_ops, + V4L2_CID_RDS_TX_TRAFFIC_PROGRAM, 0, 1, 1, 1); + dev->radio_tx_rds_ms = v4l2_ctrl_new_std(hdl_radio_tx, + &vivid_radio_tx_ctrl_ops, + V4L2_CID_RDS_TX_MUSIC_SPEECH, 0, 1, 1, 1); + } + if (dev->has_sdr_cap) { + v4l2_ctrl_new_custom(hdl_sdr_cap, + &vivid_ctrl_sdr_cap_fm_deviation, NULL); + } + if (dev->has_meta_cap) { + v4l2_ctrl_new_custom(hdl_meta_cap, + &vivid_ctrl_meta_has_pts, NULL); + v4l2_ctrl_new_custom(hdl_meta_cap, + &vivid_ctrl_meta_has_src_clk, NULL); + } + + if (hdl_user_gen->error) + return hdl_user_gen->error; + if (hdl_user_vid->error) + return hdl_user_vid->error; + if (hdl_user_aud->error) + return hdl_user_aud->error; + if (hdl_streaming->error) + return hdl_streaming->error; + if (hdl_sdr_cap->error) + return hdl_sdr_cap->error; + if (hdl_loop_cap->error) + return hdl_loop_cap->error; + + if (dev->autogain) + v4l2_ctrl_auto_cluster(2, &dev->autogain, 0, true); + + if (dev->has_vid_cap) { + v4l2_ctrl_add_handler(hdl_vid_cap, hdl_user_gen, NULL, false); + v4l2_ctrl_add_handler(hdl_vid_cap, hdl_user_vid, NULL, false); + v4l2_ctrl_add_handler(hdl_vid_cap, hdl_user_aud, NULL, false); + v4l2_ctrl_add_handler(hdl_vid_cap, hdl_streaming, NULL, false); + v4l2_ctrl_add_handler(hdl_vid_cap, hdl_sdtv_cap, NULL, false); + v4l2_ctrl_add_handler(hdl_vid_cap, hdl_loop_cap, NULL, false); + v4l2_ctrl_add_handler(hdl_vid_cap, hdl_fb, NULL, false); + if (hdl_vid_cap->error) + return hdl_vid_cap->error; + dev->vid_cap_dev.ctrl_handler = hdl_vid_cap; + } + if (dev->has_vid_out) { + v4l2_ctrl_add_handler(hdl_vid_out, hdl_user_gen, NULL, false); + v4l2_ctrl_add_handler(hdl_vid_out, hdl_user_aud, NULL, false); + v4l2_ctrl_add_handler(hdl_vid_out, hdl_streaming, NULL, false); + v4l2_ctrl_add_handler(hdl_vid_out, hdl_fb, NULL, false); + if (hdl_vid_out->error) + return hdl_vid_out->error; + dev->vid_out_dev.ctrl_handler = hdl_vid_out; + } + if (dev->has_vbi_cap) { + v4l2_ctrl_add_handler(hdl_vbi_cap, hdl_user_gen, NULL, false); + v4l2_ctrl_add_handler(hdl_vbi_cap, hdl_streaming, NULL, false); + v4l2_ctrl_add_handler(hdl_vbi_cap, hdl_sdtv_cap, NULL, false); + v4l2_ctrl_add_handler(hdl_vbi_cap, hdl_loop_cap, NULL, false); + if (hdl_vbi_cap->error) + return hdl_vbi_cap->error; + dev->vbi_cap_dev.ctrl_handler = hdl_vbi_cap; + } + if (dev->has_vbi_out) { + v4l2_ctrl_add_handler(hdl_vbi_out, hdl_user_gen, NULL, false); + v4l2_ctrl_add_handler(hdl_vbi_out, hdl_streaming, NULL, false); + if (hdl_vbi_out->error) + return hdl_vbi_out->error; + dev->vbi_out_dev.ctrl_handler = hdl_vbi_out; + } + if (dev->has_radio_rx) { + v4l2_ctrl_add_handler(hdl_radio_rx, hdl_user_gen, NULL, false); + v4l2_ctrl_add_handler(hdl_radio_rx, hdl_user_aud, NULL, false); + if (hdl_radio_rx->error) + return hdl_radio_rx->error; + dev->radio_rx_dev.ctrl_handler = hdl_radio_rx; + } + if (dev->has_radio_tx) { + v4l2_ctrl_add_handler(hdl_radio_tx, hdl_user_gen, NULL, false); + v4l2_ctrl_add_handler(hdl_radio_tx, hdl_user_aud, NULL, false); + if (hdl_radio_tx->error) + return hdl_radio_tx->error; + dev->radio_tx_dev.ctrl_handler = hdl_radio_tx; + } + if (dev->has_sdr_cap) { + v4l2_ctrl_add_handler(hdl_sdr_cap, hdl_user_gen, NULL, false); + v4l2_ctrl_add_handler(hdl_sdr_cap, hdl_streaming, NULL, false); + if (hdl_sdr_cap->error) + return hdl_sdr_cap->error; + dev->sdr_cap_dev.ctrl_handler = hdl_sdr_cap; + } + if (dev->has_meta_cap) { + v4l2_ctrl_add_handler(hdl_meta_cap, hdl_user_gen, NULL, false); + v4l2_ctrl_add_handler(hdl_meta_cap, hdl_streaming, NULL, false); + if (hdl_meta_cap->error) + return hdl_meta_cap->error; + dev->meta_cap_dev.ctrl_handler = hdl_meta_cap; + } + if (dev->has_meta_out) { + v4l2_ctrl_add_handler(hdl_meta_out, hdl_user_gen, NULL, false); + v4l2_ctrl_add_handler(hdl_meta_out, hdl_streaming, NULL, false); + if (hdl_meta_out->error) + return hdl_meta_out->error; + dev->meta_out_dev.ctrl_handler = hdl_meta_out; + } + if (dev->has_touch_cap) { + v4l2_ctrl_add_handler(hdl_tch_cap, hdl_user_gen, NULL, false); + v4l2_ctrl_add_handler(hdl_tch_cap, hdl_streaming, NULL, false); + if (hdl_tch_cap->error) + return hdl_tch_cap->error; + dev->touch_cap_dev.ctrl_handler = hdl_tch_cap; + } + return 0; +} + +void vivid_free_controls(struct vivid_dev *dev) +{ + v4l2_ctrl_handler_free(&dev->ctrl_hdl_vid_cap); + v4l2_ctrl_handler_free(&dev->ctrl_hdl_vid_out); + v4l2_ctrl_handler_free(&dev->ctrl_hdl_vbi_cap); + v4l2_ctrl_handler_free(&dev->ctrl_hdl_vbi_out); + v4l2_ctrl_handler_free(&dev->ctrl_hdl_radio_rx); + v4l2_ctrl_handler_free(&dev->ctrl_hdl_radio_tx); + v4l2_ctrl_handler_free(&dev->ctrl_hdl_sdr_cap); + v4l2_ctrl_handler_free(&dev->ctrl_hdl_user_gen); + v4l2_ctrl_handler_free(&dev->ctrl_hdl_user_vid); + v4l2_ctrl_handler_free(&dev->ctrl_hdl_user_aud); + v4l2_ctrl_handler_free(&dev->ctrl_hdl_streaming); + v4l2_ctrl_handler_free(&dev->ctrl_hdl_sdtv_cap); + v4l2_ctrl_handler_free(&dev->ctrl_hdl_loop_cap); + v4l2_ctrl_handler_free(&dev->ctrl_hdl_fb); + v4l2_ctrl_handler_free(&dev->ctrl_hdl_meta_cap); + v4l2_ctrl_handler_free(&dev->ctrl_hdl_meta_out); + v4l2_ctrl_handler_free(&dev->ctrl_hdl_touch_cap); +} diff --git a/drivers/media/test_drivers/vivid/vivid-ctrls.h b/drivers/media/test_drivers/vivid/vivid-ctrls.h new file mode 100644 index 000000000000..6fad5f5d0054 --- /dev/null +++ b/drivers/media/test_drivers/vivid/vivid-ctrls.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * vivid-ctrls.h - control support functions. + * + * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. + */ + +#ifndef _VIVID_CTRLS_H_ +#define _VIVID_CTRLS_H_ + +enum vivid_hw_seek_modes { + VIVID_HW_SEEK_BOUNDED, + VIVID_HW_SEEK_WRAP, + VIVID_HW_SEEK_BOTH, +}; + +int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap, + bool show_ccs_out, bool no_error_inj, + bool has_sdtv, bool has_hdmi); +void vivid_free_controls(struct vivid_dev *dev); + +#endif diff --git a/drivers/media/test_drivers/vivid/vivid-kthread-cap.c b/drivers/media/test_drivers/vivid/vivid-kthread-cap.c new file mode 100644 index 000000000000..01a9d671b947 --- /dev/null +++ b/drivers/media/test_drivers/vivid/vivid-kthread-cap.c @@ -0,0 +1,1007 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * vivid-kthread-cap.h - video/vbi capture thread support functions. + * + * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "vivid-core.h" +#include "vivid-vid-common.h" +#include "vivid-vid-cap.h" +#include "vivid-vid-out.h" +#include "vivid-radio-common.h" +#include "vivid-radio-rx.h" +#include "vivid-radio-tx.h" +#include "vivid-sdr-cap.h" +#include "vivid-vbi-cap.h" +#include "vivid-vbi-out.h" +#include "vivid-osd.h" +#include "vivid-ctrls.h" +#include "vivid-kthread-cap.h" +#include "vivid-meta-cap.h" + +static inline v4l2_std_id vivid_get_std_cap(const struct vivid_dev *dev) +{ + if (vivid_is_sdtv_cap(dev)) + return dev->std_cap[dev->input]; + return 0; +} + +static void copy_pix(struct vivid_dev *dev, int win_y, int win_x, + u16 *cap, const u16 *osd) +{ + u16 out; + int left = dev->overlay_out_left; + int top = dev->overlay_out_top; + int fb_x = win_x + left; + int fb_y = win_y + top; + int i; + + out = *cap; + *cap = *osd; + if (dev->bitmap_out) { + const u8 *p = dev->bitmap_out; + unsigned stride = (dev->compose_out.width + 7) / 8; + + win_x -= dev->compose_out.left; + win_y -= dev->compose_out.top; + if (!(p[stride * win_y + win_x / 8] & (1 << (win_x & 7)))) + return; + } + + for (i = 0; i < dev->clipcount_out; i++) { + struct v4l2_rect *r = &dev->clips_out[i].c; + + if (fb_y >= r->top && fb_y < r->top + r->height && + fb_x >= r->left && fb_x < r->left + r->width) + return; + } + if ((dev->fbuf_out_flags & V4L2_FBUF_FLAG_CHROMAKEY) && + *osd != dev->chromakey_out) + return; + if ((dev->fbuf_out_flags & V4L2_FBUF_FLAG_SRC_CHROMAKEY) && + out == dev->chromakey_out) + return; + if (dev->fmt_cap->alpha_mask) { + if ((dev->fbuf_out_flags & V4L2_FBUF_FLAG_GLOBAL_ALPHA) && + dev->global_alpha_out) + return; + if ((dev->fbuf_out_flags & V4L2_FBUF_FLAG_LOCAL_ALPHA) && + *cap & dev->fmt_cap->alpha_mask) + return; + if ((dev->fbuf_out_flags & V4L2_FBUF_FLAG_LOCAL_INV_ALPHA) && + !(*cap & dev->fmt_cap->alpha_mask)) + return; + } + *cap = out; +} + +static void blend_line(struct vivid_dev *dev, unsigned y_offset, unsigned x_offset, + u8 *vcapbuf, const u8 *vosdbuf, + unsigned width, unsigned pixsize) +{ + unsigned x; + + for (x = 0; x < width; x++, vcapbuf += pixsize, vosdbuf += pixsize) { + copy_pix(dev, y_offset, x_offset + x, + (u16 *)vcapbuf, (const u16 *)vosdbuf); + } +} + +static void scale_line(const u8 *src, u8 *dst, unsigned srcw, unsigned dstw, unsigned twopixsize) +{ + /* Coarse scaling with Bresenham */ + unsigned int_part; + unsigned fract_part; + unsigned src_x = 0; + unsigned error = 0; + unsigned x; + + /* + * We always combine two pixels to prevent color bleed in the packed + * yuv case. + */ + srcw /= 2; + dstw /= 2; + int_part = srcw / dstw; + fract_part = srcw % dstw; + for (x = 0; x < dstw; x++, dst += twopixsize) { + memcpy(dst, src + src_x * twopixsize, twopixsize); + src_x += int_part; + error += fract_part; + if (error >= dstw) { + error -= dstw; + src_x++; + } + } +} + +/* + * Precalculate the rectangles needed to perform video looping: + * + * The nominal pipeline is that the video output buffer is cropped by + * crop_out, scaled to compose_out, overlaid with the output overlay, + * cropped on the capture side by crop_cap and scaled again to the video + * capture buffer using compose_cap. + * + * To keep things efficient we calculate the intersection of compose_out + * and crop_cap (since that's the only part of the video that will + * actually end up in the capture buffer), determine which part of the + * video output buffer that is and which part of the video capture buffer + * so we can scale the video straight from the output buffer to the capture + * buffer without any intermediate steps. + * + * If we need to deal with an output overlay, then there is no choice and + * that intermediate step still has to be taken. For the output overlay + * support we calculate the intersection of the framebuffer and the overlay + * window (which may be partially or wholly outside of the framebuffer + * itself) and the intersection of that with loop_vid_copy (i.e. the part of + * the actual looped video that will be overlaid). The result is calculated + * both in framebuffer coordinates (loop_fb_copy) and compose_out coordinates + * (loop_vid_overlay). Finally calculate the part of the capture buffer that + * will receive that overlaid video. + */ +static void vivid_precalc_copy_rects(struct vivid_dev *dev) +{ + /* Framebuffer rectangle */ + struct v4l2_rect r_fb = { + 0, 0, dev->display_width, dev->display_height + }; + /* Overlay window rectangle in framebuffer coordinates */ + struct v4l2_rect r_overlay = { + dev->overlay_out_left, dev->overlay_out_top, + dev->compose_out.width, dev->compose_out.height + }; + + v4l2_rect_intersect(&dev->loop_vid_copy, &dev->crop_cap, &dev->compose_out); + + dev->loop_vid_out = dev->loop_vid_copy; + v4l2_rect_scale(&dev->loop_vid_out, &dev->compose_out, &dev->crop_out); + dev->loop_vid_out.left += dev->crop_out.left; + dev->loop_vid_out.top += dev->crop_out.top; + + dev->loop_vid_cap = dev->loop_vid_copy; + v4l2_rect_scale(&dev->loop_vid_cap, &dev->crop_cap, &dev->compose_cap); + + dprintk(dev, 1, + "loop_vid_copy: %dx%d@%dx%d loop_vid_out: %dx%d@%dx%d loop_vid_cap: %dx%d@%dx%d\n", + dev->loop_vid_copy.width, dev->loop_vid_copy.height, + dev->loop_vid_copy.left, dev->loop_vid_copy.top, + dev->loop_vid_out.width, dev->loop_vid_out.height, + dev->loop_vid_out.left, dev->loop_vid_out.top, + dev->loop_vid_cap.width, dev->loop_vid_cap.height, + dev->loop_vid_cap.left, dev->loop_vid_cap.top); + + v4l2_rect_intersect(&r_overlay, &r_fb, &r_overlay); + + /* shift r_overlay to the same origin as compose_out */ + r_overlay.left += dev->compose_out.left - dev->overlay_out_left; + r_overlay.top += dev->compose_out.top - dev->overlay_out_top; + + v4l2_rect_intersect(&dev->loop_vid_overlay, &r_overlay, &dev->loop_vid_copy); + dev->loop_fb_copy = dev->loop_vid_overlay; + + /* shift dev->loop_fb_copy back again to the fb origin */ + dev->loop_fb_copy.left -= dev->compose_out.left - dev->overlay_out_left; + dev->loop_fb_copy.top -= dev->compose_out.top - dev->overlay_out_top; + + dev->loop_vid_overlay_cap = dev->loop_vid_overlay; + v4l2_rect_scale(&dev->loop_vid_overlay_cap, &dev->crop_cap, &dev->compose_cap); + + dprintk(dev, 1, + "loop_fb_copy: %dx%d@%dx%d loop_vid_overlay: %dx%d@%dx%d loop_vid_overlay_cap: %dx%d@%dx%d\n", + dev->loop_fb_copy.width, dev->loop_fb_copy.height, + dev->loop_fb_copy.left, dev->loop_fb_copy.top, + dev->loop_vid_overlay.width, dev->loop_vid_overlay.height, + dev->loop_vid_overlay.left, dev->loop_vid_overlay.top, + dev->loop_vid_overlay_cap.width, dev->loop_vid_overlay_cap.height, + dev->loop_vid_overlay_cap.left, dev->loop_vid_overlay_cap.top); +} + +static void *plane_vaddr(struct tpg_data *tpg, struct vivid_buffer *buf, + unsigned p, unsigned bpl[TPG_MAX_PLANES], unsigned h) +{ + unsigned i; + void *vbuf; + + if (p == 0 || tpg_g_buffers(tpg) > 1) + return vb2_plane_vaddr(&buf->vb.vb2_buf, p); + vbuf = vb2_plane_vaddr(&buf->vb.vb2_buf, 0); + for (i = 0; i < p; i++) + vbuf += bpl[i] * h / tpg->vdownsampling[i]; + return vbuf; +} + +static noinline_for_stack int vivid_copy_buffer(struct vivid_dev *dev, unsigned p, + u8 *vcapbuf, struct vivid_buffer *vid_cap_buf) +{ + bool blank = dev->must_blank[vid_cap_buf->vb.vb2_buf.index]; + struct tpg_data *tpg = &dev->tpg; + struct vivid_buffer *vid_out_buf = NULL; + unsigned vdiv = dev->fmt_out->vdownsampling[p]; + unsigned twopixsize = tpg_g_twopixelsize(tpg, p); + unsigned img_width = tpg_hdiv(tpg, p, dev->compose_cap.width); + unsigned img_height = dev->compose_cap.height; + unsigned stride_cap = tpg->bytesperline[p]; + unsigned stride_out = dev->bytesperline_out[p]; + unsigned stride_osd = dev->display_byte_stride; + unsigned hmax = (img_height * tpg->perc_fill) / 100; + u8 *voutbuf; + u8 *vosdbuf = NULL; + unsigned y; + bool blend = dev->bitmap_out || dev->clipcount_out || dev->fbuf_out_flags; + /* Coarse scaling with Bresenham */ + unsigned vid_out_int_part; + unsigned vid_out_fract_part; + unsigned vid_out_y = 0; + unsigned vid_out_error = 0; + unsigned vid_overlay_int_part = 0; + unsigned vid_overlay_fract_part = 0; + unsigned vid_overlay_y = 0; + unsigned vid_overlay_error = 0; + unsigned vid_cap_left = tpg_hdiv(tpg, p, dev->loop_vid_cap.left); + unsigned vid_cap_right; + bool quick; + + vid_out_int_part = dev->loop_vid_out.height / dev->loop_vid_cap.height; + vid_out_fract_part = dev->loop_vid_out.height % dev->loop_vid_cap.height; + + if (!list_empty(&dev->vid_out_active)) + vid_out_buf = list_entry(dev->vid_out_active.next, + struct vivid_buffer, list); + if (vid_out_buf == NULL) + return -ENODATA; + + vid_cap_buf->vb.field = vid_out_buf->vb.field; + + voutbuf = plane_vaddr(tpg, vid_out_buf, p, + dev->bytesperline_out, dev->fmt_out_rect.height); + if (p < dev->fmt_out->buffers) + voutbuf += vid_out_buf->vb.vb2_buf.planes[p].data_offset; + voutbuf += tpg_hdiv(tpg, p, dev->loop_vid_out.left) + + (dev->loop_vid_out.top / vdiv) * stride_out; + vcapbuf += tpg_hdiv(tpg, p, dev->compose_cap.left) + + (dev->compose_cap.top / vdiv) * stride_cap; + + if (dev->loop_vid_copy.width == 0 || dev->loop_vid_copy.height == 0) { + /* + * If there is nothing to copy, then just fill the capture window + * with black. + */ + for (y = 0; y < hmax / vdiv; y++, vcapbuf += stride_cap) + memcpy(vcapbuf, tpg->black_line[p], img_width); + return 0; + } + + if (dev->overlay_out_enabled && + dev->loop_vid_overlay.width && dev->loop_vid_overlay.height) { + vosdbuf = dev->video_vbase; + vosdbuf += (dev->loop_fb_copy.left * twopixsize) / 2 + + dev->loop_fb_copy.top * stride_osd; + vid_overlay_int_part = dev->loop_vid_overlay.height / + dev->loop_vid_overlay_cap.height; + vid_overlay_fract_part = dev->loop_vid_overlay.height % + dev->loop_vid_overlay_cap.height; + } + + vid_cap_right = tpg_hdiv(tpg, p, dev->loop_vid_cap.left + dev->loop_vid_cap.width); + /* quick is true if no video scaling is needed */ + quick = dev->loop_vid_out.width == dev->loop_vid_cap.width; + + dev->cur_scaled_line = dev->loop_vid_out.height; + for (y = 0; y < hmax; y += vdiv, vcapbuf += stride_cap) { + /* osdline is true if this line requires overlay blending */ + bool osdline = vosdbuf && y >= dev->loop_vid_overlay_cap.top && + y < dev->loop_vid_overlay_cap.top + dev->loop_vid_overlay_cap.height; + + /* + * If this line of the capture buffer doesn't get any video, then + * just fill with black. + */ + if (y < dev->loop_vid_cap.top || + y >= dev->loop_vid_cap.top + dev->loop_vid_cap.height) { + memcpy(vcapbuf, tpg->black_line[p], img_width); + continue; + } + + /* fill the left border with black */ + if (dev->loop_vid_cap.left) + memcpy(vcapbuf, tpg->black_line[p], vid_cap_left); + + /* fill the right border with black */ + if (vid_cap_right < img_width) + memcpy(vcapbuf + vid_cap_right, tpg->black_line[p], + img_width - vid_cap_right); + + if (quick && !osdline) { + memcpy(vcapbuf + vid_cap_left, + voutbuf + vid_out_y * stride_out, + tpg_hdiv(tpg, p, dev->loop_vid_cap.width)); + goto update_vid_out_y; + } + if (dev->cur_scaled_line == vid_out_y) { + memcpy(vcapbuf + vid_cap_left, dev->scaled_line, + tpg_hdiv(tpg, p, dev->loop_vid_cap.width)); + goto update_vid_out_y; + } + if (!osdline) { + scale_line(voutbuf + vid_out_y * stride_out, dev->scaled_line, + tpg_hdiv(tpg, p, dev->loop_vid_out.width), + tpg_hdiv(tpg, p, dev->loop_vid_cap.width), + tpg_g_twopixelsize(tpg, p)); + } else { + /* + * Offset in bytes within loop_vid_copy to the start of the + * loop_vid_overlay rectangle. + */ + unsigned offset = + ((dev->loop_vid_overlay.left - dev->loop_vid_copy.left) * + twopixsize) / 2; + u8 *osd = vosdbuf + vid_overlay_y * stride_osd; + + scale_line(voutbuf + vid_out_y * stride_out, dev->blended_line, + dev->loop_vid_out.width, dev->loop_vid_copy.width, + tpg_g_twopixelsize(tpg, p)); + if (blend) + blend_line(dev, vid_overlay_y + dev->loop_vid_overlay.top, + dev->loop_vid_overlay.left, + dev->blended_line + offset, osd, + dev->loop_vid_overlay.width, twopixsize / 2); + else + memcpy(dev->blended_line + offset, + osd, (dev->loop_vid_overlay.width * twopixsize) / 2); + scale_line(dev->blended_line, dev->scaled_line, + dev->loop_vid_copy.width, dev->loop_vid_cap.width, + tpg_g_twopixelsize(tpg, p)); + } + dev->cur_scaled_line = vid_out_y; + memcpy(vcapbuf + vid_cap_left, dev->scaled_line, + tpg_hdiv(tpg, p, dev->loop_vid_cap.width)); + +update_vid_out_y: + if (osdline) { + vid_overlay_y += vid_overlay_int_part; + vid_overlay_error += vid_overlay_fract_part; + if (vid_overlay_error >= dev->loop_vid_overlay_cap.height) { + vid_overlay_error -= dev->loop_vid_overlay_cap.height; + vid_overlay_y++; + } + } + vid_out_y += vid_out_int_part; + vid_out_error += vid_out_fract_part; + if (vid_out_error >= dev->loop_vid_cap.height / vdiv) { + vid_out_error -= dev->loop_vid_cap.height / vdiv; + vid_out_y++; + } + } + + if (!blank) + return 0; + for (; y < img_height; y += vdiv, vcapbuf += stride_cap) + memcpy(vcapbuf, tpg->contrast_line[p], img_width); + return 0; +} + +static void vivid_fillbuff(struct vivid_dev *dev, struct vivid_buffer *buf) +{ + struct tpg_data *tpg = &dev->tpg; + unsigned factor = V4L2_FIELD_HAS_T_OR_B(dev->field_cap) ? 2 : 1; + unsigned line_height = 16 / factor; + bool is_tv = vivid_is_sdtv_cap(dev); + bool is_60hz = is_tv && (dev->std_cap[dev->input] & V4L2_STD_525_60); + unsigned p; + int line = 1; + u8 *basep[TPG_MAX_PLANES][2]; + unsigned ms; + char str[100]; + s32 gain; + bool is_loop = false; + + if (dev->loop_video && dev->can_loop_video && + ((vivid_is_svid_cap(dev) && + !VIVID_INVALID_SIGNAL(dev->std_signal_mode[dev->input])) || + (vivid_is_hdmi_cap(dev) && + !VIVID_INVALID_SIGNAL(dev->dv_timings_signal_mode[dev->input])))) + is_loop = true; + + buf->vb.sequence = dev->vid_cap_seq_count; + if (dev->field_cap == V4L2_FIELD_ALTERNATE) { + /* + * 60 Hz standards start with the bottom field, 50 Hz standards + * with the top field. So if the 0-based seq_count is even, + * then the field is TOP for 50 Hz and BOTTOM for 60 Hz + * standards. + */ + buf->vb.field = ((dev->vid_cap_seq_count & 1) ^ is_60hz) ? + V4L2_FIELD_BOTTOM : V4L2_FIELD_TOP; + /* + * The sequence counter counts frames, not fields. So divide + * by two. + */ + buf->vb.sequence /= 2; + } else { + buf->vb.field = dev->field_cap; + } + tpg_s_field(tpg, buf->vb.field, + dev->field_cap == V4L2_FIELD_ALTERNATE); + tpg_s_perc_fill_blank(tpg, dev->must_blank[buf->vb.vb2_buf.index]); + + vivid_precalc_copy_rects(dev); + + for (p = 0; p < tpg_g_planes(tpg); p++) { + void *vbuf = plane_vaddr(tpg, buf, p, + tpg->bytesperline, tpg->buf_height); + + /* + * The first plane of a multiplanar format has a non-zero + * data_offset. This helps testing whether the application + * correctly supports non-zero data offsets. + */ + if (p < tpg_g_buffers(tpg) && dev->fmt_cap->data_offset[p]) { + memset(vbuf, dev->fmt_cap->data_offset[p] & 0xff, + dev->fmt_cap->data_offset[p]); + vbuf += dev->fmt_cap->data_offset[p]; + } + tpg_calc_text_basep(tpg, basep, p, vbuf); + if (!is_loop || vivid_copy_buffer(dev, p, vbuf, buf)) + tpg_fill_plane_buffer(tpg, vivid_get_std_cap(dev), + p, vbuf); + } + dev->must_blank[buf->vb.vb2_buf.index] = false; + + /* Updates stream time, only update at the start of a new frame. */ + if (dev->field_cap != V4L2_FIELD_ALTERNATE || + (dev->vid_cap_seq_count & 1) == 0) + dev->ms_vid_cap = + jiffies_to_msecs(jiffies - dev->jiffies_vid_cap); + + ms = dev->ms_vid_cap; + if (dev->osd_mode <= 1) { + snprintf(str, sizeof(str), " %02d:%02d:%02d:%03d %u%s", + (ms / (60 * 60 * 1000)) % 24, + (ms / (60 * 1000)) % 60, + (ms / 1000) % 60, + ms % 1000, + buf->vb.sequence, + (dev->field_cap == V4L2_FIELD_ALTERNATE) ? + (buf->vb.field == V4L2_FIELD_TOP ? + " top" : " bottom") : ""); + tpg_gen_text(tpg, basep, line++ * line_height, 16, str); + } + if (dev->osd_mode == 0) { + snprintf(str, sizeof(str), " %dx%d, input %d ", + dev->src_rect.width, dev->src_rect.height, dev->input); + tpg_gen_text(tpg, basep, line++ * line_height, 16, str); + + gain = v4l2_ctrl_g_ctrl(dev->gain); + mutex_lock(dev->ctrl_hdl_user_vid.lock); + snprintf(str, sizeof(str), + " brightness %3d, contrast %3d, saturation %3d, hue %d ", + dev->brightness->cur.val, + dev->contrast->cur.val, + dev->saturation->cur.val, + dev->hue->cur.val); + tpg_gen_text(tpg, basep, line++ * line_height, 16, str); + snprintf(str, sizeof(str), + " autogain %d, gain %3d, alpha 0x%02x ", + dev->autogain->cur.val, gain, dev->alpha->cur.val); + mutex_unlock(dev->ctrl_hdl_user_vid.lock); + tpg_gen_text(tpg, basep, line++ * line_height, 16, str); + mutex_lock(dev->ctrl_hdl_user_aud.lock); + snprintf(str, sizeof(str), + " volume %3d, mute %d ", + dev->volume->cur.val, dev->mute->cur.val); + mutex_unlock(dev->ctrl_hdl_user_aud.lock); + tpg_gen_text(tpg, basep, line++ * line_height, 16, str); + mutex_lock(dev->ctrl_hdl_user_gen.lock); + snprintf(str, sizeof(str), " int32 %d, int64 %lld, bitmask %08x ", + dev->int32->cur.val, + *dev->int64->p_cur.p_s64, + dev->bitmask->cur.val); + tpg_gen_text(tpg, basep, line++ * line_height, 16, str); + snprintf(str, sizeof(str), " boolean %d, menu %s, string \"%s\" ", + dev->boolean->cur.val, + dev->menu->qmenu[dev->menu->cur.val], + dev->string->p_cur.p_char); + tpg_gen_text(tpg, basep, line++ * line_height, 16, str); + snprintf(str, sizeof(str), " integer_menu %lld, value %d ", + dev->int_menu->qmenu_int[dev->int_menu->cur.val], + dev->int_menu->cur.val); + mutex_unlock(dev->ctrl_hdl_user_gen.lock); + tpg_gen_text(tpg, basep, line++ * line_height, 16, str); + if (dev->button_pressed) { + dev->button_pressed--; + snprintf(str, sizeof(str), " button pressed!"); + tpg_gen_text(tpg, basep, line++ * line_height, 16, str); + } + if (dev->osd[0]) { + if (vivid_is_hdmi_cap(dev)) { + snprintf(str, sizeof(str), + " OSD \"%s\"", dev->osd); + tpg_gen_text(tpg, basep, line++ * line_height, + 16, str); + } + if (dev->osd_jiffies && + time_is_before_jiffies(dev->osd_jiffies + 5 * HZ)) { + dev->osd[0] = 0; + dev->osd_jiffies = 0; + } + } + } +} + +/* + * Return true if this pixel coordinate is a valid video pixel. + */ +static bool valid_pix(struct vivid_dev *dev, int win_y, int win_x, int fb_y, int fb_x) +{ + int i; + + if (dev->bitmap_cap) { + /* + * Only if the corresponding bit in the bitmap is set can + * the video pixel be shown. Coordinates are relative to + * the overlay window set by VIDIOC_S_FMT. + */ + const u8 *p = dev->bitmap_cap; + unsigned stride = (dev->compose_cap.width + 7) / 8; + + if (!(p[stride * win_y + win_x / 8] & (1 << (win_x & 7)))) + return false; + } + + for (i = 0; i < dev->clipcount_cap; i++) { + /* + * Only if the framebuffer coordinate is not in any of the + * clip rectangles will be video pixel be shown. + */ + struct v4l2_rect *r = &dev->clips_cap[i].c; + + if (fb_y >= r->top && fb_y < r->top + r->height && + fb_x >= r->left && fb_x < r->left + r->width) + return false; + } + return true; +} + +/* + * Draw the image into the overlay buffer. + * Note that the combination of overlay and multiplanar is not supported. + */ +static void vivid_overlay(struct vivid_dev *dev, struct vivid_buffer *buf) +{ + struct tpg_data *tpg = &dev->tpg; + unsigned pixsize = tpg_g_twopixelsize(tpg, 0) / 2; + void *vbase = dev->fb_vbase_cap; + void *vbuf = vb2_plane_vaddr(&buf->vb.vb2_buf, 0); + unsigned img_width = dev->compose_cap.width; + unsigned img_height = dev->compose_cap.height; + unsigned stride = tpg->bytesperline[0]; + /* if quick is true, then valid_pix() doesn't have to be called */ + bool quick = dev->bitmap_cap == NULL && dev->clipcount_cap == 0; + int x, y, w, out_x = 0; + + /* + * Overlay support is only supported for formats that have a twopixelsize + * that's >= 2. Warn and bail out if that's not the case. + */ + if (WARN_ON(pixsize == 0)) + return; + if ((dev->overlay_cap_field == V4L2_FIELD_TOP || + dev->overlay_cap_field == V4L2_FIELD_BOTTOM) && + dev->overlay_cap_field != buf->vb.field) + return; + + vbuf += dev->compose_cap.left * pixsize + dev->compose_cap.top * stride; + x = dev->overlay_cap_left; + w = img_width; + if (x < 0) { + out_x = -x; + w = w - out_x; + x = 0; + } else { + w = dev->fb_cap.fmt.width - x; + if (w > img_width) + w = img_width; + } + if (w <= 0) + return; + if (dev->overlay_cap_top >= 0) + vbase += dev->overlay_cap_top * dev->fb_cap.fmt.bytesperline; + for (y = dev->overlay_cap_top; + y < dev->overlay_cap_top + (int)img_height; + y++, vbuf += stride) { + int px; + + if (y < 0 || y > dev->fb_cap.fmt.height) + continue; + if (quick) { + memcpy(vbase + x * pixsize, + vbuf + out_x * pixsize, w * pixsize); + vbase += dev->fb_cap.fmt.bytesperline; + continue; + } + for (px = 0; px < w; px++) { + if (!valid_pix(dev, y - dev->overlay_cap_top, + px + out_x, y, px + x)) + continue; + memcpy(vbase + (px + x) * pixsize, + vbuf + (px + out_x) * pixsize, + pixsize); + } + vbase += dev->fb_cap.fmt.bytesperline; + } +} + +static void vivid_cap_update_frame_period(struct vivid_dev *dev) +{ + u64 f_period; + + f_period = (u64)dev->timeperframe_vid_cap.numerator * 1000000000; + if (WARN_ON(dev->timeperframe_vid_cap.denominator == 0)) + dev->timeperframe_vid_cap.denominator = 1; + do_div(f_period, dev->timeperframe_vid_cap.denominator); + if (dev->field_cap == V4L2_FIELD_ALTERNATE) + f_period >>= 1; + /* + * If "End of Frame", then offset the exposure time by 0.9 + * of the frame period. + */ + dev->cap_frame_eof_offset = f_period * 9; + do_div(dev->cap_frame_eof_offset, 10); + dev->cap_frame_period = f_period; +} + +static noinline_for_stack void vivid_thread_vid_cap_tick(struct vivid_dev *dev, + int dropped_bufs) +{ + struct vivid_buffer *vid_cap_buf = NULL; + struct vivid_buffer *vbi_cap_buf = NULL; + struct vivid_buffer *meta_cap_buf = NULL; + u64 f_time = 0; + + dprintk(dev, 1, "Video Capture Thread Tick\n"); + + while (dropped_bufs-- > 1) + tpg_update_mv_count(&dev->tpg, + dev->field_cap == V4L2_FIELD_NONE || + dev->field_cap == V4L2_FIELD_ALTERNATE); + + /* Drop a certain percentage of buffers. */ + if (dev->perc_dropped_buffers && + prandom_u32_max(100) < dev->perc_dropped_buffers) + goto update_mv; + + spin_lock(&dev->slock); + if (!list_empty(&dev->vid_cap_active)) { + vid_cap_buf = list_entry(dev->vid_cap_active.next, struct vivid_buffer, list); + list_del(&vid_cap_buf->list); + } + if (!list_empty(&dev->vbi_cap_active)) { + if (dev->field_cap != V4L2_FIELD_ALTERNATE || + (dev->vbi_cap_seq_count & 1)) { + vbi_cap_buf = list_entry(dev->vbi_cap_active.next, + struct vivid_buffer, list); + list_del(&vbi_cap_buf->list); + } + } + if (!list_empty(&dev->meta_cap_active)) { + meta_cap_buf = list_entry(dev->meta_cap_active.next, + struct vivid_buffer, list); + list_del(&meta_cap_buf->list); + } + + spin_unlock(&dev->slock); + + if (!vid_cap_buf && !vbi_cap_buf && !meta_cap_buf) + goto update_mv; + + f_time = dev->cap_frame_period * dev->vid_cap_seq_count + + dev->cap_stream_start + dev->time_wrap_offset; + + if (vid_cap_buf) { + v4l2_ctrl_request_setup(vid_cap_buf->vb.vb2_buf.req_obj.req, + &dev->ctrl_hdl_vid_cap); + /* Fill buffer */ + vivid_fillbuff(dev, vid_cap_buf); + dprintk(dev, 1, "filled buffer %d\n", + vid_cap_buf->vb.vb2_buf.index); + + /* Handle overlay */ + if (dev->overlay_cap_owner && dev->fb_cap.base && + dev->fb_cap.fmt.pixelformat == dev->fmt_cap->fourcc) + vivid_overlay(dev, vid_cap_buf); + + v4l2_ctrl_request_complete(vid_cap_buf->vb.vb2_buf.req_obj.req, + &dev->ctrl_hdl_vid_cap); + vb2_buffer_done(&vid_cap_buf->vb.vb2_buf, dev->dqbuf_error ? + VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE); + dprintk(dev, 2, "vid_cap buffer %d done\n", + vid_cap_buf->vb.vb2_buf.index); + + vid_cap_buf->vb.vb2_buf.timestamp = f_time; + if (!dev->tstamp_src_is_soe) + vid_cap_buf->vb.vb2_buf.timestamp += dev->cap_frame_eof_offset; + } + + if (vbi_cap_buf) { + u64 vbi_period; + + v4l2_ctrl_request_setup(vbi_cap_buf->vb.vb2_buf.req_obj.req, + &dev->ctrl_hdl_vbi_cap); + if (dev->stream_sliced_vbi_cap) + vivid_sliced_vbi_cap_process(dev, vbi_cap_buf); + else + vivid_raw_vbi_cap_process(dev, vbi_cap_buf); + v4l2_ctrl_request_complete(vbi_cap_buf->vb.vb2_buf.req_obj.req, + &dev->ctrl_hdl_vbi_cap); + vb2_buffer_done(&vbi_cap_buf->vb.vb2_buf, dev->dqbuf_error ? + VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE); + dprintk(dev, 2, "vbi_cap %d done\n", + vbi_cap_buf->vb.vb2_buf.index); + + /* If capturing a VBI, offset by 0.05 */ + vbi_period = dev->cap_frame_period * 5; + do_div(vbi_period, 100); + vbi_cap_buf->vb.vb2_buf.timestamp = f_time + dev->cap_frame_eof_offset + vbi_period; + } + + if (meta_cap_buf) { + v4l2_ctrl_request_setup(meta_cap_buf->vb.vb2_buf.req_obj.req, + &dev->ctrl_hdl_meta_cap); + vivid_meta_cap_fillbuff(dev, meta_cap_buf, f_time); + v4l2_ctrl_request_complete(meta_cap_buf->vb.vb2_buf.req_obj.req, + &dev->ctrl_hdl_meta_cap); + vb2_buffer_done(&meta_cap_buf->vb.vb2_buf, dev->dqbuf_error ? + VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE); + dprintk(dev, 2, "meta_cap %d done\n", + meta_cap_buf->vb.vb2_buf.index); + meta_cap_buf->vb.vb2_buf.timestamp = f_time + dev->cap_frame_eof_offset; + } + + dev->dqbuf_error = false; + +update_mv: + /* Update the test pattern movement counters */ + tpg_update_mv_count(&dev->tpg, dev->field_cap == V4L2_FIELD_NONE || + dev->field_cap == V4L2_FIELD_ALTERNATE); +} + +static int vivid_thread_vid_cap(void *data) +{ + struct vivid_dev *dev = data; + u64 numerators_since_start; + u64 buffers_since_start; + u64 next_jiffies_since_start; + unsigned long jiffies_since_start; + unsigned long cur_jiffies; + unsigned wait_jiffies; + unsigned numerator; + unsigned denominator; + int dropped_bufs; + + dprintk(dev, 1, "Video Capture Thread Start\n"); + + set_freezable(); + + /* Resets frame counters */ + dev->cap_seq_offset = 0; + dev->cap_seq_count = 0; + dev->cap_seq_resync = false; + dev->jiffies_vid_cap = jiffies; + dev->cap_stream_start = ktime_get_ns(); + vivid_cap_update_frame_period(dev); + + for (;;) { + try_to_freeze(); + if (kthread_should_stop()) + break; + + if (!mutex_trylock(&dev->mutex)) { + schedule_timeout_uninterruptible(1); + continue; + } + + cur_jiffies = jiffies; + if (dev->cap_seq_resync) { + dev->jiffies_vid_cap = cur_jiffies; + dev->cap_seq_offset = dev->cap_seq_count + 1; + dev->cap_seq_count = 0; + dev->cap_stream_start += dev->cap_frame_period * + dev->cap_seq_offset; + vivid_cap_update_frame_period(dev); + dev->cap_seq_resync = false; + } + numerator = dev->timeperframe_vid_cap.numerator; + denominator = dev->timeperframe_vid_cap.denominator; + + if (dev->field_cap == V4L2_FIELD_ALTERNATE) + denominator *= 2; + + /* Calculate the number of jiffies since we started streaming */ + jiffies_since_start = cur_jiffies - dev->jiffies_vid_cap; + /* Get the number of buffers streamed since the start */ + buffers_since_start = (u64)jiffies_since_start * denominator + + (HZ * numerator) / 2; + do_div(buffers_since_start, HZ * numerator); + + /* + * After more than 0xf0000000 (rounded down to a multiple of + * 'jiffies-per-day' to ease jiffies_to_msecs calculation) + * jiffies have passed since we started streaming reset the + * counters and keep track of the sequence offset. + */ + if (jiffies_since_start > JIFFIES_RESYNC) { + dev->jiffies_vid_cap = cur_jiffies; + dev->cap_seq_offset = buffers_since_start; + buffers_since_start = 0; + } + dropped_bufs = buffers_since_start + dev->cap_seq_offset - dev->cap_seq_count; + dev->cap_seq_count = buffers_since_start + dev->cap_seq_offset; + dev->vid_cap_seq_count = dev->cap_seq_count - dev->vid_cap_seq_start; + dev->vbi_cap_seq_count = dev->cap_seq_count - dev->vbi_cap_seq_start; + dev->meta_cap_seq_count = dev->cap_seq_count - dev->meta_cap_seq_start; + + vivid_thread_vid_cap_tick(dev, dropped_bufs); + + /* + * Calculate the number of 'numerators' streamed since we started, + * including the current buffer. + */ + numerators_since_start = ++buffers_since_start * numerator; + + /* And the number of jiffies since we started */ + jiffies_since_start = jiffies - dev->jiffies_vid_cap; + + mutex_unlock(&dev->mutex); + + /* + * Calculate when that next buffer is supposed to start + * in jiffies since we started streaming. + */ + next_jiffies_since_start = numerators_since_start * HZ + + denominator / 2; + do_div(next_jiffies_since_start, denominator); + /* If it is in the past, then just schedule asap */ + if (next_jiffies_since_start < jiffies_since_start) + next_jiffies_since_start = jiffies_since_start; + + wait_jiffies = next_jiffies_since_start - jiffies_since_start; + schedule_timeout_interruptible(wait_jiffies ? wait_jiffies : 1); + } + dprintk(dev, 1, "Video Capture Thread End\n"); + return 0; +} + +static void vivid_grab_controls(struct vivid_dev *dev, bool grab) +{ + v4l2_ctrl_grab(dev->ctrl_has_crop_cap, grab); + v4l2_ctrl_grab(dev->ctrl_has_compose_cap, grab); + v4l2_ctrl_grab(dev->ctrl_has_scaler_cap, grab); +} + +int vivid_start_generating_vid_cap(struct vivid_dev *dev, bool *pstreaming) +{ + dprintk(dev, 1, "%s\n", __func__); + + if (dev->kthread_vid_cap) { + u32 seq_count = dev->cap_seq_count + dev->seq_wrap * 128; + + if (pstreaming == &dev->vid_cap_streaming) + dev->vid_cap_seq_start = seq_count; + else if (pstreaming == &dev->vbi_cap_streaming) + dev->vbi_cap_seq_start = seq_count; + else + dev->meta_cap_seq_start = seq_count; + *pstreaming = true; + return 0; + } + + /* Resets frame counters */ + tpg_init_mv_count(&dev->tpg); + + dev->vid_cap_seq_start = dev->seq_wrap * 128; + dev->vbi_cap_seq_start = dev->seq_wrap * 128; + dev->meta_cap_seq_start = dev->seq_wrap * 128; + + dev->kthread_vid_cap = kthread_run(vivid_thread_vid_cap, dev, + "%s-vid-cap", dev->v4l2_dev.name); + + if (IS_ERR(dev->kthread_vid_cap)) { + int err = PTR_ERR(dev->kthread_vid_cap); + + dev->kthread_vid_cap = NULL; + v4l2_err(&dev->v4l2_dev, "kernel_thread() failed\n"); + return err; + } + *pstreaming = true; + vivid_grab_controls(dev, true); + + dprintk(dev, 1, "returning from %s\n", __func__); + return 0; +} + +void vivid_stop_generating_vid_cap(struct vivid_dev *dev, bool *pstreaming) +{ + dprintk(dev, 1, "%s\n", __func__); + + if (dev->kthread_vid_cap == NULL) + return; + + *pstreaming = false; + if (pstreaming == &dev->vid_cap_streaming) { + /* Release all active buffers */ + while (!list_empty(&dev->vid_cap_active)) { + struct vivid_buffer *buf; + + buf = list_entry(dev->vid_cap_active.next, + struct vivid_buffer, list); + list_del(&buf->list); + v4l2_ctrl_request_complete(buf->vb.vb2_buf.req_obj.req, + &dev->ctrl_hdl_vid_cap); + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); + dprintk(dev, 2, "vid_cap buffer %d done\n", + buf->vb.vb2_buf.index); + } + } + + if (pstreaming == &dev->vbi_cap_streaming) { + while (!list_empty(&dev->vbi_cap_active)) { + struct vivid_buffer *buf; + + buf = list_entry(dev->vbi_cap_active.next, + struct vivid_buffer, list); + list_del(&buf->list); + v4l2_ctrl_request_complete(buf->vb.vb2_buf.req_obj.req, + &dev->ctrl_hdl_vbi_cap); + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); + dprintk(dev, 2, "vbi_cap buffer %d done\n", + buf->vb.vb2_buf.index); + } + } + + if (pstreaming == &dev->meta_cap_streaming) { + while (!list_empty(&dev->meta_cap_active)) { + struct vivid_buffer *buf; + + buf = list_entry(dev->meta_cap_active.next, + struct vivid_buffer, list); + list_del(&buf->list); + v4l2_ctrl_request_complete(buf->vb.vb2_buf.req_obj.req, + &dev->ctrl_hdl_meta_cap); + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); + dprintk(dev, 2, "meta_cap buffer %d done\n", + buf->vb.vb2_buf.index); + } + } + + if (dev->vid_cap_streaming || dev->vbi_cap_streaming || + dev->meta_cap_streaming) + return; + + /* shutdown control thread */ + vivid_grab_controls(dev, false); + kthread_stop(dev->kthread_vid_cap); + dev->kthread_vid_cap = NULL; +} diff --git a/drivers/media/test_drivers/vivid/vivid-kthread-cap.h b/drivers/media/test_drivers/vivid/vivid-kthread-cap.h new file mode 100644 index 000000000000..0f43015306d6 --- /dev/null +++ b/drivers/media/test_drivers/vivid/vivid-kthread-cap.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * vivid-kthread-cap.h - video/vbi capture thread support functions. + * + * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. + */ + +#ifndef _VIVID_KTHREAD_CAP_H_ +#define _VIVID_KTHREAD_CAP_H_ + +int vivid_start_generating_vid_cap(struct vivid_dev *dev, bool *pstreaming); +void vivid_stop_generating_vid_cap(struct vivid_dev *dev, bool *pstreaming); + +#endif diff --git a/drivers/media/test_drivers/vivid/vivid-kthread-out.c b/drivers/media/test_drivers/vivid/vivid-kthread-out.c new file mode 100644 index 000000000000..6780687978f9 --- /dev/null +++ b/drivers/media/test_drivers/vivid/vivid-kthread-out.c @@ -0,0 +1,353 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * vivid-kthread-out.h - video/vbi output thread support functions. + * + * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "vivid-core.h" +#include "vivid-vid-common.h" +#include "vivid-vid-cap.h" +#include "vivid-vid-out.h" +#include "vivid-radio-common.h" +#include "vivid-radio-rx.h" +#include "vivid-radio-tx.h" +#include "vivid-sdr-cap.h" +#include "vivid-vbi-cap.h" +#include "vivid-vbi-out.h" +#include "vivid-osd.h" +#include "vivid-ctrls.h" +#include "vivid-kthread-out.h" +#include "vivid-meta-out.h" + +static void vivid_thread_vid_out_tick(struct vivid_dev *dev) +{ + struct vivid_buffer *vid_out_buf = NULL; + struct vivid_buffer *vbi_out_buf = NULL; + struct vivid_buffer *meta_out_buf = NULL; + + dprintk(dev, 1, "Video Output Thread Tick\n"); + + /* Drop a certain percentage of buffers. */ + if (dev->perc_dropped_buffers && + prandom_u32_max(100) < dev->perc_dropped_buffers) + return; + + spin_lock(&dev->slock); + /* + * Only dequeue buffer if there is at least one more pending. + * This makes video loopback possible. + */ + if (!list_empty(&dev->vid_out_active) && + !list_is_singular(&dev->vid_out_active)) { + vid_out_buf = list_entry(dev->vid_out_active.next, + struct vivid_buffer, list); + list_del(&vid_out_buf->list); + } + if (!list_empty(&dev->vbi_out_active) && + (dev->field_out != V4L2_FIELD_ALTERNATE || + (dev->vbi_out_seq_count & 1))) { + vbi_out_buf = list_entry(dev->vbi_out_active.next, + struct vivid_buffer, list); + list_del(&vbi_out_buf->list); + } + if (!list_empty(&dev->meta_out_active)) { + meta_out_buf = list_entry(dev->meta_out_active.next, + struct vivid_buffer, list); + list_del(&meta_out_buf->list); + } + spin_unlock(&dev->slock); + + if (!vid_out_buf && !vbi_out_buf && !meta_out_buf) + return; + + if (vid_out_buf) { + v4l2_ctrl_request_setup(vid_out_buf->vb.vb2_buf.req_obj.req, + &dev->ctrl_hdl_vid_out); + v4l2_ctrl_request_complete(vid_out_buf->vb.vb2_buf.req_obj.req, + &dev->ctrl_hdl_vid_out); + vid_out_buf->vb.sequence = dev->vid_out_seq_count; + if (dev->field_out == V4L2_FIELD_ALTERNATE) { + /* + * The sequence counter counts frames, not fields. + * So divide by two. + */ + vid_out_buf->vb.sequence /= 2; + } + vid_out_buf->vb.vb2_buf.timestamp = + ktime_get_ns() + dev->time_wrap_offset; + vb2_buffer_done(&vid_out_buf->vb.vb2_buf, dev->dqbuf_error ? + VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE); + dprintk(dev, 2, "vid_out buffer %d done\n", + vid_out_buf->vb.vb2_buf.index); + } + + if (vbi_out_buf) { + v4l2_ctrl_request_setup(vbi_out_buf->vb.vb2_buf.req_obj.req, + &dev->ctrl_hdl_vbi_out); + v4l2_ctrl_request_complete(vbi_out_buf->vb.vb2_buf.req_obj.req, + &dev->ctrl_hdl_vbi_out); + if (dev->stream_sliced_vbi_out) + vivid_sliced_vbi_out_process(dev, vbi_out_buf); + + vbi_out_buf->vb.sequence = dev->vbi_out_seq_count; + vbi_out_buf->vb.vb2_buf.timestamp = + ktime_get_ns() + dev->time_wrap_offset; + vb2_buffer_done(&vbi_out_buf->vb.vb2_buf, dev->dqbuf_error ? + VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE); + dprintk(dev, 2, "vbi_out buffer %d done\n", + vbi_out_buf->vb.vb2_buf.index); + } + if (meta_out_buf) { + v4l2_ctrl_request_setup(meta_out_buf->vb.vb2_buf.req_obj.req, + &dev->ctrl_hdl_meta_out); + v4l2_ctrl_request_complete(meta_out_buf->vb.vb2_buf.req_obj.req, + &dev->ctrl_hdl_meta_out); + vivid_meta_out_process(dev, meta_out_buf); + meta_out_buf->vb.sequence = dev->meta_out_seq_count; + meta_out_buf->vb.vb2_buf.timestamp = + ktime_get_ns() + dev->time_wrap_offset; + vb2_buffer_done(&meta_out_buf->vb.vb2_buf, dev->dqbuf_error ? + VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE); + dprintk(dev, 2, "meta_out buffer %d done\n", + meta_out_buf->vb.vb2_buf.index); + } + + dev->dqbuf_error = false; +} + +static int vivid_thread_vid_out(void *data) +{ + struct vivid_dev *dev = data; + u64 numerators_since_start; + u64 buffers_since_start; + u64 next_jiffies_since_start; + unsigned long jiffies_since_start; + unsigned long cur_jiffies; + unsigned wait_jiffies; + unsigned numerator; + unsigned denominator; + + dprintk(dev, 1, "Video Output Thread Start\n"); + + set_freezable(); + + /* Resets frame counters */ + dev->out_seq_offset = 0; + if (dev->seq_wrap) + dev->out_seq_count = 0xffffff80U; + dev->jiffies_vid_out = jiffies; + dev->vid_out_seq_start = dev->vbi_out_seq_start = 0; + dev->meta_out_seq_start = 0; + dev->out_seq_resync = false; + + for (;;) { + try_to_freeze(); + if (kthread_should_stop()) + break; + + if (!mutex_trylock(&dev->mutex)) { + schedule_timeout_uninterruptible(1); + continue; + } + + cur_jiffies = jiffies; + if (dev->out_seq_resync) { + dev->jiffies_vid_out = cur_jiffies; + dev->out_seq_offset = dev->out_seq_count + 1; + dev->out_seq_count = 0; + dev->out_seq_resync = false; + } + numerator = dev->timeperframe_vid_out.numerator; + denominator = dev->timeperframe_vid_out.denominator; + + if (dev->field_out == V4L2_FIELD_ALTERNATE) + denominator *= 2; + + /* Calculate the number of jiffies since we started streaming */ + jiffies_since_start = cur_jiffies - dev->jiffies_vid_out; + /* Get the number of buffers streamed since the start */ + buffers_since_start = (u64)jiffies_since_start * denominator + + (HZ * numerator) / 2; + do_div(buffers_since_start, HZ * numerator); + + /* + * After more than 0xf0000000 (rounded down to a multiple of + * 'jiffies-per-day' to ease jiffies_to_msecs calculation) + * jiffies have passed since we started streaming reset the + * counters and keep track of the sequence offset. + */ + if (jiffies_since_start > JIFFIES_RESYNC) { + dev->jiffies_vid_out = cur_jiffies; + dev->out_seq_offset = buffers_since_start; + buffers_since_start = 0; + } + dev->out_seq_count = buffers_since_start + dev->out_seq_offset; + dev->vid_out_seq_count = dev->out_seq_count - dev->vid_out_seq_start; + dev->vbi_out_seq_count = dev->out_seq_count - dev->vbi_out_seq_start; + dev->meta_out_seq_count = dev->out_seq_count - dev->meta_out_seq_start; + + vivid_thread_vid_out_tick(dev); + mutex_unlock(&dev->mutex); + + /* + * Calculate the number of 'numerators' streamed since we started, + * not including the current buffer. + */ + numerators_since_start = buffers_since_start * numerator; + + /* And the number of jiffies since we started */ + jiffies_since_start = jiffies - dev->jiffies_vid_out; + + /* Increase by the 'numerator' of one buffer */ + numerators_since_start += numerator; + /* + * Calculate when that next buffer is supposed to start + * in jiffies since we started streaming. + */ + next_jiffies_since_start = numerators_since_start * HZ + + denominator / 2; + do_div(next_jiffies_since_start, denominator); + /* If it is in the past, then just schedule asap */ + if (next_jiffies_since_start < jiffies_since_start) + next_jiffies_since_start = jiffies_since_start; + + wait_jiffies = next_jiffies_since_start - jiffies_since_start; + schedule_timeout_interruptible(wait_jiffies ? wait_jiffies : 1); + } + dprintk(dev, 1, "Video Output Thread End\n"); + return 0; +} + +static void vivid_grab_controls(struct vivid_dev *dev, bool grab) +{ + v4l2_ctrl_grab(dev->ctrl_has_crop_out, grab); + v4l2_ctrl_grab(dev->ctrl_has_compose_out, grab); + v4l2_ctrl_grab(dev->ctrl_has_scaler_out, grab); + v4l2_ctrl_grab(dev->ctrl_tx_mode, grab); + v4l2_ctrl_grab(dev->ctrl_tx_rgb_range, grab); +} + +int vivid_start_generating_vid_out(struct vivid_dev *dev, bool *pstreaming) +{ + dprintk(dev, 1, "%s\n", __func__); + + if (dev->kthread_vid_out) { + u32 seq_count = dev->out_seq_count + dev->seq_wrap * 128; + + if (pstreaming == &dev->vid_out_streaming) + dev->vid_out_seq_start = seq_count; + else if (pstreaming == &dev->vbi_out_streaming) + dev->vbi_out_seq_start = seq_count; + else + dev->meta_out_seq_start = seq_count; + *pstreaming = true; + return 0; + } + + /* Resets frame counters */ + dev->jiffies_vid_out = jiffies; + dev->vid_out_seq_start = dev->seq_wrap * 128; + dev->vbi_out_seq_start = dev->seq_wrap * 128; + dev->meta_out_seq_start = dev->seq_wrap * 128; + + dev->kthread_vid_out = kthread_run(vivid_thread_vid_out, dev, + "%s-vid-out", dev->v4l2_dev.name); + + if (IS_ERR(dev->kthread_vid_out)) { + int err = PTR_ERR(dev->kthread_vid_out); + + dev->kthread_vid_out = NULL; + v4l2_err(&dev->v4l2_dev, "kernel_thread() failed\n"); + return err; + } + *pstreaming = true; + vivid_grab_controls(dev, true); + + dprintk(dev, 1, "returning from %s\n", __func__); + return 0; +} + +void vivid_stop_generating_vid_out(struct vivid_dev *dev, bool *pstreaming) +{ + dprintk(dev, 1, "%s\n", __func__); + + if (dev->kthread_vid_out == NULL) + return; + + *pstreaming = false; + if (pstreaming == &dev->vid_out_streaming) { + /* Release all active buffers */ + while (!list_empty(&dev->vid_out_active)) { + struct vivid_buffer *buf; + + buf = list_entry(dev->vid_out_active.next, + struct vivid_buffer, list); + list_del(&buf->list); + v4l2_ctrl_request_complete(buf->vb.vb2_buf.req_obj.req, + &dev->ctrl_hdl_vid_out); + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); + dprintk(dev, 2, "vid_out buffer %d done\n", + buf->vb.vb2_buf.index); + } + } + + if (pstreaming == &dev->vbi_out_streaming) { + while (!list_empty(&dev->vbi_out_active)) { + struct vivid_buffer *buf; + + buf = list_entry(dev->vbi_out_active.next, + struct vivid_buffer, list); + list_del(&buf->list); + v4l2_ctrl_request_complete(buf->vb.vb2_buf.req_obj.req, + &dev->ctrl_hdl_vbi_out); + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); + dprintk(dev, 2, "vbi_out buffer %d done\n", + buf->vb.vb2_buf.index); + } + } + + if (pstreaming == &dev->meta_out_streaming) { + while (!list_empty(&dev->meta_out_active)) { + struct vivid_buffer *buf; + + buf = list_entry(dev->meta_out_active.next, + struct vivid_buffer, list); + list_del(&buf->list); + v4l2_ctrl_request_complete(buf->vb.vb2_buf.req_obj.req, + &dev->ctrl_hdl_meta_out); + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); + dprintk(dev, 2, "meta_out buffer %d done\n", + buf->vb.vb2_buf.index); + } + } + + if (dev->vid_out_streaming || dev->vbi_out_streaming || + dev->meta_out_streaming) + return; + + /* shutdown control thread */ + vivid_grab_controls(dev, false); + kthread_stop(dev->kthread_vid_out); + dev->kthread_vid_out = NULL; +} diff --git a/drivers/media/test_drivers/vivid/vivid-kthread-out.h b/drivers/media/test_drivers/vivid/vivid-kthread-out.h new file mode 100644 index 000000000000..d5bcf44bbaca --- /dev/null +++ b/drivers/media/test_drivers/vivid/vivid-kthread-out.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * vivid-kthread-out.h - video/vbi output thread support functions. + * + * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. + */ + +#ifndef _VIVID_KTHREAD_OUT_H_ +#define _VIVID_KTHREAD_OUT_H_ + +int vivid_start_generating_vid_out(struct vivid_dev *dev, bool *pstreaming); +void vivid_stop_generating_vid_out(struct vivid_dev *dev, bool *pstreaming); + +#endif diff --git a/drivers/media/test_drivers/vivid/vivid-kthread-touch.c b/drivers/media/test_drivers/vivid/vivid-kthread-touch.c new file mode 100644 index 000000000000..674507b5ccb5 --- /dev/null +++ b/drivers/media/test_drivers/vivid/vivid-kthread-touch.c @@ -0,0 +1,181 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * vivid-kthread-touch.c - touch capture thread support functions. + * + */ + +#include +#include "vivid-core.h" +#include "vivid-kthread-touch.h" +#include "vivid-touch-cap.h" + +static noinline_for_stack void vivid_thread_tch_cap_tick(struct vivid_dev *dev, + int dropped_bufs) +{ + struct vivid_buffer *tch_cap_buf = NULL; + + spin_lock(&dev->slock); + if (!list_empty(&dev->touch_cap_active)) { + tch_cap_buf = list_entry(dev->touch_cap_active.next, + struct vivid_buffer, list); + list_del(&tch_cap_buf->list); + } + + spin_unlock(&dev->slock); + + if (tch_cap_buf) { + v4l2_ctrl_request_setup(tch_cap_buf->vb.vb2_buf.req_obj.req, + &dev->ctrl_hdl_touch_cap); + + vivid_fillbuff_tch(dev, tch_cap_buf); + v4l2_ctrl_request_complete(tch_cap_buf->vb.vb2_buf.req_obj.req, + &dev->ctrl_hdl_touch_cap); + vb2_buffer_done(&tch_cap_buf->vb.vb2_buf, dev->dqbuf_error ? + VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE); + dprintk(dev, 2, "touch_cap buffer %d done\n", + tch_cap_buf->vb.vb2_buf.index); + + tch_cap_buf->vb.vb2_buf.timestamp = ktime_get_ns() + dev->time_wrap_offset; + } + dev->dqbuf_error = false; +} + +static int vivid_thread_touch_cap(void *data) +{ + struct vivid_dev *dev = data; + u64 numerators_since_start; + u64 buffers_since_start; + u64 next_jiffies_since_start; + unsigned long jiffies_since_start; + unsigned long cur_jiffies; + unsigned int wait_jiffies; + unsigned int numerator; + unsigned int denominator; + int dropped_bufs; + + dprintk(dev, 1, "Touch Capture Thread Start\n"); + + set_freezable(); + + /* Resets frame counters */ + dev->touch_cap_seq_offset = 0; + dev->touch_cap_seq_count = 0; + dev->touch_cap_seq_resync = false; + dev->jiffies_touch_cap = jiffies; + + for (;;) { + try_to_freeze(); + if (kthread_should_stop()) + break; + + if (!mutex_trylock(&dev->mutex)) { + schedule_timeout_uninterruptible(1); + continue; + } + cur_jiffies = jiffies; + if (dev->touch_cap_seq_resync) { + dev->jiffies_touch_cap = cur_jiffies; + dev->touch_cap_seq_offset = dev->touch_cap_seq_count + 1; + dev->touch_cap_seq_count = 0; + dev->cap_seq_resync = false; + } + denominator = dev->timeperframe_tch_cap.denominator; + numerator = dev->timeperframe_tch_cap.numerator; + + /* Calculate the number of jiffies since we started streaming */ + jiffies_since_start = cur_jiffies - dev->jiffies_touch_cap; + /* Get the number of buffers streamed since the start */ + buffers_since_start = (u64)jiffies_since_start * denominator + + (HZ * numerator) / 2; + do_div(buffers_since_start, HZ * numerator); + + /* + * After more than 0xf0000000 (rounded down to a multiple of + * 'jiffies-per-day' to ease jiffies_to_msecs calculation) + * jiffies have passed since we started streaming reset the + * counters and keep track of the sequence offset. + */ + if (jiffies_since_start > JIFFIES_RESYNC) { + dev->jiffies_touch_cap = cur_jiffies; + dev->cap_seq_offset = buffers_since_start; + buffers_since_start = 0; + } + dropped_bufs = buffers_since_start + dev->touch_cap_seq_offset - dev->touch_cap_seq_count; + dev->touch_cap_seq_count = buffers_since_start + dev->touch_cap_seq_offset; + + vivid_thread_tch_cap_tick(dev, dropped_bufs); + + /* + * Calculate the number of 'numerators' streamed + * since we started, including the current buffer. + */ + numerators_since_start = ++buffers_since_start * numerator; + + /* And the number of jiffies since we started */ + jiffies_since_start = jiffies - dev->jiffies_touch_cap; + + mutex_unlock(&dev->mutex); + + /* + * Calculate when that next buffer is supposed to start + * in jiffies since we started streaming. + */ + next_jiffies_since_start = numerators_since_start * HZ + + denominator / 2; + do_div(next_jiffies_since_start, denominator); + /* If it is in the past, then just schedule asap */ + if (next_jiffies_since_start < jiffies_since_start) + next_jiffies_since_start = jiffies_since_start; + + wait_jiffies = next_jiffies_since_start - jiffies_since_start; + schedule_timeout_interruptible(wait_jiffies ? wait_jiffies : 1); + } + dprintk(dev, 1, "Touch Capture Thread End\n"); + return 0; +} + +int vivid_start_generating_touch_cap(struct vivid_dev *dev) +{ + if (dev->kthread_touch_cap) { + dev->touch_cap_streaming = true; + return 0; + } + + dev->kthread_touch_cap = kthread_run(vivid_thread_touch_cap, dev, + "%s-tch-cap", dev->v4l2_dev.name); + + if (IS_ERR(dev->kthread_touch_cap)) { + int err = PTR_ERR(dev->kthread_touch_cap); + + dev->kthread_touch_cap = NULL; + v4l2_err(&dev->v4l2_dev, "kernel_thread() failed\n"); + return err; + } + dev->touch_cap_streaming = true; + dprintk(dev, 1, "returning from %s\n", __func__); + return 0; +} + +void vivid_stop_generating_touch_cap(struct vivid_dev *dev) +{ + if (!dev->kthread_touch_cap) + return; + + dev->touch_cap_streaming = false; + + while (!list_empty(&dev->touch_cap_active)) { + struct vivid_buffer *buf; + + buf = list_entry(dev->touch_cap_active.next, + struct vivid_buffer, list); + list_del(&buf->list); + v4l2_ctrl_request_complete(buf->vb.vb2_buf.req_obj.req, + &dev->ctrl_hdl_touch_cap); + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); + dprintk(dev, 2, "touch_cap buffer %d done\n", + buf->vb.vb2_buf.index); + } + + kthread_stop(dev->kthread_touch_cap); + dev->kthread_touch_cap = NULL; +} diff --git a/drivers/media/test_drivers/vivid/vivid-kthread-touch.h b/drivers/media/test_drivers/vivid/vivid-kthread-touch.h new file mode 100644 index 000000000000..ecf79b46209e --- /dev/null +++ b/drivers/media/test_drivers/vivid/vivid-kthread-touch.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * vivid-kthread-cap.h - video/vbi capture thread support functions. + * + */ + +#ifndef _VIVID_KTHREAD_CAP_H_ +#define _VIVID_KTHREAD_CAP_H_ + +int vivid_start_generating_touch_cap(struct vivid_dev *dev); +void vivid_stop_generating_touch_cap(struct vivid_dev *dev); + +#endif diff --git a/drivers/media/test_drivers/vivid/vivid-meta-cap.c b/drivers/media/test_drivers/vivid/vivid-meta-cap.c new file mode 100644 index 000000000000..780f96860a6d --- /dev/null +++ b/drivers/media/test_drivers/vivid/vivid-meta-cap.c @@ -0,0 +1,201 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * vivid-meta-cap.c - meta capture support functions. + */ + +#include +#include +#include +#include +#include + +#include "vivid-core.h" +#include "vivid-kthread-cap.h" +#include "vivid-meta-cap.h" + +static int meta_cap_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, + unsigned int *nplanes, unsigned int sizes[], + struct device *alloc_devs[]) +{ + struct vivid_dev *dev = vb2_get_drv_priv(vq); + unsigned int size = sizeof(struct vivid_uvc_meta_buf); + + if (!vivid_is_webcam(dev)) + return -EINVAL; + + if (*nplanes) { + if (sizes[0] < size) + return -EINVAL; + } else { + sizes[0] = size; + } + + if (vq->num_buffers + *nbuffers < 2) + *nbuffers = 2 - vq->num_buffers; + + *nplanes = 1; + return 0; +} + +static int meta_cap_buf_prepare(struct vb2_buffer *vb) +{ + struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); + unsigned int size = sizeof(struct vivid_uvc_meta_buf); + + dprintk(dev, 1, "%s\n", __func__); + + if (dev->buf_prepare_error) { + /* + * Error injection: test what happens if buf_prepare() returns + * an error. + */ + dev->buf_prepare_error = false; + return -EINVAL; + } + if (vb2_plane_size(vb, 0) < size) { + dprintk(dev, 1, "%s data will not fit into plane (%lu < %u)\n", + __func__, vb2_plane_size(vb, 0), size); + return -EINVAL; + } + vb2_set_plane_payload(vb, 0, size); + + return 0; +} + +static void meta_cap_buf_queue(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); + struct vivid_buffer *buf = container_of(vbuf, struct vivid_buffer, vb); + + dprintk(dev, 1, "%s\n", __func__); + + spin_lock(&dev->slock); + list_add_tail(&buf->list, &dev->meta_cap_active); + spin_unlock(&dev->slock); +} + +static int meta_cap_start_streaming(struct vb2_queue *vq, unsigned int count) +{ + struct vivid_dev *dev = vb2_get_drv_priv(vq); + int err; + + dprintk(dev, 1, "%s\n", __func__); + dev->meta_cap_seq_count = 0; + if (dev->start_streaming_error) { + dev->start_streaming_error = false; + err = -EINVAL; + } else { + err = vivid_start_generating_vid_cap(dev, + &dev->meta_cap_streaming); + } + if (err) { + struct vivid_buffer *buf, *tmp; + + list_for_each_entry_safe(buf, tmp, + &dev->meta_cap_active, list) { + list_del(&buf->list); + vb2_buffer_done(&buf->vb.vb2_buf, + VB2_BUF_STATE_QUEUED); + } + } + return err; +} + +/* abort streaming and wait for last buffer */ +static void meta_cap_stop_streaming(struct vb2_queue *vq) +{ + struct vivid_dev *dev = vb2_get_drv_priv(vq); + + dprintk(dev, 1, "%s\n", __func__); + vivid_stop_generating_vid_cap(dev, &dev->meta_cap_streaming); +} + +static void meta_cap_buf_request_complete(struct vb2_buffer *vb) +{ + struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); + + v4l2_ctrl_request_complete(vb->req_obj.req, &dev->ctrl_hdl_meta_cap); +} + +const struct vb2_ops vivid_meta_cap_qops = { + .queue_setup = meta_cap_queue_setup, + .buf_prepare = meta_cap_buf_prepare, + .buf_queue = meta_cap_buf_queue, + .start_streaming = meta_cap_start_streaming, + .stop_streaming = meta_cap_stop_streaming, + .buf_request_complete = meta_cap_buf_request_complete, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, +}; + +int vidioc_enum_fmt_meta_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (!vivid_is_webcam(dev)) + return -EINVAL; + + if (f->index > 0) + return -EINVAL; + + f->type = V4L2_BUF_TYPE_META_CAPTURE; + f->pixelformat = V4L2_META_FMT_UVC; + return 0; +} + +int vidioc_g_fmt_meta_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct vivid_dev *dev = video_drvdata(file); + struct v4l2_meta_format *meta = &f->fmt.meta; + + if (!vivid_is_webcam(dev) || !dev->has_meta_cap) + return -EINVAL; + + meta->dataformat = V4L2_META_FMT_UVC; + meta->buffersize = sizeof(struct vivid_uvc_meta_buf); + return 0; +} + +void vivid_meta_cap_fillbuff(struct vivid_dev *dev, + struct vivid_buffer *buf, u64 soe) +{ + struct vivid_uvc_meta_buf *meta = vb2_plane_vaddr(&buf->vb.vb2_buf, 0); + int buf_off = 0; + + buf->vb.sequence = dev->meta_cap_seq_count; + if (dev->field_cap == V4L2_FIELD_ALTERNATE) + buf->vb.sequence /= 2; + memset(meta, 1, vb2_plane_size(&buf->vb.vb2_buf, 0)); + + meta->ns = ktime_get_ns(); + meta->sof = buf->vb.sequence * 30; + meta->length = sizeof(*meta) - offsetof(struct vivid_uvc_meta_buf, length); + meta->flags = UVC_STREAM_EOH | UVC_STREAM_EOF; + + if ((buf->vb.sequence % 2) == 0) + meta->flags |= UVC_STREAM_FID; + + dprintk(dev, 2, "%s ns:%llu sof:%4d len:%u flags: 0x%02x", + __func__, meta->ns, meta->sof, meta->length, meta->flags); + if (dev->meta_pts) { + meta->flags |= UVC_STREAM_PTS; + meta->buf[0] = div_u64(soe, VIVID_META_CLOCK_UNIT); + buf_off = 4; + dprintk(dev, 2, " pts: %u\n", *(__u32 *)(meta->buf)); + } + + if (dev->meta_scr) { + meta->flags |= UVC_STREAM_SCR; + meta->buf[buf_off] = div_u64((soe + dev->cap_frame_eof_offset), + VIVID_META_CLOCK_UNIT); + + meta->buf[buf_off + 4] = (buf->vb.sequence * 30) % 1000; + dprintk(dev, 2, " stc: %u, sof counter: %u\n", + *(__u32 *)(meta->buf + buf_off), + *(__u16 *)(meta->buf + buf_off + 4)); + } + dprintk(dev, 2, "\n"); +} diff --git a/drivers/media/test_drivers/vivid/vivid-meta-cap.h b/drivers/media/test_drivers/vivid/vivid-meta-cap.h new file mode 100644 index 000000000000..4670d00d1576 --- /dev/null +++ b/drivers/media/test_drivers/vivid/vivid-meta-cap.h @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * vivid-meta-cap.h - meta capture support functions. + */ +#ifndef _VIVID_META_CAP_H_ +#define _VIVID_META_CAP_H_ + +#define VIVID_META_CLOCK_UNIT 10 /* 100 MHz */ + +struct vivid_uvc_meta_buf { + __u64 ns; + __u16 sof; + __u8 length; + __u8 flags; + __u8 buf[10]; /* PTS(4)+STC(4)+SOF(2) */ +} __packed; + +void vivid_meta_cap_fillbuff(struct vivid_dev *dev, + struct vivid_buffer *buf, u64 soe); + +int vidioc_enum_fmt_meta_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f); + +int vidioc_g_fmt_meta_cap(struct file *file, void *priv, + struct v4l2_format *f); + +extern const struct vb2_ops vivid_meta_cap_qops; + +#endif diff --git a/drivers/media/test_drivers/vivid/vivid-meta-out.c b/drivers/media/test_drivers/vivid/vivid-meta-out.c new file mode 100644 index 000000000000..ff8a039aba72 --- /dev/null +++ b/drivers/media/test_drivers/vivid/vivid-meta-out.c @@ -0,0 +1,174 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * vivid-meta-out.c - meta output support functions. + */ + +#include +#include +#include +#include +#include + +#include "vivid-core.h" +#include "vivid-kthread-out.h" +#include "vivid-meta-out.h" + +static int meta_out_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, + unsigned int *nplanes, unsigned int sizes[], + struct device *alloc_devs[]) +{ + struct vivid_dev *dev = vb2_get_drv_priv(vq); + unsigned int size = sizeof(struct vivid_meta_out_buf); + + if (!vivid_is_webcam(dev)) + return -EINVAL; + + if (*nplanes) { + if (sizes[0] < size) + return -EINVAL; + } else { + sizes[0] = size; + } + + if (vq->num_buffers + *nbuffers < 2) + *nbuffers = 2 - vq->num_buffers; + + *nplanes = 1; + return 0; +} + +static int meta_out_buf_prepare(struct vb2_buffer *vb) +{ + struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); + unsigned int size = sizeof(struct vivid_meta_out_buf); + + dprintk(dev, 1, "%s\n", __func__); + + if (dev->buf_prepare_error) { + /* + * Error injection: test what happens if buf_prepare() returns + * an error. + */ + dev->buf_prepare_error = false; + return -EINVAL; + } + if (vb2_plane_size(vb, 0) < size) { + dprintk(dev, 1, "%s data will not fit into plane (%lu < %u)\n", + __func__, vb2_plane_size(vb, 0), size); + return -EINVAL; + } + vb2_set_plane_payload(vb, 0, size); + + return 0; +} + +static void meta_out_buf_queue(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); + struct vivid_buffer *buf = container_of(vbuf, struct vivid_buffer, vb); + + dprintk(dev, 1, "%s\n", __func__); + + spin_lock(&dev->slock); + list_add_tail(&buf->list, &dev->meta_out_active); + spin_unlock(&dev->slock); +} + +static int meta_out_start_streaming(struct vb2_queue *vq, unsigned int count) +{ + struct vivid_dev *dev = vb2_get_drv_priv(vq); + int err; + + dprintk(dev, 1, "%s\n", __func__); + dev->meta_out_seq_count = 0; + if (dev->start_streaming_error) { + dev->start_streaming_error = false; + err = -EINVAL; + } else { + err = vivid_start_generating_vid_out(dev, + &dev->meta_out_streaming); + } + if (err) { + struct vivid_buffer *buf, *tmp; + + list_for_each_entry_safe(buf, tmp, + &dev->meta_out_active, list) { + list_del(&buf->list); + vb2_buffer_done(&buf->vb.vb2_buf, + VB2_BUF_STATE_QUEUED); + } + } + return err; +} + +/* abort streaming and wait for last buffer */ +static void meta_out_stop_streaming(struct vb2_queue *vq) +{ + struct vivid_dev *dev = vb2_get_drv_priv(vq); + + dprintk(dev, 1, "%s\n", __func__); + vivid_stop_generating_vid_out(dev, &dev->meta_out_streaming); +} + +static void meta_out_buf_request_complete(struct vb2_buffer *vb) +{ + struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); + + v4l2_ctrl_request_complete(vb->req_obj.req, &dev->ctrl_hdl_meta_out); +} + +const struct vb2_ops vivid_meta_out_qops = { + .queue_setup = meta_out_queue_setup, + .buf_prepare = meta_out_buf_prepare, + .buf_queue = meta_out_buf_queue, + .start_streaming = meta_out_start_streaming, + .stop_streaming = meta_out_stop_streaming, + .buf_request_complete = meta_out_buf_request_complete, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, +}; + +int vidioc_enum_fmt_meta_out(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (!vivid_is_webcam(dev)) + return -EINVAL; + + if (f->index > 0) + return -EINVAL; + + f->type = V4L2_BUF_TYPE_META_OUTPUT; + f->pixelformat = V4L2_META_FMT_VIVID; + return 0; +} + +int vidioc_g_fmt_meta_out(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct vivid_dev *dev = video_drvdata(file); + struct v4l2_meta_format *meta = &f->fmt.meta; + + if (!vivid_is_webcam(dev) || !dev->has_meta_out) + return -EINVAL; + + meta->dataformat = V4L2_META_FMT_VIVID; + meta->buffersize = sizeof(struct vivid_meta_out_buf); + return 0; +} + +void vivid_meta_out_process(struct vivid_dev *dev, + struct vivid_buffer *buf) +{ + struct vivid_meta_out_buf *meta = vb2_plane_vaddr(&buf->vb.vb2_buf, 0); + + tpg_s_brightness(&dev->tpg, meta->brightness); + tpg_s_contrast(&dev->tpg, meta->contrast); + tpg_s_saturation(&dev->tpg, meta->saturation); + tpg_s_hue(&dev->tpg, meta->hue); + dprintk(dev, 2, " %s brightness %u contrast %u saturation %u hue %d\n", + __func__, meta->brightness, meta->contrast, + meta->saturation, meta->hue); +} diff --git a/drivers/media/test_drivers/vivid/vivid-meta-out.h b/drivers/media/test_drivers/vivid/vivid-meta-out.h new file mode 100644 index 000000000000..0c639b7c2842 --- /dev/null +++ b/drivers/media/test_drivers/vivid/vivid-meta-out.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * vivid-meta-out.h - meta output support functions. + */ +#ifndef _VIVID_META_OUT_H_ +#define _VIVID_META_OUT_H_ + +struct vivid_meta_out_buf { + u16 brightness; + u16 contrast; + u16 saturation; + s16 hue; +}; + +void vivid_meta_out_process(struct vivid_dev *dev, struct vivid_buffer *buf); +int vidioc_enum_fmt_meta_out(struct file *file, void *priv, + struct v4l2_fmtdesc *f); +int vidioc_g_fmt_meta_out(struct file *file, void *priv, + struct v4l2_format *f); +int vidioc_s_fmt_meta_out(struct file *file, void *priv, + struct v4l2_format *f); + +extern const struct vb2_ops vivid_meta_out_qops; + +#endif diff --git a/drivers/media/test_drivers/vivid/vivid-osd.c b/drivers/media/test_drivers/vivid/vivid-osd.c new file mode 100644 index 000000000000..fbaec8acc161 --- /dev/null +++ b/drivers/media/test_drivers/vivid/vivid-osd.c @@ -0,0 +1,388 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * vivid-osd.c - osd support for testing overlays. + * + * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "vivid-core.h" +#include "vivid-osd.h" + +#define MAX_OSD_WIDTH 720 +#define MAX_OSD_HEIGHT 576 + +/* + * Order: white, yellow, cyan, green, magenta, red, blue, black, + * and same again with the alpha bit set (if any) + */ +static const u16 rgb555[16] = { + 0x7fff, 0x7fe0, 0x03ff, 0x03e0, 0x7c1f, 0x7c00, 0x001f, 0x0000, + 0xffff, 0xffe0, 0x83ff, 0x83e0, 0xfc1f, 0xfc00, 0x801f, 0x8000 +}; + +static const u16 rgb565[16] = { + 0xffff, 0xffe0, 0x07ff, 0x07e0, 0xf81f, 0xf800, 0x001f, 0x0000, + 0xffff, 0xffe0, 0x07ff, 0x07e0, 0xf81f, 0xf800, 0x001f, 0x0000 +}; + +void vivid_clear_fb(struct vivid_dev *dev) +{ + void *p = dev->video_vbase; + const u16 *rgb = rgb555; + unsigned x, y; + + if (dev->fb_defined.green.length == 6) + rgb = rgb565; + + for (y = 0; y < dev->display_height; y++) { + u16 *d = p; + + for (x = 0; x < dev->display_width; x++) + d[x] = rgb[(y / 16 + x / 16) % 16]; + p += dev->display_byte_stride; + } +} + +/* --------------------------------------------------------------------- */ + +static int vivid_fb_ioctl(struct fb_info *info, unsigned cmd, unsigned long arg) +{ + struct vivid_dev *dev = (struct vivid_dev *)info->par; + + switch (cmd) { + case FBIOGET_VBLANK: { + struct fb_vblank vblank; + + memset(&vblank, 0, sizeof(vblank)); + vblank.flags = FB_VBLANK_HAVE_COUNT | FB_VBLANK_HAVE_VCOUNT | + FB_VBLANK_HAVE_VSYNC; + vblank.count = 0; + vblank.vcount = 0; + vblank.hcount = 0; + if (copy_to_user((void __user *)arg, &vblank, sizeof(vblank))) + return -EFAULT; + return 0; + } + + default: + dprintk(dev, 1, "Unknown ioctl %08x\n", cmd); + return -EINVAL; + } + return 0; +} + +/* Framebuffer device handling */ + +static int vivid_fb_set_var(struct vivid_dev *dev, struct fb_var_screeninfo *var) +{ + dprintk(dev, 1, "vivid_fb_set_var\n"); + + if (var->bits_per_pixel != 16) { + dprintk(dev, 1, "vivid_fb_set_var - Invalid bpp\n"); + return -EINVAL; + } + dev->display_byte_stride = var->xres * dev->bytes_per_pixel; + + return 0; +} + +static int vivid_fb_get_fix(struct vivid_dev *dev, struct fb_fix_screeninfo *fix) +{ + dprintk(dev, 1, "vivid_fb_get_fix\n"); + memset(fix, 0, sizeof(struct fb_fix_screeninfo)); + strscpy(fix->id, "vioverlay fb", sizeof(fix->id)); + fix->smem_start = dev->video_pbase; + fix->smem_len = dev->video_buffer_size; + fix->type = FB_TYPE_PACKED_PIXELS; + fix->visual = FB_VISUAL_TRUECOLOR; + fix->xpanstep = 1; + fix->ypanstep = 1; + fix->ywrapstep = 0; + fix->line_length = dev->display_byte_stride; + fix->accel = FB_ACCEL_NONE; + return 0; +} + +/* Check the requested display mode, returning -EINVAL if we can't + handle it. */ + +static int _vivid_fb_check_var(struct fb_var_screeninfo *var, struct vivid_dev *dev) +{ + dprintk(dev, 1, "vivid_fb_check_var\n"); + + var->bits_per_pixel = 16; + if (var->green.length == 5) { + var->red.offset = 10; + var->red.length = 5; + var->green.offset = 5; + var->green.length = 5; + var->blue.offset = 0; + var->blue.length = 5; + var->transp.offset = 15; + var->transp.length = 1; + } else { + var->red.offset = 11; + var->red.length = 5; + var->green.offset = 5; + var->green.length = 6; + var->blue.offset = 0; + var->blue.length = 5; + var->transp.offset = 0; + var->transp.length = 0; + } + var->xoffset = var->yoffset = 0; + var->left_margin = var->upper_margin = 0; + var->nonstd = 0; + + var->vmode &= ~FB_VMODE_MASK; + var->vmode |= FB_VMODE_NONINTERLACED; + + /* Dummy values */ + var->hsync_len = 24; + var->vsync_len = 2; + var->pixclock = 84316; + var->right_margin = 776; + var->lower_margin = 591; + return 0; +} + +static int vivid_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) +{ + struct vivid_dev *dev = (struct vivid_dev *) info->par; + + dprintk(dev, 1, "vivid_fb_check_var\n"); + return _vivid_fb_check_var(var, dev); +} + +static int vivid_fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) +{ + return 0; +} + +static int vivid_fb_set_par(struct fb_info *info) +{ + int rc = 0; + struct vivid_dev *dev = (struct vivid_dev *) info->par; + + dprintk(dev, 1, "vivid_fb_set_par\n"); + + rc = vivid_fb_set_var(dev, &info->var); + vivid_fb_get_fix(dev, &info->fix); + return rc; +} + +static int vivid_fb_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, + struct fb_info *info) +{ + u32 color, *palette; + + if (regno >= info->cmap.len) + return -EINVAL; + + color = ((transp & 0xFF00) << 16) | ((red & 0xFF00) << 8) | + (green & 0xFF00) | ((blue & 0xFF00) >> 8); + if (regno >= 16) + return -EINVAL; + + palette = info->pseudo_palette; + if (info->var.bits_per_pixel == 16) { + switch (info->var.green.length) { + case 6: + color = (red & 0xf800) | + ((green & 0xfc00) >> 5) | + ((blue & 0xf800) >> 11); + break; + case 5: + color = ((red & 0xf800) >> 1) | + ((green & 0xf800) >> 6) | + ((blue & 0xf800) >> 11) | + (transp ? 0x8000 : 0); + break; + } + } + palette[regno] = color; + return 0; +} + +/* We don't really support blanking. All this does is enable or + disable the OSD. */ +static int vivid_fb_blank(int blank_mode, struct fb_info *info) +{ + struct vivid_dev *dev = (struct vivid_dev *)info->par; + + dprintk(dev, 1, "Set blanking mode : %d\n", blank_mode); + switch (blank_mode) { + case FB_BLANK_UNBLANK: + break; + case FB_BLANK_NORMAL: + case FB_BLANK_HSYNC_SUSPEND: + case FB_BLANK_VSYNC_SUSPEND: + case FB_BLANK_POWERDOWN: + break; + } + return 0; +} + +static const struct fb_ops vivid_fb_ops = { + .owner = THIS_MODULE, + .fb_check_var = vivid_fb_check_var, + .fb_set_par = vivid_fb_set_par, + .fb_setcolreg = vivid_fb_setcolreg, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_cursor = NULL, + .fb_ioctl = vivid_fb_ioctl, + .fb_pan_display = vivid_fb_pan_display, + .fb_blank = vivid_fb_blank, +}; + +/* Initialization */ + + +/* Setup our initial video mode */ +static int vivid_fb_init_vidmode(struct vivid_dev *dev) +{ + struct v4l2_rect start_window; + + /* Color mode */ + + dev->bits_per_pixel = 16; + dev->bytes_per_pixel = dev->bits_per_pixel / 8; + + start_window.width = MAX_OSD_WIDTH; + start_window.left = 0; + + dev->display_byte_stride = start_window.width * dev->bytes_per_pixel; + + /* Vertical size & position */ + + start_window.height = MAX_OSD_HEIGHT; + start_window.top = 0; + + dev->display_width = start_window.width; + dev->display_height = start_window.height; + + /* Generate a valid fb_var_screeninfo */ + + dev->fb_defined.xres = dev->display_width; + dev->fb_defined.yres = dev->display_height; + dev->fb_defined.xres_virtual = dev->display_width; + dev->fb_defined.yres_virtual = dev->display_height; + dev->fb_defined.bits_per_pixel = dev->bits_per_pixel; + dev->fb_defined.vmode = FB_VMODE_NONINTERLACED; + dev->fb_defined.left_margin = start_window.left + 1; + dev->fb_defined.upper_margin = start_window.top + 1; + dev->fb_defined.accel_flags = FB_ACCEL_NONE; + dev->fb_defined.nonstd = 0; + /* set default to 1:5:5:5 */ + dev->fb_defined.green.length = 5; + + /* We've filled in the most data, let the usual mode check + routine fill in the rest. */ + _vivid_fb_check_var(&dev->fb_defined, dev); + + /* Generate valid fb_fix_screeninfo */ + + vivid_fb_get_fix(dev, &dev->fb_fix); + + /* Generate valid fb_info */ + + dev->fb_info.node = -1; + dev->fb_info.flags = FBINFO_FLAG_DEFAULT; + dev->fb_info.par = dev; + dev->fb_info.var = dev->fb_defined; + dev->fb_info.fix = dev->fb_fix; + dev->fb_info.screen_base = (u8 __iomem *)dev->video_vbase; + dev->fb_info.fbops = &vivid_fb_ops; + + /* Supply some monitor specs. Bogus values will do for now */ + dev->fb_info.monspecs.hfmin = 8000; + dev->fb_info.monspecs.hfmax = 70000; + dev->fb_info.monspecs.vfmin = 10; + dev->fb_info.monspecs.vfmax = 100; + + /* Allocate color map */ + if (fb_alloc_cmap(&dev->fb_info.cmap, 256, 1)) { + pr_err("abort, unable to alloc cmap\n"); + return -ENOMEM; + } + + /* Allocate the pseudo palette */ + dev->fb_info.pseudo_palette = kmalloc_array(16, sizeof(u32), GFP_KERNEL); + + return dev->fb_info.pseudo_palette ? 0 : -ENOMEM; +} + +/* Release any memory we've grabbed */ +void vivid_fb_release_buffers(struct vivid_dev *dev) +{ + if (dev->video_vbase == NULL) + return; + + /* Release cmap */ + if (dev->fb_info.cmap.len) + fb_dealloc_cmap(&dev->fb_info.cmap); + + /* Release pseudo palette */ + kfree(dev->fb_info.pseudo_palette); + kfree(dev->video_vbase); +} + +/* Initialize the specified card */ + +int vivid_fb_init(struct vivid_dev *dev) +{ + int ret; + + dev->video_buffer_size = MAX_OSD_HEIGHT * MAX_OSD_WIDTH * 2; + dev->video_vbase = kzalloc(dev->video_buffer_size, GFP_KERNEL | GFP_DMA32); + if (dev->video_vbase == NULL) + return -ENOMEM; + dev->video_pbase = virt_to_phys(dev->video_vbase); + + pr_info("Framebuffer at 0x%lx, mapped to 0x%p, size %dk\n", + dev->video_pbase, dev->video_vbase, + dev->video_buffer_size / 1024); + + /* Set the startup video mode information */ + ret = vivid_fb_init_vidmode(dev); + if (ret) { + vivid_fb_release_buffers(dev); + return ret; + } + + vivid_clear_fb(dev); + + /* Register the framebuffer */ + if (register_framebuffer(&dev->fb_info) < 0) { + vivid_fb_release_buffers(dev); + return -EINVAL; + } + + /* Set the card to the requested mode */ + vivid_fb_set_par(&dev->fb_info); + return 0; + +} diff --git a/drivers/media/test_drivers/vivid/vivid-osd.h b/drivers/media/test_drivers/vivid/vivid-osd.h new file mode 100644 index 000000000000..f9ac1af25dd3 --- /dev/null +++ b/drivers/media/test_drivers/vivid/vivid-osd.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * vivid-osd.h - output overlay support functions. + * + * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. + */ + +#ifndef _VIVID_OSD_H_ +#define _VIVID_OSD_H_ + +int vivid_fb_init(struct vivid_dev *dev); +void vivid_fb_release_buffers(struct vivid_dev *dev); +void vivid_clear_fb(struct vivid_dev *dev); + +#endif diff --git a/drivers/media/test_drivers/vivid/vivid-radio-common.c b/drivers/media/test_drivers/vivid/vivid-radio-common.c new file mode 100644 index 000000000000..138c7bce68b1 --- /dev/null +++ b/drivers/media/test_drivers/vivid/vivid-radio-common.c @@ -0,0 +1,177 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * vivid-radio-common.c - common radio rx/tx support functions. + * + * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. + */ + +#include +#include +#include +#include + +#include "vivid-core.h" +#include "vivid-ctrls.h" +#include "vivid-radio-common.h" +#include "vivid-rds-gen.h" + +/* + * These functions are shared between the vivid receiver and transmitter + * since both use the same frequency bands. + */ + +const struct v4l2_frequency_band vivid_radio_bands[TOT_BANDS] = { + /* Band FM */ + { + .type = V4L2_TUNER_RADIO, + .index = 0, + .capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO | + V4L2_TUNER_CAP_FREQ_BANDS, + .rangelow = FM_FREQ_RANGE_LOW, + .rangehigh = FM_FREQ_RANGE_HIGH, + .modulation = V4L2_BAND_MODULATION_FM, + }, + /* Band AM */ + { + .type = V4L2_TUNER_RADIO, + .index = 1, + .capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_FREQ_BANDS, + .rangelow = AM_FREQ_RANGE_LOW, + .rangehigh = AM_FREQ_RANGE_HIGH, + .modulation = V4L2_BAND_MODULATION_AM, + }, + /* Band SW */ + { + .type = V4L2_TUNER_RADIO, + .index = 2, + .capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_FREQ_BANDS, + .rangelow = SW_FREQ_RANGE_LOW, + .rangehigh = SW_FREQ_RANGE_HIGH, + .modulation = V4L2_BAND_MODULATION_AM, + }, +}; + +/* + * Initialize the RDS generator. If we can loop, then the RDS generator + * is set up with the values from the RDS TX controls, otherwise it + * will fill in standard values using one of two alternates. + */ +void vivid_radio_rds_init(struct vivid_dev *dev) +{ + struct vivid_rds_gen *rds = &dev->rds_gen; + bool alt = dev->radio_rx_rds_use_alternates; + + /* Do nothing, blocks will be filled by the transmitter */ + if (dev->radio_rds_loop && !dev->radio_tx_rds_controls) + return; + + if (dev->radio_rds_loop) { + v4l2_ctrl_lock(dev->radio_tx_rds_pi); + rds->picode = dev->radio_tx_rds_pi->cur.val; + rds->pty = dev->radio_tx_rds_pty->cur.val; + rds->mono_stereo = dev->radio_tx_rds_mono_stereo->cur.val; + rds->art_head = dev->radio_tx_rds_art_head->cur.val; + rds->compressed = dev->radio_tx_rds_compressed->cur.val; + rds->dyn_pty = dev->radio_tx_rds_dyn_pty->cur.val; + rds->ta = dev->radio_tx_rds_ta->cur.val; + rds->tp = dev->radio_tx_rds_tp->cur.val; + rds->ms = dev->radio_tx_rds_ms->cur.val; + strscpy(rds->psname, + dev->radio_tx_rds_psname->p_cur.p_char, + sizeof(rds->psname)); + strscpy(rds->radiotext, + dev->radio_tx_rds_radiotext->p_cur.p_char + alt * 64, + sizeof(rds->radiotext)); + v4l2_ctrl_unlock(dev->radio_tx_rds_pi); + } else { + vivid_rds_gen_fill(rds, dev->radio_rx_freq, alt); + } + if (dev->radio_rx_rds_controls) { + v4l2_ctrl_s_ctrl(dev->radio_rx_rds_pty, rds->pty); + v4l2_ctrl_s_ctrl(dev->radio_rx_rds_ta, rds->ta); + v4l2_ctrl_s_ctrl(dev->radio_rx_rds_tp, rds->tp); + v4l2_ctrl_s_ctrl(dev->radio_rx_rds_ms, rds->ms); + v4l2_ctrl_s_ctrl_string(dev->radio_rx_rds_psname, rds->psname); + v4l2_ctrl_s_ctrl_string(dev->radio_rx_rds_radiotext, rds->radiotext); + if (!dev->radio_rds_loop) + dev->radio_rx_rds_use_alternates = !dev->radio_rx_rds_use_alternates; + } + vivid_rds_generate(rds); +} + +/* + * Calculate the emulated signal quality taking into account the frequency + * the transmitter is using. + */ +static void vivid_radio_calc_sig_qual(struct vivid_dev *dev) +{ + int mod = 16000; + int delta = 800; + int sig_qual, sig_qual_tx = mod; + + /* + * For SW and FM there is a channel every 1000 kHz, for AM there is one + * every 100 kHz. + */ + if (dev->radio_rx_freq <= AM_FREQ_RANGE_HIGH) { + mod /= 10; + delta /= 10; + } + sig_qual = (dev->radio_rx_freq + delta) % mod - delta; + if (dev->has_radio_tx) + sig_qual_tx = dev->radio_rx_freq - dev->radio_tx_freq; + if (abs(sig_qual_tx) <= abs(sig_qual)) { + sig_qual = sig_qual_tx; + /* + * Zero the internal rds buffer if we are going to loop + * rds blocks. + */ + if (!dev->radio_rds_loop && !dev->radio_tx_rds_controls) + memset(dev->rds_gen.data, 0, + sizeof(dev->rds_gen.data)); + dev->radio_rds_loop = dev->radio_rx_freq >= FM_FREQ_RANGE_LOW; + } else { + dev->radio_rds_loop = false; + } + if (dev->radio_rx_freq <= AM_FREQ_RANGE_HIGH) + sig_qual *= 10; + dev->radio_rx_sig_qual = sig_qual; +} + +int vivid_radio_g_frequency(struct file *file, const unsigned *pfreq, struct v4l2_frequency *vf) +{ + if (vf->tuner != 0) + return -EINVAL; + vf->frequency = *pfreq; + return 0; +} + +int vivid_radio_s_frequency(struct file *file, unsigned *pfreq, const struct v4l2_frequency *vf) +{ + struct vivid_dev *dev = video_drvdata(file); + unsigned freq; + unsigned band; + + if (vf->tuner != 0) + return -EINVAL; + + if (vf->frequency >= (FM_FREQ_RANGE_LOW + SW_FREQ_RANGE_HIGH) / 2) + band = BAND_FM; + else if (vf->frequency <= (AM_FREQ_RANGE_HIGH + SW_FREQ_RANGE_LOW) / 2) + band = BAND_AM; + else + band = BAND_SW; + + freq = clamp_t(u32, vf->frequency, vivid_radio_bands[band].rangelow, + vivid_radio_bands[band].rangehigh); + *pfreq = freq; + + /* + * For both receiver and transmitter recalculate the signal quality + * (since that depends on both frequencies) and re-init the rds + * generator. + */ + vivid_radio_calc_sig_qual(dev); + vivid_radio_rds_init(dev); + return 0; +} diff --git a/drivers/media/test_drivers/vivid/vivid-radio-common.h b/drivers/media/test_drivers/vivid/vivid-radio-common.h new file mode 100644 index 000000000000..30a9900e5b2b --- /dev/null +++ b/drivers/media/test_drivers/vivid/vivid-radio-common.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * vivid-radio-common.h - common radio rx/tx support functions. + * + * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. + */ + +#ifndef _VIVID_RADIO_COMMON_H_ +#define _VIVID_RADIO_COMMON_H_ + +/* The supported radio frequency ranges in kHz */ +#define FM_FREQ_RANGE_LOW (64000U * 16U) +#define FM_FREQ_RANGE_HIGH (108000U * 16U) +#define AM_FREQ_RANGE_LOW (520U * 16U) +#define AM_FREQ_RANGE_HIGH (1710U * 16U) +#define SW_FREQ_RANGE_LOW (2300U * 16U) +#define SW_FREQ_RANGE_HIGH (26100U * 16U) + +enum { BAND_FM, BAND_AM, BAND_SW, TOT_BANDS }; + +extern const struct v4l2_frequency_band vivid_radio_bands[TOT_BANDS]; + +int vivid_radio_g_frequency(struct file *file, const unsigned *freq, struct v4l2_frequency *vf); +int vivid_radio_s_frequency(struct file *file, unsigned *freq, const struct v4l2_frequency *vf); + +void vivid_radio_rds_init(struct vivid_dev *dev); + +#endif diff --git a/drivers/media/test_drivers/vivid/vivid-radio-rx.c b/drivers/media/test_drivers/vivid/vivid-radio-rx.c new file mode 100644 index 000000000000..232cab508f48 --- /dev/null +++ b/drivers/media/test_drivers/vivid/vivid-radio-rx.c @@ -0,0 +1,278 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * vivid-radio-rx.c - radio receiver support functions. + * + * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "vivid-core.h" +#include "vivid-ctrls.h" +#include "vivid-radio-common.h" +#include "vivid-rds-gen.h" +#include "vivid-radio-rx.h" + +ssize_t vivid_radio_rx_read(struct file *file, char __user *buf, + size_t size, loff_t *offset) +{ + struct vivid_dev *dev = video_drvdata(file); + struct v4l2_rds_data *data = dev->rds_gen.data; + bool use_alternates; + ktime_t timestamp; + unsigned blk; + int perc; + int i; + + if (dev->radio_rx_rds_controls) + return -EINVAL; + if (size < sizeof(*data)) + return 0; + size = sizeof(*data) * (size / sizeof(*data)); + + if (mutex_lock_interruptible(&dev->mutex)) + return -ERESTARTSYS; + if (dev->radio_rx_rds_owner && + file->private_data != dev->radio_rx_rds_owner) { + mutex_unlock(&dev->mutex); + return -EBUSY; + } + if (dev->radio_rx_rds_owner == NULL) { + vivid_radio_rds_init(dev); + dev->radio_rx_rds_owner = file->private_data; + } + +retry: + timestamp = ktime_sub(ktime_get(), dev->radio_rds_init_time); + blk = ktime_divns(timestamp, VIVID_RDS_NSEC_PER_BLK); + use_alternates = (blk % VIVID_RDS_GEN_BLOCKS) & 1; + + if (dev->radio_rx_rds_last_block == 0 || + dev->radio_rx_rds_use_alternates != use_alternates) { + dev->radio_rx_rds_use_alternates = use_alternates; + /* Re-init the RDS generator */ + vivid_radio_rds_init(dev); + } + if (blk >= dev->radio_rx_rds_last_block + VIVID_RDS_GEN_BLOCKS) + dev->radio_rx_rds_last_block = blk - VIVID_RDS_GEN_BLOCKS + 1; + + /* + * No data is available if there hasn't been time to get new data, + * or if the RDS receiver has been disabled, or if we use the data + * from the RDS transmitter and that RDS transmitter has been disabled, + * or if the signal quality is too weak. + */ + if (blk == dev->radio_rx_rds_last_block || !dev->radio_rx_rds_enabled || + (dev->radio_rds_loop && !(dev->radio_tx_subchans & V4L2_TUNER_SUB_RDS)) || + abs(dev->radio_rx_sig_qual) > 200) { + mutex_unlock(&dev->mutex); + if (file->f_flags & O_NONBLOCK) + return -EWOULDBLOCK; + if (msleep_interruptible(20) && signal_pending(current)) + return -EINTR; + if (mutex_lock_interruptible(&dev->mutex)) + return -ERESTARTSYS; + goto retry; + } + + /* abs(dev->radio_rx_sig_qual) <= 200, map that to a 0-50% range */ + perc = abs(dev->radio_rx_sig_qual) / 4; + + for (i = 0; i < size && blk > dev->radio_rx_rds_last_block; + dev->radio_rx_rds_last_block++) { + unsigned data_blk = dev->radio_rx_rds_last_block % VIVID_RDS_GEN_BLOCKS; + struct v4l2_rds_data rds = data[data_blk]; + + if (data_blk == 0 && dev->radio_rds_loop) + vivid_radio_rds_init(dev); + if (perc && prandom_u32_max(100) < perc) { + switch (prandom_u32_max(4)) { + case 0: + rds.block |= V4L2_RDS_BLOCK_CORRECTED; + break; + case 1: + rds.block |= V4L2_RDS_BLOCK_INVALID; + break; + case 2: + rds.block |= V4L2_RDS_BLOCK_ERROR; + rds.lsb = prandom_u32_max(256); + rds.msb = prandom_u32_max(256); + break; + case 3: /* Skip block altogether */ + if (i) + continue; + /* + * Must make sure at least one block is + * returned, otherwise the application + * might think that end-of-file occurred. + */ + break; + } + } + if (copy_to_user(buf + i, &rds, sizeof(rds))) { + i = -EFAULT; + break; + } + i += sizeof(rds); + } + mutex_unlock(&dev->mutex); + return i; +} + +__poll_t vivid_radio_rx_poll(struct file *file, struct poll_table_struct *wait) +{ + return EPOLLIN | EPOLLRDNORM | v4l2_ctrl_poll(file, wait); +} + +int vivid_radio_rx_enum_freq_bands(struct file *file, void *fh, struct v4l2_frequency_band *band) +{ + if (band->tuner != 0) + return -EINVAL; + + if (band->index >= TOT_BANDS) + return -EINVAL; + + *band = vivid_radio_bands[band->index]; + return 0; +} + +int vivid_radio_rx_s_hw_freq_seek(struct file *file, void *fh, const struct v4l2_hw_freq_seek *a) +{ + struct vivid_dev *dev = video_drvdata(file); + unsigned low, high; + unsigned freq; + unsigned spacing; + unsigned band; + + if (a->tuner) + return -EINVAL; + if (a->wrap_around && dev->radio_rx_hw_seek_mode == VIVID_HW_SEEK_BOUNDED) + return -EINVAL; + + if (!a->wrap_around && dev->radio_rx_hw_seek_mode == VIVID_HW_SEEK_WRAP) + return -EINVAL; + if (!a->rangelow ^ !a->rangehigh) + return -EINVAL; + + if (file->f_flags & O_NONBLOCK) + return -EWOULDBLOCK; + + if (a->rangelow) { + for (band = 0; band < TOT_BANDS; band++) + if (a->rangelow >= vivid_radio_bands[band].rangelow && + a->rangehigh <= vivid_radio_bands[band].rangehigh) + break; + if (band == TOT_BANDS) + return -EINVAL; + if (!dev->radio_rx_hw_seek_prog_lim && + (a->rangelow != vivid_radio_bands[band].rangelow || + a->rangehigh != vivid_radio_bands[band].rangehigh)) + return -EINVAL; + low = a->rangelow; + high = a->rangehigh; + } else { + for (band = 0; band < TOT_BANDS; band++) + if (dev->radio_rx_freq >= vivid_radio_bands[band].rangelow && + dev->radio_rx_freq <= vivid_radio_bands[band].rangehigh) + break; + if (band == TOT_BANDS) + return -EINVAL; + low = vivid_radio_bands[band].rangelow; + high = vivid_radio_bands[band].rangehigh; + } + spacing = band == BAND_AM ? 1600 : 16000; + freq = clamp(dev->radio_rx_freq, low, high); + + if (a->seek_upward) { + freq = spacing * (freq / spacing) + spacing; + if (freq > high) { + if (!a->wrap_around) + return -ENODATA; + freq = spacing * (low / spacing) + spacing; + if (freq >= dev->radio_rx_freq) + return -ENODATA; + } + } else { + freq = spacing * ((freq + spacing - 1) / spacing) - spacing; + if (freq < low) { + if (!a->wrap_around) + return -ENODATA; + freq = spacing * ((high + spacing - 1) / spacing) - spacing; + if (freq <= dev->radio_rx_freq) + return -ENODATA; + } + } + return 0; +} + +int vivid_radio_rx_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt) +{ + struct vivid_dev *dev = video_drvdata(file); + int delta = 800; + int sig_qual; + + if (vt->index > 0) + return -EINVAL; + + strscpy(vt->name, "AM/FM/SW Receiver", sizeof(vt->name)); + vt->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO | + V4L2_TUNER_CAP_FREQ_BANDS | V4L2_TUNER_CAP_RDS | + (dev->radio_rx_rds_controls ? + V4L2_TUNER_CAP_RDS_CONTROLS : + V4L2_TUNER_CAP_RDS_BLOCK_IO) | + (dev->radio_rx_hw_seek_prog_lim ? + V4L2_TUNER_CAP_HWSEEK_PROG_LIM : 0); + switch (dev->radio_rx_hw_seek_mode) { + case VIVID_HW_SEEK_BOUNDED: + vt->capability |= V4L2_TUNER_CAP_HWSEEK_BOUNDED; + break; + case VIVID_HW_SEEK_WRAP: + vt->capability |= V4L2_TUNER_CAP_HWSEEK_WRAP; + break; + case VIVID_HW_SEEK_BOTH: + vt->capability |= V4L2_TUNER_CAP_HWSEEK_WRAP | + V4L2_TUNER_CAP_HWSEEK_BOUNDED; + break; + } + vt->rangelow = AM_FREQ_RANGE_LOW; + vt->rangehigh = FM_FREQ_RANGE_HIGH; + sig_qual = dev->radio_rx_sig_qual; + vt->signal = abs(sig_qual) > delta ? 0 : + 0xffff - ((unsigned)abs(sig_qual) * 0xffff) / delta; + vt->afc = sig_qual > delta ? 0 : sig_qual; + if (abs(sig_qual) > delta) + vt->rxsubchans = 0; + else if (dev->radio_rx_freq < FM_FREQ_RANGE_LOW || vt->signal < 0x8000) + vt->rxsubchans = V4L2_TUNER_SUB_MONO; + else if (dev->radio_rds_loop && !(dev->radio_tx_subchans & V4L2_TUNER_SUB_STEREO)) + vt->rxsubchans = V4L2_TUNER_SUB_MONO; + else + vt->rxsubchans = V4L2_TUNER_SUB_STEREO; + if (dev->radio_rx_rds_enabled && + (!dev->radio_rds_loop || (dev->radio_tx_subchans & V4L2_TUNER_SUB_RDS)) && + dev->radio_rx_freq >= FM_FREQ_RANGE_LOW && vt->signal >= 0xc000) + vt->rxsubchans |= V4L2_TUNER_SUB_RDS; + if (dev->radio_rx_rds_controls) + vivid_radio_rds_init(dev); + vt->audmode = dev->radio_rx_audmode; + return 0; +} + +int vivid_radio_rx_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *vt) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (vt->index) + return -EINVAL; + dev->radio_rx_audmode = vt->audmode >= V4L2_TUNER_MODE_STEREO; + return 0; +} diff --git a/drivers/media/test_drivers/vivid/vivid-radio-rx.h b/drivers/media/test_drivers/vivid/vivid-radio-rx.h new file mode 100644 index 000000000000..c9c7849f6f99 --- /dev/null +++ b/drivers/media/test_drivers/vivid/vivid-radio-rx.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * vivid-radio-rx.h - radio receiver support functions. + * + * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. + */ + +#ifndef _VIVID_RADIO_RX_H_ +#define _VIVID_RADIO_RX_H_ + +ssize_t vivid_radio_rx_read(struct file *, char __user *, size_t, loff_t *); +__poll_t vivid_radio_rx_poll(struct file *file, struct poll_table_struct *wait); + +int vivid_radio_rx_enum_freq_bands(struct file *file, void *fh, struct v4l2_frequency_band *band); +int vivid_radio_rx_s_hw_freq_seek(struct file *file, void *fh, const struct v4l2_hw_freq_seek *a); +int vivid_radio_rx_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt); +int vivid_radio_rx_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *vt); + +#endif diff --git a/drivers/media/test_drivers/vivid/vivid-radio-tx.c b/drivers/media/test_drivers/vivid/vivid-radio-tx.c new file mode 100644 index 000000000000..049d40b948bb --- /dev/null +++ b/drivers/media/test_drivers/vivid/vivid-radio-tx.c @@ -0,0 +1,128 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * vivid-radio-tx.c - radio transmitter support functions. + * + * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "vivid-core.h" +#include "vivid-ctrls.h" +#include "vivid-radio-common.h" +#include "vivid-radio-tx.h" + +ssize_t vivid_radio_tx_write(struct file *file, const char __user *buf, + size_t size, loff_t *offset) +{ + struct vivid_dev *dev = video_drvdata(file); + struct v4l2_rds_data *data = dev->rds_gen.data; + ktime_t timestamp; + unsigned blk; + int i; + + if (dev->radio_tx_rds_controls) + return -EINVAL; + + if (size < sizeof(*data)) + return -EINVAL; + size = sizeof(*data) * (size / sizeof(*data)); + + if (mutex_lock_interruptible(&dev->mutex)) + return -ERESTARTSYS; + if (dev->radio_tx_rds_owner && + file->private_data != dev->radio_tx_rds_owner) { + mutex_unlock(&dev->mutex); + return -EBUSY; + } + dev->radio_tx_rds_owner = file->private_data; + +retry: + timestamp = ktime_sub(ktime_get(), dev->radio_rds_init_time); + blk = ktime_divns(timestamp, VIVID_RDS_NSEC_PER_BLK); + if (blk - VIVID_RDS_GEN_BLOCKS >= dev->radio_tx_rds_last_block) + dev->radio_tx_rds_last_block = blk - VIVID_RDS_GEN_BLOCKS + 1; + + /* + * No data is available if there hasn't been time to get new data, + * or if the RDS receiver has been disabled, or if we use the data + * from the RDS transmitter and that RDS transmitter has been disabled, + * or if the signal quality is too weak. + */ + if (blk == dev->radio_tx_rds_last_block || + !(dev->radio_tx_subchans & V4L2_TUNER_SUB_RDS)) { + mutex_unlock(&dev->mutex); + if (file->f_flags & O_NONBLOCK) + return -EWOULDBLOCK; + if (msleep_interruptible(20) && signal_pending(current)) + return -EINTR; + if (mutex_lock_interruptible(&dev->mutex)) + return -ERESTARTSYS; + goto retry; + } + + for (i = 0; i < size && blk > dev->radio_tx_rds_last_block; + dev->radio_tx_rds_last_block++) { + unsigned data_blk = dev->radio_tx_rds_last_block % VIVID_RDS_GEN_BLOCKS; + struct v4l2_rds_data rds; + + if (copy_from_user(&rds, buf + i, sizeof(rds))) { + i = -EFAULT; + break; + } + i += sizeof(rds); + if (!dev->radio_rds_loop) + continue; + if ((rds.block & V4L2_RDS_BLOCK_MSK) == V4L2_RDS_BLOCK_INVALID || + (rds.block & V4L2_RDS_BLOCK_ERROR)) + continue; + rds.block &= V4L2_RDS_BLOCK_MSK; + data[data_blk] = rds; + } + mutex_unlock(&dev->mutex); + return i; +} + +__poll_t vivid_radio_tx_poll(struct file *file, struct poll_table_struct *wait) +{ + return EPOLLOUT | EPOLLWRNORM | v4l2_ctrl_poll(file, wait); +} + +int vidioc_g_modulator(struct file *file, void *fh, struct v4l2_modulator *a) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (a->index > 0) + return -EINVAL; + + strscpy(a->name, "AM/FM/SW Transmitter", sizeof(a->name)); + a->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO | + V4L2_TUNER_CAP_FREQ_BANDS | V4L2_TUNER_CAP_RDS | + (dev->radio_tx_rds_controls ? + V4L2_TUNER_CAP_RDS_CONTROLS : + V4L2_TUNER_CAP_RDS_BLOCK_IO); + a->rangelow = AM_FREQ_RANGE_LOW; + a->rangehigh = FM_FREQ_RANGE_HIGH; + a->txsubchans = dev->radio_tx_subchans; + return 0; +} + +int vidioc_s_modulator(struct file *file, void *fh, const struct v4l2_modulator *a) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (a->index) + return -EINVAL; + if (a->txsubchans & ~0x13) + return -EINVAL; + dev->radio_tx_subchans = a->txsubchans; + return 0; +} diff --git a/drivers/media/test_drivers/vivid/vivid-radio-tx.h b/drivers/media/test_drivers/vivid/vivid-radio-tx.h new file mode 100644 index 000000000000..c2bf1e7e634a --- /dev/null +++ b/drivers/media/test_drivers/vivid/vivid-radio-tx.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * vivid-radio-tx.h - radio transmitter support functions. + * + * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. + */ + +#ifndef _VIVID_RADIO_TX_H_ +#define _VIVID_RADIO_TX_H_ + +ssize_t vivid_radio_tx_write(struct file *, const char __user *, size_t, loff_t *); +__poll_t vivid_radio_tx_poll(struct file *file, struct poll_table_struct *wait); + +int vidioc_g_modulator(struct file *file, void *fh, struct v4l2_modulator *a); +int vidioc_s_modulator(struct file *file, void *fh, const struct v4l2_modulator *a); + +#endif diff --git a/drivers/media/test_drivers/vivid/vivid-rds-gen.c b/drivers/media/test_drivers/vivid/vivid-rds-gen.c new file mode 100644 index 000000000000..b5b104ee64c9 --- /dev/null +++ b/drivers/media/test_drivers/vivid/vivid-rds-gen.c @@ -0,0 +1,157 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * vivid-rds-gen.c - rds (radio data system) generator support functions. + * + * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. + */ + +#include +#include +#include +#include + +#include "vivid-rds-gen.h" + +static u8 vivid_get_di(const struct vivid_rds_gen *rds, unsigned grp) +{ + switch (grp) { + case 0: + return (rds->dyn_pty << 2) | (grp & 3); + case 1: + return (rds->compressed << 2) | (grp & 3); + case 2: + return (rds->art_head << 2) | (grp & 3); + case 3: + return (rds->mono_stereo << 2) | (grp & 3); + } + return 0; +} + +/* + * This RDS generator creates 57 RDS groups (one group == four RDS blocks). + * Groups 0-3, 22-25 and 44-47 (spaced 22 groups apart) are filled with a + * standard 0B group containing the PI code and PS name. + * + * Groups 4-19 and 26-41 use group 2A for the radio text. + * + * Group 56 contains the time (group 4A). + * + * All remaining groups use a filler group 15B block that just repeats + * the PI and PTY codes. + */ +void vivid_rds_generate(struct vivid_rds_gen *rds) +{ + struct v4l2_rds_data *data = rds->data; + unsigned grp; + unsigned idx; + struct tm tm; + unsigned date; + unsigned time; + int l; + + for (grp = 0; grp < VIVID_RDS_GEN_GROUPS; grp++, data += VIVID_RDS_GEN_BLKS_PER_GRP) { + data[0].lsb = rds->picode & 0xff; + data[0].msb = rds->picode >> 8; + data[0].block = V4L2_RDS_BLOCK_A | (V4L2_RDS_BLOCK_A << 3); + data[1].lsb = rds->pty << 5; + data[1].msb = (rds->pty >> 3) | (rds->tp << 2); + data[1].block = V4L2_RDS_BLOCK_B | (V4L2_RDS_BLOCK_B << 3); + data[3].block = V4L2_RDS_BLOCK_D | (V4L2_RDS_BLOCK_D << 3); + + switch (grp) { + case 0 ... 3: + case 22 ... 25: + case 44 ... 47: /* Group 0B */ + idx = (grp % 22) % 4; + data[1].lsb |= (rds->ta << 4) | (rds->ms << 3); + data[1].lsb |= vivid_get_di(rds, idx); + data[1].msb |= 1 << 3; + data[2].lsb = rds->picode & 0xff; + data[2].msb = rds->picode >> 8; + data[2].block = V4L2_RDS_BLOCK_C_ALT | (V4L2_RDS_BLOCK_C_ALT << 3); + data[3].lsb = rds->psname[2 * idx + 1]; + data[3].msb = rds->psname[2 * idx]; + break; + case 4 ... 19: + case 26 ... 41: /* Group 2A */ + idx = ((grp - 4) % 22) % 16; + data[1].lsb |= idx; + data[1].msb |= 4 << 3; + data[2].msb = rds->radiotext[4 * idx]; + data[2].lsb = rds->radiotext[4 * idx + 1]; + data[2].block = V4L2_RDS_BLOCK_C | (V4L2_RDS_BLOCK_C << 3); + data[3].msb = rds->radiotext[4 * idx + 2]; + data[3].lsb = rds->radiotext[4 * idx + 3]; + break; + case 56: + /* + * Group 4A + * + * Uses the algorithm from Annex G of the RDS standard + * EN 50067:1998 to convert a UTC date to an RDS Modified + * Julian Day. + */ + time64_to_tm(ktime_get_real_seconds(), 0, &tm); + l = tm.tm_mon <= 1; + date = 14956 + tm.tm_mday + ((tm.tm_year - l) * 1461) / 4 + + ((tm.tm_mon + 2 + l * 12) * 306001) / 10000; + time = (tm.tm_hour << 12) | + (tm.tm_min << 6) | + (sys_tz.tz_minuteswest >= 0 ? 0x20 : 0) | + (abs(sys_tz.tz_minuteswest) / 30); + data[1].lsb &= ~3; + data[1].lsb |= date >> 15; + data[1].msb |= 8 << 3; + data[2].lsb = (date << 1) & 0xfe; + data[2].lsb |= (time >> 16) & 1; + data[2].msb = (date >> 7) & 0xff; + data[2].block = V4L2_RDS_BLOCK_C | (V4L2_RDS_BLOCK_C << 3); + data[3].lsb = time & 0xff; + data[3].msb = (time >> 8) & 0xff; + break; + default: /* Group 15B */ + data[1].lsb |= (rds->ta << 4) | (rds->ms << 3); + data[1].lsb |= vivid_get_di(rds, grp % 22); + data[1].msb |= 0x1f << 3; + data[2].lsb = rds->picode & 0xff; + data[2].msb = rds->picode >> 8; + data[2].block = V4L2_RDS_BLOCK_C_ALT | (V4L2_RDS_BLOCK_C_ALT << 3); + data[3].lsb = rds->pty << 5; + data[3].lsb |= (rds->ta << 4) | (rds->ms << 3); + data[3].lsb |= vivid_get_di(rds, grp % 22); + data[3].msb |= rds->pty >> 3; + data[3].msb |= 0x1f << 3; + break; + } + } +} + +void vivid_rds_gen_fill(struct vivid_rds_gen *rds, unsigned freq, + bool alt) +{ + /* Alternate PTY between Info and Weather */ + if (rds->use_rbds) { + rds->picode = 0x2e75; /* 'KLNX' call sign */ + rds->pty = alt ? 29 : 2; + } else { + rds->picode = 0x8088; + rds->pty = alt ? 16 : 3; + } + rds->mono_stereo = true; + rds->art_head = false; + rds->compressed = false; + rds->dyn_pty = false; + rds->tp = true; + rds->ta = alt; + rds->ms = true; + snprintf(rds->psname, sizeof(rds->psname), "%6d.%1d", + freq / 16, ((freq & 0xf) * 10) / 16); + if (alt) + strscpy(rds->radiotext, + " The Radio Data System can switch between different Radio Texts ", + sizeof(rds->radiotext)); + else + strscpy(rds->radiotext, + "An example of Radio Text as transmitted by the Radio Data System", + sizeof(rds->radiotext)); +} diff --git a/drivers/media/test_drivers/vivid/vivid-rds-gen.h b/drivers/media/test_drivers/vivid/vivid-rds-gen.h new file mode 100644 index 000000000000..35ac5742302b --- /dev/null +++ b/drivers/media/test_drivers/vivid/vivid-rds-gen.h @@ -0,0 +1,42 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * vivid-rds-gen.h - rds (radio data system) generator support functions. + * + * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. + */ + +#ifndef _VIVID_RDS_GEN_H_ +#define _VIVID_RDS_GEN_H_ + +/* + * It takes almost exactly 5 seconds to transmit 57 RDS groups. + * Each group has 4 blocks and each block has a payload of 16 bits + a + * block identification. The driver will generate the contents of these + * 57 groups only when necessary and it will just be played continuously. + */ +#define VIVID_RDS_GEN_GROUPS 57 +#define VIVID_RDS_GEN_BLKS_PER_GRP 4 +#define VIVID_RDS_GEN_BLOCKS (VIVID_RDS_GEN_BLKS_PER_GRP * VIVID_RDS_GEN_GROUPS) +#define VIVID_RDS_NSEC_PER_BLK (u32)(5ull * NSEC_PER_SEC / VIVID_RDS_GEN_BLOCKS) + +struct vivid_rds_gen { + struct v4l2_rds_data data[VIVID_RDS_GEN_BLOCKS]; + bool use_rbds; + u16 picode; + u8 pty; + bool mono_stereo; + bool art_head; + bool compressed; + bool dyn_pty; + bool ta; + bool tp; + bool ms; + char psname[8 + 1]; + char radiotext[64 + 1]; +}; + +void vivid_rds_gen_fill(struct vivid_rds_gen *rds, unsigned freq, + bool use_alternate); +void vivid_rds_generate(struct vivid_rds_gen *rds); + +#endif diff --git a/drivers/media/test_drivers/vivid/vivid-sdr-cap.c b/drivers/media/test_drivers/vivid/vivid-sdr-cap.c new file mode 100644 index 000000000000..2b7522e16efc --- /dev/null +++ b/drivers/media/test_drivers/vivid/vivid-sdr-cap.c @@ -0,0 +1,570 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * vivid-sdr-cap.c - software defined radio support functions. + * + * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "vivid-core.h" +#include "vivid-ctrls.h" +#include "vivid-sdr-cap.h" + +/* stream formats */ +struct vivid_format { + u32 pixelformat; + u32 buffersize; +}; + +/* format descriptions for capture and preview */ +static const struct vivid_format formats[] = { + { + .pixelformat = V4L2_SDR_FMT_CU8, + .buffersize = SDR_CAP_SAMPLES_PER_BUF * 2, + }, { + .pixelformat = V4L2_SDR_FMT_CS8, + .buffersize = SDR_CAP_SAMPLES_PER_BUF * 2, + }, +}; + +static const struct v4l2_frequency_band bands_adc[] = { + { + .tuner = 0, + .type = V4L2_TUNER_ADC, + .index = 0, + .capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS, + .rangelow = 300000, + .rangehigh = 300000, + }, + { + .tuner = 0, + .type = V4L2_TUNER_ADC, + .index = 1, + .capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS, + .rangelow = 900001, + .rangehigh = 2800000, + }, + { + .tuner = 0, + .type = V4L2_TUNER_ADC, + .index = 2, + .capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS, + .rangelow = 3200000, + .rangehigh = 3200000, + }, +}; + +/* ADC band midpoints */ +#define BAND_ADC_0 ((bands_adc[0].rangehigh + bands_adc[1].rangelow) / 2) +#define BAND_ADC_1 ((bands_adc[1].rangehigh + bands_adc[2].rangelow) / 2) + +static const struct v4l2_frequency_band bands_fm[] = { + { + .tuner = 1, + .type = V4L2_TUNER_RF, + .index = 0, + .capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS, + .rangelow = 50000000, + .rangehigh = 2000000000, + }, +}; + +static void vivid_thread_sdr_cap_tick(struct vivid_dev *dev) +{ + struct vivid_buffer *sdr_cap_buf = NULL; + + dprintk(dev, 1, "SDR Capture Thread Tick\n"); + + /* Drop a certain percentage of buffers. */ + if (dev->perc_dropped_buffers && + prandom_u32_max(100) < dev->perc_dropped_buffers) + return; + + spin_lock(&dev->slock); + if (!list_empty(&dev->sdr_cap_active)) { + sdr_cap_buf = list_entry(dev->sdr_cap_active.next, + struct vivid_buffer, list); + list_del(&sdr_cap_buf->list); + } + spin_unlock(&dev->slock); + + if (sdr_cap_buf) { + sdr_cap_buf->vb.sequence = dev->sdr_cap_seq_count; + v4l2_ctrl_request_setup(sdr_cap_buf->vb.vb2_buf.req_obj.req, + &dev->ctrl_hdl_sdr_cap); + v4l2_ctrl_request_complete(sdr_cap_buf->vb.vb2_buf.req_obj.req, + &dev->ctrl_hdl_sdr_cap); + vivid_sdr_cap_process(dev, sdr_cap_buf); + sdr_cap_buf->vb.vb2_buf.timestamp = + ktime_get_ns() + dev->time_wrap_offset; + vb2_buffer_done(&sdr_cap_buf->vb.vb2_buf, dev->dqbuf_error ? + VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE); + dev->dqbuf_error = false; + } +} + +static int vivid_thread_sdr_cap(void *data) +{ + struct vivid_dev *dev = data; + u64 samples_since_start; + u64 buffers_since_start; + u64 next_jiffies_since_start; + unsigned long jiffies_since_start; + unsigned long cur_jiffies; + unsigned wait_jiffies; + + dprintk(dev, 1, "SDR Capture Thread Start\n"); + + set_freezable(); + + /* Resets frame counters */ + dev->sdr_cap_seq_offset = 0; + if (dev->seq_wrap) + dev->sdr_cap_seq_offset = 0xffffff80U; + dev->jiffies_sdr_cap = jiffies; + dev->sdr_cap_seq_resync = false; + + for (;;) { + try_to_freeze(); + if (kthread_should_stop()) + break; + + if (!mutex_trylock(&dev->mutex)) { + schedule_timeout_uninterruptible(1); + continue; + } + + cur_jiffies = jiffies; + if (dev->sdr_cap_seq_resync) { + dev->jiffies_sdr_cap = cur_jiffies; + dev->sdr_cap_seq_offset = dev->sdr_cap_seq_count + 1; + dev->sdr_cap_seq_count = 0; + dev->sdr_cap_seq_resync = false; + } + /* Calculate the number of jiffies since we started streaming */ + jiffies_since_start = cur_jiffies - dev->jiffies_sdr_cap; + /* Get the number of buffers streamed since the start */ + buffers_since_start = + (u64)jiffies_since_start * dev->sdr_adc_freq + + (HZ * SDR_CAP_SAMPLES_PER_BUF) / 2; + do_div(buffers_since_start, HZ * SDR_CAP_SAMPLES_PER_BUF); + + /* + * After more than 0xf0000000 (rounded down to a multiple of + * 'jiffies-per-day' to ease jiffies_to_msecs calculation) + * jiffies have passed since we started streaming reset the + * counters and keep track of the sequence offset. + */ + if (jiffies_since_start > JIFFIES_RESYNC) { + dev->jiffies_sdr_cap = cur_jiffies; + dev->sdr_cap_seq_offset = buffers_since_start; + buffers_since_start = 0; + } + dev->sdr_cap_seq_count = + buffers_since_start + dev->sdr_cap_seq_offset; + + vivid_thread_sdr_cap_tick(dev); + mutex_unlock(&dev->mutex); + + /* + * Calculate the number of samples streamed since we started, + * not including the current buffer. + */ + samples_since_start = buffers_since_start * SDR_CAP_SAMPLES_PER_BUF; + + /* And the number of jiffies since we started */ + jiffies_since_start = jiffies - dev->jiffies_sdr_cap; + + /* Increase by the number of samples in one buffer */ + samples_since_start += SDR_CAP_SAMPLES_PER_BUF; + /* + * Calculate when that next buffer is supposed to start + * in jiffies since we started streaming. + */ + next_jiffies_since_start = samples_since_start * HZ + + dev->sdr_adc_freq / 2; + do_div(next_jiffies_since_start, dev->sdr_adc_freq); + /* If it is in the past, then just schedule asap */ + if (next_jiffies_since_start < jiffies_since_start) + next_jiffies_since_start = jiffies_since_start; + + wait_jiffies = next_jiffies_since_start - jiffies_since_start; + schedule_timeout_interruptible(wait_jiffies ? wait_jiffies : 1); + } + dprintk(dev, 1, "SDR Capture Thread End\n"); + return 0; +} + +static int sdr_cap_queue_setup(struct vb2_queue *vq, + unsigned *nbuffers, unsigned *nplanes, + unsigned sizes[], struct device *alloc_devs[]) +{ + /* 2 = max 16-bit sample returned */ + sizes[0] = SDR_CAP_SAMPLES_PER_BUF * 2; + *nplanes = 1; + return 0; +} + +static int sdr_cap_buf_prepare(struct vb2_buffer *vb) +{ + struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); + unsigned size = SDR_CAP_SAMPLES_PER_BUF * 2; + + dprintk(dev, 1, "%s\n", __func__); + + if (dev->buf_prepare_error) { + /* + * Error injection: test what happens if buf_prepare() returns + * an error. + */ + dev->buf_prepare_error = false; + return -EINVAL; + } + if (vb2_plane_size(vb, 0) < size) { + dprintk(dev, 1, "%s data will not fit into plane (%lu < %u)\n", + __func__, vb2_plane_size(vb, 0), size); + return -EINVAL; + } + vb2_set_plane_payload(vb, 0, size); + + return 0; +} + +static void sdr_cap_buf_queue(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); + struct vivid_buffer *buf = container_of(vbuf, struct vivid_buffer, vb); + + dprintk(dev, 1, "%s\n", __func__); + + spin_lock(&dev->slock); + list_add_tail(&buf->list, &dev->sdr_cap_active); + spin_unlock(&dev->slock); +} + +static int sdr_cap_start_streaming(struct vb2_queue *vq, unsigned count) +{ + struct vivid_dev *dev = vb2_get_drv_priv(vq); + int err = 0; + + dprintk(dev, 1, "%s\n", __func__); + dev->sdr_cap_seq_count = 0; + if (dev->start_streaming_error) { + dev->start_streaming_error = false; + err = -EINVAL; + } else if (dev->kthread_sdr_cap == NULL) { + dev->kthread_sdr_cap = kthread_run(vivid_thread_sdr_cap, dev, + "%s-sdr-cap", dev->v4l2_dev.name); + + if (IS_ERR(dev->kthread_sdr_cap)) { + v4l2_err(&dev->v4l2_dev, "kernel_thread() failed\n"); + err = PTR_ERR(dev->kthread_sdr_cap); + dev->kthread_sdr_cap = NULL; + } + } + if (err) { + struct vivid_buffer *buf, *tmp; + + list_for_each_entry_safe(buf, tmp, &dev->sdr_cap_active, list) { + list_del(&buf->list); + vb2_buffer_done(&buf->vb.vb2_buf, + VB2_BUF_STATE_QUEUED); + } + } + return err; +} + +/* abort streaming and wait for last buffer */ +static void sdr_cap_stop_streaming(struct vb2_queue *vq) +{ + struct vivid_dev *dev = vb2_get_drv_priv(vq); + + if (dev->kthread_sdr_cap == NULL) + return; + + while (!list_empty(&dev->sdr_cap_active)) { + struct vivid_buffer *buf; + + buf = list_entry(dev->sdr_cap_active.next, + struct vivid_buffer, list); + list_del(&buf->list); + v4l2_ctrl_request_complete(buf->vb.vb2_buf.req_obj.req, + &dev->ctrl_hdl_sdr_cap); + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); + } + + /* shutdown control thread */ + kthread_stop(dev->kthread_sdr_cap); + dev->kthread_sdr_cap = NULL; +} + +static void sdr_cap_buf_request_complete(struct vb2_buffer *vb) +{ + struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); + + v4l2_ctrl_request_complete(vb->req_obj.req, &dev->ctrl_hdl_sdr_cap); +} + +const struct vb2_ops vivid_sdr_cap_qops = { + .queue_setup = sdr_cap_queue_setup, + .buf_prepare = sdr_cap_buf_prepare, + .buf_queue = sdr_cap_buf_queue, + .start_streaming = sdr_cap_start_streaming, + .stop_streaming = sdr_cap_stop_streaming, + .buf_request_complete = sdr_cap_buf_request_complete, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, +}; + +int vivid_sdr_enum_freq_bands(struct file *file, void *fh, + struct v4l2_frequency_band *band) +{ + switch (band->tuner) { + case 0: + if (band->index >= ARRAY_SIZE(bands_adc)) + return -EINVAL; + *band = bands_adc[band->index]; + return 0; + case 1: + if (band->index >= ARRAY_SIZE(bands_fm)) + return -EINVAL; + *band = bands_fm[band->index]; + return 0; + default: + return -EINVAL; + } +} + +int vivid_sdr_g_frequency(struct file *file, void *fh, + struct v4l2_frequency *vf) +{ + struct vivid_dev *dev = video_drvdata(file); + + switch (vf->tuner) { + case 0: + vf->frequency = dev->sdr_adc_freq; + vf->type = V4L2_TUNER_ADC; + return 0; + case 1: + vf->frequency = dev->sdr_fm_freq; + vf->type = V4L2_TUNER_RF; + return 0; + default: + return -EINVAL; + } +} + +int vivid_sdr_s_frequency(struct file *file, void *fh, + const struct v4l2_frequency *vf) +{ + struct vivid_dev *dev = video_drvdata(file); + unsigned freq = vf->frequency; + unsigned band; + + switch (vf->tuner) { + case 0: + if (vf->type != V4L2_TUNER_ADC) + return -EINVAL; + if (freq < BAND_ADC_0) + band = 0; + else if (freq < BAND_ADC_1) + band = 1; + else + band = 2; + + freq = clamp_t(unsigned, freq, + bands_adc[band].rangelow, + bands_adc[band].rangehigh); + + if (vb2_is_streaming(&dev->vb_sdr_cap_q) && + freq != dev->sdr_adc_freq) { + /* resync the thread's timings */ + dev->sdr_cap_seq_resync = true; + } + dev->sdr_adc_freq = freq; + return 0; + case 1: + if (vf->type != V4L2_TUNER_RF) + return -EINVAL; + dev->sdr_fm_freq = clamp_t(unsigned, freq, + bands_fm[0].rangelow, + bands_fm[0].rangehigh); + return 0; + default: + return -EINVAL; + } +} + +int vivid_sdr_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt) +{ + switch (vt->index) { + case 0: + strscpy(vt->name, "ADC", sizeof(vt->name)); + vt->type = V4L2_TUNER_ADC; + vt->capability = + V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS; + vt->rangelow = bands_adc[0].rangelow; + vt->rangehigh = bands_adc[2].rangehigh; + return 0; + case 1: + strscpy(vt->name, "RF", sizeof(vt->name)); + vt->type = V4L2_TUNER_RF; + vt->capability = + V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS; + vt->rangelow = bands_fm[0].rangelow; + vt->rangehigh = bands_fm[0].rangehigh; + return 0; + default: + return -EINVAL; + } +} + +int vivid_sdr_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *vt) +{ + if (vt->index > 1) + return -EINVAL; + return 0; +} + +int vidioc_enum_fmt_sdr_cap(struct file *file, void *fh, struct v4l2_fmtdesc *f) +{ + if (f->index >= ARRAY_SIZE(formats)) + return -EINVAL; + f->pixelformat = formats[f->index].pixelformat; + return 0; +} + +int vidioc_g_fmt_sdr_cap(struct file *file, void *fh, struct v4l2_format *f) +{ + struct vivid_dev *dev = video_drvdata(file); + + f->fmt.sdr.pixelformat = dev->sdr_pixelformat; + f->fmt.sdr.buffersize = dev->sdr_buffersize; + memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved)); + return 0; +} + +int vidioc_s_fmt_sdr_cap(struct file *file, void *fh, struct v4l2_format *f) +{ + struct vivid_dev *dev = video_drvdata(file); + struct vb2_queue *q = &dev->vb_sdr_cap_q; + int i; + + if (vb2_is_busy(q)) + return -EBUSY; + + memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved)); + for (i = 0; i < ARRAY_SIZE(formats); i++) { + if (formats[i].pixelformat == f->fmt.sdr.pixelformat) { + dev->sdr_pixelformat = formats[i].pixelformat; + dev->sdr_buffersize = formats[i].buffersize; + f->fmt.sdr.buffersize = formats[i].buffersize; + return 0; + } + } + dev->sdr_pixelformat = formats[0].pixelformat; + dev->sdr_buffersize = formats[0].buffersize; + f->fmt.sdr.pixelformat = formats[0].pixelformat; + f->fmt.sdr.buffersize = formats[0].buffersize; + return 0; +} + +int vidioc_try_fmt_sdr_cap(struct file *file, void *fh, struct v4l2_format *f) +{ + int i; + + memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved)); + for (i = 0; i < ARRAY_SIZE(formats); i++) { + if (formats[i].pixelformat == f->fmt.sdr.pixelformat) { + f->fmt.sdr.buffersize = formats[i].buffersize; + return 0; + } + } + f->fmt.sdr.pixelformat = formats[0].pixelformat; + f->fmt.sdr.buffersize = formats[0].buffersize; + return 0; +} + +#define FIXP_N (15) +#define FIXP_FRAC (1 << FIXP_N) +#define FIXP_2PI ((int)(2 * 3.141592653589 * FIXP_FRAC)) +#define M_100000PI (3.14159 * 100000) + +void vivid_sdr_cap_process(struct vivid_dev *dev, struct vivid_buffer *buf) +{ + u8 *vbuf = vb2_plane_vaddr(&buf->vb.vb2_buf, 0); + unsigned long i; + unsigned long plane_size = vb2_plane_size(&buf->vb.vb2_buf, 0); + s64 s64tmp; + s32 src_phase_step; + s32 mod_phase_step; + s32 fixp_i; + s32 fixp_q; + + /* calculate phase step */ + #define BEEP_FREQ 1000 /* 1kHz beep */ + src_phase_step = DIV_ROUND_CLOSEST(FIXP_2PI * BEEP_FREQ, + dev->sdr_adc_freq); + + for (i = 0; i < plane_size; i += 2) { + mod_phase_step = fixp_cos32_rad(dev->sdr_fixp_src_phase, + FIXP_2PI) >> (31 - FIXP_N); + + dev->sdr_fixp_src_phase += src_phase_step; + s64tmp = (s64) mod_phase_step * dev->sdr_fm_deviation; + dev->sdr_fixp_mod_phase += div_s64(s64tmp, M_100000PI); + + /* + * Transfer phase angle to [0, 2xPI] in order to avoid variable + * overflow and make it suitable for cosine implementation + * used, which does not support negative angles. + */ + dev->sdr_fixp_src_phase %= FIXP_2PI; + dev->sdr_fixp_mod_phase %= FIXP_2PI; + + if (dev->sdr_fixp_mod_phase < 0) + dev->sdr_fixp_mod_phase += FIXP_2PI; + + fixp_i = fixp_cos32_rad(dev->sdr_fixp_mod_phase, FIXP_2PI); + fixp_q = fixp_sin32_rad(dev->sdr_fixp_mod_phase, FIXP_2PI); + + /* Normalize fraction values represented with 32 bit precision + * to fixed point representation with FIXP_N bits */ + fixp_i >>= (31 - FIXP_N); + fixp_q >>= (31 - FIXP_N); + + switch (dev->sdr_pixelformat) { + case V4L2_SDR_FMT_CU8: + /* convert 'fixp float' to u8 [0, +255] */ + /* u8 = X * 127.5 + 127.5; X is float [-1.0, +1.0] */ + fixp_i = fixp_i * 1275 + FIXP_FRAC * 1275; + fixp_q = fixp_q * 1275 + FIXP_FRAC * 1275; + *vbuf++ = DIV_ROUND_CLOSEST(fixp_i, FIXP_FRAC * 10); + *vbuf++ = DIV_ROUND_CLOSEST(fixp_q, FIXP_FRAC * 10); + break; + case V4L2_SDR_FMT_CS8: + /* convert 'fixp float' to s8 [-128, +127] */ + /* s8 = X * 127.5 - 0.5; X is float [-1.0, +1.0] */ + fixp_i = fixp_i * 1275 - FIXP_FRAC * 5; + fixp_q = fixp_q * 1275 - FIXP_FRAC * 5; + *vbuf++ = DIV_ROUND_CLOSEST(fixp_i, FIXP_FRAC * 10); + *vbuf++ = DIV_ROUND_CLOSEST(fixp_q, FIXP_FRAC * 10); + break; + default: + break; + } + } +} diff --git a/drivers/media/test_drivers/vivid/vivid-sdr-cap.h b/drivers/media/test_drivers/vivid/vivid-sdr-cap.h new file mode 100644 index 000000000000..813c9248e5a7 --- /dev/null +++ b/drivers/media/test_drivers/vivid/vivid-sdr-cap.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * vivid-sdr-cap.h - software defined radio support functions. + * + * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. + */ + +#ifndef _VIVID_SDR_CAP_H_ +#define _VIVID_SDR_CAP_H_ + +int vivid_sdr_enum_freq_bands(struct file *file, void *fh, struct v4l2_frequency_band *band); +int vivid_sdr_g_frequency(struct file *file, void *fh, struct v4l2_frequency *vf); +int vivid_sdr_s_frequency(struct file *file, void *fh, const struct v4l2_frequency *vf); +int vivid_sdr_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt); +int vivid_sdr_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *vt); +int vidioc_enum_fmt_sdr_cap(struct file *file, void *fh, struct v4l2_fmtdesc *f); +int vidioc_g_fmt_sdr_cap(struct file *file, void *fh, struct v4l2_format *f); +int vidioc_s_fmt_sdr_cap(struct file *file, void *fh, struct v4l2_format *f); +int vidioc_try_fmt_sdr_cap(struct file *file, void *fh, struct v4l2_format *f); +void vivid_sdr_cap_process(struct vivid_dev *dev, struct vivid_buffer *buf); + +extern const struct vb2_ops vivid_sdr_cap_qops; + +#endif diff --git a/drivers/media/test_drivers/vivid/vivid-touch-cap.c b/drivers/media/test_drivers/vivid/vivid-touch-cap.c new file mode 100644 index 000000000000..ebb00b128030 --- /dev/null +++ b/drivers/media/test_drivers/vivid/vivid-touch-cap.c @@ -0,0 +1,341 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * vivid-touch-cap.c - touch support functions. + */ + +#include "vivid-core.h" +#include "vivid-kthread-touch.h" +#include "vivid-vid-common.h" +#include "vivid-touch-cap.h" + +static int touch_cap_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, + unsigned int *nplanes, unsigned int sizes[], + struct device *alloc_devs[]) +{ + struct vivid_dev *dev = vb2_get_drv_priv(vq); + struct v4l2_pix_format *f = &dev->tch_format; + unsigned int size = f->sizeimage; + + if (*nplanes) { + if (sizes[0] < size) + return -EINVAL; + } else { + sizes[0] = size; + } + + if (vq->num_buffers + *nbuffers < 2) + *nbuffers = 2 - vq->num_buffers; + + *nplanes = 1; + return 0; +} + +static int touch_cap_buf_prepare(struct vb2_buffer *vb) +{ + struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); + struct v4l2_pix_format *f = &dev->tch_format; + unsigned int size = f->sizeimage; + + if (dev->buf_prepare_error) { + /* + * Error injection: test what happens if buf_prepare() returns + * an error. + */ + dev->buf_prepare_error = false; + return -EINVAL; + } + if (vb2_plane_size(vb, 0) < size) { + dprintk(dev, 1, "%s data will not fit into plane (%lu < %u)\n", + __func__, vb2_plane_size(vb, 0), size); + return -EINVAL; + } + vb2_set_plane_payload(vb, 0, size); + + return 0; +} + +static void touch_cap_buf_queue(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); + struct vivid_buffer *buf = container_of(vbuf, struct vivid_buffer, vb); + + vbuf->field = V4L2_FIELD_NONE; + spin_lock(&dev->slock); + list_add_tail(&buf->list, &dev->touch_cap_active); + spin_unlock(&dev->slock); +} + +static int touch_cap_start_streaming(struct vb2_queue *vq, unsigned int count) +{ + struct vivid_dev *dev = vb2_get_drv_priv(vq); + int err; + + dev->touch_cap_seq_count = 0; + if (dev->start_streaming_error) { + dev->start_streaming_error = false; + err = -EINVAL; + } else { + err = vivid_start_generating_touch_cap(dev); + } + if (err) { + struct vivid_buffer *buf, *tmp; + + list_for_each_entry_safe(buf, tmp, + &dev->touch_cap_active, list) { + list_del(&buf->list); + vb2_buffer_done(&buf->vb.vb2_buf, + VB2_BUF_STATE_QUEUED); + } + } + return err; +} + +/* abort streaming and wait for last buffer */ +static void touch_cap_stop_streaming(struct vb2_queue *vq) +{ + struct vivid_dev *dev = vb2_get_drv_priv(vq); + + vivid_stop_generating_touch_cap(dev); +} + +static void touch_cap_buf_request_complete(struct vb2_buffer *vb) +{ + struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); + + v4l2_ctrl_request_complete(vb->req_obj.req, &dev->ctrl_hdl_touch_cap); +} + +const struct vb2_ops vivid_touch_cap_qops = { + .queue_setup = touch_cap_queue_setup, + .buf_prepare = touch_cap_buf_prepare, + .buf_queue = touch_cap_buf_queue, + .start_streaming = touch_cap_start_streaming, + .stop_streaming = touch_cap_stop_streaming, + .buf_request_complete = touch_cap_buf_request_complete, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, +}; + +int vivid_enum_fmt_tch(struct file *file, void *priv, struct v4l2_fmtdesc *f) +{ + if (f->index) + return -EINVAL; + + f->pixelformat = V4L2_TCH_FMT_DELTA_TD16; + return 0; +} + +int vivid_g_fmt_tch(struct file *file, void *priv, struct v4l2_format *f) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (dev->multiplanar) + return -ENOTTY; + f->fmt.pix = dev->tch_format; + return 0; +} + +int vivid_g_fmt_tch_mplane(struct file *file, void *priv, struct v4l2_format *f) +{ + struct vivid_dev *dev = video_drvdata(file); + struct v4l2_format sp_fmt; + + if (!dev->multiplanar) + return -ENOTTY; + sp_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + sp_fmt.fmt.pix = dev->tch_format; + fmt_sp2mp(&sp_fmt, f); + return 0; +} + +int vivid_g_parm_tch(struct file *file, void *priv, + struct v4l2_streamparm *parm) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (parm->type != (dev->multiplanar ? + V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE : + V4L2_BUF_TYPE_VIDEO_CAPTURE)) + return -EINVAL; + + parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; + parm->parm.capture.timeperframe = dev->timeperframe_tch_cap; + parm->parm.capture.readbuffers = 1; + return 0; +} + +int vivid_enum_input_tch(struct file *file, void *priv, struct v4l2_input *inp) +{ + if (inp->index) + return -EINVAL; + + inp->type = V4L2_INPUT_TYPE_TOUCH; + strscpy(inp->name, "Vivid Touch", sizeof(inp->name)); + inp->capabilities = 0; + return 0; +} + +int vivid_g_input_tch(struct file *file, void *priv, unsigned int *i) +{ + *i = 0; + return 0; +} + +int vivid_set_touch(struct vivid_dev *dev, unsigned int i) +{ + struct v4l2_pix_format *f = &dev->tch_format; + + if (i) + return -EINVAL; + + f->pixelformat = V4L2_TCH_FMT_DELTA_TD16; + f->width = VIVID_TCH_WIDTH; + f->height = VIVID_TCH_HEIGHT; + f->field = V4L2_FIELD_NONE; + f->colorspace = V4L2_COLORSPACE_RAW; + f->bytesperline = f->width * sizeof(s16); + f->sizeimage = f->width * f->height * sizeof(s16); + return 0; +} + +int vivid_s_input_tch(struct file *file, void *priv, unsigned int i) +{ + return vivid_set_touch(video_drvdata(file), i); +} + +static void vivid_fill_buff_noise(__s16 *tch_buf, int size) +{ + int i; + + /* Fill 10% of the values within range -3 and 3, zero the others */ + for (i = 0; i < size; i++) { + unsigned int rand = get_random_int(); + + if (rand % 10) + tch_buf[i] = 0; + else + tch_buf[i] = (rand / 10) % 7 - 3; + } +} + +static inline int get_random_pressure(void) +{ + return get_random_int() % VIVID_PRESSURE_LIMIT; +} + +static void vivid_tch_buf_set(struct v4l2_pix_format *f, + __s16 *tch_buf, + int index) +{ + unsigned int x = index % f->width; + unsigned int y = index / f->width; + unsigned int offset = VIVID_MIN_PRESSURE; + + tch_buf[index] = offset + get_random_pressure(); + offset /= 2; + if (x) + tch_buf[index - 1] = offset + get_random_pressure(); + if (x < f->width - 1) + tch_buf[index + 1] = offset + get_random_pressure(); + if (y) + tch_buf[index - f->width] = offset + get_random_pressure(); + if (y < f->height - 1) + tch_buf[index + f->width] = offset + get_random_pressure(); + offset /= 2; + if (x && y) + tch_buf[index - 1 - f->width] = offset + get_random_pressure(); + if (x < f->width - 1 && y) + tch_buf[index + 1 - f->width] = offset + get_random_pressure(); + if (x && y < f->height - 1) + tch_buf[index - 1 + f->width] = offset + get_random_pressure(); + if (x < f->width - 1 && y < f->height - 1) + tch_buf[index + 1 + f->width] = offset + get_random_pressure(); +} + +void vivid_fillbuff_tch(struct vivid_dev *dev, struct vivid_buffer *buf) +{ + struct v4l2_pix_format *f = &dev->tch_format; + int size = f->width * f->height; + int x, y, xstart, ystart, offset_x, offset_y; + unsigned int test_pattern, test_pat_idx, rand; + + __s16 *tch_buf = vb2_plane_vaddr(&buf->vb.vb2_buf, 0); + + buf->vb.sequence = dev->touch_cap_seq_count; + test_pattern = (buf->vb.sequence / TCH_SEQ_COUNT) % TEST_CASE_MAX; + test_pat_idx = buf->vb.sequence % TCH_SEQ_COUNT; + + vivid_fill_buff_noise(tch_buf, size); + + if (test_pat_idx >= TCH_PATTERN_COUNT) + return; + + if (test_pat_idx == 0) + dev->tch_pat_random = get_random_int(); + rand = dev->tch_pat_random; + + switch (test_pattern) { + case SINGLE_TAP: + if (test_pat_idx == 2) + vivid_tch_buf_set(f, tch_buf, rand % size); + break; + case DOUBLE_TAP: + if (test_pat_idx == 2 || test_pat_idx == 4) + vivid_tch_buf_set(f, tch_buf, rand % size); + break; + case TRIPLE_TAP: + if (test_pat_idx == 2 || test_pat_idx == 4 || test_pat_idx == 6) + vivid_tch_buf_set(f, tch_buf, rand % size); + break; + case MOVE_LEFT_TO_RIGHT: + vivid_tch_buf_set(f, tch_buf, + (rand % f->height) * f->width + + test_pat_idx * + (f->width / TCH_PATTERN_COUNT)); + break; + case ZOOM_IN: + x = f->width / 2; + y = f->height / 2; + offset_x = ((TCH_PATTERN_COUNT - 1 - test_pat_idx) * x) / + TCH_PATTERN_COUNT; + offset_y = ((TCH_PATTERN_COUNT - 1 - test_pat_idx) * y) / + TCH_PATTERN_COUNT; + vivid_tch_buf_set(f, tch_buf, + (x - offset_x) + f->width * (y - offset_y)); + vivid_tch_buf_set(f, tch_buf, + (x + offset_x) + f->width * (y + offset_y)); + break; + case ZOOM_OUT: + x = f->width / 2; + y = f->height / 2; + offset_x = (test_pat_idx * x) / TCH_PATTERN_COUNT; + offset_y = (test_pat_idx * y) / TCH_PATTERN_COUNT; + vivid_tch_buf_set(f, tch_buf, + (x - offset_x) + f->width * (y - offset_y)); + vivid_tch_buf_set(f, tch_buf, + (x + offset_x) + f->width * (y + offset_y)); + break; + case PALM_PRESS: + for (x = 0; x < f->width; x++) + for (y = f->height / 2; y < f->height; y++) + tch_buf[x + f->width * y] = VIVID_MIN_PRESSURE + + get_random_pressure(); + break; + case MULTIPLE_PRESS: + /* 16 pressure points */ + for (y = 0; y < 4; y++) { + for (x = 0; x < 4; x++) { + ystart = (y * f->height) / 4 + f->height / 8; + xstart = (x * f->width) / 4 + f->width / 8; + vivid_tch_buf_set(f, tch_buf, + ystart * f->width + xstart); + } + } + break; + } +#ifdef __BIG_ENDIAN__ + for (x = 0; x < size; x++) + tch_buf[x] = (__force s16)__cpu_to_le16((u16)tch_buf[x]); +#endif +} diff --git a/drivers/media/test_drivers/vivid/vivid-touch-cap.h b/drivers/media/test_drivers/vivid/vivid-touch-cap.h new file mode 100644 index 000000000000..07e514046ae8 --- /dev/null +++ b/drivers/media/test_drivers/vivid/vivid-touch-cap.h @@ -0,0 +1,39 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * vivid-touch-cap.h - touch support functions. + */ +#ifndef _VIVID_TOUCH_CAP_H_ +#define _VIVID_TOUCH_CAP_H_ + +#define VIVID_TCH_HEIGHT 12 +#define VIVID_TCH_WIDTH 21 +#define VIVID_MIN_PRESSURE 180 +#define VIVID_PRESSURE_LIMIT 40 +#define TCH_SEQ_COUNT 16 +#define TCH_PATTERN_COUNT 12 + +enum vivid_tch_test { + SINGLE_TAP, + DOUBLE_TAP, + TRIPLE_TAP, + MOVE_LEFT_TO_RIGHT, + ZOOM_IN, + ZOOM_OUT, + PALM_PRESS, + MULTIPLE_PRESS, + TEST_CASE_MAX +}; + +extern const struct vb2_ops vivid_touch_cap_qops; + +int vivid_enum_fmt_tch(struct file *file, void *priv, struct v4l2_fmtdesc *f); +int vivid_g_fmt_tch(struct file *file, void *priv, struct v4l2_format *f); +int vivid_g_fmt_tch_mplane(struct file *file, void *priv, struct v4l2_format *f); +int vivid_enum_input_tch(struct file *file, void *priv, struct v4l2_input *inp); +int vivid_g_input_tch(struct file *file, void *priv, unsigned int *i); +int vivid_s_input_tch(struct file *file, void *priv, unsigned int i); +void vivid_fillbuff_tch(struct vivid_dev *dev, struct vivid_buffer *buf); +int vivid_set_touch(struct vivid_dev *dev, unsigned int i); +int vivid_g_parm_tch(struct file *file, void *priv, + struct v4l2_streamparm *parm); +#endif diff --git a/drivers/media/test_drivers/vivid/vivid-vbi-cap.c b/drivers/media/test_drivers/vivid/vivid-vbi-cap.c new file mode 100644 index 000000000000..1a9348eea781 --- /dev/null +++ b/drivers/media/test_drivers/vivid/vivid-vbi-cap.c @@ -0,0 +1,365 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * vivid-vbi-cap.c - vbi capture support functions. + * + * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. + */ + +#include +#include +#include +#include + +#include "vivid-core.h" +#include "vivid-kthread-cap.h" +#include "vivid-vbi-cap.h" +#include "vivid-vbi-gen.h" + +static void vivid_sliced_vbi_cap_fill(struct vivid_dev *dev, unsigned seqnr) +{ + struct vivid_vbi_gen_data *vbi_gen = &dev->vbi_gen; + bool is_60hz = dev->std_cap[dev->input] & V4L2_STD_525_60; + + vivid_vbi_gen_sliced(vbi_gen, is_60hz, seqnr); + + if (!is_60hz) { + if (dev->loop_video) { + if (dev->vbi_out_have_wss) { + vbi_gen->data[12].data[0] = dev->vbi_out_wss[0]; + vbi_gen->data[12].data[1] = dev->vbi_out_wss[1]; + } else { + vbi_gen->data[12].id = 0; + } + } else { + switch (tpg_g_video_aspect(&dev->tpg)) { + case TPG_VIDEO_ASPECT_14X9_CENTRE: + vbi_gen->data[12].data[0] = 0x01; + break; + case TPG_VIDEO_ASPECT_16X9_CENTRE: + vbi_gen->data[12].data[0] = 0x0b; + break; + case TPG_VIDEO_ASPECT_16X9_ANAMORPHIC: + vbi_gen->data[12].data[0] = 0x07; + break; + case TPG_VIDEO_ASPECT_4X3: + default: + vbi_gen->data[12].data[0] = 0x08; + break; + } + } + } else if (dev->loop_video && is_60hz) { + if (dev->vbi_out_have_cc[0]) { + vbi_gen->data[0].data[0] = dev->vbi_out_cc[0][0]; + vbi_gen->data[0].data[1] = dev->vbi_out_cc[0][1]; + } else { + vbi_gen->data[0].id = 0; + } + if (dev->vbi_out_have_cc[1]) { + vbi_gen->data[1].data[0] = dev->vbi_out_cc[1][0]; + vbi_gen->data[1].data[1] = dev->vbi_out_cc[1][1]; + } else { + vbi_gen->data[1].id = 0; + } + } +} + +static void vivid_g_fmt_vbi_cap(struct vivid_dev *dev, struct v4l2_vbi_format *vbi) +{ + bool is_60hz = dev->std_cap[dev->input] & V4L2_STD_525_60; + + vbi->sampling_rate = 27000000; + vbi->offset = 24; + vbi->samples_per_line = 1440; + vbi->sample_format = V4L2_PIX_FMT_GREY; + vbi->start[0] = is_60hz ? V4L2_VBI_ITU_525_F1_START + 9 : V4L2_VBI_ITU_625_F1_START + 5; + vbi->start[1] = is_60hz ? V4L2_VBI_ITU_525_F2_START + 9 : V4L2_VBI_ITU_625_F2_START + 5; + vbi->count[0] = vbi->count[1] = is_60hz ? 12 : 18; + vbi->flags = dev->vbi_cap_interlaced ? V4L2_VBI_INTERLACED : 0; + vbi->reserved[0] = 0; + vbi->reserved[1] = 0; +} + +void vivid_raw_vbi_cap_process(struct vivid_dev *dev, struct vivid_buffer *buf) +{ + struct v4l2_vbi_format vbi; + u8 *vbuf = vb2_plane_vaddr(&buf->vb.vb2_buf, 0); + + vivid_g_fmt_vbi_cap(dev, &vbi); + buf->vb.sequence = dev->vbi_cap_seq_count; + if (dev->field_cap == V4L2_FIELD_ALTERNATE) + buf->vb.sequence /= 2; + + vivid_sliced_vbi_cap_fill(dev, buf->vb.sequence); + + memset(vbuf, 0x10, vb2_plane_size(&buf->vb.vb2_buf, 0)); + + if (!VIVID_INVALID_SIGNAL(dev->std_signal_mode[dev->input])) + vivid_vbi_gen_raw(&dev->vbi_gen, &vbi, vbuf); +} + + +void vivid_sliced_vbi_cap_process(struct vivid_dev *dev, + struct vivid_buffer *buf) +{ + struct v4l2_sliced_vbi_data *vbuf = + vb2_plane_vaddr(&buf->vb.vb2_buf, 0); + + buf->vb.sequence = dev->vbi_cap_seq_count; + if (dev->field_cap == V4L2_FIELD_ALTERNATE) + buf->vb.sequence /= 2; + + vivid_sliced_vbi_cap_fill(dev, buf->vb.sequence); + + memset(vbuf, 0, vb2_plane_size(&buf->vb.vb2_buf, 0)); + if (!VIVID_INVALID_SIGNAL(dev->std_signal_mode[dev->input])) { + unsigned i; + + for (i = 0; i < 25; i++) + vbuf[i] = dev->vbi_gen.data[i]; + } +} + +static int vbi_cap_queue_setup(struct vb2_queue *vq, + unsigned *nbuffers, unsigned *nplanes, + unsigned sizes[], struct device *alloc_devs[]) +{ + struct vivid_dev *dev = vb2_get_drv_priv(vq); + bool is_60hz = dev->std_cap[dev->input] & V4L2_STD_525_60; + unsigned size = vq->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE ? + 36 * sizeof(struct v4l2_sliced_vbi_data) : + 1440 * 2 * (is_60hz ? 12 : 18); + + if (!vivid_is_sdtv_cap(dev)) + return -EINVAL; + + sizes[0] = size; + + if (vq->num_buffers + *nbuffers < 2) + *nbuffers = 2 - vq->num_buffers; + + *nplanes = 1; + return 0; +} + +static int vbi_cap_buf_prepare(struct vb2_buffer *vb) +{ + struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); + bool is_60hz = dev->std_cap[dev->input] & V4L2_STD_525_60; + unsigned size = vb->vb2_queue->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE ? + 36 * sizeof(struct v4l2_sliced_vbi_data) : + 1440 * 2 * (is_60hz ? 12 : 18); + + dprintk(dev, 1, "%s\n", __func__); + + if (dev->buf_prepare_error) { + /* + * Error injection: test what happens if buf_prepare() returns + * an error. + */ + dev->buf_prepare_error = false; + return -EINVAL; + } + if (vb2_plane_size(vb, 0) < size) { + dprintk(dev, 1, "%s data will not fit into plane (%lu < %u)\n", + __func__, vb2_plane_size(vb, 0), size); + return -EINVAL; + } + vb2_set_plane_payload(vb, 0, size); + + return 0; +} + +static void vbi_cap_buf_queue(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); + struct vivid_buffer *buf = container_of(vbuf, struct vivid_buffer, vb); + + dprintk(dev, 1, "%s\n", __func__); + + spin_lock(&dev->slock); + list_add_tail(&buf->list, &dev->vbi_cap_active); + spin_unlock(&dev->slock); +} + +static int vbi_cap_start_streaming(struct vb2_queue *vq, unsigned count) +{ + struct vivid_dev *dev = vb2_get_drv_priv(vq); + int err; + + dprintk(dev, 1, "%s\n", __func__); + dev->vbi_cap_seq_count = 0; + if (dev->start_streaming_error) { + dev->start_streaming_error = false; + err = -EINVAL; + } else { + err = vivid_start_generating_vid_cap(dev, &dev->vbi_cap_streaming); + } + if (err) { + struct vivid_buffer *buf, *tmp; + + list_for_each_entry_safe(buf, tmp, &dev->vbi_cap_active, list) { + list_del(&buf->list); + vb2_buffer_done(&buf->vb.vb2_buf, + VB2_BUF_STATE_QUEUED); + } + } + return err; +} + +/* abort streaming and wait for last buffer */ +static void vbi_cap_stop_streaming(struct vb2_queue *vq) +{ + struct vivid_dev *dev = vb2_get_drv_priv(vq); + + dprintk(dev, 1, "%s\n", __func__); + vivid_stop_generating_vid_cap(dev, &dev->vbi_cap_streaming); +} + +static void vbi_cap_buf_request_complete(struct vb2_buffer *vb) +{ + struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); + + v4l2_ctrl_request_complete(vb->req_obj.req, &dev->ctrl_hdl_vbi_cap); +} + +const struct vb2_ops vivid_vbi_cap_qops = { + .queue_setup = vbi_cap_queue_setup, + .buf_prepare = vbi_cap_buf_prepare, + .buf_queue = vbi_cap_buf_queue, + .start_streaming = vbi_cap_start_streaming, + .stop_streaming = vbi_cap_stop_streaming, + .buf_request_complete = vbi_cap_buf_request_complete, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, +}; + +int vidioc_g_fmt_vbi_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct vivid_dev *dev = video_drvdata(file); + struct v4l2_vbi_format *vbi = &f->fmt.vbi; + + if (!vivid_is_sdtv_cap(dev) || !dev->has_raw_vbi_cap) + return -EINVAL; + + vivid_g_fmt_vbi_cap(dev, vbi); + return 0; +} + +int vidioc_s_fmt_vbi_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct vivid_dev *dev = video_drvdata(file); + int ret = vidioc_g_fmt_vbi_cap(file, priv, f); + + if (ret) + return ret; + if (dev->stream_sliced_vbi_cap && vb2_is_busy(&dev->vb_vbi_cap_q)) + return -EBUSY; + dev->stream_sliced_vbi_cap = false; + dev->vbi_cap_dev.queue->type = V4L2_BUF_TYPE_VBI_CAPTURE; + return 0; +} + +void vivid_fill_service_lines(struct v4l2_sliced_vbi_format *vbi, u32 service_set) +{ + vbi->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36; + vbi->service_set = service_set; + memset(vbi->service_lines, 0, sizeof(vbi->service_lines)); + memset(vbi->reserved, 0, sizeof(vbi->reserved)); + + if (vbi->service_set == 0) + return; + + if (vbi->service_set & V4L2_SLICED_CAPTION_525) { + vbi->service_lines[0][21] = V4L2_SLICED_CAPTION_525; + vbi->service_lines[1][21] = V4L2_SLICED_CAPTION_525; + } + if (vbi->service_set & V4L2_SLICED_WSS_625) { + unsigned i; + + for (i = 7; i <= 18; i++) + vbi->service_lines[0][i] = + vbi->service_lines[1][i] = V4L2_SLICED_TELETEXT_B; + vbi->service_lines[0][23] = V4L2_SLICED_WSS_625; + } +} + +int vidioc_g_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) +{ + struct vivid_dev *dev = video_drvdata(file); + struct v4l2_sliced_vbi_format *vbi = &fmt->fmt.sliced; + + if (!vivid_is_sdtv_cap(dev) || !dev->has_sliced_vbi_cap) + return -EINVAL; + + vivid_fill_service_lines(vbi, dev->service_set_cap); + return 0; +} + +int vidioc_try_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) +{ + struct vivid_dev *dev = video_drvdata(file); + struct v4l2_sliced_vbi_format *vbi = &fmt->fmt.sliced; + bool is_60hz = dev->std_cap[dev->input] & V4L2_STD_525_60; + u32 service_set = vbi->service_set; + + if (!vivid_is_sdtv_cap(dev) || !dev->has_sliced_vbi_cap) + return -EINVAL; + + service_set &= is_60hz ? V4L2_SLICED_CAPTION_525 : + V4L2_SLICED_WSS_625 | V4L2_SLICED_TELETEXT_B; + vivid_fill_service_lines(vbi, service_set); + return 0; +} + +int vidioc_s_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) +{ + struct vivid_dev *dev = video_drvdata(file); + struct v4l2_sliced_vbi_format *vbi = &fmt->fmt.sliced; + int ret = vidioc_try_fmt_sliced_vbi_cap(file, fh, fmt); + + if (ret) + return ret; + if (!dev->stream_sliced_vbi_cap && vb2_is_busy(&dev->vb_vbi_cap_q)) + return -EBUSY; + dev->service_set_cap = vbi->service_set; + dev->stream_sliced_vbi_cap = true; + dev->vbi_cap_dev.queue->type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE; + return 0; +} + +int vidioc_g_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_sliced_vbi_cap *cap) +{ + struct vivid_dev *dev = video_drvdata(file); + struct video_device *vdev = video_devdata(file); + bool is_60hz; + + if (vdev->vfl_dir == VFL_DIR_RX) { + is_60hz = dev->std_cap[dev->input] & V4L2_STD_525_60; + if (!vivid_is_sdtv_cap(dev) || !dev->has_sliced_vbi_cap || + cap->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) + return -EINVAL; + } else { + is_60hz = dev->std_out & V4L2_STD_525_60; + if (!vivid_is_svid_out(dev) || !dev->has_sliced_vbi_out || + cap->type != V4L2_BUF_TYPE_SLICED_VBI_OUTPUT) + return -EINVAL; + } + + cap->service_set = is_60hz ? V4L2_SLICED_CAPTION_525 : + V4L2_SLICED_WSS_625 | V4L2_SLICED_TELETEXT_B; + if (is_60hz) { + cap->service_lines[0][21] = V4L2_SLICED_CAPTION_525; + cap->service_lines[1][21] = V4L2_SLICED_CAPTION_525; + } else { + unsigned i; + + for (i = 7; i <= 18; i++) + cap->service_lines[0][i] = + cap->service_lines[1][i] = V4L2_SLICED_TELETEXT_B; + cap->service_lines[0][23] = V4L2_SLICED_WSS_625; + } + return 0; +} diff --git a/drivers/media/test_drivers/vivid/vivid-vbi-cap.h b/drivers/media/test_drivers/vivid/vivid-vbi-cap.h new file mode 100644 index 000000000000..91d2de01381c --- /dev/null +++ b/drivers/media/test_drivers/vivid/vivid-vbi-cap.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * vivid-vbi-cap.h - vbi capture support functions. + * + * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. + */ + +#ifndef _VIVID_VBI_CAP_H_ +#define _VIVID_VBI_CAP_H_ + +void vivid_fill_time_of_day_packet(u8 *packet); +void vivid_raw_vbi_cap_process(struct vivid_dev *dev, struct vivid_buffer *buf); +void vivid_sliced_vbi_cap_process(struct vivid_dev *dev, struct vivid_buffer *buf); +void vivid_sliced_vbi_out_process(struct vivid_dev *dev, struct vivid_buffer *buf); +int vidioc_g_fmt_vbi_cap(struct file *file, void *priv, + struct v4l2_format *f); +int vidioc_s_fmt_vbi_cap(struct file *file, void *priv, + struct v4l2_format *f); +int vidioc_g_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt); +int vidioc_try_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt); +int vidioc_s_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt); +int vidioc_g_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_sliced_vbi_cap *cap); + +void vivid_fill_service_lines(struct v4l2_sliced_vbi_format *vbi, u32 service_set); + +extern const struct vb2_ops vivid_vbi_cap_qops; + +#endif diff --git a/drivers/media/test_drivers/vivid/vivid-vbi-gen.c b/drivers/media/test_drivers/vivid/vivid-vbi-gen.c new file mode 100644 index 000000000000..acc98445a1fa --- /dev/null +++ b/drivers/media/test_drivers/vivid/vivid-vbi-gen.c @@ -0,0 +1,311 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * vivid-vbi-gen.c - vbi generator support functions. + * + * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. + */ + +#include +#include +#include +#include +#include + +#include "vivid-vbi-gen.h" + +static void wss_insert(u8 *wss, u32 val, unsigned size) +{ + while (size--) + *wss++ = (val & (1 << size)) ? 0xc0 : 0x10; +} + +static void vivid_vbi_gen_wss_raw(const struct v4l2_sliced_vbi_data *data, + u8 *buf, unsigned sampling_rate) +{ + const unsigned rate = 5000000; /* WSS has a 5 MHz transmission rate */ + u8 wss[29 + 24 + 24 + 24 + 18 + 18] = { 0 }; + const unsigned zero = 0x07; + const unsigned one = 0x38; + unsigned bit = 0; + u16 wss_data; + int i; + + wss_insert(wss + bit, 0x1f1c71c7, 29); bit += 29; + wss_insert(wss + bit, 0x1e3c1f, 24); bit += 24; + + wss_data = (data->data[1] << 8) | data->data[0]; + for (i = 0; i <= 13; i++, bit += 6) + wss_insert(wss + bit, (wss_data & (1 << i)) ? one : zero, 6); + + for (i = 0, bit = 0; bit < sizeof(wss); bit++) { + unsigned n = ((bit + 1) * sampling_rate) / rate; + + while (i < n) + buf[i++] = wss[bit]; + } +} + +static void vivid_vbi_gen_teletext_raw(const struct v4l2_sliced_vbi_data *data, + u8 *buf, unsigned sampling_rate) +{ + const unsigned rate = 6937500 / 10; /* Teletext has a 6.9375 MHz transmission rate */ + u8 teletext[45] = { 0x55, 0x55, 0x27 }; + unsigned bit = 0; + int i; + + memcpy(teletext + 3, data->data, sizeof(teletext) - 3); + /* prevents 32 bit overflow */ + sampling_rate /= 10; + + for (i = 0, bit = 0; bit < sizeof(teletext) * 8; bit++) { + unsigned n = ((bit + 1) * sampling_rate) / rate; + u8 val = (teletext[bit / 8] & (1 << (bit & 7))) ? 0xc0 : 0x10; + + while (i < n) + buf[i++] = val; + } +} + +static void cc_insert(u8 *cc, u8 ch) +{ + unsigned tot = 0; + unsigned i; + + for (i = 0; i < 7; i++) { + cc[2 * i] = cc[2 * i + 1] = (ch & (1 << i)) ? 1 : 0; + tot += cc[2 * i]; + } + cc[14] = cc[15] = !(tot & 1); +} + +#define CC_PREAMBLE_BITS (14 + 4 + 2) + +static void vivid_vbi_gen_cc_raw(const struct v4l2_sliced_vbi_data *data, + u8 *buf, unsigned sampling_rate) +{ + const unsigned rate = 1000000; /* CC has a 1 MHz transmission rate */ + + u8 cc[CC_PREAMBLE_BITS + 2 * 16] = { + /* Clock run-in: 7 cycles */ + 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, + /* 2 cycles of 0 */ + 0, 0, 0, 0, + /* Start bit of 1 (each bit is two cycles) */ + 1, 1 + }; + unsigned bit, i; + + cc_insert(cc + CC_PREAMBLE_BITS, data->data[0]); + cc_insert(cc + CC_PREAMBLE_BITS + 16, data->data[1]); + + for (i = 0, bit = 0; bit < sizeof(cc); bit++) { + unsigned n = ((bit + 1) * sampling_rate) / rate; + + while (i < n) + buf[i++] = cc[bit] ? 0xc0 : 0x10; + } +} + +void vivid_vbi_gen_raw(const struct vivid_vbi_gen_data *vbi, + const struct v4l2_vbi_format *vbi_fmt, u8 *buf) +{ + unsigned idx; + + for (idx = 0; idx < 25; idx++) { + const struct v4l2_sliced_vbi_data *data = vbi->data + idx; + unsigned start_2nd_field; + unsigned line = data->line; + u8 *linebuf = buf; + + start_2nd_field = (data->id & V4L2_SLICED_VBI_525) ? 263 : 313; + if (data->field) + line += start_2nd_field; + line -= vbi_fmt->start[data->field]; + + if (vbi_fmt->flags & V4L2_VBI_INTERLACED) + linebuf += (line * 2 + data->field) * + vbi_fmt->samples_per_line; + else + linebuf += (line + data->field * vbi_fmt->count[0]) * + vbi_fmt->samples_per_line; + if (data->id == V4L2_SLICED_CAPTION_525) + vivid_vbi_gen_cc_raw(data, linebuf, vbi_fmt->sampling_rate); + else if (data->id == V4L2_SLICED_WSS_625) + vivid_vbi_gen_wss_raw(data, linebuf, vbi_fmt->sampling_rate); + else if (data->id == V4L2_SLICED_TELETEXT_B) + vivid_vbi_gen_teletext_raw(data, linebuf, vbi_fmt->sampling_rate); + } +} + +static const u8 vivid_cc_sequence1[30] = { + 0x14, 0x20, /* Resume Caption Loading */ + 'H', 'e', + 'l', 'l', + 'o', ' ', + 'w', 'o', + 'r', 'l', + 'd', '!', + 0x14, 0x2f, /* End of Caption */ +}; + +static const u8 vivid_cc_sequence2[30] = { + 0x14, 0x20, /* Resume Caption Loading */ + 'C', 'l', + 'o', 's', + 'e', 'd', + ' ', 'c', + 'a', 'p', + 't', 'i', + 'o', 'n', + 's', ' ', + 't', 'e', + 's', 't', + 0x14, 0x2f, /* End of Caption */ +}; + +static u8 calc_parity(u8 val) +{ + unsigned i; + unsigned tot = 0; + + for (i = 0; i < 7; i++) + tot += (val & (1 << i)) ? 1 : 0; + return val | ((tot & 1) ? 0 : 0x80); +} + +static void vivid_vbi_gen_set_time_of_day(u8 *packet) +{ + struct tm tm; + u8 checksum, i; + + time64_to_tm(ktime_get_real_seconds(), 0, &tm); + packet[0] = calc_parity(0x07); + packet[1] = calc_parity(0x01); + packet[2] = calc_parity(0x40 | tm.tm_min); + packet[3] = calc_parity(0x40 | tm.tm_hour); + packet[4] = calc_parity(0x40 | tm.tm_mday); + if (tm.tm_mday == 1 && tm.tm_mon == 2 && + sys_tz.tz_minuteswest > tm.tm_min + tm.tm_hour * 60) + packet[4] = calc_parity(0x60 | tm.tm_mday); + packet[5] = calc_parity(0x40 | (1 + tm.tm_mon)); + packet[6] = calc_parity(0x40 | (1 + tm.tm_wday)); + packet[7] = calc_parity(0x40 | ((tm.tm_year - 90) & 0x3f)); + packet[8] = calc_parity(0x0f); + for (checksum = i = 0; i <= 8; i++) + checksum += packet[i] & 0x7f; + packet[9] = calc_parity(0x100 - checksum); + checksum = 0; + packet[10] = calc_parity(0x07); + packet[11] = calc_parity(0x04); + if (sys_tz.tz_minuteswest >= 0) + packet[12] = calc_parity(0x40 | ((sys_tz.tz_minuteswest / 60) & 0x1f)); + else + packet[12] = calc_parity(0x40 | ((24 + sys_tz.tz_minuteswest / 60) & 0x1f)); + packet[13] = calc_parity(0); + packet[14] = calc_parity(0x0f); + for (checksum = 0, i = 10; i <= 14; i++) + checksum += packet[i] & 0x7f; + packet[15] = calc_parity(0x100 - checksum); +} + +static const u8 hamming[16] = { + 0x15, 0x02, 0x49, 0x5e, 0x64, 0x73, 0x38, 0x2f, + 0xd0, 0xc7, 0x8c, 0x9b, 0xa1, 0xb6, 0xfd, 0xea +}; + +static void vivid_vbi_gen_teletext(u8 *packet, unsigned line, unsigned frame) +{ + unsigned offset = 2; + unsigned i; + + packet[0] = hamming[1 + ((line & 1) << 3)]; + packet[1] = hamming[line >> 1]; + memset(packet + 2, 0x20, 40); + if (line == 0) { + /* subcode */ + packet[2] = hamming[frame % 10]; + packet[3] = hamming[frame / 10]; + packet[4] = hamming[0]; + packet[5] = hamming[0]; + packet[6] = hamming[0]; + packet[7] = hamming[0]; + packet[8] = hamming[0]; + packet[9] = hamming[1]; + offset = 10; + } + packet += offset; + memcpy(packet, "Page: 100 Row: 10", 17); + packet[7] = '0' + frame / 10; + packet[8] = '0' + frame % 10; + packet[15] = '0' + line / 10; + packet[16] = '0' + line % 10; + for (i = 0; i < 42 - offset; i++) + packet[i] = calc_parity(packet[i]); +} + +void vivid_vbi_gen_sliced(struct vivid_vbi_gen_data *vbi, + bool is_60hz, unsigned seqnr) +{ + struct v4l2_sliced_vbi_data *data0 = vbi->data; + struct v4l2_sliced_vbi_data *data1 = vbi->data + 1; + unsigned frame = seqnr % 60; + + memset(vbi->data, 0, sizeof(vbi->data)); + + if (!is_60hz) { + unsigned i; + + for (i = 0; i <= 11; i++) { + data0->id = V4L2_SLICED_TELETEXT_B; + data0->line = 7 + i; + vivid_vbi_gen_teletext(data0->data, i, frame); + data0++; + } + data0->id = V4L2_SLICED_WSS_625; + data0->line = 23; + /* 4x3 video aspect ratio */ + data0->data[0] = 0x08; + data0++; + for (i = 0; i <= 11; i++) { + data0->id = V4L2_SLICED_TELETEXT_B; + data0->field = 1; + data0->line = 7 + i; + vivid_vbi_gen_teletext(data0->data, 12 + i, frame); + data0++; + } + return; + } + + data0->id = V4L2_SLICED_CAPTION_525; + data0->line = 21; + data1->id = V4L2_SLICED_CAPTION_525; + data1->field = 1; + data1->line = 21; + + if (frame < 15) { + data0->data[0] = calc_parity(vivid_cc_sequence1[2 * frame]); + data0->data[1] = calc_parity(vivid_cc_sequence1[2 * frame + 1]); + } else if (frame >= 30 && frame < 45) { + frame -= 30; + data0->data[0] = calc_parity(vivid_cc_sequence2[2 * frame]); + data0->data[1] = calc_parity(vivid_cc_sequence2[2 * frame + 1]); + } else { + data0->data[0] = calc_parity(0); + data0->data[1] = calc_parity(0); + } + + frame = seqnr % (30 * 60); + switch (frame) { + case 0: + vivid_vbi_gen_set_time_of_day(vbi->time_of_day_packet); + /* fall through */ + case 1 ... 7: + data1->data[0] = vbi->time_of_day_packet[frame * 2]; + data1->data[1] = vbi->time_of_day_packet[frame * 2 + 1]; + break; + default: + data1->data[0] = calc_parity(0); + data1->data[1] = calc_parity(0); + break; + } +} diff --git a/drivers/media/test_drivers/vivid/vivid-vbi-gen.h b/drivers/media/test_drivers/vivid/vivid-vbi-gen.h new file mode 100644 index 000000000000..2657a7f5571c --- /dev/null +++ b/drivers/media/test_drivers/vivid/vivid-vbi-gen.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * vivid-vbi-gen.h - vbi generator support functions. + * + * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. + */ + +#ifndef _VIVID_VBI_GEN_H_ +#define _VIVID_VBI_GEN_H_ + +struct vivid_vbi_gen_data { + struct v4l2_sliced_vbi_data data[25]; + u8 time_of_day_packet[16]; +}; + +void vivid_vbi_gen_sliced(struct vivid_vbi_gen_data *vbi, + bool is_60hz, unsigned seqnr); +void vivid_vbi_gen_raw(const struct vivid_vbi_gen_data *vbi, + const struct v4l2_vbi_format *vbi_fmt, u8 *buf); + +#endif diff --git a/drivers/media/test_drivers/vivid/vivid-vbi-out.c b/drivers/media/test_drivers/vivid/vivid-vbi-out.c new file mode 100644 index 000000000000..cd56476902a2 --- /dev/null +++ b/drivers/media/test_drivers/vivid/vivid-vbi-out.c @@ -0,0 +1,250 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * vivid-vbi-out.c - vbi output support functions. + * + * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. + */ + +#include +#include +#include +#include + +#include "vivid-core.h" +#include "vivid-kthread-out.h" +#include "vivid-vbi-out.h" +#include "vivid-vbi-cap.h" + +static int vbi_out_queue_setup(struct vb2_queue *vq, + unsigned *nbuffers, unsigned *nplanes, + unsigned sizes[], struct device *alloc_devs[]) +{ + struct vivid_dev *dev = vb2_get_drv_priv(vq); + bool is_60hz = dev->std_out & V4L2_STD_525_60; + unsigned size = vq->type == V4L2_BUF_TYPE_SLICED_VBI_OUTPUT ? + 36 * sizeof(struct v4l2_sliced_vbi_data) : + 1440 * 2 * (is_60hz ? 12 : 18); + + if (!vivid_is_svid_out(dev)) + return -EINVAL; + + sizes[0] = size; + + if (vq->num_buffers + *nbuffers < 2) + *nbuffers = 2 - vq->num_buffers; + + *nplanes = 1; + return 0; +} + +static int vbi_out_buf_prepare(struct vb2_buffer *vb) +{ + struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); + bool is_60hz = dev->std_out & V4L2_STD_525_60; + unsigned size = vb->vb2_queue->type == V4L2_BUF_TYPE_SLICED_VBI_OUTPUT ? + 36 * sizeof(struct v4l2_sliced_vbi_data) : + 1440 * 2 * (is_60hz ? 12 : 18); + + dprintk(dev, 1, "%s\n", __func__); + + if (dev->buf_prepare_error) { + /* + * Error injection: test what happens if buf_prepare() returns + * an error. + */ + dev->buf_prepare_error = false; + return -EINVAL; + } + if (vb2_plane_size(vb, 0) < size) { + dprintk(dev, 1, "%s data will not fit into plane (%lu < %u)\n", + __func__, vb2_plane_size(vb, 0), size); + return -EINVAL; + } + vb2_set_plane_payload(vb, 0, size); + + return 0; +} + +static void vbi_out_buf_queue(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); + struct vivid_buffer *buf = container_of(vbuf, struct vivid_buffer, vb); + + dprintk(dev, 1, "%s\n", __func__); + + spin_lock(&dev->slock); + list_add_tail(&buf->list, &dev->vbi_out_active); + spin_unlock(&dev->slock); +} + +static int vbi_out_start_streaming(struct vb2_queue *vq, unsigned count) +{ + struct vivid_dev *dev = vb2_get_drv_priv(vq); + int err; + + dprintk(dev, 1, "%s\n", __func__); + dev->vbi_out_seq_count = 0; + if (dev->start_streaming_error) { + dev->start_streaming_error = false; + err = -EINVAL; + } else { + err = vivid_start_generating_vid_out(dev, &dev->vbi_out_streaming); + } + if (err) { + struct vivid_buffer *buf, *tmp; + + list_for_each_entry_safe(buf, tmp, &dev->vbi_out_active, list) { + list_del(&buf->list); + vb2_buffer_done(&buf->vb.vb2_buf, + VB2_BUF_STATE_QUEUED); + } + } + return err; +} + +/* abort streaming and wait for last buffer */ +static void vbi_out_stop_streaming(struct vb2_queue *vq) +{ + struct vivid_dev *dev = vb2_get_drv_priv(vq); + + dprintk(dev, 1, "%s\n", __func__); + vivid_stop_generating_vid_out(dev, &dev->vbi_out_streaming); + dev->vbi_out_have_wss = false; + dev->vbi_out_have_cc[0] = false; + dev->vbi_out_have_cc[1] = false; +} + +static void vbi_out_buf_request_complete(struct vb2_buffer *vb) +{ + struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); + + v4l2_ctrl_request_complete(vb->req_obj.req, &dev->ctrl_hdl_vbi_out); +} + +const struct vb2_ops vivid_vbi_out_qops = { + .queue_setup = vbi_out_queue_setup, + .buf_prepare = vbi_out_buf_prepare, + .buf_queue = vbi_out_buf_queue, + .start_streaming = vbi_out_start_streaming, + .stop_streaming = vbi_out_stop_streaming, + .buf_request_complete = vbi_out_buf_request_complete, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, +}; + +int vidioc_g_fmt_vbi_out(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct vivid_dev *dev = video_drvdata(file); + struct v4l2_vbi_format *vbi = &f->fmt.vbi; + bool is_60hz = dev->std_out & V4L2_STD_525_60; + + if (!vivid_is_svid_out(dev) || !dev->has_raw_vbi_out) + return -EINVAL; + + vbi->sampling_rate = 25000000; + vbi->offset = 24; + vbi->samples_per_line = 1440; + vbi->sample_format = V4L2_PIX_FMT_GREY; + vbi->start[0] = is_60hz ? V4L2_VBI_ITU_525_F1_START + 9 : V4L2_VBI_ITU_625_F1_START + 5; + vbi->start[1] = is_60hz ? V4L2_VBI_ITU_525_F2_START + 9 : V4L2_VBI_ITU_625_F2_START + 5; + vbi->count[0] = vbi->count[1] = is_60hz ? 12 : 18; + vbi->flags = dev->vbi_cap_interlaced ? V4L2_VBI_INTERLACED : 0; + vbi->reserved[0] = 0; + vbi->reserved[1] = 0; + return 0; +} + +int vidioc_s_fmt_vbi_out(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct vivid_dev *dev = video_drvdata(file); + int ret = vidioc_g_fmt_vbi_out(file, priv, f); + + if (ret) + return ret; + if (vb2_is_busy(&dev->vb_vbi_out_q)) + return -EBUSY; + dev->stream_sliced_vbi_out = false; + dev->vbi_out_dev.queue->type = V4L2_BUF_TYPE_VBI_OUTPUT; + return 0; +} + +int vidioc_g_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt) +{ + struct vivid_dev *dev = video_drvdata(file); + struct v4l2_sliced_vbi_format *vbi = &fmt->fmt.sliced; + + if (!vivid_is_svid_out(dev) || !dev->has_sliced_vbi_out) + return -EINVAL; + + vivid_fill_service_lines(vbi, dev->service_set_out); + return 0; +} + +int vidioc_try_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt) +{ + struct vivid_dev *dev = video_drvdata(file); + struct v4l2_sliced_vbi_format *vbi = &fmt->fmt.sliced; + bool is_60hz = dev->std_out & V4L2_STD_525_60; + u32 service_set = vbi->service_set; + + if (!vivid_is_svid_out(dev) || !dev->has_sliced_vbi_out) + return -EINVAL; + + service_set &= is_60hz ? V4L2_SLICED_CAPTION_525 : + V4L2_SLICED_WSS_625 | V4L2_SLICED_TELETEXT_B; + vivid_fill_service_lines(vbi, service_set); + return 0; +} + +int vidioc_s_fmt_sliced_vbi_out(struct file *file, void *fh, + struct v4l2_format *fmt) +{ + struct vivid_dev *dev = video_drvdata(file); + struct v4l2_sliced_vbi_format *vbi = &fmt->fmt.sliced; + int ret = vidioc_try_fmt_sliced_vbi_out(file, fh, fmt); + + if (ret) + return ret; + if (vb2_is_busy(&dev->vb_vbi_out_q)) + return -EBUSY; + dev->service_set_out = vbi->service_set; + dev->stream_sliced_vbi_out = true; + dev->vbi_out_dev.queue->type = V4L2_BUF_TYPE_SLICED_VBI_OUTPUT; + return 0; +} + +void vivid_sliced_vbi_out_process(struct vivid_dev *dev, + struct vivid_buffer *buf) +{ + struct v4l2_sliced_vbi_data *vbi = + vb2_plane_vaddr(&buf->vb.vb2_buf, 0); + unsigned elems = + vb2_get_plane_payload(&buf->vb.vb2_buf, 0) / sizeof(*vbi); + + dev->vbi_out_have_cc[0] = false; + dev->vbi_out_have_cc[1] = false; + dev->vbi_out_have_wss = false; + while (elems--) { + switch (vbi->id) { + case V4L2_SLICED_CAPTION_525: + if ((dev->std_out & V4L2_STD_525_60) && vbi->line == 21) { + dev->vbi_out_have_cc[!!vbi->field] = true; + dev->vbi_out_cc[!!vbi->field][0] = vbi->data[0]; + dev->vbi_out_cc[!!vbi->field][1] = vbi->data[1]; + } + break; + case V4L2_SLICED_WSS_625: + if ((dev->std_out & V4L2_STD_625_50) && + vbi->field == 0 && vbi->line == 23) { + dev->vbi_out_have_wss = true; + dev->vbi_out_wss[0] = vbi->data[0]; + dev->vbi_out_wss[1] = vbi->data[1]; + } + break; + } + vbi++; + } +} diff --git a/drivers/media/test_drivers/vivid/vivid-vbi-out.h b/drivers/media/test_drivers/vivid/vivid-vbi-out.h new file mode 100644 index 000000000000..76584940cdaf --- /dev/null +++ b/drivers/media/test_drivers/vivid/vivid-vbi-out.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * vivid-vbi-out.h - vbi output support functions. + * + * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. + */ + +#ifndef _VIVID_VBI_OUT_H_ +#define _VIVID_VBI_OUT_H_ + +void vivid_sliced_vbi_out_process(struct vivid_dev *dev, struct vivid_buffer *buf); +int vidioc_g_fmt_vbi_out(struct file *file, void *priv, + struct v4l2_format *f); +int vidioc_s_fmt_vbi_out(struct file *file, void *priv, + struct v4l2_format *f); +int vidioc_g_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt); +int vidioc_try_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt); +int vidioc_s_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt); + +extern const struct vb2_ops vivid_vbi_out_qops; + +#endif diff --git a/drivers/media/test_drivers/vivid/vivid-vid-cap.c b/drivers/media/test_drivers/vivid/vivid-vid-cap.c new file mode 100644 index 000000000000..e94beef008c8 --- /dev/null +++ b/drivers/media/test_drivers/vivid/vivid-vid-cap.c @@ -0,0 +1,1918 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * vivid-vid-cap.c - video capture support functions. + * + * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "vivid-core.h" +#include "vivid-vid-common.h" +#include "vivid-kthread-cap.h" +#include "vivid-vid-cap.h" + +static const struct vivid_fmt formats_ovl[] = { + { + .fourcc = V4L2_PIX_FMT_RGB565, /* gggbbbbb rrrrrggg */ + .vdownsampling = { 1 }, + .bit_depth = { 16 }, + .planes = 1, + .buffers = 1, + }, + { + .fourcc = V4L2_PIX_FMT_XRGB555, /* gggbbbbb arrrrrgg */ + .vdownsampling = { 1 }, + .bit_depth = { 16 }, + .planes = 1, + .buffers = 1, + }, + { + .fourcc = V4L2_PIX_FMT_ARGB555, /* gggbbbbb arrrrrgg */ + .vdownsampling = { 1 }, + .bit_depth = { 16 }, + .planes = 1, + .buffers = 1, + }, +}; + +/* The number of discrete webcam framesizes */ +#define VIVID_WEBCAM_SIZES 6 +/* The number of discrete webcam frameintervals */ +#define VIVID_WEBCAM_IVALS (VIVID_WEBCAM_SIZES * 2) + +/* Sizes must be in increasing order */ +static const struct v4l2_frmsize_discrete webcam_sizes[VIVID_WEBCAM_SIZES] = { + { 320, 180 }, + { 640, 360 }, + { 640, 480 }, + { 1280, 720 }, + { 1920, 1080 }, + { 3840, 2160 }, +}; + +/* + * Intervals must be in increasing order and there must be twice as many + * elements in this array as there are in webcam_sizes. + */ +static const struct v4l2_fract webcam_intervals[VIVID_WEBCAM_IVALS] = { + { 1, 1 }, + { 1, 2 }, + { 1, 4 }, + { 1, 5 }, + { 1, 10 }, + { 2, 25 }, + { 1, 15 }, + { 1, 25 }, + { 1, 30 }, + { 1, 40 }, + { 1, 50 }, + { 1, 60 }, +}; + +static int vid_cap_queue_setup(struct vb2_queue *vq, + unsigned *nbuffers, unsigned *nplanes, + unsigned sizes[], struct device *alloc_devs[]) +{ + struct vivid_dev *dev = vb2_get_drv_priv(vq); + unsigned buffers = tpg_g_buffers(&dev->tpg); + unsigned h = dev->fmt_cap_rect.height; + unsigned p; + + if (dev->field_cap == V4L2_FIELD_ALTERNATE) { + /* + * You cannot use read() with FIELD_ALTERNATE since the field + * information (TOP/BOTTOM) cannot be passed back to the user. + */ + if (vb2_fileio_is_active(vq)) + return -EINVAL; + } + + if (dev->queue_setup_error) { + /* + * Error injection: test what happens if queue_setup() returns + * an error. + */ + dev->queue_setup_error = false; + return -EINVAL; + } + if (*nplanes) { + /* + * Check if the number of requested planes match + * the number of buffers in the current format. You can't mix that. + */ + if (*nplanes != buffers) + return -EINVAL; + for (p = 0; p < buffers; p++) { + if (sizes[p] < tpg_g_line_width(&dev->tpg, p) * h + + dev->fmt_cap->data_offset[p]) + return -EINVAL; + } + } else { + for (p = 0; p < buffers; p++) + sizes[p] = (tpg_g_line_width(&dev->tpg, p) * h) / + dev->fmt_cap->vdownsampling[p] + + dev->fmt_cap->data_offset[p]; + } + + if (vq->num_buffers + *nbuffers < 2) + *nbuffers = 2 - vq->num_buffers; + + *nplanes = buffers; + + dprintk(dev, 1, "%s: count=%d\n", __func__, *nbuffers); + for (p = 0; p < buffers; p++) + dprintk(dev, 1, "%s: size[%u]=%u\n", __func__, p, sizes[p]); + + return 0; +} + +static int vid_cap_buf_prepare(struct vb2_buffer *vb) +{ + struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); + unsigned long size; + unsigned buffers = tpg_g_buffers(&dev->tpg); + unsigned p; + + dprintk(dev, 1, "%s\n", __func__); + + if (WARN_ON(NULL == dev->fmt_cap)) + return -EINVAL; + + if (dev->buf_prepare_error) { + /* + * Error injection: test what happens if buf_prepare() returns + * an error. + */ + dev->buf_prepare_error = false; + return -EINVAL; + } + for (p = 0; p < buffers; p++) { + size = (tpg_g_line_width(&dev->tpg, p) * + dev->fmt_cap_rect.height) / + dev->fmt_cap->vdownsampling[p] + + dev->fmt_cap->data_offset[p]; + + if (vb2_plane_size(vb, p) < size) { + dprintk(dev, 1, "%s data will not fit into plane %u (%lu < %lu)\n", + __func__, p, vb2_plane_size(vb, p), size); + return -EINVAL; + } + + vb2_set_plane_payload(vb, p, size); + vb->planes[p].data_offset = dev->fmt_cap->data_offset[p]; + } + + return 0; +} + +static void vid_cap_buf_finish(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); + struct v4l2_timecode *tc = &vbuf->timecode; + unsigned fps = 25; + unsigned seq = vbuf->sequence; + + if (!vivid_is_sdtv_cap(dev)) + return; + + /* + * Set the timecode. Rarely used, so it is interesting to + * test this. + */ + vbuf->flags |= V4L2_BUF_FLAG_TIMECODE; + if (dev->std_cap[dev->input] & V4L2_STD_525_60) + fps = 30; + tc->type = (fps == 30) ? V4L2_TC_TYPE_30FPS : V4L2_TC_TYPE_25FPS; + tc->flags = 0; + tc->frames = seq % fps; + tc->seconds = (seq / fps) % 60; + tc->minutes = (seq / (60 * fps)) % 60; + tc->hours = (seq / (60 * 60 * fps)) % 24; +} + +static void vid_cap_buf_queue(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); + struct vivid_buffer *buf = container_of(vbuf, struct vivid_buffer, vb); + + dprintk(dev, 1, "%s\n", __func__); + + spin_lock(&dev->slock); + list_add_tail(&buf->list, &dev->vid_cap_active); + spin_unlock(&dev->slock); +} + +static int vid_cap_start_streaming(struct vb2_queue *vq, unsigned count) +{ + struct vivid_dev *dev = vb2_get_drv_priv(vq); + unsigned i; + int err; + + if (vb2_is_streaming(&dev->vb_vid_out_q)) + dev->can_loop_video = vivid_vid_can_loop(dev); + + dev->vid_cap_seq_count = 0; + dprintk(dev, 1, "%s\n", __func__); + for (i = 0; i < VIDEO_MAX_FRAME; i++) + dev->must_blank[i] = tpg_g_perc_fill(&dev->tpg) < 100; + if (dev->start_streaming_error) { + dev->start_streaming_error = false; + err = -EINVAL; + } else { + err = vivid_start_generating_vid_cap(dev, &dev->vid_cap_streaming); + } + if (err) { + struct vivid_buffer *buf, *tmp; + + list_for_each_entry_safe(buf, tmp, &dev->vid_cap_active, list) { + list_del(&buf->list); + vb2_buffer_done(&buf->vb.vb2_buf, + VB2_BUF_STATE_QUEUED); + } + } + return err; +} + +/* abort streaming and wait for last buffer */ +static void vid_cap_stop_streaming(struct vb2_queue *vq) +{ + struct vivid_dev *dev = vb2_get_drv_priv(vq); + + dprintk(dev, 1, "%s\n", __func__); + vivid_stop_generating_vid_cap(dev, &dev->vid_cap_streaming); + dev->can_loop_video = false; +} + +static void vid_cap_buf_request_complete(struct vb2_buffer *vb) +{ + struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); + + v4l2_ctrl_request_complete(vb->req_obj.req, &dev->ctrl_hdl_vid_cap); +} + +const struct vb2_ops vivid_vid_cap_qops = { + .queue_setup = vid_cap_queue_setup, + .buf_prepare = vid_cap_buf_prepare, + .buf_finish = vid_cap_buf_finish, + .buf_queue = vid_cap_buf_queue, + .start_streaming = vid_cap_start_streaming, + .stop_streaming = vid_cap_stop_streaming, + .buf_request_complete = vid_cap_buf_request_complete, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, +}; + +/* + * Determine the 'picture' quality based on the current TV frequency: either + * COLOR for a good 'signal', GRAY (grayscale picture) for a slightly off + * signal or NOISE for no signal. + */ +void vivid_update_quality(struct vivid_dev *dev) +{ + unsigned freq_modulus; + + if (dev->loop_video && (vivid_is_svid_cap(dev) || vivid_is_hdmi_cap(dev))) { + /* + * The 'noise' will only be replaced by the actual video + * if the output video matches the input video settings. + */ + tpg_s_quality(&dev->tpg, TPG_QUAL_NOISE, 0); + return; + } + if (vivid_is_hdmi_cap(dev) && + VIVID_INVALID_SIGNAL(dev->dv_timings_signal_mode[dev->input])) { + tpg_s_quality(&dev->tpg, TPG_QUAL_NOISE, 0); + return; + } + if (vivid_is_sdtv_cap(dev) && + VIVID_INVALID_SIGNAL(dev->std_signal_mode[dev->input])) { + tpg_s_quality(&dev->tpg, TPG_QUAL_NOISE, 0); + return; + } + if (!vivid_is_tv_cap(dev)) { + tpg_s_quality(&dev->tpg, TPG_QUAL_COLOR, 0); + return; + } + + /* + * There is a fake channel every 6 MHz at 49.25, 55.25, etc. + * From +/- 0.25 MHz around the channel there is color, and from + * +/- 1 MHz there is grayscale (chroma is lost). + * Everywhere else it is just noise. + */ + freq_modulus = (dev->tv_freq - 676 /* (43.25-1) * 16 */) % (6 * 16); + if (freq_modulus > 2 * 16) { + tpg_s_quality(&dev->tpg, TPG_QUAL_NOISE, + next_pseudo_random32(dev->tv_freq ^ 0x55) & 0x3f); + return; + } + if (freq_modulus < 12 /*0.75 * 16*/ || freq_modulus > 20 /*1.25 * 16*/) + tpg_s_quality(&dev->tpg, TPG_QUAL_GRAY, 0); + else + tpg_s_quality(&dev->tpg, TPG_QUAL_COLOR, 0); +} + +/* + * Get the current picture quality and the associated afc value. + */ +static enum tpg_quality vivid_get_quality(struct vivid_dev *dev, s32 *afc) +{ + unsigned freq_modulus; + + if (afc) + *afc = 0; + if (tpg_g_quality(&dev->tpg) == TPG_QUAL_COLOR || + tpg_g_quality(&dev->tpg) == TPG_QUAL_NOISE) + return tpg_g_quality(&dev->tpg); + + /* + * There is a fake channel every 6 MHz at 49.25, 55.25, etc. + * From +/- 0.25 MHz around the channel there is color, and from + * +/- 1 MHz there is grayscale (chroma is lost). + * Everywhere else it is just gray. + */ + freq_modulus = (dev->tv_freq - 676 /* (43.25-1) * 16 */) % (6 * 16); + if (afc) + *afc = freq_modulus - 1 * 16; + return TPG_QUAL_GRAY; +} + +enum tpg_video_aspect vivid_get_video_aspect(const struct vivid_dev *dev) +{ + if (vivid_is_sdtv_cap(dev)) + return dev->std_aspect_ratio[dev->input]; + + if (vivid_is_hdmi_cap(dev)) + return dev->dv_timings_aspect_ratio[dev->input]; + + return TPG_VIDEO_ASPECT_IMAGE; +} + +static enum tpg_pixel_aspect vivid_get_pixel_aspect(const struct vivid_dev *dev) +{ + if (vivid_is_sdtv_cap(dev)) + return (dev->std_cap[dev->input] & V4L2_STD_525_60) ? + TPG_PIXEL_ASPECT_NTSC : TPG_PIXEL_ASPECT_PAL; + + if (vivid_is_hdmi_cap(dev) && + dev->src_rect.width == 720 && dev->src_rect.height <= 576) + return dev->src_rect.height == 480 ? + TPG_PIXEL_ASPECT_NTSC : TPG_PIXEL_ASPECT_PAL; + + return TPG_PIXEL_ASPECT_SQUARE; +} + +/* + * Called whenever the format has to be reset which can occur when + * changing inputs, standard, timings, etc. + */ +void vivid_update_format_cap(struct vivid_dev *dev, bool keep_controls) +{ + struct v4l2_bt_timings *bt = &dev->dv_timings_cap[dev->input].bt; + unsigned size; + u64 pixelclock; + + switch (dev->input_type[dev->input]) { + case WEBCAM: + default: + dev->src_rect.width = webcam_sizes[dev->webcam_size_idx].width; + dev->src_rect.height = webcam_sizes[dev->webcam_size_idx].height; + dev->timeperframe_vid_cap = webcam_intervals[dev->webcam_ival_idx]; + dev->field_cap = V4L2_FIELD_NONE; + tpg_s_rgb_range(&dev->tpg, V4L2_DV_RGB_RANGE_AUTO); + break; + case TV: + case SVID: + dev->field_cap = dev->tv_field_cap; + dev->src_rect.width = 720; + if (dev->std_cap[dev->input] & V4L2_STD_525_60) { + dev->src_rect.height = 480; + dev->timeperframe_vid_cap = (struct v4l2_fract) { 1001, 30000 }; + dev->service_set_cap = V4L2_SLICED_CAPTION_525; + } else { + dev->src_rect.height = 576; + dev->timeperframe_vid_cap = (struct v4l2_fract) { 1000, 25000 }; + dev->service_set_cap = V4L2_SLICED_WSS_625 | V4L2_SLICED_TELETEXT_B; + } + tpg_s_rgb_range(&dev->tpg, V4L2_DV_RGB_RANGE_AUTO); + break; + case HDMI: + dev->src_rect.width = bt->width; + dev->src_rect.height = bt->height; + size = V4L2_DV_BT_FRAME_WIDTH(bt) * V4L2_DV_BT_FRAME_HEIGHT(bt); + if (dev->reduced_fps && can_reduce_fps(bt)) { + pixelclock = div_u64(bt->pixelclock * 1000, 1001); + bt->flags |= V4L2_DV_FL_REDUCED_FPS; + } else { + pixelclock = bt->pixelclock; + bt->flags &= ~V4L2_DV_FL_REDUCED_FPS; + } + dev->timeperframe_vid_cap = (struct v4l2_fract) { + size / 100, (u32)pixelclock / 100 + }; + if (bt->interlaced) + dev->field_cap = V4L2_FIELD_ALTERNATE; + else + dev->field_cap = V4L2_FIELD_NONE; + + /* + * We can be called from within s_ctrl, in that case we can't + * set/get controls. Luckily we don't need to in that case. + */ + if (keep_controls || !dev->colorspace) + break; + if (bt->flags & V4L2_DV_FL_IS_CE_VIDEO) { + if (bt->width == 720 && bt->height <= 576) + v4l2_ctrl_s_ctrl(dev->colorspace, VIVID_CS_170M); + else + v4l2_ctrl_s_ctrl(dev->colorspace, VIVID_CS_709); + v4l2_ctrl_s_ctrl(dev->real_rgb_range_cap, 1); + } else { + v4l2_ctrl_s_ctrl(dev->colorspace, VIVID_CS_SRGB); + v4l2_ctrl_s_ctrl(dev->real_rgb_range_cap, 0); + } + tpg_s_rgb_range(&dev->tpg, v4l2_ctrl_g_ctrl(dev->rgb_range_cap)); + break; + } + vfree(dev->bitmap_cap); + dev->bitmap_cap = NULL; + vivid_update_quality(dev); + tpg_reset_source(&dev->tpg, dev->src_rect.width, dev->src_rect.height, dev->field_cap); + dev->crop_cap = dev->src_rect; + dev->crop_bounds_cap = dev->src_rect; + dev->compose_cap = dev->crop_cap; + if (V4L2_FIELD_HAS_T_OR_B(dev->field_cap)) + dev->compose_cap.height /= 2; + dev->fmt_cap_rect = dev->compose_cap; + tpg_s_video_aspect(&dev->tpg, vivid_get_video_aspect(dev)); + tpg_s_pixel_aspect(&dev->tpg, vivid_get_pixel_aspect(dev)); + tpg_update_mv_step(&dev->tpg); +} + +/* Map the field to something that is valid for the current input */ +static enum v4l2_field vivid_field_cap(struct vivid_dev *dev, enum v4l2_field field) +{ + if (vivid_is_sdtv_cap(dev)) { + switch (field) { + case V4L2_FIELD_INTERLACED_TB: + case V4L2_FIELD_INTERLACED_BT: + case V4L2_FIELD_SEQ_TB: + case V4L2_FIELD_SEQ_BT: + case V4L2_FIELD_TOP: + case V4L2_FIELD_BOTTOM: + case V4L2_FIELD_ALTERNATE: + return field; + case V4L2_FIELD_INTERLACED: + default: + return V4L2_FIELD_INTERLACED; + } + } + if (vivid_is_hdmi_cap(dev)) + return dev->dv_timings_cap[dev->input].bt.interlaced ? + V4L2_FIELD_ALTERNATE : V4L2_FIELD_NONE; + return V4L2_FIELD_NONE; +} + +static unsigned vivid_colorspace_cap(struct vivid_dev *dev) +{ + if (!dev->loop_video || vivid_is_webcam(dev) || vivid_is_tv_cap(dev)) + return tpg_g_colorspace(&dev->tpg); + return dev->colorspace_out; +} + +static unsigned vivid_xfer_func_cap(struct vivid_dev *dev) +{ + if (!dev->loop_video || vivid_is_webcam(dev) || vivid_is_tv_cap(dev)) + return tpg_g_xfer_func(&dev->tpg); + return dev->xfer_func_out; +} + +static unsigned vivid_ycbcr_enc_cap(struct vivid_dev *dev) +{ + if (!dev->loop_video || vivid_is_webcam(dev) || vivid_is_tv_cap(dev)) + return tpg_g_ycbcr_enc(&dev->tpg); + return dev->ycbcr_enc_out; +} + +static unsigned int vivid_hsv_enc_cap(struct vivid_dev *dev) +{ + if (!dev->loop_video || vivid_is_webcam(dev) || vivid_is_tv_cap(dev)) + return tpg_g_hsv_enc(&dev->tpg); + return dev->hsv_enc_out; +} + +static unsigned vivid_quantization_cap(struct vivid_dev *dev) +{ + if (!dev->loop_video || vivid_is_webcam(dev) || vivid_is_tv_cap(dev)) + return tpg_g_quantization(&dev->tpg); + return dev->quantization_out; +} + +int vivid_g_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct vivid_dev *dev = video_drvdata(file); + struct v4l2_pix_format_mplane *mp = &f->fmt.pix_mp; + unsigned p; + + mp->width = dev->fmt_cap_rect.width; + mp->height = dev->fmt_cap_rect.height; + mp->field = dev->field_cap; + mp->pixelformat = dev->fmt_cap->fourcc; + mp->colorspace = vivid_colorspace_cap(dev); + mp->xfer_func = vivid_xfer_func_cap(dev); + if (dev->fmt_cap->color_enc == TGP_COLOR_ENC_HSV) + mp->hsv_enc = vivid_hsv_enc_cap(dev); + else + mp->ycbcr_enc = vivid_ycbcr_enc_cap(dev); + mp->quantization = vivid_quantization_cap(dev); + mp->num_planes = dev->fmt_cap->buffers; + for (p = 0; p < mp->num_planes; p++) { + mp->plane_fmt[p].bytesperline = tpg_g_bytesperline(&dev->tpg, p); + mp->plane_fmt[p].sizeimage = + (tpg_g_line_width(&dev->tpg, p) * mp->height) / + dev->fmt_cap->vdownsampling[p] + + dev->fmt_cap->data_offset[p]; + } + return 0; +} + +int vivid_try_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct v4l2_pix_format_mplane *mp = &f->fmt.pix_mp; + struct v4l2_plane_pix_format *pfmt = mp->plane_fmt; + struct vivid_dev *dev = video_drvdata(file); + const struct vivid_fmt *fmt; + unsigned bytesperline, max_bpl; + unsigned factor = 1; + unsigned w, h; + unsigned p; + + fmt = vivid_get_format(dev, mp->pixelformat); + if (!fmt) { + dprintk(dev, 1, "Fourcc format (0x%08x) unknown.\n", + mp->pixelformat); + mp->pixelformat = V4L2_PIX_FMT_YUYV; + fmt = vivid_get_format(dev, mp->pixelformat); + } + + mp->field = vivid_field_cap(dev, mp->field); + if (vivid_is_webcam(dev)) { + const struct v4l2_frmsize_discrete *sz = + v4l2_find_nearest_size(webcam_sizes, + VIVID_WEBCAM_SIZES, width, + height, mp->width, mp->height); + + w = sz->width; + h = sz->height; + } else if (vivid_is_sdtv_cap(dev)) { + w = 720; + h = (dev->std_cap[dev->input] & V4L2_STD_525_60) ? 480 : 576; + } else { + w = dev->src_rect.width; + h = dev->src_rect.height; + } + if (V4L2_FIELD_HAS_T_OR_B(mp->field)) + factor = 2; + if (vivid_is_webcam(dev) || + (!dev->has_scaler_cap && !dev->has_crop_cap && !dev->has_compose_cap)) { + mp->width = w; + mp->height = h / factor; + } else { + struct v4l2_rect r = { 0, 0, mp->width, mp->height * factor }; + + v4l2_rect_set_min_size(&r, &vivid_min_rect); + v4l2_rect_set_max_size(&r, &vivid_max_rect); + if (dev->has_scaler_cap && !dev->has_compose_cap) { + struct v4l2_rect max_r = { 0, 0, MAX_ZOOM * w, MAX_ZOOM * h }; + + v4l2_rect_set_max_size(&r, &max_r); + } else if (!dev->has_scaler_cap && dev->has_crop_cap && !dev->has_compose_cap) { + v4l2_rect_set_max_size(&r, &dev->src_rect); + } else if (!dev->has_scaler_cap && !dev->has_crop_cap) { + v4l2_rect_set_min_size(&r, &dev->src_rect); + } + mp->width = r.width; + mp->height = r.height / factor; + } + + /* This driver supports custom bytesperline values */ + + mp->num_planes = fmt->buffers; + for (p = 0; p < fmt->buffers; p++) { + /* Calculate the minimum supported bytesperline value */ + bytesperline = (mp->width * fmt->bit_depth[p]) >> 3; + /* Calculate the maximum supported bytesperline value */ + max_bpl = (MAX_ZOOM * MAX_WIDTH * fmt->bit_depth[p]) >> 3; + + if (pfmt[p].bytesperline > max_bpl) + pfmt[p].bytesperline = max_bpl; + if (pfmt[p].bytesperline < bytesperline) + pfmt[p].bytesperline = bytesperline; + + pfmt[p].sizeimage = (pfmt[p].bytesperline * mp->height) / + fmt->vdownsampling[p] + fmt->data_offset[p]; + + memset(pfmt[p].reserved, 0, sizeof(pfmt[p].reserved)); + } + for (p = fmt->buffers; p < fmt->planes; p++) + pfmt[0].sizeimage += (pfmt[0].bytesperline * mp->height * + (fmt->bit_depth[p] / fmt->vdownsampling[p])) / + (fmt->bit_depth[0] / fmt->vdownsampling[0]); + + mp->colorspace = vivid_colorspace_cap(dev); + if (fmt->color_enc == TGP_COLOR_ENC_HSV) + mp->hsv_enc = vivid_hsv_enc_cap(dev); + else + mp->ycbcr_enc = vivid_ycbcr_enc_cap(dev); + mp->xfer_func = vivid_xfer_func_cap(dev); + mp->quantization = vivid_quantization_cap(dev); + memset(mp->reserved, 0, sizeof(mp->reserved)); + return 0; +} + +int vivid_s_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct v4l2_pix_format_mplane *mp = &f->fmt.pix_mp; + struct vivid_dev *dev = video_drvdata(file); + struct v4l2_rect *crop = &dev->crop_cap; + struct v4l2_rect *compose = &dev->compose_cap; + struct vb2_queue *q = &dev->vb_vid_cap_q; + int ret = vivid_try_fmt_vid_cap(file, priv, f); + unsigned factor = 1; + unsigned p; + unsigned i; + + if (ret < 0) + return ret; + + if (vb2_is_busy(q)) { + dprintk(dev, 1, "%s device busy\n", __func__); + return -EBUSY; + } + + if (dev->overlay_cap_owner && dev->fb_cap.fmt.pixelformat != mp->pixelformat) { + dprintk(dev, 1, "overlay is active, can't change pixelformat\n"); + return -EBUSY; + } + + dev->fmt_cap = vivid_get_format(dev, mp->pixelformat); + if (V4L2_FIELD_HAS_T_OR_B(mp->field)) + factor = 2; + + /* Note: the webcam input doesn't support scaling, cropping or composing */ + + if (!vivid_is_webcam(dev) && + (dev->has_scaler_cap || dev->has_crop_cap || dev->has_compose_cap)) { + struct v4l2_rect r = { 0, 0, mp->width, mp->height }; + + if (dev->has_scaler_cap) { + if (dev->has_compose_cap) + v4l2_rect_map_inside(compose, &r); + else + *compose = r; + if (dev->has_crop_cap && !dev->has_compose_cap) { + struct v4l2_rect min_r = { + 0, 0, + r.width / MAX_ZOOM, + factor * r.height / MAX_ZOOM + }; + struct v4l2_rect max_r = { + 0, 0, + r.width * MAX_ZOOM, + factor * r.height * MAX_ZOOM + }; + + v4l2_rect_set_min_size(crop, &min_r); + v4l2_rect_set_max_size(crop, &max_r); + v4l2_rect_map_inside(crop, &dev->crop_bounds_cap); + } else if (dev->has_crop_cap) { + struct v4l2_rect min_r = { + 0, 0, + compose->width / MAX_ZOOM, + factor * compose->height / MAX_ZOOM + }; + struct v4l2_rect max_r = { + 0, 0, + compose->width * MAX_ZOOM, + factor * compose->height * MAX_ZOOM + }; + + v4l2_rect_set_min_size(crop, &min_r); + v4l2_rect_set_max_size(crop, &max_r); + v4l2_rect_map_inside(crop, &dev->crop_bounds_cap); + } + } else if (dev->has_crop_cap && !dev->has_compose_cap) { + r.height *= factor; + v4l2_rect_set_size_to(crop, &r); + v4l2_rect_map_inside(crop, &dev->crop_bounds_cap); + r = *crop; + r.height /= factor; + v4l2_rect_set_size_to(compose, &r); + } else if (!dev->has_crop_cap) { + v4l2_rect_map_inside(compose, &r); + } else { + r.height *= factor; + v4l2_rect_set_max_size(crop, &r); + v4l2_rect_map_inside(crop, &dev->crop_bounds_cap); + compose->top *= factor; + compose->height *= factor; + v4l2_rect_set_size_to(compose, crop); + v4l2_rect_map_inside(compose, &r); + compose->top /= factor; + compose->height /= factor; + } + } else if (vivid_is_webcam(dev)) { + /* Guaranteed to be a match */ + for (i = 0; i < ARRAY_SIZE(webcam_sizes); i++) + if (webcam_sizes[i].width == mp->width && + webcam_sizes[i].height == mp->height) + break; + dev->webcam_size_idx = i; + if (dev->webcam_ival_idx >= 2 * (VIVID_WEBCAM_SIZES - i)) + dev->webcam_ival_idx = 2 * (VIVID_WEBCAM_SIZES - i) - 1; + vivid_update_format_cap(dev, false); + } else { + struct v4l2_rect r = { 0, 0, mp->width, mp->height }; + + v4l2_rect_set_size_to(compose, &r); + r.height *= factor; + v4l2_rect_set_size_to(crop, &r); + } + + dev->fmt_cap_rect.width = mp->width; + dev->fmt_cap_rect.height = mp->height; + tpg_s_buf_height(&dev->tpg, mp->height); + tpg_s_fourcc(&dev->tpg, dev->fmt_cap->fourcc); + for (p = 0; p < tpg_g_buffers(&dev->tpg); p++) + tpg_s_bytesperline(&dev->tpg, p, mp->plane_fmt[p].bytesperline); + dev->field_cap = mp->field; + if (dev->field_cap == V4L2_FIELD_ALTERNATE) + tpg_s_field(&dev->tpg, V4L2_FIELD_TOP, true); + else + tpg_s_field(&dev->tpg, dev->field_cap, false); + tpg_s_crop_compose(&dev->tpg, &dev->crop_cap, &dev->compose_cap); + if (vivid_is_sdtv_cap(dev)) + dev->tv_field_cap = mp->field; + tpg_update_mv_step(&dev->tpg); + return 0; +} + +int vidioc_g_fmt_vid_cap_mplane(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (!dev->multiplanar) + return -ENOTTY; + return vivid_g_fmt_vid_cap(file, priv, f); +} + +int vidioc_try_fmt_vid_cap_mplane(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (!dev->multiplanar) + return -ENOTTY; + return vivid_try_fmt_vid_cap(file, priv, f); +} + +int vidioc_s_fmt_vid_cap_mplane(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (!dev->multiplanar) + return -ENOTTY; + return vivid_s_fmt_vid_cap(file, priv, f); +} + +int vidioc_g_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (dev->multiplanar) + return -ENOTTY; + return fmt_sp2mp_func(file, priv, f, vivid_g_fmt_vid_cap); +} + +int vidioc_try_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (dev->multiplanar) + return -ENOTTY; + return fmt_sp2mp_func(file, priv, f, vivid_try_fmt_vid_cap); +} + +int vidioc_s_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (dev->multiplanar) + return -ENOTTY; + return fmt_sp2mp_func(file, priv, f, vivid_s_fmt_vid_cap); +} + +int vivid_vid_cap_g_selection(struct file *file, void *priv, + struct v4l2_selection *sel) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (!dev->has_crop_cap && !dev->has_compose_cap) + return -ENOTTY; + if (sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + if (vivid_is_webcam(dev)) + return -ENODATA; + + sel->r.left = sel->r.top = 0; + switch (sel->target) { + case V4L2_SEL_TGT_CROP: + if (!dev->has_crop_cap) + return -EINVAL; + sel->r = dev->crop_cap; + break; + case V4L2_SEL_TGT_CROP_DEFAULT: + case V4L2_SEL_TGT_CROP_BOUNDS: + if (!dev->has_crop_cap) + return -EINVAL; + sel->r = dev->src_rect; + break; + case V4L2_SEL_TGT_COMPOSE_BOUNDS: + if (!dev->has_compose_cap) + return -EINVAL; + sel->r = vivid_max_rect; + break; + case V4L2_SEL_TGT_COMPOSE: + if (!dev->has_compose_cap) + return -EINVAL; + sel->r = dev->compose_cap; + break; + case V4L2_SEL_TGT_COMPOSE_DEFAULT: + if (!dev->has_compose_cap) + return -EINVAL; + sel->r = dev->fmt_cap_rect; + break; + default: + return -EINVAL; + } + return 0; +} + +int vivid_vid_cap_s_selection(struct file *file, void *fh, struct v4l2_selection *s) +{ + struct vivid_dev *dev = video_drvdata(file); + struct v4l2_rect *crop = &dev->crop_cap; + struct v4l2_rect *compose = &dev->compose_cap; + unsigned factor = V4L2_FIELD_HAS_T_OR_B(dev->field_cap) ? 2 : 1; + int ret; + + if (!dev->has_crop_cap && !dev->has_compose_cap) + return -ENOTTY; + if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + if (vivid_is_webcam(dev)) + return -ENODATA; + + switch (s->target) { + case V4L2_SEL_TGT_CROP: + if (!dev->has_crop_cap) + return -EINVAL; + ret = vivid_vid_adjust_sel(s->flags, &s->r); + if (ret) + return ret; + v4l2_rect_set_min_size(&s->r, &vivid_min_rect); + v4l2_rect_set_max_size(&s->r, &dev->src_rect); + v4l2_rect_map_inside(&s->r, &dev->crop_bounds_cap); + s->r.top /= factor; + s->r.height /= factor; + if (dev->has_scaler_cap) { + struct v4l2_rect fmt = dev->fmt_cap_rect; + struct v4l2_rect max_rect = { + 0, 0, + s->r.width * MAX_ZOOM, + s->r.height * MAX_ZOOM + }; + struct v4l2_rect min_rect = { + 0, 0, + s->r.width / MAX_ZOOM, + s->r.height / MAX_ZOOM + }; + + v4l2_rect_set_min_size(&fmt, &min_rect); + if (!dev->has_compose_cap) + v4l2_rect_set_max_size(&fmt, &max_rect); + if (!v4l2_rect_same_size(&dev->fmt_cap_rect, &fmt) && + vb2_is_busy(&dev->vb_vid_cap_q)) + return -EBUSY; + if (dev->has_compose_cap) { + v4l2_rect_set_min_size(compose, &min_rect); + v4l2_rect_set_max_size(compose, &max_rect); + } + dev->fmt_cap_rect = fmt; + tpg_s_buf_height(&dev->tpg, fmt.height); + } else if (dev->has_compose_cap) { + struct v4l2_rect fmt = dev->fmt_cap_rect; + + v4l2_rect_set_min_size(&fmt, &s->r); + if (!v4l2_rect_same_size(&dev->fmt_cap_rect, &fmt) && + vb2_is_busy(&dev->vb_vid_cap_q)) + return -EBUSY; + dev->fmt_cap_rect = fmt; + tpg_s_buf_height(&dev->tpg, fmt.height); + v4l2_rect_set_size_to(compose, &s->r); + v4l2_rect_map_inside(compose, &dev->fmt_cap_rect); + } else { + if (!v4l2_rect_same_size(&s->r, &dev->fmt_cap_rect) && + vb2_is_busy(&dev->vb_vid_cap_q)) + return -EBUSY; + v4l2_rect_set_size_to(&dev->fmt_cap_rect, &s->r); + v4l2_rect_set_size_to(compose, &s->r); + v4l2_rect_map_inside(compose, &dev->fmt_cap_rect); + tpg_s_buf_height(&dev->tpg, dev->fmt_cap_rect.height); + } + s->r.top *= factor; + s->r.height *= factor; + *crop = s->r; + break; + case V4L2_SEL_TGT_COMPOSE: + if (!dev->has_compose_cap) + return -EINVAL; + ret = vivid_vid_adjust_sel(s->flags, &s->r); + if (ret) + return ret; + v4l2_rect_set_min_size(&s->r, &vivid_min_rect); + v4l2_rect_set_max_size(&s->r, &dev->fmt_cap_rect); + if (dev->has_scaler_cap) { + struct v4l2_rect max_rect = { + 0, 0, + dev->src_rect.width * MAX_ZOOM, + (dev->src_rect.height / factor) * MAX_ZOOM + }; + + v4l2_rect_set_max_size(&s->r, &max_rect); + if (dev->has_crop_cap) { + struct v4l2_rect min_rect = { + 0, 0, + s->r.width / MAX_ZOOM, + (s->r.height * factor) / MAX_ZOOM + }; + struct v4l2_rect max_rect = { + 0, 0, + s->r.width * MAX_ZOOM, + (s->r.height * factor) * MAX_ZOOM + }; + + v4l2_rect_set_min_size(crop, &min_rect); + v4l2_rect_set_max_size(crop, &max_rect); + v4l2_rect_map_inside(crop, &dev->crop_bounds_cap); + } + } else if (dev->has_crop_cap) { + s->r.top *= factor; + s->r.height *= factor; + v4l2_rect_set_max_size(&s->r, &dev->src_rect); + v4l2_rect_set_size_to(crop, &s->r); + v4l2_rect_map_inside(crop, &dev->crop_bounds_cap); + s->r.top /= factor; + s->r.height /= factor; + } else { + v4l2_rect_set_size_to(&s->r, &dev->src_rect); + s->r.height /= factor; + } + v4l2_rect_map_inside(&s->r, &dev->fmt_cap_rect); + if (dev->bitmap_cap && (compose->width != s->r.width || + compose->height != s->r.height)) { + vfree(dev->bitmap_cap); + dev->bitmap_cap = NULL; + } + *compose = s->r; + break; + default: + return -EINVAL; + } + + tpg_s_crop_compose(&dev->tpg, crop, compose); + return 0; +} + +int vivid_vid_cap_g_pixelaspect(struct file *file, void *priv, + int type, struct v4l2_fract *f) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + switch (vivid_get_pixel_aspect(dev)) { + case TPG_PIXEL_ASPECT_NTSC: + f->numerator = 11; + f->denominator = 10; + break; + case TPG_PIXEL_ASPECT_PAL: + f->numerator = 54; + f->denominator = 59; + break; + default: + break; + } + return 0; +} + +int vidioc_enum_fmt_vid_overlay(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + struct vivid_dev *dev = video_drvdata(file); + const struct vivid_fmt *fmt; + + if (dev->multiplanar) + return -ENOTTY; + + if (f->index >= ARRAY_SIZE(formats_ovl)) + return -EINVAL; + + fmt = &formats_ovl[f->index]; + + f->pixelformat = fmt->fourcc; + return 0; +} + +int vidioc_g_fmt_vid_overlay(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct vivid_dev *dev = video_drvdata(file); + const struct v4l2_rect *compose = &dev->compose_cap; + struct v4l2_window *win = &f->fmt.win; + unsigned clipcount = win->clipcount; + + if (dev->multiplanar) + return -ENOTTY; + + win->w.top = dev->overlay_cap_top; + win->w.left = dev->overlay_cap_left; + win->w.width = compose->width; + win->w.height = compose->height; + win->field = dev->overlay_cap_field; + win->clipcount = dev->clipcount_cap; + if (clipcount > dev->clipcount_cap) + clipcount = dev->clipcount_cap; + if (dev->bitmap_cap == NULL) + win->bitmap = NULL; + else if (win->bitmap) { + if (copy_to_user(win->bitmap, dev->bitmap_cap, + ((compose->width + 7) / 8) * compose->height)) + return -EFAULT; + } + if (clipcount && win->clips) { + if (copy_to_user(win->clips, dev->clips_cap, + clipcount * sizeof(dev->clips_cap[0]))) + return -EFAULT; + } + return 0; +} + +int vidioc_try_fmt_vid_overlay(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct vivid_dev *dev = video_drvdata(file); + const struct v4l2_rect *compose = &dev->compose_cap; + struct v4l2_window *win = &f->fmt.win; + int i, j; + + if (dev->multiplanar) + return -ENOTTY; + + win->w.left = clamp_t(int, win->w.left, + -dev->fb_cap.fmt.width, dev->fb_cap.fmt.width); + win->w.top = clamp_t(int, win->w.top, + -dev->fb_cap.fmt.height, dev->fb_cap.fmt.height); + win->w.width = compose->width; + win->w.height = compose->height; + if (win->field != V4L2_FIELD_BOTTOM && win->field != V4L2_FIELD_TOP) + win->field = V4L2_FIELD_ANY; + win->chromakey = 0; + win->global_alpha = 0; + if (win->clipcount && !win->clips) + win->clipcount = 0; + if (win->clipcount > MAX_CLIPS) + win->clipcount = MAX_CLIPS; + if (win->clipcount) { + if (copy_from_user(dev->try_clips_cap, win->clips, + win->clipcount * sizeof(dev->clips_cap[0]))) + return -EFAULT; + for (i = 0; i < win->clipcount; i++) { + struct v4l2_rect *r = &dev->try_clips_cap[i].c; + + r->top = clamp_t(s32, r->top, 0, dev->fb_cap.fmt.height - 1); + r->height = clamp_t(s32, r->height, 1, dev->fb_cap.fmt.height - r->top); + r->left = clamp_t(u32, r->left, 0, dev->fb_cap.fmt.width - 1); + r->width = clamp_t(u32, r->width, 1, dev->fb_cap.fmt.width - r->left); + } + /* + * Yeah, so sue me, it's an O(n^2) algorithm. But n is a small + * number and it's typically a one-time deal. + */ + for (i = 0; i < win->clipcount - 1; i++) { + struct v4l2_rect *r1 = &dev->try_clips_cap[i].c; + + for (j = i + 1; j < win->clipcount; j++) { + struct v4l2_rect *r2 = &dev->try_clips_cap[j].c; + + if (v4l2_rect_overlap(r1, r2)) + return -EINVAL; + } + } + if (copy_to_user(win->clips, dev->try_clips_cap, + win->clipcount * sizeof(dev->clips_cap[0]))) + return -EFAULT; + } + return 0; +} + +int vidioc_s_fmt_vid_overlay(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct vivid_dev *dev = video_drvdata(file); + const struct v4l2_rect *compose = &dev->compose_cap; + struct v4l2_window *win = &f->fmt.win; + int ret = vidioc_try_fmt_vid_overlay(file, priv, f); + unsigned bitmap_size = ((compose->width + 7) / 8) * compose->height; + unsigned clips_size = win->clipcount * sizeof(dev->clips_cap[0]); + void *new_bitmap = NULL; + + if (ret) + return ret; + + if (win->bitmap) { + new_bitmap = vzalloc(bitmap_size); + + if (new_bitmap == NULL) + return -ENOMEM; + if (copy_from_user(new_bitmap, win->bitmap, bitmap_size)) { + vfree(new_bitmap); + return -EFAULT; + } + } + + dev->overlay_cap_top = win->w.top; + dev->overlay_cap_left = win->w.left; + dev->overlay_cap_field = win->field; + vfree(dev->bitmap_cap); + dev->bitmap_cap = new_bitmap; + dev->clipcount_cap = win->clipcount; + if (dev->clipcount_cap) + memcpy(dev->clips_cap, dev->try_clips_cap, clips_size); + return 0; +} + +int vivid_vid_cap_overlay(struct file *file, void *fh, unsigned i) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (dev->multiplanar) + return -ENOTTY; + + if (i && dev->fb_vbase_cap == NULL) + return -EINVAL; + + if (i && dev->fb_cap.fmt.pixelformat != dev->fmt_cap->fourcc) { + dprintk(dev, 1, "mismatch between overlay and video capture pixelformats\n"); + return -EINVAL; + } + + if (dev->overlay_cap_owner && dev->overlay_cap_owner != fh) + return -EBUSY; + dev->overlay_cap_owner = i ? fh : NULL; + return 0; +} + +int vivid_vid_cap_g_fbuf(struct file *file, void *fh, + struct v4l2_framebuffer *a) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (dev->multiplanar) + return -ENOTTY; + + *a = dev->fb_cap; + a->capability = V4L2_FBUF_CAP_BITMAP_CLIPPING | + V4L2_FBUF_CAP_LIST_CLIPPING; + a->flags = V4L2_FBUF_FLAG_PRIMARY; + a->fmt.field = V4L2_FIELD_NONE; + a->fmt.colorspace = V4L2_COLORSPACE_SRGB; + a->fmt.priv = 0; + return 0; +} + +int vivid_vid_cap_s_fbuf(struct file *file, void *fh, + const struct v4l2_framebuffer *a) +{ + struct vivid_dev *dev = video_drvdata(file); + const struct vivid_fmt *fmt; + + if (dev->multiplanar) + return -ENOTTY; + + if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RAWIO)) + return -EPERM; + + if (dev->overlay_cap_owner) + return -EBUSY; + + if (a->base == NULL) { + dev->fb_cap.base = NULL; + dev->fb_vbase_cap = NULL; + return 0; + } + + if (a->fmt.width < 48 || a->fmt.height < 32) + return -EINVAL; + fmt = vivid_get_format(dev, a->fmt.pixelformat); + if (!fmt || !fmt->can_do_overlay) + return -EINVAL; + if (a->fmt.bytesperline < (a->fmt.width * fmt->bit_depth[0]) / 8) + return -EINVAL; + if (a->fmt.height * a->fmt.bytesperline < a->fmt.sizeimage) + return -EINVAL; + + dev->fb_vbase_cap = phys_to_virt((unsigned long)a->base); + dev->fb_cap = *a; + dev->overlay_cap_left = clamp_t(int, dev->overlay_cap_left, + -dev->fb_cap.fmt.width, dev->fb_cap.fmt.width); + dev->overlay_cap_top = clamp_t(int, dev->overlay_cap_top, + -dev->fb_cap.fmt.height, dev->fb_cap.fmt.height); + return 0; +} + +static const struct v4l2_audio vivid_audio_inputs[] = { + { 0, "TV", V4L2_AUDCAP_STEREO }, + { 1, "Line-In", V4L2_AUDCAP_STEREO }, +}; + +int vidioc_enum_input(struct file *file, void *priv, + struct v4l2_input *inp) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (inp->index >= dev->num_inputs) + return -EINVAL; + + inp->type = V4L2_INPUT_TYPE_CAMERA; + switch (dev->input_type[inp->index]) { + case WEBCAM: + snprintf(inp->name, sizeof(inp->name), "Webcam %u", + dev->input_name_counter[inp->index]); + inp->capabilities = 0; + break; + case TV: + snprintf(inp->name, sizeof(inp->name), "TV %u", + dev->input_name_counter[inp->index]); + inp->type = V4L2_INPUT_TYPE_TUNER; + inp->std = V4L2_STD_ALL; + if (dev->has_audio_inputs) + inp->audioset = (1 << ARRAY_SIZE(vivid_audio_inputs)) - 1; + inp->capabilities = V4L2_IN_CAP_STD; + break; + case SVID: + snprintf(inp->name, sizeof(inp->name), "S-Video %u", + dev->input_name_counter[inp->index]); + inp->std = V4L2_STD_ALL; + if (dev->has_audio_inputs) + inp->audioset = (1 << ARRAY_SIZE(vivid_audio_inputs)) - 1; + inp->capabilities = V4L2_IN_CAP_STD; + break; + case HDMI: + snprintf(inp->name, sizeof(inp->name), "HDMI %u", + dev->input_name_counter[inp->index]); + inp->capabilities = V4L2_IN_CAP_DV_TIMINGS; + if (dev->edid_blocks == 0 || + dev->dv_timings_signal_mode[dev->input] == NO_SIGNAL) + inp->status |= V4L2_IN_ST_NO_SIGNAL; + else if (dev->dv_timings_signal_mode[dev->input] == NO_LOCK || + dev->dv_timings_signal_mode[dev->input] == OUT_OF_RANGE) + inp->status |= V4L2_IN_ST_NO_H_LOCK; + break; + } + if (dev->sensor_hflip) + inp->status |= V4L2_IN_ST_HFLIP; + if (dev->sensor_vflip) + inp->status |= V4L2_IN_ST_VFLIP; + if (dev->input == inp->index && vivid_is_sdtv_cap(dev)) { + if (dev->std_signal_mode[dev->input] == NO_SIGNAL) { + inp->status |= V4L2_IN_ST_NO_SIGNAL; + } else if (dev->std_signal_mode[dev->input] == NO_LOCK) { + inp->status |= V4L2_IN_ST_NO_H_LOCK; + } else if (vivid_is_tv_cap(dev)) { + switch (tpg_g_quality(&dev->tpg)) { + case TPG_QUAL_GRAY: + inp->status |= V4L2_IN_ST_COLOR_KILL; + break; + case TPG_QUAL_NOISE: + inp->status |= V4L2_IN_ST_NO_H_LOCK; + break; + default: + break; + } + } + } + return 0; +} + +int vidioc_g_input(struct file *file, void *priv, unsigned *i) +{ + struct vivid_dev *dev = video_drvdata(file); + + *i = dev->input; + return 0; +} + +int vidioc_s_input(struct file *file, void *priv, unsigned i) +{ + struct vivid_dev *dev = video_drvdata(file); + struct v4l2_bt_timings *bt = &dev->dv_timings_cap[dev->input].bt; + unsigned brightness; + + if (i >= dev->num_inputs) + return -EINVAL; + + if (i == dev->input) + return 0; + + if (vb2_is_busy(&dev->vb_vid_cap_q) || + vb2_is_busy(&dev->vb_vbi_cap_q) || + vb2_is_busy(&dev->vb_meta_cap_q)) + return -EBUSY; + + dev->input = i; + dev->vid_cap_dev.tvnorms = 0; + if (dev->input_type[i] == TV || dev->input_type[i] == SVID) { + dev->tv_audio_input = (dev->input_type[i] == TV) ? 0 : 1; + dev->vid_cap_dev.tvnorms = V4L2_STD_ALL; + } + dev->vbi_cap_dev.tvnorms = dev->vid_cap_dev.tvnorms; + dev->meta_cap_dev.tvnorms = dev->vid_cap_dev.tvnorms; + vivid_update_format_cap(dev, false); + + if (dev->colorspace) { + switch (dev->input_type[i]) { + case WEBCAM: + v4l2_ctrl_s_ctrl(dev->colorspace, VIVID_CS_SRGB); + break; + case TV: + case SVID: + v4l2_ctrl_s_ctrl(dev->colorspace, VIVID_CS_170M); + break; + case HDMI: + if (bt->flags & V4L2_DV_FL_IS_CE_VIDEO) { + if (dev->src_rect.width == 720 && dev->src_rect.height <= 576) + v4l2_ctrl_s_ctrl(dev->colorspace, VIVID_CS_170M); + else + v4l2_ctrl_s_ctrl(dev->colorspace, VIVID_CS_709); + } else { + v4l2_ctrl_s_ctrl(dev->colorspace, VIVID_CS_SRGB); + } + break; + } + } + + /* + * Modify the brightness range depending on the input. + * This makes it easy to use vivid to test if applications can + * handle control range modifications and is also how this is + * typically used in practice as different inputs may be hooked + * up to different receivers with different control ranges. + */ + brightness = 128 * i + dev->input_brightness[i]; + v4l2_ctrl_modify_range(dev->brightness, + 128 * i, 255 + 128 * i, 1, 128 + 128 * i); + v4l2_ctrl_s_ctrl(dev->brightness, brightness); + + /* Restore per-input states. */ + v4l2_ctrl_activate(dev->ctrl_dv_timings_signal_mode, + vivid_is_hdmi_cap(dev)); + v4l2_ctrl_activate(dev->ctrl_dv_timings, vivid_is_hdmi_cap(dev) && + dev->dv_timings_signal_mode[dev->input] == + SELECTED_DV_TIMINGS); + v4l2_ctrl_activate(dev->ctrl_std_signal_mode, vivid_is_sdtv_cap(dev)); + v4l2_ctrl_activate(dev->ctrl_standard, vivid_is_sdtv_cap(dev) && + dev->std_signal_mode[dev->input]); + + if (vivid_is_hdmi_cap(dev)) { + v4l2_ctrl_s_ctrl(dev->ctrl_dv_timings_signal_mode, + dev->dv_timings_signal_mode[dev->input]); + v4l2_ctrl_s_ctrl(dev->ctrl_dv_timings, + dev->query_dv_timings[dev->input]); + } else if (vivid_is_sdtv_cap(dev)) { + v4l2_ctrl_s_ctrl(dev->ctrl_std_signal_mode, + dev->std_signal_mode[dev->input]); + v4l2_ctrl_s_ctrl(dev->ctrl_standard, + dev->std_signal_mode[dev->input]); + } + + return 0; +} + +int vidioc_enumaudio(struct file *file, void *fh, struct v4l2_audio *vin) +{ + if (vin->index >= ARRAY_SIZE(vivid_audio_inputs)) + return -EINVAL; + *vin = vivid_audio_inputs[vin->index]; + return 0; +} + +int vidioc_g_audio(struct file *file, void *fh, struct v4l2_audio *vin) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (!vivid_is_sdtv_cap(dev)) + return -EINVAL; + *vin = vivid_audio_inputs[dev->tv_audio_input]; + return 0; +} + +int vidioc_s_audio(struct file *file, void *fh, const struct v4l2_audio *vin) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (!vivid_is_sdtv_cap(dev)) + return -EINVAL; + if (vin->index >= ARRAY_SIZE(vivid_audio_inputs)) + return -EINVAL; + dev->tv_audio_input = vin->index; + return 0; +} + +int vivid_video_g_frequency(struct file *file, void *fh, struct v4l2_frequency *vf) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (vf->tuner != 0) + return -EINVAL; + vf->frequency = dev->tv_freq; + return 0; +} + +int vivid_video_s_frequency(struct file *file, void *fh, const struct v4l2_frequency *vf) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (vf->tuner != 0) + return -EINVAL; + dev->tv_freq = clamp_t(unsigned, vf->frequency, MIN_TV_FREQ, MAX_TV_FREQ); + if (vivid_is_tv_cap(dev)) + vivid_update_quality(dev); + return 0; +} + +int vivid_video_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *vt) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (vt->index != 0) + return -EINVAL; + if (vt->audmode > V4L2_TUNER_MODE_LANG1_LANG2) + return -EINVAL; + dev->tv_audmode = vt->audmode; + return 0; +} + +int vivid_video_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt) +{ + struct vivid_dev *dev = video_drvdata(file); + enum tpg_quality qual; + + if (vt->index != 0) + return -EINVAL; + + vt->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO | + V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2; + vt->audmode = dev->tv_audmode; + vt->rangelow = MIN_TV_FREQ; + vt->rangehigh = MAX_TV_FREQ; + qual = vivid_get_quality(dev, &vt->afc); + if (qual == TPG_QUAL_COLOR) + vt->signal = 0xffff; + else if (qual == TPG_QUAL_GRAY) + vt->signal = 0x8000; + else + vt->signal = 0; + if (qual == TPG_QUAL_NOISE) { + vt->rxsubchans = 0; + } else if (qual == TPG_QUAL_GRAY) { + vt->rxsubchans = V4L2_TUNER_SUB_MONO; + } else { + unsigned int channel_nr = dev->tv_freq / (6 * 16); + unsigned int options = + (dev->std_cap[dev->input] & V4L2_STD_NTSC_M) ? 4 : 3; + + switch (channel_nr % options) { + case 0: + vt->rxsubchans = V4L2_TUNER_SUB_MONO; + break; + case 1: + vt->rxsubchans = V4L2_TUNER_SUB_STEREO; + break; + case 2: + if (dev->std_cap[dev->input] & V4L2_STD_NTSC_M) + vt->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_SAP; + else + vt->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; + break; + case 3: + vt->rxsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_SAP; + break; + } + } + strscpy(vt->name, "TV Tuner", sizeof(vt->name)); + return 0; +} + +/* Must remain in sync with the vivid_ctrl_standard_strings array */ +const v4l2_std_id vivid_standard[] = { + V4L2_STD_NTSC_M, + V4L2_STD_NTSC_M_JP, + V4L2_STD_NTSC_M_KR, + V4L2_STD_NTSC_443, + V4L2_STD_PAL_BG | V4L2_STD_PAL_H, + V4L2_STD_PAL_I, + V4L2_STD_PAL_DK, + V4L2_STD_PAL_M, + V4L2_STD_PAL_N, + V4L2_STD_PAL_Nc, + V4L2_STD_PAL_60, + V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H, + V4L2_STD_SECAM_DK, + V4L2_STD_SECAM_L, + V4L2_STD_SECAM_LC, + V4L2_STD_UNKNOWN +}; + +/* Must remain in sync with the vivid_standard array */ +const char * const vivid_ctrl_standard_strings[] = { + "NTSC-M", + "NTSC-M-JP", + "NTSC-M-KR", + "NTSC-443", + "PAL-BGH", + "PAL-I", + "PAL-DK", + "PAL-M", + "PAL-N", + "PAL-Nc", + "PAL-60", + "SECAM-BGH", + "SECAM-DK", + "SECAM-L", + "SECAM-Lc", + NULL, +}; + +int vidioc_querystd(struct file *file, void *priv, v4l2_std_id *id) +{ + struct vivid_dev *dev = video_drvdata(file); + unsigned int last = dev->query_std_last[dev->input]; + + if (!vivid_is_sdtv_cap(dev)) + return -ENODATA; + if (dev->std_signal_mode[dev->input] == NO_SIGNAL || + dev->std_signal_mode[dev->input] == NO_LOCK) { + *id = V4L2_STD_UNKNOWN; + return 0; + } + if (vivid_is_tv_cap(dev) && tpg_g_quality(&dev->tpg) == TPG_QUAL_NOISE) { + *id = V4L2_STD_UNKNOWN; + } else if (dev->std_signal_mode[dev->input] == CURRENT_STD) { + *id = dev->std_cap[dev->input]; + } else if (dev->std_signal_mode[dev->input] == SELECTED_STD) { + *id = dev->query_std[dev->input]; + } else { + *id = vivid_standard[last]; + dev->query_std_last[dev->input] = + (last + 1) % ARRAY_SIZE(vivid_standard); + } + + return 0; +} + +int vivid_vid_cap_s_std(struct file *file, void *priv, v4l2_std_id id) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (!vivid_is_sdtv_cap(dev)) + return -ENODATA; + if (dev->std_cap[dev->input] == id) + return 0; + if (vb2_is_busy(&dev->vb_vid_cap_q) || vb2_is_busy(&dev->vb_vbi_cap_q)) + return -EBUSY; + dev->std_cap[dev->input] = id; + vivid_update_format_cap(dev, false); + return 0; +} + +static void find_aspect_ratio(u32 width, u32 height, + u32 *num, u32 *denom) +{ + if (!(height % 3) && ((height * 4 / 3) == width)) { + *num = 4; + *denom = 3; + } else if (!(height % 9) && ((height * 16 / 9) == width)) { + *num = 16; + *denom = 9; + } else if (!(height % 10) && ((height * 16 / 10) == width)) { + *num = 16; + *denom = 10; + } else if (!(height % 4) && ((height * 5 / 4) == width)) { + *num = 5; + *denom = 4; + } else if (!(height % 9) && ((height * 15 / 9) == width)) { + *num = 15; + *denom = 9; + } else { /* default to 16:9 */ + *num = 16; + *denom = 9; + } +} + +static bool valid_cvt_gtf_timings(struct v4l2_dv_timings *timings) +{ + struct v4l2_bt_timings *bt = &timings->bt; + u32 total_h_pixel; + u32 total_v_lines; + u32 h_freq; + + if (!v4l2_valid_dv_timings(timings, &vivid_dv_timings_cap, + NULL, NULL)) + return false; + + total_h_pixel = V4L2_DV_BT_FRAME_WIDTH(bt); + total_v_lines = V4L2_DV_BT_FRAME_HEIGHT(bt); + + h_freq = (u32)bt->pixelclock / total_h_pixel; + + if (bt->standards == 0 || (bt->standards & V4L2_DV_BT_STD_CVT)) { + if (v4l2_detect_cvt(total_v_lines, h_freq, bt->vsync, bt->width, + bt->polarities, bt->interlaced, timings)) + return true; + } + + if (bt->standards == 0 || (bt->standards & V4L2_DV_BT_STD_GTF)) { + struct v4l2_fract aspect_ratio; + + find_aspect_ratio(bt->width, bt->height, + &aspect_ratio.numerator, + &aspect_ratio.denominator); + if (v4l2_detect_gtf(total_v_lines, h_freq, bt->vsync, + bt->polarities, bt->interlaced, + aspect_ratio, timings)) + return true; + } + return false; +} + +int vivid_vid_cap_s_dv_timings(struct file *file, void *_fh, + struct v4l2_dv_timings *timings) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (!vivid_is_hdmi_cap(dev)) + return -ENODATA; + if (!v4l2_find_dv_timings_cap(timings, &vivid_dv_timings_cap, + 0, NULL, NULL) && + !valid_cvt_gtf_timings(timings)) + return -EINVAL; + + if (v4l2_match_dv_timings(timings, &dev->dv_timings_cap[dev->input], + 0, false)) + return 0; + if (vb2_is_busy(&dev->vb_vid_cap_q)) + return -EBUSY; + + dev->dv_timings_cap[dev->input] = *timings; + vivid_update_format_cap(dev, false); + return 0; +} + +int vidioc_query_dv_timings(struct file *file, void *_fh, + struct v4l2_dv_timings *timings) +{ + struct vivid_dev *dev = video_drvdata(file); + unsigned int input = dev->input; + unsigned int last = dev->query_dv_timings_last[input]; + + if (!vivid_is_hdmi_cap(dev)) + return -ENODATA; + if (dev->dv_timings_signal_mode[input] == NO_SIGNAL || + dev->edid_blocks == 0) + return -ENOLINK; + if (dev->dv_timings_signal_mode[input] == NO_LOCK) + return -ENOLCK; + if (dev->dv_timings_signal_mode[input] == OUT_OF_RANGE) { + timings->bt.pixelclock = vivid_dv_timings_cap.bt.max_pixelclock * 2; + return -ERANGE; + } + if (dev->dv_timings_signal_mode[input] == CURRENT_DV_TIMINGS) { + *timings = dev->dv_timings_cap[input]; + } else if (dev->dv_timings_signal_mode[input] == + SELECTED_DV_TIMINGS) { + *timings = + v4l2_dv_timings_presets[dev->query_dv_timings[input]]; + } else { + *timings = + v4l2_dv_timings_presets[last]; + dev->query_dv_timings_last[input] = + (last + 1) % dev->query_dv_timings_size; + } + return 0; +} + +int vidioc_s_edid(struct file *file, void *_fh, + struct v4l2_edid *edid) +{ + struct vivid_dev *dev = video_drvdata(file); + u16 phys_addr; + u32 display_present = 0; + unsigned int i, j; + int ret; + + memset(edid->reserved, 0, sizeof(edid->reserved)); + if (edid->pad >= dev->num_inputs) + return -EINVAL; + if (dev->input_type[edid->pad] != HDMI || edid->start_block) + return -EINVAL; + if (edid->blocks == 0) { + dev->edid_blocks = 0; + v4l2_ctrl_s_ctrl(dev->ctrl_tx_edid_present, 0); + v4l2_ctrl_s_ctrl(dev->ctrl_tx_hotplug, 0); + phys_addr = CEC_PHYS_ADDR_INVALID; + goto set_phys_addr; + } + if (edid->blocks > dev->edid_max_blocks) { + edid->blocks = dev->edid_max_blocks; + return -E2BIG; + } + phys_addr = cec_get_edid_phys_addr(edid->edid, edid->blocks * 128, NULL); + ret = v4l2_phys_addr_validate(phys_addr, &phys_addr, NULL); + if (ret) + return ret; + + if (vb2_is_busy(&dev->vb_vid_cap_q)) + return -EBUSY; + + dev->edid_blocks = edid->blocks; + memcpy(dev->edid, edid->edid, edid->blocks * 128); + + for (i = 0, j = 0; i < dev->num_outputs; i++) + if (dev->output_type[i] == HDMI) + display_present |= + dev->display_present[i] << j++; + + v4l2_ctrl_s_ctrl(dev->ctrl_tx_edid_present, display_present); + v4l2_ctrl_s_ctrl(dev->ctrl_tx_hotplug, display_present); + +set_phys_addr: + /* TODO: a proper hotplug detect cycle should be emulated here */ + cec_s_phys_addr(dev->cec_rx_adap, phys_addr, false); + + for (i = 0; i < MAX_OUTPUTS && dev->cec_tx_adap[i]; i++) + cec_s_phys_addr(dev->cec_tx_adap[i], + dev->display_present[i] ? + v4l2_phys_addr_for_input(phys_addr, i + 1) : + CEC_PHYS_ADDR_INVALID, + false); + return 0; +} + +int vidioc_enum_framesizes(struct file *file, void *fh, + struct v4l2_frmsizeenum *fsize) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (!vivid_is_webcam(dev) && !dev->has_scaler_cap) + return -EINVAL; + if (vivid_get_format(dev, fsize->pixel_format) == NULL) + return -EINVAL; + if (vivid_is_webcam(dev)) { + if (fsize->index >= ARRAY_SIZE(webcam_sizes)) + return -EINVAL; + fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; + fsize->discrete = webcam_sizes[fsize->index]; + return 0; + } + if (fsize->index) + return -EINVAL; + fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; + fsize->stepwise.min_width = MIN_WIDTH; + fsize->stepwise.max_width = MAX_WIDTH * MAX_ZOOM; + fsize->stepwise.step_width = 2; + fsize->stepwise.min_height = MIN_HEIGHT; + fsize->stepwise.max_height = MAX_HEIGHT * MAX_ZOOM; + fsize->stepwise.step_height = 2; + return 0; +} + +/* timeperframe is arbitrary and continuous */ +int vidioc_enum_frameintervals(struct file *file, void *priv, + struct v4l2_frmivalenum *fival) +{ + struct vivid_dev *dev = video_drvdata(file); + const struct vivid_fmt *fmt; + int i; + + fmt = vivid_get_format(dev, fival->pixel_format); + if (!fmt) + return -EINVAL; + + if (!vivid_is_webcam(dev)) { + if (fival->index) + return -EINVAL; + if (fival->width < MIN_WIDTH || fival->width > MAX_WIDTH * MAX_ZOOM) + return -EINVAL; + if (fival->height < MIN_HEIGHT || fival->height > MAX_HEIGHT * MAX_ZOOM) + return -EINVAL; + fival->type = V4L2_FRMIVAL_TYPE_DISCRETE; + fival->discrete = dev->timeperframe_vid_cap; + return 0; + } + + for (i = 0; i < ARRAY_SIZE(webcam_sizes); i++) + if (fival->width == webcam_sizes[i].width && + fival->height == webcam_sizes[i].height) + break; + if (i == ARRAY_SIZE(webcam_sizes)) + return -EINVAL; + if (fival->index >= 2 * (VIVID_WEBCAM_SIZES - i)) + return -EINVAL; + fival->type = V4L2_FRMIVAL_TYPE_DISCRETE; + fival->discrete = webcam_intervals[fival->index]; + return 0; +} + +int vivid_vid_cap_g_parm(struct file *file, void *priv, + struct v4l2_streamparm *parm) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (parm->type != (dev->multiplanar ? + V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE : + V4L2_BUF_TYPE_VIDEO_CAPTURE)) + return -EINVAL; + + parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; + parm->parm.capture.timeperframe = dev->timeperframe_vid_cap; + parm->parm.capture.readbuffers = 1; + return 0; +} + +int vivid_vid_cap_s_parm(struct file *file, void *priv, + struct v4l2_streamparm *parm) +{ + struct vivid_dev *dev = video_drvdata(file); + unsigned ival_sz = 2 * (VIVID_WEBCAM_SIZES - dev->webcam_size_idx); + struct v4l2_fract tpf; + unsigned i; + + if (parm->type != (dev->multiplanar ? + V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE : + V4L2_BUF_TYPE_VIDEO_CAPTURE)) + return -EINVAL; + if (!vivid_is_webcam(dev)) + return vivid_vid_cap_g_parm(file, priv, parm); + + tpf = parm->parm.capture.timeperframe; + + if (tpf.denominator == 0) + tpf = webcam_intervals[ival_sz - 1]; + for (i = 0; i < ival_sz; i++) + if (V4L2_FRACT_COMPARE(tpf, >=, webcam_intervals[i])) + break; + if (i == ival_sz) + i = ival_sz - 1; + dev->webcam_ival_idx = i; + tpf = webcam_intervals[dev->webcam_ival_idx]; + + /* resync the thread's timings */ + dev->cap_seq_resync = true; + dev->timeperframe_vid_cap = tpf; + parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; + parm->parm.capture.timeperframe = tpf; + parm->parm.capture.readbuffers = 1; + return 0; +} diff --git a/drivers/media/test_drivers/vivid/vivid-vid-cap.h b/drivers/media/test_drivers/vivid/vivid-vid-cap.h new file mode 100644 index 000000000000..1e422a59eeab --- /dev/null +++ b/drivers/media/test_drivers/vivid/vivid-vid-cap.h @@ -0,0 +1,59 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * vivid-vid-cap.h - video capture support functions. + * + * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. + */ + +#ifndef _VIVID_VID_CAP_H_ +#define _VIVID_VID_CAP_H_ + +void vivid_update_quality(struct vivid_dev *dev); +void vivid_update_format_cap(struct vivid_dev *dev, bool keep_controls); +enum tpg_video_aspect vivid_get_video_aspect(const struct vivid_dev *dev); + +extern const v4l2_std_id vivid_standard[]; +extern const char * const vivid_ctrl_standard_strings[]; + +extern const struct vb2_ops vivid_vid_cap_qops; + +int vivid_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f); +int vivid_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f); +int vivid_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f); +int vidioc_g_fmt_vid_cap_mplane(struct file *file, void *priv, struct v4l2_format *f); +int vidioc_try_fmt_vid_cap_mplane(struct file *file, void *priv, struct v4l2_format *f); +int vidioc_s_fmt_vid_cap_mplane(struct file *file, void *priv, struct v4l2_format *f); +int vidioc_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f); +int vidioc_try_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f); +int vidioc_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f); +int vivid_vid_cap_g_selection(struct file *file, void *priv, struct v4l2_selection *sel); +int vivid_vid_cap_s_selection(struct file *file, void *fh, struct v4l2_selection *s); +int vivid_vid_cap_g_pixelaspect(struct file *file, void *priv, int type, struct v4l2_fract *f); +int vidioc_enum_fmt_vid_overlay(struct file *file, void *priv, struct v4l2_fmtdesc *f); +int vidioc_g_fmt_vid_overlay(struct file *file, void *priv, struct v4l2_format *f); +int vidioc_try_fmt_vid_overlay(struct file *file, void *priv, struct v4l2_format *f); +int vidioc_s_fmt_vid_overlay(struct file *file, void *priv, struct v4l2_format *f); +int vivid_vid_cap_overlay(struct file *file, void *fh, unsigned i); +int vivid_vid_cap_g_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *a); +int vivid_vid_cap_s_fbuf(struct file *file, void *fh, const struct v4l2_framebuffer *a); +int vidioc_enum_input(struct file *file, void *priv, struct v4l2_input *inp); +int vidioc_g_input(struct file *file, void *priv, unsigned *i); +int vidioc_s_input(struct file *file, void *priv, unsigned i); +int vidioc_enumaudio(struct file *file, void *fh, struct v4l2_audio *vin); +int vidioc_g_audio(struct file *file, void *fh, struct v4l2_audio *vin); +int vidioc_s_audio(struct file *file, void *fh, const struct v4l2_audio *vin); +int vivid_video_g_frequency(struct file *file, void *fh, struct v4l2_frequency *vf); +int vivid_video_s_frequency(struct file *file, void *fh, const struct v4l2_frequency *vf); +int vivid_video_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *vt); +int vivid_video_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt); +int vidioc_querystd(struct file *file, void *priv, v4l2_std_id *id); +int vivid_vid_cap_s_std(struct file *file, void *priv, v4l2_std_id id); +int vivid_vid_cap_s_dv_timings(struct file *file, void *_fh, struct v4l2_dv_timings *timings); +int vidioc_query_dv_timings(struct file *file, void *_fh, struct v4l2_dv_timings *timings); +int vidioc_s_edid(struct file *file, void *_fh, struct v4l2_edid *edid); +int vidioc_enum_framesizes(struct file *file, void *fh, struct v4l2_frmsizeenum *fsize); +int vidioc_enum_frameintervals(struct file *file, void *priv, struct v4l2_frmivalenum *fival); +int vivid_vid_cap_g_parm(struct file *file, void *priv, struct v4l2_streamparm *parm); +int vivid_vid_cap_s_parm(struct file *file, void *priv, struct v4l2_streamparm *parm); + +#endif diff --git a/drivers/media/test_drivers/vivid/vivid-vid-common.c b/drivers/media/test_drivers/vivid/vivid-vid-common.c new file mode 100644 index 000000000000..76b0be670ebb --- /dev/null +++ b/drivers/media/test_drivers/vivid/vivid-vid-common.c @@ -0,0 +1,1035 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * vivid-vid-common.c - common video support functions. + * + * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "vivid-core.h" +#include "vivid-vid-common.h" + +const struct v4l2_dv_timings_cap vivid_dv_timings_cap = { + .type = V4L2_DV_BT_656_1120, + /* keep this initialization for compatibility with GCC < 4.4.6 */ + .reserved = { 0 }, + V4L2_INIT_BT_TIMINGS(16, MAX_WIDTH, 16, MAX_HEIGHT, 14000000, 775000000, + V4L2_DV_BT_STD_CEA861 | V4L2_DV_BT_STD_DMT | + V4L2_DV_BT_STD_CVT | V4L2_DV_BT_STD_GTF, + V4L2_DV_BT_CAP_PROGRESSIVE | V4L2_DV_BT_CAP_INTERLACED) +}; + +/* ------------------------------------------------------------------ + Basic structures + ------------------------------------------------------------------*/ + +struct vivid_fmt vivid_formats[] = { + { + .fourcc = V4L2_PIX_FMT_YUYV, + .vdownsampling = { 1 }, + .bit_depth = { 16 }, + .color_enc = TGP_COLOR_ENC_YCBCR, + .planes = 1, + .buffers = 1, + .data_offset = { PLANE0_DATA_OFFSET }, + }, + { + .fourcc = V4L2_PIX_FMT_UYVY, + .vdownsampling = { 1 }, + .bit_depth = { 16 }, + .color_enc = TGP_COLOR_ENC_YCBCR, + .planes = 1, + .buffers = 1, + }, + { + .fourcc = V4L2_PIX_FMT_YVYU, + .vdownsampling = { 1 }, + .bit_depth = { 16 }, + .color_enc = TGP_COLOR_ENC_YCBCR, + .planes = 1, + .buffers = 1, + }, + { + .fourcc = V4L2_PIX_FMT_VYUY, + .vdownsampling = { 1 }, + .bit_depth = { 16 }, + .color_enc = TGP_COLOR_ENC_YCBCR, + .planes = 1, + .buffers = 1, + }, + { + .fourcc = V4L2_PIX_FMT_YUV422P, + .vdownsampling = { 1, 1, 1 }, + .bit_depth = { 8, 4, 4 }, + .color_enc = TGP_COLOR_ENC_YCBCR, + .planes = 3, + .buffers = 1, + }, + { + .fourcc = V4L2_PIX_FMT_YUV420, + .vdownsampling = { 1, 2, 2 }, + .bit_depth = { 8, 4, 4 }, + .color_enc = TGP_COLOR_ENC_YCBCR, + .planes = 3, + .buffers = 1, + }, + { + .fourcc = V4L2_PIX_FMT_YVU420, + .vdownsampling = { 1, 2, 2 }, + .bit_depth = { 8, 4, 4 }, + .color_enc = TGP_COLOR_ENC_YCBCR, + .planes = 3, + .buffers = 1, + }, + { + .fourcc = V4L2_PIX_FMT_NV12, + .vdownsampling = { 1, 2 }, + .bit_depth = { 8, 8 }, + .color_enc = TGP_COLOR_ENC_YCBCR, + .planes = 2, + .buffers = 1, + }, + { + .fourcc = V4L2_PIX_FMT_NV21, + .vdownsampling = { 1, 2 }, + .bit_depth = { 8, 8 }, + .color_enc = TGP_COLOR_ENC_YCBCR, + .planes = 2, + .buffers = 1, + }, + { + .fourcc = V4L2_PIX_FMT_NV16, + .vdownsampling = { 1, 1 }, + .bit_depth = { 8, 8 }, + .color_enc = TGP_COLOR_ENC_YCBCR, + .planes = 2, + .buffers = 1, + }, + { + .fourcc = V4L2_PIX_FMT_NV61, + .vdownsampling = { 1, 1 }, + .bit_depth = { 8, 8 }, + .color_enc = TGP_COLOR_ENC_YCBCR, + .planes = 2, + .buffers = 1, + }, + { + .fourcc = V4L2_PIX_FMT_NV24, + .vdownsampling = { 1, 1 }, + .bit_depth = { 8, 16 }, + .color_enc = TGP_COLOR_ENC_YCBCR, + .planes = 2, + .buffers = 1, + }, + { + .fourcc = V4L2_PIX_FMT_NV42, + .vdownsampling = { 1, 1 }, + .bit_depth = { 8, 16 }, + .color_enc = TGP_COLOR_ENC_YCBCR, + .planes = 2, + .buffers = 1, + }, + { + .fourcc = V4L2_PIX_FMT_YUV555, /* uuuvvvvv ayyyyyuu */ + .vdownsampling = { 1 }, + .bit_depth = { 16 }, + .planes = 1, + .buffers = 1, + .alpha_mask = 0x8000, + }, + { + .fourcc = V4L2_PIX_FMT_YUV565, /* uuuvvvvv yyyyyuuu */ + .vdownsampling = { 1 }, + .bit_depth = { 16 }, + .planes = 1, + .buffers = 1, + }, + { + .fourcc = V4L2_PIX_FMT_YUV444, /* uuuuvvvv aaaayyyy */ + .vdownsampling = { 1 }, + .bit_depth = { 16 }, + .planes = 1, + .buffers = 1, + .alpha_mask = 0xf000, + }, + { + .fourcc = V4L2_PIX_FMT_YUV32, /* ayuv */ + .vdownsampling = { 1 }, + .bit_depth = { 32 }, + .planes = 1, + .buffers = 1, + .alpha_mask = 0x000000ff, + }, + { + .fourcc = V4L2_PIX_FMT_AYUV32, + .vdownsampling = { 1 }, + .bit_depth = { 32 }, + .planes = 1, + .buffers = 1, + .alpha_mask = 0x000000ff, + }, + { + .fourcc = V4L2_PIX_FMT_XYUV32, + .vdownsampling = { 1 }, + .bit_depth = { 32 }, + .planes = 1, + .buffers = 1, + }, + { + .fourcc = V4L2_PIX_FMT_VUYA32, + .vdownsampling = { 1 }, + .bit_depth = { 32 }, + .planes = 1, + .buffers = 1, + .alpha_mask = 0xff000000, + }, + { + .fourcc = V4L2_PIX_FMT_VUYX32, + .vdownsampling = { 1 }, + .bit_depth = { 32 }, + .planes = 1, + .buffers = 1, + }, + { + .fourcc = V4L2_PIX_FMT_GREY, + .vdownsampling = { 1 }, + .bit_depth = { 8 }, + .color_enc = TGP_COLOR_ENC_LUMA, + .planes = 1, + .buffers = 1, + }, + { + .fourcc = V4L2_PIX_FMT_Y10, + .vdownsampling = { 1 }, + .bit_depth = { 16 }, + .color_enc = TGP_COLOR_ENC_LUMA, + .planes = 1, + .buffers = 1, + }, + { + .fourcc = V4L2_PIX_FMT_Y12, + .vdownsampling = { 1 }, + .bit_depth = { 16 }, + .color_enc = TGP_COLOR_ENC_LUMA, + .planes = 1, + .buffers = 1, + }, + { + .fourcc = V4L2_PIX_FMT_Y16, + .vdownsampling = { 1 }, + .bit_depth = { 16 }, + .color_enc = TGP_COLOR_ENC_LUMA, + .planes = 1, + .buffers = 1, + }, + { + .fourcc = V4L2_PIX_FMT_Y16_BE, + .vdownsampling = { 1 }, + .bit_depth = { 16 }, + .color_enc = TGP_COLOR_ENC_LUMA, + .planes = 1, + .buffers = 1, + }, + { + .fourcc = V4L2_PIX_FMT_RGB332, /* rrrgggbb */ + .vdownsampling = { 1 }, + .bit_depth = { 8 }, + .planes = 1, + .buffers = 1, + }, + { + .fourcc = V4L2_PIX_FMT_RGB565, /* gggbbbbb rrrrrggg */ + .vdownsampling = { 1 }, + .bit_depth = { 16 }, + .planes = 1, + .buffers = 1, + .can_do_overlay = true, + }, + { + .fourcc = V4L2_PIX_FMT_RGB565X, /* rrrrrggg gggbbbbb */ + .vdownsampling = { 1 }, + .bit_depth = { 16 }, + .planes = 1, + .buffers = 1, + .can_do_overlay = true, + }, + { + .fourcc = V4L2_PIX_FMT_RGB444, /* ggggbbbb xxxxrrrr */ + .vdownsampling = { 1 }, + .bit_depth = { 16 }, + .planes = 1, + .buffers = 1, + }, + { + .fourcc = V4L2_PIX_FMT_XRGB444, /* ggggbbbb xxxxrrrr */ + .vdownsampling = { 1 }, + .bit_depth = { 16 }, + .planes = 1, + .buffers = 1, + }, + { + .fourcc = V4L2_PIX_FMT_ARGB444, /* ggggbbbb aaaarrrr */ + .vdownsampling = { 1 }, + .bit_depth = { 16 }, + .planes = 1, + .buffers = 1, + .alpha_mask = 0x00f0, + }, + { + .fourcc = V4L2_PIX_FMT_RGBX444, /* bbbbxxxx rrrrgggg */ + .vdownsampling = { 1 }, + .bit_depth = { 16 }, + .planes = 1, + .buffers = 1, + }, + { + .fourcc = V4L2_PIX_FMT_RGBA444, /* bbbbaaaa rrrrgggg */ + .vdownsampling = { 1 }, + .bit_depth = { 16 }, + .planes = 1, + .buffers = 1, + .alpha_mask = 0x00f0, + }, + { + .fourcc = V4L2_PIX_FMT_XBGR444, /* ggggrrrr xxxxbbbb */ + .vdownsampling = { 1 }, + .bit_depth = { 16 }, + .planes = 1, + .buffers = 1, + }, + { + .fourcc = V4L2_PIX_FMT_ABGR444, /* ggggrrrr aaaabbbb */ + .vdownsampling = { 1 }, + .bit_depth = { 16 }, + .planes = 1, + .buffers = 1, + .alpha_mask = 0x00f0, + }, + { + .fourcc = V4L2_PIX_FMT_BGRX444, /* rrrrxxxx bbbbgggg */ + .vdownsampling = { 1 }, + .bit_depth = { 16 }, + .planes = 1, + .buffers = 1, + }, + { + .fourcc = V4L2_PIX_FMT_BGRA444, /* rrrraaaa bbbbgggg */ + .vdownsampling = { 1 }, + .bit_depth = { 16 }, + .planes = 1, + .buffers = 1, + .alpha_mask = 0x00f0, + }, + { + .fourcc = V4L2_PIX_FMT_RGB555, /* gggbbbbb xrrrrrgg */ + .vdownsampling = { 1 }, + .bit_depth = { 16 }, + .planes = 1, + .buffers = 1, + .can_do_overlay = true, + }, + { + .fourcc = V4L2_PIX_FMT_XRGB555, /* gggbbbbb xrrrrrgg */ + .vdownsampling = { 1 }, + .bit_depth = { 16 }, + .planes = 1, + .buffers = 1, + .can_do_overlay = true, + }, + { + .fourcc = V4L2_PIX_FMT_ARGB555, /* gggbbbbb arrrrrgg */ + .vdownsampling = { 1 }, + .bit_depth = { 16 }, + .planes = 1, + .buffers = 1, + .can_do_overlay = true, + .alpha_mask = 0x8000, + }, + { + .fourcc = V4L2_PIX_FMT_RGBX555, /* ggbbbbbx rrrrrggg */ + .vdownsampling = { 1 }, + .bit_depth = { 16 }, + .planes = 1, + .buffers = 1, + .can_do_overlay = true, + }, + { + .fourcc = V4L2_PIX_FMT_RGBA555, /* ggbbbbba rrrrrggg */ + .vdownsampling = { 1 }, + .bit_depth = { 16 }, + .planes = 1, + .buffers = 1, + .can_do_overlay = true, + .alpha_mask = 0x8000, + }, + { + .fourcc = V4L2_PIX_FMT_XBGR555, /* gggrrrrr xbbbbbgg */ + .vdownsampling = { 1 }, + .bit_depth = { 16 }, + .planes = 1, + .buffers = 1, + .can_do_overlay = true, + }, + { + .fourcc = V4L2_PIX_FMT_ABGR555, /* gggrrrrr abbbbbgg */ + .vdownsampling = { 1 }, + .bit_depth = { 16 }, + .planes = 1, + .buffers = 1, + .can_do_overlay = true, + .alpha_mask = 0x8000, + }, + { + .fourcc = V4L2_PIX_FMT_BGRX555, /* ggrrrrrx bbbbbggg */ + .vdownsampling = { 1 }, + .bit_depth = { 16 }, + .planes = 1, + .buffers = 1, + .can_do_overlay = true, + }, + { + .fourcc = V4L2_PIX_FMT_BGRA555, /* ggrrrrra bbbbbggg */ + .vdownsampling = { 1 }, + .bit_depth = { 16 }, + .planes = 1, + .buffers = 1, + .can_do_overlay = true, + .alpha_mask = 0x8000, + }, + { + .fourcc = V4L2_PIX_FMT_RGB555X, /* xrrrrrgg gggbbbbb */ + .vdownsampling = { 1 }, + .bit_depth = { 16 }, + .planes = 1, + .buffers = 1, + }, + { + .fourcc = V4L2_PIX_FMT_XRGB555X, /* xrrrrrgg gggbbbbb */ + .vdownsampling = { 1 }, + .bit_depth = { 16 }, + .planes = 1, + .buffers = 1, + }, + { + .fourcc = V4L2_PIX_FMT_ARGB555X, /* arrrrrgg gggbbbbb */ + .vdownsampling = { 1 }, + .bit_depth = { 16 }, + .planes = 1, + .buffers = 1, + .alpha_mask = 0x0080, + }, + { + .fourcc = V4L2_PIX_FMT_RGB24, /* rgb */ + .vdownsampling = { 1 }, + .bit_depth = { 24 }, + .planes = 1, + .buffers = 1, + }, + { + .fourcc = V4L2_PIX_FMT_BGR24, /* bgr */ + .vdownsampling = { 1 }, + .bit_depth = { 24 }, + .planes = 1, + .buffers = 1, + }, + { + .fourcc = V4L2_PIX_FMT_BGR666, /* bbbbbbgg ggggrrrr rrxxxxxx */ + .vdownsampling = { 1 }, + .bit_depth = { 32 }, + .planes = 1, + .buffers = 1, + }, + { + .fourcc = V4L2_PIX_FMT_RGB32, /* xrgb */ + .vdownsampling = { 1 }, + .bit_depth = { 32 }, + .planes = 1, + .buffers = 1, + }, + { + .fourcc = V4L2_PIX_FMT_BGR32, /* bgrx */ + .vdownsampling = { 1 }, + .bit_depth = { 32 }, + .planes = 1, + .buffers = 1, + }, + { + .fourcc = V4L2_PIX_FMT_XRGB32, /* xrgb */ + .vdownsampling = { 1 }, + .bit_depth = { 32 }, + .planes = 1, + .buffers = 1, + }, + { + .fourcc = V4L2_PIX_FMT_XBGR32, /* bgrx */ + .vdownsampling = { 1 }, + .bit_depth = { 32 }, + .planes = 1, + .buffers = 1, + }, + { + .fourcc = V4L2_PIX_FMT_ARGB32, /* argb */ + .vdownsampling = { 1 }, + .bit_depth = { 32 }, + .planes = 1, + .buffers = 1, + .alpha_mask = 0x000000ff, + }, + { + .fourcc = V4L2_PIX_FMT_ABGR32, /* bgra */ + .vdownsampling = { 1 }, + .bit_depth = { 32 }, + .planes = 1, + .buffers = 1, + .alpha_mask = 0xff000000, + }, + { + .fourcc = V4L2_PIX_FMT_RGBX32, /* rgbx */ + .vdownsampling = { 1 }, + .bit_depth = { 32 }, + .planes = 1, + .buffers = 1, + }, + { + .fourcc = V4L2_PIX_FMT_BGRX32, /* xbgr */ + .vdownsampling = { 1 }, + .bit_depth = { 32 }, + .planes = 1, + .buffers = 1, + }, + { + .fourcc = V4L2_PIX_FMT_RGBA32, /* rgba */ + .vdownsampling = { 1 }, + .bit_depth = { 32 }, + .planes = 1, + .buffers = 1, + .alpha_mask = 0x000000ff, + }, + { + .fourcc = V4L2_PIX_FMT_BGRA32, /* abgr */ + .vdownsampling = { 1 }, + .bit_depth = { 32 }, + .planes = 1, + .buffers = 1, + .alpha_mask = 0xff000000, + }, + { + .fourcc = V4L2_PIX_FMT_SBGGR8, /* Bayer BG/GR */ + .vdownsampling = { 1 }, + .bit_depth = { 8 }, + .planes = 1, + .buffers = 1, + }, + { + .fourcc = V4L2_PIX_FMT_SGBRG8, /* Bayer GB/RG */ + .vdownsampling = { 1 }, + .bit_depth = { 8 }, + .planes = 1, + .buffers = 1, + }, + { + .fourcc = V4L2_PIX_FMT_SGRBG8, /* Bayer GR/BG */ + .vdownsampling = { 1 }, + .bit_depth = { 8 }, + .planes = 1, + .buffers = 1, + }, + { + .fourcc = V4L2_PIX_FMT_SRGGB8, /* Bayer RG/GB */ + .vdownsampling = { 1 }, + .bit_depth = { 8 }, + .planes = 1, + .buffers = 1, + }, + { + .fourcc = V4L2_PIX_FMT_SBGGR10, /* Bayer BG/GR */ + .vdownsampling = { 1 }, + .bit_depth = { 16 }, + .planes = 1, + .buffers = 1, + }, + { + .fourcc = V4L2_PIX_FMT_SGBRG10, /* Bayer GB/RG */ + .vdownsampling = { 1 }, + .bit_depth = { 16 }, + .planes = 1, + .buffers = 1, + }, + { + .fourcc = V4L2_PIX_FMT_SGRBG10, /* Bayer GR/BG */ + .vdownsampling = { 1 }, + .bit_depth = { 16 }, + .planes = 1, + .buffers = 1, + }, + { + .fourcc = V4L2_PIX_FMT_SRGGB10, /* Bayer RG/GB */ + .vdownsampling = { 1 }, + .bit_depth = { 16 }, + .planes = 1, + .buffers = 1, + }, + { + .fourcc = V4L2_PIX_FMT_SBGGR12, /* Bayer BG/GR */ + .vdownsampling = { 1 }, + .bit_depth = { 16 }, + .planes = 1, + .buffers = 1, + }, + { + .fourcc = V4L2_PIX_FMT_SGBRG12, /* Bayer GB/RG */ + .vdownsampling = { 1 }, + .bit_depth = { 16 }, + .planes = 1, + .buffers = 1, + }, + { + .fourcc = V4L2_PIX_FMT_SGRBG12, /* Bayer GR/BG */ + .vdownsampling = { 1 }, + .bit_depth = { 16 }, + .planes = 1, + .buffers = 1, + }, + { + .fourcc = V4L2_PIX_FMT_SRGGB12, /* Bayer RG/GB */ + .vdownsampling = { 1 }, + .bit_depth = { 16 }, + .planes = 1, + .buffers = 1, + }, + { + .fourcc = V4L2_PIX_FMT_SBGGR16, /* Bayer BG/GR */ + .vdownsampling = { 1 }, + .bit_depth = { 16 }, + .planes = 1, + .buffers = 1, + }, + { + .fourcc = V4L2_PIX_FMT_SGBRG16, /* Bayer GB/RG */ + .vdownsampling = { 1 }, + .bit_depth = { 16 }, + .planes = 1, + .buffers = 1, + }, + { + .fourcc = V4L2_PIX_FMT_SGRBG16, /* Bayer GR/BG */ + .vdownsampling = { 1 }, + .bit_depth = { 16 }, + .planes = 1, + .buffers = 1, + }, + { + .fourcc = V4L2_PIX_FMT_SRGGB16, /* Bayer RG/GB */ + .vdownsampling = { 1 }, + .bit_depth = { 16 }, + .planes = 1, + .buffers = 1, + }, + { + .fourcc = V4L2_PIX_FMT_HSV24, /* HSV 24bits */ + .color_enc = TGP_COLOR_ENC_HSV, + .vdownsampling = { 1 }, + .bit_depth = { 24 }, + .planes = 1, + .buffers = 1, + }, + { + .fourcc = V4L2_PIX_FMT_HSV32, /* HSV 32bits */ + .color_enc = TGP_COLOR_ENC_HSV, + .vdownsampling = { 1 }, + .bit_depth = { 32 }, + .planes = 1, + .buffers = 1, + }, + + /* Multiplanar formats */ + + { + .fourcc = V4L2_PIX_FMT_NV16M, + .vdownsampling = { 1, 1 }, + .bit_depth = { 8, 8 }, + .color_enc = TGP_COLOR_ENC_YCBCR, + .planes = 2, + .buffers = 2, + .data_offset = { PLANE0_DATA_OFFSET, 0 }, + }, + { + .fourcc = V4L2_PIX_FMT_NV61M, + .vdownsampling = { 1, 1 }, + .bit_depth = { 8, 8 }, + .color_enc = TGP_COLOR_ENC_YCBCR, + .planes = 2, + .buffers = 2, + .data_offset = { 0, PLANE0_DATA_OFFSET }, + }, + { + .fourcc = V4L2_PIX_FMT_YUV420M, + .vdownsampling = { 1, 2, 2 }, + .bit_depth = { 8, 4, 4 }, + .color_enc = TGP_COLOR_ENC_YCBCR, + .planes = 3, + .buffers = 3, + }, + { + .fourcc = V4L2_PIX_FMT_YVU420M, + .vdownsampling = { 1, 2, 2 }, + .bit_depth = { 8, 4, 4 }, + .color_enc = TGP_COLOR_ENC_YCBCR, + .planes = 3, + .buffers = 3, + }, + { + .fourcc = V4L2_PIX_FMT_NV12M, + .vdownsampling = { 1, 2 }, + .bit_depth = { 8, 8 }, + .color_enc = TGP_COLOR_ENC_YCBCR, + .planes = 2, + .buffers = 2, + }, + { + .fourcc = V4L2_PIX_FMT_NV21M, + .vdownsampling = { 1, 2 }, + .bit_depth = { 8, 8 }, + .color_enc = TGP_COLOR_ENC_YCBCR, + .planes = 2, + .buffers = 2, + }, + { + .fourcc = V4L2_PIX_FMT_YUV422M, + .vdownsampling = { 1, 1, 1 }, + .bit_depth = { 8, 4, 4 }, + .color_enc = TGP_COLOR_ENC_YCBCR, + .planes = 3, + .buffers = 3, + }, + { + .fourcc = V4L2_PIX_FMT_YVU422M, + .vdownsampling = { 1, 1, 1 }, + .bit_depth = { 8, 4, 4 }, + .color_enc = TGP_COLOR_ENC_YCBCR, + .planes = 3, + .buffers = 3, + }, + { + .fourcc = V4L2_PIX_FMT_YUV444M, + .vdownsampling = { 1, 1, 1 }, + .bit_depth = { 8, 8, 8 }, + .color_enc = TGP_COLOR_ENC_YCBCR, + .planes = 3, + .buffers = 3, + }, + { + .fourcc = V4L2_PIX_FMT_YVU444M, + .vdownsampling = { 1, 1, 1 }, + .bit_depth = { 8, 8, 8 }, + .color_enc = TGP_COLOR_ENC_YCBCR, + .planes = 3, + .buffers = 3, + }, +}; + +/* There are this many multiplanar formats in the list */ +#define VIVID_MPLANAR_FORMATS 10 + +const struct vivid_fmt *vivid_get_format(struct vivid_dev *dev, u32 pixelformat) +{ + const struct vivid_fmt *fmt; + unsigned k; + + for (k = 0; k < ARRAY_SIZE(vivid_formats); k++) { + fmt = &vivid_formats[k]; + if (fmt->fourcc == pixelformat) + if (fmt->buffers == 1 || dev->multiplanar) + return fmt; + } + + return NULL; +} + +bool vivid_vid_can_loop(struct vivid_dev *dev) +{ + if (dev->src_rect.width != dev->sink_rect.width || + dev->src_rect.height != dev->sink_rect.height) + return false; + if (dev->fmt_cap->fourcc != dev->fmt_out->fourcc) + return false; + if (dev->field_cap != dev->field_out) + return false; + /* + * While this can be supported, it is just too much work + * to actually implement. + */ + if (dev->field_cap == V4L2_FIELD_SEQ_TB || + dev->field_cap == V4L2_FIELD_SEQ_BT) + return false; + if (vivid_is_svid_cap(dev) && vivid_is_svid_out(dev)) { + if (!(dev->std_cap[dev->input] & V4L2_STD_525_60) != + !(dev->std_out & V4L2_STD_525_60)) + return false; + return true; + } + if (vivid_is_hdmi_cap(dev) && vivid_is_hdmi_out(dev)) + return true; + return false; +} + +void vivid_send_source_change(struct vivid_dev *dev, unsigned type) +{ + struct v4l2_event ev = { + .type = V4L2_EVENT_SOURCE_CHANGE, + .u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION, + }; + unsigned i; + + for (i = 0; i < dev->num_inputs; i++) { + ev.id = i; + if (dev->input_type[i] == type) { + if (video_is_registered(&dev->vid_cap_dev) && dev->has_vid_cap) + v4l2_event_queue(&dev->vid_cap_dev, &ev); + if (video_is_registered(&dev->vbi_cap_dev) && dev->has_vbi_cap) + v4l2_event_queue(&dev->vbi_cap_dev, &ev); + } + } +} + +/* + * Conversion function that converts a single-planar format to a + * single-plane multiplanar format. + */ +void fmt_sp2mp(const struct v4l2_format *sp_fmt, struct v4l2_format *mp_fmt) +{ + struct v4l2_pix_format_mplane *mp = &mp_fmt->fmt.pix_mp; + struct v4l2_plane_pix_format *ppix = &mp->plane_fmt[0]; + const struct v4l2_pix_format *pix = &sp_fmt->fmt.pix; + bool is_out = sp_fmt->type == V4L2_BUF_TYPE_VIDEO_OUTPUT; + + memset(mp->reserved, 0, sizeof(mp->reserved)); + mp_fmt->type = is_out ? V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE : + V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + mp->width = pix->width; + mp->height = pix->height; + mp->pixelformat = pix->pixelformat; + mp->field = pix->field; + mp->colorspace = pix->colorspace; + mp->xfer_func = pix->xfer_func; + /* Also copies hsv_enc */ + mp->ycbcr_enc = pix->ycbcr_enc; + mp->quantization = pix->quantization; + mp->num_planes = 1; + mp->flags = pix->flags; + ppix->sizeimage = pix->sizeimage; + ppix->bytesperline = pix->bytesperline; + memset(ppix->reserved, 0, sizeof(ppix->reserved)); +} + +int fmt_sp2mp_func(struct file *file, void *priv, + struct v4l2_format *f, fmtfunc func) +{ + struct v4l2_format fmt; + struct v4l2_pix_format_mplane *mp = &fmt.fmt.pix_mp; + struct v4l2_plane_pix_format *ppix = &mp->plane_fmt[0]; + struct v4l2_pix_format *pix = &f->fmt.pix; + int ret; + + /* Converts to a mplane format */ + fmt_sp2mp(f, &fmt); + /* Passes it to the generic mplane format function */ + ret = func(file, priv, &fmt); + /* Copies back the mplane data to the single plane format */ + pix->width = mp->width; + pix->height = mp->height; + pix->pixelformat = mp->pixelformat; + pix->field = mp->field; + pix->colorspace = mp->colorspace; + pix->xfer_func = mp->xfer_func; + /* Also copies hsv_enc */ + pix->ycbcr_enc = mp->ycbcr_enc; + pix->quantization = mp->quantization; + pix->sizeimage = ppix->sizeimage; + pix->bytesperline = ppix->bytesperline; + pix->flags = mp->flags; + return ret; +} + +int vivid_vid_adjust_sel(unsigned flags, struct v4l2_rect *r) +{ + unsigned w = r->width; + unsigned h = r->height; + + /* sanitize w and h in case someone passes ~0 as the value */ + w &= 0xffff; + h &= 0xffff; + if (!(flags & V4L2_SEL_FLAG_LE)) { + w++; + h++; + if (w < 2) + w = 2; + if (h < 2) + h = 2; + } + if (!(flags & V4L2_SEL_FLAG_GE)) { + if (w > MAX_WIDTH) + w = MAX_WIDTH; + if (h > MAX_HEIGHT) + h = MAX_HEIGHT; + } + w = w & ~1; + h = h & ~1; + if (w < 2 || h < 2) + return -ERANGE; + if (w > MAX_WIDTH || h > MAX_HEIGHT) + return -ERANGE; + if (r->top < 0) + r->top = 0; + if (r->left < 0) + r->left = 0; + /* sanitize left and top in case someone passes ~0 as the value */ + r->left &= 0xfffe; + r->top &= 0xfffe; + if (r->left + w > MAX_WIDTH) + r->left = MAX_WIDTH - w; + if (r->top + h > MAX_HEIGHT) + r->top = MAX_HEIGHT - h; + if ((flags & (V4L2_SEL_FLAG_GE | V4L2_SEL_FLAG_LE)) == + (V4L2_SEL_FLAG_GE | V4L2_SEL_FLAG_LE) && + (r->width != w || r->height != h)) + return -ERANGE; + r->width = w; + r->height = h; + return 0; +} + +int vivid_enum_fmt_vid(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + struct vivid_dev *dev = video_drvdata(file); + const struct vivid_fmt *fmt; + + if (f->index >= ARRAY_SIZE(vivid_formats) - + (dev->multiplanar ? 0 : VIVID_MPLANAR_FORMATS)) + return -EINVAL; + + fmt = &vivid_formats[f->index]; + + f->pixelformat = fmt->fourcc; + return 0; +} + +int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id) +{ + struct vivid_dev *dev = video_drvdata(file); + struct video_device *vdev = video_devdata(file); + + if (vdev->vfl_dir == VFL_DIR_RX) { + if (!vivid_is_sdtv_cap(dev)) + return -ENODATA; + *id = dev->std_cap[dev->input]; + } else { + if (!vivid_is_svid_out(dev)) + return -ENODATA; + *id = dev->std_out; + } + return 0; +} + +int vidioc_g_dv_timings(struct file *file, void *_fh, + struct v4l2_dv_timings *timings) +{ + struct vivid_dev *dev = video_drvdata(file); + struct video_device *vdev = video_devdata(file); + + if (vdev->vfl_dir == VFL_DIR_RX) { + if (!vivid_is_hdmi_cap(dev)) + return -ENODATA; + *timings = dev->dv_timings_cap[dev->input]; + } else { + if (!vivid_is_hdmi_out(dev)) + return -ENODATA; + *timings = dev->dv_timings_out; + } + return 0; +} + +int vidioc_enum_dv_timings(struct file *file, void *_fh, + struct v4l2_enum_dv_timings *timings) +{ + struct vivid_dev *dev = video_drvdata(file); + struct video_device *vdev = video_devdata(file); + + if (vdev->vfl_dir == VFL_DIR_RX) { + if (!vivid_is_hdmi_cap(dev)) + return -ENODATA; + } else { + if (!vivid_is_hdmi_out(dev)) + return -ENODATA; + } + return v4l2_enum_dv_timings_cap(timings, &vivid_dv_timings_cap, + NULL, NULL); +} + +int vidioc_dv_timings_cap(struct file *file, void *_fh, + struct v4l2_dv_timings_cap *cap) +{ + struct vivid_dev *dev = video_drvdata(file); + struct video_device *vdev = video_devdata(file); + + if (vdev->vfl_dir == VFL_DIR_RX) { + if (!vivid_is_hdmi_cap(dev)) + return -ENODATA; + } else { + if (!vivid_is_hdmi_out(dev)) + return -ENODATA; + } + *cap = vivid_dv_timings_cap; + return 0; +} + +int vidioc_g_edid(struct file *file, void *_fh, + struct v4l2_edid *edid) +{ + struct vivid_dev *dev = video_drvdata(file); + struct video_device *vdev = video_devdata(file); + struct cec_adapter *adap; + + memset(edid->reserved, 0, sizeof(edid->reserved)); + if (vdev->vfl_dir == VFL_DIR_RX) { + if (edid->pad >= dev->num_inputs) + return -EINVAL; + if (dev->input_type[edid->pad] != HDMI) + return -EINVAL; + adap = dev->cec_rx_adap; + } else { + unsigned int bus_idx; + + if (edid->pad >= dev->num_outputs) + return -EINVAL; + if (dev->output_type[edid->pad] != HDMI) + return -EINVAL; + if (!dev->display_present[edid->pad]) + return -ENODATA; + bus_idx = dev->cec_output2bus_map[edid->pad]; + adap = dev->cec_tx_adap[bus_idx]; + } + if (edid->start_block == 0 && edid->blocks == 0) { + edid->blocks = dev->edid_blocks; + return 0; + } + if (dev->edid_blocks == 0) + return -ENODATA; + if (edid->start_block >= dev->edid_blocks) + return -EINVAL; + if (edid->blocks > dev->edid_blocks - edid->start_block) + edid->blocks = dev->edid_blocks - edid->start_block; + if (adap) + v4l2_set_edid_phys_addr(dev->edid, dev->edid_blocks * 128, adap->phys_addr); + memcpy(edid->edid, dev->edid + edid->start_block * 128, edid->blocks * 128); + return 0; +} diff --git a/drivers/media/test_drivers/vivid/vivid-vid-common.h b/drivers/media/test_drivers/vivid/vivid-vid-common.h new file mode 100644 index 000000000000..d908d9725283 --- /dev/null +++ b/drivers/media/test_drivers/vivid/vivid-vid-common.h @@ -0,0 +1,38 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * vivid-vid-common.h - common video support functions. + * + * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. + */ + +#ifndef _VIVID_VID_COMMON_H_ +#define _VIVID_VID_COMMON_H_ + +typedef int (*fmtfunc)(struct file *file, void *priv, struct v4l2_format *f); + +/* + * Conversion function that converts a single-planar format to a + * single-plane multiplanar format. + */ +void fmt_sp2mp(const struct v4l2_format *sp_fmt, struct v4l2_format *mp_fmt); +int fmt_sp2mp_func(struct file *file, void *priv, + struct v4l2_format *f, fmtfunc func); + +extern const struct v4l2_dv_timings_cap vivid_dv_timings_cap; + +const struct vivid_fmt *vivid_get_format(struct vivid_dev *dev, u32 pixelformat); + +bool vivid_vid_can_loop(struct vivid_dev *dev); +void vivid_send_source_change(struct vivid_dev *dev, unsigned type); + +int vivid_vid_adjust_sel(unsigned flags, struct v4l2_rect *r); + +int vivid_enum_fmt_vid(struct file *file, void *priv, struct v4l2_fmtdesc *f); +int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id); +int vidioc_g_dv_timings(struct file *file, void *_fh, struct v4l2_dv_timings *timings); +int vidioc_enum_dv_timings(struct file *file, void *_fh, struct v4l2_enum_dv_timings *timings); +int vidioc_dv_timings_cap(struct file *file, void *_fh, struct v4l2_dv_timings_cap *cap); +int vidioc_g_edid(struct file *file, void *_fh, struct v4l2_edid *edid); +int vidioc_subscribe_event(struct v4l2_fh *fh, const struct v4l2_event_subscription *sub); + +#endif diff --git a/drivers/media/test_drivers/vivid/vivid-vid-out.c b/drivers/media/test_drivers/vivid/vivid-vid-out.c new file mode 100644 index 000000000000..ee3446e3217c --- /dev/null +++ b/drivers/media/test_drivers/vivid/vivid-vid-out.c @@ -0,0 +1,1210 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * vivid-vid-out.c - video output support functions. + * + * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "vivid-core.h" +#include "vivid-vid-common.h" +#include "vivid-kthread-out.h" +#include "vivid-vid-out.h" + +static int vid_out_queue_setup(struct vb2_queue *vq, + unsigned *nbuffers, unsigned *nplanes, + unsigned sizes[], struct device *alloc_devs[]) +{ + struct vivid_dev *dev = vb2_get_drv_priv(vq); + const struct vivid_fmt *vfmt = dev->fmt_out; + unsigned planes = vfmt->buffers; + unsigned h = dev->fmt_out_rect.height; + unsigned int size = dev->bytesperline_out[0] * h + vfmt->data_offset[0]; + unsigned p; + + for (p = vfmt->buffers; p < vfmt->planes; p++) + size += dev->bytesperline_out[p] * h / vfmt->vdownsampling[p] + + vfmt->data_offset[p]; + + if (dev->field_out == V4L2_FIELD_ALTERNATE) { + /* + * You cannot use write() with FIELD_ALTERNATE since the field + * information (TOP/BOTTOM) cannot be passed to the kernel. + */ + if (vb2_fileio_is_active(vq)) + return -EINVAL; + } + + if (dev->queue_setup_error) { + /* + * Error injection: test what happens if queue_setup() returns + * an error. + */ + dev->queue_setup_error = false; + return -EINVAL; + } + + if (*nplanes) { + /* + * Check if the number of requested planes match + * the number of planes in the current format. You can't mix that. + */ + if (*nplanes != planes) + return -EINVAL; + if (sizes[0] < size) + return -EINVAL; + for (p = 1; p < planes; p++) { + if (sizes[p] < dev->bytesperline_out[p] * h + + vfmt->data_offset[p]) + return -EINVAL; + } + } else { + for (p = 0; p < planes; p++) + sizes[p] = p ? dev->bytesperline_out[p] * h + + vfmt->data_offset[p] : size; + } + + if (vq->num_buffers + *nbuffers < 2) + *nbuffers = 2 - vq->num_buffers; + + *nplanes = planes; + + dprintk(dev, 1, "%s: count=%d\n", __func__, *nbuffers); + for (p = 0; p < planes; p++) + dprintk(dev, 1, "%s: size[%u]=%u\n", __func__, p, sizes[p]); + return 0; +} + +static int vid_out_buf_out_validate(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); + + dprintk(dev, 1, "%s\n", __func__); + + if (dev->field_out != V4L2_FIELD_ALTERNATE) + vbuf->field = dev->field_out; + else if (vbuf->field != V4L2_FIELD_TOP && + vbuf->field != V4L2_FIELD_BOTTOM) + return -EINVAL; + return 0; +} + +static int vid_out_buf_prepare(struct vb2_buffer *vb) +{ + struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); + const struct vivid_fmt *vfmt = dev->fmt_out; + unsigned int planes = vfmt->buffers; + unsigned int h = dev->fmt_out_rect.height; + unsigned int size = dev->bytesperline_out[0] * h; + unsigned p; + + for (p = vfmt->buffers; p < vfmt->planes; p++) + size += dev->bytesperline_out[p] * h / vfmt->vdownsampling[p]; + + dprintk(dev, 1, "%s\n", __func__); + + if (WARN_ON(NULL == dev->fmt_out)) + return -EINVAL; + + if (dev->buf_prepare_error) { + /* + * Error injection: test what happens if buf_prepare() returns + * an error. + */ + dev->buf_prepare_error = false; + return -EINVAL; + } + + for (p = 0; p < planes; p++) { + if (p) + size = dev->bytesperline_out[p] * h; + size += vb->planes[p].data_offset; + + if (vb2_get_plane_payload(vb, p) < size) { + dprintk(dev, 1, "%s the payload is too small for plane %u (%lu < %u)\n", + __func__, p, vb2_get_plane_payload(vb, p), size); + return -EINVAL; + } + } + + return 0; +} + +static void vid_out_buf_queue(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); + struct vivid_buffer *buf = container_of(vbuf, struct vivid_buffer, vb); + + dprintk(dev, 1, "%s\n", __func__); + + spin_lock(&dev->slock); + list_add_tail(&buf->list, &dev->vid_out_active); + spin_unlock(&dev->slock); +} + +static int vid_out_start_streaming(struct vb2_queue *vq, unsigned count) +{ + struct vivid_dev *dev = vb2_get_drv_priv(vq); + int err; + + if (vb2_is_streaming(&dev->vb_vid_cap_q)) + dev->can_loop_video = vivid_vid_can_loop(dev); + + dev->vid_out_seq_count = 0; + dprintk(dev, 1, "%s\n", __func__); + if (dev->start_streaming_error) { + dev->start_streaming_error = false; + err = -EINVAL; + } else { + err = vivid_start_generating_vid_out(dev, &dev->vid_out_streaming); + } + if (err) { + struct vivid_buffer *buf, *tmp; + + list_for_each_entry_safe(buf, tmp, &dev->vid_out_active, list) { + list_del(&buf->list); + vb2_buffer_done(&buf->vb.vb2_buf, + VB2_BUF_STATE_QUEUED); + } + } + return err; +} + +/* abort streaming and wait for last buffer */ +static void vid_out_stop_streaming(struct vb2_queue *vq) +{ + struct vivid_dev *dev = vb2_get_drv_priv(vq); + + dprintk(dev, 1, "%s\n", __func__); + vivid_stop_generating_vid_out(dev, &dev->vid_out_streaming); + dev->can_loop_video = false; +} + +static void vid_out_buf_request_complete(struct vb2_buffer *vb) +{ + struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue); + + v4l2_ctrl_request_complete(vb->req_obj.req, &dev->ctrl_hdl_vid_out); +} + +const struct vb2_ops vivid_vid_out_qops = { + .queue_setup = vid_out_queue_setup, + .buf_out_validate = vid_out_buf_out_validate, + .buf_prepare = vid_out_buf_prepare, + .buf_queue = vid_out_buf_queue, + .start_streaming = vid_out_start_streaming, + .stop_streaming = vid_out_stop_streaming, + .buf_request_complete = vid_out_buf_request_complete, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, +}; + +/* + * Called whenever the format has to be reset which can occur when + * changing outputs, standard, timings, etc. + */ +void vivid_update_format_out(struct vivid_dev *dev) +{ + struct v4l2_bt_timings *bt = &dev->dv_timings_out.bt; + unsigned size, p; + u64 pixelclock; + + switch (dev->output_type[dev->output]) { + case SVID: + default: + dev->field_out = dev->tv_field_out; + dev->sink_rect.width = 720; + if (dev->std_out & V4L2_STD_525_60) { + dev->sink_rect.height = 480; + dev->timeperframe_vid_out = (struct v4l2_fract) { 1001, 30000 }; + dev->service_set_out = V4L2_SLICED_CAPTION_525; + } else { + dev->sink_rect.height = 576; + dev->timeperframe_vid_out = (struct v4l2_fract) { 1000, 25000 }; + dev->service_set_out = V4L2_SLICED_WSS_625 | V4L2_SLICED_TELETEXT_B; + } + dev->colorspace_out = V4L2_COLORSPACE_SMPTE170M; + break; + case HDMI: + dev->sink_rect.width = bt->width; + dev->sink_rect.height = bt->height; + size = V4L2_DV_BT_FRAME_WIDTH(bt) * V4L2_DV_BT_FRAME_HEIGHT(bt); + + if (can_reduce_fps(bt) && (bt->flags & V4L2_DV_FL_REDUCED_FPS)) + pixelclock = div_u64(bt->pixelclock * 1000, 1001); + else + pixelclock = bt->pixelclock; + + dev->timeperframe_vid_out = (struct v4l2_fract) { + size / 100, (u32)pixelclock / 100 + }; + if (bt->interlaced) + dev->field_out = V4L2_FIELD_ALTERNATE; + else + dev->field_out = V4L2_FIELD_NONE; + if (!dev->dvi_d_out && (bt->flags & V4L2_DV_FL_IS_CE_VIDEO)) { + if (bt->width == 720 && bt->height <= 576) + dev->colorspace_out = V4L2_COLORSPACE_SMPTE170M; + else + dev->colorspace_out = V4L2_COLORSPACE_REC709; + } else { + dev->colorspace_out = V4L2_COLORSPACE_SRGB; + } + break; + } + dev->xfer_func_out = V4L2_XFER_FUNC_DEFAULT; + dev->ycbcr_enc_out = V4L2_YCBCR_ENC_DEFAULT; + dev->hsv_enc_out = V4L2_HSV_ENC_180; + dev->quantization_out = V4L2_QUANTIZATION_DEFAULT; + dev->compose_out = dev->sink_rect; + dev->compose_bounds_out = dev->sink_rect; + dev->crop_out = dev->compose_out; + if (V4L2_FIELD_HAS_T_OR_B(dev->field_out)) + dev->crop_out.height /= 2; + dev->fmt_out_rect = dev->crop_out; + for (p = 0; p < dev->fmt_out->planes; p++) + dev->bytesperline_out[p] = + (dev->sink_rect.width * dev->fmt_out->bit_depth[p]) / 8; +} + +/* Map the field to something that is valid for the current output */ +static enum v4l2_field vivid_field_out(struct vivid_dev *dev, enum v4l2_field field) +{ + if (vivid_is_svid_out(dev)) { + switch (field) { + case V4L2_FIELD_INTERLACED_TB: + case V4L2_FIELD_INTERLACED_BT: + case V4L2_FIELD_SEQ_TB: + case V4L2_FIELD_SEQ_BT: + case V4L2_FIELD_ALTERNATE: + return field; + case V4L2_FIELD_INTERLACED: + default: + return V4L2_FIELD_INTERLACED; + } + } + if (vivid_is_hdmi_out(dev)) + return dev->dv_timings_out.bt.interlaced ? V4L2_FIELD_ALTERNATE : + V4L2_FIELD_NONE; + return V4L2_FIELD_NONE; +} + +static enum tpg_pixel_aspect vivid_get_pixel_aspect(const struct vivid_dev *dev) +{ + if (vivid_is_svid_out(dev)) + return (dev->std_out & V4L2_STD_525_60) ? + TPG_PIXEL_ASPECT_NTSC : TPG_PIXEL_ASPECT_PAL; + + if (vivid_is_hdmi_out(dev) && + dev->sink_rect.width == 720 && dev->sink_rect.height <= 576) + return dev->sink_rect.height == 480 ? + TPG_PIXEL_ASPECT_NTSC : TPG_PIXEL_ASPECT_PAL; + + return TPG_PIXEL_ASPECT_SQUARE; +} + +int vivid_g_fmt_vid_out(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct vivid_dev *dev = video_drvdata(file); + struct v4l2_pix_format_mplane *mp = &f->fmt.pix_mp; + const struct vivid_fmt *fmt = dev->fmt_out; + unsigned p; + + mp->width = dev->fmt_out_rect.width; + mp->height = dev->fmt_out_rect.height; + mp->field = dev->field_out; + mp->pixelformat = fmt->fourcc; + mp->colorspace = dev->colorspace_out; + mp->xfer_func = dev->xfer_func_out; + mp->ycbcr_enc = dev->ycbcr_enc_out; + mp->quantization = dev->quantization_out; + mp->num_planes = fmt->buffers; + for (p = 0; p < mp->num_planes; p++) { + mp->plane_fmt[p].bytesperline = dev->bytesperline_out[p]; + mp->plane_fmt[p].sizeimage = + mp->plane_fmt[p].bytesperline * mp->height + + fmt->data_offset[p]; + } + for (p = fmt->buffers; p < fmt->planes; p++) { + unsigned stride = dev->bytesperline_out[p]; + + mp->plane_fmt[0].sizeimage += + (stride * mp->height) / fmt->vdownsampling[p]; + } + return 0; +} + +int vivid_try_fmt_vid_out(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct vivid_dev *dev = video_drvdata(file); + struct v4l2_bt_timings *bt = &dev->dv_timings_out.bt; + struct v4l2_pix_format_mplane *mp = &f->fmt.pix_mp; + struct v4l2_plane_pix_format *pfmt = mp->plane_fmt; + const struct vivid_fmt *fmt; + unsigned bytesperline, max_bpl; + unsigned factor = 1; + unsigned w, h; + unsigned p; + + fmt = vivid_get_format(dev, mp->pixelformat); + if (!fmt) { + dprintk(dev, 1, "Fourcc format (0x%08x) unknown.\n", + mp->pixelformat); + mp->pixelformat = V4L2_PIX_FMT_YUYV; + fmt = vivid_get_format(dev, mp->pixelformat); + } + + mp->field = vivid_field_out(dev, mp->field); + if (vivid_is_svid_out(dev)) { + w = 720; + h = (dev->std_out & V4L2_STD_525_60) ? 480 : 576; + } else { + w = dev->sink_rect.width; + h = dev->sink_rect.height; + } + if (V4L2_FIELD_HAS_T_OR_B(mp->field)) + factor = 2; + if (!dev->has_scaler_out && !dev->has_crop_out && !dev->has_compose_out) { + mp->width = w; + mp->height = h / factor; + } else { + struct v4l2_rect r = { 0, 0, mp->width, mp->height * factor }; + + v4l2_rect_set_min_size(&r, &vivid_min_rect); + v4l2_rect_set_max_size(&r, &vivid_max_rect); + if (dev->has_scaler_out && !dev->has_crop_out) { + struct v4l2_rect max_r = { 0, 0, MAX_ZOOM * w, MAX_ZOOM * h }; + + v4l2_rect_set_max_size(&r, &max_r); + } else if (!dev->has_scaler_out && dev->has_compose_out && !dev->has_crop_out) { + v4l2_rect_set_max_size(&r, &dev->sink_rect); + } else if (!dev->has_scaler_out && !dev->has_compose_out) { + v4l2_rect_set_min_size(&r, &dev->sink_rect); + } + mp->width = r.width; + mp->height = r.height / factor; + } + + /* This driver supports custom bytesperline values */ + + mp->num_planes = fmt->buffers; + for (p = 0; p < fmt->buffers; p++) { + /* Calculate the minimum supported bytesperline value */ + bytesperline = (mp->width * fmt->bit_depth[p]) >> 3; + /* Calculate the maximum supported bytesperline value */ + max_bpl = (MAX_ZOOM * MAX_WIDTH * fmt->bit_depth[p]) >> 3; + + if (pfmt[p].bytesperline > max_bpl) + pfmt[p].bytesperline = max_bpl; + if (pfmt[p].bytesperline < bytesperline) + pfmt[p].bytesperline = bytesperline; + + pfmt[p].sizeimage = (pfmt[p].bytesperline * mp->height) / + fmt->vdownsampling[p] + fmt->data_offset[p]; + + memset(pfmt[p].reserved, 0, sizeof(pfmt[p].reserved)); + } + for (p = fmt->buffers; p < fmt->planes; p++) + pfmt[0].sizeimage += (pfmt[0].bytesperline * mp->height * + (fmt->bit_depth[p] / fmt->vdownsampling[p])) / + (fmt->bit_depth[0] / fmt->vdownsampling[0]); + + mp->xfer_func = V4L2_XFER_FUNC_DEFAULT; + mp->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + mp->quantization = V4L2_QUANTIZATION_DEFAULT; + if (vivid_is_svid_out(dev)) { + mp->colorspace = V4L2_COLORSPACE_SMPTE170M; + } else if (dev->dvi_d_out || !(bt->flags & V4L2_DV_FL_IS_CE_VIDEO)) { + mp->colorspace = V4L2_COLORSPACE_SRGB; + if (dev->dvi_d_out) + mp->quantization = V4L2_QUANTIZATION_LIM_RANGE; + } else if (bt->width == 720 && bt->height <= 576) { + mp->colorspace = V4L2_COLORSPACE_SMPTE170M; + } else if (mp->colorspace != V4L2_COLORSPACE_SMPTE170M && + mp->colorspace != V4L2_COLORSPACE_REC709 && + mp->colorspace != V4L2_COLORSPACE_OPRGB && + mp->colorspace != V4L2_COLORSPACE_BT2020 && + mp->colorspace != V4L2_COLORSPACE_SRGB) { + mp->colorspace = V4L2_COLORSPACE_REC709; + } + memset(mp->reserved, 0, sizeof(mp->reserved)); + return 0; +} + +int vivid_s_fmt_vid_out(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct v4l2_pix_format_mplane *mp = &f->fmt.pix_mp; + struct vivid_dev *dev = video_drvdata(file); + struct v4l2_rect *crop = &dev->crop_out; + struct v4l2_rect *compose = &dev->compose_out; + struct vb2_queue *q = &dev->vb_vid_out_q; + int ret = vivid_try_fmt_vid_out(file, priv, f); + unsigned factor = 1; + unsigned p; + + if (ret < 0) + return ret; + + if (vb2_is_busy(q) && + (vivid_is_svid_out(dev) || + mp->width != dev->fmt_out_rect.width || + mp->height != dev->fmt_out_rect.height || + mp->pixelformat != dev->fmt_out->fourcc || + mp->field != dev->field_out)) { + dprintk(dev, 1, "%s device busy\n", __func__); + return -EBUSY; + } + + /* + * Allow for changing the colorspace on the fly. Useful for testing + * purposes, and it is something that HDMI transmitters are able + * to do. + */ + if (vb2_is_busy(q)) + goto set_colorspace; + + dev->fmt_out = vivid_get_format(dev, mp->pixelformat); + if (V4L2_FIELD_HAS_T_OR_B(mp->field)) + factor = 2; + + if (dev->has_scaler_out || dev->has_crop_out || dev->has_compose_out) { + struct v4l2_rect r = { 0, 0, mp->width, mp->height }; + + if (dev->has_scaler_out) { + if (dev->has_crop_out) + v4l2_rect_map_inside(crop, &r); + else + *crop = r; + if (dev->has_compose_out && !dev->has_crop_out) { + struct v4l2_rect min_r = { + 0, 0, + r.width / MAX_ZOOM, + factor * r.height / MAX_ZOOM + }; + struct v4l2_rect max_r = { + 0, 0, + r.width * MAX_ZOOM, + factor * r.height * MAX_ZOOM + }; + + v4l2_rect_set_min_size(compose, &min_r); + v4l2_rect_set_max_size(compose, &max_r); + v4l2_rect_map_inside(compose, &dev->compose_bounds_out); + } else if (dev->has_compose_out) { + struct v4l2_rect min_r = { + 0, 0, + crop->width / MAX_ZOOM, + factor * crop->height / MAX_ZOOM + }; + struct v4l2_rect max_r = { + 0, 0, + crop->width * MAX_ZOOM, + factor * crop->height * MAX_ZOOM + }; + + v4l2_rect_set_min_size(compose, &min_r); + v4l2_rect_set_max_size(compose, &max_r); + v4l2_rect_map_inside(compose, &dev->compose_bounds_out); + } + } else if (dev->has_compose_out && !dev->has_crop_out) { + v4l2_rect_set_size_to(crop, &r); + r.height *= factor; + v4l2_rect_set_size_to(compose, &r); + v4l2_rect_map_inside(compose, &dev->compose_bounds_out); + } else if (!dev->has_compose_out) { + v4l2_rect_map_inside(crop, &r); + r.height /= factor; + v4l2_rect_set_size_to(compose, &r); + } else { + r.height *= factor; + v4l2_rect_set_max_size(compose, &r); + v4l2_rect_map_inside(compose, &dev->compose_bounds_out); + crop->top *= factor; + crop->height *= factor; + v4l2_rect_set_size_to(crop, compose); + v4l2_rect_map_inside(crop, &r); + crop->top /= factor; + crop->height /= factor; + } + } else { + struct v4l2_rect r = { 0, 0, mp->width, mp->height }; + + v4l2_rect_set_size_to(crop, &r); + r.height /= factor; + v4l2_rect_set_size_to(compose, &r); + } + + dev->fmt_out_rect.width = mp->width; + dev->fmt_out_rect.height = mp->height; + for (p = 0; p < mp->num_planes; p++) + dev->bytesperline_out[p] = mp->plane_fmt[p].bytesperline; + for (p = dev->fmt_out->buffers; p < dev->fmt_out->planes; p++) + dev->bytesperline_out[p] = + (dev->bytesperline_out[0] * dev->fmt_out->bit_depth[p]) / + dev->fmt_out->bit_depth[0]; + dev->field_out = mp->field; + if (vivid_is_svid_out(dev)) + dev->tv_field_out = mp->field; + +set_colorspace: + dev->colorspace_out = mp->colorspace; + dev->xfer_func_out = mp->xfer_func; + dev->ycbcr_enc_out = mp->ycbcr_enc; + dev->quantization_out = mp->quantization; + if (dev->loop_video) { + vivid_send_source_change(dev, SVID); + vivid_send_source_change(dev, HDMI); + } + return 0; +} + +int vidioc_g_fmt_vid_out_mplane(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (!dev->multiplanar) + return -ENOTTY; + return vivid_g_fmt_vid_out(file, priv, f); +} + +int vidioc_try_fmt_vid_out_mplane(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (!dev->multiplanar) + return -ENOTTY; + return vivid_try_fmt_vid_out(file, priv, f); +} + +int vidioc_s_fmt_vid_out_mplane(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (!dev->multiplanar) + return -ENOTTY; + return vivid_s_fmt_vid_out(file, priv, f); +} + +int vidioc_g_fmt_vid_out(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (dev->multiplanar) + return -ENOTTY; + return fmt_sp2mp_func(file, priv, f, vivid_g_fmt_vid_out); +} + +int vidioc_try_fmt_vid_out(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (dev->multiplanar) + return -ENOTTY; + return fmt_sp2mp_func(file, priv, f, vivid_try_fmt_vid_out); +} + +int vidioc_s_fmt_vid_out(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (dev->multiplanar) + return -ENOTTY; + return fmt_sp2mp_func(file, priv, f, vivid_s_fmt_vid_out); +} + +int vivid_vid_out_g_selection(struct file *file, void *priv, + struct v4l2_selection *sel) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (!dev->has_crop_out && !dev->has_compose_out) + return -ENOTTY; + if (sel->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) + return -EINVAL; + + sel->r.left = sel->r.top = 0; + switch (sel->target) { + case V4L2_SEL_TGT_CROP: + if (!dev->has_crop_out) + return -EINVAL; + sel->r = dev->crop_out; + break; + case V4L2_SEL_TGT_CROP_DEFAULT: + if (!dev->has_crop_out) + return -EINVAL; + sel->r = dev->fmt_out_rect; + break; + case V4L2_SEL_TGT_CROP_BOUNDS: + if (!dev->has_crop_out) + return -EINVAL; + sel->r = vivid_max_rect; + break; + case V4L2_SEL_TGT_COMPOSE: + if (!dev->has_compose_out) + return -EINVAL; + sel->r = dev->compose_out; + break; + case V4L2_SEL_TGT_COMPOSE_DEFAULT: + case V4L2_SEL_TGT_COMPOSE_BOUNDS: + if (!dev->has_compose_out) + return -EINVAL; + sel->r = dev->sink_rect; + break; + default: + return -EINVAL; + } + return 0; +} + +int vivid_vid_out_s_selection(struct file *file, void *fh, struct v4l2_selection *s) +{ + struct vivid_dev *dev = video_drvdata(file); + struct v4l2_rect *crop = &dev->crop_out; + struct v4l2_rect *compose = &dev->compose_out; + unsigned factor = V4L2_FIELD_HAS_T_OR_B(dev->field_out) ? 2 : 1; + int ret; + + if (!dev->has_crop_out && !dev->has_compose_out) + return -ENOTTY; + if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) + return -EINVAL; + + switch (s->target) { + case V4L2_SEL_TGT_CROP: + if (!dev->has_crop_out) + return -EINVAL; + ret = vivid_vid_adjust_sel(s->flags, &s->r); + if (ret) + return ret; + v4l2_rect_set_min_size(&s->r, &vivid_min_rect); + v4l2_rect_set_max_size(&s->r, &dev->fmt_out_rect); + if (dev->has_scaler_out) { + struct v4l2_rect max_rect = { + 0, 0, + dev->sink_rect.width * MAX_ZOOM, + (dev->sink_rect.height / factor) * MAX_ZOOM + }; + + v4l2_rect_set_max_size(&s->r, &max_rect); + if (dev->has_compose_out) { + struct v4l2_rect min_rect = { + 0, 0, + s->r.width / MAX_ZOOM, + (s->r.height * factor) / MAX_ZOOM + }; + struct v4l2_rect max_rect = { + 0, 0, + s->r.width * MAX_ZOOM, + (s->r.height * factor) * MAX_ZOOM + }; + + v4l2_rect_set_min_size(compose, &min_rect); + v4l2_rect_set_max_size(compose, &max_rect); + v4l2_rect_map_inside(compose, &dev->compose_bounds_out); + } + } else if (dev->has_compose_out) { + s->r.top *= factor; + s->r.height *= factor; + v4l2_rect_set_max_size(&s->r, &dev->sink_rect); + v4l2_rect_set_size_to(compose, &s->r); + v4l2_rect_map_inside(compose, &dev->compose_bounds_out); + s->r.top /= factor; + s->r.height /= factor; + } else { + v4l2_rect_set_size_to(&s->r, &dev->sink_rect); + s->r.height /= factor; + } + v4l2_rect_map_inside(&s->r, &dev->fmt_out_rect); + *crop = s->r; + break; + case V4L2_SEL_TGT_COMPOSE: + if (!dev->has_compose_out) + return -EINVAL; + ret = vivid_vid_adjust_sel(s->flags, &s->r); + if (ret) + return ret; + v4l2_rect_set_min_size(&s->r, &vivid_min_rect); + v4l2_rect_set_max_size(&s->r, &dev->sink_rect); + v4l2_rect_map_inside(&s->r, &dev->compose_bounds_out); + s->r.top /= factor; + s->r.height /= factor; + if (dev->has_scaler_out) { + struct v4l2_rect fmt = dev->fmt_out_rect; + struct v4l2_rect max_rect = { + 0, 0, + s->r.width * MAX_ZOOM, + s->r.height * MAX_ZOOM + }; + struct v4l2_rect min_rect = { + 0, 0, + s->r.width / MAX_ZOOM, + s->r.height / MAX_ZOOM + }; + + v4l2_rect_set_min_size(&fmt, &min_rect); + if (!dev->has_crop_out) + v4l2_rect_set_max_size(&fmt, &max_rect); + if (!v4l2_rect_same_size(&dev->fmt_out_rect, &fmt) && + vb2_is_busy(&dev->vb_vid_out_q)) + return -EBUSY; + if (dev->has_crop_out) { + v4l2_rect_set_min_size(crop, &min_rect); + v4l2_rect_set_max_size(crop, &max_rect); + } + dev->fmt_out_rect = fmt; + } else if (dev->has_crop_out) { + struct v4l2_rect fmt = dev->fmt_out_rect; + + v4l2_rect_set_min_size(&fmt, &s->r); + if (!v4l2_rect_same_size(&dev->fmt_out_rect, &fmt) && + vb2_is_busy(&dev->vb_vid_out_q)) + return -EBUSY; + dev->fmt_out_rect = fmt; + v4l2_rect_set_size_to(crop, &s->r); + v4l2_rect_map_inside(crop, &dev->fmt_out_rect); + } else { + if (!v4l2_rect_same_size(&s->r, &dev->fmt_out_rect) && + vb2_is_busy(&dev->vb_vid_out_q)) + return -EBUSY; + v4l2_rect_set_size_to(&dev->fmt_out_rect, &s->r); + v4l2_rect_set_size_to(crop, &s->r); + crop->height /= factor; + v4l2_rect_map_inside(crop, &dev->fmt_out_rect); + } + s->r.top *= factor; + s->r.height *= factor; + if (dev->bitmap_out && (compose->width != s->r.width || + compose->height != s->r.height)) { + vfree(dev->bitmap_out); + dev->bitmap_out = NULL; + } + *compose = s->r; + break; + default: + return -EINVAL; + } + + return 0; +} + +int vivid_vid_out_g_pixelaspect(struct file *file, void *priv, + int type, struct v4l2_fract *f) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (type != V4L2_BUF_TYPE_VIDEO_OUTPUT) + return -EINVAL; + + switch (vivid_get_pixel_aspect(dev)) { + case TPG_PIXEL_ASPECT_NTSC: + f->numerator = 11; + f->denominator = 10; + break; + case TPG_PIXEL_ASPECT_PAL: + f->numerator = 54; + f->denominator = 59; + break; + default: + break; + } + return 0; +} + +int vidioc_g_fmt_vid_out_overlay(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct vivid_dev *dev = video_drvdata(file); + const struct v4l2_rect *compose = &dev->compose_out; + struct v4l2_window *win = &f->fmt.win; + unsigned clipcount = win->clipcount; + + if (!dev->has_fb) + return -EINVAL; + win->w.top = dev->overlay_out_top; + win->w.left = dev->overlay_out_left; + win->w.width = compose->width; + win->w.height = compose->height; + win->clipcount = dev->clipcount_out; + win->field = V4L2_FIELD_ANY; + win->chromakey = dev->chromakey_out; + win->global_alpha = dev->global_alpha_out; + if (clipcount > dev->clipcount_out) + clipcount = dev->clipcount_out; + if (dev->bitmap_out == NULL) + win->bitmap = NULL; + else if (win->bitmap) { + if (copy_to_user(win->bitmap, dev->bitmap_out, + ((dev->compose_out.width + 7) / 8) * dev->compose_out.height)) + return -EFAULT; + } + if (clipcount && win->clips) { + if (copy_to_user(win->clips, dev->clips_out, + clipcount * sizeof(dev->clips_out[0]))) + return -EFAULT; + } + return 0; +} + +int vidioc_try_fmt_vid_out_overlay(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct vivid_dev *dev = video_drvdata(file); + const struct v4l2_rect *compose = &dev->compose_out; + struct v4l2_window *win = &f->fmt.win; + int i, j; + + if (!dev->has_fb) + return -EINVAL; + win->w.left = clamp_t(int, win->w.left, + -dev->display_width, dev->display_width); + win->w.top = clamp_t(int, win->w.top, + -dev->display_height, dev->display_height); + win->w.width = compose->width; + win->w.height = compose->height; + /* + * It makes no sense for an OSD to overlay only top or bottom fields, + * so always set this to ANY. + */ + win->field = V4L2_FIELD_ANY; + if (win->clipcount && !win->clips) + win->clipcount = 0; + if (win->clipcount > MAX_CLIPS) + win->clipcount = MAX_CLIPS; + if (win->clipcount) { + if (copy_from_user(dev->try_clips_out, win->clips, + win->clipcount * sizeof(dev->clips_out[0]))) + return -EFAULT; + for (i = 0; i < win->clipcount; i++) { + struct v4l2_rect *r = &dev->try_clips_out[i].c; + + r->top = clamp_t(s32, r->top, 0, dev->display_height - 1); + r->height = clamp_t(s32, r->height, 1, dev->display_height - r->top); + r->left = clamp_t(u32, r->left, 0, dev->display_width - 1); + r->width = clamp_t(u32, r->width, 1, dev->display_width - r->left); + } + /* + * Yeah, so sue me, it's an O(n^2) algorithm. But n is a small + * number and it's typically a one-time deal. + */ + for (i = 0; i < win->clipcount - 1; i++) { + struct v4l2_rect *r1 = &dev->try_clips_out[i].c; + + for (j = i + 1; j < win->clipcount; j++) { + struct v4l2_rect *r2 = &dev->try_clips_out[j].c; + + if (v4l2_rect_overlap(r1, r2)) + return -EINVAL; + } + } + if (copy_to_user(win->clips, dev->try_clips_out, + win->clipcount * sizeof(dev->clips_out[0]))) + return -EFAULT; + } + return 0; +} + +int vidioc_s_fmt_vid_out_overlay(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct vivid_dev *dev = video_drvdata(file); + const struct v4l2_rect *compose = &dev->compose_out; + struct v4l2_window *win = &f->fmt.win; + int ret = vidioc_try_fmt_vid_out_overlay(file, priv, f); + unsigned bitmap_size = ((compose->width + 7) / 8) * compose->height; + unsigned clips_size = win->clipcount * sizeof(dev->clips_out[0]); + void *new_bitmap = NULL; + + if (ret) + return ret; + + if (win->bitmap) { + new_bitmap = vzalloc(bitmap_size); + + if (!new_bitmap) + return -ENOMEM; + if (copy_from_user(new_bitmap, win->bitmap, bitmap_size)) { + vfree(new_bitmap); + return -EFAULT; + } + } + + dev->overlay_out_top = win->w.top; + dev->overlay_out_left = win->w.left; + vfree(dev->bitmap_out); + dev->bitmap_out = new_bitmap; + dev->clipcount_out = win->clipcount; + if (dev->clipcount_out) + memcpy(dev->clips_out, dev->try_clips_out, clips_size); + dev->chromakey_out = win->chromakey; + dev->global_alpha_out = win->global_alpha; + return ret; +} + +int vivid_vid_out_overlay(struct file *file, void *fh, unsigned i) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (i && !dev->fmt_out->can_do_overlay) { + dprintk(dev, 1, "unsupported output format for output overlay\n"); + return -EINVAL; + } + + dev->overlay_out_enabled = i; + return 0; +} + +int vivid_vid_out_g_fbuf(struct file *file, void *fh, + struct v4l2_framebuffer *a) +{ + struct vivid_dev *dev = video_drvdata(file); + + a->capability = V4L2_FBUF_CAP_EXTERNOVERLAY | + V4L2_FBUF_CAP_BITMAP_CLIPPING | + V4L2_FBUF_CAP_LIST_CLIPPING | + V4L2_FBUF_CAP_CHROMAKEY | + V4L2_FBUF_CAP_SRC_CHROMAKEY | + V4L2_FBUF_CAP_GLOBAL_ALPHA | + V4L2_FBUF_CAP_LOCAL_ALPHA | + V4L2_FBUF_CAP_LOCAL_INV_ALPHA; + a->flags = V4L2_FBUF_FLAG_OVERLAY | dev->fbuf_out_flags; + a->base = (void *)dev->video_pbase; + a->fmt.width = dev->display_width; + a->fmt.height = dev->display_height; + if (dev->fb_defined.green.length == 5) + a->fmt.pixelformat = V4L2_PIX_FMT_ARGB555; + else + a->fmt.pixelformat = V4L2_PIX_FMT_RGB565; + a->fmt.bytesperline = dev->display_byte_stride; + a->fmt.sizeimage = a->fmt.height * a->fmt.bytesperline; + a->fmt.field = V4L2_FIELD_NONE; + a->fmt.colorspace = V4L2_COLORSPACE_SRGB; + a->fmt.priv = 0; + return 0; +} + +int vivid_vid_out_s_fbuf(struct file *file, void *fh, + const struct v4l2_framebuffer *a) +{ + struct vivid_dev *dev = video_drvdata(file); + const unsigned chroma_flags = V4L2_FBUF_FLAG_CHROMAKEY | + V4L2_FBUF_FLAG_SRC_CHROMAKEY; + const unsigned alpha_flags = V4L2_FBUF_FLAG_GLOBAL_ALPHA | + V4L2_FBUF_FLAG_LOCAL_ALPHA | + V4L2_FBUF_FLAG_LOCAL_INV_ALPHA; + + + if ((a->flags & chroma_flags) == chroma_flags) + return -EINVAL; + switch (a->flags & alpha_flags) { + case 0: + case V4L2_FBUF_FLAG_GLOBAL_ALPHA: + case V4L2_FBUF_FLAG_LOCAL_ALPHA: + case V4L2_FBUF_FLAG_LOCAL_INV_ALPHA: + break; + default: + return -EINVAL; + } + dev->fbuf_out_flags &= ~(chroma_flags | alpha_flags); + dev->fbuf_out_flags = a->flags & (chroma_flags | alpha_flags); + return 0; +} + +static const struct v4l2_audioout vivid_audio_outputs[] = { + { 0, "Line-Out 1" }, + { 1, "Line-Out 2" }, +}; + +int vidioc_enum_output(struct file *file, void *priv, + struct v4l2_output *out) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (out->index >= dev->num_outputs) + return -EINVAL; + + out->type = V4L2_OUTPUT_TYPE_ANALOG; + switch (dev->output_type[out->index]) { + case SVID: + snprintf(out->name, sizeof(out->name), "S-Video %u", + dev->output_name_counter[out->index]); + out->std = V4L2_STD_ALL; + if (dev->has_audio_outputs) + out->audioset = (1 << ARRAY_SIZE(vivid_audio_outputs)) - 1; + out->capabilities = V4L2_OUT_CAP_STD; + break; + case HDMI: + snprintf(out->name, sizeof(out->name), "HDMI %u", + dev->output_name_counter[out->index]); + out->capabilities = V4L2_OUT_CAP_DV_TIMINGS; + break; + } + return 0; +} + +int vidioc_g_output(struct file *file, void *priv, unsigned *o) +{ + struct vivid_dev *dev = video_drvdata(file); + + *o = dev->output; + return 0; +} + +int vidioc_s_output(struct file *file, void *priv, unsigned o) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (o >= dev->num_outputs) + return -EINVAL; + + if (o == dev->output) + return 0; + + if (vb2_is_busy(&dev->vb_vid_out_q) || + vb2_is_busy(&dev->vb_vbi_out_q) || + vb2_is_busy(&dev->vb_meta_out_q)) + return -EBUSY; + + dev->output = o; + dev->tv_audio_output = 0; + if (dev->output_type[o] == SVID) + dev->vid_out_dev.tvnorms = V4L2_STD_ALL; + else + dev->vid_out_dev.tvnorms = 0; + + dev->vbi_out_dev.tvnorms = dev->vid_out_dev.tvnorms; + dev->meta_out_dev.tvnorms = dev->vid_out_dev.tvnorms; + vivid_update_format_out(dev); + + v4l2_ctrl_activate(dev->ctrl_display_present, vivid_is_hdmi_out(dev)); + if (vivid_is_hdmi_out(dev)) + v4l2_ctrl_s_ctrl(dev->ctrl_display_present, + dev->display_present[dev->output]); + + return 0; +} + +int vidioc_enumaudout(struct file *file, void *fh, struct v4l2_audioout *vout) +{ + if (vout->index >= ARRAY_SIZE(vivid_audio_outputs)) + return -EINVAL; + *vout = vivid_audio_outputs[vout->index]; + return 0; +} + +int vidioc_g_audout(struct file *file, void *fh, struct v4l2_audioout *vout) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (!vivid_is_svid_out(dev)) + return -EINVAL; + *vout = vivid_audio_outputs[dev->tv_audio_output]; + return 0; +} + +int vidioc_s_audout(struct file *file, void *fh, const struct v4l2_audioout *vout) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (!vivid_is_svid_out(dev)) + return -EINVAL; + if (vout->index >= ARRAY_SIZE(vivid_audio_outputs)) + return -EINVAL; + dev->tv_audio_output = vout->index; + return 0; +} + +int vivid_vid_out_s_std(struct file *file, void *priv, v4l2_std_id id) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (!vivid_is_svid_out(dev)) + return -ENODATA; + if (dev->std_out == id) + return 0; + if (vb2_is_busy(&dev->vb_vid_out_q) || vb2_is_busy(&dev->vb_vbi_out_q)) + return -EBUSY; + dev->std_out = id; + vivid_update_format_out(dev); + return 0; +} + +static bool valid_cvt_gtf_timings(struct v4l2_dv_timings *timings) +{ + struct v4l2_bt_timings *bt = &timings->bt; + + if ((bt->standards & (V4L2_DV_BT_STD_CVT | V4L2_DV_BT_STD_GTF)) && + v4l2_valid_dv_timings(timings, &vivid_dv_timings_cap, NULL, NULL)) + return true; + + return false; +} + +int vivid_vid_out_s_dv_timings(struct file *file, void *_fh, + struct v4l2_dv_timings *timings) +{ + struct vivid_dev *dev = video_drvdata(file); + if (!vivid_is_hdmi_out(dev)) + return -ENODATA; + if (!v4l2_find_dv_timings_cap(timings, &vivid_dv_timings_cap, + 0, NULL, NULL) && + !valid_cvt_gtf_timings(timings)) + return -EINVAL; + if (v4l2_match_dv_timings(timings, &dev->dv_timings_out, 0, true)) + return 0; + if (vb2_is_busy(&dev->vb_vid_out_q)) + return -EBUSY; + dev->dv_timings_out = *timings; + vivid_update_format_out(dev); + return 0; +} + +int vivid_vid_out_g_parm(struct file *file, void *priv, + struct v4l2_streamparm *parm) +{ + struct vivid_dev *dev = video_drvdata(file); + + if (parm->type != (dev->multiplanar ? + V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE : + V4L2_BUF_TYPE_VIDEO_OUTPUT)) + return -EINVAL; + + parm->parm.output.capability = V4L2_CAP_TIMEPERFRAME; + parm->parm.output.timeperframe = dev->timeperframe_vid_out; + parm->parm.output.writebuffers = 1; + + return 0; +} + +int vidioc_subscribe_event(struct v4l2_fh *fh, + const struct v4l2_event_subscription *sub) +{ + switch (sub->type) { + case V4L2_EVENT_SOURCE_CHANGE: + if (fh->vdev->vfl_dir == VFL_DIR_RX) + return v4l2_src_change_event_subscribe(fh, sub); + break; + default: + return v4l2_ctrl_subscribe_event(fh, sub); + } + return -EINVAL; +} diff --git a/drivers/media/test_drivers/vivid/vivid-vid-out.h b/drivers/media/test_drivers/vivid/vivid-vid-out.h new file mode 100644 index 000000000000..8d56314f4ea1 --- /dev/null +++ b/drivers/media/test_drivers/vivid/vivid-vid-out.h @@ -0,0 +1,44 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * vivid-vid-out.h - video output support functions. + * + * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved. + */ + +#ifndef _VIVID_VID_OUT_H_ +#define _VIVID_VID_OUT_H_ + +extern const struct vb2_ops vivid_vid_out_qops; + +void vivid_update_format_out(struct vivid_dev *dev); + +int vivid_g_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f); +int vivid_try_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f); +int vivid_s_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f); +int vidioc_g_fmt_vid_out_mplane(struct file *file, void *priv, struct v4l2_format *f); +int vidioc_try_fmt_vid_out_mplane(struct file *file, void *priv, struct v4l2_format *f); +int vidioc_s_fmt_vid_out_mplane(struct file *file, void *priv, struct v4l2_format *f); +int vidioc_g_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f); +int vidioc_try_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f); +int vidioc_s_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f); +int vivid_vid_out_g_selection(struct file *file, void *priv, struct v4l2_selection *sel); +int vivid_vid_out_s_selection(struct file *file, void *fh, struct v4l2_selection *s); +int vivid_vid_out_g_pixelaspect(struct file *file, void *priv, int type, struct v4l2_fract *f); +int vidioc_enum_fmt_vid_out_overlay(struct file *file, void *priv, struct v4l2_fmtdesc *f); +int vidioc_g_fmt_vid_out_overlay(struct file *file, void *priv, struct v4l2_format *f); +int vidioc_try_fmt_vid_out_overlay(struct file *file, void *priv, struct v4l2_format *f); +int vidioc_s_fmt_vid_out_overlay(struct file *file, void *priv, struct v4l2_format *f); +int vivid_vid_out_overlay(struct file *file, void *fh, unsigned i); +int vivid_vid_out_g_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *a); +int vivid_vid_out_s_fbuf(struct file *file, void *fh, const struct v4l2_framebuffer *a); +int vidioc_enum_output(struct file *file, void *priv, struct v4l2_output *out); +int vidioc_g_output(struct file *file, void *priv, unsigned *i); +int vidioc_s_output(struct file *file, void *priv, unsigned i); +int vidioc_enumaudout(struct file *file, void *fh, struct v4l2_audioout *vout); +int vidioc_g_audout(struct file *file, void *fh, struct v4l2_audioout *vout); +int vidioc_s_audout(struct file *file, void *fh, const struct v4l2_audioout *vout); +int vivid_vid_out_s_std(struct file *file, void *priv, v4l2_std_id id); +int vivid_vid_out_s_dv_timings(struct file *file, void *_fh, struct v4l2_dv_timings *timings); +int vivid_vid_out_g_parm(struct file *file, void *priv, struct v4l2_streamparm *parm); + +#endif -- cgit v1.2.3 From a41034df538968e726c6aad3e5d8b99799d2d0cd Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 24 Mar 2020 13:43:23 +0100 Subject: media: Kconfig: move comment to siano include Showing this comment without showing the Siano mmc option is very weird! Place the option together, and make it visible only when showing Siano configuration. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/mmc/Kconfig | 1 - drivers/media/mmc/siano/Kconfig | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/mmc/Kconfig b/drivers/media/mmc/Kconfig index de0528c6994a..75aa6de08d53 100644 --- a/drivers/media/mmc/Kconfig +++ b/drivers/media/mmc/Kconfig @@ -1,3 +1,2 @@ # SPDX-License-Identifier: GPL-2.0-only -comment "Supported MMC/SDIO adapters" source "drivers/media/mmc/siano/Kconfig" diff --git a/drivers/media/mmc/siano/Kconfig b/drivers/media/mmc/siano/Kconfig index 1919f6fea8b1..570696019a9e 100644 --- a/drivers/media/mmc/siano/Kconfig +++ b/drivers/media/mmc/siano/Kconfig @@ -2,6 +2,8 @@ # # Siano Mobile Silicon Digital TV device configuration # +comment "MMC/SDIO DVB adapters" + depends on DVB_CORE && HAS_DMA && MMC config SMS_SDIO_DRV tristate "Siano SMS1xxx based MDTV via SDIO interface" -- cgit v1.2.3 From 3bb112016616ca01f6ee06ee2bf77d8eec4afeb1 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 24 Mar 2020 13:53:23 +0100 Subject: media: Kconfig: move drivers-specific TTPCI_EEPROM Kconfig var This option is used only by av7110 and by an USB driver. As the av7110 is the first DVB hardware, hardly found those days, let's opt to place it at usb/Kconfig, as the driver with needs it might have a longer lifetime. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/Kconfig | 5 ----- drivers/media/usb/Kconfig | 6 ++++++ 2 files changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index b35c980dcf56..f37c0c26fa65 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -178,11 +178,6 @@ config DVB_NET You may want to disable the network support on embedded devices. If unsure say Y. -# This Kconfig option is used by both PCI and USB drivers -config TTPCI_EEPROM - tristate - depends on I2C - source "drivers/media/dvb-core/Kconfig" comment "Media drivers" diff --git a/drivers/media/usb/Kconfig b/drivers/media/usb/Kconfig index e678d3d11467..bf08393e38d1 100644 --- a/drivers/media/usb/Kconfig +++ b/drivers/media/usb/Kconfig @@ -1,4 +1,10 @@ # SPDX-License-Identifier: GPL-2.0-only + +# This Kconfig option is also used by the legacy av7110 driver +config TTPCI_EEPROM + tristate + depends on I2C + if USB && MEDIA_SUPPORT menuconfig MEDIA_USB_SUPPORT -- cgit v1.2.3 From 6a79117187b384e837310d85a824fe0b6381e057 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 24 Mar 2020 14:06:08 +0100 Subject: media: Kconfig: mode firewire comment to firewire/Kconfig This comment should only be visible if the DVB_FIREDTV config will show. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/Kconfig | 2 -- drivers/media/firewire/Kconfig | 5 ++++- 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index f37c0c26fa65..dc0cc42d48ad 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -192,8 +192,6 @@ source "drivers/media/test_drivers/Kconfig" source "drivers/media/mmc/Kconfig" endif -comment "Supported FireWire (IEEE 1394) Adapters" - depends on DVB_CORE && FIREWIRE source "drivers/media/firewire/Kconfig" # Common driver options diff --git a/drivers/media/firewire/Kconfig b/drivers/media/firewire/Kconfig index e7837da5905b..0c1f326f581f 100644 --- a/drivers/media/firewire/Kconfig +++ b/drivers/media/firewire/Kconfig @@ -1,7 +1,9 @@ # SPDX-License-Identifier: GPL-2.0-only +if DVB_CORE && FIREWIRE +comment "FireWire (IEEE 1394) Adapters" + config DVB_FIREDTV tristate "FireDTV and FloppyDTV" - depends on DVB_CORE && FIREWIRE help Support for DVB receivers from Digital Everywhere which are connected via IEEE 1394 (FireWire). @@ -18,3 +20,4 @@ config DVB_FIREDTV_INPUT def_bool INPUT = y || (INPUT = m && DVB_FIREDTV = m) endif # DVB_FIREDTV +endif # DVB_CORE && FIREWIRE -- cgit v1.2.3 From 3a137f81f76850b3cc024360147b1c3fb4b12c03 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 26 Mar 2020 15:06:02 +0100 Subject: media: ddbridge: copy the dvb_dummy_fe driver to ddbridge As we'll be transforming the dvb-dummy-fe driver soon into a virtual driver, let's first copy the existing one to ddbridge as-is, as it is needed there. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/ddbridge/ddbridge-dummy-fe.c | 286 +++++++++++++++++++++++++ drivers/media/pci/ddbridge/ddbridge-dummy-fe.h | 36 ++++ 2 files changed, 322 insertions(+) create mode 100644 drivers/media/pci/ddbridge/ddbridge-dummy-fe.c create mode 100644 drivers/media/pci/ddbridge/ddbridge-dummy-fe.h (limited to 'drivers/media') diff --git a/drivers/media/pci/ddbridge/ddbridge-dummy-fe.c b/drivers/media/pci/ddbridge/ddbridge-dummy-fe.c new file mode 100644 index 000000000000..9ff1ebaa5e04 --- /dev/null +++ b/drivers/media/pci/ddbridge/ddbridge-dummy-fe.c @@ -0,0 +1,286 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Driver for Dummy Frontend + * + * Written by Emard + */ + +#include +#include +#include +#include + +#include +#include "dvb_dummy_fe.h" + + +struct dvb_dummy_fe_state { + struct dvb_frontend frontend; +}; + + +static int dvb_dummy_fe_read_status(struct dvb_frontend *fe, + enum fe_status *status) +{ + *status = FE_HAS_SIGNAL + | FE_HAS_CARRIER + | FE_HAS_VITERBI + | FE_HAS_SYNC + | FE_HAS_LOCK; + + return 0; +} + +static int dvb_dummy_fe_read_ber(struct dvb_frontend *fe, u32 *ber) +{ + *ber = 0; + return 0; +} + +static int dvb_dummy_fe_read_signal_strength(struct dvb_frontend *fe, + u16 *strength) +{ + *strength = 0; + return 0; +} + +static int dvb_dummy_fe_read_snr(struct dvb_frontend *fe, u16 *snr) +{ + *snr = 0; + return 0; +} + +static int dvb_dummy_fe_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) +{ + *ucblocks = 0; + return 0; +} + +/* + * Should only be implemented if it actually reads something from the hardware. + * Also, it should check for the locks, in order to avoid report wrong data + * to userspace. + */ +static int dvb_dummy_fe_get_frontend(struct dvb_frontend *fe, + struct dtv_frontend_properties *p) +{ + return 0; +} + +static int dvb_dummy_fe_set_frontend(struct dvb_frontend *fe) +{ + if (fe->ops.tuner_ops.set_params) { + fe->ops.tuner_ops.set_params(fe); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + } + + return 0; +} + +static int dvb_dummy_fe_sleep(struct dvb_frontend *fe) +{ + return 0; +} + +static int dvb_dummy_fe_init(struct dvb_frontend *fe) +{ + return 0; +} + +static int dvb_dummy_fe_set_tone(struct dvb_frontend *fe, + enum fe_sec_tone_mode tone) +{ + return 0; +} + +static int dvb_dummy_fe_set_voltage(struct dvb_frontend *fe, + enum fe_sec_voltage voltage) +{ + return 0; +} + +static void dvb_dummy_fe_release(struct dvb_frontend *fe) +{ + struct dvb_dummy_fe_state *state = fe->demodulator_priv; + + kfree(state); +} + +static const struct dvb_frontend_ops dvb_dummy_fe_ofdm_ops; + +struct dvb_frontend *dvb_dummy_fe_ofdm_attach(void) +{ + struct dvb_dummy_fe_state *state = NULL; + + /* allocate memory for the internal state */ + state = kzalloc(sizeof(struct dvb_dummy_fe_state), GFP_KERNEL); + if (!state) + return NULL; + + /* create dvb_frontend */ + memcpy(&state->frontend.ops, + &dvb_dummy_fe_ofdm_ops, + sizeof(struct dvb_frontend_ops)); + + state->frontend.demodulator_priv = state; + return &state->frontend; +} +EXPORT_SYMBOL(dvb_dummy_fe_ofdm_attach); + +static const struct dvb_frontend_ops dvb_dummy_fe_qpsk_ops; + +struct dvb_frontend *dvb_dummy_fe_qpsk_attach(void) +{ + struct dvb_dummy_fe_state *state = NULL; + + /* allocate memory for the internal state */ + state = kzalloc(sizeof(struct dvb_dummy_fe_state), GFP_KERNEL); + if (!state) + return NULL; + + /* create dvb_frontend */ + memcpy(&state->frontend.ops, + &dvb_dummy_fe_qpsk_ops, + sizeof(struct dvb_frontend_ops)); + + state->frontend.demodulator_priv = state; + return &state->frontend; +} +EXPORT_SYMBOL(dvb_dummy_fe_qpsk_attach); + +static const struct dvb_frontend_ops dvb_dummy_fe_qam_ops; + +struct dvb_frontend *dvb_dummy_fe_qam_attach(void) +{ + struct dvb_dummy_fe_state *state = NULL; + + /* allocate memory for the internal state */ + state = kzalloc(sizeof(struct dvb_dummy_fe_state), GFP_KERNEL); + if (!state) + return NULL; + + /* create dvb_frontend */ + memcpy(&state->frontend.ops, + &dvb_dummy_fe_qam_ops, + sizeof(struct dvb_frontend_ops)); + + state->frontend.demodulator_priv = state; + return &state->frontend; +} +EXPORT_SYMBOL(dvb_dummy_fe_qam_attach); + +static const struct dvb_frontend_ops dvb_dummy_fe_ofdm_ops = { + .delsys = { SYS_DVBT }, + .info = { + .name = "Dummy DVB-T", + .frequency_min_hz = 0, + .frequency_max_hz = 863250 * kHz, + .frequency_stepsize_hz = 62500, + .caps = FE_CAN_FEC_1_2 | + FE_CAN_FEC_2_3 | + FE_CAN_FEC_3_4 | + FE_CAN_FEC_4_5 | + FE_CAN_FEC_5_6 | + FE_CAN_FEC_6_7 | + FE_CAN_FEC_7_8 | + FE_CAN_FEC_8_9 | + FE_CAN_FEC_AUTO | + FE_CAN_QAM_16 | + FE_CAN_QAM_64 | + FE_CAN_QAM_AUTO | + FE_CAN_TRANSMISSION_MODE_AUTO | + FE_CAN_GUARD_INTERVAL_AUTO | + FE_CAN_HIERARCHY_AUTO, + }, + + .release = dvb_dummy_fe_release, + + .init = dvb_dummy_fe_init, + .sleep = dvb_dummy_fe_sleep, + + .set_frontend = dvb_dummy_fe_set_frontend, + .get_frontend = dvb_dummy_fe_get_frontend, + + .read_status = dvb_dummy_fe_read_status, + .read_ber = dvb_dummy_fe_read_ber, + .read_signal_strength = dvb_dummy_fe_read_signal_strength, + .read_snr = dvb_dummy_fe_read_snr, + .read_ucblocks = dvb_dummy_fe_read_ucblocks, +}; + +static const struct dvb_frontend_ops dvb_dummy_fe_qam_ops = { + .delsys = { SYS_DVBC_ANNEX_A }, + .info = { + .name = "Dummy DVB-C", + .frequency_min_hz = 51 * MHz, + .frequency_max_hz = 858 * MHz, + .frequency_stepsize_hz = 62500, + /* symbol_rate_min: SACLK/64 == (XIN/2)/64 */ + .symbol_rate_min = (57840000 / 2) / 64, + .symbol_rate_max = (57840000 / 2) / 4, /* SACLK/4 */ + .caps = FE_CAN_QAM_16 | + FE_CAN_QAM_32 | + FE_CAN_QAM_64 | + FE_CAN_QAM_128 | + FE_CAN_QAM_256 | + FE_CAN_FEC_AUTO | + FE_CAN_INVERSION_AUTO + }, + + .release = dvb_dummy_fe_release, + + .init = dvb_dummy_fe_init, + .sleep = dvb_dummy_fe_sleep, + + .set_frontend = dvb_dummy_fe_set_frontend, + .get_frontend = dvb_dummy_fe_get_frontend, + + .read_status = dvb_dummy_fe_read_status, + .read_ber = dvb_dummy_fe_read_ber, + .read_signal_strength = dvb_dummy_fe_read_signal_strength, + .read_snr = dvb_dummy_fe_read_snr, + .read_ucblocks = dvb_dummy_fe_read_ucblocks, +}; + +static const struct dvb_frontend_ops dvb_dummy_fe_qpsk_ops = { + .delsys = { SYS_DVBS }, + .info = { + .name = "Dummy DVB-S", + .frequency_min_hz = 950 * MHz, + .frequency_max_hz = 2150 * MHz, + .frequency_stepsize_hz = 250 * kHz, + .frequency_tolerance_hz = 29500 * kHz, + .symbol_rate_min = 1000000, + .symbol_rate_max = 45000000, + .caps = FE_CAN_INVERSION_AUTO | + FE_CAN_FEC_1_2 | + FE_CAN_FEC_2_3 | + FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | + FE_CAN_FEC_7_8 | + FE_CAN_FEC_AUTO | + FE_CAN_QPSK + }, + + .release = dvb_dummy_fe_release, + + .init = dvb_dummy_fe_init, + .sleep = dvb_dummy_fe_sleep, + + .set_frontend = dvb_dummy_fe_set_frontend, + .get_frontend = dvb_dummy_fe_get_frontend, + + .read_status = dvb_dummy_fe_read_status, + .read_ber = dvb_dummy_fe_read_ber, + .read_signal_strength = dvb_dummy_fe_read_signal_strength, + .read_snr = dvb_dummy_fe_read_snr, + .read_ucblocks = dvb_dummy_fe_read_ucblocks, + + .set_voltage = dvb_dummy_fe_set_voltage, + .set_tone = dvb_dummy_fe_set_tone, +}; + +MODULE_DESCRIPTION("DVB DUMMY Frontend"); +MODULE_AUTHOR("Emard"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/pci/ddbridge/ddbridge-dummy-fe.h b/drivers/media/pci/ddbridge/ddbridge-dummy-fe.h new file mode 100644 index 000000000000..463abf5ebd56 --- /dev/null +++ b/drivers/media/pci/ddbridge/ddbridge-dummy-fe.h @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Driver for Dummy Frontend + * + * Written by Emard + */ + +#ifndef DVB_DUMMY_FE_H +#define DVB_DUMMY_FE_H + +#include +#include + +#if IS_REACHABLE(CONFIG_DVB_DUMMY_FE) +struct dvb_frontend *dvb_dummy_fe_ofdm_attach(void); +struct dvb_frontend *dvb_dummy_fe_qpsk_attach(void); +struct dvb_frontend *dvb_dummy_fe_qam_attach(void); +#else +static inline struct dvb_frontend *dvb_dummy_fe_ofdm_attach(void) +{ + pr_warn("%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +static inline struct dvb_frontend *dvb_dummy_fe_qpsk_attach(void) +{ + pr_warn("%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +static inline struct dvb_frontend *dvb_dummy_fe_qam_attach(void) +{ + pr_warn("%s: driver disabled by Kconfig\n", __func__); + return NULL; +} +#endif /* CONFIG_DVB_DUMMY_FE */ + +#endif // DVB_DUMMY_FE_H -- cgit v1.2.3 From 94ab24a2c886620fd3d0c0241d98b6c448cc8b38 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 26 Mar 2020 15:08:59 +0100 Subject: media: ddbridge-dummy_fe: do some vars and function renames As the name of this driver is now ddbridge-dummy, do some renames internally. No functional changes. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/ddbridge/ddbridge-dummy-fe.c | 144 ++++++++++++------------- drivers/media/pci/ddbridge/ddbridge-dummy-fe.h | 22 ++-- 2 files changed, 83 insertions(+), 83 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/ddbridge/ddbridge-dummy-fe.c b/drivers/media/pci/ddbridge/ddbridge-dummy-fe.c index 9ff1ebaa5e04..ebf4d9c30a55 100644 --- a/drivers/media/pci/ddbridge/ddbridge-dummy-fe.c +++ b/drivers/media/pci/ddbridge/ddbridge-dummy-fe.c @@ -11,15 +11,15 @@ #include #include -#include "dvb_dummy_fe.h" +#include "ddbridge-dummy-fe.h" -struct dvb_dummy_fe_state { +struct ddbridge_dummy_fe_state { struct dvb_frontend frontend; }; -static int dvb_dummy_fe_read_status(struct dvb_frontend *fe, +static int ddbridge_dummy_fe_read_status(struct dvb_frontend *fe, enum fe_status *status) { *status = FE_HAS_SIGNAL @@ -31,26 +31,26 @@ static int dvb_dummy_fe_read_status(struct dvb_frontend *fe, return 0; } -static int dvb_dummy_fe_read_ber(struct dvb_frontend *fe, u32 *ber) +static int ddbridge_dummy_fe_read_ber(struct dvb_frontend *fe, u32 *ber) { *ber = 0; return 0; } -static int dvb_dummy_fe_read_signal_strength(struct dvb_frontend *fe, +static int ddbridge_dummy_fe_read_signal_strength(struct dvb_frontend *fe, u16 *strength) { *strength = 0; return 0; } -static int dvb_dummy_fe_read_snr(struct dvb_frontend *fe, u16 *snr) +static int ddbridge_dummy_fe_read_snr(struct dvb_frontend *fe, u16 *snr) { *snr = 0; return 0; } -static int dvb_dummy_fe_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) +static int ddbridge_dummy_fe_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) { *ucblocks = 0; return 0; @@ -61,13 +61,13 @@ static int dvb_dummy_fe_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) * Also, it should check for the locks, in order to avoid report wrong data * to userspace. */ -static int dvb_dummy_fe_get_frontend(struct dvb_frontend *fe, +static int ddbridge_dummy_fe_get_frontend(struct dvb_frontend *fe, struct dtv_frontend_properties *p) { return 0; } -static int dvb_dummy_fe_set_frontend(struct dvb_frontend *fe) +static int ddbridge_dummy_fe_set_frontend(struct dvb_frontend *fe) { if (fe->ops.tuner_ops.set_params) { fe->ops.tuner_ops.set_params(fe); @@ -78,102 +78,102 @@ static int dvb_dummy_fe_set_frontend(struct dvb_frontend *fe) return 0; } -static int dvb_dummy_fe_sleep(struct dvb_frontend *fe) +static int ddbridge_dummy_fe_sleep(struct dvb_frontend *fe) { return 0; } -static int dvb_dummy_fe_init(struct dvb_frontend *fe) +static int ddbridge_dummy_fe_init(struct dvb_frontend *fe) { return 0; } -static int dvb_dummy_fe_set_tone(struct dvb_frontend *fe, +static int ddbridge_dummy_fe_set_tone(struct dvb_frontend *fe, enum fe_sec_tone_mode tone) { return 0; } -static int dvb_dummy_fe_set_voltage(struct dvb_frontend *fe, +static int ddbridge_dummy_fe_set_voltage(struct dvb_frontend *fe, enum fe_sec_voltage voltage) { return 0; } -static void dvb_dummy_fe_release(struct dvb_frontend *fe) +static void ddbridge_dummy_fe_release(struct dvb_frontend *fe) { - struct dvb_dummy_fe_state *state = fe->demodulator_priv; + struct ddbridge_dummy_fe_state *state = fe->demodulator_priv; kfree(state); } -static const struct dvb_frontend_ops dvb_dummy_fe_ofdm_ops; +static const struct dvb_frontend_ops ddbridge_dummy_fe_ofdm_ops; -struct dvb_frontend *dvb_dummy_fe_ofdm_attach(void) +struct dvb_frontend *ddbridge_dummy_fe_ofdm_attach(void) { - struct dvb_dummy_fe_state *state = NULL; + struct ddbridge_dummy_fe_state *state = NULL; /* allocate memory for the internal state */ - state = kzalloc(sizeof(struct dvb_dummy_fe_state), GFP_KERNEL); + state = kzalloc(sizeof(struct ddbridge_dummy_fe_state), GFP_KERNEL); if (!state) return NULL; /* create dvb_frontend */ memcpy(&state->frontend.ops, - &dvb_dummy_fe_ofdm_ops, + &ddbridge_dummy_fe_ofdm_ops, sizeof(struct dvb_frontend_ops)); state->frontend.demodulator_priv = state; return &state->frontend; } -EXPORT_SYMBOL(dvb_dummy_fe_ofdm_attach); +EXPORT_SYMBOL(ddbridge_dummy_fe_ofdm_attach); -static const struct dvb_frontend_ops dvb_dummy_fe_qpsk_ops; +static const struct dvb_frontend_ops ddbridge_dummy_fe_qpsk_ops; -struct dvb_frontend *dvb_dummy_fe_qpsk_attach(void) +struct dvb_frontend *ddbridge_dummy_fe_qpsk_attach(void) { - struct dvb_dummy_fe_state *state = NULL; + struct ddbridge_dummy_fe_state *state = NULL; /* allocate memory for the internal state */ - state = kzalloc(sizeof(struct dvb_dummy_fe_state), GFP_KERNEL); + state = kzalloc(sizeof(struct ddbridge_dummy_fe_state), GFP_KERNEL); if (!state) return NULL; /* create dvb_frontend */ memcpy(&state->frontend.ops, - &dvb_dummy_fe_qpsk_ops, + &ddbridge_dummy_fe_qpsk_ops, sizeof(struct dvb_frontend_ops)); state->frontend.demodulator_priv = state; return &state->frontend; } -EXPORT_SYMBOL(dvb_dummy_fe_qpsk_attach); +EXPORT_SYMBOL(ddbridge_dummy_fe_qpsk_attach); -static const struct dvb_frontend_ops dvb_dummy_fe_qam_ops; +static const struct dvb_frontend_ops ddbridge_dummy_fe_qam_ops; -struct dvb_frontend *dvb_dummy_fe_qam_attach(void) +struct dvb_frontend *ddbridge_dummy_fe_qam_attach(void) { - struct dvb_dummy_fe_state *state = NULL; + struct ddbridge_dummy_fe_state *state = NULL; /* allocate memory for the internal state */ - state = kzalloc(sizeof(struct dvb_dummy_fe_state), GFP_KERNEL); + state = kzalloc(sizeof(struct ddbridge_dummy_fe_state), GFP_KERNEL); if (!state) return NULL; /* create dvb_frontend */ memcpy(&state->frontend.ops, - &dvb_dummy_fe_qam_ops, + &ddbridge_dummy_fe_qam_ops, sizeof(struct dvb_frontend_ops)); state->frontend.demodulator_priv = state; return &state->frontend; } -EXPORT_SYMBOL(dvb_dummy_fe_qam_attach); +EXPORT_SYMBOL(ddbridge_dummy_fe_qam_attach); -static const struct dvb_frontend_ops dvb_dummy_fe_ofdm_ops = { +static const struct dvb_frontend_ops ddbridge_dummy_fe_ofdm_ops = { .delsys = { SYS_DVBT }, .info = { - .name = "Dummy DVB-T", + .name = "ddbridge dummy DVB-T", .frequency_min_hz = 0, .frequency_max_hz = 863250 * kHz, .frequency_stepsize_hz = 62500, @@ -194,25 +194,25 @@ static const struct dvb_frontend_ops dvb_dummy_fe_ofdm_ops = { FE_CAN_HIERARCHY_AUTO, }, - .release = dvb_dummy_fe_release, + .release = ddbridge_dummy_fe_release, - .init = dvb_dummy_fe_init, - .sleep = dvb_dummy_fe_sleep, + .init = ddbridge_dummy_fe_init, + .sleep = ddbridge_dummy_fe_sleep, - .set_frontend = dvb_dummy_fe_set_frontend, - .get_frontend = dvb_dummy_fe_get_frontend, + .set_frontend = ddbridge_dummy_fe_set_frontend, + .get_frontend = ddbridge_dummy_fe_get_frontend, - .read_status = dvb_dummy_fe_read_status, - .read_ber = dvb_dummy_fe_read_ber, - .read_signal_strength = dvb_dummy_fe_read_signal_strength, - .read_snr = dvb_dummy_fe_read_snr, - .read_ucblocks = dvb_dummy_fe_read_ucblocks, + .read_status = ddbridge_dummy_fe_read_status, + .read_ber = ddbridge_dummy_fe_read_ber, + .read_signal_strength = ddbridge_dummy_fe_read_signal_strength, + .read_snr = ddbridge_dummy_fe_read_snr, + .read_ucblocks = ddbridge_dummy_fe_read_ucblocks, }; -static const struct dvb_frontend_ops dvb_dummy_fe_qam_ops = { +static const struct dvb_frontend_ops ddbridge_dummy_fe_qam_ops = { .delsys = { SYS_DVBC_ANNEX_A }, .info = { - .name = "Dummy DVB-C", + .name = "ddbridge dummy DVB-C", .frequency_min_hz = 51 * MHz, .frequency_max_hz = 858 * MHz, .frequency_stepsize_hz = 62500, @@ -228,25 +228,25 @@ static const struct dvb_frontend_ops dvb_dummy_fe_qam_ops = { FE_CAN_INVERSION_AUTO }, - .release = dvb_dummy_fe_release, + .release = ddbridge_dummy_fe_release, - .init = dvb_dummy_fe_init, - .sleep = dvb_dummy_fe_sleep, + .init = ddbridge_dummy_fe_init, + .sleep = ddbridge_dummy_fe_sleep, - .set_frontend = dvb_dummy_fe_set_frontend, - .get_frontend = dvb_dummy_fe_get_frontend, + .set_frontend = ddbridge_dummy_fe_set_frontend, + .get_frontend = ddbridge_dummy_fe_get_frontend, - .read_status = dvb_dummy_fe_read_status, - .read_ber = dvb_dummy_fe_read_ber, - .read_signal_strength = dvb_dummy_fe_read_signal_strength, - .read_snr = dvb_dummy_fe_read_snr, - .read_ucblocks = dvb_dummy_fe_read_ucblocks, + .read_status = ddbridge_dummy_fe_read_status, + .read_ber = ddbridge_dummy_fe_read_ber, + .read_signal_strength = ddbridge_dummy_fe_read_signal_strength, + .read_snr = ddbridge_dummy_fe_read_snr, + .read_ucblocks = ddbridge_dummy_fe_read_ucblocks, }; -static const struct dvb_frontend_ops dvb_dummy_fe_qpsk_ops = { +static const struct dvb_frontend_ops ddbridge_dummy_fe_qpsk_ops = { .delsys = { SYS_DVBS }, .info = { - .name = "Dummy DVB-S", + .name = "ddbridge dummy DVB-S", .frequency_min_hz = 950 * MHz, .frequency_max_hz = 2150 * MHz, .frequency_stepsize_hz = 250 * kHz, @@ -263,24 +263,24 @@ static const struct dvb_frontend_ops dvb_dummy_fe_qpsk_ops = { FE_CAN_QPSK }, - .release = dvb_dummy_fe_release, + .release = ddbridge_dummy_fe_release, - .init = dvb_dummy_fe_init, - .sleep = dvb_dummy_fe_sleep, + .init = ddbridge_dummy_fe_init, + .sleep = ddbridge_dummy_fe_sleep, - .set_frontend = dvb_dummy_fe_set_frontend, - .get_frontend = dvb_dummy_fe_get_frontend, + .set_frontend = ddbridge_dummy_fe_set_frontend, + .get_frontend = ddbridge_dummy_fe_get_frontend, - .read_status = dvb_dummy_fe_read_status, - .read_ber = dvb_dummy_fe_read_ber, - .read_signal_strength = dvb_dummy_fe_read_signal_strength, - .read_snr = dvb_dummy_fe_read_snr, - .read_ucblocks = dvb_dummy_fe_read_ucblocks, + .read_status = ddbridge_dummy_fe_read_status, + .read_ber = ddbridge_dummy_fe_read_ber, + .read_signal_strength = ddbridge_dummy_fe_read_signal_strength, + .read_snr = ddbridge_dummy_fe_read_snr, + .read_ucblocks = ddbridge_dummy_fe_read_ucblocks, - .set_voltage = dvb_dummy_fe_set_voltage, - .set_tone = dvb_dummy_fe_set_tone, + .set_voltage = ddbridge_dummy_fe_set_voltage, + .set_tone = ddbridge_dummy_fe_set_tone, }; -MODULE_DESCRIPTION("DVB DUMMY Frontend"); +MODULE_DESCRIPTION("ddbridge dummy Frontend"); MODULE_AUTHOR("Emard"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/pci/ddbridge/ddbridge-dummy-fe.h b/drivers/media/pci/ddbridge/ddbridge-dummy-fe.h index 463abf5ebd56..811c203539e2 100644 --- a/drivers/media/pci/ddbridge/ddbridge-dummy-fe.h +++ b/drivers/media/pci/ddbridge/ddbridge-dummy-fe.h @@ -5,32 +5,32 @@ * Written by Emard */ -#ifndef DVB_DUMMY_FE_H -#define DVB_DUMMY_FE_H +#ifndef DDBRIDGE_DUMMY_FE_H +#define DDBRIDGE_DUMMY_FE_H #include #include -#if IS_REACHABLE(CONFIG_DVB_DUMMY_FE) -struct dvb_frontend *dvb_dummy_fe_ofdm_attach(void); -struct dvb_frontend *dvb_dummy_fe_qpsk_attach(void); -struct dvb_frontend *dvb_dummy_fe_qam_attach(void); +#if IS_REACHABLE(CONFIG_DDBRIDGE_DUMMY_FE) +struct dvb_frontend *ddbridge_dummy_fe_ofdm_attach(void); +struct dvb_frontend *ddbridge_dummy_fe_qpsk_attach(void); +struct dvb_frontend *ddbridge_dummy_fe_qam_attach(void); #else -static inline struct dvb_frontend *dvb_dummy_fe_ofdm_attach(void) +static inline struct dvb_frontend *ddbridge_dummy_fe_ofdm_attach(void) { pr_warn("%s: driver disabled by Kconfig\n", __func__); return NULL; } -static inline struct dvb_frontend *dvb_dummy_fe_qpsk_attach(void) +static inline struct dvb_frontend *ddbridge_dummy_fe_qpsk_attach(void) { pr_warn("%s: driver disabled by Kconfig\n", __func__); return NULL; } -static inline struct dvb_frontend *dvb_dummy_fe_qam_attach(void) +static inline struct dvb_frontend *ddbridge_dummy_fe_qam_attach(void) { pr_warn("%s: driver disabled by Kconfig\n", __func__); return NULL; } -#endif /* CONFIG_DVB_DUMMY_FE */ +#endif /* CONFIG_DDBRIDGE_DUMMY_FE */ -#endif // DVB_DUMMY_FE_H +#endif // DDBRIDGE_DUMMY_FE_H -- cgit v1.2.3 From 9a33a27e7fe5b1aebf045829f92fd11562ad0ac7 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 26 Mar 2020 15:23:34 +0100 Subject: media: ddbridge: use the ddbridge's own dummy fe driver Cleanup the ddbridge's dummy driver by removing the parts that aren't needed by ddbridge, adding it to the building system and changing the binding at the driver to use the newer function name. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/ddbridge/Kconfig | 1 - drivers/media/pci/ddbridge/Makefile | 2 +- drivers/media/pci/ddbridge/ddbridge-core.c | 4 +- drivers/media/pci/ddbridge/ddbridge-dummy-fe.c | 133 ------------------------- drivers/media/pci/ddbridge/ddbridge-dummy-fe.h | 20 ---- 5 files changed, 3 insertions(+), 157 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/ddbridge/Kconfig b/drivers/media/pci/ddbridge/Kconfig index dab34fb85c09..169efd558e45 100644 --- a/drivers/media/pci/ddbridge/Kconfig +++ b/drivers/media/pci/ddbridge/Kconfig @@ -15,7 +15,6 @@ config DVB_DDBRIDGE select MEDIA_TUNER_TDA18212 if MEDIA_SUBDRV_AUTOSELECT select DVB_MXL5XX if MEDIA_SUBDRV_AUTOSELECT select DVB_CXD2099 if MEDIA_SUBDRV_AUTOSELECT - select DVB_DUMMY_FE if MEDIA_SUBDRV_AUTOSELECT help Support for cards with the Digital Devices PCI express bridge: - Octopus PCIe Bridge diff --git a/drivers/media/pci/ddbridge/Makefile b/drivers/media/pci/ddbridge/Makefile index 2b77c8d0eb2e..5e7eab81173b 100644 --- a/drivers/media/pci/ddbridge/Makefile +++ b/drivers/media/pci/ddbridge/Makefile @@ -7,7 +7,7 @@ ddbridge-objs := ddbridge-main.o ddbridge-core.o ddbridge-ci.o \ ddbridge-hw.o ddbridge-i2c.o ddbridge-max.o ddbridge-mci.o \ ddbridge-sx8.o -obj-$(CONFIG_DVB_DDBRIDGE) += ddbridge.o +obj-$(CONFIG_DVB_DDBRIDGE) += ddbridge.o ddbridge-dummy-fe.o ccflags-y += -I $(srctree)/drivers/media/dvb-frontends/ ccflags-y += -I $(srctree)/drivers/media/tuners/ diff --git a/drivers/media/pci/ddbridge/ddbridge-core.c b/drivers/media/pci/ddbridge/ddbridge-core.c index 7a2d19682fe3..7cabb9e9ffe2 100644 --- a/drivers/media/pci/ddbridge/ddbridge-core.c +++ b/drivers/media/pci/ddbridge/ddbridge-core.c @@ -50,7 +50,7 @@ #include "stv6111.h" #include "lnbh25.h" #include "cxd2099.h" -#include "dvb_dummy_fe.h" +#include "ddbridge-dummy-fe.h" /****************************************************************************/ @@ -1265,7 +1265,7 @@ static int demod_attach_dummy(struct ddb_input *input) struct ddb_dvb *dvb = &input->port->dvb[input->nr & 1]; struct device *dev = input->port->dev->dev; - dvb->fe = dvb_attach(dvb_dummy_fe_qam_attach); + dvb->fe = dvb_attach(ddbridge_dummy_fe_qam_attach); if (!dvb->fe) { dev_err(dev, "QAM dummy attach failed!\n"); return -ENODEV; diff --git a/drivers/media/pci/ddbridge/ddbridge-dummy-fe.c b/drivers/media/pci/ddbridge/ddbridge-dummy-fe.c index ebf4d9c30a55..6868a0c4fc82 100644 --- a/drivers/media/pci/ddbridge/ddbridge-dummy-fe.c +++ b/drivers/media/pci/ddbridge/ddbridge-dummy-fe.c @@ -13,12 +13,10 @@ #include #include "ddbridge-dummy-fe.h" - struct ddbridge_dummy_fe_state { struct dvb_frontend frontend; }; - static int ddbridge_dummy_fe_read_status(struct dvb_frontend *fe, enum fe_status *status) { @@ -88,18 +86,6 @@ static int ddbridge_dummy_fe_init(struct dvb_frontend *fe) return 0; } -static int ddbridge_dummy_fe_set_tone(struct dvb_frontend *fe, - enum fe_sec_tone_mode tone) -{ - return 0; -} - -static int ddbridge_dummy_fe_set_voltage(struct dvb_frontend *fe, - enum fe_sec_voltage voltage) -{ - return 0; -} - static void ddbridge_dummy_fe_release(struct dvb_frontend *fe) { struct ddbridge_dummy_fe_state *state = fe->demodulator_priv; @@ -107,48 +93,6 @@ static void ddbridge_dummy_fe_release(struct dvb_frontend *fe) kfree(state); } -static const struct dvb_frontend_ops ddbridge_dummy_fe_ofdm_ops; - -struct dvb_frontend *ddbridge_dummy_fe_ofdm_attach(void) -{ - struct ddbridge_dummy_fe_state *state = NULL; - - /* allocate memory for the internal state */ - state = kzalloc(sizeof(struct ddbridge_dummy_fe_state), GFP_KERNEL); - if (!state) - return NULL; - - /* create dvb_frontend */ - memcpy(&state->frontend.ops, - &ddbridge_dummy_fe_ofdm_ops, - sizeof(struct dvb_frontend_ops)); - - state->frontend.demodulator_priv = state; - return &state->frontend; -} -EXPORT_SYMBOL(ddbridge_dummy_fe_ofdm_attach); - -static const struct dvb_frontend_ops ddbridge_dummy_fe_qpsk_ops; - -struct dvb_frontend *ddbridge_dummy_fe_qpsk_attach(void) -{ - struct ddbridge_dummy_fe_state *state = NULL; - - /* allocate memory for the internal state */ - state = kzalloc(sizeof(struct ddbridge_dummy_fe_state), GFP_KERNEL); - if (!state) - return NULL; - - /* create dvb_frontend */ - memcpy(&state->frontend.ops, - &ddbridge_dummy_fe_qpsk_ops, - sizeof(struct dvb_frontend_ops)); - - state->frontend.demodulator_priv = state; - return &state->frontend; -} -EXPORT_SYMBOL(ddbridge_dummy_fe_qpsk_attach); - static const struct dvb_frontend_ops ddbridge_dummy_fe_qam_ops; struct dvb_frontend *ddbridge_dummy_fe_qam_attach(void) @@ -170,45 +114,6 @@ struct dvb_frontend *ddbridge_dummy_fe_qam_attach(void) } EXPORT_SYMBOL(ddbridge_dummy_fe_qam_attach); -static const struct dvb_frontend_ops ddbridge_dummy_fe_ofdm_ops = { - .delsys = { SYS_DVBT }, - .info = { - .name = "ddbridge dummy DVB-T", - .frequency_min_hz = 0, - .frequency_max_hz = 863250 * kHz, - .frequency_stepsize_hz = 62500, - .caps = FE_CAN_FEC_1_2 | - FE_CAN_FEC_2_3 | - FE_CAN_FEC_3_4 | - FE_CAN_FEC_4_5 | - FE_CAN_FEC_5_6 | - FE_CAN_FEC_6_7 | - FE_CAN_FEC_7_8 | - FE_CAN_FEC_8_9 | - FE_CAN_FEC_AUTO | - FE_CAN_QAM_16 | - FE_CAN_QAM_64 | - FE_CAN_QAM_AUTO | - FE_CAN_TRANSMISSION_MODE_AUTO | - FE_CAN_GUARD_INTERVAL_AUTO | - FE_CAN_HIERARCHY_AUTO, - }, - - .release = ddbridge_dummy_fe_release, - - .init = ddbridge_dummy_fe_init, - .sleep = ddbridge_dummy_fe_sleep, - - .set_frontend = ddbridge_dummy_fe_set_frontend, - .get_frontend = ddbridge_dummy_fe_get_frontend, - - .read_status = ddbridge_dummy_fe_read_status, - .read_ber = ddbridge_dummy_fe_read_ber, - .read_signal_strength = ddbridge_dummy_fe_read_signal_strength, - .read_snr = ddbridge_dummy_fe_read_snr, - .read_ucblocks = ddbridge_dummy_fe_read_ucblocks, -}; - static const struct dvb_frontend_ops ddbridge_dummy_fe_qam_ops = { .delsys = { SYS_DVBC_ANNEX_A }, .info = { @@ -243,44 +148,6 @@ static const struct dvb_frontend_ops ddbridge_dummy_fe_qam_ops = { .read_ucblocks = ddbridge_dummy_fe_read_ucblocks, }; -static const struct dvb_frontend_ops ddbridge_dummy_fe_qpsk_ops = { - .delsys = { SYS_DVBS }, - .info = { - .name = "ddbridge dummy DVB-S", - .frequency_min_hz = 950 * MHz, - .frequency_max_hz = 2150 * MHz, - .frequency_stepsize_hz = 250 * kHz, - .frequency_tolerance_hz = 29500 * kHz, - .symbol_rate_min = 1000000, - .symbol_rate_max = 45000000, - .caps = FE_CAN_INVERSION_AUTO | - FE_CAN_FEC_1_2 | - FE_CAN_FEC_2_3 | - FE_CAN_FEC_3_4 | - FE_CAN_FEC_5_6 | - FE_CAN_FEC_7_8 | - FE_CAN_FEC_AUTO | - FE_CAN_QPSK - }, - - .release = ddbridge_dummy_fe_release, - - .init = ddbridge_dummy_fe_init, - .sleep = ddbridge_dummy_fe_sleep, - - .set_frontend = ddbridge_dummy_fe_set_frontend, - .get_frontend = ddbridge_dummy_fe_get_frontend, - - .read_status = ddbridge_dummy_fe_read_status, - .read_ber = ddbridge_dummy_fe_read_ber, - .read_signal_strength = ddbridge_dummy_fe_read_signal_strength, - .read_snr = ddbridge_dummy_fe_read_snr, - .read_ucblocks = ddbridge_dummy_fe_read_ucblocks, - - .set_voltage = ddbridge_dummy_fe_set_voltage, - .set_tone = ddbridge_dummy_fe_set_tone, -}; - MODULE_DESCRIPTION("ddbridge dummy Frontend"); MODULE_AUTHOR("Emard"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/pci/ddbridge/ddbridge-dummy-fe.h b/drivers/media/pci/ddbridge/ddbridge-dummy-fe.h index 811c203539e2..ddf189c09524 100644 --- a/drivers/media/pci/ddbridge/ddbridge-dummy-fe.h +++ b/drivers/media/pci/ddbridge/ddbridge-dummy-fe.h @@ -11,26 +11,6 @@ #include #include -#if IS_REACHABLE(CONFIG_DDBRIDGE_DUMMY_FE) -struct dvb_frontend *ddbridge_dummy_fe_ofdm_attach(void); -struct dvb_frontend *ddbridge_dummy_fe_qpsk_attach(void); struct dvb_frontend *ddbridge_dummy_fe_qam_attach(void); -#else -static inline struct dvb_frontend *ddbridge_dummy_fe_ofdm_attach(void) -{ - pr_warn("%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -static inline struct dvb_frontend *ddbridge_dummy_fe_qpsk_attach(void) -{ - pr_warn("%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -static inline struct dvb_frontend *ddbridge_dummy_fe_qam_attach(void) -{ - pr_warn("%s: driver disabled by Kconfig\n", __func__); - return NULL; -} -#endif /* CONFIG_DDBRIDGE_DUMMY_FE */ #endif // DDBRIDGE_DUMMY_FE_H -- cgit v1.2.3 From 97b19498dc0250826f6c9f4921b1e4c553cb086c Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 26 Mar 2020 09:45:31 +0100 Subject: media: Kconfig: mark other drivers as test drivers Neither the PCI skeleton nor the DVB dummy driver are real drivers. They're there just as an example for a driver writter. Distros should not enable those drivers. So, hide them if MEDIA_TEST_SUPPORT is not selected. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/Kconfig | 4 ++++ drivers/media/pci/Kconfig | 1 + 2 files changed, 5 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig index a29e9ddf9c82..932fd88fdc12 100644 --- a/drivers/media/dvb-frontends/Kconfig +++ b/drivers/media/dvb-frontends/Kconfig @@ -944,8 +944,12 @@ config DVB_SP2 CIMaX SP2/SP2HF Common Interface module. comment "Tools to develop new frontends" + depends on MEDIA_TEST_SUPPORT config DVB_DUMMY_FE tristate "Dummy frontend driver" depends on DVB_CORE + depends on MEDIA_TEST_SUPPORT + help + Dummy skeleton frontend driver. endmenu diff --git a/drivers/media/pci/Kconfig b/drivers/media/pci/Kconfig index 9336f8446cf0..e576283ebbf5 100644 --- a/drivers/media/pci/Kconfig +++ b/drivers/media/pci/Kconfig @@ -58,6 +58,7 @@ source "drivers/media/pci/intel/ipu3/Kconfig" config VIDEO_PCI_SKELETON tristate "Skeleton PCI V4L2 driver" + depends on MEDIA_TEST_SUPPORT depends on PCI depends on SAMPLES depends on VIDEO_V4L2 && VIDEOBUF2_CORE -- cgit v1.2.3 From a832862295e0e604949e49f286ed368d5dfc2e3b Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 25 Mar 2020 09:59:18 +0100 Subject: media: Kconfig: simplify some dependencies both DVB_CORE and VIDEO_DEV already depends on MEDIA_SUPPORT, as they're below an if block. So, remove this double dependency. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/Kconfig | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index dc0cc42d48ad..f6763d02f1be 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -125,7 +125,6 @@ source "drivers/media/mc/Kconfig" config VIDEO_DEV tristate - depends on MEDIA_SUPPORT default MEDIA_CAMERA_SUPPORT || MEDIA_ANALOG_TV_SUPPORT || MEDIA_RADIO_SUPPORT || MEDIA_SDR_SUPPORT || MEDIA_PLATFORM_SUPPORT config VIDEO_V4L2_SUBDEV_API @@ -146,7 +145,6 @@ source "drivers/media/v4l2-core/Kconfig" config DVB_CORE tristate - depends on MEDIA_SUPPORT depends on MEDIA_DIGITAL_TV_SUPPORT depends on (I2C || I2C=n) default y -- cgit v1.2.3 From a3b91d8bd1e034c8ed89d3f55243478af97a0a52 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 25 Mar 2020 08:36:36 +0100 Subject: media: Kconfig: better support hybrid TV devices Right now, if one has an hybrid TV card, it has to select both analog and digital TV support, as otherwise the needed core support won't be selected. Change the logic to auto-select the core support for those drivers, as this is a way more intuitive. It should be noticed that, as now both DVB_CORE and VIDEO_DEV defaults depends on selecting a hybrid cards, we had to remove the explicit dependencies there, in order to avoid circular dependencies. That requires some tricks: 1) the prompt should not be not visible when an hybrid card is selected, as the user shold not change it. 2) When a media hybrid device is selected, the modular option for DVB_CORE and VIDEO_DEV will follow the MEDIA_SUPPORT dependency, as we can't have a core built with "y" with a driver built as module. Note: while here, moved two pure V4L2 PCI drivers out of the "hybrid" part of config and consider pvrusb2 as an hybrid device. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/Kconfig | 24 +++++++++++------------- drivers/media/pci/Kconfig | 11 +++++++++-- drivers/media/pci/bt8xx/Kconfig | 5 ++--- drivers/media/pci/cx18/Kconfig | 2 +- drivers/media/pci/cx23885/Kconfig | 4 ++-- drivers/media/pci/cx88/Kconfig | 4 ++-- drivers/media/pci/saa7134/Kconfig | 4 ++-- drivers/media/pci/saa7164/Kconfig | 2 +- drivers/media/platform/Kconfig | 2 +- drivers/media/usb/Kconfig | 8 +++++++- drivers/media/usb/au0828/Kconfig | 6 ++---- drivers/media/usb/cx231xx/Kconfig | 4 ++-- drivers/media/usb/pvrusb2/Kconfig | 4 ++-- drivers/media/usb/tm6000/Kconfig | 4 ++-- 14 files changed, 46 insertions(+), 38 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index f6763d02f1be..f400370b2928 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -44,20 +44,14 @@ config MEDIA_ANALOG_TV_SUPPORT help Enable analog TV support. - Say Y when you have a TV board with analog support or with a - hybrid analog/digital TV chipset. - - Note: There are several DVB cards that are based on chips that - support both analog and digital TV. Disabling this option - will disable support for them. + Say Y when you have a board with analog TV support. config MEDIA_DIGITAL_TV_SUPPORT bool "Digital TV support" help Enable digital TV support. - Say Y when you have a board with digital support or a board with - hybrid digital TV and analog TV. + Say Y when you have a board with digital TV support. config MEDIA_RADIO_SUPPORT bool "AM/FM radio receivers/transmitters support" @@ -69,10 +63,6 @@ config MEDIA_RADIO_SUPPORT Say Y when you have a board with radio support. - Note: There are several TV cards that are based on chips that - support radio reception. Disabling this option will - disable support for them. - config MEDIA_SDR_SUPPORT bool "Software defined radio support" help @@ -123,9 +113,13 @@ source "drivers/media/mc/Kconfig" # Only enables if one of the V4L2 types (ATV, webcam, radio) is selected # +comment "Video4Linux core enabled to support hybrid TV devices" + depends on MEDIA_HYBRID_USB || MEDIA_HYBRID_PCI + config VIDEO_DEV tristate - default MEDIA_CAMERA_SUPPORT || MEDIA_ANALOG_TV_SUPPORT || MEDIA_RADIO_SUPPORT || MEDIA_SDR_SUPPORT || MEDIA_PLATFORM_SUPPORT + prompt "Video4Linux core" if !(MEDIA_HYBRID_USB || MEDIA_HYBRID_PCI) + default MEDIA_CAMERA_SUPPORT || MEDIA_ANALOG_TV_SUPPORT || MEDIA_RADIO_SUPPORT || MEDIA_SDR_SUPPORT || MEDIA_PLATFORM_SUPPORT || MEDIA_HYBRID_USB || MEDIA_HYBRID_PCI config VIDEO_V4L2_SUBDEV_API bool "V4L2 sub-device userspace API" @@ -143,8 +137,12 @@ source "drivers/media/v4l2-core/Kconfig" # Only enables if one of DTV is selected # +comment "Digital TV core enabled to support hybrid TV devices" + depends on MEDIA_HYBRID_USB || MEDIA_HYBRID_PCI + config DVB_CORE tristate + prompt "Digital TV core" if !(MEDIA_HYBRID_USB || MEDIA_HYBRID_PCI) depends on MEDIA_DIGITAL_TV_SUPPORT depends on (I2C || I2C=n) default y diff --git a/drivers/media/pci/Kconfig b/drivers/media/pci/Kconfig index e576283ebbf5..348da044ec78 100644 --- a/drivers/media/pci/Kconfig +++ b/drivers/media/pci/Kconfig @@ -1,4 +1,11 @@ # SPDX-License-Identifier: GPL-2.0-only + +# Should match the hybrid card list below +config MEDIA_HYBRID_PCI + bool + depends on VIDEO_CX18 || VIDEO_CX23885 || VIDEO_CX88 || VIDEO_BT848 || VIDEO_SAA7134 || VIDEO_SAA7164 + default y + if PCI && MEDIA_SUPPORT menuconfig MEDIA_PCI_SUPPORT @@ -24,18 +31,18 @@ if MEDIA_ANALOG_TV_SUPPORT source "drivers/media/pci/ivtv/Kconfig" source "drivers/media/pci/saa7146/Kconfig" source "drivers/media/pci/dt3155/Kconfig" +source "drivers/media/pci/cx25821/Kconfig" +source "drivers/media/pci/cobalt/Kconfig" endif if MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT comment "Media capture/analog/hybrid TV support" source "drivers/media/pci/cx18/Kconfig" source "drivers/media/pci/cx23885/Kconfig" -source "drivers/media/pci/cx25821/Kconfig" source "drivers/media/pci/cx88/Kconfig" source "drivers/media/pci/bt8xx/Kconfig" source "drivers/media/pci/saa7134/Kconfig" source "drivers/media/pci/saa7164/Kconfig" -source "drivers/media/pci/cobalt/Kconfig" endif diff --git a/drivers/media/pci/bt8xx/Kconfig b/drivers/media/pci/bt8xx/Kconfig index 75d172a6f54c..c79c6175c262 100644 --- a/drivers/media/pci/bt8xx/Kconfig +++ b/drivers/media/pci/bt8xx/Kconfig @@ -1,11 +1,10 @@ # SPDX-License-Identifier: GPL-2.0-only config VIDEO_BT848 tristate "BT848 Video For Linux" - depends on VIDEO_DEV && PCI && I2C && VIDEO_V4L2 + depends on PCI && I2C select I2C_ALGOBIT select VIDEOBUF_DMA_SG depends on RC_CORE - depends on MEDIA_RADIO_SUPPORT select VIDEO_TUNER select VIDEO_TVEEPROM select VIDEO_MSP3400 if MEDIA_SUBDRV_AUTOSELECT @@ -24,7 +23,7 @@ config VIDEO_BT848 config DVB_BT8XX tristate "DVB/ATSC Support for bt878 based TV cards" - depends on DVB_CORE && PCI && I2C && VIDEO_BT848 + depends on PCI && I2C && VIDEO_BT848 select DVB_MT352 if MEDIA_SUBDRV_AUTOSELECT select DVB_SP887X if MEDIA_SUBDRV_AUTOSELECT select DVB_NXT6000 if MEDIA_SUBDRV_AUTOSELECT diff --git a/drivers/media/pci/cx18/Kconfig b/drivers/media/pci/cx18/Kconfig index 7074a1071302..110e072bd8ba 100644 --- a/drivers/media/pci/cx18/Kconfig +++ b/drivers/media/pci/cx18/Kconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only config VIDEO_CX18 tristate "Conexant cx23418 MPEG encoder support" - depends on VIDEO_V4L2 && DVB_CORE && PCI && I2C + depends on PCI && I2C select I2C_ALGOBIT select VIDEOBUF_VMALLOC depends on RC_CORE diff --git a/drivers/media/pci/cx23885/Kconfig b/drivers/media/pci/cx23885/Kconfig index 926da881929d..e8f4edf270c8 100644 --- a/drivers/media/pci/cx23885/Kconfig +++ b/drivers/media/pci/cx23885/Kconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only config VIDEO_CX23885 tristate "Conexant cx23885 (2388x successor) support" - depends on DVB_CORE && VIDEO_DEV && PCI && I2C && INPUT && SND + depends on PCI && I2C && INPUT && SND select SND_PCM select I2C_ALGOBIT select VIDEO_TUNER @@ -53,7 +53,7 @@ config VIDEO_CX23885 config MEDIA_ALTERA_CI tristate "Altera FPGA based CI module" - depends on VIDEO_CX23885 && DVB_CORE + depends on VIDEO_CX23885 select ALTERA_STAPL help An Altera FPGA CI module for NetUP Dual DVB-T/C RF CI card. diff --git a/drivers/media/pci/cx88/Kconfig b/drivers/media/pci/cx88/Kconfig index 24e1e7c41744..ab994b3049f4 100644 --- a/drivers/media/pci/cx88/Kconfig +++ b/drivers/media/pci/cx88/Kconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only config VIDEO_CX88 tristate "Conexant 2388x (bt878 successor) support" - depends on VIDEO_DEV && PCI && I2C && RC_CORE + depends on PCI && I2C && RC_CORE select I2C_ALGOBIT select VIDEOBUF2_DMA_SG select VIDEO_TUNER @@ -44,7 +44,7 @@ config VIDEO_CX88_BLACKBIRD config VIDEO_CX88_DVB tristate "DVB/ATSC Support for cx2388x based TV cards" - depends on VIDEO_CX88 && DVB_CORE + depends on VIDEO_CX88 select VIDEOBUF2_DVB select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT select DVB_MT352 if MEDIA_SUBDRV_AUTOSELECT diff --git a/drivers/media/pci/saa7134/Kconfig b/drivers/media/pci/saa7134/Kconfig index 30c1759682a9..a2af02f6d593 100644 --- a/drivers/media/pci/saa7134/Kconfig +++ b/drivers/media/pci/saa7134/Kconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only config VIDEO_SAA7134 tristate "Philips SAA7134 support" - depends on VIDEO_DEV && PCI && I2C + depends on PCI && I2C select VIDEOBUF2_DMA_SG select VIDEO_TUNER select VIDEO_TVEEPROM @@ -37,7 +37,7 @@ config VIDEO_SAA7134_RC config VIDEO_SAA7134_DVB tristate "DVB/ATSC Support for saa7134 based TV cards" - depends on VIDEO_SAA7134 && DVB_CORE + depends on VIDEO_SAA7134 select VIDEOBUF2_DVB select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT select DVB_MT352 if MEDIA_SUBDRV_AUTOSELECT diff --git a/drivers/media/pci/saa7164/Kconfig b/drivers/media/pci/saa7164/Kconfig index 6655c3e504cd..8df933a722a7 100644 --- a/drivers/media/pci/saa7164/Kconfig +++ b/drivers/media/pci/saa7164/Kconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only config VIDEO_SAA7164 tristate "NXP SAA7164 support" - depends on DVB_CORE && VIDEO_DEV && PCI && I2C + depends on PCI && I2C select I2C_ALGOBIT select FW_LOADER select VIDEO_TUNER diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index 80028337bf00..6b693cd0576e 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -531,7 +531,7 @@ config VIDEO_TI_CSC menuconfig DVB_PLATFORM_DRIVERS bool "DVB platform devices" - depends on MEDIA_DIGITAL_TV_SUPPORT + select DVB_CORE help Say Y here to enable support for platform-specific Digital TV drivers. diff --git a/drivers/media/usb/Kconfig b/drivers/media/usb/Kconfig index bf08393e38d1..036aa4385fdc 100644 --- a/drivers/media/usb/Kconfig +++ b/drivers/media/usb/Kconfig @@ -5,6 +5,12 @@ config TTPCI_EEPROM tristate depends on I2C +# Should match the hybrid card list below +config MEDIA_HYBRID_USB + bool + depends on VIDEO_AU0828 || VIDEO_CX231XX || VIDEO_TM6000 || VIDEO_PVRUSB2 + default y + if USB && MEDIA_SUPPORT menuconfig MEDIA_USB_SUPPORT @@ -29,7 +35,6 @@ endif if MEDIA_ANALOG_TV_SUPPORT comment "Analog TV USB devices" -source "drivers/media/usb/pvrusb2/Kconfig" source "drivers/media/usb/hdpvr/Kconfig" source "drivers/media/usb/stk1160/Kconfig" source "drivers/media/usb/go7007/Kconfig" @@ -39,6 +44,7 @@ if (MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT) comment "Analog/digital TV USB devices" source "drivers/media/usb/au0828/Kconfig" source "drivers/media/usb/cx231xx/Kconfig" +source "drivers/media/usb/pvrusb2/Kconfig" source "drivers/media/usb/tm6000/Kconfig" endif diff --git a/drivers/media/usb/au0828/Kconfig b/drivers/media/usb/au0828/Kconfig index 05cc6c48c26f..2f5ee684a278 100644 --- a/drivers/media/usb/au0828/Kconfig +++ b/drivers/media/usb/au0828/Kconfig @@ -2,12 +2,12 @@ config VIDEO_AU0828 tristate "Auvitek AU0828 support" - depends on I2C && INPUT && DVB_CORE && USB && VIDEO_V4L2 + depends on I2C && INPUT && USB select MEDIA_CONTROLLER select MEDIA_CONTROLLER_DVB select I2C_ALGOBIT select VIDEO_TVEEPROM - select VIDEOBUF2_VMALLOC if VIDEO_V4L2 + select VIDEOBUF2_VMALLOC select DVB_AU8522_DTV if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_XC5000 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_MXL5007T if MEDIA_SUBDRV_AUTOSELECT @@ -22,8 +22,6 @@ config VIDEO_AU0828 config VIDEO_AU0828_V4L2 bool "Auvitek AU0828 v4l2 analog video support" depends on VIDEO_AU0828 - depends on VIDEO_V4L2=y || VIDEO_V4L2=VIDEO_AU0828 - select DVB_AU8522_V4L if MEDIA_SUBDRV_AUTOSELECT select VIDEO_TUNER default y help diff --git a/drivers/media/usb/cx231xx/Kconfig b/drivers/media/usb/cx231xx/Kconfig index 2fe2b2d335ba..7e3b189f9dca 100644 --- a/drivers/media/usb/cx231xx/Kconfig +++ b/drivers/media/usb/cx231xx/Kconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only config VIDEO_CX231XX tristate "Conexant cx231xx USB video capture support" - depends on VIDEO_DEV && I2C && I2C_MUX + depends on I2C && I2C_MUX select VIDEO_TUNER select VIDEO_TVEEPROM select VIDEOBUF2_VMALLOC @@ -40,7 +40,7 @@ config VIDEO_CX231XX_ALSA config VIDEO_CX231XX_DVB tristate "DVB/ATSC Support for Cx231xx based TV cards" - depends on VIDEO_CX231XX && DVB_CORE + depends on VIDEO_CX231XX select MEDIA_TUNER_XC5000 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_TDA18271 if MEDIA_SUBDRV_AUTOSELECT select DVB_MB86A20S if MEDIA_SUBDRV_AUTOSELECT diff --git a/drivers/media/usb/pvrusb2/Kconfig b/drivers/media/usb/pvrusb2/Kconfig index e6a4f730591b..5bf45f2b2517 100644 --- a/drivers/media/usb/pvrusb2/Kconfig +++ b/drivers/media/usb/pvrusb2/Kconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only config VIDEO_PVRUSB2 tristate "Hauppauge WinTV-PVR USB2 support" - depends on VIDEO_V4L2 && I2C + depends on I2C select VIDEO_TUNER select VIDEO_TVEEPROM select VIDEO_CX2341X @@ -36,7 +36,7 @@ config VIDEO_PVRUSB2_SYSFS config VIDEO_PVRUSB2_DVB bool "pvrusb2 ATSC/DVB support" default y - depends on VIDEO_PVRUSB2 && DVB_CORE + depends on VIDEO_PVRUSB2 select DVB_LGDT330X if MEDIA_SUBDRV_AUTOSELECT select DVB_S5H1409 if MEDIA_SUBDRV_AUTOSELECT select DVB_S5H1411 if MEDIA_SUBDRV_AUTOSELECT diff --git a/drivers/media/usb/tm6000/Kconfig b/drivers/media/usb/tm6000/Kconfig index 56e977deba81..ad9cfa855eac 100644 --- a/drivers/media/usb/tm6000/Kconfig +++ b/drivers/media/usb/tm6000/Kconfig @@ -1,7 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only config VIDEO_TM6000 tristate "TV Master TM5600/6000/6010 driver" - depends on VIDEO_DEV && I2C && INPUT && RC_CORE && USB + depends on I2C && INPUT && RC_CORE && USB select VIDEO_TUNER select MEDIA_TUNER_XC2028 select MEDIA_TUNER_XC5000 @@ -28,7 +28,7 @@ config VIDEO_TM6000_ALSA config VIDEO_TM6000_DVB tristate "DVB Support for tm6000 based TV cards" - depends on VIDEO_TM6000 && DVB_CORE && USB + depends on VIDEO_TM6000 && USB select DVB_ZL10353 help This adds support for DVB cards based on the tm5600/tm6000 chip. -- cgit v1.2.3 From 6268b351394450e9168a9281a9279f7cb420669f Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 26 Mar 2020 15:47:25 +0100 Subject: media: Kconfig: fix selection for test drivers There are some long-time mistakes related to build test drivers, with regards to depends on/select. Also, as we now want to build any test driver without needing to enable anything else, change the logic in order to properly filter them. Please notice that the PCI skeleton is somewhat an exception, as it requires to select *both* SAMPLES and MEDIA_TEST_SUPPORT. I almost changed it to be either one, but decided to keep it as-is, as this is something that we don't really need to be included on any distribution. The only reason for someone to build it is for COMPILE_TEST purposes. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/Kconfig | 2 +- drivers/media/dvb-frontends/Kconfig | 9 +++++++-- drivers/media/pci/Kconfig | 10 +++++----- drivers/media/test_drivers/Kconfig | 2 +- 4 files changed, 14 insertions(+), 9 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index f400370b2928..9c32616f863a 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -119,7 +119,7 @@ comment "Video4Linux core enabled to support hybrid TV devices" config VIDEO_DEV tristate prompt "Video4Linux core" if !(MEDIA_HYBRID_USB || MEDIA_HYBRID_PCI) - default MEDIA_CAMERA_SUPPORT || MEDIA_ANALOG_TV_SUPPORT || MEDIA_RADIO_SUPPORT || MEDIA_SDR_SUPPORT || MEDIA_PLATFORM_SUPPORT || MEDIA_HYBRID_USB || MEDIA_HYBRID_PCI + default MEDIA_CAMERA_SUPPORT || MEDIA_ANALOG_TV_SUPPORT || MEDIA_RADIO_SUPPORT || MEDIA_SDR_SUPPORT || MEDIA_PLATFORM_SUPPORT || MEDIA_TEST_SUPPORT || MEDIA_HYBRID_USB || MEDIA_HYBRID_PCI config VIDEO_V4L2_SUBDEV_API bool "V4L2 sub-device userspace API" diff --git a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig index 932fd88fdc12..1f45808d94da 100644 --- a/drivers/media/dvb-frontends/Kconfig +++ b/drivers/media/dvb-frontends/Kconfig @@ -1,3 +1,5 @@ +if MEDIA_DIGITAL_TV_SUPPORT + comment "DVB Frontend drivers hidden by 'Autoselect ancillary drivers'" depends on MEDIA_HIDE_ANCILLARY_SUBDRV @@ -943,13 +945,16 @@ config DVB_SP2 help CIMaX SP2/SP2HF Common Interface module. +endmenu # Customise DVB Frontends + +endif # MEDIA_DIGITAL_TV_SUPPORT + comment "Tools to develop new frontends" depends on MEDIA_TEST_SUPPORT config DVB_DUMMY_FE tristate "Dummy frontend driver" - depends on DVB_CORE depends on MEDIA_TEST_SUPPORT + select DVB_CORE help Dummy skeleton frontend driver. -endmenu diff --git a/drivers/media/pci/Kconfig b/drivers/media/pci/Kconfig index 348da044ec78..44f1efd21272 100644 --- a/drivers/media/pci/Kconfig +++ b/drivers/media/pci/Kconfig @@ -6,7 +6,7 @@ config MEDIA_HYBRID_PCI depends on VIDEO_CX18 || VIDEO_CX23885 || VIDEO_CX88 || VIDEO_BT848 || VIDEO_SAA7134 || VIDEO_SAA7164 default y -if PCI && MEDIA_SUPPORT +if PCI menuconfig MEDIA_PCI_SUPPORT bool "Media PCI Adapters" @@ -65,11 +65,11 @@ source "drivers/media/pci/intel/ipu3/Kconfig" config VIDEO_PCI_SKELETON tristate "Skeleton PCI V4L2 driver" - depends on MEDIA_TEST_SUPPORT - depends on PCI depends on SAMPLES - depends on VIDEO_V4L2 && VIDEOBUF2_CORE - depends on VIDEOBUF2_MEMOPS && VIDEOBUF2_DMA_CONTIG + depends on MEDIA_TEST_SUPPORT + depends on PCI && VIDEO_V4L2 + select VIDEOBUF2_MEMOPS + select VIDEOBUF2_DMA_CONTIG help Enable build of the skeleton PCI driver, used as a reference when developing new drivers. diff --git a/drivers/media/test_drivers/Kconfig b/drivers/media/test_drivers/Kconfig index 258a4d36c0d3..9f4a9cfbacc9 100644 --- a/drivers/media/test_drivers/Kconfig +++ b/drivers/media/test_drivers/Kconfig @@ -4,7 +4,7 @@ if MEDIA_TEST_SUPPORT menuconfig V4L_TEST_DRIVERS bool "V4L test drivers" - depends on MEDIA_CAMERA_SUPPORT + depends on VIDEO_DEV if V4L_TEST_DRIVERS -- cgit v1.2.3 From 76c34a8d0e53f98975a2da5f753a99b4abc05c44 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 26 Mar 2020 16:13:16 +0100 Subject: media: add SPDX headers on Kconfig and Makefile files Most of media Kconfig/Makefile files already has SPDX, but there are a few ones still missing. Add it to them. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/Kconfig | 2 ++ drivers/media/mc/Kconfig | 2 ++ drivers/media/platform/sunxi/Kconfig | 2 ++ drivers/media/platform/sunxi/Makefile | 2 ++ drivers/media/platform/sunxi/sun4i-csi/Kconfig | 2 ++ drivers/media/platform/sunxi/sun4i-csi/Makefile | 2 ++ drivers/staging/media/hantro/Makefile | 2 ++ drivers/staging/media/rkisp1/Makefile | 2 ++ 8 files changed, 16 insertions(+) (limited to 'drivers/media') diff --git a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig index 1f45808d94da..aa24506257b3 100644 --- a/drivers/media/dvb-frontends/Kconfig +++ b/drivers/media/dvb-frontends/Kconfig @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0 + if MEDIA_DIGITAL_TV_SUPPORT comment "DVB Frontend drivers hidden by 'Autoselect ancillary drivers'" diff --git a/drivers/media/mc/Kconfig b/drivers/media/mc/Kconfig index 3b9795cfcb36..0c5c52f14c64 100644 --- a/drivers/media/mc/Kconfig +++ b/drivers/media/mc/Kconfig @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0 + # # Media controller # Selectable only for webcam/grabbers, as other drivers don't use it diff --git a/drivers/media/platform/sunxi/Kconfig b/drivers/media/platform/sunxi/Kconfig index 71808e93ac2e..7151cc249afa 100644 --- a/drivers/media/platform/sunxi/Kconfig +++ b/drivers/media/platform/sunxi/Kconfig @@ -1,2 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 + source "drivers/media/platform/sunxi/sun4i-csi/Kconfig" source "drivers/media/platform/sunxi/sun6i-csi/Kconfig" diff --git a/drivers/media/platform/sunxi/Makefile b/drivers/media/platform/sunxi/Makefile index ff0993f70dc3..fc537c9f5ca9 100644 --- a/drivers/media/platform/sunxi/Makefile +++ b/drivers/media/platform/sunxi/Makefile @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0 + obj-y += sun4i-csi/ obj-y += sun6i-csi/ obj-y += sun8i-di/ diff --git a/drivers/media/platform/sunxi/sun4i-csi/Kconfig b/drivers/media/platform/sunxi/sun4i-csi/Kconfig index e86e29b6a603..93b4e82a2655 100644 --- a/drivers/media/platform/sunxi/sun4i-csi/Kconfig +++ b/drivers/media/platform/sunxi/sun4i-csi/Kconfig @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0 + config VIDEO_SUN4I_CSI tristate "Allwinner A10 CMOS Sensor Interface Support" depends on VIDEO_V4L2 && COMMON_CLK && VIDEO_V4L2_SUBDEV_API && HAS_DMA diff --git a/drivers/media/platform/sunxi/sun4i-csi/Makefile b/drivers/media/platform/sunxi/sun4i-csi/Makefile index 7c790a57f5ee..5062b006d63e 100644 --- a/drivers/media/platform/sunxi/sun4i-csi/Makefile +++ b/drivers/media/platform/sunxi/sun4i-csi/Makefile @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0 + sun4i-csi-y += sun4i_csi.o sun4i-csi-y += sun4i_dma.o sun4i-csi-y += sun4i_v4l2.o diff --git a/drivers/staging/media/hantro/Makefile b/drivers/staging/media/hantro/Makefile index 68c29a9c4946..743ce08eb184 100644 --- a/drivers/staging/media/hantro/Makefile +++ b/drivers/staging/media/hantro/Makefile @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0 + obj-$(CONFIG_VIDEO_HANTRO) += hantro-vpu.o hantro-vpu-y += \ diff --git a/drivers/staging/media/rkisp1/Makefile b/drivers/staging/media/rkisp1/Makefile index 69ca59c7ef34..ab32a77db8f7 100644 --- a/drivers/staging/media/rkisp1/Makefile +++ b/drivers/staging/media/rkisp1/Makefile @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0 + obj-$(CONFIG_VIDEO_ROCKCHIP_ISP1) += rockchip-isp1.o rockchip-isp1-objs += rkisp1-capture.o \ rkisp1-common.o \ -- cgit v1.2.3 From e58be01614ca8640d727ea7cd37f5984e0b57a7a Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 25 Mar 2020 15:01:25 +0100 Subject: media: dvb-core: Kconfig: default to use dynamic minors All modern Linux distributions nowadays use udev or some alternative (like systemd). So, it makes sense to change the default to use dynamic minors. Please notice that this default doesn't enable any code. It just changes the dvb-core behavior. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/media') diff --git a/drivers/media/dvb-core/Kconfig b/drivers/media/dvb-core/Kconfig index 90e038d5ffd9..61f9e1ce99cb 100644 --- a/drivers/media/dvb-core/Kconfig +++ b/drivers/media/dvb-core/Kconfig @@ -19,6 +19,7 @@ config DVB_MAX_ADAPTERS config DVB_DYNAMIC_MINORS bool "Dynamic DVB minor allocation" depends on DVB_CORE + default y help If you say Y here, the DVB subsystem will use dynamic minor allocation for any device that uses the DVB major number. -- cgit v1.2.3 From 32a363d0b0b142f35512848dc646ee53e0926723 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 25 Mar 2020 15:36:56 +0100 Subject: media: Kconfig files: use select for V4L2 subdevs and MC There are lots of drivers that only work when the media controller and/or the V4L2 subdev APIs are present. Right now, someone need to first enable those APIs before using those drivers. Well, ideally, drivers, should, instead *optionally* depend on it, in order for PC camera drivers to be able to use them, but nowadays most drivers are UVC cameras, with don't require a sensor driver. So, be it. Let's instead make them select the MEDIA_CONTROLLER and the SUBDEV API, in order to make easier for people to be able of enabling them. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/Kconfig | 210 +++++++++++++++++-------- drivers/media/i2c/et8ek8/Kconfig | 4 +- drivers/media/i2c/m5mols/Kconfig | 5 +- drivers/media/i2c/smiapp/Kconfig | 5 +- drivers/media/mc/Kconfig | 2 +- drivers/media/pci/cobalt/Kconfig | 4 +- drivers/media/pci/intel/ipu3/Kconfig | 4 +- drivers/media/pci/sta2x11/Kconfig | 6 +- drivers/media/platform/Kconfig | 28 +++- drivers/media/platform/am437x/Kconfig | 4 +- drivers/media/platform/atmel/Kconfig | 4 +- drivers/media/platform/cadence/Kconfig | 8 +- drivers/media/platform/exynos4-is/Kconfig | 5 +- drivers/media/platform/rcar-vin/Kconfig | 8 +- drivers/media/platform/sunxi/sun4i-csi/Kconfig | 4 +- drivers/media/platform/sunxi/sun6i-csi/Kconfig | 4 +- drivers/media/platform/xilinx/Kconfig | 4 +- drivers/media/spi/Kconfig | 4 +- drivers/media/test_drivers/vimc/Kconfig | 4 +- drivers/staging/media/hantro/Kconfig | 5 +- drivers/staging/media/imx/Kconfig | 5 +- drivers/staging/media/ipu3/Kconfig | 3 +- drivers/staging/media/omap4iss/Kconfig | 4 +- drivers/staging/media/rkisp1/Kconfig | 4 +- drivers/staging/media/sunxi/cedrus/Kconfig | 5 +- 25 files changed, 237 insertions(+), 106 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 125d596c13dd..4bc4cfea2f20 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -19,7 +19,7 @@ config VIDEO_IR_I2C In doubt, say Y. # -# Encoder / Decoder module configuration +# V4L2 I2C drivers that aren't related with Camera support # comment "I2C drivers hidden by 'Autoselect ancillary drivers'" @@ -28,6 +28,10 @@ comment "I2C drivers hidden by 'Autoselect ancillary drivers'" menu "I2C Encoders, decoders, sensors and other helper chips" visible if !MEDIA_HIDE_ANCILLARY_SUBDRV +# +# Encoder / Decoder module configuration +# + comment "Audio decoders, processors and mixers" config VIDEO_TVAUDIO @@ -62,11 +66,13 @@ config VIDEO_TDA9840 config VIDEO_TDA1997X tristate "NXP TDA1997x HDMI receiver" - depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API + depends on VIDEO_V4L2 && I2C depends on SND_SOC select HDMI select SND_PCM select V4L2_FWNODE + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API help V4L2 subdevice driver for the NXP TDA1997x HDMI receivers. @@ -204,7 +210,9 @@ comment "Video decoders" config VIDEO_ADV7180 tristate "Analog Devices ADV7180 decoder" - depends on GPIOLIB && VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API + depends on GPIOLIB && VIDEO_V4L2 && I2C + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API help Support for the Analog Devices ADV7180 video decoder. @@ -223,8 +231,10 @@ config VIDEO_ADV7183 config VIDEO_ADV748X tristate "Analog Devices ADV748x decoder" - depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API + depends on VIDEO_V4L2 && I2C depends on OF + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API select REGMAP_I2C select V4L2_FWNODE help @@ -236,8 +246,10 @@ config VIDEO_ADV748X config VIDEO_ADV7604 tristate "Analog Devices ADV7604 decoder" - depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API + depends on VIDEO_V4L2 && I2C depends on GPIOLIB || COMPILE_TEST + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API select REGMAP_I2C select HDMI select V4L2_FWNODE @@ -260,7 +272,9 @@ config VIDEO_ADV7604_CEC config VIDEO_ADV7842 tristate "Analog Devices ADV7842 decoder" - depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API + depends on VIDEO_V4L2 && I2C + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API select HDMI help Support for the Analog Devices ADV7842 video decoder. @@ -347,7 +361,9 @@ config VIDEO_SAA711X config VIDEO_TC358743 tristate "Toshiba TC358743 decoder" - depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API + depends on VIDEO_V4L2 && I2C + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API select HDMI select V4L2_FWNODE help @@ -515,8 +531,10 @@ config VIDEO_ADV7393 config VIDEO_ADV7511 tristate "Analog Devices ADV7511 encoder" - depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API + depends on VIDEO_V4L2 && I2C depends on DRM_I2C_ADV7511=n || COMPILE_TEST + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API select HDMI help Support for the Analog Devices ADV7511 video encoder. @@ -536,7 +554,10 @@ config VIDEO_ADV7511_CEC config VIDEO_AD9389B tristate "Analog Devices AD9389B encoder" - depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API + depends on VIDEO_V4L2 && I2C + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API + help Support for the Analog Devices AD9389B video encoder. @@ -568,12 +589,17 @@ config VIDEO_APTINA_PLL config VIDEO_SMIAPP_PLL tristate +# +# All drivers that are related to Media Camera Support should be here +# + if MEDIA_CAMERA_SUPPORT config VIDEO_HI556 tristate "Hynix Hi-556 sensor support" - depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API - depends on MEDIA_CONTROLLER + depends on I2C && VIDEO_V4L2 + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API select V4L2_FWNODE help This is a Video4Linux2 sensor driver for the Hynix @@ -584,8 +610,10 @@ config VIDEO_HI556 config VIDEO_IMX214 tristate "Sony IMX214 sensor support" - depends on GPIOLIB && I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API + depends on GPIOLIB && I2C && VIDEO_V4L2 depends on V4L2_FWNODE + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API select REGMAP_I2C help This is a Video4Linux2 sensor driver for the Sony @@ -596,7 +624,9 @@ config VIDEO_IMX214 config VIDEO_IMX219 tristate "Sony IMX219 sensor support" - depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API + depends on I2C && VIDEO_V4L2 + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API select V4L2_FWNODE help This is a Video4Linux2 sensor driver for the Sony @@ -607,7 +637,9 @@ config VIDEO_IMX219 config VIDEO_IMX258 tristate "Sony IMX258 sensor support" - depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API + depends on I2C && VIDEO_V4L2 + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API help This is a Video4Linux2 sensor driver for the Sony IMX258 camera. @@ -617,7 +649,9 @@ config VIDEO_IMX258 config VIDEO_IMX274 tristate "Sony IMX274 sensor support" - depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API + depends on I2C && VIDEO_V4L2 + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API select REGMAP_I2C help This is a V4L2 sensor driver for the Sony IMX274 @@ -625,7 +659,9 @@ config VIDEO_IMX274 config VIDEO_IMX290 tristate "Sony IMX290 sensor support" - depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API + depends on I2C && VIDEO_V4L2 + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API select REGMAP_I2C select V4L2_FWNODE help @@ -637,7 +673,9 @@ config VIDEO_IMX290 config VIDEO_IMX319 tristate "Sony IMX319 sensor support" - depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API + depends on I2C && VIDEO_V4L2 + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API help This is a Video4Linux2 sensor driver for the Sony IMX319 camera. @@ -647,7 +685,9 @@ config VIDEO_IMX319 config VIDEO_IMX355 tristate "Sony IMX355 sensor support" - depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API + depends on I2C && VIDEO_V4L2 + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API help This is a Video4Linux2 sensor driver for the Sony IMX355 camera. @@ -678,7 +718,8 @@ config VIDEO_OV2659 config VIDEO_OV2680 tristate "OmniVision OV2680 sensor support" - depends on VIDEO_V4L2 && I2C && MEDIA_CONTROLLER + depends on VIDEO_V4L2 && I2C + select MEDIA_CONTROLLER select V4L2_FWNODE help This is a Video4Linux2 sensor driver for the OmniVision @@ -689,7 +730,8 @@ config VIDEO_OV2680 config VIDEO_OV2685 tristate "OmniVision OV2685 sensor support" - depends on VIDEO_V4L2 && I2C && MEDIA_CONTROLLER + depends on VIDEO_V4L2 && I2C + select MEDIA_CONTROLLER select V4L2_FWNODE help This is a Video4Linux2 sensor driver for the OmniVision @@ -701,7 +743,9 @@ config VIDEO_OV2685 config VIDEO_OV5640 tristate "OmniVision OV5640 sensor support" depends on OF - depends on GPIOLIB && VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API + depends on GPIOLIB && VIDEO_V4L2 && I2C + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API select V4L2_FWNODE help This is a Video4Linux2 sensor driver for the Omnivision @@ -710,7 +754,9 @@ config VIDEO_OV5640 config VIDEO_OV5645 tristate "OmniVision OV5645 sensor support" depends on OF - depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API + depends on I2C && VIDEO_V4L2 + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API select V4L2_FWNODE help This is a Video4Linux2 sensor driver for the OmniVision @@ -721,7 +767,9 @@ config VIDEO_OV5645 config VIDEO_OV5647 tristate "OmniVision OV5647 sensor support" - depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API + depends on I2C && VIDEO_V4L2 + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API select V4L2_FWNODE help This is a Video4Linux2 sensor driver for the OmniVision @@ -742,8 +790,9 @@ config VIDEO_OV6650 config VIDEO_OV5670 tristate "OmniVision OV5670 sensor support" - depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API - depends on MEDIA_CONTROLLER + depends on I2C && VIDEO_V4L2 + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API select V4L2_FWNODE help This is a Video4Linux2 sensor driver for the OmniVision @@ -754,8 +803,9 @@ config VIDEO_OV5670 config VIDEO_OV5675 tristate "OmniVision OV5675 sensor support" - depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API - depends on MEDIA_CONTROLLER + depends on I2C && VIDEO_V4L2 + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API select V4L2_FWNODE help This is a Video4Linux2 sensor driver for the OmniVision @@ -777,7 +827,9 @@ config VIDEO_OV5695 config VIDEO_OV7251 tristate "OmniVision OV7251 sensor support" - depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API + depends on I2C && VIDEO_V4L2 + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API select V4L2_FWNODE help This is a Video4Linux2 sensor driver for the OmniVision @@ -826,7 +878,9 @@ config VIDEO_OV7740 config VIDEO_OV8856 tristate "OmniVision OV8856 sensor support" - depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API + depends on I2C && VIDEO_V4L2 + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API select V4L2_FWNODE help This is a Video4Linux2 sensor driver for the OmniVision @@ -844,7 +898,9 @@ config VIDEO_OV9640 config VIDEO_OV9650 tristate "OmniVision OV9650/OV9652 sensor support" - depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API + depends on I2C && VIDEO_V4L2 + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API select REGMAP_SCCB help This is a V4L2 sensor driver for the Omnivision @@ -852,7 +908,9 @@ config VIDEO_OV9650 config VIDEO_OV13858 tristate "OmniVision OV13858 sensor support" - depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API + depends on I2C && VIDEO_V4L2 + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API select V4L2_FWNODE help This is a Video4Linux2 sensor driver for the OmniVision @@ -870,14 +928,18 @@ config VIDEO_VS6624 config VIDEO_MT9M001 tristate "mt9m001 support" - depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API + depends on I2C && VIDEO_V4L2 + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API help This driver supports MT9M001 cameras from Micron, monochrome and colour models. config VIDEO_MT9M032 tristate "MT9M032 camera sensor support" - depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API + depends on I2C && VIDEO_V4L2 + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API select VIDEO_APTINA_PLL help This driver supports MT9M032 camera sensors from Aptina, monochrome @@ -893,7 +955,9 @@ config VIDEO_MT9M111 config VIDEO_MT9P031 tristate "Aptina MT9P031 support" - depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API + depends on I2C && VIDEO_V4L2 + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API select VIDEO_APTINA_PLL help This is a Video4Linux2 sensor driver for the Aptina @@ -901,7 +965,9 @@ config VIDEO_MT9P031 config VIDEO_MT9T001 tristate "Aptina MT9T001 support" - depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API + depends on I2C && VIDEO_V4L2 + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API help This is a Video4Linux2 sensor driver for the Aptina (Micron) mt0t001 3 Mpixel camera. @@ -926,7 +992,9 @@ config VIDEO_MT9V011 config VIDEO_MT9V032 tristate "Micron MT9V032 sensor support" - depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API + depends on I2C && VIDEO_V4L2 + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API select REGMAP_I2C select V4L2_FWNODE help @@ -951,7 +1019,9 @@ config VIDEO_SR030PC30 config VIDEO_NOON010PC30 tristate "Siliconfile NOON010PC30 sensor support" - depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API + depends on I2C && VIDEO_V4L2 + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API help This driver supports NOON010PC30 CIF camera from Siliconfile @@ -969,21 +1039,27 @@ config VIDEO_RJ54N1 config VIDEO_S5K6AA tristate "Samsung S5K6AAFX sensor support" - depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API + depends on I2C && VIDEO_V4L2 + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API help This is a V4L2 sensor driver for Samsung S5K6AA(FX) 1.3M camera sensor with an embedded SoC image signal processor. config VIDEO_S5K6A3 tristate "Samsung S5K6A3 sensor support" - depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API + depends on I2C && VIDEO_V4L2 + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API help This is a V4L2 sensor driver for Samsung S5K6A3 raw camera sensor. config VIDEO_S5K4ECGX tristate "Samsung S5K4ECGX sensor support" - depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API + depends on I2C && VIDEO_V4L2 + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API select CRC32 help This is a V4L2 sensor driver for Samsung S5K4ECGX 5M @@ -991,7 +1067,9 @@ config VIDEO_S5K4ECGX config VIDEO_S5K5BAF tristate "Samsung S5K5BAF sensor support" - depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API + depends on I2C && VIDEO_V4L2 + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API select V4L2_FWNODE help This is a V4L2 sensor driver for Samsung S5K5BAF 2M @@ -1002,28 +1080,29 @@ source "drivers/media/i2c/et8ek8/Kconfig" config VIDEO_S5C73M3 tristate "Samsung S5C73M3 sensor support" - depends on I2C && SPI && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API + depends on I2C && SPI && VIDEO_V4L2 + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API select V4L2_FWNODE help This is a V4L2 sensor driver for Samsung S5C73M3 8 Mpixel camera. -endif comment "Lens drivers" -if MEDIA_CAMERA_SUPPORT - config VIDEO_AD5820 tristate "AD5820 lens voice coil support" - depends on GPIOLIB && I2C && VIDEO_V4L2 && MEDIA_CONTROLLER + depends on GPIOLIB && I2C && VIDEO_V4L2 + select MEDIA_CONTROLLER help This is a driver for the AD5820 camera lens voice coil. It is used for example in Nokia N900 (RX-51). config VIDEO_AK7375 tristate "AK7375 lens voice coil support" - depends on I2C && VIDEO_V4L2 && MEDIA_CONTROLLER - depends on VIDEO_V4L2_SUBDEV_API + depends on I2C && VIDEO_V4L2 + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API help This is a driver for the AK7375 camera lens voice coil. AK7375 is a 12 bit DAC with 120mA output current sink @@ -1032,8 +1111,9 @@ config VIDEO_AK7375 config VIDEO_DW9714 tristate "DW9714 lens voice coil support" - depends on I2C && VIDEO_V4L2 && MEDIA_CONTROLLER - depends on VIDEO_V4L2_SUBDEV_API + depends on I2C && VIDEO_V4L2 + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API help This is a driver for the DW9714 camera lens voice coil. DW9714 is a 10 bit DAC with 120mA output current sink @@ -1042,30 +1122,30 @@ config VIDEO_DW9714 config VIDEO_DW9807_VCM tristate "DW9807 lens voice coil support" - depends on I2C && VIDEO_V4L2 && MEDIA_CONTROLLER - depends on VIDEO_V4L2_SUBDEV_API + depends on I2C && VIDEO_V4L2 + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API help This is a driver for the DW9807 camera lens voice coil. DW9807 is a 10 bit DAC with 100mA output current sink capability. This is designed for linear control of voice coil motors, controlled via I2C serial interface. -endif comment "Flash devices" -if MEDIA_CAMERA_SUPPORT - config VIDEO_ADP1653 tristate "ADP1653 flash support" - depends on I2C && VIDEO_V4L2 && MEDIA_CONTROLLER + depends on I2C && VIDEO_V4L2 + select MEDIA_CONTROLLER help This is a driver for the ADP1653 flash controller. It is used for example in Nokia N900. config VIDEO_LM3560 tristate "LM3560 dual flash driver support" - depends on I2C && VIDEO_V4L2 && MEDIA_CONTROLLER + depends on I2C && VIDEO_V4L2 + select MEDIA_CONTROLLER select REGMAP_I2C help This is a driver for the lm3560 dual flash controllers. It controls @@ -1073,13 +1153,18 @@ config VIDEO_LM3560 config VIDEO_LM3646 tristate "LM3646 dual flash driver support" - depends on I2C && VIDEO_V4L2 && MEDIA_CONTROLLER + depends on I2C && VIDEO_V4L2 + select MEDIA_CONTROLLER select REGMAP_I2C help This is a driver for the lm3646 dual flash controllers. It controls flash, torch LEDs. -endif +endif # MEDIA_CAMERA_SUPPORT + +# +# Other V4L2 drivers that aren't related with Camera support +# comment "Video improvement chips" @@ -1168,8 +1253,9 @@ config VIDEO_I2C config VIDEO_ST_MIPID02 tristate "STMicroelectronics MIPID02 CSI-2 to PARALLEL bridge" - depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API - depends on MEDIA_CAMERA_SUPPORT + depends on I2C && VIDEO_V4L2 + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API select V4L2_FWNODE help Support for STMicroelectronics MIPID02 CSI-2 to PARALLEL bridge. @@ -1181,4 +1267,4 @@ config VIDEO_ST_MIPID02 endmenu -endif +endif # VIDEO_V4L2 diff --git a/drivers/media/i2c/et8ek8/Kconfig b/drivers/media/i2c/et8ek8/Kconfig index 1c6909874d56..afcc4ea764f6 100644 --- a/drivers/media/i2c/et8ek8/Kconfig +++ b/drivers/media/i2c/et8ek8/Kconfig @@ -1,7 +1,9 @@ # SPDX-License-Identifier: GPL-2.0-only config VIDEO_ET8EK8 tristate "ET8EK8 camera sensor support" - depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API + depends on I2C && VIDEO_V4L2 + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API select V4L2_FWNODE help This is a driver for the Toshiba ET8EK8 5 MP camera sensor. diff --git a/drivers/media/i2c/m5mols/Kconfig b/drivers/media/i2c/m5mols/Kconfig index e573482f269f..6f0ef33b7ee1 100644 --- a/drivers/media/i2c/m5mols/Kconfig +++ b/drivers/media/i2c/m5mols/Kconfig @@ -1,7 +1,8 @@ # SPDX-License-Identifier: GPL-2.0-only config VIDEO_M5MOLS tristate "Fujitsu M-5MOLS 8MP sensor support" - depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API - depends on MEDIA_CAMERA_SUPPORT + depends on I2C && VIDEO_V4L2 + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API help This driver supports Fujitsu M-5MOLS camera sensor with ISP diff --git a/drivers/media/i2c/smiapp/Kconfig b/drivers/media/i2c/smiapp/Kconfig index fcaa7f9494a8..6893b532824f 100644 --- a/drivers/media/i2c/smiapp/Kconfig +++ b/drivers/media/i2c/smiapp/Kconfig @@ -1,8 +1,9 @@ # SPDX-License-Identifier: GPL-2.0-only config VIDEO_SMIAPP tristate "SMIA++/SMIA sensor support" - depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && HAVE_CLK - depends on MEDIA_CAMERA_SUPPORT + depends on I2C && VIDEO_V4L2 && HAVE_CLK + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API select VIDEO_SMIAPP_PLL select V4L2_FWNODE help diff --git a/drivers/media/mc/Kconfig b/drivers/media/mc/Kconfig index 0c5c52f14c64..e740ace54d7f 100644 --- a/drivers/media/mc/Kconfig +++ b/drivers/media/mc/Kconfig @@ -7,7 +7,7 @@ config MEDIA_CONTROLLER bool "Media Controller API" - depends on MEDIA_CAMERA_SUPPORT || MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT + default MEDIA_CAMERA_SUPPORT || MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT || MEDIA_PLATFORM_SUPPORT help Enable the media controller API used to query media devices internal topology and configure it dynamically. diff --git a/drivers/media/pci/cobalt/Kconfig b/drivers/media/pci/cobalt/Kconfig index e0e7df460a92..d8d9ea6b09bc 100644 --- a/drivers/media/pci/cobalt/Kconfig +++ b/drivers/media/pci/cobalt/Kconfig @@ -1,11 +1,13 @@ # SPDX-License-Identifier: GPL-2.0-only config VIDEO_COBALT tristate "Cisco Cobalt support" - depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API + depends on VIDEO_V4L2 && I2C depends on PCI_MSI && MTD_COMPLEX_MAPPINGS depends on (GPIOLIB && DRM_I2C_ADV7511=n) || COMPILE_TEST depends on SND depends on MTD + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API select I2C_ALGOBIT select SND_PCM select VIDEO_ADV7604 diff --git a/drivers/media/pci/intel/ipu3/Kconfig b/drivers/media/pci/intel/ipu3/Kconfig index f35bba16b60e..82d7f17e6a02 100644 --- a/drivers/media/pci/intel/ipu3/Kconfig +++ b/drivers/media/pci/intel/ipu3/Kconfig @@ -2,9 +2,9 @@ config VIDEO_IPU3_CIO2 tristate "Intel ipu3-cio2 driver" depends on VIDEO_V4L2 && PCI - depends on VIDEO_V4L2_SUBDEV_API depends on (X86 && ACPI) || COMPILE_TEST - depends on MEDIA_CONTROLLER + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API select V4L2_FWNODE select VIDEOBUF2_DMA_SG diff --git a/drivers/media/pci/sta2x11/Kconfig b/drivers/media/pci/sta2x11/Kconfig index 011b766f0bff..4dd98f94a91e 100644 --- a/drivers/media/pci/sta2x11/Kconfig +++ b/drivers/media/pci/sta2x11/Kconfig @@ -1,12 +1,12 @@ # SPDX-License-Identifier: GPL-2.0-only config STA2X11_VIP tristate "STA2X11 VIP Video For Linux" + depends on PCI && VIDEO_V4L2 && VIRT_TO_BUS && I2C depends on STA2X11 || COMPILE_TEST select VIDEO_ADV7180 if MEDIA_SUBDRV_AUTOSELECT select VIDEOBUF2_DMA_CONTIG - depends on PCI && VIDEO_V4L2 && VIRT_TO_BUS - depends on VIDEO_V4L2_SUBDEV_API - depends on I2C + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API help Say Y for support for STA2X11 VIP (Video Input Port) capture device. diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index 6b693cd0576e..b8b2de5f1541 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -63,7 +63,9 @@ config VIDEO_VIU config VIDEO_MUX tristate "Video Multiplexer" select MULTIPLEXER - depends on VIDEO_V4L2 && OF && VIDEO_V4L2_SUBDEV_API && MEDIA_CONTROLLER + depends on VIDEO_V4L2 && OF + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API select REGMAP select V4L2_FWNODE help @@ -71,10 +73,12 @@ config VIDEO_MUX config VIDEO_OMAP3 tristate "OMAP 3 Camera support" - depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API + depends on VIDEO_V4L2 && I2C depends on (ARCH_OMAP3 && OMAP_IOMMU) || COMPILE_TEST depends on COMMON_CLK && OF select ARM_DMA_USE_IOMMU if OMAP_IOMMU + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API select VIDEOBUF2_DMA_CONTIG select MFD_SYSCON select V4L2_FWNODE @@ -99,16 +103,19 @@ config VIDEO_PXA27x config VIDEO_QCOM_CAMSS tristate "Qualcomm V4L2 Camera Subsystem driver" - depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API + depends on VIDEO_V4L2 depends on (ARCH_QCOM && IOMMU_DMA) || COMPILE_TEST + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API select VIDEOBUF2_DMA_SG select V4L2_FWNODE config VIDEO_S3C_CAMIF tristate "Samsung S3C24XX/S3C64XX SoC Camera Interface driver" - depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API - depends on PM + depends on VIDEO_V4L2 && I2C && PM depends on ARCH_S3C64XX || PLAT_S3C24XX || COMPILE_TEST + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API select VIDEOBUF2_DMA_CONTIG help This is a v4l2 driver for s3c24xx and s3c64xx SoC series camera @@ -119,9 +126,10 @@ config VIDEO_S3C_CAMIF config VIDEO_STM32_DCMI tristate "STM32 Digital Camera Memory Interface (DCMI) support" - depends on VIDEO_V4L2 && OF && MEDIA_CONTROLLER + depends on VIDEO_V4L2 && OF depends on ARCH_STM32 || COMPILE_TEST select VIDEOBUF2_DMA_CONTIG + select MEDIA_CONTROLLER select V4L2_FWNODE help This module makes the STM32 Digital Camera Memory Interface (DCMI) @@ -148,7 +156,9 @@ source "drivers/media/platform/sunxi/Kconfig" config VIDEO_TI_CAL tristate "TI CAL (Camera Adaptation Layer) driver" - depends on VIDEO_DEV && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API + depends on VIDEO_DEV && VIDEO_V4L2 + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API depends on SOC_DRA7XX || ARCH_K3 || COMPILE_TEST select VIDEOBUF2_DMA_CONTIG select V4L2_FWNODE @@ -432,9 +442,11 @@ config VIDEO_RENESAS_FCP config VIDEO_RENESAS_VSP1 tristate "Renesas VSP1 Video Processing Engine" - depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API + depends on VIDEO_V4L2 depends on ARCH_RENESAS || COMPILE_TEST depends on (!ARM64 && !VIDEO_RENESAS_FCP) || VIDEO_RENESAS_FCP + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API select VIDEOBUF2_DMA_CONTIG select VIDEOBUF2_VMALLOC help diff --git a/drivers/media/platform/am437x/Kconfig b/drivers/media/platform/am437x/Kconfig index d6f2e3d0cbef..9ef898f512de 100644 --- a/drivers/media/platform/am437x/Kconfig +++ b/drivers/media/platform/am437x/Kconfig @@ -1,8 +1,10 @@ # SPDX-License-Identifier: GPL-2.0-only config VIDEO_AM437X_VPFE tristate "TI AM437x VPFE video capture driver" - depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API + depends on VIDEO_V4L2 depends on SOC_AM43XX || COMPILE_TEST + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API select VIDEOBUF2_DMA_CONTIG select V4L2_FWNODE help diff --git a/drivers/media/platform/atmel/Kconfig b/drivers/media/platform/atmel/Kconfig index 5ae3f60b81b1..1850fe7f9360 100644 --- a/drivers/media/platform/atmel/Kconfig +++ b/drivers/media/platform/atmel/Kconfig @@ -1,8 +1,10 @@ # SPDX-License-Identifier: GPL-2.0-only config VIDEO_ATMEL_ISC tristate "ATMEL Image Sensor Controller (ISC) support" - depends on VIDEO_V4L2 && COMMON_CLK && VIDEO_V4L2_SUBDEV_API + depends on VIDEO_V4L2 && COMMON_CLK depends on ARCH_AT91 || COMPILE_TEST + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API select VIDEOBUF2_DMA_CONTIG select REGMAP_MMIO select V4L2_FWNODE diff --git a/drivers/media/platform/cadence/Kconfig b/drivers/media/platform/cadence/Kconfig index c154e368d701..80cf601323ce 100644 --- a/drivers/media/platform/cadence/Kconfig +++ b/drivers/media/platform/cadence/Kconfig @@ -13,8 +13,8 @@ if VIDEO_CADENCE config VIDEO_CADENCE_CSI2RX tristate "Cadence MIPI-CSI2 RX Controller" depends on VIDEO_V4L2 - depends on MEDIA_CONTROLLER - depends on VIDEO_V4L2_SUBDEV_API + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API select V4L2_FWNODE help Support for the Cadence MIPI CSI2 Receiver controller. @@ -25,8 +25,8 @@ config VIDEO_CADENCE_CSI2RX config VIDEO_CADENCE_CSI2TX tristate "Cadence MIPI-CSI2 TX Controller" depends on VIDEO_V4L2 - depends on MEDIA_CONTROLLER - depends on VIDEO_V4L2_SUBDEV_API + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API select V4L2_FWNODE help Support for the Cadence MIPI CSI2 Transceiver controller. diff --git a/drivers/media/platform/exynos4-is/Kconfig b/drivers/media/platform/exynos4-is/Kconfig index be4effcbfe7b..136d3b2a0fbb 100644 --- a/drivers/media/platform/exynos4-is/Kconfig +++ b/drivers/media/platform/exynos4-is/Kconfig @@ -2,9 +2,10 @@ config VIDEO_SAMSUNG_EXYNOS4_IS tristate "Samsung S5P/EXYNOS4 SoC series Camera Subsystem driver" - depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API + depends on VIDEO_V4L2 && OF && COMMON_CLK depends on ARCH_S5PV210 || ARCH_EXYNOS || COMPILE_TEST - depends on OF && COMMON_CLK + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API select V4L2_FWNODE help Say Y here to enable camera host interface devices for diff --git a/drivers/media/platform/rcar-vin/Kconfig b/drivers/media/platform/rcar-vin/Kconfig index 240ac3f3c941..ca0d906dce2f 100644 --- a/drivers/media/platform/rcar-vin/Kconfig +++ b/drivers/media/platform/rcar-vin/Kconfig @@ -1,8 +1,10 @@ # SPDX-License-Identifier: GPL-2.0 config VIDEO_RCAR_CSI2 tristate "R-Car MIPI CSI-2 Receiver" - depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && OF + depends on VIDEO_V4L2 && OF depends on ARCH_RENESAS || COMPILE_TEST + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API select RESET_CONTROLLER select V4L2_FWNODE help @@ -14,8 +16,10 @@ config VIDEO_RCAR_CSI2 config VIDEO_RCAR_VIN tristate "R-Car Video Input (VIN) Driver" - depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && OF && MEDIA_CONTROLLER + depends on VIDEO_V4L2 && OF depends on ARCH_RENESAS || COMPILE_TEST + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API select VIDEOBUF2_DMA_CONTIG select V4L2_FWNODE help diff --git a/drivers/media/platform/sunxi/sun4i-csi/Kconfig b/drivers/media/platform/sunxi/sun4i-csi/Kconfig index 93b4e82a2655..903c6152f6e8 100644 --- a/drivers/media/platform/sunxi/sun4i-csi/Kconfig +++ b/drivers/media/platform/sunxi/sun4i-csi/Kconfig @@ -2,8 +2,10 @@ config VIDEO_SUN4I_CSI tristate "Allwinner A10 CMOS Sensor Interface Support" - depends on VIDEO_V4L2 && COMMON_CLK && VIDEO_V4L2_SUBDEV_API && HAS_DMA + depends on VIDEO_V4L2 && COMMON_CLK && HAS_DMA depends on ARCH_SUNXI || COMPILE_TEST + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API select VIDEOBUF2_DMA_CONTIG select V4L2_FWNODE help diff --git a/drivers/media/platform/sunxi/sun6i-csi/Kconfig b/drivers/media/platform/sunxi/sun6i-csi/Kconfig index 269b3ebf4f52..586e3fb3a80d 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/Kconfig +++ b/drivers/media/platform/sunxi/sun6i-csi/Kconfig @@ -1,8 +1,10 @@ # SPDX-License-Identifier: GPL-2.0-only config VIDEO_SUN6I_CSI tristate "Allwinner V3s Camera Sensor Interface driver" - depends on VIDEO_V4L2 && COMMON_CLK && VIDEO_V4L2_SUBDEV_API && HAS_DMA + depends on VIDEO_V4L2 && COMMON_CLK && HAS_DMA depends on ARCH_SUNXI || COMPILE_TEST + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API select VIDEOBUF2_DMA_CONTIG select REGMAP_MMIO select V4L2_FWNODE diff --git a/drivers/media/platform/xilinx/Kconfig b/drivers/media/platform/xilinx/Kconfig index a2773ad7c185..01c96fb66414 100644 --- a/drivers/media/platform/xilinx/Kconfig +++ b/drivers/media/platform/xilinx/Kconfig @@ -2,7 +2,9 @@ config VIDEO_XILINX tristate "Xilinx Video IP (EXPERIMENTAL)" - depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && OF && HAS_DMA + depends on VIDEO_V4L2 && OF && HAS_DMA + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API select VIDEOBUF2_DMA_CONTIG select V4L2_FWNODE help diff --git a/drivers/media/spi/Kconfig b/drivers/media/spi/Kconfig index bcc49cb47de6..bf385d503cab 100644 --- a/drivers/media/spi/Kconfig +++ b/drivers/media/spi/Kconfig @@ -9,7 +9,9 @@ menu "SPI helper chips" config VIDEO_GS1662 tristate "Gennum Serializers video" - depends on SPI && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API + depends on SPI && VIDEO_V4L2 + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API help Enable the GS1662 driver which serializes video streams. diff --git a/drivers/media/test_drivers/vimc/Kconfig b/drivers/media/test_drivers/vimc/Kconfig index bd221d3e1a4a..4068a67585f9 100644 --- a/drivers/media/test_drivers/vimc/Kconfig +++ b/drivers/media/test_drivers/vimc/Kconfig @@ -1,7 +1,9 @@ # SPDX-License-Identifier: GPL-2.0-only config VIDEO_VIMC tristate "Virtual Media Controller Driver (VIMC)" - depends on VIDEO_DEV && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API + depends on VIDEO_DEV && VIDEO_V4L2 + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API select VIDEOBUF2_VMALLOC select VIDEO_V4L2_TPG help diff --git a/drivers/staging/media/hantro/Kconfig b/drivers/staging/media/hantro/Kconfig index 99aed9a5b0b9..68e5b06cdab7 100644 --- a/drivers/staging/media/hantro/Kconfig +++ b/drivers/staging/media/hantro/Kconfig @@ -2,8 +2,9 @@ config VIDEO_HANTRO tristate "Hantro VPU driver" depends on ARCH_MXC || ARCH_ROCKCHIP || COMPILE_TEST - depends on VIDEO_DEV && VIDEO_V4L2 && MEDIA_CONTROLLER - depends on MEDIA_CONTROLLER_REQUEST_API + depends on VIDEO_DEV && VIDEO_V4L2 + select MEDIA_CONTROLLER + select MEDIA_CONTROLLER_REQUEST_API select VIDEOBUF2_DMA_CONTIG select VIDEOBUF2_VMALLOC select V4L2_MEM2MEM_DEV diff --git a/drivers/staging/media/imx/Kconfig b/drivers/staging/media/imx/Kconfig index 8f1ae50a4abd..f555aac8a9d5 100644 --- a/drivers/staging/media/imx/Kconfig +++ b/drivers/staging/media/imx/Kconfig @@ -2,8 +2,9 @@ config VIDEO_IMX_MEDIA tristate "i.MX5/6 V4L2 media core driver" depends on ARCH_MXC || COMPILE_TEST - depends on MEDIA_CONTROLLER && VIDEO_V4L2 && IMX_IPUV3_CORE - depends on VIDEO_V4L2_SUBDEV_API + depends on VIDEO_V4L2 && IMX_IPUV3_CORE + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG select V4L2_FWNODE diff --git a/drivers/staging/media/ipu3/Kconfig b/drivers/staging/media/ipu3/Kconfig index 4b51c67eac88..3e9640523e50 100644 --- a/drivers/staging/media/ipu3/Kconfig +++ b/drivers/staging/media/ipu3/Kconfig @@ -2,8 +2,9 @@ config VIDEO_IPU3_IMGU tristate "Intel ipu3-imgu driver" depends on PCI && VIDEO_V4L2 - depends on MEDIA_CONTROLLER && VIDEO_V4L2_SUBDEV_API depends on X86 + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API select IOMMU_IOVA select VIDEOBUF2_DMA_SG help diff --git a/drivers/staging/media/omap4iss/Kconfig b/drivers/staging/media/omap4iss/Kconfig index 4dcbc5065821..6c254907a27b 100644 --- a/drivers/staging/media/omap4iss/Kconfig +++ b/drivers/staging/media/omap4iss/Kconfig @@ -2,8 +2,10 @@ config VIDEO_OMAP4 tristate "OMAP 4 Camera support" - depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && I2C + depends on VIDEO_V4L2 && I2C depends on ARCH_OMAP4 || COMPILE_TEST + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API select MFD_SYSCON select VIDEOBUF2_DMA_CONTIG help diff --git a/drivers/staging/media/rkisp1/Kconfig b/drivers/staging/media/rkisp1/Kconfig index b859a493caba..5ecbefa0f5ec 100644 --- a/drivers/staging/media/rkisp1/Kconfig +++ b/drivers/staging/media/rkisp1/Kconfig @@ -2,8 +2,10 @@ config VIDEO_ROCKCHIP_ISP1 tristate "Rockchip Image Signal Processing v1 Unit driver" - depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API + depends on VIDEO_V4L2 depends on ARCH_ROCKCHIP || COMPILE_TEST + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API select VIDEOBUF2_DMA_CONTIG select VIDEOBUF2_VMALLOC select V4L2_FWNODE diff --git a/drivers/staging/media/sunxi/cedrus/Kconfig b/drivers/staging/media/sunxi/cedrus/Kconfig index 17733e9a088f..da369950bbf2 100644 --- a/drivers/staging/media/sunxi/cedrus/Kconfig +++ b/drivers/staging/media/sunxi/cedrus/Kconfig @@ -1,10 +1,11 @@ # SPDX-License-Identifier: GPL-2.0 config VIDEO_SUNXI_CEDRUS tristate "Allwinner Cedrus VPU driver" - depends on VIDEO_DEV && VIDEO_V4L2 && MEDIA_CONTROLLER + depends on VIDEO_DEV && VIDEO_V4L2 depends on HAS_DMA depends on OF - depends on MEDIA_CONTROLLER_REQUEST_API + select MEDIA_CONTROLLER + select MEDIA_CONTROLLER_REQUEST_API select SUNXI_SRAM select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV -- cgit v1.2.3 From 7d5bc6930db43b737ef29e67b11b32624727802c Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 24 Mar 2020 10:14:15 +0100 Subject: media: Kconfig: reorganize the drivers menu options The comments before some of the drivers support look weird, because their Kconfig have their own "comment" directive inside it. So, rearrange them to make it look a little nicer for the ones with are not too familiar with the media system. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/Kconfig | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index 9c32616f863a..b1a6874acbcc 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -104,9 +104,7 @@ config MEDIA_TEST_SUPPORT In case of doubts, say N. -source "drivers/media/cec/Kconfig" - -source "drivers/media/mc/Kconfig" +comment "Multimedia core features" # # Video4Linux support @@ -130,8 +128,6 @@ config VIDEO_V4L2_SUBDEV_API This API is mostly used by camera interfaces in embedded platforms. -source "drivers/media/v4l2-core/Kconfig" - # # DVB Core # Only enables if one of DTV is selected @@ -174,7 +170,10 @@ config DVB_NET You may want to disable the network support on embedded devices. If unsure say Y. +source "drivers/media/v4l2-core/Kconfig" +source "drivers/media/mc/Kconfig" source "drivers/media/dvb-core/Kconfig" +source "drivers/media/cec/Kconfig" comment "Media drivers" @@ -182,6 +181,9 @@ source "drivers/media/usb/Kconfig" source "drivers/media/pci/Kconfig" source "drivers/media/radio/Kconfig" +# Common driver options +source "drivers/media/common/Kconfig" + if MEDIA_PLATFORM_SUPPORT source "drivers/media/platform/Kconfig" source "drivers/media/test_drivers/Kconfig" @@ -190,9 +192,6 @@ endif source "drivers/media/firewire/Kconfig" -# Common driver options -source "drivers/media/common/Kconfig" - comment "Media ancillary drivers (tuners, sensors, i2c, spi, frontends)" # -- cgit v1.2.3 From c39d57044a253a22b5cfc129d1f1f04be6199341 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 24 Mar 2020 10:25:09 +0100 Subject: media: Kconfig: use a sub-menu to select supported devices The media subsystem has hundreds of driver-specific options. The *_SUPPORT config options work as a sort of filter, allowing to reduce its complexity for users that won't want to dig into thousands of options they don't need. Yet, it the filtering options are becoming large. So, let's place it on a sub-menu. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/Kconfig | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index b1a6874acbcc..a57f898fa35e 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -25,36 +25,35 @@ menuconfig MEDIA_SUPPORT Additional info and docs are available on the web at -if MEDIA_SUPPORT - -comment "Multimedia core support" +menu "Types of devices to be supported" + depends on MEDIA_SUPPORT # # Multimedia support - automatically enable V4L2 and DVB core # config MEDIA_CAMERA_SUPPORT - bool "Cameras/video grabbers support" + bool "Cameras and video grabbers" help Enable support for webcams and video grabbers. Say Y when you have a webcam or a video capture grabber board. config MEDIA_ANALOG_TV_SUPPORT - bool "Analog TV support" + bool "Analog TV" help Enable analog TV support. Say Y when you have a board with analog TV support. config MEDIA_DIGITAL_TV_SUPPORT - bool "Digital TV support" + bool "Digital TV" help Enable digital TV support. Say Y when you have a board with digital TV support. config MEDIA_RADIO_SUPPORT - bool "AM/FM radio receivers/transmitters support" + bool "AM/FM radio receivers/transmitters" help Enable AM/FM radio support. @@ -64,14 +63,14 @@ config MEDIA_RADIO_SUPPORT Say Y when you have a board with radio support. config MEDIA_SDR_SUPPORT - bool "Software defined radio support" + bool "Software defined radio" help Enable software defined radio support. Say Y when you have a software defined radio device. config MEDIA_CEC_SUPPORT - bool "HDMI CEC support" + bool "HDMI CEC" help Enable support for HDMI CEC (Consumer Electronics Control), which is an optional HDMI feature. @@ -80,7 +79,7 @@ config MEDIA_CEC_SUPPORT adapter that supports HDMI CEC. config MEDIA_PLATFORM_SUPPORT - bool "Platform-specific devices support" + bool "Platform-specific devices" help Enable support for complex cameras, codecs, and other hardware that are integrated at the CPU, GPU or on Image Signalling Processor @@ -92,7 +91,7 @@ config MEDIA_PLATFORM_SUPPORT Say Y when you want to be able so see such devices. config MEDIA_TEST_SUPPORT - bool "Test drivers support" + bool "Test drivers" help Those drivers should not be used on production Kernels, but can be useful on debug ones. It enables several dummy drivers @@ -103,6 +102,10 @@ config MEDIA_TEST_SUPPORT Say Y if you want to use some virtual test driver. In case of doubts, say N. + Say Y when you have a software defined radio device. +endmenu # Types of devices to be supported + +if MEDIA_SUPPORT comment "Multimedia core features" -- cgit v1.2.3 From c6774ee035dcb8782c59a3f7f958f36ad439793b Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 24 Mar 2020 11:36:10 +0100 Subject: media: Kconfig: make filtering devices optional The per-device option selection is a feature that some developers love, while others hate... So, let's make both happy by making it optional. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/Kconfig | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index a57f898fa35e..8b070fb703f9 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -25,14 +25,32 @@ menuconfig MEDIA_SUPPORT Additional info and docs are available on the web at -menu "Types of devices to be supported" +if MEDIA_SUPPORT + +config MEDIA_SUPPORT_FILTER + bool "Filter devices by their types" depends on MEDIA_SUPPORT + help + Configuring the media subsystem can be complex, as there are + hundreds of drivers and other config options. + + This menu offers option that will help the Kernel's config + system to hide drivers that are out of the scope of the + user needs, and disabling core support for unused APIs. + + If not selected, all non-optional media core functionality + needed to support media drivers will be enabled. Also, all + media device drivers should be shown. + +menu "Media device types" + visible if MEDIA_SUPPORT_FILTER # # Multimedia support - automatically enable V4L2 and DVB core # config MEDIA_CAMERA_SUPPORT bool "Cameras and video grabbers" + default y if !MEDIA_SUPPORT_FILTER help Enable support for webcams and video grabbers. @@ -40,6 +58,7 @@ config MEDIA_CAMERA_SUPPORT config MEDIA_ANALOG_TV_SUPPORT bool "Analog TV" + default y if !MEDIA_SUPPORT_FILTER help Enable analog TV support. @@ -47,6 +66,7 @@ config MEDIA_ANALOG_TV_SUPPORT config MEDIA_DIGITAL_TV_SUPPORT bool "Digital TV" + default y if !MEDIA_SUPPORT_FILTER help Enable digital TV support. @@ -54,6 +74,7 @@ config MEDIA_DIGITAL_TV_SUPPORT config MEDIA_RADIO_SUPPORT bool "AM/FM radio receivers/transmitters" + default y if !MEDIA_SUPPORT_FILTER help Enable AM/FM radio support. @@ -64,6 +85,7 @@ config MEDIA_RADIO_SUPPORT config MEDIA_SDR_SUPPORT bool "Software defined radio" + default y if !MEDIA_SUPPORT_FILTER help Enable software defined radio support. @@ -71,6 +93,7 @@ config MEDIA_SDR_SUPPORT config MEDIA_CEC_SUPPORT bool "HDMI CEC" + default y if !MEDIA_SUPPORT_FILTER help Enable support for HDMI CEC (Consumer Electronics Control), which is an optional HDMI feature. @@ -80,6 +103,7 @@ config MEDIA_CEC_SUPPORT config MEDIA_PLATFORM_SUPPORT bool "Platform-specific devices" + default y if !MEDIA_SUPPORT_FILTER help Enable support for complex cameras, codecs, and other hardware that are integrated at the CPU, GPU or on Image Signalling Processor @@ -92,6 +116,7 @@ config MEDIA_PLATFORM_SUPPORT config MEDIA_TEST_SUPPORT bool "Test drivers" + default y if !MEDIA_SUPPORT_FILTER help Those drivers should not be used on production Kernels, but can be useful on debug ones. It enables several dummy drivers @@ -103,9 +128,7 @@ config MEDIA_TEST_SUPPORT In case of doubts, say N. Say Y when you have a software defined radio device. -endmenu # Types of devices to be supported - -if MEDIA_SUPPORT +endmenu # media device types comment "Multimedia core features" -- cgit v1.2.3 From ce971d957015d5ea8c7369114e701bc66d866c25 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 26 Mar 2020 09:44:13 +0100 Subject: media: Kconfig: warn if drivers are filtered As per a tester feedback, add an option to report when the drivers are filtered at the Kconfig menu. Cc: Helen Koike Signed-off-by: Mauro Carvalho Chehab --- drivers/media/Kconfig | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index 8b070fb703f9..79aa83a966db 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -28,7 +28,7 @@ menuconfig MEDIA_SUPPORT if MEDIA_SUPPORT config MEDIA_SUPPORT_FILTER - bool "Filter devices by their types" + bool "Filter media drivers" depends on MEDIA_SUPPORT help Configuring the media subsystem can be complex, as there are @@ -203,6 +203,9 @@ source "drivers/media/cec/Kconfig" comment "Media drivers" +comment "Drivers filtered as selected at 'Filter media drivers'" + depends on MEDIA_SUPPORT_FILTER + source "drivers/media/usb/Kconfig" source "drivers/media/pci/Kconfig" source "drivers/media/radio/Kconfig" -- cgit v1.2.3 From f1991411257bdb68d96ef8c8c5b35f412b480375 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 24 Mar 2020 13:41:57 +0100 Subject: media: Kconfig: move CEC-specific options to cec/Kconfig There's no need to have the CEC definitions inside the media Kconfig, as the Kconfig parser doesn't require symbols to be declared before their usages. With that, the main Kconfig menu becomes cleaner. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/Kconfig | 9 --------- drivers/media/cec/Kconfig | 10 ++++++++++ 2 files changed, 10 insertions(+), 9 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index 79aa83a966db..9cc528e0b120 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -3,15 +3,6 @@ # Multimedia device configuration # -config CEC_CORE - tristate - -config CEC_NOTIFIER - bool - -config CEC_PIN - bool - source "drivers/media/rc/Kconfig" menuconfig MEDIA_SUPPORT diff --git a/drivers/media/cec/Kconfig b/drivers/media/cec/Kconfig index c01919713ab9..31417feaa213 100644 --- a/drivers/media/cec/Kconfig +++ b/drivers/media/cec/Kconfig @@ -1,4 +1,14 @@ # SPDX-License-Identifier: GPL-2.0-only + +config CEC_CORE + tristate + +config CEC_NOTIFIER + bool + +config CEC_PIN + bool + config MEDIA_CEC_RC bool "HDMI CEC RC integration" depends on CEC_CORE && RC_CORE -- cgit v1.2.3 From 10713a9420403837ea55d5bbf8650dab36841ae6 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 24 Mar 2020 13:47:11 +0100 Subject: media: Kconfig: move DVB-specific options to dvb-core/Kconfig In order to cleanup the main media Kconfig, move the DVB-core specific options to dvb-core/Kconfig. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/Kconfig | 21 --------------------- drivers/media/dvb-core/Kconfig | 26 ++++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 21 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index 9cc528e0b120..dda449556f22 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -161,31 +161,10 @@ config DVB_CORE default y select CRC32 -config DVB_MMAP - bool "Enable DVB memory-mapped API (EXPERIMENTAL)" - depends on DVB_CORE - depends on VIDEO_V4L2=y || VIDEO_V4L2=DVB_CORE - select VIDEOBUF2_VMALLOC help - This option enables DVB experimental memory-mapped API, which - reduces the number of context switches to read DVB buffers, as - the buffers can use mmap() syscalls. - Support for it is experimental. Use with care. If unsure, - say N. -config DVB_NET - bool "DVB Network Support" - default (NET && INET) - depends on NET && INET && DVB_CORE - help - This option enables DVB Network Support which is a part of the DVB - standard. It is used, for example, by automatic firmware updates used - on Set-Top-Boxes. It can also be used to access the Internet via the - DVB card, if the network provider supports it. - You may want to disable the network support on embedded devices. If - unsure say Y. source "drivers/media/v4l2-core/Kconfig" source "drivers/media/mc/Kconfig" diff --git a/drivers/media/dvb-core/Kconfig b/drivers/media/dvb-core/Kconfig index 61f9e1ce99cb..6ffac618417b 100644 --- a/drivers/media/dvb-core/Kconfig +++ b/drivers/media/dvb-core/Kconfig @@ -3,6 +3,32 @@ # DVB device configuration # +config DVB_MMAP + bool "Enable DVB memory-mapped API (EXPERIMENTAL)" + depends on DVB_CORE + depends on VIDEO_V4L2=y || VIDEO_V4L2=DVB_CORE + select VIDEOBUF2_VMALLOC + help + This option enables DVB experimental memory-mapped API, which + reduces the number of context switches to read DVB buffers, as + the buffers can use mmap() syscalls. + + Support for it is experimental. Use with care. If unsure, + say N. + +config DVB_NET + bool "DVB Network Support" + default (NET && INET) + depends on NET && INET && DVB_CORE + help + This option enables DVB Network Support which is a part of the DVB + standard. It is used, for example, by automatic firmware updates used + on Set-Top-Boxes. It can also be used to access the Internet via the + DVB card, if the network provider supports it. + + You may want to disable the network support on embedded devices. If + unsure say Y. + config DVB_MAX_ADAPTERS int "maximum number of DVB/ATSC adapters" depends on DVB_CORE -- cgit v1.2.3 From 8164ab872115396ed8329f25a643bcc87500867d Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 24 Mar 2020 13:50:33 +0100 Subject: media: Kconfig: move V4L2 subdev API to v4l2-core/Kconfig This option is part of V4L2 API extra functionality set. Move it to be at the v4l2-core/Kconfig, where it belongs, cleaning the main Kconfig file. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/Kconfig | 9 --------- drivers/media/v4l2-core/Kconfig | 9 +++++++++ 2 files changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index dda449556f22..f14b583c9ee1 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -136,15 +136,6 @@ config VIDEO_DEV prompt "Video4Linux core" if !(MEDIA_HYBRID_USB || MEDIA_HYBRID_PCI) default MEDIA_CAMERA_SUPPORT || MEDIA_ANALOG_TV_SUPPORT || MEDIA_RADIO_SUPPORT || MEDIA_SDR_SUPPORT || MEDIA_PLATFORM_SUPPORT || MEDIA_TEST_SUPPORT || MEDIA_HYBRID_USB || MEDIA_HYBRID_PCI -config VIDEO_V4L2_SUBDEV_API - bool "V4L2 sub-device userspace API" - depends on VIDEO_DEV && MEDIA_CONTROLLER - help - Enables the V4L2 sub-device pad-level userspace API used to configure - video format, size and frame rate between hardware blocks. - - This API is mostly used by camera interfaces in embedded platforms. - # # DVB Core # Only enables if one of DTV is selected diff --git a/drivers/media/v4l2-core/Kconfig b/drivers/media/v4l2-core/Kconfig index 26276b257eae..33aa7fe571f8 100644 --- a/drivers/media/v4l2-core/Kconfig +++ b/drivers/media/v4l2-core/Kconfig @@ -16,6 +16,15 @@ config VIDEO_V4L2_I2C depends on I2C && VIDEO_V4L2 default y +config VIDEO_V4L2_SUBDEV_API + bool "V4L2 sub-device userspace API" + depends on VIDEO_DEV && MEDIA_CONTROLLER + help + Enables the V4L2 sub-device pad-level userspace API used to configure + video format, size and frame rate between hardware blocks. + + This API is mostly used by camera interfaces in embedded platforms. + config VIDEO_ADV_DEBUG bool "Enable advanced debug functionality on V4L2 drivers" help -- cgit v1.2.3 From 8fc42fff164b92dbea1961533875730314e8fe34 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 24 Mar 2020 13:59:23 +0100 Subject: media: Kconfig: move media controller core select to main Kconfig Let's place the main API selections at the media/Kconfig file, as this way we can better organize things. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/Kconfig | 9 +++++++++ drivers/media/mc/Kconfig | 9 --------- 2 files changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index f14b583c9ee1..9c1de28ef070 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -136,6 +136,15 @@ config VIDEO_DEV prompt "Video4Linux core" if !(MEDIA_HYBRID_USB || MEDIA_HYBRID_PCI) default MEDIA_CAMERA_SUPPORT || MEDIA_ANALOG_TV_SUPPORT || MEDIA_RADIO_SUPPORT || MEDIA_SDR_SUPPORT || MEDIA_PLATFORM_SUPPORT || MEDIA_TEST_SUPPORT || MEDIA_HYBRID_USB || MEDIA_HYBRID_PCI +config MEDIA_CONTROLLER + bool "Media Controller API" + default MEDIA_CAMERA_SUPPORT || MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT || MEDIA_PLATFORM_SUPPORT + help + Enable the media controller API used to query media devices internal + topology and configure it dynamically. + + This API is mostly used by camera interfaces in embedded platforms. + # # DVB Core # Only enables if one of DTV is selected diff --git a/drivers/media/mc/Kconfig b/drivers/media/mc/Kconfig index e740ace54d7f..002a918c4c75 100644 --- a/drivers/media/mc/Kconfig +++ b/drivers/media/mc/Kconfig @@ -5,15 +5,6 @@ # Selectable only for webcam/grabbers, as other drivers don't use it # -config MEDIA_CONTROLLER - bool "Media Controller API" - default MEDIA_CAMERA_SUPPORT || MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT || MEDIA_PLATFORM_SUPPORT - help - Enable the media controller API used to query media devices internal - topology and configure it dynamically. - - This API is mostly used by camera interfaces in embedded platforms. - config MEDIA_CONTROLLER_DVB bool "Enable Media controller for DVB (EXPERIMENTAL)" depends on MEDIA_CONTROLLER && DVB_CORE -- cgit v1.2.3 From 5e9e60f4214153e66217310b55ca52946181c933 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 24 Mar 2020 14:09:23 +0100 Subject: media: Kconfig: place all options under a sub-menu That should make easier for people setting the media subsystem config options, as they'll be split by the type of functionality that will be enabled. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/Kconfig | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index 9c1de28ef070..c95b534c5d40 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -121,12 +121,9 @@ config MEDIA_TEST_SUPPORT Say Y when you have a software defined radio device. endmenu # media device types -comment "Multimedia core features" -# -# Video4Linux support -# Only enables if one of the V4L2 types (ATV, webcam, radio) is selected -# +menu "Media core support" + visible if !MEDIA_SUPPORT_FILTER comment "Video4Linux core enabled to support hybrid TV devices" depends on MEDIA_HYBRID_USB || MEDIA_HYBRID_PCI @@ -135,6 +132,9 @@ config VIDEO_DEV tristate prompt "Video4Linux core" if !(MEDIA_HYBRID_USB || MEDIA_HYBRID_PCI) default MEDIA_CAMERA_SUPPORT || MEDIA_ANALOG_TV_SUPPORT || MEDIA_RADIO_SUPPORT || MEDIA_SDR_SUPPORT || MEDIA_PLATFORM_SUPPORT || MEDIA_TEST_SUPPORT || MEDIA_HYBRID_USB || MEDIA_HYBRID_PCI + help + Enables the V4L2 API, used by cameras, analog TV, video grabbers, + radio devices and by some input devices. config MEDIA_CONTROLLER bool "Media Controller API" @@ -158,20 +158,24 @@ config DVB_CORE prompt "Digital TV core" if !(MEDIA_HYBRID_USB || MEDIA_HYBRID_PCI) depends on MEDIA_DIGITAL_TV_SUPPORT depends on (I2C || I2C=n) - default y select CRC32 - help + Enables the DVB API, used by Digital TV devices. Supports several + standards, including DVB, ATSC, ISDB and CMDB. +endmenu # Media core support +# +# Extra per-media API core functionality - +menu "Media core additional options" source "drivers/media/v4l2-core/Kconfig" source "drivers/media/mc/Kconfig" source "drivers/media/dvb-core/Kconfig" source "drivers/media/cec/Kconfig" +endmenu -comment "Media drivers" +menu "Media drivers" comment "Drivers filtered as selected at 'Filter media drivers'" depends on MEDIA_SUPPORT_FILTER @@ -191,7 +195,9 @@ endif source "drivers/media/firewire/Kconfig" -comment "Media ancillary drivers (tuners, sensors, i2c, spi, frontends)" +endmenu + +menu "Media ancillary drivers (tuners, sensors, i2c, spi, frontends)" # # Ancillary drivers (tuners, i2c, spi, frontends) @@ -236,4 +242,6 @@ source "drivers/media/spi/Kconfig" source "drivers/media/tuners/Kconfig" source "drivers/media/dvb-frontends/Kconfig" +endmenu + endif # MEDIA_SUPPORT -- cgit v1.2.3 From 1b80d36aeb92a767da8c75eb0118cfe4b34b840c Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 24 Mar 2020 14:24:41 +0100 Subject: media: Kconfig: move the position of sub-driver autoselection Let's place the sub-driver-autoselection option just below the device filtering one, as it also controls a filter menu, with is not even visible if !EXPERT && !EMBEDDED. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/Kconfig | 50 +++++++++++++++++++++++++------------------------- 1 file changed, 25 insertions(+), 25 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index c95b534c5d40..db918a89e40e 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -33,6 +33,28 @@ config MEDIA_SUPPORT_FILTER needed to support media drivers will be enabled. Also, all media device drivers should be shown. +config MEDIA_SUBDRV_AUTOSELECT + bool "Autoselect ancillary drivers (tuners, sensors, i2c, spi, frontends)" + depends on HAS_IOMEM + select I2C + select I2C_MUX + default y if MEDIA_SUPPORT_FILTER + help + By default, a media driver auto-selects all possible ancillary + devices such as tuners, sensors, video encoders/decoders and + frontends, that are used by any of the supported devices. + + This is generally the right thing to do, except when there + are strict constraints with regards to the kernel size, + like on embedded systems. + + Use this option with care, as deselecting ancillary drivers which + are, in fact, necessary will result in the lack of the needed + functionality for your device (it may not tune or may not have + the needed demodulators). + + If unsure say Y. + menu "Media device types" visible if MEDIA_SUPPORT_FILTER @@ -197,40 +219,18 @@ source "drivers/media/firewire/Kconfig" endmenu -menu "Media ancillary drivers (tuners, sensors, i2c, spi, frontends)" - # # Ancillary drivers (tuners, i2c, spi, frontends) # -config MEDIA_SUBDRV_AUTOSELECT - bool "Autoselect ancillary drivers (tuners, sensors, i2c, spi, frontends)" - depends on MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT || MEDIA_CAMERA_SUPPORT || MEDIA_SDR_SUPPORT - depends on HAS_IOMEM - select I2C - select I2C_MUX - default y if !EMBEDDED - help - By default, a media driver auto-selects all possible ancillary - devices such as tuners, sensors, video encoders/decoders and - frontends, that are used by any of the supported devices. - - This is generally the right thing to do, except when there - are strict constraints with regards to the kernel size, - like on embedded systems. - - Use this option with care, as deselecting ancillary drivers which - are, in fact, necessary will result in the lack of the needed - functionality for your device (it may not tune or may not have - the needed demodulators). - - If unsure say Y. - config MEDIA_HIDE_ANCILLARY_SUBDRV bool depends on MEDIA_SUBDRV_AUTOSELECT && !COMPILE_TEST && !EXPERT default y +menu "Media ancillary drivers" + visible if !MEDIA_HIDE_ANCILLARY_SUBDRV + config MEDIA_ATTACH bool depends on MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT || MEDIA_RADIO_SUPPORT -- cgit v1.2.3 From b0cd4fb276653f8f18cdbc1bcc041a4227bdb9da Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 24 Mar 2020 14:29:57 +0100 Subject: media: Kconfig: on !EMBEDDED && !EXPERT, enable driver filtering Advanced and embedded users know what to do, so, by default, they will likely want to be able to open the entire set of Kconfig media options. Normal "poor" users usually needs more help when setting stuff, so let's open an more simplified version to them by default. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/media') diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index db918a89e40e..913903c8e942 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -21,6 +21,7 @@ if MEDIA_SUPPORT config MEDIA_SUPPORT_FILTER bool "Filter media drivers" depends on MEDIA_SUPPORT + default y if !EMBEDDED && !EXPERT help Configuring the media subsystem can be complex, as there are hundreds of drivers and other config options. -- cgit v1.2.3 From 0c822d97bd1450034576a8331b92d7e912326551 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 25 Mar 2020 11:15:15 +0100 Subject: media: Kconfig: Better organize the per-API options After this change, the menu is displayed like above. 1) When filtering is not active: --- Multimedia support [ ] Filter devices by their types [*] Autoselect ancillary drivers (tuners, sensors, i2c, spi, frontends) Media core support ---> Video4Linux options ---> Media controller options ---> Digital TV options ---> HDMI CEC options ---> Media drivers ---> 2) When filtering is active: --- Multimedia support [*] Filter devices by their types [*] Autoselect ancillary drivers (tuners, sensors, i2c, spi, frontends) Media device types ---> Video4Linux options ---> Media controller options ---> Digital TV options ---> HDMI CEC options ---> Media drivers ---> The per-API menu will only be displayed if the corresponding core support is enabled. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/Kconfig | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) (limited to 'drivers/media') diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index 913903c8e942..382366b8ab46 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -191,10 +191,27 @@ endmenu # Media core support # # Extra per-media API core functionality -menu "Media core additional options" +menu "Video4Linux options" + visible if VIDEO_DEV + source "drivers/media/v4l2-core/Kconfig" +endmenu + +menu "Media controller options" + visible if MEDIA_CONTROLLER + source "drivers/media/mc/Kconfig" +endmenu + +menu "Digital TV options" + visible if DVB_CORE + source "drivers/media/dvb-core/Kconfig" +endmenu + +menu "HDMI CEC options" + visible if CEC_CORE + source "drivers/media/cec/Kconfig" endmenu -- cgit v1.2.3 From f48fd1514212b5c72b98db79efee4ed914acf662 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 25 Mar 2020 15:56:15 +0100 Subject: media: i2c/Kconfig: reorganize items there Right now, there are I2C drivers that don't depend on camera support before and after those. Move the camera support drivers to the end, and add a notice at the "endif", in order to make easier to maintain and to avoid adding extra dependencies at the other i2c/*/Kconfig files. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/Kconfig | 216 +++++++++++++++++++++++----------------------- 1 file changed, 106 insertions(+), 110 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 4bc4cfea2f20..efd12bf4f8eb 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -581,13 +581,106 @@ config VIDEO_THS8200 To compile this driver as a module, choose M here: the module will be called ths8200. -comment "Camera sensor devices" +comment "Video improvement chips" -config VIDEO_APTINA_PLL - tristate +config VIDEO_UPD64031A + tristate "NEC Electronics uPD64031A Ghost Reduction" + depends on VIDEO_V4L2 && I2C + help + Support for the NEC Electronics uPD64031A Ghost Reduction + video chip. It is most often found in NTSC TV cards made for + Japan and is used to reduce the 'ghosting' effect that can + be present in analog TV broadcasts. -config VIDEO_SMIAPP_PLL - tristate + To compile this driver as a module, choose M here: the + module will be called upd64031a. + +config VIDEO_UPD64083 + tristate "NEC Electronics uPD64083 3-Dimensional Y/C separation" + depends on VIDEO_V4L2 && I2C + help + Support for the NEC Electronics uPD64083 3-Dimensional Y/C + separation video chip. It is used to improve the quality of + the colors of a composite signal. + + To compile this driver as a module, choose M here: the + module will be called upd64083. + +comment "Audio/Video compression chips" + +config VIDEO_SAA6752HS + tristate "Philips SAA6752HS MPEG-2 Audio/Video Encoder" + depends on VIDEO_V4L2 && I2C + select CRC32 + help + Support for the Philips SAA6752HS MPEG-2 video and MPEG-audio/AC-3 + audio encoder with multiplexer. + + To compile this driver as a module, choose M here: the + module will be called saa6752hs. + +comment "SDR tuner chips" + +config SDR_MAX2175 + tristate "Maxim 2175 RF to Bits tuner" + depends on VIDEO_V4L2 && MEDIA_SDR_SUPPORT && I2C + select REGMAP_I2C + help + Support for Maxim 2175 tuner. It is an advanced analog/digital + radio receiver with RF-to-Bits front-end designed for SDR solutions. + + To compile this driver as a module, choose M here; the + module will be called max2175. + +comment "Miscellaneous helper chips" + +config VIDEO_THS7303 + tristate "THS7303/53 Video Amplifier" + depends on VIDEO_V4L2 && I2C + help + Support for TI THS7303/53 video amplifier + + To compile this driver as a module, choose M here: the + module will be called ths7303. + +config VIDEO_M52790 + tristate "Mitsubishi M52790 A/V switch" + depends on VIDEO_V4L2 && I2C + help + Support for the Mitsubishi M52790 A/V switch. + + To compile this driver as a module, choose M here: the + module will be called m52790. + +config VIDEO_I2C + tristate "I2C transport video support" + depends on VIDEO_V4L2 && I2C + select VIDEOBUF2_VMALLOC + imply HWMON + help + Enable the I2C transport video support which supports the + following: + * Panasonic AMG88xx Grid-Eye Sensors + * Melexis MLX90640 Thermal Cameras + + To compile this driver as a module, choose M here: the + module will be called video-i2c + +config VIDEO_ST_MIPID02 + tristate "STMicroelectronics MIPID02 CSI-2 to PARALLEL bridge" + depends on I2C && VIDEO_V4L2 + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API + select V4L2_FWNODE + help + Support for STMicroelectronics MIPID02 CSI-2 to PARALLEL bridge. + It is used to allow usage of CSI-2 sensor with PARALLEL port + controller. + + To compile this driver as a module, choose M here: the + module will be called st-mipid02. + +endmenu # # All drivers that are related to Media Camera Support should be here @@ -595,6 +688,14 @@ config VIDEO_SMIAPP_PLL if MEDIA_CAMERA_SUPPORT +comment "Camera sensor devices" + +config VIDEO_APTINA_PLL + tristate + +config VIDEO_SMIAPP_PLL + tristate + config VIDEO_HI556 tristate "Hynix Hi-556 sensor support" depends on I2C && VIDEO_V4L2 @@ -1162,109 +1263,4 @@ config VIDEO_LM3646 endif # MEDIA_CAMERA_SUPPORT -# -# Other V4L2 drivers that aren't related with Camera support -# - -comment "Video improvement chips" - -config VIDEO_UPD64031A - tristate "NEC Electronics uPD64031A Ghost Reduction" - depends on VIDEO_V4L2 && I2C - help - Support for the NEC Electronics uPD64031A Ghost Reduction - video chip. It is most often found in NTSC TV cards made for - Japan and is used to reduce the 'ghosting' effect that can - be present in analog TV broadcasts. - - To compile this driver as a module, choose M here: the - module will be called upd64031a. - -config VIDEO_UPD64083 - tristate "NEC Electronics uPD64083 3-Dimensional Y/C separation" - depends on VIDEO_V4L2 && I2C - help - Support for the NEC Electronics uPD64083 3-Dimensional Y/C - separation video chip. It is used to improve the quality of - the colors of a composite signal. - - To compile this driver as a module, choose M here: the - module will be called upd64083. - -comment "Audio/Video compression chips" - -config VIDEO_SAA6752HS - tristate "Philips SAA6752HS MPEG-2 Audio/Video Encoder" - depends on VIDEO_V4L2 && I2C - select CRC32 - help - Support for the Philips SAA6752HS MPEG-2 video and MPEG-audio/AC-3 - audio encoder with multiplexer. - - To compile this driver as a module, choose M here: the - module will be called saa6752hs. - -comment "SDR tuner chips" - -config SDR_MAX2175 - tristate "Maxim 2175 RF to Bits tuner" - depends on VIDEO_V4L2 && MEDIA_SDR_SUPPORT && I2C - select REGMAP_I2C - help - Support for Maxim 2175 tuner. It is an advanced analog/digital - radio receiver with RF-to-Bits front-end designed for SDR solutions. - - To compile this driver as a module, choose M here; the - module will be called max2175. - -comment "Miscellaneous helper chips" - -config VIDEO_THS7303 - tristate "THS7303/53 Video Amplifier" - depends on VIDEO_V4L2 && I2C - help - Support for TI THS7303/53 video amplifier - - To compile this driver as a module, choose M here: the - module will be called ths7303. - -config VIDEO_M52790 - tristate "Mitsubishi M52790 A/V switch" - depends on VIDEO_V4L2 && I2C - help - Support for the Mitsubishi M52790 A/V switch. - - To compile this driver as a module, choose M here: the - module will be called m52790. - -config VIDEO_I2C - tristate "I2C transport video support" - depends on VIDEO_V4L2 && I2C - select VIDEOBUF2_VMALLOC - imply HWMON - help - Enable the I2C transport video support which supports the - following: - * Panasonic AMG88xx Grid-Eye Sensors - * Melexis MLX90640 Thermal Cameras - - To compile this driver as a module, choose M here: the - module will be called video-i2c - -config VIDEO_ST_MIPID02 - tristate "STMicroelectronics MIPID02 CSI-2 to PARALLEL bridge" - depends on I2C && VIDEO_V4L2 - select MEDIA_CONTROLLER - select VIDEO_V4L2_SUBDEV_API - select V4L2_FWNODE - help - Support for STMicroelectronics MIPID02 CSI-2 to PARALLEL bridge. - It is used to allow usage of CSI-2 sensor with PARALLEL port - controller. - - To compile this driver as a module, choose M here: the - module will be called st-mipid02. - -endmenu - endif # VIDEO_V4L2 -- cgit v1.2.3 From b6a7d1bcc55fd297ad4bf341237f08ca989adf93 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 25 Mar 2020 16:33:35 +0100 Subject: media: Kconfig: don't use visible for device type select While making the menu invisible seemed a good idea, there's a drawback: when the menu is not visible, it is not parsing the "default" dependency. So, instead, let's just avoid the items at the menu to be prompted, by using the "prompt ... if" construction. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/Kconfig | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index 382366b8ab46..0972a42e7e0c 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -57,13 +57,13 @@ config MEDIA_SUBDRV_AUTOSELECT If unsure say Y. menu "Media device types" - visible if MEDIA_SUPPORT_FILTER # # Multimedia support - automatically enable V4L2 and DVB core # config MEDIA_CAMERA_SUPPORT - bool "Cameras and video grabbers" + bool + prompt "Cameras and video grabbers" if MEDIA_SUPPORT_FILTER default y if !MEDIA_SUPPORT_FILTER help Enable support for webcams and video grabbers. @@ -71,7 +71,8 @@ config MEDIA_CAMERA_SUPPORT Say Y when you have a webcam or a video capture grabber board. config MEDIA_ANALOG_TV_SUPPORT - bool "Analog TV" + bool + prompt "Analog TV" if MEDIA_SUPPORT_FILTER default y if !MEDIA_SUPPORT_FILTER help Enable analog TV support. @@ -79,7 +80,8 @@ config MEDIA_ANALOG_TV_SUPPORT Say Y when you have a board with analog TV support. config MEDIA_DIGITAL_TV_SUPPORT - bool "Digital TV" + bool + prompt "Digital TV" if MEDIA_SUPPORT_FILTER default y if !MEDIA_SUPPORT_FILTER help Enable digital TV support. @@ -87,7 +89,8 @@ config MEDIA_DIGITAL_TV_SUPPORT Say Y when you have a board with digital TV support. config MEDIA_RADIO_SUPPORT - bool "AM/FM radio receivers/transmitters" + bool + prompt "AM/FM radio receivers/transmitters" if MEDIA_SUPPORT_FILTER default y if !MEDIA_SUPPORT_FILTER help Enable AM/FM radio support. @@ -98,7 +101,8 @@ config MEDIA_RADIO_SUPPORT Say Y when you have a board with radio support. config MEDIA_SDR_SUPPORT - bool "Software defined radio" + bool + prompt "Software defined radio" if MEDIA_SUPPORT_FILTER default y if !MEDIA_SUPPORT_FILTER help Enable software defined radio support. @@ -106,7 +110,8 @@ config MEDIA_SDR_SUPPORT Say Y when you have a software defined radio device. config MEDIA_CEC_SUPPORT - bool "HDMI CEC" + bool + prompt "HDMI CEC support" if MEDIA_SUPPORT_FILTER default y if !MEDIA_SUPPORT_FILTER help Enable support for HDMI CEC (Consumer Electronics Control), @@ -116,7 +121,8 @@ config MEDIA_CEC_SUPPORT adapter that supports HDMI CEC. config MEDIA_PLATFORM_SUPPORT - bool "Platform-specific devices" + bool + prompt "Platform-specific devices" if MEDIA_SUPPORT_FILTER default y if !MEDIA_SUPPORT_FILTER help Enable support for complex cameras, codecs, and other hardware @@ -129,7 +135,8 @@ config MEDIA_PLATFORM_SUPPORT Say Y when you want to be able so see such devices. config MEDIA_TEST_SUPPORT - bool "Test drivers" + bool + prompt "Test drivers" if MEDIA_SUPPORT_FILTER default y if !MEDIA_SUPPORT_FILTER help Those drivers should not be used on production Kernels, but -- cgit v1.2.3 From 087362d96356c213b1b1cfc835951c91a04ed433 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 6 Mar 2020 06:26:59 +0100 Subject: media: docs: cx18-streams.c: fix broken references to docs There are two places inside this file that points to the cx2341x documentation, with was split into two. Looking at changeset dcc0ef88209a ("V4L/DVB (10442): cx18: Fixes for enforcing when Encoder Raw VBI params can be set") with added those comments, it was originally pointing to: Documentation/video4linux/cx2341x/fw-encoder-api.txt Well, the firmware details went to Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx18/cx18-streams.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/media') diff --git a/drivers/media/pci/cx18/cx18-streams.c b/drivers/media/pci/cx18/cx18-streams.c index 3178df3c4922..0e2365c9f4ad 100644 --- a/drivers/media/pci/cx18/cx18-streams.c +++ b/drivers/media/pci/cx18/cx18-streams.c @@ -845,7 +845,7 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s) /* * Audio related reset according to - * Documentation/media/v4l-drivers/cx2341x.rst + * Documentation/media/v4l-drivers/cx2341x-devel.rst */ if (atomic_read(&cx->ana_capturing) == 0) cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 2, @@ -853,7 +853,7 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s) /* * Number of lines for Field 1 & Field 2 according to - * Documentation/media/v4l-drivers/cx2341x.rst + * Documentation/media/v4l-drivers/cx2341x-devel.rst * Field 1 is 312 for 625 line systems in BT.656 * Field 2 is 313 for 625 line systems in BT.656 */ -- cgit v1.2.3 From 54f38fcae536ea202ce7d6a359521492fba30c1f Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 4 Mar 2020 10:21:39 +0100 Subject: media: docs: move uAPI book to userspace-api/media Since 2017, there is an space reserved for userspace API, created by changeset 1d596dee3862 ("docs: Create a user-space API guide"). As the media subsystem was one of the first subsystems to use Sphinx, until this patch, we were keeping things on a separate place. Let's just use the new location, as having all uAPI altogether will likely make things easier for developers. Signed-off-by: Mauro Carvalho Chehab --- Documentation/ABI/testing/debugfs-cec-error-inj | 2 +- Documentation/Makefile | 10 +- Documentation/doc-guide/parse-headers.rst | 2 +- Documentation/fb/api.rst | 4 +- Documentation/media/Makefile | 69 - Documentation/media/audio.h.rst.exceptions | 19 - Documentation/media/ca.h.rst.exceptions | 25 - Documentation/media/cec.h.rst.exceptions | 575 -- Documentation/media/conf_nitpick.py | 111 - Documentation/media/dmx.h.rst.exceptions | 66 - Documentation/media/frontend.h.rst.exceptions | 214 - Documentation/media/index.rst | 2 +- Documentation/media/intro.rst | 46 - Documentation/media/lirc.h.rst.exceptions | 80 - Documentation/media/media.h.rst.exceptions | 32 - Documentation/media/media_uapi.rst | 33 - Documentation/media/net.h.rst.exceptions | 13 - Documentation/media/typical_media_device.svg | 116 - Documentation/media/uapi/cec/cec-api.rst | 54 - Documentation/media/uapi/cec/cec-func-close.rst | 54 - Documentation/media/uapi/cec/cec-func-ioctl.rst | 73 - Documentation/media/uapi/cec/cec-func-open.rst | 85 - Documentation/media/uapi/cec/cec-func-poll.rst | 85 - Documentation/media/uapi/cec/cec-funcs.rst | 30 - Documentation/media/uapi/cec/cec-header.rst | 17 - Documentation/media/uapi/cec/cec-intro.rst | 49 - .../media/uapi/cec/cec-ioc-adap-g-caps.rst | 150 - .../media/uapi/cec/cec-ioc-adap-g-conn-info.rst | 105 - .../media/uapi/cec/cec-ioc-adap-g-log-addrs.rst | 378 - .../media/uapi/cec/cec-ioc-adap-g-phys-addr.rst | 100 - Documentation/media/uapi/cec/cec-ioc-dqevent.rst | 257 - Documentation/media/uapi/cec/cec-ioc-g-mode.rst | 301 - Documentation/media/uapi/cec/cec-ioc-receive.rst | 391 - Documentation/media/uapi/cec/cec-pin-error-inj.rst | 334 - .../uapi/dvb/audio-bilingual-channel-select.rst | 66 - .../media/uapi/dvb/audio-channel-select.rst | 66 - .../media/uapi/dvb/audio-clear-buffer.rst | 55 - Documentation/media/uapi/dvb/audio-continue.rst | 56 - Documentation/media/uapi/dvb/audio-fclose.rst | 63 - Documentation/media/uapi/dvb/audio-fopen.rst | 115 - Documentation/media/uapi/dvb/audio-fwrite.rst | 91 - .../media/uapi/dvb/audio-get-capabilities.rst | 63 - Documentation/media/uapi/dvb/audio-get-status.rst | 63 - Documentation/media/uapi/dvb/audio-pause.rst | 57 - Documentation/media/uapi/dvb/audio-play.rst | 56 - .../media/uapi/dvb/audio-select-source.rst | 65 - Documentation/media/uapi/dvb/audio-set-av-sync.rst | 67 - .../media/uapi/dvb/audio-set-bypass-mode.rst | 70 - Documentation/media/uapi/dvb/audio-set-id.rst | 67 - Documentation/media/uapi/dvb/audio-set-mixer.rst | 61 - Documentation/media/uapi/dvb/audio-set-mute.rst | 71 - .../media/uapi/dvb/audio-set-streamtype.rst | 77 - Documentation/media/uapi/dvb/audio-stop.rst | 56 - Documentation/media/uapi/dvb/audio.rst | 34 - Documentation/media/uapi/dvb/audio_data_types.rst | 123 - .../media/uapi/dvb/audio_function_calls.rst | 37 - Documentation/media/uapi/dvb/ca-fclose.rst | 50 - Documentation/media/uapi/dvb/ca-fopen.rst | 84 - Documentation/media/uapi/dvb/ca-get-cap.rst | 53 - Documentation/media/uapi/dvb/ca-get-descr-info.rst | 49 - Documentation/media/uapi/dvb/ca-get-msg.rst | 59 - Documentation/media/uapi/dvb/ca-get-slot-info.rst | 64 - Documentation/media/uapi/dvb/ca-reset.rst | 51 - Documentation/media/uapi/dvb/ca-send-msg.rst | 58 - Documentation/media/uapi/dvb/ca-set-descr.rst | 53 - Documentation/media/uapi/dvb/ca.rst | 32 - Documentation/media/uapi/dvb/ca_data_types.rst | 16 - Documentation/media/uapi/dvb/ca_function_calls.rst | 27 - Documentation/media/uapi/dvb/ca_high_level.rst | 157 - Documentation/media/uapi/dvb/demux.rst | 30 - Documentation/media/uapi/dvb/dmx-add-pid.rst | 56 - Documentation/media/uapi/dvb/dmx-expbuf.rst | 97 - Documentation/media/uapi/dvb/dmx-fclose.rst | 52 - Documentation/media/uapi/dvb/dmx-fopen.rst | 98 - Documentation/media/uapi/dvb/dmx-fread.rst | 87 - Documentation/media/uapi/dvb/dmx-fwrite.rst | 79 - Documentation/media/uapi/dvb/dmx-get-pes-pids.rst | 71 - Documentation/media/uapi/dvb/dmx-get-stc.rst | 73 - Documentation/media/uapi/dvb/dmx-mmap.rst | 125 - Documentation/media/uapi/dvb/dmx-munmap.rst | 63 - Documentation/media/uapi/dvb/dmx-qbuf.rst | 93 - Documentation/media/uapi/dvb/dmx-querybuf.rst | 72 - Documentation/media/uapi/dvb/dmx-remove-pid.rst | 57 - Documentation/media/uapi/dvb/dmx-reqbufs.rst | 83 - .../media/uapi/dvb/dmx-set-buffer-size.rst | 57 - Documentation/media/uapi/dvb/dmx-set-filter.rst | 64 - .../media/uapi/dvb/dmx-set-pes-filter.rst | 76 - Documentation/media/uapi/dvb/dmx-start.rst | 75 - Documentation/media/uapi/dvb/dmx-stop.rst | 52 - Documentation/media/uapi/dvb/dmx_fcalls.rst | 37 - Documentation/media/uapi/dvb/dmx_types.rst | 16 - .../media/uapi/dvb/dvb-fe-read-status.rst | 32 - .../media/uapi/dvb/dvb-frontend-event.rst | 22 - .../media/uapi/dvb/dvb-frontend-parameters.rst | 126 - Documentation/media/uapi/dvb/dvbapi.rst | 126 - Documentation/media/uapi/dvb/dvbproperty.rst | 133 - Documentation/media/uapi/dvb/dvbstb.svg | 43 - Documentation/media/uapi/dvb/examples.rst | 23 - Documentation/media/uapi/dvb/fe-bandwidth-t.rst | 81 - .../media/uapi/dvb/fe-diseqc-recv-slave-reply.rst | 55 - .../media/uapi/dvb/fe-diseqc-reset-overload.rst | 53 - .../media/uapi/dvb/fe-diseqc-send-burst.rst | 59 - .../media/uapi/dvb/fe-diseqc-send-master-cmd.rst | 56 - .../uapi/dvb/fe-dishnetwork-send-legacy-cmd.rst | 62 - .../media/uapi/dvb/fe-enable-high-lnb-voltage.rst | 61 - Documentation/media/uapi/dvb/fe-get-event.rst | 78 - Documentation/media/uapi/dvb/fe-get-frontend.rst | 69 - Documentation/media/uapi/dvb/fe-get-info.rst | 70 - Documentation/media/uapi/dvb/fe-get-property.rst | 83 - Documentation/media/uapi/dvb/fe-read-ber.rst | 57 - .../media/uapi/dvb/fe-read-signal-strength.rst | 57 - Documentation/media/uapi/dvb/fe-read-snr.rst | 57 - Documentation/media/uapi/dvb/fe-read-status.rst | 72 - .../media/uapi/dvb/fe-read-uncorrected-blocks.rst | 59 - .../media/uapi/dvb/fe-set-frontend-tune-mode.rst | 64 - Documentation/media/uapi/dvb/fe-set-frontend.rst | 78 - Documentation/media/uapi/dvb/fe-set-tone.rst | 65 - Documentation/media/uapi/dvb/fe-set-voltage.rst | 69 - Documentation/media/uapi/dvb/fe-type-t.rst | 98 - .../media/uapi/dvb/fe_property_parameters.rst | 1014 --- Documentation/media/uapi/dvb/frontend-header.rst | 13 - .../uapi/dvb/frontend-property-cable-systems.rst | 82 - .../dvb/frontend-property-satellite-systems.rst | 112 - .../dvb/frontend-property-terrestrial-systems.rst | 301 - .../media/uapi/dvb/frontend-stat-properties.rst | 252 - Documentation/media/uapi/dvb/frontend.rst | 63 - Documentation/media/uapi/dvb/frontend_f_close.rst | 57 - Documentation/media/uapi/dvb/frontend_f_open.rst | 117 - Documentation/media/uapi/dvb/frontend_fcalls.rst | 31 - .../media/uapi/dvb/frontend_legacy_api.rst | 45 - .../media/uapi/dvb/frontend_legacy_dvbv3_api.rst | 25 - Documentation/media/uapi/dvb/headers.rst | 30 - Documentation/media/uapi/dvb/intro.rst | 190 - Documentation/media/uapi/dvb/legacy_dvb_apis.rst | 39 - Documentation/media/uapi/dvb/net-add-if.rst | 60 - Documentation/media/uapi/dvb/net-get-if.rst | 59 - Documentation/media/uapi/dvb/net-remove-if.rst | 55 - Documentation/media/uapi/dvb/net-types.rst | 16 - Documentation/media/uapi/dvb/net.rst | 48 - .../media/uapi/dvb/query-dvb-frontend-info.rst | 20 - .../media/uapi/dvb/video-clear-buffer.rst | 63 - Documentation/media/uapi/dvb/video-command.rst | 105 - Documentation/media/uapi/dvb/video-continue.rst | 66 - .../media/uapi/dvb/video-fast-forward.rst | 83 - Documentation/media/uapi/dvb/video-fclose.rst | 62 - Documentation/media/uapi/dvb/video-fopen.rst | 122 - Documentation/media/uapi/dvb/video-freeze.rst | 70 - Documentation/media/uapi/dvb/video-fwrite.rst | 90 - .../media/uapi/dvb/video-get-capabilities.rst | 70 - Documentation/media/uapi/dvb/video-get-event.rst | 114 - .../media/uapi/dvb/video-get-frame-count.rst | 74 - Documentation/media/uapi/dvb/video-get-pts.rst | 78 - Documentation/media/uapi/dvb/video-get-size.rst | 78 - Documentation/media/uapi/dvb/video-get-status.rst | 80 - Documentation/media/uapi/dvb/video-play.rst | 66 - .../media/uapi/dvb/video-select-source.rst | 84 - Documentation/media/uapi/dvb/video-set-blank.rst | 73 - .../media/uapi/dvb/video-set-display-format.rst | 69 - Documentation/media/uapi/dvb/video-set-format.rst | 92 - .../media/uapi/dvb/video-set-streamtype.rst | 70 - Documentation/media/uapi/dvb/video-slowmotion.rst | 83 - .../media/uapi/dvb/video-stillpicture.rst | 70 - Documentation/media/uapi/dvb/video-stop.rst | 83 - Documentation/media/uapi/dvb/video-try-command.rst | 75 - Documentation/media/uapi/dvb/video.rst | 43 - .../media/uapi/dvb/video_function_calls.rst | 42 - Documentation/media/uapi/dvb/video_types.rst | 255 - Documentation/media/uapi/fdl-appendix.rst | 478 -- Documentation/media/uapi/gen-errors.rst | 103 - .../media/uapi/mediactl/media-controller-intro.rst | 40 - .../media/uapi/mediactl/media-controller-model.rst | 42 - .../media/uapi/mediactl/media-controller.rst | 62 - .../media/uapi/mediactl/media-func-close.rst | 54 - .../media/uapi/mediactl/media-func-ioctl.rst | 74 - .../media/uapi/mediactl/media-func-open.rst | 76 - Documentation/media/uapi/mediactl/media-funcs.rst | 33 - Documentation/media/uapi/mediactl/media-header.rst | 17 - .../media/uapi/mediactl/media-ioc-device-info.rst | 118 - .../uapi/mediactl/media-ioc-enum-entities.rst | 156 - .../media/uapi/mediactl/media-ioc-enum-links.rst | 157 - .../media/uapi/mediactl/media-ioc-g-topology.rst | 307 - .../uapi/mediactl/media-ioc-request-alloc.rst | 90 - .../media/uapi/mediactl/media-ioc-setup-link.rst | 74 - .../uapi/mediactl/media-request-ioc-queue.rst | 102 - .../uapi/mediactl/media-request-ioc-reinit.rst | 75 - Documentation/media/uapi/mediactl/media-types.rst | 425 -- Documentation/media/uapi/mediactl/request-api.rst | 276 - .../media/uapi/mediactl/request-func-close.rst | 73 - .../media/uapi/mediactl/request-func-ioctl.rst | 91 - .../media/uapi/mediactl/request-func-poll.rst | 101 - Documentation/media/uapi/rc/keytable.c.rst | 183 - Documentation/media/uapi/rc/lirc-dev-intro.rst | 171 - Documentation/media/uapi/rc/lirc-dev.rst | 21 - Documentation/media/uapi/rc/lirc-func.rst | 34 - Documentation/media/uapi/rc/lirc-get-features.rst | 200 - Documentation/media/uapi/rc/lirc-get-rec-mode.rst | 74 - .../media/uapi/rc/lirc-get-rec-resolution.rst | 54 - Documentation/media/uapi/rc/lirc-get-send-mode.rst | 78 - Documentation/media/uapi/rc/lirc-get-timeout.rst | 63 - Documentation/media/uapi/rc/lirc-header.rst | 17 - Documentation/media/uapi/rc/lirc-read.rst | 76 - .../uapi/rc/lirc-set-measure-carrier-mode.rst | 53 - .../media/uapi/rc/lirc-set-rec-carrier-range.rst | 54 - .../media/uapi/rc/lirc-set-rec-carrier.rst | 53 - .../media/uapi/rc/lirc-set-rec-timeout-reports.rst | 56 - .../media/uapi/rc/lirc-set-rec-timeout.rst | 61 - .../media/uapi/rc/lirc-set-send-carrier.rst | 48 - .../media/uapi/rc/lirc-set-send-duty-cycle.rst | 54 - .../media/uapi/rc/lirc-set-transmitter-mask.rst | 58 - .../media/uapi/rc/lirc-set-wideband-receiver.rst | 63 - Documentation/media/uapi/rc/lirc-write.rst | 82 - Documentation/media/uapi/rc/rc-intro.rst | 31 - Documentation/media/uapi/rc/rc-protos.rst | 456 -- Documentation/media/uapi/rc/rc-sysfs-nodes.rst | 151 - Documentation/media/uapi/rc/rc-table-change.rst | 25 - Documentation/media/uapi/rc/rc-tables.rst | 766 -- Documentation/media/uapi/rc/remote_controllers.rst | 59 - Documentation/media/uapi/v4l/app-pri.rst | 37 - Documentation/media/uapi/v4l/async.rst | 16 - Documentation/media/uapi/v4l/audio.rst | 104 - Documentation/media/uapi/v4l/bayer.svg | 56 - Documentation/media/uapi/v4l/biblio.rst | 416 -- Documentation/media/uapi/v4l/buffer.rst | 817 -- Documentation/media/uapi/v4l/capture-example.rst | 20 - Documentation/media/uapi/v4l/capture.c.rst | 671 -- Documentation/media/uapi/v4l/colorspaces-defs.rst | 183 - .../media/uapi/v4l/colorspaces-details.rst | 813 -- Documentation/media/uapi/v4l/colorspaces.rst | 170 - Documentation/media/uapi/v4l/common-defs.rst | 20 - Documentation/media/uapi/v4l/common.rst | 64 - Documentation/media/uapi/v4l/compat.rst | 25 - Documentation/media/uapi/v4l/constraints.svg | 37 - Documentation/media/uapi/v4l/control.rst | 512 -- Documentation/media/uapi/v4l/crop.rst | 324 - Documentation/media/uapi/v4l/crop.svg | 290 - Documentation/media/uapi/v4l/depth-formats.rst | 24 - Documentation/media/uapi/v4l/dev-capture.rst | 111 - Documentation/media/uapi/v4l/dev-decoder.rst | 1101 --- Documentation/media/uapi/v4l/dev-event.rst | 54 - Documentation/media/uapi/v4l/dev-mem2mem.rst | 49 - Documentation/media/uapi/v4l/dev-meta.rst | 74 - Documentation/media/uapi/v4l/dev-osd.rst | 157 - Documentation/media/uapi/v4l/dev-output.rst | 108 - Documentation/media/uapi/v4l/dev-overlay.rst | 328 - Documentation/media/uapi/v4l/dev-radio.rst | 59 - Documentation/media/uapi/v4l/dev-raw-vbi.rst | 306 - Documentation/media/uapi/v4l/dev-rds.rst | 191 - Documentation/media/uapi/v4l/dev-sdr.rst | 114 - Documentation/media/uapi/v4l/dev-sliced-vbi.rst | 669 -- .../media/uapi/v4l/dev-stateless-decoder.rst | 424 -- Documentation/media/uapi/v4l/dev-subdev.rst | 503 -- Documentation/media/uapi/v4l/dev-touch.rst | 63 - Documentation/media/uapi/v4l/devices.rst | 33 - Documentation/media/uapi/v4l/diff-v4l.rst | 693 -- Documentation/media/uapi/v4l/dmabuf.rst | 169 - Documentation/media/uapi/v4l/dv-timings.rst | 45 - Documentation/media/uapi/v4l/ext-ctrls-camera.rst | 515 -- Documentation/media/uapi/v4l/ext-ctrls-codec.rst | 4264 ----------- Documentation/media/uapi/v4l/ext-ctrls-detect.rst | 71 - Documentation/media/uapi/v4l/ext-ctrls-dv.rst | 166 - Documentation/media/uapi/v4l/ext-ctrls-flash.rst | 192 - Documentation/media/uapi/v4l/ext-ctrls-fm-rx.rst | 95 - Documentation/media/uapi/v4l/ext-ctrls-fm-tx.rst | 188 - .../media/uapi/v4l/ext-ctrls-image-process.rst | 63 - .../media/uapi/v4l/ext-ctrls-image-source.rst | 67 - Documentation/media/uapi/v4l/ext-ctrls-jpeg.rst | 113 - .../media/uapi/v4l/ext-ctrls-rf-tuner.rst | 96 - Documentation/media/uapi/v4l/extended-controls.rst | 180 - Documentation/media/uapi/v4l/field-order.rst | 172 - Documentation/media/uapi/v4l/fieldseq_bt.svg | 2621 ------- Documentation/media/uapi/v4l/fieldseq_tb.svg | 2618 ------- Documentation/media/uapi/v4l/format.rst | 99 - Documentation/media/uapi/v4l/func-close.rst | 56 - Documentation/media/uapi/v4l/func-ioctl.rst | 69 - Documentation/media/uapi/v4l/func-mmap.rst | 148 - Documentation/media/uapi/v4l/func-munmap.rst | 65 - Documentation/media/uapi/v4l/func-open.rst | 90 - Documentation/media/uapi/v4l/func-poll.rst | 124 - Documentation/media/uapi/v4l/func-read.rst | 140 - Documentation/media/uapi/v4l/func-select.rst | 127 - Documentation/media/uapi/v4l/func-write.rst | 91 - Documentation/media/uapi/v4l/hist-v4l2.rst | 1374 ---- Documentation/media/uapi/v4l/hsv-formats.rst | 26 - Documentation/media/uapi/v4l/io.rst | 58 - .../media/uapi/v4l/libv4l-introduction.rst | 191 - Documentation/media/uapi/v4l/libv4l.rst | 20 - Documentation/media/uapi/v4l/meta-formats.rst | 27 - Documentation/media/uapi/v4l/mmap.rst | 292 - Documentation/media/uapi/v4l/nv12mt.svg | 477 -- Documentation/media/uapi/v4l/nv12mt_example.svg | 1616 ---- Documentation/media/uapi/v4l/open.rst | 165 - Documentation/media/uapi/v4l/pipeline.dot | 14 - Documentation/media/uapi/v4l/pixfmt-bayer.rst | 39 - Documentation/media/uapi/v4l/pixfmt-cnf4.rst | 31 - Documentation/media/uapi/v4l/pixfmt-compressed.rst | 232 - Documentation/media/uapi/v4l/pixfmt-grey.rst | 51 - Documentation/media/uapi/v4l/pixfmt-indexed.rst | 54 - Documentation/media/uapi/v4l/pixfmt-intro.rst | 58 - Documentation/media/uapi/v4l/pixfmt-inzi.rst | 89 - Documentation/media/uapi/v4l/pixfmt-m420.rst | 133 - Documentation/media/uapi/v4l/pixfmt-meta-d4xx.rst | 220 - .../media/uapi/v4l/pixfmt-meta-intel-ipu3.rst | 104 - Documentation/media/uapi/v4l/pixfmt-meta-uvc.rst | 58 - Documentation/media/uapi/v4l/pixfmt-meta-vivid.rst | 60 - .../media/uapi/v4l/pixfmt-meta-vsp1-hgo.rst | 175 - .../media/uapi/v4l/pixfmt-meta-vsp1-hgt.rst | 136 - Documentation/media/uapi/v4l/pixfmt-nv12.rst | 136 - Documentation/media/uapi/v4l/pixfmt-nv12m.rst | 151 - Documentation/media/uapi/v4l/pixfmt-nv12mt.rst | 67 - Documentation/media/uapi/v4l/pixfmt-nv16.rst | 160 - Documentation/media/uapi/v4l/pixfmt-nv16m.rst | 164 - Documentation/media/uapi/v4l/pixfmt-nv24.rst | 102 - Documentation/media/uapi/v4l/pixfmt-packed-hsv.rst | 164 - Documentation/media/uapi/v4l/pixfmt-packed-yuv.rst | 380 - Documentation/media/uapi/v4l/pixfmt-reserved.rst | 282 - Documentation/media/uapi/v4l/pixfmt-rgb.rst | 1304 ---- Documentation/media/uapi/v4l/pixfmt-sdr-cs08.rst | 37 - Documentation/media/uapi/v4l/pixfmt-sdr-cs14le.rst | 41 - Documentation/media/uapi/v4l/pixfmt-sdr-cu08.rst | 37 - Documentation/media/uapi/v4l/pixfmt-sdr-cu16le.rst | 41 - .../media/uapi/v4l/pixfmt-sdr-pcu16be.rst | 62 - .../media/uapi/v4l/pixfmt-sdr-pcu18be.rst | 62 - .../media/uapi/v4l/pixfmt-sdr-pcu20be.rst | 62 - Documentation/media/uapi/v4l/pixfmt-sdr-ru12le.rst | 39 - .../media/uapi/v4l/pixfmt-srggb10-ipu3.rst | 342 - Documentation/media/uapi/v4l/pixfmt-srggb10.rst | 83 - .../media/uapi/v4l/pixfmt-srggb10alaw8.rst | 31 - .../media/uapi/v4l/pixfmt-srggb10dpcm8.rst | 35 - Documentation/media/uapi/v4l/pixfmt-srggb10p.rst | 81 - Documentation/media/uapi/v4l/pixfmt-srggb12.rst | 84 - Documentation/media/uapi/v4l/pixfmt-srggb12p.rst | 94 - Documentation/media/uapi/v4l/pixfmt-srggb14.rst | 82 - Documentation/media/uapi/v4l/pixfmt-srggb14p.rst | 152 - Documentation/media/uapi/v4l/pixfmt-srggb16.rst | 76 - Documentation/media/uapi/v4l/pixfmt-srggb8.rst | 61 - Documentation/media/uapi/v4l/pixfmt-tch-td08.rst | 59 - Documentation/media/uapi/v4l/pixfmt-tch-td16.rst | 74 - Documentation/media/uapi/v4l/pixfmt-tch-tu08.rst | 57 - Documentation/media/uapi/v4l/pixfmt-tch-tu16.rst | 73 - Documentation/media/uapi/v4l/pixfmt-uv8.rst | 54 - Documentation/media/uapi/v4l/pixfmt-uyvy.rst | 117 - .../media/uapi/v4l/pixfmt-v4l2-mplane.rst | 138 - Documentation/media/uapi/v4l/pixfmt-v4l2.rst | 171 - Documentation/media/uapi/v4l/pixfmt-vyuy.rst | 115 - Documentation/media/uapi/v4l/pixfmt-y10.rst | 72 - Documentation/media/uapi/v4l/pixfmt-y10b.rst | 40 - Documentation/media/uapi/v4l/pixfmt-y10p.rst | 50 - Documentation/media/uapi/v4l/pixfmt-y12.rst | 72 - Documentation/media/uapi/v4l/pixfmt-y12i.rst | 43 - Documentation/media/uapi/v4l/pixfmt-y14.rst | 72 - Documentation/media/uapi/v4l/pixfmt-y16-be.rst | 76 - Documentation/media/uapi/v4l/pixfmt-y16.rst | 76 - Documentation/media/uapi/v4l/pixfmt-y41p.rst | 158 - Documentation/media/uapi/v4l/pixfmt-y8i.rst | 73 - Documentation/media/uapi/v4l/pixfmt-yuv410.rst | 134 - Documentation/media/uapi/v4l/pixfmt-yuv411p.rst | 122 - Documentation/media/uapi/v4l/pixfmt-yuv420.rst | 150 - Documentation/media/uapi/v4l/pixfmt-yuv420m.rst | 159 - Documentation/media/uapi/v4l/pixfmt-yuv422m.rst | 148 - Documentation/media/uapi/v4l/pixfmt-yuv422p.rst | 136 - Documentation/media/uapi/v4l/pixfmt-yuv444m.rst | 148 - Documentation/media/uapi/v4l/pixfmt-yuyv.rst | 125 - Documentation/media/uapi/v4l/pixfmt-yvyu.rst | 115 - Documentation/media/uapi/v4l/pixfmt-z16.rst | 73 - Documentation/media/uapi/v4l/pixfmt.rst | 45 - Documentation/media/uapi/v4l/planar-apis.rst | 68 - Documentation/media/uapi/v4l/querycap.rst | 41 - Documentation/media/uapi/v4l/rw.rst | 54 - Documentation/media/uapi/v4l/sdr-formats.rst | 29 - .../media/uapi/v4l/selection-api-configuration.rst | 144 - .../media/uapi/v4l/selection-api-examples.rst | 91 - .../media/uapi/v4l/selection-api-intro.rst | 35 - .../media/uapi/v4l/selection-api-targets.rst | 27 - .../media/uapi/v4l/selection-api-vs-crop-api.rst | 46 - Documentation/media/uapi/v4l/selection-api.rst | 23 - Documentation/media/uapi/v4l/selection.svg | 1178 --- Documentation/media/uapi/v4l/selections-common.rst | 30 - Documentation/media/uapi/v4l/standard.rst | 192 - Documentation/media/uapi/v4l/streaming-par.rst | 40 - Documentation/media/uapi/v4l/subdev-formats.rst | 7833 -------------------- .../uapi/v4l/subdev-image-processing-crop.svg | 312 - .../uapi/v4l/subdev-image-processing-full.svg | 752 -- ...ubdev-image-processing-scaling-multi-source.svg | 550 -- Documentation/media/uapi/v4l/tch-formats.rst | 25 - Documentation/media/uapi/v4l/tuner.rst | 92 - Documentation/media/uapi/v4l/user-func.rst | 88 - Documentation/media/uapi/v4l/userp.rst | 128 - .../media/uapi/v4l/v4l2-selection-flags.rst | 51 - .../media/uapi/v4l/v4l2-selection-targets.rst | 78 - Documentation/media/uapi/v4l/v4l2.rst | 423 -- Documentation/media/uapi/v4l/v4l2grab-example.rst | 24 - Documentation/media/uapi/v4l/v4l2grab.c.rst | 176 - Documentation/media/uapi/v4l/vbi_525.svg | 821 -- Documentation/media/uapi/v4l/vbi_625.svg | 870 --- Documentation/media/uapi/v4l/vbi_hsync.svg | 321 - Documentation/media/uapi/v4l/video.rst | 75 - Documentation/media/uapi/v4l/videodev.rst | 16 - .../media/uapi/v4l/vidioc-create-bufs.rst | 141 - Documentation/media/uapi/v4l/vidioc-cropcap.rst | 143 - .../media/uapi/v4l/vidioc-dbg-g-chip-info.rst | 167 - .../media/uapi/v4l/vidioc-dbg-g-register.rst | 171 - .../media/uapi/v4l/vidioc-decoder-cmd.rst | 226 - Documentation/media/uapi/v4l/vidioc-dqevent.rst | 391 - .../media/uapi/v4l/vidioc-dv-timings-cap.rst | 169 - .../media/uapi/v4l/vidioc-encoder-cmd.rst | 168 - .../media/uapi/v4l/vidioc-enum-dv-timings.rst | 114 - Documentation/media/uapi/v4l/vidioc-enum-fmt.rst | 159 - .../media/uapi/v4l/vidioc-enum-frameintervals.rst | 203 - .../media/uapi/v4l/vidioc-enum-framesizes.rst | 213 - .../media/uapi/v4l/vidioc-enum-freq-bands.rst | 150 - Documentation/media/uapi/v4l/vidioc-enumaudio.rst | 62 - .../media/uapi/v4l/vidioc-enumaudioout.rst | 67 - Documentation/media/uapi/v4l/vidioc-enuminput.rst | 242 - Documentation/media/uapi/v4l/vidioc-enumoutput.rst | 165 - Documentation/media/uapi/v4l/vidioc-enumstd.rst | 367 - Documentation/media/uapi/v4l/vidioc-expbuf.rst | 175 - Documentation/media/uapi/v4l/vidioc-g-audio.rst | 135 - Documentation/media/uapi/v4l/vidioc-g-audioout.rst | 108 - Documentation/media/uapi/v4l/vidioc-g-crop.rst | 119 - Documentation/media/uapi/v4l/vidioc-g-ctrl.rst | 106 - .../media/uapi/v4l/vidioc-g-dv-timings.rst | 312 - Documentation/media/uapi/v4l/vidioc-g-edid.rst | 154 - .../media/uapi/v4l/vidioc-g-enc-index.rst | 156 - .../media/uapi/v4l/vidioc-g-ext-ctrls.rst | 416 -- Documentation/media/uapi/v4l/vidioc-g-fbuf.rst | 362 - Documentation/media/uapi/v4l/vidioc-g-fmt.rst | 161 - .../media/uapi/v4l/vidioc-g-frequency.rst | 112 - Documentation/media/uapi/v4l/vidioc-g-input.rst | 71 - Documentation/media/uapi/v4l/vidioc-g-jpegcomp.rst | 134 - .../media/uapi/v4l/vidioc-g-modulator.rst | 202 - Documentation/media/uapi/v4l/vidioc-g-output.rst | 73 - Documentation/media/uapi/v4l/vidioc-g-parm.rst | 270 - Documentation/media/uapi/v4l/vidioc-g-priority.rst | 100 - .../media/uapi/v4l/vidioc-g-selection.rst | 200 - .../media/uapi/v4l/vidioc-g-sliced-vbi-cap.rst | 202 - Documentation/media/uapi/v4l/vidioc-g-std.rst | 81 - Documentation/media/uapi/v4l/vidioc-g-tuner.rst | 476 -- Documentation/media/uapi/v4l/vidioc-log-status.rst | 56 - Documentation/media/uapi/v4l/vidioc-overlay.rst | 61 - .../media/uapi/v4l/vidioc-prepare-buf.rst | 65 - Documentation/media/uapi/v4l/vidioc-qbuf.rst | 205 - .../media/uapi/v4l/vidioc-query-dv-timings.rst | 94 - Documentation/media/uapi/v4l/vidioc-querybuf.rst | 87 - Documentation/media/uapi/v4l/vidioc-querycap.rst | 284 - Documentation/media/uapi/v4l/vidioc-queryctrl.rst | 616 -- Documentation/media/uapi/v4l/vidioc-querystd.rst | 77 - Documentation/media/uapi/v4l/vidioc-reqbufs.rst | 169 - .../media/uapi/v4l/vidioc-s-hw-freq-seek.rst | 147 - Documentation/media/uapi/v4l/vidioc-streamon.rst | 113 - .../uapi/v4l/vidioc-subdev-enum-frame-interval.rst | 120 - .../uapi/v4l/vidioc-subdev-enum-frame-size.rst | 125 - .../uapi/v4l/vidioc-subdev-enum-mbus-code.rst | 98 - .../media/uapi/v4l/vidioc-subdev-g-crop.rst | 125 - .../media/uapi/v4l/vidioc-subdev-g-fmt.rst | 154 - .../uapi/v4l/vidioc-subdev-g-frame-interval.rst | 120 - .../media/uapi/v4l/vidioc-subdev-g-selection.rst | 125 - .../media/uapi/v4l/vidioc-subscribe-event.rst | 123 - Documentation/media/uapi/v4l/yuv-formats.rst | 64 - Documentation/media/video.h.rst.exceptions | 39 - Documentation/media/videodev2.h.rst.exceptions | 572 -- .../translations/it_IT/doc-guide/parse-headers.rst | 2 +- Documentation/userspace-api/media/Makefile | 69 + .../userspace-api/media/audio.h.rst.exceptions | 19 + .../userspace-api/media/ca.h.rst.exceptions | 25 + .../userspace-api/media/cec.h.rst.exceptions | 575 ++ Documentation/userspace-api/media/cec/cec-api.rst | 54 + .../userspace-api/media/cec/cec-func-close.rst | 54 + .../userspace-api/media/cec/cec-func-ioctl.rst | 73 + .../userspace-api/media/cec/cec-func-open.rst | 85 + .../userspace-api/media/cec/cec-func-poll.rst | 85 + .../userspace-api/media/cec/cec-funcs.rst | 30 + .../userspace-api/media/cec/cec-header.rst | 17 + .../userspace-api/media/cec/cec-intro.rst | 49 + .../media/cec/cec-ioc-adap-g-caps.rst | 150 + .../media/cec/cec-ioc-adap-g-conn-info.rst | 105 + .../media/cec/cec-ioc-adap-g-log-addrs.rst | 378 + .../media/cec/cec-ioc-adap-g-phys-addr.rst | 100 + .../userspace-api/media/cec/cec-ioc-dqevent.rst | 257 + .../userspace-api/media/cec/cec-ioc-g-mode.rst | 301 + .../userspace-api/media/cec/cec-ioc-receive.rst | 391 + .../userspace-api/media/cec/cec-pin-error-inj.rst | 334 + Documentation/userspace-api/media/conf_nitpick.py | 111 + .../userspace-api/media/dmx.h.rst.exceptions | 66 + .../media/dvb/audio-bilingual-channel-select.rst | 66 + .../media/dvb/audio-channel-select.rst | 66 + .../userspace-api/media/dvb/audio-clear-buffer.rst | 55 + .../userspace-api/media/dvb/audio-continue.rst | 56 + .../userspace-api/media/dvb/audio-fclose.rst | 63 + .../userspace-api/media/dvb/audio-fopen.rst | 115 + .../userspace-api/media/dvb/audio-fwrite.rst | 91 + .../media/dvb/audio-get-capabilities.rst | 63 + .../userspace-api/media/dvb/audio-get-status.rst | 63 + .../userspace-api/media/dvb/audio-pause.rst | 57 + .../userspace-api/media/dvb/audio-play.rst | 56 + .../media/dvb/audio-select-source.rst | 65 + .../userspace-api/media/dvb/audio-set-av-sync.rst | 67 + .../media/dvb/audio-set-bypass-mode.rst | 70 + .../userspace-api/media/dvb/audio-set-id.rst | 67 + .../userspace-api/media/dvb/audio-set-mixer.rst | 61 + .../userspace-api/media/dvb/audio-set-mute.rst | 71 + .../media/dvb/audio-set-streamtype.rst | 77 + .../userspace-api/media/dvb/audio-stop.rst | 56 + Documentation/userspace-api/media/dvb/audio.rst | 34 + .../userspace-api/media/dvb/audio_data_types.rst | 123 + .../media/dvb/audio_function_calls.rst | 37 + .../userspace-api/media/dvb/ca-fclose.rst | 50 + Documentation/userspace-api/media/dvb/ca-fopen.rst | 84 + .../userspace-api/media/dvb/ca-get-cap.rst | 53 + .../userspace-api/media/dvb/ca-get-descr-info.rst | 49 + .../userspace-api/media/dvb/ca-get-msg.rst | 59 + .../userspace-api/media/dvb/ca-get-slot-info.rst | 64 + Documentation/userspace-api/media/dvb/ca-reset.rst | 51 + .../userspace-api/media/dvb/ca-send-msg.rst | 58 + .../userspace-api/media/dvb/ca-set-descr.rst | 53 + Documentation/userspace-api/media/dvb/ca.rst | 32 + .../userspace-api/media/dvb/ca_data_types.rst | 16 + .../userspace-api/media/dvb/ca_function_calls.rst | 27 + .../userspace-api/media/dvb/ca_high_level.rst | 157 + Documentation/userspace-api/media/dvb/demux.rst | 30 + .../userspace-api/media/dvb/dmx-add-pid.rst | 56 + .../userspace-api/media/dvb/dmx-expbuf.rst | 97 + .../userspace-api/media/dvb/dmx-fclose.rst | 52 + .../userspace-api/media/dvb/dmx-fopen.rst | 98 + .../userspace-api/media/dvb/dmx-fread.rst | 87 + .../userspace-api/media/dvb/dmx-fwrite.rst | 79 + .../userspace-api/media/dvb/dmx-get-pes-pids.rst | 71 + .../userspace-api/media/dvb/dmx-get-stc.rst | 73 + Documentation/userspace-api/media/dvb/dmx-mmap.rst | 125 + .../userspace-api/media/dvb/dmx-munmap.rst | 63 + Documentation/userspace-api/media/dvb/dmx-qbuf.rst | 93 + .../userspace-api/media/dvb/dmx-querybuf.rst | 72 + .../userspace-api/media/dvb/dmx-remove-pid.rst | 57 + .../userspace-api/media/dvb/dmx-reqbufs.rst | 83 + .../media/dvb/dmx-set-buffer-size.rst | 57 + .../userspace-api/media/dvb/dmx-set-filter.rst | 64 + .../userspace-api/media/dvb/dmx-set-pes-filter.rst | 76 + .../userspace-api/media/dvb/dmx-start.rst | 75 + Documentation/userspace-api/media/dvb/dmx-stop.rst | 52 + .../userspace-api/media/dvb/dmx_fcalls.rst | 37 + .../userspace-api/media/dvb/dmx_types.rst | 16 + .../userspace-api/media/dvb/dvb-fe-read-status.rst | 32 + .../userspace-api/media/dvb/dvb-frontend-event.rst | 22 + .../media/dvb/dvb-frontend-parameters.rst | 126 + Documentation/userspace-api/media/dvb/dvbapi.rst | 126 + .../userspace-api/media/dvb/dvbproperty.rst | 133 + Documentation/userspace-api/media/dvb/dvbstb.svg | 43 + Documentation/userspace-api/media/dvb/examples.rst | 23 + .../userspace-api/media/dvb/fe-bandwidth-t.rst | 81 + .../media/dvb/fe-diseqc-recv-slave-reply.rst | 55 + .../media/dvb/fe-diseqc-reset-overload.rst | 53 + .../media/dvb/fe-diseqc-send-burst.rst | 59 + .../media/dvb/fe-diseqc-send-master-cmd.rst | 56 + .../media/dvb/fe-dishnetwork-send-legacy-cmd.rst | 62 + .../media/dvb/fe-enable-high-lnb-voltage.rst | 61 + .../userspace-api/media/dvb/fe-get-event.rst | 78 + .../userspace-api/media/dvb/fe-get-frontend.rst | 69 + .../userspace-api/media/dvb/fe-get-info.rst | 70 + .../userspace-api/media/dvb/fe-get-property.rst | 83 + .../userspace-api/media/dvb/fe-read-ber.rst | 57 + .../media/dvb/fe-read-signal-strength.rst | 57 + .../userspace-api/media/dvb/fe-read-snr.rst | 57 + .../userspace-api/media/dvb/fe-read-status.rst | 72 + .../media/dvb/fe-read-uncorrected-blocks.rst | 59 + .../media/dvb/fe-set-frontend-tune-mode.rst | 64 + .../userspace-api/media/dvb/fe-set-frontend.rst | 78 + .../userspace-api/media/dvb/fe-set-tone.rst | 65 + .../userspace-api/media/dvb/fe-set-voltage.rst | 69 + .../userspace-api/media/dvb/fe-type-t.rst | 98 + .../media/dvb/fe_property_parameters.rst | 1014 +++ .../userspace-api/media/dvb/frontend-header.rst | 13 + .../media/dvb/frontend-property-cable-systems.rst | 82 + .../dvb/frontend-property-satellite-systems.rst | 112 + .../dvb/frontend-property-terrestrial-systems.rst | 301 + .../media/dvb/frontend-stat-properties.rst | 252 + Documentation/userspace-api/media/dvb/frontend.rst | 63 + .../userspace-api/media/dvb/frontend_f_close.rst | 57 + .../userspace-api/media/dvb/frontend_f_open.rst | 117 + .../userspace-api/media/dvb/frontend_fcalls.rst | 31 + .../media/dvb/frontend_legacy_api.rst | 45 + .../media/dvb/frontend_legacy_dvbv3_api.rst | 25 + Documentation/userspace-api/media/dvb/headers.rst | 30 + Documentation/userspace-api/media/dvb/intro.rst | 190 + .../userspace-api/media/dvb/legacy_dvb_apis.rst | 39 + .../userspace-api/media/dvb/net-add-if.rst | 60 + .../userspace-api/media/dvb/net-get-if.rst | 59 + .../userspace-api/media/dvb/net-remove-if.rst | 55 + .../userspace-api/media/dvb/net-types.rst | 16 + Documentation/userspace-api/media/dvb/net.rst | 48 + .../media/dvb/query-dvb-frontend-info.rst | 20 + .../userspace-api/media/dvb/video-clear-buffer.rst | 63 + .../userspace-api/media/dvb/video-command.rst | 105 + .../userspace-api/media/dvb/video-continue.rst | 66 + .../userspace-api/media/dvb/video-fast-forward.rst | 83 + .../userspace-api/media/dvb/video-fclose.rst | 62 + .../userspace-api/media/dvb/video-fopen.rst | 122 + .../userspace-api/media/dvb/video-freeze.rst | 70 + .../userspace-api/media/dvb/video-fwrite.rst | 90 + .../media/dvb/video-get-capabilities.rst | 70 + .../userspace-api/media/dvb/video-get-event.rst | 114 + .../media/dvb/video-get-frame-count.rst | 74 + .../userspace-api/media/dvb/video-get-pts.rst | 78 + .../userspace-api/media/dvb/video-get-size.rst | 78 + .../userspace-api/media/dvb/video-get-status.rst | 80 + .../userspace-api/media/dvb/video-play.rst | 66 + .../media/dvb/video-select-source.rst | 84 + .../userspace-api/media/dvb/video-set-blank.rst | 73 + .../media/dvb/video-set-display-format.rst | 69 + .../userspace-api/media/dvb/video-set-format.rst | 92 + .../media/dvb/video-set-streamtype.rst | 70 + .../userspace-api/media/dvb/video-slowmotion.rst | 83 + .../userspace-api/media/dvb/video-stillpicture.rst | 70 + .../userspace-api/media/dvb/video-stop.rst | 83 + .../userspace-api/media/dvb/video-try-command.rst | 75 + Documentation/userspace-api/media/dvb/video.rst | 43 + .../media/dvb/video_function_calls.rst | 42 + .../userspace-api/media/dvb/video_types.rst | 255 + Documentation/userspace-api/media/fdl-appendix.rst | 478 ++ .../userspace-api/media/frontend.h.rst.exceptions | 214 + Documentation/userspace-api/media/gen-errors.rst | 103 + Documentation/userspace-api/media/index.rst | 33 + Documentation/userspace-api/media/intro.rst | 46 + .../userspace-api/media/lirc.h.rst.exceptions | 80 + .../userspace-api/media/media.h.rst.exceptions | 32 + .../media/mediactl/media-controller-intro.rst | 40 + .../media/mediactl/media-controller-model.rst | 42 + .../media/mediactl/media-controller.rst | 62 + .../media/mediactl/media-func-close.rst | 54 + .../media/mediactl/media-func-ioctl.rst | 74 + .../media/mediactl/media-func-open.rst | 76 + .../userspace-api/media/mediactl/media-funcs.rst | 33 + .../userspace-api/media/mediactl/media-header.rst | 17 + .../media/mediactl/media-ioc-device-info.rst | 118 + .../media/mediactl/media-ioc-enum-entities.rst | 156 + .../media/mediactl/media-ioc-enum-links.rst | 157 + .../media/mediactl/media-ioc-g-topology.rst | 307 + .../media/mediactl/media-ioc-request-alloc.rst | 90 + .../media/mediactl/media-ioc-setup-link.rst | 74 + .../media/mediactl/media-request-ioc-queue.rst | 102 + .../media/mediactl/media-request-ioc-reinit.rst | 75 + .../userspace-api/media/mediactl/media-types.rst | 425 ++ .../userspace-api/media/mediactl/request-api.rst | 276 + .../media/mediactl/request-func-close.rst | 73 + .../media/mediactl/request-func-ioctl.rst | 91 + .../media/mediactl/request-func-poll.rst | 101 + .../userspace-api/media/net.h.rst.exceptions | 13 + .../userspace-api/media/rc/keytable.c.rst | 183 + .../userspace-api/media/rc/lirc-dev-intro.rst | 171 + Documentation/userspace-api/media/rc/lirc-dev.rst | 21 + Documentation/userspace-api/media/rc/lirc-func.rst | 34 + .../userspace-api/media/rc/lirc-get-features.rst | 200 + .../userspace-api/media/rc/lirc-get-rec-mode.rst | 74 + .../media/rc/lirc-get-rec-resolution.rst | 54 + .../userspace-api/media/rc/lirc-get-send-mode.rst | 78 + .../userspace-api/media/rc/lirc-get-timeout.rst | 63 + .../userspace-api/media/rc/lirc-header.rst | 17 + Documentation/userspace-api/media/rc/lirc-read.rst | 76 + .../media/rc/lirc-set-measure-carrier-mode.rst | 53 + .../media/rc/lirc-set-rec-carrier-range.rst | 54 + .../media/rc/lirc-set-rec-carrier.rst | 53 + .../media/rc/lirc-set-rec-timeout-reports.rst | 56 + .../media/rc/lirc-set-rec-timeout.rst | 61 + .../media/rc/lirc-set-send-carrier.rst | 48 + .../media/rc/lirc-set-send-duty-cycle.rst | 54 + .../media/rc/lirc-set-transmitter-mask.rst | 58 + .../media/rc/lirc-set-wideband-receiver.rst | 63 + .../userspace-api/media/rc/lirc-write.rst | 82 + Documentation/userspace-api/media/rc/rc-intro.rst | 31 + Documentation/userspace-api/media/rc/rc-protos.rst | 456 ++ .../userspace-api/media/rc/rc-sysfs-nodes.rst | 151 + .../userspace-api/media/rc/rc-table-change.rst | 25 + Documentation/userspace-api/media/rc/rc-tables.rst | 766 ++ .../userspace-api/media/rc/remote_controllers.rst | 59 + .../userspace-api/media/typical_media_device.svg | 116 + Documentation/userspace-api/media/v4l/app-pri.rst | 37 + Documentation/userspace-api/media/v4l/async.rst | 16 + Documentation/userspace-api/media/v4l/audio.rst | 104 + Documentation/userspace-api/media/v4l/bayer.svg | 56 + Documentation/userspace-api/media/v4l/biblio.rst | 416 ++ Documentation/userspace-api/media/v4l/buffer.rst | 817 ++ .../userspace-api/media/v4l/capture-example.rst | 20 + .../userspace-api/media/v4l/capture.c.rst | 671 ++ .../userspace-api/media/v4l/colorspaces-defs.rst | 183 + .../media/v4l/colorspaces-details.rst | 813 ++ .../userspace-api/media/v4l/colorspaces.rst | 170 + .../userspace-api/media/v4l/common-defs.rst | 20 + Documentation/userspace-api/media/v4l/common.rst | 64 + Documentation/userspace-api/media/v4l/compat.rst | 25 + .../userspace-api/media/v4l/constraints.svg | 37 + Documentation/userspace-api/media/v4l/control.rst | 512 ++ Documentation/userspace-api/media/v4l/crop.rst | 324 + Documentation/userspace-api/media/v4l/crop.svg | 290 + .../userspace-api/media/v4l/depth-formats.rst | 24 + .../userspace-api/media/v4l/dev-capture.rst | 111 + .../userspace-api/media/v4l/dev-decoder.rst | 1101 +++ .../userspace-api/media/v4l/dev-event.rst | 54 + .../userspace-api/media/v4l/dev-mem2mem.rst | 49 + Documentation/userspace-api/media/v4l/dev-meta.rst | 74 + Documentation/userspace-api/media/v4l/dev-osd.rst | 157 + .../userspace-api/media/v4l/dev-output.rst | 108 + .../userspace-api/media/v4l/dev-overlay.rst | 328 + .../userspace-api/media/v4l/dev-radio.rst | 59 + .../userspace-api/media/v4l/dev-raw-vbi.rst | 306 + Documentation/userspace-api/media/v4l/dev-rds.rst | 191 + Documentation/userspace-api/media/v4l/dev-sdr.rst | 114 + .../userspace-api/media/v4l/dev-sliced-vbi.rst | 669 ++ .../media/v4l/dev-stateless-decoder.rst | 424 ++ .../userspace-api/media/v4l/dev-subdev.rst | 503 ++ .../userspace-api/media/v4l/dev-touch.rst | 63 + Documentation/userspace-api/media/v4l/devices.rst | 33 + Documentation/userspace-api/media/v4l/diff-v4l.rst | 693 ++ Documentation/userspace-api/media/v4l/dmabuf.rst | 169 + .../userspace-api/media/v4l/dv-timings.rst | 45 + .../userspace-api/media/v4l/ext-ctrls-camera.rst | 515 ++ .../userspace-api/media/v4l/ext-ctrls-codec.rst | 4264 +++++++++++ .../userspace-api/media/v4l/ext-ctrls-detect.rst | 71 + .../userspace-api/media/v4l/ext-ctrls-dv.rst | 166 + .../userspace-api/media/v4l/ext-ctrls-flash.rst | 192 + .../userspace-api/media/v4l/ext-ctrls-fm-rx.rst | 95 + .../userspace-api/media/v4l/ext-ctrls-fm-tx.rst | 188 + .../media/v4l/ext-ctrls-image-process.rst | 63 + .../media/v4l/ext-ctrls-image-source.rst | 67 + .../userspace-api/media/v4l/ext-ctrls-jpeg.rst | 113 + .../userspace-api/media/v4l/ext-ctrls-rf-tuner.rst | 96 + .../userspace-api/media/v4l/extended-controls.rst | 180 + .../userspace-api/media/v4l/field-order.rst | 172 + .../userspace-api/media/v4l/fieldseq_bt.svg | 2621 +++++++ .../userspace-api/media/v4l/fieldseq_tb.svg | 2618 +++++++ Documentation/userspace-api/media/v4l/format.rst | 99 + .../userspace-api/media/v4l/func-close.rst | 56 + .../userspace-api/media/v4l/func-ioctl.rst | 69 + .../userspace-api/media/v4l/func-mmap.rst | 148 + .../userspace-api/media/v4l/func-munmap.rst | 65 + .../userspace-api/media/v4l/func-open.rst | 90 + .../userspace-api/media/v4l/func-poll.rst | 124 + .../userspace-api/media/v4l/func-read.rst | 140 + .../userspace-api/media/v4l/func-select.rst | 127 + .../userspace-api/media/v4l/func-write.rst | 91 + .../userspace-api/media/v4l/hist-v4l2.rst | 1374 ++++ .../userspace-api/media/v4l/hsv-formats.rst | 26 + Documentation/userspace-api/media/v4l/io.rst | 58 + .../media/v4l/libv4l-introduction.rst | 191 + Documentation/userspace-api/media/v4l/libv4l.rst | 20 + .../userspace-api/media/v4l/meta-formats.rst | 27 + Documentation/userspace-api/media/v4l/mmap.rst | 292 + Documentation/userspace-api/media/v4l/nv12mt.svg | 477 ++ .../userspace-api/media/v4l/nv12mt_example.svg | 1616 ++++ Documentation/userspace-api/media/v4l/open.rst | 165 + Documentation/userspace-api/media/v4l/pipeline.dot | 14 + .../userspace-api/media/v4l/pixfmt-bayer.rst | 39 + .../userspace-api/media/v4l/pixfmt-cnf4.rst | 31 + .../userspace-api/media/v4l/pixfmt-compressed.rst | 232 + .../userspace-api/media/v4l/pixfmt-grey.rst | 51 + .../userspace-api/media/v4l/pixfmt-indexed.rst | 54 + .../userspace-api/media/v4l/pixfmt-intro.rst | 58 + .../userspace-api/media/v4l/pixfmt-inzi.rst | 89 + .../userspace-api/media/v4l/pixfmt-m420.rst | 133 + .../userspace-api/media/v4l/pixfmt-meta-d4xx.rst | 220 + .../media/v4l/pixfmt-meta-intel-ipu3.rst | 104 + .../userspace-api/media/v4l/pixfmt-meta-uvc.rst | 58 + .../userspace-api/media/v4l/pixfmt-meta-vivid.rst | 60 + .../media/v4l/pixfmt-meta-vsp1-hgo.rst | 175 + .../media/v4l/pixfmt-meta-vsp1-hgt.rst | 136 + .../userspace-api/media/v4l/pixfmt-nv12.rst | 136 + .../userspace-api/media/v4l/pixfmt-nv12m.rst | 151 + .../userspace-api/media/v4l/pixfmt-nv12mt.rst | 67 + .../userspace-api/media/v4l/pixfmt-nv16.rst | 160 + .../userspace-api/media/v4l/pixfmt-nv16m.rst | 164 + .../userspace-api/media/v4l/pixfmt-nv24.rst | 102 + .../userspace-api/media/v4l/pixfmt-packed-hsv.rst | 164 + .../userspace-api/media/v4l/pixfmt-packed-yuv.rst | 380 + .../userspace-api/media/v4l/pixfmt-reserved.rst | 282 + .../userspace-api/media/v4l/pixfmt-rgb.rst | 1304 ++++ .../userspace-api/media/v4l/pixfmt-sdr-cs08.rst | 37 + .../userspace-api/media/v4l/pixfmt-sdr-cs14le.rst | 41 + .../userspace-api/media/v4l/pixfmt-sdr-cu08.rst | 37 + .../userspace-api/media/v4l/pixfmt-sdr-cu16le.rst | 41 + .../userspace-api/media/v4l/pixfmt-sdr-pcu16be.rst | 62 + .../userspace-api/media/v4l/pixfmt-sdr-pcu18be.rst | 62 + .../userspace-api/media/v4l/pixfmt-sdr-pcu20be.rst | 62 + .../userspace-api/media/v4l/pixfmt-sdr-ru12le.rst | 39 + .../media/v4l/pixfmt-srggb10-ipu3.rst | 342 + .../userspace-api/media/v4l/pixfmt-srggb10.rst | 83 + .../media/v4l/pixfmt-srggb10alaw8.rst | 31 + .../media/v4l/pixfmt-srggb10dpcm8.rst | 35 + .../userspace-api/media/v4l/pixfmt-srggb10p.rst | 81 + .../userspace-api/media/v4l/pixfmt-srggb12.rst | 84 + .../userspace-api/media/v4l/pixfmt-srggb12p.rst | 94 + .../userspace-api/media/v4l/pixfmt-srggb14.rst | 82 + .../userspace-api/media/v4l/pixfmt-srggb14p.rst | 152 + .../userspace-api/media/v4l/pixfmt-srggb16.rst | 76 + .../userspace-api/media/v4l/pixfmt-srggb8.rst | 61 + .../userspace-api/media/v4l/pixfmt-tch-td08.rst | 59 + .../userspace-api/media/v4l/pixfmt-tch-td16.rst | 74 + .../userspace-api/media/v4l/pixfmt-tch-tu08.rst | 57 + .../userspace-api/media/v4l/pixfmt-tch-tu16.rst | 73 + .../userspace-api/media/v4l/pixfmt-uv8.rst | 54 + .../userspace-api/media/v4l/pixfmt-uyvy.rst | 117 + .../userspace-api/media/v4l/pixfmt-v4l2-mplane.rst | 138 + .../userspace-api/media/v4l/pixfmt-v4l2.rst | 171 + .../userspace-api/media/v4l/pixfmt-vyuy.rst | 115 + .../userspace-api/media/v4l/pixfmt-y10.rst | 72 + .../userspace-api/media/v4l/pixfmt-y10b.rst | 40 + .../userspace-api/media/v4l/pixfmt-y10p.rst | 50 + .../userspace-api/media/v4l/pixfmt-y12.rst | 72 + .../userspace-api/media/v4l/pixfmt-y12i.rst | 43 + .../userspace-api/media/v4l/pixfmt-y14.rst | 72 + .../userspace-api/media/v4l/pixfmt-y16-be.rst | 76 + .../userspace-api/media/v4l/pixfmt-y16.rst | 76 + .../userspace-api/media/v4l/pixfmt-y41p.rst | 158 + .../userspace-api/media/v4l/pixfmt-y8i.rst | 73 + .../userspace-api/media/v4l/pixfmt-yuv410.rst | 134 + .../userspace-api/media/v4l/pixfmt-yuv411p.rst | 122 + .../userspace-api/media/v4l/pixfmt-yuv420.rst | 150 + .../userspace-api/media/v4l/pixfmt-yuv420m.rst | 159 + .../userspace-api/media/v4l/pixfmt-yuv422m.rst | 148 + .../userspace-api/media/v4l/pixfmt-yuv422p.rst | 136 + .../userspace-api/media/v4l/pixfmt-yuv444m.rst | 148 + .../userspace-api/media/v4l/pixfmt-yuyv.rst | 125 + .../userspace-api/media/v4l/pixfmt-yvyu.rst | 115 + .../userspace-api/media/v4l/pixfmt-z16.rst | 73 + Documentation/userspace-api/media/v4l/pixfmt.rst | 45 + .../userspace-api/media/v4l/planar-apis.rst | 68 + Documentation/userspace-api/media/v4l/querycap.rst | 41 + Documentation/userspace-api/media/v4l/rw.rst | 54 + .../userspace-api/media/v4l/sdr-formats.rst | 29 + .../media/v4l/selection-api-configuration.rst | 144 + .../media/v4l/selection-api-examples.rst | 91 + .../media/v4l/selection-api-intro.rst | 35 + .../media/v4l/selection-api-targets.rst | 27 + .../media/v4l/selection-api-vs-crop-api.rst | 46 + .../userspace-api/media/v4l/selection-api.rst | 23 + .../userspace-api/media/v4l/selection.svg | 1178 +++ .../userspace-api/media/v4l/selections-common.rst | 30 + Documentation/userspace-api/media/v4l/standard.rst | 192 + .../userspace-api/media/v4l/streaming-par.rst | 40 + .../userspace-api/media/v4l/subdev-formats.rst | 7833 ++++++++++++++++++++ .../media/v4l/subdev-image-processing-crop.svg | 312 + .../media/v4l/subdev-image-processing-full.svg | 752 ++ ...ubdev-image-processing-scaling-multi-source.svg | 550 ++ .../userspace-api/media/v4l/tch-formats.rst | 25 + Documentation/userspace-api/media/v4l/tuner.rst | 92 + .../userspace-api/media/v4l/user-func.rst | 88 + Documentation/userspace-api/media/v4l/userp.rst | 128 + .../media/v4l/v4l2-selection-flags.rst | 51 + .../media/v4l/v4l2-selection-targets.rst | 78 + Documentation/userspace-api/media/v4l/v4l2.rst | 423 ++ .../userspace-api/media/v4l/v4l2grab-example.rst | 24 + .../userspace-api/media/v4l/v4l2grab.c.rst | 176 + Documentation/userspace-api/media/v4l/vbi_525.svg | 821 ++ Documentation/userspace-api/media/v4l/vbi_625.svg | 870 +++ .../userspace-api/media/v4l/vbi_hsync.svg | 321 + Documentation/userspace-api/media/v4l/video.rst | 75 + Documentation/userspace-api/media/v4l/videodev.rst | 16 + .../userspace-api/media/v4l/vidioc-create-bufs.rst | 141 + .../userspace-api/media/v4l/vidioc-cropcap.rst | 143 + .../media/v4l/vidioc-dbg-g-chip-info.rst | 167 + .../media/v4l/vidioc-dbg-g-register.rst | 171 + .../userspace-api/media/v4l/vidioc-decoder-cmd.rst | 226 + .../userspace-api/media/v4l/vidioc-dqevent.rst | 391 + .../media/v4l/vidioc-dv-timings-cap.rst | 169 + .../userspace-api/media/v4l/vidioc-encoder-cmd.rst | 168 + .../media/v4l/vidioc-enum-dv-timings.rst | 114 + .../userspace-api/media/v4l/vidioc-enum-fmt.rst | 159 + .../media/v4l/vidioc-enum-frameintervals.rst | 203 + .../media/v4l/vidioc-enum-framesizes.rst | 213 + .../media/v4l/vidioc-enum-freq-bands.rst | 150 + .../userspace-api/media/v4l/vidioc-enumaudio.rst | 62 + .../media/v4l/vidioc-enumaudioout.rst | 67 + .../userspace-api/media/v4l/vidioc-enuminput.rst | 242 + .../userspace-api/media/v4l/vidioc-enumoutput.rst | 165 + .../userspace-api/media/v4l/vidioc-enumstd.rst | 367 + .../userspace-api/media/v4l/vidioc-expbuf.rst | 175 + .../userspace-api/media/v4l/vidioc-g-audio.rst | 135 + .../userspace-api/media/v4l/vidioc-g-audioout.rst | 108 + .../userspace-api/media/v4l/vidioc-g-crop.rst | 119 + .../userspace-api/media/v4l/vidioc-g-ctrl.rst | 106 + .../media/v4l/vidioc-g-dv-timings.rst | 312 + .../userspace-api/media/v4l/vidioc-g-edid.rst | 154 + .../userspace-api/media/v4l/vidioc-g-enc-index.rst | 156 + .../userspace-api/media/v4l/vidioc-g-ext-ctrls.rst | 416 ++ .../userspace-api/media/v4l/vidioc-g-fbuf.rst | 362 + .../userspace-api/media/v4l/vidioc-g-fmt.rst | 161 + .../userspace-api/media/v4l/vidioc-g-frequency.rst | 112 + .../userspace-api/media/v4l/vidioc-g-input.rst | 71 + .../userspace-api/media/v4l/vidioc-g-jpegcomp.rst | 134 + .../userspace-api/media/v4l/vidioc-g-modulator.rst | 202 + .../userspace-api/media/v4l/vidioc-g-output.rst | 73 + .../userspace-api/media/v4l/vidioc-g-parm.rst | 270 + .../userspace-api/media/v4l/vidioc-g-priority.rst | 100 + .../userspace-api/media/v4l/vidioc-g-selection.rst | 200 + .../media/v4l/vidioc-g-sliced-vbi-cap.rst | 202 + .../userspace-api/media/v4l/vidioc-g-std.rst | 81 + .../userspace-api/media/v4l/vidioc-g-tuner.rst | 476 ++ .../userspace-api/media/v4l/vidioc-log-status.rst | 56 + .../userspace-api/media/v4l/vidioc-overlay.rst | 61 + .../userspace-api/media/v4l/vidioc-prepare-buf.rst | 65 + .../userspace-api/media/v4l/vidioc-qbuf.rst | 205 + .../media/v4l/vidioc-query-dv-timings.rst | 94 + .../userspace-api/media/v4l/vidioc-querybuf.rst | 87 + .../userspace-api/media/v4l/vidioc-querycap.rst | 284 + .../userspace-api/media/v4l/vidioc-queryctrl.rst | 616 ++ .../userspace-api/media/v4l/vidioc-querystd.rst | 77 + .../userspace-api/media/v4l/vidioc-reqbufs.rst | 169 + .../media/v4l/vidioc-s-hw-freq-seek.rst | 147 + .../userspace-api/media/v4l/vidioc-streamon.rst | 113 + .../v4l/vidioc-subdev-enum-frame-interval.rst | 120 + .../media/v4l/vidioc-subdev-enum-frame-size.rst | 125 + .../media/v4l/vidioc-subdev-enum-mbus-code.rst | 98 + .../media/v4l/vidioc-subdev-g-crop.rst | 125 + .../media/v4l/vidioc-subdev-g-fmt.rst | 154 + .../media/v4l/vidioc-subdev-g-frame-interval.rst | 120 + .../media/v4l/vidioc-subdev-g-selection.rst | 125 + .../media/v4l/vidioc-subscribe-event.rst | 123 + .../userspace-api/media/v4l/yuv-formats.rst | 64 + .../userspace-api/media/video.h.rst.exceptions | 39 + .../userspace-api/media/videodev2.h.rst.exceptions | 572 ++ MAINTAINERS | 8 +- drivers/media/radio/Kconfig | 10 +- drivers/media/radio/wl128x/Kconfig | 2 +- 919 files changed, 81543 insertions(+), 81541 deletions(-) delete mode 100644 Documentation/media/Makefile delete mode 100644 Documentation/media/audio.h.rst.exceptions delete mode 100644 Documentation/media/ca.h.rst.exceptions delete mode 100644 Documentation/media/cec.h.rst.exceptions delete mode 100644 Documentation/media/conf_nitpick.py delete mode 100644 Documentation/media/dmx.h.rst.exceptions delete mode 100644 Documentation/media/frontend.h.rst.exceptions delete mode 100644 Documentation/media/intro.rst delete mode 100644 Documentation/media/lirc.h.rst.exceptions delete mode 100644 Documentation/media/media.h.rst.exceptions delete mode 100644 Documentation/media/media_uapi.rst delete mode 100644 Documentation/media/net.h.rst.exceptions delete mode 100644 Documentation/media/typical_media_device.svg delete mode 100644 Documentation/media/uapi/cec/cec-api.rst delete mode 100644 Documentation/media/uapi/cec/cec-func-close.rst delete mode 100644 Documentation/media/uapi/cec/cec-func-ioctl.rst delete mode 100644 Documentation/media/uapi/cec/cec-func-open.rst delete mode 100644 Documentation/media/uapi/cec/cec-func-poll.rst delete mode 100644 Documentation/media/uapi/cec/cec-funcs.rst delete mode 100644 Documentation/media/uapi/cec/cec-header.rst delete mode 100644 Documentation/media/uapi/cec/cec-intro.rst delete mode 100644 Documentation/media/uapi/cec/cec-ioc-adap-g-caps.rst delete mode 100644 Documentation/media/uapi/cec/cec-ioc-adap-g-conn-info.rst delete mode 100644 Documentation/media/uapi/cec/cec-ioc-adap-g-log-addrs.rst delete mode 100644 Documentation/media/uapi/cec/cec-ioc-adap-g-phys-addr.rst delete mode 100644 Documentation/media/uapi/cec/cec-ioc-dqevent.rst delete mode 100644 Documentation/media/uapi/cec/cec-ioc-g-mode.rst delete mode 100644 Documentation/media/uapi/cec/cec-ioc-receive.rst delete mode 100644 Documentation/media/uapi/cec/cec-pin-error-inj.rst delete mode 100644 Documentation/media/uapi/dvb/audio-bilingual-channel-select.rst delete mode 100644 Documentation/media/uapi/dvb/audio-channel-select.rst delete mode 100644 Documentation/media/uapi/dvb/audio-clear-buffer.rst delete mode 100644 Documentation/media/uapi/dvb/audio-continue.rst delete mode 100644 Documentation/media/uapi/dvb/audio-fclose.rst delete mode 100644 Documentation/media/uapi/dvb/audio-fopen.rst delete mode 100644 Documentation/media/uapi/dvb/audio-fwrite.rst delete mode 100644 Documentation/media/uapi/dvb/audio-get-capabilities.rst delete mode 100644 Documentation/media/uapi/dvb/audio-get-status.rst delete mode 100644 Documentation/media/uapi/dvb/audio-pause.rst delete mode 100644 Documentation/media/uapi/dvb/audio-play.rst delete mode 100644 Documentation/media/uapi/dvb/audio-select-source.rst delete mode 100644 Documentation/media/uapi/dvb/audio-set-av-sync.rst delete mode 100644 Documentation/media/uapi/dvb/audio-set-bypass-mode.rst delete mode 100644 Documentation/media/uapi/dvb/audio-set-id.rst delete mode 100644 Documentation/media/uapi/dvb/audio-set-mixer.rst delete mode 100644 Documentation/media/uapi/dvb/audio-set-mute.rst delete mode 100644 Documentation/media/uapi/dvb/audio-set-streamtype.rst delete mode 100644 Documentation/media/uapi/dvb/audio-stop.rst delete mode 100644 Documentation/media/uapi/dvb/audio.rst delete mode 100644 Documentation/media/uapi/dvb/audio_data_types.rst delete mode 100644 Documentation/media/uapi/dvb/audio_function_calls.rst delete mode 100644 Documentation/media/uapi/dvb/ca-fclose.rst delete mode 100644 Documentation/media/uapi/dvb/ca-fopen.rst delete mode 100644 Documentation/media/uapi/dvb/ca-get-cap.rst delete mode 100644 Documentation/media/uapi/dvb/ca-get-descr-info.rst delete mode 100644 Documentation/media/uapi/dvb/ca-get-msg.rst delete mode 100644 Documentation/media/uapi/dvb/ca-get-slot-info.rst delete mode 100644 Documentation/media/uapi/dvb/ca-reset.rst delete mode 100644 Documentation/media/uapi/dvb/ca-send-msg.rst delete mode 100644 Documentation/media/uapi/dvb/ca-set-descr.rst delete mode 100644 Documentation/media/uapi/dvb/ca.rst delete mode 100644 Documentation/media/uapi/dvb/ca_data_types.rst delete mode 100644 Documentation/media/uapi/dvb/ca_function_calls.rst delete mode 100644 Documentation/media/uapi/dvb/ca_high_level.rst delete mode 100644 Documentation/media/uapi/dvb/demux.rst delete mode 100644 Documentation/media/uapi/dvb/dmx-add-pid.rst delete mode 100644 Documentation/media/uapi/dvb/dmx-expbuf.rst delete mode 100644 Documentation/media/uapi/dvb/dmx-fclose.rst delete mode 100644 Documentation/media/uapi/dvb/dmx-fopen.rst delete mode 100644 Documentation/media/uapi/dvb/dmx-fread.rst delete mode 100644 Documentation/media/uapi/dvb/dmx-fwrite.rst delete mode 100644 Documentation/media/uapi/dvb/dmx-get-pes-pids.rst delete mode 100644 Documentation/media/uapi/dvb/dmx-get-stc.rst delete mode 100644 Documentation/media/uapi/dvb/dmx-mmap.rst delete mode 100644 Documentation/media/uapi/dvb/dmx-munmap.rst delete mode 100644 Documentation/media/uapi/dvb/dmx-qbuf.rst delete mode 100644 Documentation/media/uapi/dvb/dmx-querybuf.rst delete mode 100644 Documentation/media/uapi/dvb/dmx-remove-pid.rst delete mode 100644 Documentation/media/uapi/dvb/dmx-reqbufs.rst delete mode 100644 Documentation/media/uapi/dvb/dmx-set-buffer-size.rst delete mode 100644 Documentation/media/uapi/dvb/dmx-set-filter.rst delete mode 100644 Documentation/media/uapi/dvb/dmx-set-pes-filter.rst delete mode 100644 Documentation/media/uapi/dvb/dmx-start.rst delete mode 100644 Documentation/media/uapi/dvb/dmx-stop.rst delete mode 100644 Documentation/media/uapi/dvb/dmx_fcalls.rst delete mode 100644 Documentation/media/uapi/dvb/dmx_types.rst delete mode 100644 Documentation/media/uapi/dvb/dvb-fe-read-status.rst delete mode 100644 Documentation/media/uapi/dvb/dvb-frontend-event.rst delete mode 100644 Documentation/media/uapi/dvb/dvb-frontend-parameters.rst delete mode 100644 Documentation/media/uapi/dvb/dvbapi.rst delete mode 100644 Documentation/media/uapi/dvb/dvbproperty.rst delete mode 100644 Documentation/media/uapi/dvb/dvbstb.svg delete mode 100644 Documentation/media/uapi/dvb/examples.rst delete mode 100644 Documentation/media/uapi/dvb/fe-bandwidth-t.rst delete mode 100644 Documentation/media/uapi/dvb/fe-diseqc-recv-slave-reply.rst delete mode 100644 Documentation/media/uapi/dvb/fe-diseqc-reset-overload.rst delete mode 100644 Documentation/media/uapi/dvb/fe-diseqc-send-burst.rst delete mode 100644 Documentation/media/uapi/dvb/fe-diseqc-send-master-cmd.rst delete mode 100644 Documentation/media/uapi/dvb/fe-dishnetwork-send-legacy-cmd.rst delete mode 100644 Documentation/media/uapi/dvb/fe-enable-high-lnb-voltage.rst delete mode 100644 Documentation/media/uapi/dvb/fe-get-event.rst delete mode 100644 Documentation/media/uapi/dvb/fe-get-frontend.rst delete mode 100644 Documentation/media/uapi/dvb/fe-get-info.rst delete mode 100644 Documentation/media/uapi/dvb/fe-get-property.rst delete mode 100644 Documentation/media/uapi/dvb/fe-read-ber.rst delete mode 100644 Documentation/media/uapi/dvb/fe-read-signal-strength.rst delete mode 100644 Documentation/media/uapi/dvb/fe-read-snr.rst delete mode 100644 Documentation/media/uapi/dvb/fe-read-status.rst delete mode 100644 Documentation/media/uapi/dvb/fe-read-uncorrected-blocks.rst delete mode 100644 Documentation/media/uapi/dvb/fe-set-frontend-tune-mode.rst delete mode 100644 Documentation/media/uapi/dvb/fe-set-frontend.rst delete mode 100644 Documentation/media/uapi/dvb/fe-set-tone.rst delete mode 100644 Documentation/media/uapi/dvb/fe-set-voltage.rst delete mode 100644 Documentation/media/uapi/dvb/fe-type-t.rst delete mode 100644 Documentation/media/uapi/dvb/fe_property_parameters.rst delete mode 100644 Documentation/media/uapi/dvb/frontend-header.rst delete mode 100644 Documentation/media/uapi/dvb/frontend-property-cable-systems.rst delete mode 100644 Documentation/media/uapi/dvb/frontend-property-satellite-systems.rst delete mode 100644 Documentation/media/uapi/dvb/frontend-property-terrestrial-systems.rst delete mode 100644 Documentation/media/uapi/dvb/frontend-stat-properties.rst delete mode 100644 Documentation/media/uapi/dvb/frontend.rst delete mode 100644 Documentation/media/uapi/dvb/frontend_f_close.rst delete mode 100644 Documentation/media/uapi/dvb/frontend_f_open.rst delete mode 100644 Documentation/media/uapi/dvb/frontend_fcalls.rst delete mode 100644 Documentation/media/uapi/dvb/frontend_legacy_api.rst delete mode 100644 Documentation/media/uapi/dvb/frontend_legacy_dvbv3_api.rst delete mode 100644 Documentation/media/uapi/dvb/headers.rst delete mode 100644 Documentation/media/uapi/dvb/intro.rst delete mode 100644 Documentation/media/uapi/dvb/legacy_dvb_apis.rst delete mode 100644 Documentation/media/uapi/dvb/net-add-if.rst delete mode 100644 Documentation/media/uapi/dvb/net-get-if.rst delete mode 100644 Documentation/media/uapi/dvb/net-remove-if.rst delete mode 100644 Documentation/media/uapi/dvb/net-types.rst delete mode 100644 Documentation/media/uapi/dvb/net.rst delete mode 100644 Documentation/media/uapi/dvb/query-dvb-frontend-info.rst delete mode 100644 Documentation/media/uapi/dvb/video-clear-buffer.rst delete mode 100644 Documentation/media/uapi/dvb/video-command.rst delete mode 100644 Documentation/media/uapi/dvb/video-continue.rst delete mode 100644 Documentation/media/uapi/dvb/video-fast-forward.rst delete mode 100644 Documentation/media/uapi/dvb/video-fclose.rst delete mode 100644 Documentation/media/uapi/dvb/video-fopen.rst delete mode 100644 Documentation/media/uapi/dvb/video-freeze.rst delete mode 100644 Documentation/media/uapi/dvb/video-fwrite.rst delete mode 100644 Documentation/media/uapi/dvb/video-get-capabilities.rst delete mode 100644 Documentation/media/uapi/dvb/video-get-event.rst delete mode 100644 Documentation/media/uapi/dvb/video-get-frame-count.rst delete mode 100644 Documentation/media/uapi/dvb/video-get-pts.rst delete mode 100644 Documentation/media/uapi/dvb/video-get-size.rst delete mode 100644 Documentation/media/uapi/dvb/video-get-status.rst delete mode 100644 Documentation/media/uapi/dvb/video-play.rst delete mode 100644 Documentation/media/uapi/dvb/video-select-source.rst delete mode 100644 Documentation/media/uapi/dvb/video-set-blank.rst delete mode 100644 Documentation/media/uapi/dvb/video-set-display-format.rst delete mode 100644 Documentation/media/uapi/dvb/video-set-format.rst delete mode 100644 Documentation/media/uapi/dvb/video-set-streamtype.rst delete mode 100644 Documentation/media/uapi/dvb/video-slowmotion.rst delete mode 100644 Documentation/media/uapi/dvb/video-stillpicture.rst delete mode 100644 Documentation/media/uapi/dvb/video-stop.rst delete mode 100644 Documentation/media/uapi/dvb/video-try-command.rst delete mode 100644 Documentation/media/uapi/dvb/video.rst delete mode 100644 Documentation/media/uapi/dvb/video_function_calls.rst delete mode 100644 Documentation/media/uapi/dvb/video_types.rst delete mode 100644 Documentation/media/uapi/fdl-appendix.rst delete mode 100644 Documentation/media/uapi/gen-errors.rst delete mode 100644 Documentation/media/uapi/mediactl/media-controller-intro.rst delete mode 100644 Documentation/media/uapi/mediactl/media-controller-model.rst delete mode 100644 Documentation/media/uapi/mediactl/media-controller.rst delete mode 100644 Documentation/media/uapi/mediactl/media-func-close.rst delete mode 100644 Documentation/media/uapi/mediactl/media-func-ioctl.rst delete mode 100644 Documentation/media/uapi/mediactl/media-func-open.rst delete mode 100644 Documentation/media/uapi/mediactl/media-funcs.rst delete mode 100644 Documentation/media/uapi/mediactl/media-header.rst delete mode 100644 Documentation/media/uapi/mediactl/media-ioc-device-info.rst delete mode 100644 Documentation/media/uapi/mediactl/media-ioc-enum-entities.rst delete mode 100644 Documentation/media/uapi/mediactl/media-ioc-enum-links.rst delete mode 100644 Documentation/media/uapi/mediactl/media-ioc-g-topology.rst delete mode 100644 Documentation/media/uapi/mediactl/media-ioc-request-alloc.rst delete mode 100644 Documentation/media/uapi/mediactl/media-ioc-setup-link.rst delete mode 100644 Documentation/media/uapi/mediactl/media-request-ioc-queue.rst delete mode 100644 Documentation/media/uapi/mediactl/media-request-ioc-reinit.rst delete mode 100644 Documentation/media/uapi/mediactl/media-types.rst delete mode 100644 Documentation/media/uapi/mediactl/request-api.rst delete mode 100644 Documentation/media/uapi/mediactl/request-func-close.rst delete mode 100644 Documentation/media/uapi/mediactl/request-func-ioctl.rst delete mode 100644 Documentation/media/uapi/mediactl/request-func-poll.rst delete mode 100644 Documentation/media/uapi/rc/keytable.c.rst delete mode 100644 Documentation/media/uapi/rc/lirc-dev-intro.rst delete mode 100644 Documentation/media/uapi/rc/lirc-dev.rst delete mode 100644 Documentation/media/uapi/rc/lirc-func.rst delete mode 100644 Documentation/media/uapi/rc/lirc-get-features.rst delete mode 100644 Documentation/media/uapi/rc/lirc-get-rec-mode.rst delete mode 100644 Documentation/media/uapi/rc/lirc-get-rec-resolution.rst delete mode 100644 Documentation/media/uapi/rc/lirc-get-send-mode.rst delete mode 100644 Documentation/media/uapi/rc/lirc-get-timeout.rst delete mode 100644 Documentation/media/uapi/rc/lirc-header.rst delete mode 100644 Documentation/media/uapi/rc/lirc-read.rst delete mode 100644 Documentation/media/uapi/rc/lirc-set-measure-carrier-mode.rst delete mode 100644 Documentation/media/uapi/rc/lirc-set-rec-carrier-range.rst delete mode 100644 Documentation/media/uapi/rc/lirc-set-rec-carrier.rst delete mode 100644 Documentation/media/uapi/rc/lirc-set-rec-timeout-reports.rst delete mode 100644 Documentation/media/uapi/rc/lirc-set-rec-timeout.rst delete mode 100644 Documentation/media/uapi/rc/lirc-set-send-carrier.rst delete mode 100644 Documentation/media/uapi/rc/lirc-set-send-duty-cycle.rst delete mode 100644 Documentation/media/uapi/rc/lirc-set-transmitter-mask.rst delete mode 100644 Documentation/media/uapi/rc/lirc-set-wideband-receiver.rst delete mode 100644 Documentation/media/uapi/rc/lirc-write.rst delete mode 100644 Documentation/media/uapi/rc/rc-intro.rst delete mode 100644 Documentation/media/uapi/rc/rc-protos.rst delete mode 100644 Documentation/media/uapi/rc/rc-sysfs-nodes.rst delete mode 100644 Documentation/media/uapi/rc/rc-table-change.rst delete mode 100644 Documentation/media/uapi/rc/rc-tables.rst delete mode 100644 Documentation/media/uapi/rc/remote_controllers.rst delete mode 100644 Documentation/media/uapi/v4l/app-pri.rst delete mode 100644 Documentation/media/uapi/v4l/async.rst delete mode 100644 Documentation/media/uapi/v4l/audio.rst delete mode 100644 Documentation/media/uapi/v4l/bayer.svg delete mode 100644 Documentation/media/uapi/v4l/biblio.rst delete mode 100644 Documentation/media/uapi/v4l/buffer.rst delete mode 100644 Documentation/media/uapi/v4l/capture-example.rst delete mode 100644 Documentation/media/uapi/v4l/capture.c.rst delete mode 100644 Documentation/media/uapi/v4l/colorspaces-defs.rst delete mode 100644 Documentation/media/uapi/v4l/colorspaces-details.rst delete mode 100644 Documentation/media/uapi/v4l/colorspaces.rst delete mode 100644 Documentation/media/uapi/v4l/common-defs.rst delete mode 100644 Documentation/media/uapi/v4l/common.rst delete mode 100644 Documentation/media/uapi/v4l/compat.rst delete mode 100644 Documentation/media/uapi/v4l/constraints.svg delete mode 100644 Documentation/media/uapi/v4l/control.rst delete mode 100644 Documentation/media/uapi/v4l/crop.rst delete mode 100644 Documentation/media/uapi/v4l/crop.svg delete mode 100644 Documentation/media/uapi/v4l/depth-formats.rst delete mode 100644 Documentation/media/uapi/v4l/dev-capture.rst delete mode 100644 Documentation/media/uapi/v4l/dev-decoder.rst delete mode 100644 Documentation/media/uapi/v4l/dev-event.rst delete mode 100644 Documentation/media/uapi/v4l/dev-mem2mem.rst delete mode 100644 Documentation/media/uapi/v4l/dev-meta.rst delete mode 100644 Documentation/media/uapi/v4l/dev-osd.rst delete mode 100644 Documentation/media/uapi/v4l/dev-output.rst delete mode 100644 Documentation/media/uapi/v4l/dev-overlay.rst delete mode 100644 Documentation/media/uapi/v4l/dev-radio.rst delete mode 100644 Documentation/media/uapi/v4l/dev-raw-vbi.rst delete mode 100644 Documentation/media/uapi/v4l/dev-rds.rst delete mode 100644 Documentation/media/uapi/v4l/dev-sdr.rst delete mode 100644 Documentation/media/uapi/v4l/dev-sliced-vbi.rst delete mode 100644 Documentation/media/uapi/v4l/dev-stateless-decoder.rst delete mode 100644 Documentation/media/uapi/v4l/dev-subdev.rst delete mode 100644 Documentation/media/uapi/v4l/dev-touch.rst delete mode 100644 Documentation/media/uapi/v4l/devices.rst delete mode 100644 Documentation/media/uapi/v4l/diff-v4l.rst delete mode 100644 Documentation/media/uapi/v4l/dmabuf.rst delete mode 100644 Documentation/media/uapi/v4l/dv-timings.rst delete mode 100644 Documentation/media/uapi/v4l/ext-ctrls-camera.rst delete mode 100644 Documentation/media/uapi/v4l/ext-ctrls-codec.rst delete mode 100644 Documentation/media/uapi/v4l/ext-ctrls-detect.rst delete mode 100644 Documentation/media/uapi/v4l/ext-ctrls-dv.rst delete mode 100644 Documentation/media/uapi/v4l/ext-ctrls-flash.rst delete mode 100644 Documentation/media/uapi/v4l/ext-ctrls-fm-rx.rst delete mode 100644 Documentation/media/uapi/v4l/ext-ctrls-fm-tx.rst delete mode 100644 Documentation/media/uapi/v4l/ext-ctrls-image-process.rst delete mode 100644 Documentation/media/uapi/v4l/ext-ctrls-image-source.rst delete mode 100644 Documentation/media/uapi/v4l/ext-ctrls-jpeg.rst delete mode 100644 Documentation/media/uapi/v4l/ext-ctrls-rf-tuner.rst delete mode 100644 Documentation/media/uapi/v4l/extended-controls.rst delete mode 100644 Documentation/media/uapi/v4l/field-order.rst delete mode 100644 Documentation/media/uapi/v4l/fieldseq_bt.svg delete mode 100644 Documentation/media/uapi/v4l/fieldseq_tb.svg delete mode 100644 Documentation/media/uapi/v4l/format.rst delete mode 100644 Documentation/media/uapi/v4l/func-close.rst delete mode 100644 Documentation/media/uapi/v4l/func-ioctl.rst delete mode 100644 Documentation/media/uapi/v4l/func-mmap.rst delete mode 100644 Documentation/media/uapi/v4l/func-munmap.rst delete mode 100644 Documentation/media/uapi/v4l/func-open.rst delete mode 100644 Documentation/media/uapi/v4l/func-poll.rst delete mode 100644 Documentation/media/uapi/v4l/func-read.rst delete mode 100644 Documentation/media/uapi/v4l/func-select.rst delete mode 100644 Documentation/media/uapi/v4l/func-write.rst delete mode 100644 Documentation/media/uapi/v4l/hist-v4l2.rst delete mode 100644 Documentation/media/uapi/v4l/hsv-formats.rst delete mode 100644 Documentation/media/uapi/v4l/io.rst delete mode 100644 Documentation/media/uapi/v4l/libv4l-introduction.rst delete mode 100644 Documentation/media/uapi/v4l/libv4l.rst delete mode 100644 Documentation/media/uapi/v4l/meta-formats.rst delete mode 100644 Documentation/media/uapi/v4l/mmap.rst delete mode 100644 Documentation/media/uapi/v4l/nv12mt.svg delete mode 100644 Documentation/media/uapi/v4l/nv12mt_example.svg delete mode 100644 Documentation/media/uapi/v4l/open.rst delete mode 100644 Documentation/media/uapi/v4l/pipeline.dot delete mode 100644 Documentation/media/uapi/v4l/pixfmt-bayer.rst delete mode 100644 Documentation/media/uapi/v4l/pixfmt-cnf4.rst delete mode 100644 Documentation/media/uapi/v4l/pixfmt-compressed.rst delete mode 100644 Documentation/media/uapi/v4l/pixfmt-grey.rst delete mode 100644 Documentation/media/uapi/v4l/pixfmt-indexed.rst delete mode 100644 Documentation/media/uapi/v4l/pixfmt-intro.rst delete mode 100644 Documentation/media/uapi/v4l/pixfmt-inzi.rst delete mode 100644 Documentation/media/uapi/v4l/pixfmt-m420.rst delete mode 100644 Documentation/media/uapi/v4l/pixfmt-meta-d4xx.rst delete mode 100644 Documentation/media/uapi/v4l/pixfmt-meta-intel-ipu3.rst delete mode 100644 Documentation/media/uapi/v4l/pixfmt-meta-uvc.rst delete mode 100644 Documentation/media/uapi/v4l/pixfmt-meta-vivid.rst delete mode 100644 Documentation/media/uapi/v4l/pixfmt-meta-vsp1-hgo.rst delete mode 100644 Documentation/media/uapi/v4l/pixfmt-meta-vsp1-hgt.rst delete mode 100644 Documentation/media/uapi/v4l/pixfmt-nv12.rst delete mode 100644 Documentation/media/uapi/v4l/pixfmt-nv12m.rst delete mode 100644 Documentation/media/uapi/v4l/pixfmt-nv12mt.rst delete mode 100644 Documentation/media/uapi/v4l/pixfmt-nv16.rst delete mode 100644 Documentation/media/uapi/v4l/pixfmt-nv16m.rst delete mode 100644 Documentation/media/uapi/v4l/pixfmt-nv24.rst delete mode 100644 Documentation/media/uapi/v4l/pixfmt-packed-hsv.rst delete mode 100644 Documentation/media/uapi/v4l/pixfmt-packed-yuv.rst delete mode 100644 Documentation/media/uapi/v4l/pixfmt-reserved.rst delete mode 100644 Documentation/media/uapi/v4l/pixfmt-rgb.rst delete mode 100644 Documentation/media/uapi/v4l/pixfmt-sdr-cs08.rst delete mode 100644 Documentation/media/uapi/v4l/pixfmt-sdr-cs14le.rst delete mode 100644 Documentation/media/uapi/v4l/pixfmt-sdr-cu08.rst delete mode 100644 Documentation/media/uapi/v4l/pixfmt-sdr-cu16le.rst delete mode 100644 Documentation/media/uapi/v4l/pixfmt-sdr-pcu16be.rst delete mode 100644 Documentation/media/uapi/v4l/pixfmt-sdr-pcu18be.rst delete mode 100644 Documentation/media/uapi/v4l/pixfmt-sdr-pcu20be.rst delete mode 100644 Documentation/media/uapi/v4l/pixfmt-sdr-ru12le.rst delete mode 100644 Documentation/media/uapi/v4l/pixfmt-srggb10-ipu3.rst delete mode 100644 Documentation/media/uapi/v4l/pixfmt-srggb10.rst delete mode 100644 Documentation/media/uapi/v4l/pixfmt-srggb10alaw8.rst delete mode 100644 Documentation/media/uapi/v4l/pixfmt-srggb10dpcm8.rst delete mode 100644 Documentation/media/uapi/v4l/pixfmt-srggb10p.rst delete mode 100644 Documentation/media/uapi/v4l/pixfmt-srggb12.rst delete mode 100644 Documentation/media/uapi/v4l/pixfmt-srggb12p.rst delete mode 100644 Documentation/media/uapi/v4l/pixfmt-srggb14.rst delete mode 100644 Documentation/media/uapi/v4l/pixfmt-srggb14p.rst delete mode 100644 Documentation/media/uapi/v4l/pixfmt-srggb16.rst delete mode 100644 Documentation/media/uapi/v4l/pixfmt-srggb8.rst delete mode 100644 Documentation/media/uapi/v4l/pixfmt-tch-td08.rst delete mode 100644 Documentation/media/uapi/v4l/pixfmt-tch-td16.rst delete mode 100644 Documentation/media/uapi/v4l/pixfmt-tch-tu08.rst delete mode 100644 Documentation/media/uapi/v4l/pixfmt-tch-tu16.rst delete mode 100644 Documentation/media/uapi/v4l/pixfmt-uv8.rst delete mode 100644 Documentation/media/uapi/v4l/pixfmt-uyvy.rst delete mode 100644 Documentation/media/uapi/v4l/pixfmt-v4l2-mplane.rst delete mode 100644 Documentation/media/uapi/v4l/pixfmt-v4l2.rst delete mode 100644 Documentation/media/uapi/v4l/pixfmt-vyuy.rst delete mode 100644 Documentation/media/uapi/v4l/pixfmt-y10.rst delete mode 100644 Documentation/media/uapi/v4l/pixfmt-y10b.rst delete mode 100644 Documentation/media/uapi/v4l/pixfmt-y10p.rst delete mode 100644 Documentation/media/uapi/v4l/pixfmt-y12.rst delete mode 100644 Documentation/media/uapi/v4l/pixfmt-y12i.rst delete mode 100644 Documentation/media/uapi/v4l/pixfmt-y14.rst delete mode 100644 Documentation/media/uapi/v4l/pixfmt-y16-be.rst delete mode 100644 Documentation/media/uapi/v4l/pixfmt-y16.rst delete mode 100644 Documentation/media/uapi/v4l/pixfmt-y41p.rst delete mode 100644 Documentation/media/uapi/v4l/pixfmt-y8i.rst delete mode 100644 Documentation/media/uapi/v4l/pixfmt-yuv410.rst delete mode 100644 Documentation/media/uapi/v4l/pixfmt-yuv411p.rst delete mode 100644 Documentation/media/uapi/v4l/pixfmt-yuv420.rst delete mode 100644 Documentation/media/uapi/v4l/pixfmt-yuv420m.rst delete mode 100644 Documentation/media/uapi/v4l/pixfmt-yuv422m.rst delete mode 100644 Documentation/media/uapi/v4l/pixfmt-yuv422p.rst delete mode 100644 Documentation/media/uapi/v4l/pixfmt-yuv444m.rst delete mode 100644 Documentation/media/uapi/v4l/pixfmt-yuyv.rst delete mode 100644 Documentation/media/uapi/v4l/pixfmt-yvyu.rst delete mode 100644 Documentation/media/uapi/v4l/pixfmt-z16.rst delete mode 100644 Documentation/media/uapi/v4l/pixfmt.rst delete mode 100644 Documentation/media/uapi/v4l/planar-apis.rst delete mode 100644 Documentation/media/uapi/v4l/querycap.rst delete mode 100644 Documentation/media/uapi/v4l/rw.rst delete mode 100644 Documentation/media/uapi/v4l/sdr-formats.rst delete mode 100644 Documentation/media/uapi/v4l/selection-api-configuration.rst delete mode 100644 Documentation/media/uapi/v4l/selection-api-examples.rst delete mode 100644 Documentation/media/uapi/v4l/selection-api-intro.rst delete mode 100644 Documentation/media/uapi/v4l/selection-api-targets.rst delete mode 100644 Documentation/media/uapi/v4l/selection-api-vs-crop-api.rst delete mode 100644 Documentation/media/uapi/v4l/selection-api.rst delete mode 100644 Documentation/media/uapi/v4l/selection.svg delete mode 100644 Documentation/media/uapi/v4l/selections-common.rst delete mode 100644 Documentation/media/uapi/v4l/standard.rst delete mode 100644 Documentation/media/uapi/v4l/streaming-par.rst delete mode 100644 Documentation/media/uapi/v4l/subdev-formats.rst delete mode 100644 Documentation/media/uapi/v4l/subdev-image-processing-crop.svg delete mode 100644 Documentation/media/uapi/v4l/subdev-image-processing-full.svg delete mode 100644 Documentation/media/uapi/v4l/subdev-image-processing-scaling-multi-source.svg delete mode 100644 Documentation/media/uapi/v4l/tch-formats.rst delete mode 100644 Documentation/media/uapi/v4l/tuner.rst delete mode 100644 Documentation/media/uapi/v4l/user-func.rst delete mode 100644 Documentation/media/uapi/v4l/userp.rst delete mode 100644 Documentation/media/uapi/v4l/v4l2-selection-flags.rst delete mode 100644 Documentation/media/uapi/v4l/v4l2-selection-targets.rst delete mode 100644 Documentation/media/uapi/v4l/v4l2.rst delete mode 100644 Documentation/media/uapi/v4l/v4l2grab-example.rst delete mode 100644 Documentation/media/uapi/v4l/v4l2grab.c.rst delete mode 100644 Documentation/media/uapi/v4l/vbi_525.svg delete mode 100644 Documentation/media/uapi/v4l/vbi_625.svg delete mode 100644 Documentation/media/uapi/v4l/vbi_hsync.svg delete mode 100644 Documentation/media/uapi/v4l/video.rst delete mode 100644 Documentation/media/uapi/v4l/videodev.rst delete mode 100644 Documentation/media/uapi/v4l/vidioc-create-bufs.rst delete mode 100644 Documentation/media/uapi/v4l/vidioc-cropcap.rst delete mode 100644 Documentation/media/uapi/v4l/vidioc-dbg-g-chip-info.rst delete mode 100644 Documentation/media/uapi/v4l/vidioc-dbg-g-register.rst delete mode 100644 Documentation/media/uapi/v4l/vidioc-decoder-cmd.rst delete mode 100644 Documentation/media/uapi/v4l/vidioc-dqevent.rst delete mode 100644 Documentation/media/uapi/v4l/vidioc-dv-timings-cap.rst delete mode 100644 Documentation/media/uapi/v4l/vidioc-encoder-cmd.rst delete mode 100644 Documentation/media/uapi/v4l/vidioc-enum-dv-timings.rst delete mode 100644 Documentation/media/uapi/v4l/vidioc-enum-fmt.rst delete mode 100644 Documentation/media/uapi/v4l/vidioc-enum-frameintervals.rst delete mode 100644 Documentation/media/uapi/v4l/vidioc-enum-framesizes.rst delete mode 100644 Documentation/media/uapi/v4l/vidioc-enum-freq-bands.rst delete mode 100644 Documentation/media/uapi/v4l/vidioc-enumaudio.rst delete mode 100644 Documentation/media/uapi/v4l/vidioc-enumaudioout.rst delete mode 100644 Documentation/media/uapi/v4l/vidioc-enuminput.rst delete mode 100644 Documentation/media/uapi/v4l/vidioc-enumoutput.rst delete mode 100644 Documentation/media/uapi/v4l/vidioc-enumstd.rst delete mode 100644 Documentation/media/uapi/v4l/vidioc-expbuf.rst delete mode 100644 Documentation/media/uapi/v4l/vidioc-g-audio.rst delete mode 100644 Documentation/media/uapi/v4l/vidioc-g-audioout.rst delete mode 100644 Documentation/media/uapi/v4l/vidioc-g-crop.rst delete mode 100644 Documentation/media/uapi/v4l/vidioc-g-ctrl.rst delete mode 100644 Documentation/media/uapi/v4l/vidioc-g-dv-timings.rst delete mode 100644 Documentation/media/uapi/v4l/vidioc-g-edid.rst delete mode 100644 Documentation/media/uapi/v4l/vidioc-g-enc-index.rst delete mode 100644 Documentation/media/uapi/v4l/vidioc-g-ext-ctrls.rst delete mode 100644 Documentation/media/uapi/v4l/vidioc-g-fbuf.rst delete mode 100644 Documentation/media/uapi/v4l/vidioc-g-fmt.rst delete mode 100644 Documentation/media/uapi/v4l/vidioc-g-frequency.rst delete mode 100644 Documentation/media/uapi/v4l/vidioc-g-input.rst delete mode 100644 Documentation/media/uapi/v4l/vidioc-g-jpegcomp.rst delete mode 100644 Documentation/media/uapi/v4l/vidioc-g-modulator.rst delete mode 100644 Documentation/media/uapi/v4l/vidioc-g-output.rst delete mode 100644 Documentation/media/uapi/v4l/vidioc-g-parm.rst delete mode 100644 Documentation/media/uapi/v4l/vidioc-g-priority.rst delete mode 100644 Documentation/media/uapi/v4l/vidioc-g-selection.rst delete mode 100644 Documentation/media/uapi/v4l/vidioc-g-sliced-vbi-cap.rst delete mode 100644 Documentation/media/uapi/v4l/vidioc-g-std.rst delete mode 100644 Documentation/media/uapi/v4l/vidioc-g-tuner.rst delete mode 100644 Documentation/media/uapi/v4l/vidioc-log-status.rst delete mode 100644 Documentation/media/uapi/v4l/vidioc-overlay.rst delete mode 100644 Documentation/media/uapi/v4l/vidioc-prepare-buf.rst delete mode 100644 Documentation/media/uapi/v4l/vidioc-qbuf.rst delete mode 100644 Documentation/media/uapi/v4l/vidioc-query-dv-timings.rst delete mode 100644 Documentation/media/uapi/v4l/vidioc-querybuf.rst delete mode 100644 Documentation/media/uapi/v4l/vidioc-querycap.rst delete mode 100644 Documentation/media/uapi/v4l/vidioc-queryctrl.rst delete mode 100644 Documentation/media/uapi/v4l/vidioc-querystd.rst delete mode 100644 Documentation/media/uapi/v4l/vidioc-reqbufs.rst delete mode 100644 Documentation/media/uapi/v4l/vidioc-s-hw-freq-seek.rst delete mode 100644 Documentation/media/uapi/v4l/vidioc-streamon.rst delete mode 100644 Documentation/media/uapi/v4l/vidioc-subdev-enum-frame-interval.rst delete mode 100644 Documentation/media/uapi/v4l/vidioc-subdev-enum-frame-size.rst delete mode 100644 Documentation/media/uapi/v4l/vidioc-subdev-enum-mbus-code.rst delete mode 100644 Documentation/media/uapi/v4l/vidioc-subdev-g-crop.rst delete mode 100644 Documentation/media/uapi/v4l/vidioc-subdev-g-fmt.rst delete mode 100644 Documentation/media/uapi/v4l/vidioc-subdev-g-frame-interval.rst delete mode 100644 Documentation/media/uapi/v4l/vidioc-subdev-g-selection.rst delete mode 100644 Documentation/media/uapi/v4l/vidioc-subscribe-event.rst delete mode 100644 Documentation/media/uapi/v4l/yuv-formats.rst delete mode 100644 Documentation/media/video.h.rst.exceptions delete mode 100644 Documentation/media/videodev2.h.rst.exceptions create mode 100644 Documentation/userspace-api/media/Makefile create mode 100644 Documentation/userspace-api/media/audio.h.rst.exceptions create mode 100644 Documentation/userspace-api/media/ca.h.rst.exceptions create mode 100644 Documentation/userspace-api/media/cec.h.rst.exceptions create mode 100644 Documentation/userspace-api/media/cec/cec-api.rst create mode 100644 Documentation/userspace-api/media/cec/cec-func-close.rst create mode 100644 Documentation/userspace-api/media/cec/cec-func-ioctl.rst create mode 100644 Documentation/userspace-api/media/cec/cec-func-open.rst create mode 100644 Documentation/userspace-api/media/cec/cec-func-poll.rst create mode 100644 Documentation/userspace-api/media/cec/cec-funcs.rst create mode 100644 Documentation/userspace-api/media/cec/cec-header.rst create mode 100644 Documentation/userspace-api/media/cec/cec-intro.rst create mode 100644 Documentation/userspace-api/media/cec/cec-ioc-adap-g-caps.rst create mode 100644 Documentation/userspace-api/media/cec/cec-ioc-adap-g-conn-info.rst create mode 100644 Documentation/userspace-api/media/cec/cec-ioc-adap-g-log-addrs.rst create mode 100644 Documentation/userspace-api/media/cec/cec-ioc-adap-g-phys-addr.rst create mode 100644 Documentation/userspace-api/media/cec/cec-ioc-dqevent.rst create mode 100644 Documentation/userspace-api/media/cec/cec-ioc-g-mode.rst create mode 100644 Documentation/userspace-api/media/cec/cec-ioc-receive.rst create mode 100644 Documentation/userspace-api/media/cec/cec-pin-error-inj.rst create mode 100644 Documentation/userspace-api/media/conf_nitpick.py create mode 100644 Documentation/userspace-api/media/dmx.h.rst.exceptions create mode 100644 Documentation/userspace-api/media/dvb/audio-bilingual-channel-select.rst create mode 100644 Documentation/userspace-api/media/dvb/audio-channel-select.rst create mode 100644 Documentation/userspace-api/media/dvb/audio-clear-buffer.rst create mode 100644 Documentation/userspace-api/media/dvb/audio-continue.rst create mode 100644 Documentation/userspace-api/media/dvb/audio-fclose.rst create mode 100644 Documentation/userspace-api/media/dvb/audio-fopen.rst create mode 100644 Documentation/userspace-api/media/dvb/audio-fwrite.rst create mode 100644 Documentation/userspace-api/media/dvb/audio-get-capabilities.rst create mode 100644 Documentation/userspace-api/media/dvb/audio-get-status.rst create mode 100644 Documentation/userspace-api/media/dvb/audio-pause.rst create mode 100644 Documentation/userspace-api/media/dvb/audio-play.rst create mode 100644 Documentation/userspace-api/media/dvb/audio-select-source.rst create mode 100644 Documentation/userspace-api/media/dvb/audio-set-av-sync.rst create mode 100644 Documentation/userspace-api/media/dvb/audio-set-bypass-mode.rst create mode 100644 Documentation/userspace-api/media/dvb/audio-set-id.rst create mode 100644 Documentation/userspace-api/media/dvb/audio-set-mixer.rst create mode 100644 Documentation/userspace-api/media/dvb/audio-set-mute.rst create mode 100644 Documentation/userspace-api/media/dvb/audio-set-streamtype.rst create mode 100644 Documentation/userspace-api/media/dvb/audio-stop.rst create mode 100644 Documentation/userspace-api/media/dvb/audio.rst create mode 100644 Documentation/userspace-api/media/dvb/audio_data_types.rst create mode 100644 Documentation/userspace-api/media/dvb/audio_function_calls.rst create mode 100644 Documentation/userspace-api/media/dvb/ca-fclose.rst create mode 100644 Documentation/userspace-api/media/dvb/ca-fopen.rst create mode 100644 Documentation/userspace-api/media/dvb/ca-get-cap.rst create mode 100644 Documentation/userspace-api/media/dvb/ca-get-descr-info.rst create mode 100644 Documentation/userspace-api/media/dvb/ca-get-msg.rst create mode 100644 Documentation/userspace-api/media/dvb/ca-get-slot-info.rst create mode 100644 Documentation/userspace-api/media/dvb/ca-reset.rst create mode 100644 Documentation/userspace-api/media/dvb/ca-send-msg.rst create mode 100644 Documentation/userspace-api/media/dvb/ca-set-descr.rst create mode 100644 Documentation/userspace-api/media/dvb/ca.rst create mode 100644 Documentation/userspace-api/media/dvb/ca_data_types.rst create mode 100644 Documentation/userspace-api/media/dvb/ca_function_calls.rst create mode 100644 Documentation/userspace-api/media/dvb/ca_high_level.rst create mode 100644 Documentation/userspace-api/media/dvb/demux.rst create mode 100644 Documentation/userspace-api/media/dvb/dmx-add-pid.rst create mode 100644 Documentation/userspace-api/media/dvb/dmx-expbuf.rst create mode 100644 Documentation/userspace-api/media/dvb/dmx-fclose.rst create mode 100644 Documentation/userspace-api/media/dvb/dmx-fopen.rst create mode 100644 Documentation/userspace-api/media/dvb/dmx-fread.rst create mode 100644 Documentation/userspace-api/media/dvb/dmx-fwrite.rst create mode 100644 Documentation/userspace-api/media/dvb/dmx-get-pes-pids.rst create mode 100644 Documentation/userspace-api/media/dvb/dmx-get-stc.rst create mode 100644 Documentation/userspace-api/media/dvb/dmx-mmap.rst create mode 100644 Documentation/userspace-api/media/dvb/dmx-munmap.rst create mode 100644 Documentation/userspace-api/media/dvb/dmx-qbuf.rst create mode 100644 Documentation/userspace-api/media/dvb/dmx-querybuf.rst create mode 100644 Documentation/userspace-api/media/dvb/dmx-remove-pid.rst create mode 100644 Documentation/userspace-api/media/dvb/dmx-reqbufs.rst create mode 100644 Documentation/userspace-api/media/dvb/dmx-set-buffer-size.rst create mode 100644 Documentation/userspace-api/media/dvb/dmx-set-filter.rst create mode 100644 Documentation/userspace-api/media/dvb/dmx-set-pes-filter.rst create mode 100644 Documentation/userspace-api/media/dvb/dmx-start.rst create mode 100644 Documentation/userspace-api/media/dvb/dmx-stop.rst create mode 100644 Documentation/userspace-api/media/dvb/dmx_fcalls.rst create mode 100644 Documentation/userspace-api/media/dvb/dmx_types.rst create mode 100644 Documentation/userspace-api/media/dvb/dvb-fe-read-status.rst create mode 100644 Documentation/userspace-api/media/dvb/dvb-frontend-event.rst create mode 100644 Documentation/userspace-api/media/dvb/dvb-frontend-parameters.rst create mode 100644 Documentation/userspace-api/media/dvb/dvbapi.rst create mode 100644 Documentation/userspace-api/media/dvb/dvbproperty.rst create mode 100644 Documentation/userspace-api/media/dvb/dvbstb.svg create mode 100644 Documentation/userspace-api/media/dvb/examples.rst create mode 100644 Documentation/userspace-api/media/dvb/fe-bandwidth-t.rst create mode 100644 Documentation/userspace-api/media/dvb/fe-diseqc-recv-slave-reply.rst create mode 100644 Documentation/userspace-api/media/dvb/fe-diseqc-reset-overload.rst create mode 100644 Documentation/userspace-api/media/dvb/fe-diseqc-send-burst.rst create mode 100644 Documentation/userspace-api/media/dvb/fe-diseqc-send-master-cmd.rst create mode 100644 Documentation/userspace-api/media/dvb/fe-dishnetwork-send-legacy-cmd.rst create mode 100644 Documentation/userspace-api/media/dvb/fe-enable-high-lnb-voltage.rst create mode 100644 Documentation/userspace-api/media/dvb/fe-get-event.rst create mode 100644 Documentation/userspace-api/media/dvb/fe-get-frontend.rst create mode 100644 Documentation/userspace-api/media/dvb/fe-get-info.rst create mode 100644 Documentation/userspace-api/media/dvb/fe-get-property.rst create mode 100644 Documentation/userspace-api/media/dvb/fe-read-ber.rst create mode 100644 Documentation/userspace-api/media/dvb/fe-read-signal-strength.rst create mode 100644 Documentation/userspace-api/media/dvb/fe-read-snr.rst create mode 100644 Documentation/userspace-api/media/dvb/fe-read-status.rst create mode 100644 Documentation/userspace-api/media/dvb/fe-read-uncorrected-blocks.rst create mode 100644 Documentation/userspace-api/media/dvb/fe-set-frontend-tune-mode.rst create mode 100644 Documentation/userspace-api/media/dvb/fe-set-frontend.rst create mode 100644 Documentation/userspace-api/media/dvb/fe-set-tone.rst create mode 100644 Documentation/userspace-api/media/dvb/fe-set-voltage.rst create mode 100644 Documentation/userspace-api/media/dvb/fe-type-t.rst create mode 100644 Documentation/userspace-api/media/dvb/fe_property_parameters.rst create mode 100644 Documentation/userspace-api/media/dvb/frontend-header.rst create mode 100644 Documentation/userspace-api/media/dvb/frontend-property-cable-systems.rst create mode 100644 Documentation/userspace-api/media/dvb/frontend-property-satellite-systems.rst create mode 100644 Documentation/userspace-api/media/dvb/frontend-property-terrestrial-systems.rst create mode 100644 Documentation/userspace-api/media/dvb/frontend-stat-properties.rst create mode 100644 Documentation/userspace-api/media/dvb/frontend.rst create mode 100644 Documentation/userspace-api/media/dvb/frontend_f_close.rst create mode 100644 Documentation/userspace-api/media/dvb/frontend_f_open.rst create mode 100644 Documentation/userspace-api/media/dvb/frontend_fcalls.rst create mode 100644 Documentation/userspace-api/media/dvb/frontend_legacy_api.rst create mode 100644 Documentation/userspace-api/media/dvb/frontend_legacy_dvbv3_api.rst create mode 100644 Documentation/userspace-api/media/dvb/headers.rst create mode 100644 Documentation/userspace-api/media/dvb/intro.rst create mode 100644 Documentation/userspace-api/media/dvb/legacy_dvb_apis.rst create mode 100644 Documentation/userspace-api/media/dvb/net-add-if.rst create mode 100644 Documentation/userspace-api/media/dvb/net-get-if.rst create mode 100644 Documentation/userspace-api/media/dvb/net-remove-if.rst create mode 100644 Documentation/userspace-api/media/dvb/net-types.rst create mode 100644 Documentation/userspace-api/media/dvb/net.rst create mode 100644 Documentation/userspace-api/media/dvb/query-dvb-frontend-info.rst create mode 100644 Documentation/userspace-api/media/dvb/video-clear-buffer.rst create mode 100644 Documentation/userspace-api/media/dvb/video-command.rst create mode 100644 Documentation/userspace-api/media/dvb/video-continue.rst create mode 100644 Documentation/userspace-api/media/dvb/video-fast-forward.rst create mode 100644 Documentation/userspace-api/media/dvb/video-fclose.rst create mode 100644 Documentation/userspace-api/media/dvb/video-fopen.rst create mode 100644 Documentation/userspace-api/media/dvb/video-freeze.rst create mode 100644 Documentation/userspace-api/media/dvb/video-fwrite.rst create mode 100644 Documentation/userspace-api/media/dvb/video-get-capabilities.rst create mode 100644 Documentation/userspace-api/media/dvb/video-get-event.rst create mode 100644 Documentation/userspace-api/media/dvb/video-get-frame-count.rst create mode 100644 Documentation/userspace-api/media/dvb/video-get-pts.rst create mode 100644 Documentation/userspace-api/media/dvb/video-get-size.rst create mode 100644 Documentation/userspace-api/media/dvb/video-get-status.rst create mode 100644 Documentation/userspace-api/media/dvb/video-play.rst create mode 100644 Documentation/userspace-api/media/dvb/video-select-source.rst create mode 100644 Documentation/userspace-api/media/dvb/video-set-blank.rst create mode 100644 Documentation/userspace-api/media/dvb/video-set-display-format.rst create mode 100644 Documentation/userspace-api/media/dvb/video-set-format.rst create mode 100644 Documentation/userspace-api/media/dvb/video-set-streamtype.rst create mode 100644 Documentation/userspace-api/media/dvb/video-slowmotion.rst create mode 100644 Documentation/userspace-api/media/dvb/video-stillpicture.rst create mode 100644 Documentation/userspace-api/media/dvb/video-stop.rst create mode 100644 Documentation/userspace-api/media/dvb/video-try-command.rst create mode 100644 Documentation/userspace-api/media/dvb/video.rst create mode 100644 Documentation/userspace-api/media/dvb/video_function_calls.rst create mode 100644 Documentation/userspace-api/media/dvb/video_types.rst create mode 100644 Documentation/userspace-api/media/fdl-appendix.rst create mode 100644 Documentation/userspace-api/media/frontend.h.rst.exceptions create mode 100644 Documentation/userspace-api/media/gen-errors.rst create mode 100644 Documentation/userspace-api/media/index.rst create mode 100644 Documentation/userspace-api/media/intro.rst create mode 100644 Documentation/userspace-api/media/lirc.h.rst.exceptions create mode 100644 Documentation/userspace-api/media/media.h.rst.exceptions create mode 100644 Documentation/userspace-api/media/mediactl/media-controller-intro.rst create mode 100644 Documentation/userspace-api/media/mediactl/media-controller-model.rst create mode 100644 Documentation/userspace-api/media/mediactl/media-controller.rst create mode 100644 Documentation/userspace-api/media/mediactl/media-func-close.rst create mode 100644 Documentation/userspace-api/media/mediactl/media-func-ioctl.rst create mode 100644 Documentation/userspace-api/media/mediactl/media-func-open.rst create mode 100644 Documentation/userspace-api/media/mediactl/media-funcs.rst create mode 100644 Documentation/userspace-api/media/mediactl/media-header.rst create mode 100644 Documentation/userspace-api/media/mediactl/media-ioc-device-info.rst create mode 100644 Documentation/userspace-api/media/mediactl/media-ioc-enum-entities.rst create mode 100644 Documentation/userspace-api/media/mediactl/media-ioc-enum-links.rst create mode 100644 Documentation/userspace-api/media/mediactl/media-ioc-g-topology.rst create mode 100644 Documentation/userspace-api/media/mediactl/media-ioc-request-alloc.rst create mode 100644 Documentation/userspace-api/media/mediactl/media-ioc-setup-link.rst create mode 100644 Documentation/userspace-api/media/mediactl/media-request-ioc-queue.rst create mode 100644 Documentation/userspace-api/media/mediactl/media-request-ioc-reinit.rst create mode 100644 Documentation/userspace-api/media/mediactl/media-types.rst create mode 100644 Documentation/userspace-api/media/mediactl/request-api.rst create mode 100644 Documentation/userspace-api/media/mediactl/request-func-close.rst create mode 100644 Documentation/userspace-api/media/mediactl/request-func-ioctl.rst create mode 100644 Documentation/userspace-api/media/mediactl/request-func-poll.rst create mode 100644 Documentation/userspace-api/media/net.h.rst.exceptions create mode 100644 Documentation/userspace-api/media/rc/keytable.c.rst create mode 100644 Documentation/userspace-api/media/rc/lirc-dev-intro.rst create mode 100644 Documentation/userspace-api/media/rc/lirc-dev.rst create mode 100644 Documentation/userspace-api/media/rc/lirc-func.rst create mode 100644 Documentation/userspace-api/media/rc/lirc-get-features.rst create mode 100644 Documentation/userspace-api/media/rc/lirc-get-rec-mode.rst create mode 100644 Documentation/userspace-api/media/rc/lirc-get-rec-resolution.rst create mode 100644 Documentation/userspace-api/media/rc/lirc-get-send-mode.rst create mode 100644 Documentation/userspace-api/media/rc/lirc-get-timeout.rst create mode 100644 Documentation/userspace-api/media/rc/lirc-header.rst create mode 100644 Documentation/userspace-api/media/rc/lirc-read.rst create mode 100644 Documentation/userspace-api/media/rc/lirc-set-measure-carrier-mode.rst create mode 100644 Documentation/userspace-api/media/rc/lirc-set-rec-carrier-range.rst create mode 100644 Documentation/userspace-api/media/rc/lirc-set-rec-carrier.rst create mode 100644 Documentation/userspace-api/media/rc/lirc-set-rec-timeout-reports.rst create mode 100644 Documentation/userspace-api/media/rc/lirc-set-rec-timeout.rst create mode 100644 Documentation/userspace-api/media/rc/lirc-set-send-carrier.rst create mode 100644 Documentation/userspace-api/media/rc/lirc-set-send-duty-cycle.rst create mode 100644 Documentation/userspace-api/media/rc/lirc-set-transmitter-mask.rst create mode 100644 Documentation/userspace-api/media/rc/lirc-set-wideband-receiver.rst create mode 100644 Documentation/userspace-api/media/rc/lirc-write.rst create mode 100644 Documentation/userspace-api/media/rc/rc-intro.rst create mode 100644 Documentation/userspace-api/media/rc/rc-protos.rst create mode 100644 Documentation/userspace-api/media/rc/rc-sysfs-nodes.rst create mode 100644 Documentation/userspace-api/media/rc/rc-table-change.rst create mode 100644 Documentation/userspace-api/media/rc/rc-tables.rst create mode 100644 Documentation/userspace-api/media/rc/remote_controllers.rst create mode 100644 Documentation/userspace-api/media/typical_media_device.svg create mode 100644 Documentation/userspace-api/media/v4l/app-pri.rst create mode 100644 Documentation/userspace-api/media/v4l/async.rst create mode 100644 Documentation/userspace-api/media/v4l/audio.rst create mode 100644 Documentation/userspace-api/media/v4l/bayer.svg create mode 100644 Documentation/userspace-api/media/v4l/biblio.rst create mode 100644 Documentation/userspace-api/media/v4l/buffer.rst create mode 100644 Documentation/userspace-api/media/v4l/capture-example.rst create mode 100644 Documentation/userspace-api/media/v4l/capture.c.rst create mode 100644 Documentation/userspace-api/media/v4l/colorspaces-defs.rst create mode 100644 Documentation/userspace-api/media/v4l/colorspaces-details.rst create mode 100644 Documentation/userspace-api/media/v4l/colorspaces.rst create mode 100644 Documentation/userspace-api/media/v4l/common-defs.rst create mode 100644 Documentation/userspace-api/media/v4l/common.rst create mode 100644 Documentation/userspace-api/media/v4l/compat.rst create mode 100644 Documentation/userspace-api/media/v4l/constraints.svg create mode 100644 Documentation/userspace-api/media/v4l/control.rst create mode 100644 Documentation/userspace-api/media/v4l/crop.rst create mode 100644 Documentation/userspace-api/media/v4l/crop.svg create mode 100644 Documentation/userspace-api/media/v4l/depth-formats.rst create mode 100644 Documentation/userspace-api/media/v4l/dev-capture.rst create mode 100644 Documentation/userspace-api/media/v4l/dev-decoder.rst create mode 100644 Documentation/userspace-api/media/v4l/dev-event.rst create mode 100644 Documentation/userspace-api/media/v4l/dev-mem2mem.rst create mode 100644 Documentation/userspace-api/media/v4l/dev-meta.rst create mode 100644 Documentation/userspace-api/media/v4l/dev-osd.rst create mode 100644 Documentation/userspace-api/media/v4l/dev-output.rst create mode 100644 Documentation/userspace-api/media/v4l/dev-overlay.rst create mode 100644 Documentation/userspace-api/media/v4l/dev-radio.rst create mode 100644 Documentation/userspace-api/media/v4l/dev-raw-vbi.rst create mode 100644 Documentation/userspace-api/media/v4l/dev-rds.rst create mode 100644 Documentation/userspace-api/media/v4l/dev-sdr.rst create mode 100644 Documentation/userspace-api/media/v4l/dev-sliced-vbi.rst create mode 100644 Documentation/userspace-api/media/v4l/dev-stateless-decoder.rst create mode 100644 Documentation/userspace-api/media/v4l/dev-subdev.rst create mode 100644 Documentation/userspace-api/media/v4l/dev-touch.rst create mode 100644 Documentation/userspace-api/media/v4l/devices.rst create mode 100644 Documentation/userspace-api/media/v4l/diff-v4l.rst create mode 100644 Documentation/userspace-api/media/v4l/dmabuf.rst create mode 100644 Documentation/userspace-api/media/v4l/dv-timings.rst create mode 100644 Documentation/userspace-api/media/v4l/ext-ctrls-camera.rst create mode 100644 Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst create mode 100644 Documentation/userspace-api/media/v4l/ext-ctrls-detect.rst create mode 100644 Documentation/userspace-api/media/v4l/ext-ctrls-dv.rst create mode 100644 Documentation/userspace-api/media/v4l/ext-ctrls-flash.rst create mode 100644 Documentation/userspace-api/media/v4l/ext-ctrls-fm-rx.rst create mode 100644 Documentation/userspace-api/media/v4l/ext-ctrls-fm-tx.rst create mode 100644 Documentation/userspace-api/media/v4l/ext-ctrls-image-process.rst create mode 100644 Documentation/userspace-api/media/v4l/ext-ctrls-image-source.rst create mode 100644 Documentation/userspace-api/media/v4l/ext-ctrls-jpeg.rst create mode 100644 Documentation/userspace-api/media/v4l/ext-ctrls-rf-tuner.rst create mode 100644 Documentation/userspace-api/media/v4l/extended-controls.rst create mode 100644 Documentation/userspace-api/media/v4l/field-order.rst create mode 100644 Documentation/userspace-api/media/v4l/fieldseq_bt.svg create mode 100644 Documentation/userspace-api/media/v4l/fieldseq_tb.svg create mode 100644 Documentation/userspace-api/media/v4l/format.rst create mode 100644 Documentation/userspace-api/media/v4l/func-close.rst create mode 100644 Documentation/userspace-api/media/v4l/func-ioctl.rst create mode 100644 Documentation/userspace-api/media/v4l/func-mmap.rst create mode 100644 Documentation/userspace-api/media/v4l/func-munmap.rst create mode 100644 Documentation/userspace-api/media/v4l/func-open.rst create mode 100644 Documentation/userspace-api/media/v4l/func-poll.rst create mode 100644 Documentation/userspace-api/media/v4l/func-read.rst create mode 100644 Documentation/userspace-api/media/v4l/func-select.rst create mode 100644 Documentation/userspace-api/media/v4l/func-write.rst create mode 100644 Documentation/userspace-api/media/v4l/hist-v4l2.rst create mode 100644 Documentation/userspace-api/media/v4l/hsv-formats.rst create mode 100644 Documentation/userspace-api/media/v4l/io.rst create mode 100644 Documentation/userspace-api/media/v4l/libv4l-introduction.rst create mode 100644 Documentation/userspace-api/media/v4l/libv4l.rst create mode 100644 Documentation/userspace-api/media/v4l/meta-formats.rst create mode 100644 Documentation/userspace-api/media/v4l/mmap.rst create mode 100644 Documentation/userspace-api/media/v4l/nv12mt.svg create mode 100644 Documentation/userspace-api/media/v4l/nv12mt_example.svg create mode 100644 Documentation/userspace-api/media/v4l/open.rst create mode 100644 Documentation/userspace-api/media/v4l/pipeline.dot create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-bayer.rst create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-cnf4.rst create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-compressed.rst create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-grey.rst create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-indexed.rst create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-intro.rst create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-inzi.rst create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-m420.rst create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-meta-d4xx.rst create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-meta-intel-ipu3.rst create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-meta-uvc.rst create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-meta-vivid.rst create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-meta-vsp1-hgo.rst create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-meta-vsp1-hgt.rst create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-nv12.rst create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-nv12m.rst create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-nv12mt.rst create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-nv16.rst create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-nv16m.rst create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-nv24.rst create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-packed-hsv.rst create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-packed-yuv.rst create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-reserved.rst create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-rgb.rst create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-sdr-cs08.rst create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-sdr-cs14le.rst create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-sdr-cu08.rst create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-sdr-cu16le.rst create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-sdr-pcu16be.rst create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-sdr-pcu18be.rst create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-sdr-pcu20be.rst create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-sdr-ru12le.rst create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-srggb10-ipu3.rst create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-srggb10.rst create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-srggb10alaw8.rst create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-srggb10dpcm8.rst create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-srggb10p.rst create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-srggb12.rst create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-srggb12p.rst create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-srggb14.rst create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-srggb14p.rst create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-srggb16.rst create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-srggb8.rst create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-tch-td08.rst create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-tch-td16.rst create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-tch-tu08.rst create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-tch-tu16.rst create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-uv8.rst create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-uyvy.rst create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-v4l2-mplane.rst create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-v4l2.rst create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-vyuy.rst create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-y10.rst create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-y10b.rst create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-y10p.rst create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-y12.rst create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-y12i.rst create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-y14.rst create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-y16-be.rst create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-y16.rst create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-y41p.rst create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-y8i.rst create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-yuv410.rst create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-yuv411p.rst create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-yuv420.rst create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-yuv420m.rst create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-yuv422m.rst create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-yuv422p.rst create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-yuv444m.rst create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-yuyv.rst create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-yvyu.rst create mode 100644 Documentation/userspace-api/media/v4l/pixfmt-z16.rst create mode 100644 Documentation/userspace-api/media/v4l/pixfmt.rst create mode 100644 Documentation/userspace-api/media/v4l/planar-apis.rst create mode 100644 Documentation/userspace-api/media/v4l/querycap.rst create mode 100644 Documentation/userspace-api/media/v4l/rw.rst create mode 100644 Documentation/userspace-api/media/v4l/sdr-formats.rst create mode 100644 Documentation/userspace-api/media/v4l/selection-api-configuration.rst create mode 100644 Documentation/userspace-api/media/v4l/selection-api-examples.rst create mode 100644 Documentation/userspace-api/media/v4l/selection-api-intro.rst create mode 100644 Documentation/userspace-api/media/v4l/selection-api-targets.rst create mode 100644 Documentation/userspace-api/media/v4l/selection-api-vs-crop-api.rst create mode 100644 Documentation/userspace-api/media/v4l/selection-api.rst create mode 100644 Documentation/userspace-api/media/v4l/selection.svg create mode 100644 Documentation/userspace-api/media/v4l/selections-common.rst create mode 100644 Documentation/userspace-api/media/v4l/standard.rst create mode 100644 Documentation/userspace-api/media/v4l/streaming-par.rst create mode 100644 Documentation/userspace-api/media/v4l/subdev-formats.rst create mode 100644 Documentation/userspace-api/media/v4l/subdev-image-processing-crop.svg create mode 100644 Documentation/userspace-api/media/v4l/subdev-image-processing-full.svg create mode 100644 Documentation/userspace-api/media/v4l/subdev-image-processing-scaling-multi-source.svg create mode 100644 Documentation/userspace-api/media/v4l/tch-formats.rst create mode 100644 Documentation/userspace-api/media/v4l/tuner.rst create mode 100644 Documentation/userspace-api/media/v4l/user-func.rst create mode 100644 Documentation/userspace-api/media/v4l/userp.rst create mode 100644 Documentation/userspace-api/media/v4l/v4l2-selection-flags.rst create mode 100644 Documentation/userspace-api/media/v4l/v4l2-selection-targets.rst create mode 100644 Documentation/userspace-api/media/v4l/v4l2.rst create mode 100644 Documentation/userspace-api/media/v4l/v4l2grab-example.rst create mode 100644 Documentation/userspace-api/media/v4l/v4l2grab.c.rst create mode 100644 Documentation/userspace-api/media/v4l/vbi_525.svg create mode 100644 Documentation/userspace-api/media/v4l/vbi_625.svg create mode 100644 Documentation/userspace-api/media/v4l/vbi_hsync.svg create mode 100644 Documentation/userspace-api/media/v4l/video.rst create mode 100644 Documentation/userspace-api/media/v4l/videodev.rst create mode 100644 Documentation/userspace-api/media/v4l/vidioc-create-bufs.rst create mode 100644 Documentation/userspace-api/media/v4l/vidioc-cropcap.rst create mode 100644 Documentation/userspace-api/media/v4l/vidioc-dbg-g-chip-info.rst create mode 100644 Documentation/userspace-api/media/v4l/vidioc-dbg-g-register.rst create mode 100644 Documentation/userspace-api/media/v4l/vidioc-decoder-cmd.rst create mode 100644 Documentation/userspace-api/media/v4l/vidioc-dqevent.rst create mode 100644 Documentation/userspace-api/media/v4l/vidioc-dv-timings-cap.rst create mode 100644 Documentation/userspace-api/media/v4l/vidioc-encoder-cmd.rst create mode 100644 Documentation/userspace-api/media/v4l/vidioc-enum-dv-timings.rst create mode 100644 Documentation/userspace-api/media/v4l/vidioc-enum-fmt.rst create mode 100644 Documentation/userspace-api/media/v4l/vidioc-enum-frameintervals.rst create mode 100644 Documentation/userspace-api/media/v4l/vidioc-enum-framesizes.rst create mode 100644 Documentation/userspace-api/media/v4l/vidioc-enum-freq-bands.rst create mode 100644 Documentation/userspace-api/media/v4l/vidioc-enumaudio.rst create mode 100644 Documentation/userspace-api/media/v4l/vidioc-enumaudioout.rst create mode 100644 Documentation/userspace-api/media/v4l/vidioc-enuminput.rst create mode 100644 Documentation/userspace-api/media/v4l/vidioc-enumoutput.rst create mode 100644 Documentation/userspace-api/media/v4l/vidioc-enumstd.rst create mode 100644 Documentation/userspace-api/media/v4l/vidioc-expbuf.rst create mode 100644 Documentation/userspace-api/media/v4l/vidioc-g-audio.rst create mode 100644 Documentation/userspace-api/media/v4l/vidioc-g-audioout.rst create mode 100644 Documentation/userspace-api/media/v4l/vidioc-g-crop.rst create mode 100644 Documentation/userspace-api/media/v4l/vidioc-g-ctrl.rst create mode 100644 Documentation/userspace-api/media/v4l/vidioc-g-dv-timings.rst create mode 100644 Documentation/userspace-api/media/v4l/vidioc-g-edid.rst create mode 100644 Documentation/userspace-api/media/v4l/vidioc-g-enc-index.rst create mode 100644 Documentation/userspace-api/media/v4l/vidioc-g-ext-ctrls.rst create mode 100644 Documentation/userspace-api/media/v4l/vidioc-g-fbuf.rst create mode 100644 Documentation/userspace-api/media/v4l/vidioc-g-fmt.rst create mode 100644 Documentation/userspace-api/media/v4l/vidioc-g-frequency.rst create mode 100644 Documentation/userspace-api/media/v4l/vidioc-g-input.rst create mode 100644 Documentation/userspace-api/media/v4l/vidioc-g-jpegcomp.rst create mode 100644 Documentation/userspace-api/media/v4l/vidioc-g-modulator.rst create mode 100644 Documentation/userspace-api/media/v4l/vidioc-g-output.rst create mode 100644 Documentation/userspace-api/media/v4l/vidioc-g-parm.rst create mode 100644 Documentation/userspace-api/media/v4l/vidioc-g-priority.rst create mode 100644 Documentation/userspace-api/media/v4l/vidioc-g-selection.rst create mode 100644 Documentation/userspace-api/media/v4l/vidioc-g-sliced-vbi-cap.rst create mode 100644 Documentation/userspace-api/media/v4l/vidioc-g-std.rst create mode 100644 Documentation/userspace-api/media/v4l/vidioc-g-tuner.rst create mode 100644 Documentation/userspace-api/media/v4l/vidioc-log-status.rst create mode 100644 Documentation/userspace-api/media/v4l/vidioc-overlay.rst create mode 100644 Documentation/userspace-api/media/v4l/vidioc-prepare-buf.rst create mode 100644 Documentation/userspace-api/media/v4l/vidioc-qbuf.rst create mode 100644 Documentation/userspace-api/media/v4l/vidioc-query-dv-timings.rst create mode 100644 Documentation/userspace-api/media/v4l/vidioc-querybuf.rst create mode 100644 Documentation/userspace-api/media/v4l/vidioc-querycap.rst create mode 100644 Documentation/userspace-api/media/v4l/vidioc-queryctrl.rst create mode 100644 Documentation/userspace-api/media/v4l/vidioc-querystd.rst create mode 100644 Documentation/userspace-api/media/v4l/vidioc-reqbufs.rst create mode 100644 Documentation/userspace-api/media/v4l/vidioc-s-hw-freq-seek.rst create mode 100644 Documentation/userspace-api/media/v4l/vidioc-streamon.rst create mode 100644 Documentation/userspace-api/media/v4l/vidioc-subdev-enum-frame-interval.rst create mode 100644 Documentation/userspace-api/media/v4l/vidioc-subdev-enum-frame-size.rst create mode 100644 Documentation/userspace-api/media/v4l/vidioc-subdev-enum-mbus-code.rst create mode 100644 Documentation/userspace-api/media/v4l/vidioc-subdev-g-crop.rst create mode 100644 Documentation/userspace-api/media/v4l/vidioc-subdev-g-fmt.rst create mode 100644 Documentation/userspace-api/media/v4l/vidioc-subdev-g-frame-interval.rst create mode 100644 Documentation/userspace-api/media/v4l/vidioc-subdev-g-selection.rst create mode 100644 Documentation/userspace-api/media/v4l/vidioc-subscribe-event.rst create mode 100644 Documentation/userspace-api/media/v4l/yuv-formats.rst create mode 100644 Documentation/userspace-api/media/video.h.rst.exceptions create mode 100644 Documentation/userspace-api/media/videodev2.h.rst.exceptions (limited to 'drivers/media') diff --git a/Documentation/ABI/testing/debugfs-cec-error-inj b/Documentation/ABI/testing/debugfs-cec-error-inj index 4c3596c6d25b..5afcd78fbdb7 100644 --- a/Documentation/ABI/testing/debugfs-cec-error-inj +++ b/Documentation/ABI/testing/debugfs-cec-error-inj @@ -37,4 +37,4 @@ when changes are made. The following CEC error injection implementations exist: -- Documentation/media/uapi/cec/cec-pin-error-inj.rst +- Documentation/userspace-api/media/cec/cec-pin-error-inj.rst diff --git a/Documentation/Makefile b/Documentation/Makefile index cc786d11a028..7e12d10ca8e0 100644 --- a/Documentation/Makefile +++ b/Documentation/Makefile @@ -55,15 +55,15 @@ I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . loop_cmd = $(echo-cmd) $(cmd_$(1)) || exit; # $2 sphinx builder e.g. "html" -# $3 name of the build subfolder / e.g. "media", used as: +# $3 name of the build subfolder / e.g. "userspace-api/media", used as: # * dest folder relative to $(BUILDDIR) and # * cache folder relative to $(BUILDDIR)/.doctrees -# $4 dest subfolder e.g. "man" for man pages at media/man +# $4 dest subfolder e.g. "man" for man pages at userspace-api/media/man # $5 reST source folder relative to $(srctree)/$(src), -# e.g. "media" for the linux-tv book-set at ./Documentation/media +# e.g. "userspace-api/media" for the linux-tv book-set at ./Documentation/userspace-api/media quiet_cmd_sphinx = SPHINX $@ --> file://$(abspath $(BUILDDIR)/$3/$4) - cmd_sphinx = $(MAKE) BUILDDIR=$(abspath $(BUILDDIR)) $(build)=Documentation/media $2 && \ + cmd_sphinx = $(MAKE) BUILDDIR=$(abspath $(BUILDDIR)) $(build)=Documentation/userspace-api/media $2 && \ PYTHONDONTWRITEBYTECODE=1 \ BUILDDIR=$(abspath $(BUILDDIR)) SPHINX_CONF=$(abspath $(srctree)/$(src)/$5/$(SPHINX_CONF)) \ $(PYTHON) $(srctree)/scripts/jobserver-exec \ @@ -120,7 +120,7 @@ refcheckdocs: cleandocs: $(Q)rm -rf $(BUILDDIR) - $(Q)$(MAKE) BUILDDIR=$(abspath $(BUILDDIR)) $(build)=Documentation/media clean + $(Q)$(MAKE) BUILDDIR=$(abspath $(BUILDDIR)) $(build)=Documentation/userspace-api/media clean dochelp: @echo ' Linux kernel internal documentation in different formats from ReST:' diff --git a/Documentation/doc-guide/parse-headers.rst b/Documentation/doc-guide/parse-headers.rst index 24cfaa15dd81..f7135b058246 100644 --- a/Documentation/doc-guide/parse-headers.rst +++ b/Documentation/doc-guide/parse-headers.rst @@ -10,7 +10,7 @@ if a symbol is not found at the documentation. That helps to keep the uAPI documentation in sync with the Kernel changes. The :ref:`parse_headers.pl ` provide a way to generate such cross-references. It has to be called via Makefile, while building the -documentation. Please see ``Documentation/media/Makefile`` for an example +documentation. Please see ``Documentation/userspace-api/media/Makefile`` for an example about how to use it inside the Kernel tree. .. _parse_headers: diff --git a/Documentation/fb/api.rst b/Documentation/fb/api.rst index 79ec33dded74..4f00e7196fef 100644 --- a/Documentation/fb/api.rst +++ b/Documentation/fb/api.rst @@ -290,12 +290,12 @@ the FB_CAP_FOURCC bit in the fb_fix_screeninfo capabilities field. FOURCC definitions are located in the linux/videodev2.h header. However, and despite starting with the V4L2_PIX_FMT_prefix, they are not restricted to V4L2 and don't require usage of the V4L2 subsystem. FOURCC documentation is -available in Documentation/media/uapi/v4l/pixfmt.rst. +available in Documentation/userspace-api/media/v4l/pixfmt.rst. To select a format, applications set the grayscale field to the desired FOURCC. For YUV formats, they should also select the appropriate colorspace by setting the colorspace field to one of the colorspaces listed in linux/videodev2.h and -documented in Documentation/media/uapi/v4l/colorspaces.rst. +documented in Documentation/userspace-api/media/v4l/colorspaces.rst. The red, green, blue and transp fields are not used with the FOURCC-based API. For forward compatibility reasons applications must zero those fields, and diff --git a/Documentation/media/Makefile b/Documentation/media/Makefile deleted file mode 100644 index d75d70f191bc..000000000000 --- a/Documentation/media/Makefile +++ /dev/null @@ -1,69 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 - -# Rules to convert a .h file to inline RST documentation - -SRC_DIR=$(srctree)/Documentation/media -PARSER = $(srctree)/Documentation/sphinx/parse-headers.pl -UAPI = $(srctree)/include/uapi/linux -KAPI = $(srctree)/include/linux - -FILES = audio.h.rst ca.h.rst dmx.h.rst frontend.h.rst net.h.rst video.h.rst \ - videodev2.h.rst media.h.rst cec.h.rst lirc.h.rst - -TARGETS := $(addprefix $(BUILDDIR)/, $(FILES)) - -gen_rst = \ - echo ${PARSER} $< $@ $(SRC_DIR)/$(notdir $@).exceptions; \ - ${PARSER} $< $@ $(SRC_DIR)/$(notdir $@).exceptions - -quiet_gen_rst = echo ' PARSE $(patsubst $(srctree)/%,%,$<)'; \ - ${PARSER} $< $@ $(SRC_DIR)/$(notdir $@).exceptions - -silent_gen_rst = ${gen_rst} - -$(BUILDDIR)/audio.h.rst: ${UAPI}/dvb/audio.h ${PARSER} $(SRC_DIR)/audio.h.rst.exceptions - @$($(quiet)gen_rst) - -$(BUILDDIR)/ca.h.rst: ${UAPI}/dvb/ca.h ${PARSER} $(SRC_DIR)/ca.h.rst.exceptions - @$($(quiet)gen_rst) - -$(BUILDDIR)/dmx.h.rst: ${UAPI}/dvb/dmx.h ${PARSER} $(SRC_DIR)/dmx.h.rst.exceptions - @$($(quiet)gen_rst) - -$(BUILDDIR)/frontend.h.rst: ${UAPI}/dvb/frontend.h ${PARSER} $(SRC_DIR)/frontend.h.rst.exceptions - @$($(quiet)gen_rst) - -$(BUILDDIR)/net.h.rst: ${UAPI}/dvb/net.h ${PARSER} $(SRC_DIR)/net.h.rst.exceptions - @$($(quiet)gen_rst) - -$(BUILDDIR)/video.h.rst: ${UAPI}/dvb/video.h ${PARSER} $(SRC_DIR)/video.h.rst.exceptions - @$($(quiet)gen_rst) - -$(BUILDDIR)/videodev2.h.rst: ${UAPI}/videodev2.h ${PARSER} $(SRC_DIR)/videodev2.h.rst.exceptions - @$($(quiet)gen_rst) - -$(BUILDDIR)/media.h.rst: ${UAPI}/media.h ${PARSER} $(SRC_DIR)/media.h.rst.exceptions - @$($(quiet)gen_rst) - -$(BUILDDIR)/cec.h.rst: ${UAPI}/cec.h ${PARSER} $(SRC_DIR)/cec.h.rst.exceptions - @$($(quiet)gen_rst) - -$(BUILDDIR)/lirc.h.rst: ${UAPI}/lirc.h ${PARSER} $(SRC_DIR)/lirc.h.rst.exceptions - @$($(quiet)gen_rst) - -# Media build rules - -.PHONY: all html epub xml latex - -all: $(IMGDOT) $(BUILDDIR) ${TARGETS} -html: all -epub: all -xml: all -latex: $(IMGPDF) all -linkcheck: - -clean: - -rm -f $(DOTTGT) $(IMGTGT) ${TARGETS} 2>/dev/null - -$(BUILDDIR): - $(Q)mkdir -p $@ diff --git a/Documentation/media/audio.h.rst.exceptions b/Documentation/media/audio.h.rst.exceptions deleted file mode 100644 index cf6620477f73..000000000000 --- a/Documentation/media/audio.h.rst.exceptions +++ /dev/null @@ -1,19 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 - -# Ignore header name -ignore define _DVBAUDIO_H_ - -# Undocumented audio caps, as this is a deprecated API anyway -ignore define AUDIO_CAP_DTS -ignore define AUDIO_CAP_LPCM -ignore define AUDIO_CAP_MP1 -ignore define AUDIO_CAP_MP2 -ignore define AUDIO_CAP_MP3 -ignore define AUDIO_CAP_AAC -ignore define AUDIO_CAP_OGG -ignore define AUDIO_CAP_SDDS -ignore define AUDIO_CAP_AC3 - -# some typedefs should point to struct/enums -replace typedef audio_mixer_t :c:type:`audio_mixer` -replace typedef audio_status_t :c:type:`audio_status` diff --git a/Documentation/media/ca.h.rst.exceptions b/Documentation/media/ca.h.rst.exceptions deleted file mode 100644 index f6828238eb48..000000000000 --- a/Documentation/media/ca.h.rst.exceptions +++ /dev/null @@ -1,25 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 - -# Ignore header name -ignore define _DVBCA_H_ - -# struct ca_slot_info defines -replace define CA_CI :c:type:`ca_slot_info` -replace define CA_CI_LINK :c:type:`ca_slot_info` -replace define CA_CI_PHYS :c:type:`ca_slot_info` -replace define CA_DESCR :c:type:`ca_slot_info` -replace define CA_SC :c:type:`ca_slot_info` -replace define CA_CI_MODULE_PRESENT :c:type:`ca_slot_info` -replace define CA_CI_MODULE_READY :c:type:`ca_slot_info` - -# struct ca_descr_info defines -replace define CA_ECD :c:type:`ca_descr_info` -replace define CA_NDS :c:type:`ca_descr_info` -replace define CA_DSS :c:type:`ca_descr_info` - -# some typedefs should point to struct/enums -replace typedef ca_slot_info_t :c:type:`ca_slot_info` -replace typedef ca_descr_info_t :c:type:`ca_descr_info` -replace typedef ca_caps_t :c:type:`ca_caps` -replace typedef ca_msg_t :c:type:`ca_msg` -replace typedef ca_descr_t :c:type:`ca_descr` diff --git a/Documentation/media/cec.h.rst.exceptions b/Documentation/media/cec.h.rst.exceptions deleted file mode 100644 index d83790ccac8e..000000000000 --- a/Documentation/media/cec.h.rst.exceptions +++ /dev/null @@ -1,575 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 - -# Ignore header name -ignore define _CEC_UAPI_H - -# define macros to ignore - -ignore define CEC_MAX_MSG_SIZE -ignore define CEC_MAX_LOG_ADDRS - -ignore define CEC_LOG_ADDR_MASK_TV -ignore define CEC_LOG_ADDR_MASK_RECORD -ignore define CEC_LOG_ADDR_MASK_TUNER -ignore define CEC_LOG_ADDR_MASK_PLAYBACK -ignore define CEC_LOG_ADDR_MASK_AUDIOSYSTEM -ignore define CEC_LOG_ADDR_MASK_BACKUP -ignore define CEC_LOG_ADDR_MASK_SPECIFIC -ignore define CEC_LOG_ADDR_MASK_UNREGISTERED - -# Shouldn't them be documented? -ignore define CEC_LOG_ADDR_INVALID -ignore define CEC_PHYS_ADDR_INVALID - -ignore define CEC_VENDOR_ID_NONE - -ignore define CEC_MODE_INITIATOR_MSK -ignore define CEC_MODE_FOLLOWER_MSK - -# Part of CEC 2.0 spec - shouldn't be documented too? -ignore define CEC_LOG_ADDR_TV -ignore define CEC_LOG_ADDR_RECORD_1 -ignore define CEC_LOG_ADDR_RECORD_2 -ignore define CEC_LOG_ADDR_TUNER_1 -ignore define CEC_LOG_ADDR_PLAYBACK_1 -ignore define CEC_LOG_ADDR_AUDIOSYSTEM -ignore define CEC_LOG_ADDR_TUNER_2 -ignore define CEC_LOG_ADDR_TUNER_3 -ignore define CEC_LOG_ADDR_PLAYBACK_2 -ignore define CEC_LOG_ADDR_RECORD_3 -ignore define CEC_LOG_ADDR_TUNER_4 -ignore define CEC_LOG_ADDR_PLAYBACK_3 -ignore define CEC_LOG_ADDR_BACKUP_1 -ignore define CEC_LOG_ADDR_BACKUP_2 -ignore define CEC_LOG_ADDR_SPECIFIC -ignore define CEC_LOG_ADDR_UNREGISTERED -ignore define CEC_LOG_ADDR_BROADCAST - -# IMHO, those should also be documented - -ignore define CEC_MSG_ACTIVE_SOURCE -ignore define CEC_MSG_IMAGE_VIEW_ON -ignore define CEC_MSG_TEXT_VIEW_ON - -ignore define CEC_MSG_INACTIVE_SOURCE -ignore define CEC_MSG_REQUEST_ACTIVE_SOURCE -ignore define CEC_MSG_ROUTING_CHANGE -ignore define CEC_MSG_ROUTING_INFORMATION -ignore define CEC_MSG_SET_STREAM_PATH - -ignore define CEC_MSG_STANDBY - -ignore define CEC_MSG_RECORD_OFF -ignore define CEC_MSG_RECORD_ON - -ignore define CEC_OP_RECORD_SRC_OWN -ignore define CEC_OP_RECORD_SRC_DIGITAL -ignore define CEC_OP_RECORD_SRC_ANALOG -ignore define CEC_OP_RECORD_SRC_EXT_PLUG -ignore define CEC_OP_RECORD_SRC_EXT_PHYS_ADDR - -ignore define CEC_OP_SERVICE_ID_METHOD_BY_DIG_ID -ignore define CEC_OP_SERVICE_ID_METHOD_BY_CHANNEL - -ignore define CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ARIB_GEN -ignore define CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_GEN -ignore define CEC_OP_DIG_SERVICE_BCAST_SYSTEM_DVB_GEN -ignore define CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ARIB_BS -ignore define CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ARIB_CS -ignore define CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ARIB_T -ignore define CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_CABLE -ignore define CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_SAT -ignore define CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_T -ignore define CEC_OP_DIG_SERVICE_BCAST_SYSTEM_DVB_C -ignore define CEC_OP_DIG_SERVICE_BCAST_SYSTEM_DVB_S -ignore define CEC_OP_DIG_SERVICE_BCAST_SYSTEM_DVB_S2 -ignore define CEC_OP_DIG_SERVICE_BCAST_SYSTEM_DVB_T - -ignore define CEC_OP_ANA_BCAST_TYPE_CABLE -ignore define CEC_OP_ANA_BCAST_TYPE_SATELLITE -ignore define CEC_OP_ANA_BCAST_TYPE_TERRESTRIAL - -ignore define CEC_OP_BCAST_SYSTEM_PAL_BG -ignore define CEC_OP_BCAST_SYSTEM_SECAM_LQ -ignore define CEC_OP_BCAST_SYSTEM_PAL_M -ignore define CEC_OP_BCAST_SYSTEM_NTSC_M -ignore define CEC_OP_BCAST_SYSTEM_PAL_I -ignore define CEC_OP_BCAST_SYSTEM_SECAM_DK -ignore define CEC_OP_BCAST_SYSTEM_SECAM_BG -ignore define CEC_OP_BCAST_SYSTEM_SECAM_L -ignore define CEC_OP_BCAST_SYSTEM_PAL_DK -ignore define CEC_OP_BCAST_SYSTEM_OTHER - -ignore define CEC_OP_CHANNEL_NUMBER_FMT_1_PART -ignore define CEC_OP_CHANNEL_NUMBER_FMT_2_PART - -ignore define CEC_MSG_RECORD_STATUS - -ignore define CEC_OP_RECORD_STATUS_CUR_SRC -ignore define CEC_OP_RECORD_STATUS_DIG_SERVICE -ignore define CEC_OP_RECORD_STATUS_ANA_SERVICE -ignore define CEC_OP_RECORD_STATUS_EXT_INPUT -ignore define CEC_OP_RECORD_STATUS_NO_DIG_SERVICE -ignore define CEC_OP_RECORD_STATUS_NO_ANA_SERVICE -ignore define CEC_OP_RECORD_STATUS_NO_SERVICE -ignore define CEC_OP_RECORD_STATUS_INVALID_EXT_PLUG -ignore define CEC_OP_RECORD_STATUS_INVALID_EXT_PHYS_ADDR -ignore define CEC_OP_RECORD_STATUS_UNSUP_CA -ignore define CEC_OP_RECORD_STATUS_NO_CA_ENTITLEMENTS -ignore define CEC_OP_RECORD_STATUS_CANT_COPY_SRC -ignore define CEC_OP_RECORD_STATUS_NO_MORE_COPIES -ignore define CEC_OP_RECORD_STATUS_NO_MEDIA -ignore define CEC_OP_RECORD_STATUS_PLAYING -ignore define CEC_OP_RECORD_STATUS_ALREADY_RECORDING -ignore define CEC_OP_RECORD_STATUS_MEDIA_PROT -ignore define CEC_OP_RECORD_STATUS_NO_SIGNAL -ignore define CEC_OP_RECORD_STATUS_MEDIA_PROBLEM -ignore define CEC_OP_RECORD_STATUS_NO_SPACE -ignore define CEC_OP_RECORD_STATUS_PARENTAL_LOCK -ignore define CEC_OP_RECORD_STATUS_TERMINATED_OK -ignore define CEC_OP_RECORD_STATUS_ALREADY_TERM -ignore define CEC_OP_RECORD_STATUS_OTHER - -ignore define CEC_MSG_RECORD_TV_SCREEN - -ignore define CEC_MSG_CLEAR_ANALOGUE_TIMER - -ignore define CEC_OP_REC_SEQ_SUNDAY -ignore define CEC_OP_REC_SEQ_MONDAY -ignore define CEC_OP_REC_SEQ_TUESDAY -ignore define CEC_OP_REC_SEQ_WEDNESDAY -ignore define CEC_OP_REC_SEQ_THURSDAY -ignore define CEC_OP_REC_SEQ_FRIDAY -ignore define CEC_OP_REC_SEQ_SATERDAY -ignore define CEC_OP_REC_SEQ_ONCE_ONLY - -ignore define CEC_MSG_CLEAR_DIGITAL_TIMER - -ignore define CEC_MSG_CLEAR_EXT_TIMER - -ignore define CEC_OP_EXT_SRC_PLUG -ignore define CEC_OP_EXT_SRC_PHYS_ADDR - -ignore define CEC_MSG_SET_ANALOGUE_TIMER -ignore define CEC_MSG_SET_DIGITAL_TIMER -ignore define CEC_MSG_SET_EXT_TIMER - -ignore define CEC_MSG_SET_TIMER_PROGRAM_TITLE -ignore define CEC_MSG_TIMER_CLEARED_STATUS - -ignore define CEC_OP_TIMER_CLR_STAT_RECORDING -ignore define CEC_OP_TIMER_CLR_STAT_NO_MATCHING -ignore define CEC_OP_TIMER_CLR_STAT_NO_INFO -ignore define CEC_OP_TIMER_CLR_STAT_CLEARED - -ignore define CEC_MSG_TIMER_STATUS - -ignore define CEC_OP_TIMER_OVERLAP_WARNING_NO_OVERLAP -ignore define CEC_OP_TIMER_OVERLAP_WARNING_OVERLAP - -ignore define CEC_OP_MEDIA_INFO_UNPROT_MEDIA -ignore define CEC_OP_MEDIA_INFO_PROT_MEDIA -ignore define CEC_OP_MEDIA_INFO_NO_MEDIA - -ignore define CEC_OP_PROG_IND_NOT_PROGRAMMED -ignore define CEC_OP_PROG_IND_PROGRAMMED - -ignore define CEC_OP_PROG_INFO_ENOUGH_SPACE -ignore define CEC_OP_PROG_INFO_NOT_ENOUGH_SPACE -ignore define CEC_OP_PROG_INFO_MIGHT_NOT_BE_ENOUGH_SPACE -ignore define CEC_OP_PROG_INFO_NONE_AVAILABLE - -ignore define CEC_OP_PROG_ERROR_NO_FREE_TIMER -ignore define CEC_OP_PROG_ERROR_DATE_OUT_OF_RANGE -ignore define CEC_OP_PROG_ERROR_REC_SEQ_ERROR -ignore define CEC_OP_PROG_ERROR_INV_EXT_PLUG -ignore define CEC_OP_PROG_ERROR_INV_EXT_PHYS_ADDR -ignore define CEC_OP_PROG_ERROR_CA_UNSUPP -ignore define CEC_OP_PROG_ERROR_INSUF_CA_ENTITLEMENTS -ignore define CEC_OP_PROG_ERROR_RESOLUTION_UNSUPP -ignore define CEC_OP_PROG_ERROR_PARENTAL_LOCK -ignore define CEC_OP_PROG_ERROR_CLOCK_FAILURE -ignore define CEC_OP_PROG_ERROR_DUPLICATE - -ignore define CEC_MSG_CEC_VERSION - -ignore define CEC_OP_CEC_VERSION_1_3A -ignore define CEC_OP_CEC_VERSION_1_4 -ignore define CEC_OP_CEC_VERSION_2_0 - -ignore define CEC_MSG_GET_CEC_VERSION -ignore define CEC_MSG_GIVE_PHYSICAL_ADDR -ignore define CEC_MSG_GET_MENU_LANGUAGE -ignore define CEC_MSG_REPORT_PHYSICAL_ADDR - -ignore define CEC_OP_PRIM_DEVTYPE_TV -ignore define CEC_OP_PRIM_DEVTYPE_RECORD -ignore define CEC_OP_PRIM_DEVTYPE_TUNER -ignore define CEC_OP_PRIM_DEVTYPE_PLAYBACK -ignore define CEC_OP_PRIM_DEVTYPE_AUDIOSYSTEM -ignore define CEC_OP_PRIM_DEVTYPE_SWITCH -ignore define CEC_OP_PRIM_DEVTYPE_PROCESSOR - -ignore define CEC_MSG_SET_MENU_LANGUAGE -ignore define CEC_MSG_REPORT_FEATURES - -ignore define CEC_OP_ALL_DEVTYPE_TV -ignore define CEC_OP_ALL_DEVTYPE_RECORD -ignore define CEC_OP_ALL_DEVTYPE_TUNER -ignore define CEC_OP_ALL_DEVTYPE_PLAYBACK -ignore define CEC_OP_ALL_DEVTYPE_AUDIOSYSTEM -ignore define CEC_OP_ALL_DEVTYPE_SWITCH - -ignore define CEC_OP_FEAT_EXT - -ignore define CEC_OP_FEAT_RC_TV_PROFILE_NONE -ignore define CEC_OP_FEAT_RC_TV_PROFILE_1 -ignore define CEC_OP_FEAT_RC_TV_PROFILE_2 -ignore define CEC_OP_FEAT_RC_TV_PROFILE_3 -ignore define CEC_OP_FEAT_RC_TV_PROFILE_4 -ignore define CEC_OP_FEAT_RC_SRC_HAS_DEV_ROOT_MENU -ignore define CEC_OP_FEAT_RC_SRC_HAS_DEV_SETUP_MENU -ignore define CEC_OP_FEAT_RC_SRC_HAS_CONTENTS_MENU -ignore define CEC_OP_FEAT_RC_SRC_HAS_MEDIA_TOP_MENU -ignore define CEC_OP_FEAT_RC_SRC_HAS_MEDIA_CONTEXT_MENU - -ignore define CEC_OP_FEAT_DEV_HAS_RECORD_TV_SCREEN -ignore define CEC_OP_FEAT_DEV_HAS_SET_OSD_STRING -ignore define CEC_OP_FEAT_DEV_HAS_DECK_CONTROL -ignore define CEC_OP_FEAT_DEV_HAS_SET_AUDIO_RATE -ignore define CEC_OP_FEAT_DEV_SINK_HAS_ARC_TX -ignore define CEC_OP_FEAT_DEV_SOURCE_HAS_ARC_RX - -ignore define CEC_MSG_GIVE_FEATURES - -ignore define CEC_MSG_DECK_CONTROL - -ignore define CEC_OP_DECK_CTL_MODE_SKIP_FWD -ignore define CEC_OP_DECK_CTL_MODE_SKIP_REV -ignore define CEC_OP_DECK_CTL_MODE_STOP -ignore define CEC_OP_DECK_CTL_MODE_EJECT - -ignore define CEC_MSG_DECK_STATUS - -ignore define CEC_OP_DECK_INFO_PLAY -ignore define CEC_OP_DECK_INFO_RECORD -ignore define CEC_OP_DECK_INFO_PLAY_REV -ignore define CEC_OP_DECK_INFO_STILL -ignore define CEC_OP_DECK_INFO_SLOW -ignore define CEC_OP_DECK_INFO_SLOW_REV -ignore define CEC_OP_DECK_INFO_FAST_FWD -ignore define CEC_OP_DECK_INFO_FAST_REV -ignore define CEC_OP_DECK_INFO_NO_MEDIA -ignore define CEC_OP_DECK_INFO_STOP -ignore define CEC_OP_DECK_INFO_SKIP_FWD -ignore define CEC_OP_DECK_INFO_SKIP_REV -ignore define CEC_OP_DECK_INFO_INDEX_SEARCH_FWD -ignore define CEC_OP_DECK_INFO_INDEX_SEARCH_REV -ignore define CEC_OP_DECK_INFO_OTHER - -ignore define CEC_MSG_GIVE_DECK_STATUS - -ignore define CEC_OP_STATUS_REQ_ON -ignore define CEC_OP_STATUS_REQ_OFF -ignore define CEC_OP_STATUS_REQ_ONCE - -ignore define CEC_MSG_PLAY - -ignore define CEC_OP_PLAY_MODE_PLAY_FWD -ignore define CEC_OP_PLAY_MODE_PLAY_REV -ignore define CEC_OP_PLAY_MODE_PLAY_STILL -ignore define CEC_OP_PLAY_MODE_PLAY_FAST_FWD_MIN -ignore define CEC_OP_PLAY_MODE_PLAY_FAST_FWD_MED -ignore define CEC_OP_PLAY_MODE_PLAY_FAST_FWD_MAX -ignore define CEC_OP_PLAY_MODE_PLAY_FAST_REV_MIN -ignore define CEC_OP_PLAY_MODE_PLAY_FAST_REV_MED -ignore define CEC_OP_PLAY_MODE_PLAY_FAST_REV_MAX -ignore define CEC_OP_PLAY_MODE_PLAY_SLOW_FWD_MIN -ignore define CEC_OP_PLAY_MODE_PLAY_SLOW_FWD_MED -ignore define CEC_OP_PLAY_MODE_PLAY_SLOW_FWD_MAX -ignore define CEC_OP_PLAY_MODE_PLAY_SLOW_REV_MIN -ignore define CEC_OP_PLAY_MODE_PLAY_SLOW_REV_MED -ignore define CEC_OP_PLAY_MODE_PLAY_SLOW_REV_MAX - -ignore define CEC_MSG_GIVE_TUNER_DEVICE_STATUS -ignore define CEC_MSG_SELECT_ANALOGUE_SERVICE -ignore define CEC_MSG_SELECT_DIGITAL_SERVICE -ignore define CEC_MSG_TUNER_DEVICE_STATUS - -ignore define CEC_OP_REC_FLAG_USED -ignore define CEC_OP_REC_FLAG_NOT_USED - -ignore define CEC_OP_TUNER_DISPLAY_INFO_DIGITAL -ignore define CEC_OP_TUNER_DISPLAY_INFO_NONE -ignore define CEC_OP_TUNER_DISPLAY_INFO_ANALOGUE - -ignore define CEC_MSG_TUNER_STEP_DECREMENT -ignore define CEC_MSG_TUNER_STEP_INCREMENT - -ignore define CEC_MSG_DEVICE_VENDOR_ID -ignore define CEC_MSG_GIVE_DEVICE_VENDOR_ID -ignore define CEC_MSG_VENDOR_COMMAND -ignore define CEC_MSG_VENDOR_COMMAND_WITH_ID -ignore define CEC_MSG_VENDOR_REMOTE_BUTTON_DOWN -ignore define CEC_MSG_VENDOR_REMOTE_BUTTON_UP - -ignore define CEC_MSG_SET_OSD_STRING - -ignore define CEC_OP_DISP_CTL_DEFAULT -ignore define CEC_OP_DISP_CTL_UNTIL_CLEARED -ignore define CEC_OP_DISP_CTL_CLEAR - -ignore define CEC_MSG_GIVE_OSD_NAME -ignore define CEC_MSG_SET_OSD_NAME - -ignore define CEC_MSG_MENU_REQUEST - -ignore define CEC_OP_MENU_REQUEST_ACTIVATE -ignore define CEC_OP_MENU_REQUEST_DEACTIVATE -ignore define CEC_OP_MENU_REQUEST_QUERY - -ignore define CEC_MSG_MENU_STATUS - -ignore define CEC_OP_MENU_STATE_ACTIVATED -ignore define CEC_OP_MENU_STATE_DEACTIVATED - -ignore define CEC_MSG_USER_CONTROL_PRESSED - -ignore define CEC_OP_UI_CMD_SELECT -ignore define CEC_OP_UI_CMD_UP -ignore define CEC_OP_UI_CMD_DOWN -ignore define CEC_OP_UI_CMD_LEFT -ignore define CEC_OP_UI_CMD_RIGHT -ignore define CEC_OP_UI_CMD_RIGHT_UP -ignore define CEC_OP_UI_CMD_RIGHT_DOWN -ignore define CEC_OP_UI_CMD_LEFT_UP -ignore define CEC_OP_UI_CMD_LEFT_DOWN -ignore define CEC_OP_UI_CMD_DEVICE_ROOT_MENU -ignore define CEC_OP_UI_CMD_DEVICE_SETUP_MENU -ignore define CEC_OP_UI_CMD_CONTENTS_MENU -ignore define CEC_OP_UI_CMD_FAVORITE_MENU -ignore define CEC_OP_UI_CMD_BACK -ignore define CEC_OP_UI_CMD_MEDIA_TOP_MENU -ignore define CEC_OP_UI_CMD_MEDIA_CONTEXT_SENSITIVE_MENU -ignore define CEC_OP_UI_CMD_NUMBER_ENTRY_MODE -ignore define CEC_OP_UI_CMD_NUMBER_11 -ignore define CEC_OP_UI_CMD_NUMBER_12 -ignore define CEC_OP_UI_CMD_NUMBER_0_OR_NUMBER_10 -ignore define CEC_OP_UI_CMD_NUMBER_1 -ignore define CEC_OP_UI_CMD_NUMBER_2 -ignore define CEC_OP_UI_CMD_NUMBER_3 -ignore define CEC_OP_UI_CMD_NUMBER_4 -ignore define CEC_OP_UI_CMD_NUMBER_5 -ignore define CEC_OP_UI_CMD_NUMBER_6 -ignore define CEC_OP_UI_CMD_NUMBER_7 -ignore define CEC_OP_UI_CMD_NUMBER_8 -ignore define CEC_OP_UI_CMD_NUMBER_9 -ignore define CEC_OP_UI_CMD_DOT -ignore define CEC_OP_UI_CMD_ENTER -ignore define CEC_OP_UI_CMD_CLEAR -ignore define CEC_OP_UI_CMD_NEXT_FAVORITE -ignore define CEC_OP_UI_CMD_CHANNEL_UP -ignore define CEC_OP_UI_CMD_CHANNEL_DOWN -ignore define CEC_OP_UI_CMD_PREVIOUS_CHANNEL -ignore define CEC_OP_UI_CMD_SOUND_SELECT -ignore define CEC_OP_UI_CMD_INPUT_SELECT -ignore define CEC_OP_UI_CMD_DISPLAY_INFORMATION -ignore define CEC_OP_UI_CMD_HELP -ignore define CEC_OP_UI_CMD_PAGE_UP -ignore define CEC_OP_UI_CMD_PAGE_DOWN -ignore define CEC_OP_UI_CMD_POWER -ignore define CEC_OP_UI_CMD_VOLUME_UP -ignore define CEC_OP_UI_CMD_VOLUME_DOWN -ignore define CEC_OP_UI_CMD_MUTE -ignore define CEC_OP_UI_CMD_PLAY -ignore define CEC_OP_UI_CMD_STOP -ignore define CEC_OP_UI_CMD_PAUSE -ignore define CEC_OP_UI_CMD_RECORD -ignore define CEC_OP_UI_CMD_REWIND -ignore define CEC_OP_UI_CMD_FAST_FORWARD -ignore define CEC_OP_UI_CMD_EJECT -ignore define CEC_OP_UI_CMD_SKIP_FORWARD -ignore define CEC_OP_UI_CMD_SKIP_BACKWARD -ignore define CEC_OP_UI_CMD_STOP_RECORD -ignore define CEC_OP_UI_CMD_PAUSE_RECORD -ignore define CEC_OP_UI_CMD_ANGLE -ignore define CEC_OP_UI_CMD_SUB_PICTURE -ignore define CEC_OP_UI_CMD_VIDEO_ON_DEMAND -ignore define CEC_OP_UI_CMD_ELECTRONIC_PROGRAM_GUIDE -ignore define CEC_OP_UI_CMD_TIMER_PROGRAMMING -ignore define CEC_OP_UI_CMD_INITIAL_CONFIGURATION -ignore define CEC_OP_UI_CMD_SELECT_BROADCAST_TYPE -ignore define CEC_OP_UI_CMD_SELECT_SOUND_PRESENTATION -ignore define CEC_OP_UI_CMD_AUDIO_DESCRIPTION -ignore define CEC_OP_UI_CMD_INTERNET -ignore define CEC_OP_UI_CMD_3D_MODE -ignore define CEC_OP_UI_CMD_PLAY_FUNCTION -ignore define CEC_OP_UI_CMD_PAUSE_PLAY_FUNCTION -ignore define CEC_OP_UI_CMD_RECORD_FUNCTION -ignore define CEC_OP_UI_CMD_PAUSE_RECORD_FUNCTION -ignore define CEC_OP_UI_CMD_STOP_FUNCTION -ignore define CEC_OP_UI_CMD_MUTE_FUNCTION -ignore define CEC_OP_UI_CMD_RESTORE_VOLUME_FUNCTION -ignore define CEC_OP_UI_CMD_TUNE_FUNCTION -ignore define CEC_OP_UI_CMD_SELECT_MEDIA_FUNCTION -ignore define CEC_OP_UI_CMD_SELECT_AV_INPUT_FUNCTION -ignore define CEC_OP_UI_CMD_SELECT_AUDIO_INPUT_FUNCTION -ignore define CEC_OP_UI_CMD_POWER_TOGGLE_FUNCTION -ignore define CEC_OP_UI_CMD_POWER_OFF_FUNCTION -ignore define CEC_OP_UI_CMD_POWER_ON_FUNCTION -ignore define CEC_OP_UI_CMD_F1_BLUE -ignore define CEC_OP_UI_CMD_F2_RED -ignore define CEC_OP_UI_CMD_F3_GREEN -ignore define CEC_OP_UI_CMD_F4_YELLOW -ignore define CEC_OP_UI_CMD_F5 -ignore define CEC_OP_UI_CMD_DATA - -ignore define CEC_OP_UI_BCAST_TYPE_TOGGLE_ALL -ignore define CEC_OP_UI_BCAST_TYPE_TOGGLE_DIG_ANA -ignore define CEC_OP_UI_BCAST_TYPE_ANALOGUE -ignore define CEC_OP_UI_BCAST_TYPE_ANALOGUE_T -ignore define CEC_OP_UI_BCAST_TYPE_ANALOGUE_CABLE -ignore define CEC_OP_UI_BCAST_TYPE_ANALOGUE_SAT -ignore define CEC_OP_UI_BCAST_TYPE_DIGITAL -ignore define CEC_OP_UI_BCAST_TYPE_DIGITAL_T -ignore define CEC_OP_UI_BCAST_TYPE_DIGITAL_CABLE -ignore define CEC_OP_UI_BCAST_TYPE_DIGITAL_SAT -ignore define CEC_OP_UI_BCAST_TYPE_DIGITAL_COM_SAT -ignore define CEC_OP_UI_BCAST_TYPE_DIGITAL_COM_SAT2 -ignore define CEC_OP_UI_BCAST_TYPE_IP - -ignore define CEC_OP_UI_SND_PRES_CTL_DUAL_MONO -ignore define CEC_OP_UI_SND_PRES_CTL_KARAOKE -ignore define CEC_OP_UI_SND_PRES_CTL_DOWNMIX -ignore define CEC_OP_UI_SND_PRES_CTL_REVERB -ignore define CEC_OP_UI_SND_PRES_CTL_EQUALIZER -ignore define CEC_OP_UI_SND_PRES_CTL_BASS_UP -ignore define CEC_OP_UI_SND_PRES_CTL_BASS_NEUTRAL -ignore define CEC_OP_UI_SND_PRES_CTL_BASS_DOWN -ignore define CEC_OP_UI_SND_PRES_CTL_TREBLE_UP -ignore define CEC_OP_UI_SND_PRES_CTL_TREBLE_NEUTRAL -ignore define CEC_OP_UI_SND_PRES_CTL_TREBLE_DOWN - -ignore define CEC_MSG_USER_CONTROL_RELEASED - -ignore define CEC_MSG_GIVE_DEVICE_POWER_STATUS -ignore define CEC_MSG_REPORT_POWER_STATUS - -ignore define CEC_OP_POWER_STATUS_ON -ignore define CEC_OP_POWER_STATUS_STANDBY -ignore define CEC_OP_POWER_STATUS_TO_ON -ignore define CEC_OP_POWER_STATUS_TO_STANDBY - -ignore define CEC_MSG_FEATURE_ABORT - -ignore define CEC_OP_ABORT_UNRECOGNIZED_OP -ignore define CEC_OP_ABORT_INCORRECT_MODE -ignore define CEC_OP_ABORT_NO_SOURCE -ignore define CEC_OP_ABORT_INVALID_OP -ignore define CEC_OP_ABORT_REFUSED -ignore define CEC_OP_ABORT_UNDETERMINED - -ignore define CEC_MSG_ABORT - -ignore define CEC_MSG_GIVE_AUDIO_STATUS -ignore define CEC_MSG_GIVE_SYSTEM_AUDIO_MODE_STATUS -ignore define CEC_MSG_REPORT_AUDIO_STATUS - -ignore define CEC_OP_AUD_MUTE_STATUS_OFF -ignore define CEC_OP_AUD_MUTE_STATUS_ON - -ignore define CEC_MSG_REPORT_SHORT_AUDIO_DESCRIPTOR -ignore define CEC_MSG_REQUEST_SHORT_AUDIO_DESCRIPTOR -ignore define CEC_MSG_SET_SYSTEM_AUDIO_MODE - -ignore define CEC_OP_SYS_AUD_STATUS_OFF -ignore define CEC_OP_SYS_AUD_STATUS_ON - -ignore define CEC_MSG_SYSTEM_AUDIO_MODE_REQUEST -ignore define CEC_MSG_SYSTEM_AUDIO_MODE_STATUS - -ignore define CEC_OP_AUD_FMT_ID_CEA861 -ignore define CEC_OP_AUD_FMT_ID_CEA861_CXT - -ignore define CEC_MSG_SET_AUDIO_RATE - -ignore define CEC_OP_AUD_RATE_OFF -ignore define CEC_OP_AUD_RATE_WIDE_STD -ignore define CEC_OP_AUD_RATE_WIDE_FAST -ignore define CEC_OP_AUD_RATE_WIDE_SLOW -ignore define CEC_OP_AUD_RATE_NARROW_STD -ignore define CEC_OP_AUD_RATE_NARROW_FAST -ignore define CEC_OP_AUD_RATE_NARROW_SLOW - -ignore define CEC_MSG_INITIATE_ARC -ignore define CEC_MSG_REPORT_ARC_INITIATED -ignore define CEC_MSG_REPORT_ARC_TERMINATED -ignore define CEC_MSG_REQUEST_ARC_INITIATION -ignore define CEC_MSG_REQUEST_ARC_TERMINATION -ignore define CEC_MSG_TERMINATE_ARC - -ignore define CEC_MSG_REQUEST_CURRENT_LATENCY -ignore define CEC_MSG_REPORT_CURRENT_LATENCY - -ignore define CEC_OP_LOW_LATENCY_MODE_OFF -ignore define CEC_OP_LOW_LATENCY_MODE_ON - -ignore define CEC_OP_AUD_OUT_COMPENSATED_NA -ignore define CEC_OP_AUD_OUT_COMPENSATED_DELAY -ignore define CEC_OP_AUD_OUT_COMPENSATED_NO_DELAY -ignore define CEC_OP_AUD_OUT_COMPENSATED_PARTIAL_DELAY - -ignore define CEC_MSG_CDC_MESSAGE - -ignore define CEC_MSG_CDC_HEC_INQUIRE_STATE -ignore define CEC_MSG_CDC_HEC_REPORT_STATE - -ignore define CEC_OP_HEC_FUNC_STATE_NOT_SUPPORTED -ignore define CEC_OP_HEC_FUNC_STATE_INACTIVE -ignore define CEC_OP_HEC_FUNC_STATE_ACTIVE -ignore define CEC_OP_HEC_FUNC_STATE_ACTIVATION_FIELD - -ignore define CEC_OP_HOST_FUNC_STATE_NOT_SUPPORTED -ignore define CEC_OP_HOST_FUNC_STATE_INACTIVE -ignore define CEC_OP_HOST_FUNC_STATE_ACTIVE - -ignore define CEC_OP_ENC_FUNC_STATE_EXT_CON_NOT_SUPPORTED -ignore define CEC_OP_ENC_FUNC_STATE_EXT_CON_INACTIVE -ignore define CEC_OP_ENC_FUNC_STATE_EXT_CON_ACTIVE - -ignore define CEC_OP_CDC_ERROR_CODE_NONE -ignore define CEC_OP_CDC_ERROR_CODE_CAP_UNSUPPORTED -ignore define CEC_OP_CDC_ERROR_CODE_WRONG_STATE -ignore define CEC_OP_CDC_ERROR_CODE_OTHER - -ignore define CEC_OP_HEC_SUPPORT_NO -ignore define CEC_OP_HEC_SUPPORT_YES - -ignore define CEC_OP_HEC_ACTIVATION_ON -ignore define CEC_OP_HEC_ACTIVATION_OFF - -ignore define CEC_MSG_CDC_HEC_SET_STATE_ADJACENT -ignore define CEC_MSG_CDC_HEC_SET_STATE - -ignore define CEC_OP_HEC_SET_STATE_DEACTIVATE -ignore define CEC_OP_HEC_SET_STATE_ACTIVATE - -ignore define CEC_MSG_CDC_HEC_REQUEST_DEACTIVATION -ignore define CEC_MSG_CDC_HEC_NOTIFY_ALIVE -ignore define CEC_MSG_CDC_HEC_DISCOVER - -ignore define CEC_MSG_CDC_HPD_SET_STATE - -ignore define CEC_OP_HPD_STATE_CP_EDID_DISABLE -ignore define CEC_OP_HPD_STATE_CP_EDID_ENABLE -ignore define CEC_OP_HPD_STATE_CP_EDID_DISABLE_ENABLE -ignore define CEC_OP_HPD_STATE_EDID_DISABLE -ignore define CEC_OP_HPD_STATE_EDID_ENABLE -ignore define CEC_OP_HPD_STATE_EDID_DISABLE_ENABLE -ignore define CEC_MSG_CDC_HPD_REPORT_STATE - -ignore define CEC_OP_HPD_ERROR_NONE -ignore define CEC_OP_HPD_ERROR_INITIATOR_NOT_CAPABLE -ignore define CEC_OP_HPD_ERROR_INITIATOR_WRONG_STATE -ignore define CEC_OP_HPD_ERROR_OTHER -ignore define CEC_OP_HPD_ERROR_NONE_NO_VIDEO diff --git a/Documentation/media/conf_nitpick.py b/Documentation/media/conf_nitpick.py deleted file mode 100644 index d0c50d75f518..000000000000 --- a/Documentation/media/conf_nitpick.py +++ /dev/null @@ -1,111 +0,0 @@ -# -*- coding: utf-8; mode: python -*- - -# SPDX-License-Identifier: GPL-2.0 - -project = 'Linux Media Subsystem Documentation' - -# It is possible to run Sphinx in nickpick mode with: -nitpicky = True - -# within nit-picking build, do not refer to any intersphinx object -intersphinx_mapping = {} - -# In nickpick mode, it will complain about lots of missing references that -# -# 1) are just typedefs like: bool, __u32, etc; -# 2) It will complain for things like: enum, NULL; -# 3) It will complain for symbols that should be on different -# books (but currently aren't ported to ReST) -# -# The list below has a list of such symbols to be ignored in nitpick mode -# -nitpick_ignore = [ - ("c:func", "clock_gettime"), - ("c:func", "close"), - ("c:func", "container_of"), - ("c:func", "copy_from_user"), - ("c:func", "copy_to_user"), - ("c:func", "determine_valid_ioctls"), - ("c:func", "ERR_PTR"), - ("c:func", "i2c_new_device"), - ("c:func", "ioctl"), - ("c:func", "IS_ERR"), - ("c:func", "KERNEL_VERSION"), - ("c:func", "mmap"), - ("c:func", "open"), - ("c:func", "pci_name"), - ("c:func", "poll"), - ("c:func", "PTR_ERR"), - ("c:func", "read"), - ("c:func", "release"), - ("c:func", "set"), - ("c:func", "struct fd_set"), - ("c:func", "struct pollfd"), - ("c:func", "usb_make_path"), - ("c:func", "wait_finish"), - ("c:func", "wait_prepare"), - ("c:func", "write"), - - ("c:type", "atomic_t"), - ("c:type", "bool"), - ("c:type", "boolean"), - ("c:type", "buf_queue"), - ("c:type", "device"), - ("c:type", "device_driver"), - ("c:type", "device_node"), - ("c:type", "enum"), - ("c:type", "fd"), - ("c:type", "fd_set"), - ("c:type", "file"), - ("c:type", "i2c_adapter"), - ("c:type", "i2c_board_info"), - ("c:type", "i2c_client"), - ("c:type", "int16_t"), - ("c:type", "ktime_t"), - ("c:type", "led_classdev_flash"), - ("c:type", "list_head"), - ("c:type", "lock_class_key"), - ("c:type", "module"), - ("c:type", "mutex"), - ("c:type", "NULL"), - ("c:type", "off_t"), - ("c:type", "pci_dev"), - ("c:type", "pdvbdev"), - ("c:type", "poll_table"), - ("c:type", "platform_device"), - ("c:type", "pollfd"), - ("c:type", "poll_table_struct"), - ("c:type", "s32"), - ("c:type", "s64"), - ("c:type", "sd"), - ("c:type", "size_t"), - ("c:type", "spi_board_info"), - ("c:type", "spi_device"), - ("c:type", "spi_master"), - ("c:type", "ssize_t"), - ("c:type", "fb_fix_screeninfo"), - ("c:type", "pollfd"), - ("c:type", "timeval"), - ("c:type", "video_capability"), - ("c:type", "timeval"), - ("c:type", "__u16"), - ("c:type", "u16"), - ("c:type", "__u32"), - ("c:type", "u32"), - ("c:type", "__u64"), - ("c:type", "u64"), - ("c:type", "u8"), - ("c:type", "uint16_t"), - ("c:type", "uint32_t"), - ("c:type", "union"), - ("c:type", "__user"), - ("c:type", "usb_device"), - ("c:type", "usb_interface"), - ("c:type", "v4l2_std_id"), - ("c:type", "video_system_t"), - ("c:type", "vm_area_struct"), - - # Opaque structures - - ("c:type", "v4l2_m2m_dev"), -] diff --git a/Documentation/media/dmx.h.rst.exceptions b/Documentation/media/dmx.h.rst.exceptions deleted file mode 100644 index afc14d384b83..000000000000 --- a/Documentation/media/dmx.h.rst.exceptions +++ /dev/null @@ -1,66 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 - -# Ignore header name -ignore define _UAPI_DVBDMX_H_ - -# Ignore limit constants -ignore define DMX_FILTER_SIZE - -# dmx_pes_type_t enum symbols -replace enum dmx_ts_pes :c:type:`dmx_pes_type` -replace symbol DMX_PES_AUDIO0 :c:type:`dmx_pes_type` -replace symbol DMX_PES_VIDEO0 :c:type:`dmx_pes_type` -replace symbol DMX_PES_TELETEXT0 :c:type:`dmx_pes_type` -replace symbol DMX_PES_SUBTITLE0 :c:type:`dmx_pes_type` -replace symbol DMX_PES_PCR0 :c:type:`dmx_pes_type` -replace symbol DMX_PES_AUDIO1 :c:type:`dmx_pes_type` -replace symbol DMX_PES_VIDEO1 :c:type:`dmx_pes_type` -replace symbol DMX_PES_TELETEXT1 :c:type:`dmx_pes_type` -replace symbol DMX_PES_SUBTITLE1 :c:type:`dmx_pes_type` -replace symbol DMX_PES_PCR1 :c:type:`dmx_pes_type` -replace symbol DMX_PES_AUDIO2 :c:type:`dmx_pes_type` -replace symbol DMX_PES_VIDEO2 :c:type:`dmx_pes_type` -replace symbol DMX_PES_TELETEXT2 :c:type:`dmx_pes_type` -replace symbol DMX_PES_SUBTITLE2 :c:type:`dmx_pes_type` -replace symbol DMX_PES_PCR2 :c:type:`dmx_pes_type` -replace symbol DMX_PES_AUDIO3 :c:type:`dmx_pes_type` -replace symbol DMX_PES_VIDEO3 :c:type:`dmx_pes_type` -replace symbol DMX_PES_TELETEXT3 :c:type:`dmx_pes_type` -replace symbol DMX_PES_SUBTITLE3 :c:type:`dmx_pes_type` -replace symbol DMX_PES_PCR3 :c:type:`dmx_pes_type` -replace symbol DMX_PES_OTHER :c:type:`dmx_pes_type` - -# Ignore obsolete symbols -ignore define DMX_PES_AUDIO -ignore define DMX_PES_VIDEO -ignore define DMX_PES_TELETEXT -ignore define DMX_PES_SUBTITLE -ignore define DMX_PES_PCR - -# dmx_input_t symbols -replace enum dmx_input :c:type:`dmx_input` -replace symbol DMX_IN_FRONTEND :c:type:`dmx_input` -replace symbol DMX_IN_DVR :c:type:`dmx_input` - -# Flags for struct dmx_sct_filter_params -replace define DMX_CHECK_CRC :c:type:`dmx_sct_filter_params` -replace define DMX_ONESHOT :c:type:`dmx_sct_filter_params` -replace define DMX_IMMEDIATE_START :c:type:`dmx_sct_filter_params` - -# some typedefs should point to struct/enums -replace typedef dmx_filter_t :c:type:`dmx_filter` -replace typedef dmx_pes_type_t :c:type:`dmx_pes_type` -replace typedef dmx_input_t :c:type:`dmx_input` - -replace symbol DMX_BUFFER_FLAG_HAD_CRC32_DISCARD :c:type:`dmx_buffer_flags` -replace symbol DMX_BUFFER_FLAG_TEI :c:type:`dmx_buffer_flags` -replace symbol DMX_BUFFER_PKT_COUNTER_MISMATCH :c:type:`dmx_buffer_flags` -replace symbol DMX_BUFFER_FLAG_DISCONTINUITY_DETECTED :c:type:`dmx_buffer_flags` -replace symbol DMX_BUFFER_FLAG_DISCONTINUITY_INDICATOR :c:type:`dmx_buffer_flags` - -replace symbol DMX_OUT_DECODER :c:type:`dmx_output` -replace symbol DMX_OUT_TAP :c:type:`dmx_output` -replace symbol DMX_OUT_TS_TAP :c:type:`dmx_output` -replace symbol DMX_OUT_TSDEMUX_TAP :c:type:`dmx_output` - -replace ioctl DMX_DQBUF dmx_qbuf diff --git a/Documentation/media/frontend.h.rst.exceptions b/Documentation/media/frontend.h.rst.exceptions deleted file mode 100644 index 6283702c08c8..000000000000 --- a/Documentation/media/frontend.h.rst.exceptions +++ /dev/null @@ -1,214 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 - -# Ignore header name -ignore define _DVBFRONTEND_H_ - -# Group layer A-C symbols together -replace define DTV_ISDBT_LAYERA_FEC dtv-isdbt-layer-fec -replace define DTV_ISDBT_LAYERB_FEC dtv-isdbt-layer-fec -replace define DTV_ISDBT_LAYERC_FEC dtv-isdbt-layer-fec -replace define DTV_ISDBT_LAYERA_MODULATION dtv-isdbt-layer-modulation -replace define DTV_ISDBT_LAYERB_MODULATION dtv-isdbt-layer-modulation -replace define DTV_ISDBT_LAYERC_MODULATION dtv-isdbt-layer-modulation -replace define DTV_ISDBT_LAYERA_SEGMENT_COUNT dtv-isdbt-layer-segment-count -replace define DTV_ISDBT_LAYERB_SEGMENT_COUNT dtv-isdbt-layer-segment-count -replace define DTV_ISDBT_LAYERC_SEGMENT_COUNT dtv-isdbt-layer-segment-count -replace define DTV_ISDBT_LAYERA_TIME_INTERLEAVING dtv-isdbt-layer-time-interleaving -replace define DTV_ISDBT_LAYERB_TIME_INTERLEAVING dtv-isdbt-layer-time-interleaving -replace define DTV_ISDBT_LAYERC_TIME_INTERLEAVING dtv-isdbt-layer-time-interleaving - -# Ignore legacy defines -ignore define DTV_ISDBS_TS_ID_LEGACY -ignore define SYS_DVBC_ANNEX_AC -ignore define SYS_DMBTH - -# Ignore limits -ignore define DTV_MAX_COMMAND -ignore define MAX_DTV_STATS -ignore define DTV_IOCTL_MAX_MSGS - -# the same reference is used for both get and set ioctls -replace ioctl FE_SET_PROPERTY :c:type:`FE_GET_PROPERTY` - -# Typedefs that use the enum reference -replace typedef fe_sec_voltage_t :c:type:`fe_sec_voltage` - -# Replaces for flag constants -replace define FE_TUNE_MODE_ONESHOT :c:func:`FE_SET_FRONTEND_TUNE_MODE` -replace define LNA_AUTO dtv-lna -replace define NO_STREAM_ID_FILTER dtv-stream-id - -# Those enums are defined at the frontend.h header, and not externally - -ignore symbol FE_IS_STUPID -ignore symbol FE_CAN_INVERSION_AUTO -ignore symbol FE_CAN_FEC_1_2 -ignore symbol FE_CAN_FEC_2_3 -ignore symbol FE_CAN_FEC_3_4 -ignore symbol FE_CAN_FEC_4_5 -ignore symbol FE_CAN_FEC_5_6 -ignore symbol FE_CAN_FEC_6_7 -ignore symbol FE_CAN_FEC_7_8 -ignore symbol FE_CAN_FEC_8_9 -ignore symbol FE_CAN_FEC_AUTO -ignore symbol FE_CAN_QPSK -ignore symbol FE_CAN_QAM_16 -ignore symbol FE_CAN_QAM_32 -ignore symbol FE_CAN_QAM_64 -ignore symbol FE_CAN_QAM_128 -ignore symbol FE_CAN_QAM_256 -ignore symbol FE_CAN_QAM_AUTO -ignore symbol FE_CAN_TRANSMISSION_MODE_AUTO -ignore symbol FE_CAN_BANDWIDTH_AUTO -ignore symbol FE_CAN_GUARD_INTERVAL_AUTO -ignore symbol FE_CAN_HIERARCHY_AUTO -ignore symbol FE_CAN_8VSB -ignore symbol FE_CAN_16VSB -ignore symbol FE_HAS_EXTENDED_CAPS -ignore symbol FE_CAN_MULTISTREAM -ignore symbol FE_CAN_TURBO_FEC -ignore symbol FE_CAN_2G_MODULATION -ignore symbol FE_NEEDS_BENDING -ignore symbol FE_CAN_RECOVER -ignore symbol FE_CAN_MUTE_TS - -ignore symbol QPSK -ignore symbol QAM_16 -ignore symbol QAM_32 -ignore symbol QAM_64 -ignore symbol QAM_128 -ignore symbol QAM_256 -ignore symbol QAM_AUTO -ignore symbol VSB_8 -ignore symbol VSB_16 -ignore symbol PSK_8 -ignore symbol APSK_16 -ignore symbol APSK_32 -ignore symbol DQPSK -ignore symbol QAM_4_NR - -ignore symbol SEC_VOLTAGE_13 -ignore symbol SEC_VOLTAGE_18 -ignore symbol SEC_VOLTAGE_OFF - -ignore symbol SEC_TONE_ON -ignore symbol SEC_TONE_OFF - -ignore symbol SEC_MINI_A -ignore symbol SEC_MINI_B - -ignore symbol FE_NONE -ignore symbol FE_HAS_SIGNAL -ignore symbol FE_HAS_CARRIER -ignore symbol FE_HAS_VITERBI -ignore symbol FE_HAS_SYNC -ignore symbol FE_HAS_LOCK -ignore symbol FE_REINIT -ignore symbol FE_TIMEDOUT - -ignore symbol FEC_NONE -ignore symbol FEC_1_2 -ignore symbol FEC_2_3 -ignore symbol FEC_3_4 -ignore symbol FEC_4_5 -ignore symbol FEC_5_6 -ignore symbol FEC_6_7 -ignore symbol FEC_7_8 -ignore symbol FEC_8_9 -ignore symbol FEC_AUTO -ignore symbol FEC_3_5 -ignore symbol FEC_9_10 -ignore symbol FEC_2_5 - -ignore symbol TRANSMISSION_MODE_AUTO -ignore symbol TRANSMISSION_MODE_1K -ignore symbol TRANSMISSION_MODE_2K -ignore symbol TRANSMISSION_MODE_8K -ignore symbol TRANSMISSION_MODE_4K -ignore symbol TRANSMISSION_MODE_16K -ignore symbol TRANSMISSION_MODE_32K -ignore symbol TRANSMISSION_MODE_C1 -ignore symbol TRANSMISSION_MODE_C3780 -ignore symbol TRANSMISSION_MODE_2K -ignore symbol TRANSMISSION_MODE_8K - -ignore symbol GUARD_INTERVAL_AUTO -ignore symbol GUARD_INTERVAL_1_128 -ignore symbol GUARD_INTERVAL_1_32 -ignore symbol GUARD_INTERVAL_1_16 -ignore symbol GUARD_INTERVAL_1_8 -ignore symbol GUARD_INTERVAL_1_4 -ignore symbol GUARD_INTERVAL_19_128 -ignore symbol GUARD_INTERVAL_19_256 -ignore symbol GUARD_INTERVAL_PN420 -ignore symbol GUARD_INTERVAL_PN595 -ignore symbol GUARD_INTERVAL_PN945 - -ignore symbol HIERARCHY_NONE -ignore symbol HIERARCHY_AUTO -ignore symbol HIERARCHY_1 -ignore symbol HIERARCHY_2 -ignore symbol HIERARCHY_4 - -ignore symbol INTERLEAVING_NONE -ignore symbol INTERLEAVING_AUTO -ignore symbol INTERLEAVING_240 -ignore symbol INTERLEAVING_720 - -ignore symbol PILOT_ON -ignore symbol PILOT_OFF -ignore symbol PILOT_AUTO - -ignore symbol ROLLOFF_35 -ignore symbol ROLLOFF_20 -ignore symbol ROLLOFF_25 -ignore symbol ROLLOFF_AUTO - -ignore symbol INVERSION_ON -ignore symbol INVERSION_OFF -ignore symbol INVERSION_AUTO - -ignore symbol SYS_UNDEFINED -ignore symbol SYS_DVBC_ANNEX_A -ignore symbol SYS_DVBC_ANNEX_B -ignore symbol SYS_DVBC_ANNEX_C -ignore symbol SYS_ISDBC -ignore symbol SYS_DVBT -ignore symbol SYS_DVBT2 -ignore symbol SYS_ISDBT -ignore symbol SYS_ATSC -ignore symbol SYS_ATSCMH -ignore symbol SYS_DTMB -ignore symbol SYS_DVBS -ignore symbol SYS_DVBS2 -ignore symbol SYS_TURBO -ignore symbol SYS_ISDBS -ignore symbol SYS_DAB -ignore symbol SYS_DSS -ignore symbol SYS_CMMB -ignore symbol SYS_DVBH - -ignore symbol ATSCMH_SCCC_BLK_SEP -ignore symbol ATSCMH_SCCC_BLK_COMB -ignore symbol ATSCMH_SCCC_BLK_RES - -ignore symbol ATSCMH_SCCC_CODE_HLF -ignore symbol ATSCMH_SCCC_CODE_QTR -ignore symbol ATSCMH_SCCC_CODE_RES - -ignore symbol ATSCMH_RSFRAME_ENS_PRI -ignore symbol ATSCMH_RSFRAME_ENS_SEC - -ignore symbol ATSCMH_RSFRAME_PRI_ONLY -ignore symbol ATSCMH_RSFRAME_PRI_SEC -ignore symbol ATSCMH_RSFRAME_RES - -ignore symbol ATSCMH_RSCODE_211_187 -ignore symbol ATSCMH_RSCODE_223_187 -ignore symbol ATSCMH_RSCODE_235_187 -ignore symbol ATSCMH_RSCODE_RES - -ignore symbol FE_SCALE_NOT_AVAILABLE -ignore symbol FE_SCALE_DECIBEL -ignore symbol FE_SCALE_RELATIVE -ignore symbol FE_SCALE_COUNTER diff --git a/Documentation/media/index.rst b/Documentation/media/index.rst index 0301c25ff887..8118c2d001ff 100644 --- a/Documentation/media/index.rst +++ b/Documentation/media/index.rst @@ -12,7 +12,7 @@ Linux Media Subsystem Documentation .. toctree:: :maxdepth: 2 - media_uapi + ../userspace-api/media/index media_kapi dvb-drivers/index v4l-drivers/index diff --git a/Documentation/media/intro.rst b/Documentation/media/intro.rst deleted file mode 100644 index 4a6bd665b884..000000000000 --- a/Documentation/media/intro.rst +++ /dev/null @@ -1,46 +0,0 @@ -.. SPDX-License-Identifier: GPL-2.0 - -============ -Introduction -============ - -This document covers the Linux Kernel to Userspace API's used by video -and radio streaming devices, including video cameras, analog and digital -TV receiver cards, AM/FM receiver cards, Software Defined Radio (SDR), -streaming capture and output devices, codec devices and remote controllers. - -A typical media device hardware is shown at :ref:`typical_media_device`. - -.. _typical_media_device: - -.. kernel-figure:: typical_media_device.svg - :alt: typical_media_device.svg - :align: center - - Typical Media Device - -The media infrastructure API was designed to control such devices. It is -divided into five parts. - -1. The :ref:`first part ` covers radio, video capture and output, - cameras, analog TV devices and codecs. - -2. The :ref:`second part ` covers the API used for digital TV and - Internet reception via one of the several digital tv standards. While it is - called as DVB API, in fact it covers several different video standards - including DVB-T/T2, DVB-S/S2, DVB-C, ATSC, ISDB-T, ISDB-S, DTMB, etc. The - complete list of supported standards can be found at - :c:type:`fe_delivery_system`. - -3. The :ref:`third part ` covers the Remote Controller API. - -4. The :ref:`fourth part ` covers the Media Controller API. - -5. The :ref:`fifth part ` covers the CEC (Consumer Electronics Control) API. - -It should also be noted that a media device may also have audio components, like -mixers, PCM capture, PCM playback, etc, which are controlled via ALSA API. For -additional information and for the latest development code, see: -`https://linuxtv.org `__. For discussing improvements, -reporting troubles, sending new drivers, etc, please mail to: `Linux Media -Mailing List (LMML) `__. diff --git a/Documentation/media/lirc.h.rst.exceptions b/Documentation/media/lirc.h.rst.exceptions deleted file mode 100644 index ac768d769113..000000000000 --- a/Documentation/media/lirc.h.rst.exceptions +++ /dev/null @@ -1,80 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 - -# Ignore header name -ignore define _LINUX_LIRC_H - -# Ignore helper macros - -ignore define lirc_t - -ignore define LIRC_SPACE -ignore define LIRC_PULSE -ignore define LIRC_FREQUENCY -ignore define LIRC_TIMEOUT -ignore define LIRC_VALUE -ignore define LIRC_MODE2 -ignore define LIRC_IS_SPACE -ignore define LIRC_IS_PULSE -ignore define LIRC_IS_FREQUENCY -ignore define LIRC_IS_TIMEOUT - -ignore define LIRC_MODE2SEND -ignore define LIRC_SEND2MODE -ignore define LIRC_MODE2REC -ignore define LIRC_REC2MODE - -ignore define LIRC_CAN_SEND -ignore define LIRC_CAN_REC - -ignore define LIRC_CAN_SEND_MASK -ignore define LIRC_CAN_REC_MASK -ignore define LIRC_CAN_SET_REC_DUTY_CYCLE - -# Obsolete ioctls - -ignore ioctl LIRC_GET_LENGTH - -# rc protocols - -ignore symbol RC_PROTO_UNKNOWN -ignore symbol RC_PROTO_OTHER -ignore symbol RC_PROTO_RC5 -ignore symbol RC_PROTO_RC5X_20 -ignore symbol RC_PROTO_RC5_SZ -ignore symbol RC_PROTO_JVC -ignore symbol RC_PROTO_SONY12 -ignore symbol RC_PROTO_SONY15 -ignore symbol RC_PROTO_SONY20 -ignore symbol RC_PROTO_NEC -ignore symbol RC_PROTO_NECX -ignore symbol RC_PROTO_NEC32 -ignore symbol RC_PROTO_SANYO -ignore symbol RC_PROTO_MCIR2_KBD -ignore symbol RC_PROTO_MCIR2_MSE -ignore symbol RC_PROTO_RC6_0 -ignore symbol RC_PROTO_RC6_6A_20 -ignore symbol RC_PROTO_RC6_6A_24 -ignore symbol RC_PROTO_RC6_6A_32 -ignore symbol RC_PROTO_RC6_MCE -ignore symbol RC_PROTO_SHARP -ignore symbol RC_PROTO_XMP -ignore symbol RC_PROTO_CEC -ignore symbol RC_PROTO_IMON -ignore symbol RC_PROTO_RCMM12 -ignore symbol RC_PROTO_RCMM24 -ignore symbol RC_PROTO_RCMM32 -ignore symbol RC_PROTO_XBOX_DVD - -# Undocumented macros - -ignore define PULSE_BIT -ignore define PULSE_MASK - -ignore define LIRC_MODE2_SPACE -ignore define LIRC_MODE2_PULSE - -ignore define LIRC_VALUE_MASK -ignore define LIRC_MODE2_MASK - -ignore define LIRC_MODE_RAW -ignore define LIRC_MODE_LIRCCODE diff --git a/Documentation/media/media.h.rst.exceptions b/Documentation/media/media.h.rst.exceptions deleted file mode 100644 index 9b4c26502d95..000000000000 --- a/Documentation/media/media.h.rst.exceptions +++ /dev/null @@ -1,32 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 - -# Ignore header name -ignore define __LINUX_MEDIA_H - -# Ignore macros -ignore define MEDIA_API_VERSION -ignore define MEDIA_ENT_F_BASE -ignore define MEDIA_ENT_F_OLD_BASE -ignore define MEDIA_ENT_F_OLD_SUBDEV_BASE -ignore define MEDIA_ENT_F_DTV_DECODER -ignore define MEDIA_INTF_T_DVB_BASE -ignore define MEDIA_INTF_T_V4L_BASE -ignore define MEDIA_INTF_T_ALSA_BASE -#ignore legacy entity type macros -ignore define MEDIA_ENT_TYPE_SHIFT -ignore define MEDIA_ENT_TYPE_MASK -ignore define MEDIA_ENT_SUBTYPE_MASK -ignore define MEDIA_ENT_T_DEVNODE_UNKNOWN -ignore define MEDIA_ENT_T_DEVNODE -ignore define MEDIA_ENT_T_DEVNODE_V4L -ignore define MEDIA_ENT_T_DEVNODE_FB -ignore define MEDIA_ENT_T_DEVNODE_ALSA -ignore define MEDIA_ENT_T_DEVNODE_DVB -ignore define MEDIA_ENT_T_UNKNOWN -ignore define MEDIA_ENT_T_V4L2_VIDEO -ignore define MEDIA_ENT_T_V4L2_SUBDEV -ignore define MEDIA_ENT_T_V4L2_SUBDEV_SENSOR -ignore define MEDIA_ENT_T_V4L2_SUBDEV_FLASH -ignore define MEDIA_ENT_T_V4L2_SUBDEV_LENS -ignore define MEDIA_ENT_T_V4L2_SUBDEV_DECODER -ignore define MEDIA_ENT_T_V4L2_SUBDEV_TUNER diff --git a/Documentation/media/media_uapi.rst b/Documentation/media/media_uapi.rst deleted file mode 100644 index 0753005c7bb4..000000000000 --- a/Documentation/media/media_uapi.rst +++ /dev/null @@ -1,33 +0,0 @@ -.. SPDX-License-Identifier: GPL-2.0 - -.. include:: - -######################################## -Linux Media Infrastructure userspace API -######################################## - -**Copyright** |copy| 2009-2016 : LinuxTV Developers - -Permission is granted to copy, distribute and/or modify this document -under the terms of the GNU Free Documentation License, Version 1.1 or -any later version published by the Free Software Foundation, with no -Invariant Sections. A copy of the license is included in the chapter -entitled "GNU Free Documentation License". - -.. only:: html - - .. class:: toc-title - - Table of Contents - -.. toctree:: - :maxdepth: 1 - - intro - uapi/v4l/v4l2 - uapi/dvb/dvbapi - uapi/rc/remote_controllers - uapi/mediactl/media-controller - uapi/cec/cec-api - uapi/gen-errors - uapi/fdl-appendix diff --git a/Documentation/media/net.h.rst.exceptions b/Documentation/media/net.h.rst.exceptions deleted file mode 100644 index 5159aa4bbbb9..000000000000 --- a/Documentation/media/net.h.rst.exceptions +++ /dev/null @@ -1,13 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 - -# Ignore header name -ignore define _DVBNET_H_ - -# Ignore old ioctls/structs -ignore ioctl __NET_ADD_IF_OLD -ignore ioctl __NET_GET_IF_OLD -ignore struct __dvb_net_if_old - -# Macros used at struct dvb_net_if -replace define DVB_NET_FEEDTYPE_MPE :c:type:`dvb_net_if` -replace define DVB_NET_FEEDTYPE_ULE :c:type:`dvb_net_if` diff --git a/Documentation/media/typical_media_device.svg b/Documentation/media/typical_media_device.svg deleted file mode 100644 index bfd5c7db3b00..000000000000 --- a/Documentation/media/typical_media_device.svg +++ /dev/null @@ -1,116 +0,0 @@ - - -image/svg+xmlAudio decoder -Video decoder -Audio encoder -Button Key/IR input logic -EEPROM -Sensor -System Bus -Demux -Conditional Access Module -Video encoder -Radio / Analog TV -Digital TV -PS.: picture is not complete: other blocks may be present -Webcam -Processing blocks -Smartcard -TunerFM/TV -Satellite Equipment Control (SEC) -Demod -I2C Bus (control bus) -Digital TV Frontend - -CPU -PCI, USB, SPI, I2C, ... -Bridge - DMA - diff --git a/Documentation/media/uapi/cec/cec-api.rst b/Documentation/media/uapi/cec/cec-api.rst deleted file mode 100644 index 0780ba07995a..000000000000 --- a/Documentation/media/uapi/cec/cec-api.rst +++ /dev/null @@ -1,54 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. include:: - -.. _cec: - -######################################### -Part V - Consumer Electronics Control API -######################################### - -This part describes the CEC: Consumer Electronics Control - - -.. only:: html - - .. class:: toc-title - - Table of Contents - -.. toctree:: - :maxdepth: 5 - :numbered: - - cec-intro - cec-funcs - cec-pin-error-inj - cec-header - - -********************** -Revision and Copyright -********************** -Authors: - -- Verkuil, Hans - - - Initial version. - -**Copyright** |copy| 2016 : Hans Verkuil - -**************** -Revision History -**************** - -:revision: 1.0.0 / 2016-03-17 (*hv*) - -Initial revision diff --git a/Documentation/media/uapi/cec/cec-func-close.rst b/Documentation/media/uapi/cec/cec-func-close.rst deleted file mode 100644 index e10d675546f8..000000000000 --- a/Documentation/media/uapi/cec/cec-func-close.rst +++ /dev/null @@ -1,54 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _cec-func-close: - -*********** -cec close() -*********** - -Name -==== - -cec-close - Close a cec device - - -Synopsis -======== - -.. code-block:: c - - #include - - -.. c:function:: int close( int fd ) - :name: cec-close - -Arguments -========= - -``fd`` - File descriptor returned by :c:func:`open() `. - - -Description -=========== - -Closes the cec device. Resources associated with the file descriptor are -freed. The device configuration remain unchanged. - - -Return Value -============ - -:c:func:`close() ` returns 0 on success. On error, -1 is returned, and -``errno`` is set appropriately. Possible error codes are: - -``EBADF`` - ``fd`` is not a valid open file descriptor. diff --git a/Documentation/media/uapi/cec/cec-func-ioctl.rst b/Documentation/media/uapi/cec/cec-func-ioctl.rst deleted file mode 100644 index c18d4ba5eb37..000000000000 --- a/Documentation/media/uapi/cec/cec-func-ioctl.rst +++ /dev/null @@ -1,73 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _cec-func-ioctl: - -*********** -cec ioctl() -*********** - -Name -==== - -cec-ioctl - Control a cec device - -Synopsis -======== - -.. code-block:: c - - #include - - -.. c:function:: int ioctl( int fd, int request, void *argp ) - :name: cec-ioctl - -Arguments -========= - -``fd`` - File descriptor returned by :c:func:`open() `. - -``request`` - CEC ioctl request code as defined in the cec.h header file, for - example :ref:`CEC_ADAP_G_CAPS `. - -``argp`` - Pointer to a request-specific structure. - - -Description -=========== - -The :c:func:`ioctl() ` function manipulates cec device parameters. The -argument ``fd`` must be an open file descriptor. - -The ioctl ``request`` code specifies the cec function to be called. It -has encoded in it whether the argument is an input, output or read/write -parameter, and the size of the argument ``argp`` in bytes. - -Macros and structures definitions specifying cec ioctl requests and -their parameters are located in the cec.h header file. All cec ioctl -requests, their respective function and parameters are specified in -:ref:`cec-user-func`. - - -Return Value -============ - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. - -Request-specific error codes are listed in the individual requests -descriptions. - -When an ioctl that takes an output or read/write parameter fails, the -parameter remains unmodified. diff --git a/Documentation/media/uapi/cec/cec-func-open.rst b/Documentation/media/uapi/cec/cec-func-open.rst deleted file mode 100644 index f235aa80155c..000000000000 --- a/Documentation/media/uapi/cec/cec-func-open.rst +++ /dev/null @@ -1,85 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _cec-func-open: - -********** -cec open() -********** - -Name -==== - -cec-open - Open a cec device - -Synopsis -======== - -.. code-block:: c - - #include - - -.. c:function:: int open( const char *device_name, int flags ) - :name: cec-open - - -Arguments -========= - -``device_name`` - Device to be opened. - -``flags`` - Open flags. Access mode must be ``O_RDWR``. - - When the ``O_NONBLOCK`` flag is given, the - :ref:`CEC_RECEIVE ` and :ref:`CEC_DQEVENT ` ioctls - will return the ``EAGAIN`` error code when no message or event is available, and - ioctls :ref:`CEC_TRANSMIT `, - :ref:`CEC_ADAP_S_PHYS_ADDR ` and - :ref:`CEC_ADAP_S_LOG_ADDRS ` - all return 0. - - Other flags have no effect. - - -Description -=========== - -To open a cec device applications call :c:func:`open() ` with the -desired device name. The function has no side effects; the device -configuration remain unchanged. - -When the device is opened in read-only mode, attempts to modify its -configuration will result in an error, and ``errno`` will be set to -EBADF. - - -Return Value -============ - -:c:func:`open() ` returns the new file descriptor on success. On error, --1 is returned, and ``errno`` is set appropriately. Possible error codes -include: - -``EACCES`` - The requested access to the file is not allowed. - -``EMFILE`` - The process already has the maximum number of files open. - -``ENFILE`` - The system limit on the total number of open files has been reached. - -``ENOMEM`` - Insufficient kernel memory was available. - -``ENXIO`` - No device corresponding to this device special file exists. diff --git a/Documentation/media/uapi/cec/cec-func-poll.rst b/Documentation/media/uapi/cec/cec-func-poll.rst deleted file mode 100644 index 3f6c5b0effa3..000000000000 --- a/Documentation/media/uapi/cec/cec-func-poll.rst +++ /dev/null @@ -1,85 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _cec-func-poll: - -********** -cec poll() -********** - -Name -==== - -cec-poll - Wait for some event on a file descriptor - - -Synopsis -======== - -.. code-block:: c - - #include - - -.. c:function:: int poll( struct pollfd *ufds, unsigned int nfds, int timeout ) - :name: cec-poll - -Arguments -========= - -``ufds`` - List of FD events to be watched - -``nfds`` - Number of FD events at the \*ufds array - -``timeout`` - Timeout to wait for events - - -Description -=========== - -With the :c:func:`poll() ` function applications can wait for CEC -events. - -On success :c:func:`poll() ` returns the number of file descriptors -that have been selected (that is, file descriptors for which the -``revents`` field of the respective struct :c:type:`pollfd` -is non-zero). CEC devices set the ``POLLIN`` and ``POLLRDNORM`` flags in -the ``revents`` field if there are messages in the receive queue. If the -transmit queue has room for new messages, the ``POLLOUT`` and -``POLLWRNORM`` flags are set. If there are events in the event queue, -then the ``POLLPRI`` flag is set. When the function times out it returns -a value of zero, on failure it returns -1 and the ``errno`` variable is -set appropriately. - -For more details see the :c:func:`poll() ` manual page. - - -Return Value -============ - -On success, :c:func:`poll() ` returns the number structures which have -non-zero ``revents`` fields, or zero if the call timed out. On error -1 -is returned, and the ``errno`` variable is set appropriately: - -``EBADF`` - One or more of the ``ufds`` members specify an invalid file - descriptor. - -``EFAULT`` - ``ufds`` references an inaccessible memory area. - -``EINTR`` - The call was interrupted by a signal. - -``EINVAL`` - The ``nfds`` value exceeds the ``RLIMIT_NOFILE`` value. Use - ``getrlimit()`` to obtain this value. diff --git a/Documentation/media/uapi/cec/cec-funcs.rst b/Documentation/media/uapi/cec/cec-funcs.rst deleted file mode 100644 index dc6da9c639a8..000000000000 --- a/Documentation/media/uapi/cec/cec-funcs.rst +++ /dev/null @@ -1,30 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _cec-user-func: - -****************** -Function Reference -****************** - - -.. toctree:: - :maxdepth: 1 - - cec-func-open - cec-func-close - cec-func-ioctl - cec-func-poll - cec-ioc-adap-g-caps - cec-ioc-adap-g-log-addrs - cec-ioc-adap-g-phys-addr - cec-ioc-adap-g-conn-info - cec-ioc-dqevent - cec-ioc-g-mode - cec-ioc-receive diff --git a/Documentation/media/uapi/cec/cec-header.rst b/Documentation/media/uapi/cec/cec-header.rst deleted file mode 100644 index 726f9766a130..000000000000 --- a/Documentation/media/uapi/cec/cec-header.rst +++ /dev/null @@ -1,17 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _cec_header: - -*************** -CEC Header File -*************** - -.. kernel-include:: $BUILDDIR/cec.h.rst - diff --git a/Documentation/media/uapi/cec/cec-intro.rst b/Documentation/media/uapi/cec/cec-intro.rst deleted file mode 100644 index 05088fcefe81..000000000000 --- a/Documentation/media/uapi/cec/cec-intro.rst +++ /dev/null @@ -1,49 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _cec-intro: - -Introduction -============ - -HDMI connectors provide a single pin for use by the Consumer Electronics -Control protocol. This protocol allows different devices connected by an -HDMI cable to communicate. The protocol for CEC version 1.4 is defined -in supplements 1 (CEC) and 2 (HEAC or HDMI Ethernet and Audio Return -Channel) of the HDMI 1.4a (:ref:`hdmi`) specification and the -extensions added to CEC version 2.0 are defined in chapter 11 of the -HDMI 2.0 (:ref:`hdmi2`) specification. - -The bitrate is very slow (effectively no more than 36 bytes per second) -and is based on the ancient AV.link protocol used in old SCART -connectors. The protocol closely resembles a crazy Rube Goldberg -contraption and is an unholy mix of low and high level messages. Some -messages, especially those part of the HEAC protocol layered on top of -CEC, need to be handled by the kernel, others can be handled either by -the kernel or by userspace. - -In addition, CEC can be implemented in HDMI receivers, transmitters and -in USB devices that have an HDMI input and an HDMI output and that -control just the CEC pin. - -Drivers that support CEC will create a CEC device node (/dev/cecX) to -give userspace access to the CEC adapter. The -:ref:`CEC_ADAP_G_CAPS` ioctl will tell userspace what it is allowed to do. - -In order to check the support and test it, it is suggested to download -the `v4l-utils `_ package. It -provides three tools to handle CEC: - -- cec-ctl: the Swiss army knife of CEC. Allows you to configure, transmit - and monitor CEC messages. - -- cec-compliance: does a CEC compliance test of a remote CEC device to - determine how compliant the CEC implementation is. - -- cec-follower: emulates a CEC follower. diff --git a/Documentation/media/uapi/cec/cec-ioc-adap-g-caps.rst b/Documentation/media/uapi/cec/cec-ioc-adap-g-caps.rst deleted file mode 100644 index 76761a98c312..000000000000 --- a/Documentation/media/uapi/cec/cec-ioc-adap-g-caps.rst +++ /dev/null @@ -1,150 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _CEC_ADAP_G_CAPS: - -********************* -ioctl CEC_ADAP_G_CAPS -********************* - -Name -==== - -CEC_ADAP_G_CAPS - Query device capabilities - -Synopsis -======== - -.. c:function:: int ioctl( int fd, CEC_ADAP_G_CAPS, struct cec_caps *argp ) - :name: CEC_ADAP_G_CAPS - -Arguments -========= - -``fd`` - File descriptor returned by :c:func:`open() `. - -``argp`` - - -Description -=========== - -All cec devices must support :ref:`ioctl CEC_ADAP_G_CAPS `. To query -device information, applications call the ioctl with a pointer to a -struct :c:type:`cec_caps`. The driver fills the structure and -returns the information to the application. The ioctl never fails. - -.. tabularcolumns:: |p{1.2cm}|p{2.5cm}|p{13.8cm}| - -.. c:type:: cec_caps - -.. flat-table:: struct cec_caps - :header-rows: 0 - :stub-columns: 0 - :widths: 1 1 16 - - * - char - - ``driver[32]`` - - The name of the cec adapter driver. - * - char - - ``name[32]`` - - The name of this CEC adapter. The combination ``driver`` and - ``name`` must be unique. - * - __u32 - - ``capabilities`` - - The capabilities of the CEC adapter, see - :ref:`cec-capabilities`. - * - __u32 - - ``version`` - - CEC Framework API version, formatted with the ``KERNEL_VERSION()`` - macro. - - -.. tabularcolumns:: |p{4.4cm}|p{2.5cm}|p{10.6cm}| - -.. _cec-capabilities: - -.. flat-table:: CEC Capabilities Flags - :header-rows: 0 - :stub-columns: 0 - :widths: 3 1 8 - - * .. _`CEC-CAP-PHYS-ADDR`: - - - ``CEC_CAP_PHYS_ADDR`` - - 0x00000001 - - Userspace has to configure the physical address by calling - :ref:`ioctl CEC_ADAP_S_PHYS_ADDR `. If - this capability isn't set, then setting the physical address is - handled by the kernel whenever the EDID is set (for an HDMI - receiver) or read (for an HDMI transmitter). - * .. _`CEC-CAP-LOG-ADDRS`: - - - ``CEC_CAP_LOG_ADDRS`` - - 0x00000002 - - Userspace has to configure the logical addresses by calling - :ref:`ioctl CEC_ADAP_S_LOG_ADDRS `. If - this capability isn't set, then the kernel will have configured - this. - * .. _`CEC-CAP-TRANSMIT`: - - - ``CEC_CAP_TRANSMIT`` - - 0x00000004 - - Userspace can transmit CEC messages by calling - :ref:`ioctl CEC_TRANSMIT `. This implies that - userspace can be a follower as well, since being able to transmit - messages is a prerequisite of becoming a follower. If this - capability isn't set, then the kernel will handle all CEC - transmits and process all CEC messages it receives. - * .. _`CEC-CAP-PASSTHROUGH`: - - - ``CEC_CAP_PASSTHROUGH`` - - 0x00000008 - - Userspace can use the passthrough mode by calling - :ref:`ioctl CEC_S_MODE `. - * .. _`CEC-CAP-RC`: - - - ``CEC_CAP_RC`` - - 0x00000010 - - This adapter supports the remote control protocol. - * .. _`CEC-CAP-MONITOR-ALL`: - - - ``CEC_CAP_MONITOR_ALL`` - - 0x00000020 - - The CEC hardware can monitor all messages, not just directed and - broadcast messages. - * .. _`CEC-CAP-NEEDS-HPD`: - - - ``CEC_CAP_NEEDS_HPD`` - - 0x00000040 - - The CEC hardware is only active if the HDMI Hotplug Detect pin is - high. This makes it impossible to use CEC to wake up displays that - set the HPD pin low when in standby mode, but keep the CEC bus - alive. - * .. _`CEC-CAP-MONITOR-PIN`: - - - ``CEC_CAP_MONITOR_PIN`` - - 0x00000080 - - The CEC hardware can monitor CEC pin changes from low to high voltage - and vice versa. When in pin monitoring mode the application will - receive ``CEC_EVENT_PIN_CEC_LOW`` and ``CEC_EVENT_PIN_CEC_HIGH`` events. - * .. _`CEC-CAP-CONNECTOR-INFO`: - - - ``CEC_CAP_CONNECTOR_INFO`` - - 0x00000100 - - If this capability is set, then :ref:`CEC_ADAP_G_CONNECTOR_INFO` can - be used. - -Return Value -============ - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/cec/cec-ioc-adap-g-conn-info.rst b/Documentation/media/uapi/cec/cec-ioc-adap-g-conn-info.rst deleted file mode 100644 index 6818ddf1495c..000000000000 --- a/Documentation/media/uapi/cec/cec-ioc-adap-g-conn-info.rst +++ /dev/null @@ -1,105 +0,0 @@ -.. SPDX-License-Identifier: GPL-2.0 -.. -.. Copyright 2019 Google LLC -.. -.. _CEC_ADAP_G_CONNECTOR_INFO: - -******************************* -ioctl CEC_ADAP_G_CONNECTOR_INFO -******************************* - -Name -==== - -CEC_ADAP_G_CONNECTOR_INFO - Query HDMI connector information - -Synopsis -======== - -.. c:function:: int ioctl( int fd, CEC_ADAP_G_CONNECTOR_INFO, struct cec_connector_info *argp ) - :name: CEC_ADAP_G_CONNECTOR_INFO - -Arguments -========= - -``fd`` - File descriptor returned by :c:func:`open() `. - -``argp`` - - -Description -=========== - -Using this ioctl an application can learn which HDMI connector this CEC -device corresponds to. While calling this ioctl the application should -provide a pointer to a cec_connector_info struct which will be populated -by the kernel with the info provided by the adapter's driver. This ioctl -is only available if the ``CEC_CAP_CONNECTOR_INFO`` capability is set. - -.. tabularcolumns:: |p{1.0cm}|p{4.4cm}|p{2.5cm}|p{9.6cm}| - -.. c:type:: cec_connector_info - -.. flat-table:: struct cec_connector_info - :header-rows: 0 - :stub-columns: 0 - :widths: 1 1 8 - - * - __u32 - - ``type`` - - The type of connector this adapter is associated with. - * - union { - - ``(anonymous)`` - * - ``struct cec_drm_connector_info`` - - drm - - :ref:`cec-drm-connector-info` - * - } - - - - -.. tabularcolumns:: |p{4.4cm}|p{2.5cm}|p{10.6cm}| - -.. _connector-type: - -.. flat-table:: Connector types - :header-rows: 0 - :stub-columns: 0 - :widths: 3 1 8 - - * .. _`CEC-CONNECTOR-TYPE-NO-CONNECTOR`: - - - ``CEC_CONNECTOR_TYPE_NO_CONNECTOR`` - - 0 - - No connector is associated with the adapter/the information is not - provided by the driver. - * .. _`CEC-CONNECTOR-TYPE-DRM`: - - - ``CEC_CONNECTOR_TYPE_DRM`` - - 1 - - Indicates that a DRM connector is associated with this adapter. - Information about the connector can be found in - :ref:`cec-drm-connector-info`. - -.. tabularcolumns:: |p{4.4cm}|p{2.5cm}|p{10.6cm}| - -.. c:type:: cec_drm_connector_info - -.. _cec-drm-connector-info: - -.. flat-table:: struct cec_drm_connector_info - :header-rows: 0 - :stub-columns: 0 - :widths: 3 1 8 - - * .. _`CEC-DRM-CONNECTOR-TYPE-CARD-NO`: - - - __u32 - - ``card_no`` - - DRM card number: the number from a card's path, e.g. 0 in case of - /dev/card0. - * .. _`CEC-DRM-CONNECTOR-TYPE-CONNECTOR_ID`: - - - __u32 - - ``connector_id`` - - DRM connector ID. diff --git a/Documentation/media/uapi/cec/cec-ioc-adap-g-log-addrs.rst b/Documentation/media/uapi/cec/cec-ioc-adap-g-log-addrs.rst deleted file mode 100644 index 26465094e3f1..000000000000 --- a/Documentation/media/uapi/cec/cec-ioc-adap-g-log-addrs.rst +++ /dev/null @@ -1,378 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _CEC_ADAP_LOG_ADDRS: -.. _CEC_ADAP_G_LOG_ADDRS: -.. _CEC_ADAP_S_LOG_ADDRS: - -**************************************************** -ioctls CEC_ADAP_G_LOG_ADDRS and CEC_ADAP_S_LOG_ADDRS -**************************************************** - -Name -==== - -CEC_ADAP_G_LOG_ADDRS, CEC_ADAP_S_LOG_ADDRS - Get or set the logical addresses - - -Synopsis -======== - -.. c:function:: int ioctl( int fd, CEC_ADAP_G_LOG_ADDRS, struct cec_log_addrs *argp ) - :name: CEC_ADAP_G_LOG_ADDRS - -.. c:function:: int ioctl( int fd, CEC_ADAP_S_LOG_ADDRS, struct cec_log_addrs *argp ) - :name: CEC_ADAP_S_LOG_ADDRS - -Arguments -========= - -``fd`` - File descriptor returned by :c:func:`open() `. - -``argp`` - Pointer to struct :c:type:`cec_log_addrs`. - -Description -=========== - -To query the current CEC logical addresses, applications call -:ref:`ioctl CEC_ADAP_G_LOG_ADDRS ` with a pointer to a -struct :c:type:`cec_log_addrs` where the driver stores the logical addresses. - -To set new logical addresses, applications fill in -struct :c:type:`cec_log_addrs` and call :ref:`ioctl CEC_ADAP_S_LOG_ADDRS ` -with a pointer to this struct. The :ref:`ioctl CEC_ADAP_S_LOG_ADDRS ` -is only available if ``CEC_CAP_LOG_ADDRS`` is set (the ``ENOTTY`` error code is -returned otherwise). The :ref:`ioctl CEC_ADAP_S_LOG_ADDRS ` -can only be called by a file descriptor in initiator mode (see :ref:`CEC_S_MODE`), if not -the ``EBUSY`` error code will be returned. - -To clear existing logical addresses set ``num_log_addrs`` to 0. All other fields -will be ignored in that case. The adapter will go to the unconfigured state and the -``cec_version``, ``vendor_id`` and ``osd_name`` fields are all reset to their default -values (CEC version 2.0, no vendor ID and an empty OSD name). - -If the physical address is valid (see :ref:`ioctl CEC_ADAP_S_PHYS_ADDR `), -then this ioctl will block until all requested logical -addresses have been claimed. If the file descriptor is in non-blocking mode then it will -not wait for the logical addresses to be claimed, instead it just returns 0. - -A :ref:`CEC_EVENT_STATE_CHANGE ` event is sent when the -logical addresses are claimed or cleared. - -Attempting to call :ref:`ioctl CEC_ADAP_S_LOG_ADDRS ` when -logical address types are already defined will return with error ``EBUSY``. - -.. c:type:: cec_log_addrs - -.. tabularcolumns:: |p{1.0cm}|p{8.0cm}|p{7.5cm}| - -.. cssclass:: longtable - -.. flat-table:: struct cec_log_addrs - :header-rows: 0 - :stub-columns: 0 - :widths: 1 1 16 - - * - __u8 - - ``log_addr[CEC_MAX_LOG_ADDRS]`` - - The actual logical addresses that were claimed. This is set by the - driver. If no logical address could be claimed, then it is set to - ``CEC_LOG_ADDR_INVALID``. If this adapter is Unregistered, then - ``log_addr[0]`` is set to 0xf and all others to - ``CEC_LOG_ADDR_INVALID``. - * - __u16 - - ``log_addr_mask`` - - The bitmask of all logical addresses this adapter has claimed. If - this adapter is Unregistered then ``log_addr_mask`` sets bit 15 - and clears all other bits. If this adapter is not configured at - all, then ``log_addr_mask`` is set to 0. Set by the driver. - * - __u8 - - ``cec_version`` - - The CEC version that this adapter shall use. See - :ref:`cec-versions`. Used to implement the - ``CEC_MSG_CEC_VERSION`` and ``CEC_MSG_REPORT_FEATURES`` messages. - Note that :ref:`CEC_OP_CEC_VERSION_1_3A ` is not allowed by the CEC - framework. - * - __u8 - - ``num_log_addrs`` - - Number of logical addresses to set up. Must be ≤ - ``available_log_addrs`` as returned by - :ref:`CEC_ADAP_G_CAPS`. All arrays in - this structure are only filled up to index - ``available_log_addrs``-1. The remaining array elements will be - ignored. Note that the CEC 2.0 standard allows for a maximum of 2 - logical addresses, although some hardware has support for more. - ``CEC_MAX_LOG_ADDRS`` is 4. The driver will return the actual - number of logical addresses it could claim, which may be less than - what was requested. If this field is set to 0, then the CEC - adapter shall clear all claimed logical addresses and all other - fields will be ignored. - * - __u32 - - ``vendor_id`` - - The vendor ID is a 24-bit number that identifies the specific - vendor or entity. Based on this ID vendor specific commands may be - defined. If you do not want a vendor ID then set it to - ``CEC_VENDOR_ID_NONE``. - * - __u32 - - ``flags`` - - Flags. See :ref:`cec-log-addrs-flags` for a list of available flags. - * - char - - ``osd_name[15]`` - - The On-Screen Display name as is returned by the - ``CEC_MSG_SET_OSD_NAME`` message. - * - __u8 - - ``primary_device_type[CEC_MAX_LOG_ADDRS]`` - - Primary device type for each logical address. See - :ref:`cec-prim-dev-types` for possible types. - * - __u8 - - ``log_addr_type[CEC_MAX_LOG_ADDRS]`` - - Logical address types. See :ref:`cec-log-addr-types` for - possible types. The driver will update this with the actual - logical address type that it claimed (e.g. it may have to fallback - to :ref:`CEC_LOG_ADDR_TYPE_UNREGISTERED `). - * - __u8 - - ``all_device_types[CEC_MAX_LOG_ADDRS]`` - - CEC 2.0 specific: the bit mask of all device types. See - :ref:`cec-all-dev-types-flags`. It is used in the CEC 2.0 - ``CEC_MSG_REPORT_FEATURES`` message. For CEC 1.4 you can either leave - this field to 0, or fill it in according to the CEC 2.0 guidelines to - give the CEC framework more information about the device type, even - though the framework won't use it directly in the CEC message. - * - __u8 - - ``features[CEC_MAX_LOG_ADDRS][12]`` - - Features for each logical address. It is used in the CEC 2.0 - ``CEC_MSG_REPORT_FEATURES`` message. The 12 bytes include both the - RC Profile and the Device Features. For CEC 1.4 you can either leave - this field to all 0, or fill it in according to the CEC 2.0 guidelines to - give the CEC framework more information about the device type, even - though the framework won't use it directly in the CEC message. - - -.. tabularcolumns:: |p{7.8cm}|p{1.0cm}|p{8.7cm}| - -.. _cec-log-addrs-flags: - -.. flat-table:: Flags for struct cec_log_addrs - :header-rows: 0 - :stub-columns: 0 - :widths: 3 1 4 - - * .. _`CEC-LOG-ADDRS-FL-ALLOW-UNREG-FALLBACK`: - - - ``CEC_LOG_ADDRS_FL_ALLOW_UNREG_FALLBACK`` - - 1 - - By default if no logical address of the requested type can be claimed, then - it will go back to the unconfigured state. If this flag is set, then it will - fallback to the Unregistered logical address. Note that if the Unregistered - logical address was explicitly requested, then this flag has no effect. - * .. _`CEC-LOG-ADDRS-FL-ALLOW-RC-PASSTHRU`: - - - ``CEC_LOG_ADDRS_FL_ALLOW_RC_PASSTHRU`` - - 2 - - By default the ``CEC_MSG_USER_CONTROL_PRESSED`` and ``CEC_MSG_USER_CONTROL_RELEASED`` - messages are only passed on to the follower(s), if any. If this flag is set, - then these messages are also passed on to the remote control input subsystem - and will appear as keystrokes. This features needs to be enabled explicitly. - If CEC is used to enter e.g. passwords, then you may not want to enable this - to avoid trivial snooping of the keystrokes. - * .. _`CEC-LOG-ADDRS-FL-CDC-ONLY`: - - - ``CEC_LOG_ADDRS_FL_CDC_ONLY`` - - 4 - - If this flag is set, then the device is CDC-Only. CDC-Only CEC devices - are CEC devices that can only handle CDC messages. - - All other messages are ignored. - - -.. tabularcolumns:: |p{7.8cm}|p{1.0cm}|p{8.7cm}| - -.. _cec-versions: - -.. flat-table:: CEC Versions - :header-rows: 0 - :stub-columns: 0 - :widths: 3 1 4 - - * .. _`CEC-OP-CEC-VERSION-1-3A`: - - - ``CEC_OP_CEC_VERSION_1_3A`` - - 4 - - CEC version according to the HDMI 1.3a standard. - * .. _`CEC-OP-CEC-VERSION-1-4B`: - - - ``CEC_OP_CEC_VERSION_1_4B`` - - 5 - - CEC version according to the HDMI 1.4b standard. - * .. _`CEC-OP-CEC-VERSION-2-0`: - - - ``CEC_OP_CEC_VERSION_2_0`` - - 6 - - CEC version according to the HDMI 2.0 standard. - - -.. tabularcolumns:: |p{6.6cm}|p{2.2cm}|p{8.7cm}| - -.. _cec-prim-dev-types: - -.. flat-table:: CEC Primary Device Types - :header-rows: 0 - :stub-columns: 0 - :widths: 3 1 4 - - * .. _`CEC-OP-PRIM-DEVTYPE-TV`: - - - ``CEC_OP_PRIM_DEVTYPE_TV`` - - 0 - - Use for a TV. - * .. _`CEC-OP-PRIM-DEVTYPE-RECORD`: - - - ``CEC_OP_PRIM_DEVTYPE_RECORD`` - - 1 - - Use for a recording device. - * .. _`CEC-OP-PRIM-DEVTYPE-TUNER`: - - - ``CEC_OP_PRIM_DEVTYPE_TUNER`` - - 3 - - Use for a device with a tuner. - * .. _`CEC-OP-PRIM-DEVTYPE-PLAYBACK`: - - - ``CEC_OP_PRIM_DEVTYPE_PLAYBACK`` - - 4 - - Use for a playback device. - * .. _`CEC-OP-PRIM-DEVTYPE-AUDIOSYSTEM`: - - - ``CEC_OP_PRIM_DEVTYPE_AUDIOSYSTEM`` - - 5 - - Use for an audio system (e.g. an audio/video receiver). - * .. _`CEC-OP-PRIM-DEVTYPE-SWITCH`: - - - ``CEC_OP_PRIM_DEVTYPE_SWITCH`` - - 6 - - Use for a CEC switch. - * .. _`CEC-OP-PRIM-DEVTYPE-VIDEOPROC`: - - - ``CEC_OP_PRIM_DEVTYPE_VIDEOPROC`` - - 7 - - Use for a video processor device. - - -.. tabularcolumns:: |p{6.6cm}|p{2.2cm}|p{8.7cm}| - -.. _cec-log-addr-types: - -.. flat-table:: CEC Logical Address Types - :header-rows: 0 - :stub-columns: 0 - :widths: 3 1 16 - - * .. _`CEC-LOG-ADDR-TYPE-TV`: - - - ``CEC_LOG_ADDR_TYPE_TV`` - - 0 - - Use for a TV. - * .. _`CEC-LOG-ADDR-TYPE-RECORD`: - - - ``CEC_LOG_ADDR_TYPE_RECORD`` - - 1 - - Use for a recording device. - * .. _`CEC-LOG-ADDR-TYPE-TUNER`: - - - ``CEC_LOG_ADDR_TYPE_TUNER`` - - 2 - - Use for a tuner device. - * .. _`CEC-LOG-ADDR-TYPE-PLAYBACK`: - - - ``CEC_LOG_ADDR_TYPE_PLAYBACK`` - - 3 - - Use for a playback device. - * .. _`CEC-LOG-ADDR-TYPE-AUDIOSYSTEM`: - - - ``CEC_LOG_ADDR_TYPE_AUDIOSYSTEM`` - - 4 - - Use for an audio system device. - * .. _`CEC-LOG-ADDR-TYPE-SPECIFIC`: - - - ``CEC_LOG_ADDR_TYPE_SPECIFIC`` - - 5 - - Use for a second TV or for a video processor device. - * .. _`CEC-LOG-ADDR-TYPE-UNREGISTERED`: - - - ``CEC_LOG_ADDR_TYPE_UNREGISTERED`` - - 6 - - Use this if you just want to remain unregistered. Used for pure - CEC switches or CDC-only devices (CDC: Capability Discovery and - Control). - - - -.. tabularcolumns:: |p{6.6cm}|p{2.2cm}|p{8.7cm}| - -.. _cec-all-dev-types-flags: - -.. flat-table:: CEC All Device Types Flags - :header-rows: 0 - :stub-columns: 0 - :widths: 3 1 4 - - * .. _`CEC-OP-ALL-DEVTYPE-TV`: - - - ``CEC_OP_ALL_DEVTYPE_TV`` - - 0x80 - - This supports the TV type. - * .. _`CEC-OP-ALL-DEVTYPE-RECORD`: - - - ``CEC_OP_ALL_DEVTYPE_RECORD`` - - 0x40 - - This supports the Recording type. - * .. _`CEC-OP-ALL-DEVTYPE-TUNER`: - - - ``CEC_OP_ALL_DEVTYPE_TUNER`` - - 0x20 - - This supports the Tuner type. - * .. _`CEC-OP-ALL-DEVTYPE-PLAYBACK`: - - - ``CEC_OP_ALL_DEVTYPE_PLAYBACK`` - - 0x10 - - This supports the Playback type. - * .. _`CEC-OP-ALL-DEVTYPE-AUDIOSYSTEM`: - - - ``CEC_OP_ALL_DEVTYPE_AUDIOSYSTEM`` - - 0x08 - - This supports the Audio System type. - * .. _`CEC-OP-ALL-DEVTYPE-SWITCH`: - - - ``CEC_OP_ALL_DEVTYPE_SWITCH`` - - 0x04 - - This supports the CEC Switch or Video Processing type. - - - -Return Value -============ - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. - -The :ref:`ioctl CEC_ADAP_S_LOG_ADDRS ` can return the following -error codes: - -ENOTTY - The ``CEC_CAP_LOG_ADDRS`` capability wasn't set, so this ioctl is not supported. - -EBUSY - The CEC adapter is currently configuring itself, or it is already configured and - ``num_log_addrs`` is non-zero, or another filehandle is in exclusive follower or - initiator mode, or the filehandle is in mode ``CEC_MODE_NO_INITIATOR``. - -EINVAL - The contents of struct :c:type:`cec_log_addrs` is invalid. diff --git a/Documentation/media/uapi/cec/cec-ioc-adap-g-phys-addr.rst b/Documentation/media/uapi/cec/cec-ioc-adap-g-phys-addr.rst deleted file mode 100644 index 693be2f9bf2e..000000000000 --- a/Documentation/media/uapi/cec/cec-ioc-adap-g-phys-addr.rst +++ /dev/null @@ -1,100 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _CEC_ADAP_PHYS_ADDR: -.. _CEC_ADAP_G_PHYS_ADDR: -.. _CEC_ADAP_S_PHYS_ADDR: - -**************************************************** -ioctls CEC_ADAP_G_PHYS_ADDR and CEC_ADAP_S_PHYS_ADDR -**************************************************** - -Name -==== - -CEC_ADAP_G_PHYS_ADDR, CEC_ADAP_S_PHYS_ADDR - Get or set the physical address - - -Synopsis -======== - -.. c:function:: int ioctl( int fd, CEC_ADAP_G_PHYS_ADDR, __u16 *argp ) - :name: CEC_ADAP_G_PHYS_ADDR - -.. c:function:: int ioctl( int fd, CEC_ADAP_S_PHYS_ADDR, __u16 *argp ) - :name: CEC_ADAP_S_PHYS_ADDR - -Arguments -========= - -``fd`` - File descriptor returned by :c:func:`open() `. - -``argp`` - Pointer to the CEC address. - -Description -=========== - -To query the current physical address applications call -:ref:`ioctl CEC_ADAP_G_PHYS_ADDR ` with a pointer to a __u16 where the -driver stores the physical address. - -To set a new physical address applications store the physical address in -a __u16 and call :ref:`ioctl CEC_ADAP_S_PHYS_ADDR ` with a pointer to -this integer. The :ref:`ioctl CEC_ADAP_S_PHYS_ADDR ` is only available if -``CEC_CAP_PHYS_ADDR`` is set (the ``ENOTTY`` error code will be returned -otherwise). The :ref:`ioctl CEC_ADAP_S_PHYS_ADDR ` can only be called -by a file descriptor in initiator mode (see :ref:`CEC_S_MODE`), if not -the ``EBUSY`` error code will be returned. - -To clear an existing physical address use ``CEC_PHYS_ADDR_INVALID``. -The adapter will go to the unconfigured state. - -If logical address types have been defined (see :ref:`ioctl CEC_ADAP_S_LOG_ADDRS `), -then this ioctl will block until all -requested logical addresses have been claimed. If the file descriptor is in non-blocking mode -then it will not wait for the logical addresses to be claimed, instead it just returns 0. - -A :ref:`CEC_EVENT_STATE_CHANGE ` event is sent when the physical address -changes. - -The physical address is a 16-bit number where each group of 4 bits -represent a digit of the physical address a.b.c.d where the most -significant 4 bits represent 'a'. The CEC root device (usually the TV) -has address 0.0.0.0. Every device that is hooked up to an input of the -TV has address a.0.0.0 (where 'a' is ≥ 1), devices hooked up to those in -turn have addresses a.b.0.0, etc. So a topology of up to 5 devices deep -is supported. The physical address a device shall use is stored in the -EDID of the sink. - -For example, the EDID for each HDMI input of the TV will have a -different physical address of the form a.0.0.0 that the sources will -read out and use as their physical address. - - -Return Value -============ - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. - -The :ref:`ioctl CEC_ADAP_S_PHYS_ADDR ` can return the following -error codes: - -ENOTTY - The ``CEC_CAP_PHYS_ADDR`` capability wasn't set, so this ioctl is not supported. - -EBUSY - Another filehandle is in exclusive follower or initiator mode, or the filehandle - is in mode ``CEC_MODE_NO_INITIATOR``. - -EINVAL - The physical address is malformed. diff --git a/Documentation/media/uapi/cec/cec-ioc-dqevent.rst b/Documentation/media/uapi/cec/cec-ioc-dqevent.rst deleted file mode 100644 index d16b226b1bef..000000000000 --- a/Documentation/media/uapi/cec/cec-ioc-dqevent.rst +++ /dev/null @@ -1,257 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _CEC_DQEVENT: - -***************** -ioctl CEC_DQEVENT -***************** - -Name -==== - -CEC_DQEVENT - Dequeue a CEC event - - -Synopsis -======== - -.. c:function:: int ioctl( int fd, CEC_DQEVENT, struct cec_event *argp ) - :name: CEC_DQEVENT - -Arguments -========= - -``fd`` - File descriptor returned by :c:func:`open() `. - -``argp`` - - -Description -=========== - -CEC devices can send asynchronous events. These can be retrieved by -calling :c:func:`CEC_DQEVENT`. If the file descriptor is in -non-blocking mode and no event is pending, then it will return -1 and -set errno to the ``EAGAIN`` error code. - -The internal event queues are per-filehandle and per-event type. If -there is no more room in a queue then the last event is overwritten with -the new one. This means that intermediate results can be thrown away but -that the latest event is always available. This also means that is it -possible to read two successive events that have the same value (e.g. -two :ref:`CEC_EVENT_STATE_CHANGE ` events with -the same state). In that case the intermediate state changes were lost but -it is guaranteed that the state did change in between the two events. - -.. tabularcolumns:: |p{1.2cm}|p{2.9cm}|p{13.4cm}| - -.. c:type:: cec_event_state_change - -.. flat-table:: struct cec_event_state_change - :header-rows: 0 - :stub-columns: 0 - :widths: 1 1 8 - - * - __u16 - - ``phys_addr`` - - The current physical address. This is ``CEC_PHYS_ADDR_INVALID`` if no - valid physical address is set. - * - __u16 - - ``log_addr_mask`` - - The current set of claimed logical addresses. This is 0 if no logical - addresses are claimed or if ``phys_addr`` is ``CEC_PHYS_ADDR_INVALID``. - If bit 15 is set (``1 << CEC_LOG_ADDR_UNREGISTERED``) then this device - has the unregistered logical address. In that case all other bits are 0. - * - __u16 - - ``have_conn_info`` - - If non-zero, then HDMI connector information is available. - This field is only valid if ``CEC_CAP_CONNECTOR_INFO`` is set. If that - capability is set and ``have_conn_info`` is zero, then that indicates - that the HDMI connector device is not instantiated, either because - the HDMI driver is still configuring the device or because the HDMI - device was unbound. - - -.. c:type:: cec_event_lost_msgs - -.. tabularcolumns:: |p{1.0cm}|p{2.0cm}|p{14.5cm}| - -.. flat-table:: struct cec_event_lost_msgs - :header-rows: 0 - :stub-columns: 0 - :widths: 1 1 16 - - * - __u32 - - ``lost_msgs`` - - Set to the number of lost messages since the filehandle was opened - or since the last time this event was dequeued for this - filehandle. The messages lost are the oldest messages. So when a - new message arrives and there is no more room, then the oldest - message is discarded to make room for the new one. The internal - size of the message queue guarantees that all messages received in - the last two seconds will be stored. Since messages should be - replied to within a second according to the CEC specification, - this is more than enough. - - -.. tabularcolumns:: |p{1.0cm}|p{4.4cm}|p{2.5cm}|p{9.6cm}| - -.. c:type:: cec_event - -.. flat-table:: struct cec_event - :header-rows: 0 - :stub-columns: 0 - :widths: 1 1 8 - - * - __u64 - - ``ts`` - - Timestamp of the event in ns. - - The timestamp has been taken from the ``CLOCK_MONOTONIC`` clock. - - To access the same clock from userspace use :c:func:`clock_gettime`. - * - __u32 - - ``event`` - - The CEC event type, see :ref:`cec-events`. - * - __u32 - - ``flags`` - - Event flags, see :ref:`cec-event-flags`. - * - union { - - (anonymous) - * - struct cec_event_state_change - - ``state_change`` - - The new adapter state as sent by the :ref:`CEC_EVENT_STATE_CHANGE ` - event. - * - struct cec_event_lost_msgs - - ``lost_msgs`` - - The number of lost messages as sent by the :ref:`CEC_EVENT_LOST_MSGS ` - event. - * - } - - - - -.. tabularcolumns:: |p{5.6cm}|p{0.9cm}|p{11.0cm}| - -.. _cec-events: - -.. flat-table:: CEC Events Types - :header-rows: 0 - :stub-columns: 0 - :widths: 3 1 16 - - * .. _`CEC-EVENT-STATE-CHANGE`: - - - ``CEC_EVENT_STATE_CHANGE`` - - 1 - - Generated when the CEC Adapter's state changes. When open() is - called an initial event will be generated for that filehandle with - the CEC Adapter's state at that time. - * .. _`CEC-EVENT-LOST-MSGS`: - - - ``CEC_EVENT_LOST_MSGS`` - - 2 - - Generated if one or more CEC messages were lost because the - application didn't dequeue CEC messages fast enough. - * .. _`CEC-EVENT-PIN-CEC-LOW`: - - - ``CEC_EVENT_PIN_CEC_LOW`` - - 3 - - Generated if the CEC pin goes from a high voltage to a low voltage. - Only applies to adapters that have the ``CEC_CAP_MONITOR_PIN`` - capability set. - * .. _`CEC-EVENT-PIN-CEC-HIGH`: - - - ``CEC_EVENT_PIN_CEC_HIGH`` - - 4 - - Generated if the CEC pin goes from a low voltage to a high voltage. - Only applies to adapters that have the ``CEC_CAP_MONITOR_PIN`` - capability set. - * .. _`CEC-EVENT-PIN-HPD-LOW`: - - - ``CEC_EVENT_PIN_HPD_LOW`` - - 5 - - Generated if the HPD pin goes from a high voltage to a low voltage. - Only applies to adapters that have the ``CEC_CAP_MONITOR_PIN`` - capability set. When open() is called, the HPD pin can be read and - if the HPD is low, then an initial event will be generated for that - filehandle. - * .. _`CEC-EVENT-PIN-HPD-HIGH`: - - - ``CEC_EVENT_PIN_HPD_HIGH`` - - 6 - - Generated if the HPD pin goes from a low voltage to a high voltage. - Only applies to adapters that have the ``CEC_CAP_MONITOR_PIN`` - capability set. When open() is called, the HPD pin can be read and - if the HPD is high, then an initial event will be generated for that - filehandle. - * .. _`CEC-EVENT-PIN-5V-LOW`: - - - ``CEC_EVENT_PIN_5V_LOW`` - - 6 - - Generated if the 5V pin goes from a high voltage to a low voltage. - Only applies to adapters that have the ``CEC_CAP_MONITOR_PIN`` - capability set. When open() is called, the 5V pin can be read and - if the 5V is low, then an initial event will be generated for that - filehandle. - * .. _`CEC-EVENT-PIN-5V-HIGH`: - - - ``CEC_EVENT_PIN_5V_HIGH`` - - 7 - - Generated if the 5V pin goes from a low voltage to a high voltage. - Only applies to adapters that have the ``CEC_CAP_MONITOR_PIN`` - capability set. When open() is called, the 5V pin can be read and - if the 5V is high, then an initial event will be generated for that - filehandle. - - -.. tabularcolumns:: |p{6.0cm}|p{0.6cm}|p{10.9cm}| - -.. _cec-event-flags: - -.. flat-table:: CEC Event Flags - :header-rows: 0 - :stub-columns: 0 - :widths: 3 1 8 - - * .. _`CEC-EVENT-FL-INITIAL-STATE`: - - - ``CEC_EVENT_FL_INITIAL_STATE`` - - 1 - - Set for the initial events that are generated when the device is - opened. See the table above for which events do this. This allows - applications to learn the initial state of the CEC adapter at - open() time. - * .. _`CEC-EVENT-FL-DROPPED-EVENTS`: - - - ``CEC_EVENT_FL_DROPPED_EVENTS`` - - 2 - - Set if one or more events of the given event type have been dropped. - This is an indication that the application cannot keep up. - - - -Return Value -============ - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. - -The :ref:`ioctl CEC_DQEVENT ` can return the following -error codes: - -EAGAIN - This is returned when the filehandle is in non-blocking mode and there - are no pending events. - -ERESTARTSYS - An interrupt (e.g. Ctrl-C) arrived while in blocking mode waiting for - events to arrive. diff --git a/Documentation/media/uapi/cec/cec-ioc-g-mode.rst b/Documentation/media/uapi/cec/cec-ioc-g-mode.rst deleted file mode 100644 index 2535b77e3459..000000000000 --- a/Documentation/media/uapi/cec/cec-ioc-g-mode.rst +++ /dev/null @@ -1,301 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _CEC_MODE: -.. _CEC_G_MODE: -.. _CEC_S_MODE: - -******************************** -ioctls CEC_G_MODE and CEC_S_MODE -******************************** - -CEC_G_MODE, CEC_S_MODE - Get or set exclusive use of the CEC adapter - -Synopsis -======== - -.. c:function:: int ioctl( int fd, CEC_G_MODE, __u32 *argp ) - :name: CEC_G_MODE - -.. c:function:: int ioctl( int fd, CEC_S_MODE, __u32 *argp ) - :name: CEC_S_MODE - -Arguments -========= - -``fd`` - File descriptor returned by :c:func:`open() `. - -``argp`` - Pointer to CEC mode. - -Description -=========== - -By default any filehandle can use :ref:`CEC_TRANSMIT`, but in order to prevent -applications from stepping on each others toes it must be possible to -obtain exclusive access to the CEC adapter. This ioctl sets the -filehandle to initiator and/or follower mode which can be exclusive -depending on the chosen mode. The initiator is the filehandle that is -used to initiate messages, i.e. it commands other CEC devices. The -follower is the filehandle that receives messages sent to the CEC -adapter and processes them. The same filehandle can be both initiator -and follower, or this role can be taken by two different filehandles. - -When a CEC message is received, then the CEC framework will decide how -it will be processed. If the message is a reply to an earlier -transmitted message, then the reply is sent back to the filehandle that -is waiting for it. In addition the CEC framework will process it. - -If the message is not a reply, then the CEC framework will process it -first. If there is no follower, then the message is just discarded and a -feature abort is sent back to the initiator if the framework couldn't -process it. If there is a follower, then the message is passed on to the -follower who will use :ref:`ioctl CEC_RECEIVE ` to dequeue -the new message. The framework expects the follower to make the right -decisions. - -The CEC framework will process core messages unless requested otherwise -by the follower. The follower can enable the passthrough mode. In that -case, the CEC framework will pass on most core messages without -processing them and the follower will have to implement those messages. -There are some messages that the core will always process, regardless of -the passthrough mode. See :ref:`cec-core-processing` for details. - -If there is no initiator, then any CEC filehandle can use -:ref:`ioctl CEC_TRANSMIT `. If there is an exclusive -initiator then only that initiator can call -:ref:`CEC_TRANSMIT`. The follower can of course -always call :ref:`ioctl CEC_TRANSMIT `. - -Available initiator modes are: - -.. tabularcolumns:: |p{5.6cm}|p{0.9cm}|p{11.0cm}| - -.. _cec-mode-initiator_e: - -.. flat-table:: Initiator Modes - :header-rows: 0 - :stub-columns: 0 - :widths: 3 1 16 - - * .. _`CEC-MODE-NO-INITIATOR`: - - - ``CEC_MODE_NO_INITIATOR`` - - 0x0 - - This is not an initiator, i.e. it cannot transmit CEC messages or - make any other changes to the CEC adapter. - * .. _`CEC-MODE-INITIATOR`: - - - ``CEC_MODE_INITIATOR`` - - 0x1 - - This is an initiator (the default when the device is opened) and - it can transmit CEC messages and make changes to the CEC adapter, - unless there is an exclusive initiator. - * .. _`CEC-MODE-EXCL-INITIATOR`: - - - ``CEC_MODE_EXCL_INITIATOR`` - - 0x2 - - This is an exclusive initiator and this file descriptor is the - only one that can transmit CEC messages and make changes to the - CEC adapter. If someone else is already the exclusive initiator - then an attempt to become one will return the ``EBUSY`` error code - error. - - -Available follower modes are: - -.. tabularcolumns:: |p{6.6cm}|p{0.9cm}|p{10.0cm}| - -.. _cec-mode-follower_e: - -.. cssclass:: longtable - -.. flat-table:: Follower Modes - :header-rows: 0 - :stub-columns: 0 - :widths: 3 1 16 - - * .. _`CEC-MODE-NO-FOLLOWER`: - - - ``CEC_MODE_NO_FOLLOWER`` - - 0x00 - - This is not a follower (the default when the device is opened). - * .. _`CEC-MODE-FOLLOWER`: - - - ``CEC_MODE_FOLLOWER`` - - 0x10 - - This is a follower and it will receive CEC messages unless there - is an exclusive follower. You cannot become a follower if - :ref:`CEC_CAP_TRANSMIT ` is not set or if :ref:`CEC_MODE_NO_INITIATOR ` - was specified, the ``EINVAL`` error code is returned in that case. - * .. _`CEC-MODE-EXCL-FOLLOWER`: - - - ``CEC_MODE_EXCL_FOLLOWER`` - - 0x20 - - This is an exclusive follower and only this file descriptor will - receive CEC messages for processing. If someone else is already - the exclusive follower then an attempt to become one will return - the ``EBUSY`` error code. You cannot become a follower if - :ref:`CEC_CAP_TRANSMIT ` is not set or if :ref:`CEC_MODE_NO_INITIATOR ` - was specified, the ``EINVAL`` error code is returned in that case. - * .. _`CEC-MODE-EXCL-FOLLOWER-PASSTHRU`: - - - ``CEC_MODE_EXCL_FOLLOWER_PASSTHRU`` - - 0x30 - - This is an exclusive follower and only this file descriptor will - receive CEC messages for processing. In addition it will put the - CEC device into passthrough mode, allowing the exclusive follower - to handle most core messages instead of relying on the CEC - framework for that. If someone else is already the exclusive - follower then an attempt to become one will return the ``EBUSY`` error - code. You cannot become a follower if :ref:`CEC_CAP_TRANSMIT ` - is not set or if :ref:`CEC_MODE_NO_INITIATOR ` was specified, - the ``EINVAL`` error code is returned in that case. - * .. _`CEC-MODE-MONITOR-PIN`: - - - ``CEC_MODE_MONITOR_PIN`` - - 0xd0 - - Put the file descriptor into pin monitoring mode. Can only be used in - combination with :ref:`CEC_MODE_NO_INITIATOR `, - otherwise the ``EINVAL`` error code will be returned. - This mode requires that the :ref:`CEC_CAP_MONITOR_PIN ` - capability is set, otherwise the ``EINVAL`` error code is returned. - While in pin monitoring mode this file descriptor can receive the - ``CEC_EVENT_PIN_CEC_LOW`` and ``CEC_EVENT_PIN_CEC_HIGH`` events to see the - low-level CEC pin transitions. This is very useful for debugging. - This mode is only allowed if the process has the ``CAP_NET_ADMIN`` - capability. If that is not set, then the ``EPERM`` error code is returned. - * .. _`CEC-MODE-MONITOR`: - - - ``CEC_MODE_MONITOR`` - - 0xe0 - - Put the file descriptor into monitor mode. Can only be used in - combination with :ref:`CEC_MODE_NO_INITIATOR `, - otherwise the ``EINVAL`` error code will be returned. - In monitor mode all messages this CEC - device transmits and all messages it receives (both broadcast - messages and directed messages for one its logical addresses) will - be reported. This is very useful for debugging. This is only - allowed if the process has the ``CAP_NET_ADMIN`` capability. If - that is not set, then the ``EPERM`` error code is returned. - * .. _`CEC-MODE-MONITOR-ALL`: - - - ``CEC_MODE_MONITOR_ALL`` - - 0xf0 - - Put the file descriptor into 'monitor all' mode. Can only be used - in combination with :ref:`CEC_MODE_NO_INITIATOR `, otherwise - the ``EINVAL`` error code will be returned. In 'monitor all' mode all messages - this CEC device transmits and all messages it receives, including - directed messages for other CEC devices will be reported. This is - very useful for debugging, but not all devices support this. This - mode requires that the :ref:`CEC_CAP_MONITOR_ALL ` capability is set, - otherwise the ``EINVAL`` error code is returned. This is only allowed if - the process has the ``CAP_NET_ADMIN`` capability. If that is not - set, then the ``EPERM`` error code is returned. - - -Core message processing details: - -.. tabularcolumns:: |p{6.6cm}|p{10.9cm}| - -.. _cec-core-processing: - -.. flat-table:: Core Message Processing - :header-rows: 0 - :stub-columns: 0 - :widths: 1 8 - - * .. _`CEC-MSG-GET-CEC-VERSION`: - - - ``CEC_MSG_GET_CEC_VERSION`` - - The core will return the CEC version that was set with - :ref:`ioctl CEC_ADAP_S_LOG_ADDRS `, - except when in passthrough mode. In passthrough mode the core - does nothing and this message has to be handled by a follower - instead. - * .. _`CEC-MSG-GIVE-DEVICE-VENDOR-ID`: - - - ``CEC_MSG_GIVE_DEVICE_VENDOR_ID`` - - The core will return the vendor ID that was set with - :ref:`ioctl CEC_ADAP_S_LOG_ADDRS `, - except when in passthrough mode. In passthrough mode the core - does nothing and this message has to be handled by a follower - instead. - * .. _`CEC-MSG-ABORT`: - - - ``CEC_MSG_ABORT`` - - The core will return a Feature Abort message with reason - 'Feature Refused' as per the specification, except when in - passthrough mode. In passthrough mode the core does nothing - and this message has to be handled by a follower instead. - * .. _`CEC-MSG-GIVE-PHYSICAL-ADDR`: - - - ``CEC_MSG_GIVE_PHYSICAL_ADDR`` - - The core will report the current physical address, except when - in passthrough mode. In passthrough mode the core does nothing - and this message has to be handled by a follower instead. - * .. _`CEC-MSG-GIVE-OSD-NAME`: - - - ``CEC_MSG_GIVE_OSD_NAME`` - - The core will report the current OSD name that was set with - :ref:`ioctl CEC_ADAP_S_LOG_ADDRS `, - except when in passthrough mode. In passthrough mode the core - does nothing and this message has to be handled by a follower - instead. - * .. _`CEC-MSG-GIVE-FEATURES`: - - - ``CEC_MSG_GIVE_FEATURES`` - - The core will do nothing if the CEC version is older than 2.0, - otherwise it will report the current features that were set with - :ref:`ioctl CEC_ADAP_S_LOG_ADDRS `, - except when in passthrough mode. In passthrough mode the core - does nothing (for any CEC version) and this message has to be handled - by a follower instead. - * .. _`CEC-MSG-USER-CONTROL-PRESSED`: - - - ``CEC_MSG_USER_CONTROL_PRESSED`` - - If :ref:`CEC_CAP_RC ` is set and if - :ref:`CEC_LOG_ADDRS_FL_ALLOW_RC_PASSTHRU ` - is set, then generate a remote control key - press. This message is always passed on to the follower(s). - * .. _`CEC-MSG-USER-CONTROL-RELEASED`: - - - ``CEC_MSG_USER_CONTROL_RELEASED`` - - If :ref:`CEC_CAP_RC ` is set and if - :ref:`CEC_LOG_ADDRS_FL_ALLOW_RC_PASSTHRU ` - is set, then generate a remote control key - release. This message is always passed on to the follower(s). - * .. _`CEC-MSG-REPORT-PHYSICAL-ADDR`: - - - ``CEC_MSG_REPORT_PHYSICAL_ADDR`` - - The CEC framework will make note of the reported physical address - and then just pass the message on to the follower(s). - - - -Return Value -============ - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. - -The :ref:`ioctl CEC_S_MODE ` can return the following -error codes: - -EINVAL - The requested mode is invalid. - -EPERM - Monitor mode is requested, but the process does have the ``CAP_NET_ADMIN`` - capability. - -EBUSY - Someone else is already an exclusive follower or initiator. diff --git a/Documentation/media/uapi/cec/cec-ioc-receive.rst b/Documentation/media/uapi/cec/cec-ioc-receive.rst deleted file mode 100644 index 4137903d672e..000000000000 --- a/Documentation/media/uapi/cec/cec-ioc-receive.rst +++ /dev/null @@ -1,391 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _CEC_TRANSMIT: -.. _CEC_RECEIVE: - -*********************************** -ioctls CEC_RECEIVE and CEC_TRANSMIT -*********************************** - -Name -==== - -CEC_RECEIVE, CEC_TRANSMIT - Receive or transmit a CEC message - - -Synopsis -======== - -.. c:function:: int ioctl( int fd, CEC_RECEIVE, struct cec_msg \*argp ) - :name: CEC_RECEIVE - -.. c:function:: int ioctl( int fd, CEC_TRANSMIT, struct cec_msg \*argp ) - :name: CEC_TRANSMIT - -Arguments -========= - -``fd`` - File descriptor returned by :c:func:`open() `. - -``argp`` - Pointer to struct cec_msg. - -Description -=========== - -To receive a CEC message the application has to fill in the -``timeout`` field of struct :c:type:`cec_msg` and pass it to -:ref:`ioctl CEC_RECEIVE `. -If the file descriptor is in non-blocking mode and there are no received -messages pending, then it will return -1 and set errno to the ``EAGAIN`` -error code. If the file descriptor is in blocking mode and ``timeout`` -is non-zero and no message arrived within ``timeout`` milliseconds, then -it will return -1 and set errno to the ``ETIMEDOUT`` error code. - -A received message can be: - -1. a message received from another CEC device (the ``sequence`` field will - be 0). -2. the result of an earlier non-blocking transmit (the ``sequence`` field will - be non-zero). - -To send a CEC message the application has to fill in the struct -:c:type:`cec_msg` and pass it to :ref:`ioctl CEC_TRANSMIT `. -The :ref:`ioctl CEC_TRANSMIT ` is only available if -``CEC_CAP_TRANSMIT`` is set. If there is no more room in the transmit -queue, then it will return -1 and set errno to the ``EBUSY`` error code. -The transmit queue has enough room for 18 messages (about 1 second worth -of 2-byte messages). Note that the CEC kernel framework will also reply -to core messages (see :ref:`cec-core-processing`), so it is not a good -idea to fully fill up the transmit queue. - -If the file descriptor is in non-blocking mode then the transmit will -return 0 and the result of the transmit will be available via -:ref:`ioctl CEC_RECEIVE ` once the transmit has finished -(including waiting for a reply, if requested). - -The ``sequence`` field is filled in for every transmit and this can be -checked against the received messages to find the corresponding transmit -result. - -Normally calling :ref:`ioctl CEC_TRANSMIT ` when the physical -address is invalid (due to e.g. a disconnect) will return ``ENONET``. - -However, the CEC specification allows sending messages from 'Unregistered' to -'TV' when the physical address is invalid since some TVs pull the hotplug detect -pin of the HDMI connector low when they go into standby, or when switching to -another input. - -When the hotplug detect pin goes low the EDID disappears, and thus the -physical address, but the cable is still connected and CEC still works. -In order to detect/wake up the device it is allowed to send poll and 'Image/Text -View On' messages from initiator 0xf ('Unregistered') to destination 0 ('TV'). - -.. tabularcolumns:: |p{1.0cm}|p{3.5cm}|p{13.0cm}| - -.. c:type:: cec_msg - -.. cssclass:: longtable - -.. flat-table:: struct cec_msg - :header-rows: 0 - :stub-columns: 0 - :widths: 1 1 16 - - * - __u64 - - ``tx_ts`` - - Timestamp in ns of when the last byte of the message was transmitted. - The timestamp has been taken from the ``CLOCK_MONOTONIC`` clock. To access - the same clock from userspace use :c:func:`clock_gettime`. - * - __u64 - - ``rx_ts`` - - Timestamp in ns of when the last byte of the message was received. - The timestamp has been taken from the ``CLOCK_MONOTONIC`` clock. To access - the same clock from userspace use :c:func:`clock_gettime`. - * - __u32 - - ``len`` - - The length of the message. For :ref:`ioctl CEC_TRANSMIT ` this is filled in - by the application. The driver will fill this in for - :ref:`ioctl CEC_RECEIVE `. For :ref:`ioctl CEC_TRANSMIT ` it will be - filled in by the driver with the length of the reply message if ``reply`` was set. - * - __u32 - - ``timeout`` - - The timeout in milliseconds. This is the time the device will wait - for a message to be received before timing out. If it is set to 0, - then it will wait indefinitely when it is called by :ref:`ioctl CEC_RECEIVE `. - If it is 0 and it is called by :ref:`ioctl CEC_TRANSMIT `, - then it will be replaced by 1000 if the ``reply`` is non-zero or - ignored if ``reply`` is 0. - * - __u32 - - ``sequence`` - - A non-zero sequence number is automatically assigned by the CEC framework - for all transmitted messages. It is used by the CEC framework when it queues - the transmit result (when transmit was called in non-blocking mode). This - allows the application to associate the received message with the original - transmit. - * - __u32 - - ``flags`` - - Flags. See :ref:`cec-msg-flags` for a list of available flags. - * - __u8 - - ``tx_status`` - - The status bits of the transmitted message. See - :ref:`cec-tx-status` for the possible status values. It is 0 if - this message was received, not transmitted. - * - __u8 - - ``msg[16]`` - - The message payload. For :ref:`ioctl CEC_TRANSMIT ` this is filled in by the - application. The driver will fill this in for :ref:`ioctl CEC_RECEIVE `. - For :ref:`ioctl CEC_TRANSMIT ` it will be filled in by the driver with - the payload of the reply message if ``timeout`` was set. - * - __u8 - - ``reply`` - - Wait until this message is replied. If ``reply`` is 0 and the - ``timeout`` is 0, then don't wait for a reply but return after - transmitting the message. Ignored by :ref:`ioctl CEC_RECEIVE `. - The case where ``reply`` is 0 (this is the opcode for the Feature Abort - message) and ``timeout`` is non-zero is specifically allowed to make it - possible to send a message and wait up to ``timeout`` milliseconds for a - Feature Abort reply. In this case ``rx_status`` will either be set - to :ref:`CEC_RX_STATUS_TIMEOUT ` or - :ref:`CEC_RX_STATUS_FEATURE_ABORT `. - - If the transmitter message is ``CEC_MSG_INITIATE_ARC`` then the ``reply`` - values ``CEC_MSG_REPORT_ARC_INITIATED`` and ``CEC_MSG_REPORT_ARC_TERMINATED`` - are processed differently: either value will match both possible replies. - The reason is that the ``CEC_MSG_INITIATE_ARC`` message is the only CEC - message that has two possible replies other than Feature Abort. The - ``reply`` field will be updated with the actual reply so that it is - synchronized with the contents of the received message. - * - __u8 - - ``rx_status`` - - The status bits of the received message. See - :ref:`cec-rx-status` for the possible status values. It is 0 if - this message was transmitted, not received, unless this is the - reply to a transmitted message. In that case both ``rx_status`` - and ``tx_status`` are set. - * - __u8 - - ``tx_status`` - - The status bits of the transmitted message. See - :ref:`cec-tx-status` for the possible status values. It is 0 if - this message was received, not transmitted. - * - __u8 - - ``tx_arb_lost_cnt`` - - A counter of the number of transmit attempts that resulted in the - Arbitration Lost error. This is only set if the hardware supports - this, otherwise it is always 0. This counter is only valid if the - :ref:`CEC_TX_STATUS_ARB_LOST ` status bit is set. - * - __u8 - - ``tx_nack_cnt`` - - A counter of the number of transmit attempts that resulted in the - Not Acknowledged error. This is only set if the hardware supports - this, otherwise it is always 0. This counter is only valid if the - :ref:`CEC_TX_STATUS_NACK ` status bit is set. - * - __u8 - - ``tx_low_drive_cnt`` - - A counter of the number of transmit attempts that resulted in the - Arbitration Lost error. This is only set if the hardware supports - this, otherwise it is always 0. This counter is only valid if the - :ref:`CEC_TX_STATUS_LOW_DRIVE ` status bit is set. - * - __u8 - - ``tx_error_cnt`` - - A counter of the number of transmit errors other than Arbitration - Lost or Not Acknowledged. This is only set if the hardware - supports this, otherwise it is always 0. This counter is only - valid if the :ref:`CEC_TX_STATUS_ERROR ` status bit is set. - - -.. tabularcolumns:: |p{6.2cm}|p{1.0cm}|p{10.3cm}| - -.. _cec-msg-flags: - -.. flat-table:: Flags for struct cec_msg - :header-rows: 0 - :stub-columns: 0 - :widths: 3 1 4 - - * .. _`CEC-MSG-FL-REPLY-TO-FOLLOWERS`: - - - ``CEC_MSG_FL_REPLY_TO_FOLLOWERS`` - - 1 - - If a CEC transmit expects a reply, then by default that reply is only sent to - the filehandle that called :ref:`ioctl CEC_TRANSMIT `. If this - flag is set, then the reply is also sent to all followers, if any. If the - filehandle that called :ref:`ioctl CEC_TRANSMIT ` is also a - follower, then that filehandle will receive the reply twice: once as the - result of the :ref:`ioctl CEC_TRANSMIT `, and once via - :ref:`ioctl CEC_RECEIVE `. - - * .. _`CEC-MSG-FL-RAW`: - - - ``CEC_MSG_FL_RAW`` - - 2 - - Normally CEC messages are validated before transmitting them. If this - flag is set when :ref:`ioctl CEC_TRANSMIT ` is called, - then no validation takes place and the message is transmitted as-is. - This is useful when debugging CEC issues. - This flag is only allowed if the process has the ``CAP_SYS_RAWIO`` - capability. If that is not set, then the ``EPERM`` error code is - returned. - - -.. tabularcolumns:: |p{5.6cm}|p{0.9cm}|p{11.0cm}| - -.. _cec-tx-status: - -.. flat-table:: CEC Transmit Status - :header-rows: 0 - :stub-columns: 0 - :widths: 3 1 16 - - * .. _`CEC-TX-STATUS-OK`: - - - ``CEC_TX_STATUS_OK`` - - 0x01 - - The message was transmitted successfully. This is mutually - exclusive with :ref:`CEC_TX_STATUS_MAX_RETRIES `. - Other bits can still be set if earlier attempts met with failure before - the transmit was eventually successful. - * .. _`CEC-TX-STATUS-ARB-LOST`: - - - ``CEC_TX_STATUS_ARB_LOST`` - - 0x02 - - CEC line arbitration was lost, i.e. another transmit started at the - same time with a higher priority. Optional status, not all hardware - can detect this error condition. - * .. _`CEC-TX-STATUS-NACK`: - - - ``CEC_TX_STATUS_NACK`` - - 0x04 - - Message was not acknowledged. Note that some hardware cannot tell apart - a 'Not Acknowledged' status from other error conditions, i.e. the result - of a transmit is just OK or FAIL. In that case this status will be - returned when the transmit failed. - * .. _`CEC-TX-STATUS-LOW-DRIVE`: - - - ``CEC_TX_STATUS_LOW_DRIVE`` - - 0x08 - - Low drive was detected on the CEC bus. This indicates that a - follower detected an error on the bus and requests a - retransmission. Optional status, not all hardware can detect this - error condition. - * .. _`CEC-TX-STATUS-ERROR`: - - - ``CEC_TX_STATUS_ERROR`` - - 0x10 - - Some error occurred. This is used for any errors that do not fit - ``CEC_TX_STATUS_ARB_LOST`` or ``CEC_TX_STATUS_LOW_DRIVE``, either because - the hardware could not tell which error occurred, or because the hardware - tested for other conditions besides those two. Optional status. - * .. _`CEC-TX-STATUS-MAX-RETRIES`: - - - ``CEC_TX_STATUS_MAX_RETRIES`` - - 0x20 - - The transmit failed after one or more retries. This status bit is - mutually exclusive with :ref:`CEC_TX_STATUS_OK `. - Other bits can still be set to explain which failures were seen. - * .. _`CEC-TX-STATUS-ABORTED`: - - - ``CEC_TX_STATUS_ABORTED`` - - 0x40 - - The transmit was aborted due to an HDMI disconnect, or the adapter - was unconfigured, or a transmit was interrupted, or the driver - returned an error when attempting to start a transmit. - * .. _`CEC-TX-STATUS-TIMEOUT`: - - - ``CEC_TX_STATUS_TIMEOUT`` - - 0x80 - - The transmit timed out. This should not normally happen and this - indicates a driver problem. - - -.. tabularcolumns:: |p{5.6cm}|p{0.9cm}|p{11.0cm}| - -.. _cec-rx-status: - -.. flat-table:: CEC Receive Status - :header-rows: 0 - :stub-columns: 0 - :widths: 3 1 16 - - * .. _`CEC-RX-STATUS-OK`: - - - ``CEC_RX_STATUS_OK`` - - 0x01 - - The message was received successfully. - * .. _`CEC-RX-STATUS-TIMEOUT`: - - - ``CEC_RX_STATUS_TIMEOUT`` - - 0x02 - - The reply to an earlier transmitted message timed out. - * .. _`CEC-RX-STATUS-FEATURE-ABORT`: - - - ``CEC_RX_STATUS_FEATURE_ABORT`` - - 0x04 - - The message was received successfully but the reply was - ``CEC_MSG_FEATURE_ABORT``. This status is only set if this message - was the reply to an earlier transmitted message. - * .. _`CEC-RX-STATUS-ABORTED`: - - - ``CEC_RX_STATUS_ABORTED`` - - 0x08 - - The wait for a reply to an earlier transmitted message was aborted - because the HDMI cable was disconnected, the adapter was unconfigured - or the :ref:`CEC_TRANSMIT ` that waited for a - reply was interrupted. - - - -Return Value -============ - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. - -The :ref:`ioctl CEC_RECEIVE ` can return the following -error codes: - -EAGAIN - No messages are in the receive queue, and the filehandle is in non-blocking mode. - -ETIMEDOUT - The ``timeout`` was reached while waiting for a message. - -ERESTARTSYS - The wait for a message was interrupted (e.g. by Ctrl-C). - -The :ref:`ioctl CEC_TRANSMIT ` can return the following -error codes: - -ENOTTY - The ``CEC_CAP_TRANSMIT`` capability wasn't set, so this ioctl is not supported. - -EPERM - The CEC adapter is not configured, i.e. :ref:`ioctl CEC_ADAP_S_LOG_ADDRS ` - has never been called, or ``CEC_MSG_FL_RAW`` was used from a process that - did not have the ``CAP_SYS_RAWIO`` capability. - -ENONET - The CEC adapter is not configured, i.e. :ref:`ioctl CEC_ADAP_S_LOG_ADDRS ` - was called, but the physical address is invalid so no logical address was claimed. - An exception is made in this case for transmits from initiator 0xf ('Unregistered') - to destination 0 ('TV'). In that case the transmit will proceed as usual. - -EBUSY - Another filehandle is in exclusive follower or initiator mode, or the filehandle - is in mode ``CEC_MODE_NO_INITIATOR``. This is also returned if the transmit - queue is full. - -EINVAL - The contents of struct :c:type:`cec_msg` is invalid. - -ERESTARTSYS - The wait for a successful transmit was interrupted (e.g. by Ctrl-C). diff --git a/Documentation/media/uapi/cec/cec-pin-error-inj.rst b/Documentation/media/uapi/cec/cec-pin-error-inj.rst deleted file mode 100644 index 725f8b1c9965..000000000000 --- a/Documentation/media/uapi/cec/cec-pin-error-inj.rst +++ /dev/null @@ -1,334 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -CEC Pin Framework Error Injection -================================= - -The CEC Pin Framework is a core CEC framework for CEC hardware that only -has low-level support for the CEC bus. Most hardware today will have -high-level CEC support where the hardware deals with driving the CEC bus, -but some older devices aren't that fancy. However, this framework also -allows you to connect the CEC pin to a GPIO on e.g. a Raspberry Pi and -you have now made a CEC adapter. - -What makes doing this so interesting is that since we have full control -over the bus it is easy to support error injection. This is ideal to -test how well CEC adapters can handle error conditions. - -Currently only the cec-gpio driver (when the CEC line is directly -connected to a pull-up GPIO line) and the AllWinner A10/A20 drm driver -support this framework. - -If ``CONFIG_CEC_PIN_ERROR_INJ`` is enabled, then error injection is available -through debugfs. Specifically, in ``/sys/kernel/debug/cec/cecX/`` there is -now an ``error-inj`` file. - -.. note:: - - The error injection commands are not a stable ABI and may change in the - future. - -With ``cat error-inj`` you can see both the possible commands and the current -error injection status:: - - $ cat /sys/kernel/debug/cec/cec0/error-inj - # Clear error injections: - # clear clear all rx and tx error injections - # rx-clear clear all rx error injections - # tx-clear clear all tx error injections - # clear clear all rx and tx error injections for - # rx-clear clear all rx error injections for - # tx-clear clear all tx error injections for - # - # RX error injection: - # [,] rx-nack NACK the message instead of sending an ACK - # [,] rx-low-drive force a low-drive condition at this bit position - # [,] rx-add-byte add a spurious byte to the received CEC message - # [,] rx-remove-byte remove the last byte from the received CEC message - # [,] rx-arb-lost generate a POLL message to trigger an arbitration lost - # - # TX error injection settings: - # tx-ignore-nack-until-eom ignore early NACKs until EOM - # tx-custom-low-usecs define the 'low' time for the custom pulse - # tx-custom-high-usecs define the 'high' time for the custom pulse - # tx-custom-pulse transmit the custom pulse once the bus is idle - # - # TX error injection: - # [,] tx-no-eom don't set the EOM bit - # [,] tx-early-eom set the EOM bit one byte too soon - # [,] tx-add-bytes append (1-255) spurious bytes to the message - # [,] tx-remove-byte drop the last byte from the message - # [,] tx-short-bit make this bit shorter than allowed - # [,] tx-long-bit make this bit longer than allowed - # [,] tx-custom-bit send the custom pulse instead of this bit - # [,] tx-short-start send a start pulse that's too short - # [,] tx-long-start send a start pulse that's too long - # [,] tx-custom-start send the custom pulse instead of the start pulse - # [,] tx-last-bit stop sending after this bit - # [,] tx-low-drive force a low-drive condition at this bit position - # - # CEC message opcode (0-255) or 'any' - # 'once' (default), 'always', 'toggle' or 'off' - # CEC message bit (0-159) - # 10 bits per 'byte': bits 0-7: data, bit 8: EOM, bit 9: ACK - # CEC poll message used to test arbitration lost (0x00-0xff, default 0x0f) - # microseconds (0-10000000, default 1000) - - clear - -You can write error injection commands to ``error-inj`` using -``echo 'cmd' >error-inj`` or ``cat cmd.txt >error-inj``. The ``cat error-inj`` -output contains the current error commands. You can save the output to a file -and use it as an input to ``error-inj`` later. - -Basic Syntax ------------- - -Leading spaces/tabs are ignored. If the next character is a ``#`` or the end -of the line was reached, then the whole line is ignored. Otherwise a command -is expected. - -The error injection commands fall in two main groups: those relating to -receiving CEC messages and those relating to transmitting CEC messages. In -addition, there are commands to clear existing error injection commands and -to create custom pulses on the CEC bus. - -Most error injection commands can be executed for specific CEC opcodes or for -all opcodes (``any``). Each command also has a 'mode' which can be ``off`` -(can be used to turn off an existing error injection command), ``once`` -(the default) which will trigger the error injection only once for the next -received or transmitted message, ``always`` to always trigger the error -injection and ``toggle`` to toggle the error injection on or off for every -transmit or receive. - -So '``any rx-nack``' will NACK the next received CEC message, -'``any,always rx-nack``' will NACK all received CEC messages and -'``0x82,toggle rx-nack``' will only NACK if an Active Source message was -received and do that only for every other received message. - -After an error was injected with mode ``once`` the error injection command -is cleared automatically, so ``once`` is a one-time deal. - -All combinations of ```` and error injection commands can co-exist. So -this is fine:: - - 0x9e tx-add-bytes 1 - 0x9e tx-early-eom - 0x9f tx-add-bytes 2 - any rx-nack - -All four error injection commands will be active simultaneously. - -However, if the same ```` and command combination is specified, -but with different arguments:: - - 0x9e tx-add-bytes 1 - 0x9e tx-add-bytes 2 - -Then the second will overwrite the first. - -Clear Error Injections ----------------------- - -``clear`` - Clear all error injections. - -``rx-clear`` - Clear all receive error injections - -``tx-clear`` - Clear all transmit error injections - -`` clear`` - Clear all error injections for the given opcode. - -`` rx-clear`` - Clear all receive error injections for the given opcode. - -`` tx-clear`` - Clear all transmit error injections for the given opcode. - -Receive Messages ----------------- - -``[,] rx-nack`` - NACK broadcast messages and messages directed to this CEC adapter. - Every byte of the message will be NACKed in case the transmitter - keeps transmitting after the first byte was NACKed. - -``[,] rx-low-drive `` - Force a Low Drive condition at this bit position. If specifies - a specific CEC opcode then the bit position must be at least 18, - otherwise the opcode hasn't been received yet. This tests if the - transmitter can handle the Low Drive condition correctly and reports - the error correctly. Note that a Low Drive in the first 4 bits can also - be interpreted as an Arbitration Lost condition by the transmitter. - This is implementation dependent. - -``[,] rx-add-byte`` - Add a spurious 0x55 byte to the received CEC message, provided - the message was 15 bytes long or less. This is useful to test - the high-level protocol since spurious bytes should be ignored. - -``[,] rx-remove-byte`` - Remove the last byte from the received CEC message, provided it - was at least 2 bytes long. This is useful to test the high-level - protocol since messages that are too short should be ignored. - -``[,] rx-arb-lost `` - Generate a POLL message to trigger an Arbitration Lost condition. - This command is only allowed for ```` values of ``next`` or ``all``. - As soon as a start bit has been received the CEC adapter will switch - to transmit mode and it will transmit a POLL message. By default this is - 0x0f, but it can also be specified explicitly via the ```` argument. - - This command can be used to test the Arbitration Lost condition in - the remote CEC transmitter. Arbitration happens when two CEC adapters - start sending a message at the same time. In that case the initiator - with the most leading zeroes wins and the other transmitter has to - stop transmitting ('Arbitration Lost'). This is very hard to test, - except by using this error injection command. - - This does not work if the remote CEC transmitter has logical address - 0 ('TV') since that will always win. - -Transmit Messages ------------------ - -``tx-ignore-nack-until-eom`` - This setting changes the behavior of transmitting CEC messages. Normally - as soon as the receiver NACKs a byte the transmit will stop, but the - specification also allows that the full message is transmitted and only - at the end will the transmitter look at the ACK bit. This is not - recommended behavior since there is no point in keeping the CEC bus busy - for longer than is strictly needed. Especially given how slow the bus is. - - This setting can be used to test how well a receiver deals with - transmitters that ignore NACKs until the very end of the message. - -``[,] tx-no-eom`` - Don't set the EOM bit. Normally the last byte of the message has the EOM - (End-Of-Message) bit set. With this command the transmit will just stop - without ever sending an EOM. This can be used to test how a receiver - handles this case. Normally receivers have a time-out after which - they will go back to the Idle state. - -``[,] tx-early-eom`` - Set the EOM bit one byte too soon. This obviously only works for messages - of two bytes or more. The EOM bit will be set for the second-to-last byte - and not for the final byte. The receiver should ignore the last byte in - this case. Since the resulting message is likely to be too short for this - same reason the whole message is typically ignored. The receiver should be - in Idle state after the last byte was transmitted. - -``[,] tx-add-bytes `` - Append ```` (1-255) spurious bytes to the message. The extra bytes - have the value of the byte position in the message. So if you transmit a - two byte message (e.g. a Get CEC Version message) and add 2 bytes, then - the full message received by the remote CEC adapter is - ``0x40 0x9f 0x02 0x03``. - - This command can be used to test buffer overflows in the receiver. E.g. - what does it do when it receives more than the maximum message size of 16 - bytes. - -``[,] tx-remove-byte`` - Drop the last byte from the message, provided the message is at least - two bytes long. The receiver should ignore messages that are too short. - -``[,] tx-short-bit `` - Make this bit period shorter than allowed. The bit position cannot be - an Ack bit. If specifies a specific CEC opcode then the bit position - must be at least 18, otherwise the opcode hasn't been received yet. - Normally the period of a data bit is between 2.05 and 2.75 milliseconds. - With this command the period of this bit is 1.8 milliseconds, this is - done by reducing the time the CEC bus is high. This bit period is less - than is allowed and the receiver should respond with a Low Drive - condition. - - This command is ignored for 0 bits in bit positions 0 to 3. This is - because the receiver also looks for an Arbitration Lost condition in - those first four bits and it is undefined what will happen if it - sees a too-short 0 bit. - -``[,] tx-long-bit `` - Make this bit period longer than is valid. The bit position cannot be - an Ack bit. If specifies a specific CEC opcode then the bit position - must be at least 18, otherwise the opcode hasn't been received yet. - Normally the period of a data bit is between 2.05 and 2.75 milliseconds. - With this command the period of this bit is 2.9 milliseconds, this is - done by increasing the time the CEC bus is high. - - Even though this bit period is longer than is valid it is undefined what - a receiver will do. It might just accept it, or it might time out and - return to Idle state. Unfortunately the CEC specification is silent about - this. - - This command is ignored for 0 bits in bit positions 0 to 3. This is - because the receiver also looks for an Arbitration Lost condition in - those first four bits and it is undefined what will happen if it - sees a too-long 0 bit. - -``[,] tx-short-start`` - Make this start bit period shorter than allowed. Normally the period of - a start bit is between 4.3 and 4.7 milliseconds. With this command the - period of the start bit is 4.1 milliseconds, this is done by reducing - the time the CEC bus is high. This start bit period is less than is - allowed and the receiver should return to Idle state when this is detected. - -``[,] tx-long-start`` - Make this start bit period longer than is valid. Normally the period of - a start bit is between 4.3 and 4.7 milliseconds. With this command the - period of the start bit is 5 milliseconds, this is done by increasing - the time the CEC bus is high. This start bit period is more than is - valid and the receiver should return to Idle state when this is detected. - - Even though this start bit period is longer than is valid it is undefined - what a receiver will do. It might just accept it, or it might time out and - return to Idle state. Unfortunately the CEC specification is silent about - this. - -``[,] tx-last-bit `` - Just stop transmitting after this bit. If specifies a specific CEC - opcode then the bit position must be at least 18, otherwise the opcode - hasn't been received yet. This command can be used to test how the receiver - reacts when a message just suddenly stops. It should time out and go back - to Idle state. - -``[,] tx-low-drive `` - Force a Low Drive condition at this bit position. If specifies a - specific CEC opcode then the bit position must be at least 18, otherwise - the opcode hasn't been received yet. This can be used to test how the - receiver handles Low Drive conditions. Note that if this happens at bit - positions 0-3 the receiver can interpret this as an Arbitration Lost - condition. This is implementation dependent. - -Custom Pulses -------------- - -``tx-custom-low-usecs `` - This defines the duration in microseconds that the custom pulse pulls - the CEC line low. The default is 1000 microseconds. - -``tx-custom-high-usecs `` - This defines the duration in microseconds that the custom pulse keeps the - CEC line high (unless another CEC adapter pulls it low in that time). - The default is 1000 microseconds. The total period of the custom pulse is - ``tx-custom-low-usecs + tx-custom-high-usecs``. - -``[,] tx-custom-bit `` - Send the custom bit instead of a regular data bit. The bit position cannot - be an Ack bit. If specifies a specific CEC opcode then the bit - position must be at least 18, otherwise the opcode hasn't been received yet. - -``[,] tx-custom-start`` - Send the custom bit instead of a regular start bit. - -``tx-custom-pulse`` - Transmit a single custom pulse as soon as the CEC bus is idle. diff --git a/Documentation/media/uapi/dvb/audio-bilingual-channel-select.rst b/Documentation/media/uapi/dvb/audio-bilingual-channel-select.rst deleted file mode 100644 index ee2ee74dafa3..000000000000 --- a/Documentation/media/uapi/dvb/audio-bilingual-channel-select.rst +++ /dev/null @@ -1,66 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _AUDIO_BILINGUAL_CHANNEL_SELECT: - -============================== -AUDIO_BILINGUAL_CHANNEL_SELECT -============================== - -Name ----- - -AUDIO_BILINGUAL_CHANNEL_SELECT - -.. attention:: This ioctl is deprecated - -Synopsis --------- - -.. c:function:: int ioctl(int fd, AUDIO_BILINGUAL_CHANNEL_SELECT, struct *audio_channel_select) - :name: AUDIO_BILINGUAL_CHANNEL_SELECT - - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - - - - int fd - - - File descriptor returned by a previous call to open(). - - - - - - audio_channel_select_t ch - - - Select the output format of the audio (mono left/right, stereo). - - -Description ------------ - -This ioctl is obsolete. Do not use in new drivers. It has been replaced -by the V4L2 ``V4L2_CID_MPEG_AUDIO_DEC_MULTILINGUAL_PLAYBACK`` control -for MPEG decoders controlled through V4L2. - -This ioctl call asks the Audio Device to select the requested channel -for bilingual streams if possible. - - -Return Value ------------- - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/dvb/audio-channel-select.rst b/Documentation/media/uapi/dvb/audio-channel-select.rst deleted file mode 100644 index ebb2f121c4c8..000000000000 --- a/Documentation/media/uapi/dvb/audio-channel-select.rst +++ /dev/null @@ -1,66 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _AUDIO_CHANNEL_SELECT: - -==================== -AUDIO_CHANNEL_SELECT -==================== - -Name ----- - -AUDIO_CHANNEL_SELECT - -.. attention:: This ioctl is deprecated - -Synopsis --------- - -.. c:function:: int ioctl(int fd, AUDIO_CHANNEL_SELECT, struct *audio_channel_select) - :name: AUDIO_CHANNEL_SELECT - - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - - - - - int fd - - - File descriptor returned by a previous call to open(). - - - - - - audio_channel_select_t ch - - - Select the output format of the audio (mono left/right, stereo). - - -Description ------------ - -This ioctl is for Digital TV devices only. To control a V4L2 decoder use the -V4L2 ``V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK`` control instead. - -This ioctl call asks the Audio Device to select the requested channel if -possible. - - -Return Value ------------- - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/dvb/audio-clear-buffer.rst b/Documentation/media/uapi/dvb/audio-clear-buffer.rst deleted file mode 100644 index c5b62cde18c8..000000000000 --- a/Documentation/media/uapi/dvb/audio-clear-buffer.rst +++ /dev/null @@ -1,55 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _AUDIO_CLEAR_BUFFER: - -================== -AUDIO_CLEAR_BUFFER -================== - -Name ----- - -AUDIO_CLEAR_BUFFER - -.. attention:: This ioctl is deprecated - -Synopsis --------- - -.. c:function:: int ioctl(int fd, AUDIO_CLEAR_BUFFER) - :name: AUDIO_CLEAR_BUFFER - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - - .. row 1 - - - int fd - - - File descriptor returned by a previous call to open(). - -Description ------------ - -This ioctl call asks the Audio Device to clear all software and hardware -buffers of the audio decoder device. - - -Return Value ------------- - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/dvb/audio-continue.rst b/Documentation/media/uapi/dvb/audio-continue.rst deleted file mode 100644 index 6bdc99e39e20..000000000000 --- a/Documentation/media/uapi/dvb/audio-continue.rst +++ /dev/null @@ -1,56 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _AUDIO_CONTINUE: - -============== -AUDIO_CONTINUE -============== - -Name ----- - -AUDIO_CONTINUE - -.. attention:: This ioctl is deprecated - -Synopsis --------- - -.. c:function:: int ioctl(int fd, AUDIO_CONTINUE) - :name: AUDIO_CONTINUE - - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - - .. row 1 - - - int fd - - - File descriptor returned by a previous call to open(). - -Description ------------ - -This ioctl restarts the decoding and playing process previously paused -with AUDIO_PAUSE command. - - -Return Value ------------- - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/dvb/audio-fclose.rst b/Documentation/media/uapi/dvb/audio-fclose.rst deleted file mode 100644 index 1e4ad7a0325d..000000000000 --- a/Documentation/media/uapi/dvb/audio-fclose.rst +++ /dev/null @@ -1,63 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _audio_fclose: - -======================== -Digital TV audio close() -======================== - -Name ----- - -Digital TV audio close() - -.. attention:: This ioctl is deprecated - -Synopsis --------- - -.. c:function:: int close(int fd) - :name: dvb-audio-close - - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - - .. row 1 - - - int fd - - - File descriptor returned by a previous call to open(). - - -Description ------------ - -This system call closes a previously opened audio device. - - -Return Value ------------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - - .. row 1 - - - ``EBADF`` - - - fd is not a valid open file descriptor. diff --git a/Documentation/media/uapi/dvb/audio-fopen.rst b/Documentation/media/uapi/dvb/audio-fopen.rst deleted file mode 100644 index 2cf4d83661f4..000000000000 --- a/Documentation/media/uapi/dvb/audio-fopen.rst +++ /dev/null @@ -1,115 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _audio_fopen: - -======================= -Digital TV audio open() -======================= - -Name ----- - -Digital TV audio open() - -.. attention:: This ioctl is deprecated - -Synopsis --------- - -.. c:function:: int open(const char *deviceName, int flags) - :name: dvb-audio-open - - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - - .. row 1 - - - const char \*deviceName - - - Name of specific audio device. - - - .. row 2 - - - int flags - - - A bit-wise OR of the following flags: - - - .. row 3 - - - - - O_RDONLY read-only access - - - .. row 4 - - - - - O_RDWR read/write access - - - .. row 5 - - - - - O_NONBLOCK open in non-blocking mode - - - .. row 6 - - - - - (blocking mode is the default) - - -Description ------------ - -This system call opens a named audio device (e.g. -/dev/dvb/adapter0/audio0) for subsequent use. When an open() call has -succeeded, the device will be ready for use. The significance of -blocking or non-blocking mode is described in the documentation for -functions where there is a difference. It does not affect the semantics -of the open() call itself. A device opened in blocking mode can later be -put into non-blocking mode (and vice versa) using the F_SETFL command -of the fcntl system call. This is a standard system call, documented in -the Linux manual page for fcntl. Only one user can open the Audio Device -in O_RDWR mode. All other attempts to open the device in this mode will -fail, and an error code will be returned. If the Audio Device is opened -in O_RDONLY mode, the only ioctl call that can be used is -AUDIO_GET_STATUS. All other call will return with an error code. - - -Return Value ------------- - -.. tabularcolumns:: |p{2.5cm}|p{15.0cm}| - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - - .. row 1 - - - ``ENODEV`` - - - Device driver not loaded/available. - - - .. row 2 - - - ``EBUSY`` - - - Device or resource busy. - - - .. row 3 - - - ``EINVAL`` - - - Invalid argument. diff --git a/Documentation/media/uapi/dvb/audio-fwrite.rst b/Documentation/media/uapi/dvb/audio-fwrite.rst deleted file mode 100644 index 6dc6bf6cbbc7..000000000000 --- a/Documentation/media/uapi/dvb/audio-fwrite.rst +++ /dev/null @@ -1,91 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _audio_fwrite: - -========================= -Digital TV audio write() -========================= - -Name ----- - -Digital TV audio write() - -.. attention:: This ioctl is deprecated - -Synopsis --------- - -.. c:function:: size_t write(int fd, const void *buf, size_t count) - :name: dvb-audio-write - - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - - .. row 1 - - - int fd - - - File descriptor returned by a previous call to open(). - - - .. row 2 - - - void \*buf - - - Pointer to the buffer containing the PES data. - - - .. row 3 - - - size_t count - - - Size of buf. - - -Description ------------ - -This system call can only be used if AUDIO_SOURCE_MEMORY is selected -in the ioctl call AUDIO_SELECT_SOURCE. The data provided shall be in -PES format. If O_NONBLOCK is not specified the function will block -until buffer space is available. The amount of data to be transferred is -implied by count. - - -Return Value ------------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - - .. row 1 - - - ``EPERM`` - - - Mode AUDIO_SOURCE_MEMORY not selected. - - - .. row 2 - - - ``ENOMEM`` - - - Attempted to write more data than the internal buffer can hold. - - - .. row 3 - - - ``EBADF`` - - - fd is not a valid open file descriptor. diff --git a/Documentation/media/uapi/dvb/audio-get-capabilities.rst b/Documentation/media/uapi/dvb/audio-get-capabilities.rst deleted file mode 100644 index 4f1ec47e8ac2..000000000000 --- a/Documentation/media/uapi/dvb/audio-get-capabilities.rst +++ /dev/null @@ -1,63 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _AUDIO_GET_CAPABILITIES: - -====================== -AUDIO_GET_CAPABILITIES -====================== - -Name ----- - -AUDIO_GET_CAPABILITIES - -.. attention:: This ioctl is deprecated - -Synopsis --------- - -.. c:function:: int ioctl(int fd, AUDIO_GET_CAPABILITIES, unsigned int *cap) - :name: AUDIO_GET_CAPABILITIES - - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - - - - - int fd - - - File descriptor returned by a previous call to open(). - - - - - - unsigned int \*cap - - - Returns a bit array of supported sound formats. - - -Description ------------ - -This ioctl call asks the Audio Device to tell us about the decoding -capabilities of the audio hardware. - - -Return Value ------------- - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/dvb/audio-get-status.rst b/Documentation/media/uapi/dvb/audio-get-status.rst deleted file mode 100644 index 30e4dd7fce6d..000000000000 --- a/Documentation/media/uapi/dvb/audio-get-status.rst +++ /dev/null @@ -1,63 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _AUDIO_GET_STATUS: - -================ -AUDIO_GET_STATUS -================ - -Name ----- - -AUDIO_GET_STATUS - -.. attention:: This ioctl is deprecated - -Synopsis --------- - -.. c:function:: int ioctl(int fd, AUDIO_GET_STATUS, struct audio_status *status) - :name: AUDIO_GET_STATUS - - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - - - - - int fd - - - File descriptor returned by a previous call to open(). - - - - - - struct audio_status \*status - - - Returns the current state of Audio Device. - - -Description ------------ - -This ioctl call asks the Audio Device to return the current state of the -Audio Device. - - -Return Value ------------- - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/dvb/audio-pause.rst b/Documentation/media/uapi/dvb/audio-pause.rst deleted file mode 100644 index 4567ecd9e0a3..000000000000 --- a/Documentation/media/uapi/dvb/audio-pause.rst +++ /dev/null @@ -1,57 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _AUDIO_PAUSE: - -=========== -AUDIO_PAUSE -=========== - -Name ----- - -AUDIO_PAUSE - -.. attention:: This ioctl is deprecated - -Synopsis --------- - -.. c:function:: int ioctl(int fd, AUDIO_PAUSE) - :name: AUDIO_PAUSE - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - - .. row 1 - - - int fd - - - File descriptor returned by a previous call to open(). - - -Description ------------ - -This ioctl call suspends the audio stream being played. Decoding and -playing are paused. It is then possible to restart again decoding and -playing process of the audio stream using AUDIO_CONTINUE command. - - -Return Value ------------- - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/dvb/audio-play.rst b/Documentation/media/uapi/dvb/audio-play.rst deleted file mode 100644 index 17acd4c411b8..000000000000 --- a/Documentation/media/uapi/dvb/audio-play.rst +++ /dev/null @@ -1,56 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _AUDIO_PLAY: - -========== -AUDIO_PLAY -========== - -Name ----- - -AUDIO_PLAY - -.. attention:: This ioctl is deprecated - -Synopsis --------- - -.. c:function:: int ioctl(int fd, AUDIO_PLAY) - :name: AUDIO_PLAY - - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - - .. row 1 - - - int fd - - - File descriptor returned by a previous call to open(). - -Description ------------ - -This ioctl call asks the Audio Device to start playing an audio stream -from the selected source. - - -Return Value ------------- - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/dvb/audio-select-source.rst b/Documentation/media/uapi/dvb/audio-select-source.rst deleted file mode 100644 index c5ed6243b11c..000000000000 --- a/Documentation/media/uapi/dvb/audio-select-source.rst +++ /dev/null @@ -1,65 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _AUDIO_SELECT_SOURCE: - -=================== -AUDIO_SELECT_SOURCE -=================== - -Name ----- - -AUDIO_SELECT_SOURCE - -.. attention:: This ioctl is deprecated - -Synopsis --------- - -.. c:function:: int ioctl(int fd, AUDIO_SELECT_SOURCE, struct audio_stream_source *source) - :name: AUDIO_SELECT_SOURCE - - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - - - - - int fd - - - File descriptor returned by a previous call to open(). - - - - - - audio_stream_source_t source - - - Indicates the source that shall be used for the Audio stream. - - -Description ------------ - -This ioctl call informs the audio device which source shall be used for -the input data. The possible sources are demux or memory. If -AUDIO_SOURCE_MEMORY is selected, the data is fed to the Audio Device -through the write command. - - -Return Value ------------- - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/dvb/audio-set-av-sync.rst b/Documentation/media/uapi/dvb/audio-set-av-sync.rst deleted file mode 100644 index c116d105fdea..000000000000 --- a/Documentation/media/uapi/dvb/audio-set-av-sync.rst +++ /dev/null @@ -1,67 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _AUDIO_SET_AV_SYNC: - -================= -AUDIO_SET_AV_SYNC -================= - -Name ----- - -AUDIO_SET_AV_SYNC - -.. attention:: This ioctl is deprecated - -Synopsis --------- - -.. c:function:: int ioctl(int fd, AUDIO_SET_AV_SYNC, boolean state) - :name: AUDIO_SET_AV_SYNC - - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - - - - - int fd - - - File descriptor returned by a previous call to open(). - - - - - - boolean state - - - Tells the Digital TV subsystem if A/V synchronization shall be ON or OFF. - - TRUE: AV-sync ON - - FALSE: AV-sync OFF - - -Description ------------ - -This ioctl call asks the Audio Device to turn ON or OFF A/V -synchronization. - - -Return Value ------------- - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/dvb/audio-set-bypass-mode.rst b/Documentation/media/uapi/dvb/audio-set-bypass-mode.rst deleted file mode 100644 index d68f05d48d12..000000000000 --- a/Documentation/media/uapi/dvb/audio-set-bypass-mode.rst +++ /dev/null @@ -1,70 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _AUDIO_SET_BYPASS_MODE: - -===================== -AUDIO_SET_BYPASS_MODE -===================== - -Name ----- - -AUDIO_SET_BYPASS_MODE - -.. attention:: This ioctl is deprecated - -Synopsis --------- - -.. c:function:: int ioctl(int fd, AUDIO_SET_BYPASS_MODE, boolean mode) - :name: AUDIO_SET_BYPASS_MODE - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - - - - - int fd - - - File descriptor returned by a previous call to open(). - - - - - - boolean mode - - - Enables or disables the decoding of the current Audio stream in - the Digital TV subsystem. - - TRUE: Bypass is disabled - - FALSE: Bypass is enabled - - -Description ------------ - -This ioctl call asks the Audio Device to bypass the Audio decoder and -forward the stream without decoding. This mode shall be used if streams -that can’t be handled by the Digital TV system shall be decoded. Dolby -DigitalTM streams are automatically forwarded by the Digital TV subsystem if -the hardware can handle it. - - -Return Value ------------- - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/dvb/audio-set-id.rst b/Documentation/media/uapi/dvb/audio-set-id.rst deleted file mode 100644 index aeb6ace6cd1e..000000000000 --- a/Documentation/media/uapi/dvb/audio-set-id.rst +++ /dev/null @@ -1,67 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _AUDIO_SET_ID: - -============ -AUDIO_SET_ID -============ - -Name ----- - -AUDIO_SET_ID - -.. attention:: This ioctl is deprecated - -Synopsis --------- - -.. c:function:: int ioctl(int fd, AUDIO_SET_ID, int id) - :name: AUDIO_SET_ID - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - - - - - int fd - - - File descriptor returned by a previous call to open(). - - - - - - int id - - - audio sub-stream id - - -Description ------------ - -This ioctl selects which sub-stream is to be decoded if a program or -system stream is sent to the video device. If no audio stream type is -set the id has to be in [0xC0,0xDF] for MPEG sound, in [0x80,0x87] for -AC3 and in [0xA0,0xA7] for LPCM. More specifications may follow for -other stream types. If the stream type is set the id just specifies the -substream id of the audio stream and only the first 5 bits are -recognized. - - -Return Value ------------- - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/dvb/audio-set-mixer.rst b/Documentation/media/uapi/dvb/audio-set-mixer.rst deleted file mode 100644 index 60781aa88202..000000000000 --- a/Documentation/media/uapi/dvb/audio-set-mixer.rst +++ /dev/null @@ -1,61 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _AUDIO_SET_MIXER: - -=============== -AUDIO_SET_MIXER -=============== - -Name ----- - -AUDIO_SET_MIXER - -.. attention:: This ioctl is deprecated - -Synopsis --------- - -.. c:function:: int ioctl(int fd, AUDIO_SET_MIXER, struct audio_mixer *mix) - :name: AUDIO_SET_MIXER - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - - - - - int fd - - - File descriptor returned by a previous call to open(). - - - - - - audio_mixer_t \*mix - - - mixer settings. - - -Description ------------ - -This ioctl lets you adjust the mixer settings of the audio decoder. - - -Return Value ------------- - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/dvb/audio-set-mute.rst b/Documentation/media/uapi/dvb/audio-set-mute.rst deleted file mode 100644 index 4449f225e48c..000000000000 --- a/Documentation/media/uapi/dvb/audio-set-mute.rst +++ /dev/null @@ -1,71 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _AUDIO_SET_MUTE: - -============== -AUDIO_SET_MUTE -============== - -Name ----- - -AUDIO_SET_MUTE - -.. attention:: This ioctl is deprecated - -Synopsis --------- - -.. c:function:: int ioctl(int fd, AUDIO_SET_MUTE, boolean state) - :name: AUDIO_SET_MUTE - - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - - - - - int fd - - - File descriptor returned by a previous call to open(). - - - - - - boolean state - - - Indicates if audio device shall mute or not. - - TRUE: Audio Mute - - FALSE: Audio Un-mute - - -Description ------------ - -This ioctl is for Digital TV devices only. To control a V4L2 decoder use the -V4L2 :ref:`VIDIOC_DECODER_CMD` with the -``V4L2_DEC_CMD_START_MUTE_AUDIO`` flag instead. - -This ioctl call asks the audio device to mute the stream that is -currently being played. - - -Return Value ------------- - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/dvb/audio-set-streamtype.rst b/Documentation/media/uapi/dvb/audio-set-streamtype.rst deleted file mode 100644 index d20c34fc7128..000000000000 --- a/Documentation/media/uapi/dvb/audio-set-streamtype.rst +++ /dev/null @@ -1,77 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _AUDIO_SET_STREAMTYPE: - -==================== -AUDIO_SET_STREAMTYPE -==================== - -Name ----- - -AUDIO_SET_STREAMTYPE - -.. attention:: This ioctl is deprecated - -Synopsis --------- - -.. c:function:: int ioctl(fd, AUDIO_SET_STREAMTYPE, int type) - :name: AUDIO_SET_STREAMTYPE - - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - - - - - int fd - - - File descriptor returned by a previous call to open(). - - - - - - int type - - - stream type - - -Description ------------ - -This ioctl tells the driver which kind of audio stream to expect. This -is useful if the stream offers several audio sub-streams like LPCM and -AC3. - - -Return Value ------------- - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. - - - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - - .. row 1 - - - ``EINVAL`` - - - type is not a valid or supported stream type. diff --git a/Documentation/media/uapi/dvb/audio-stop.rst b/Documentation/media/uapi/dvb/audio-stop.rst deleted file mode 100644 index 1bba2e50c364..000000000000 --- a/Documentation/media/uapi/dvb/audio-stop.rst +++ /dev/null @@ -1,56 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _AUDIO_STOP: - -========== -AUDIO_STOP -========== - -Name ----- - -AUDIO_STOP - -.. attention:: This ioctl is deprecated - -Synopsis --------- - -.. c:function:: int ioctl(int fd, AUDIO_STOP) - :name: AUDIO_STOP - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - - .. row 1 - - - int fd - - - File descriptor returned by a previous call to open(). - - -Description ------------ - -This ioctl call asks the Audio Device to stop playing the current -stream. - - -Return Value ------------- - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/dvb/audio.rst b/Documentation/media/uapi/dvb/audio.rst deleted file mode 100644 index ebc18fca76a4..000000000000 --- a/Documentation/media/uapi/dvb/audio.rst +++ /dev/null @@ -1,34 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _dvb_audio: - -####################### -Digital TV Audio Device -####################### - -The Digital TV audio device controls the MPEG2 audio decoder of the Digital -TV hardware. It can be accessed through ``/dev/dvb/adapter?/audio?``. Data -types and and ioctl definitions can be accessed by including -``linux/dvb/audio.h`` in your application. - -Please note that some Digital TV cards don’t have their own MPEG decoder, which -results in the omission of the audio and video device. - -These ioctls were also used by V4L2 to control MPEG decoders implemented -in V4L2. The use of these ioctls for that purpose has been made obsolete -and proper V4L2 ioctls or controls have been created to replace that -functionality. - - -.. toctree:: - :maxdepth: 1 - - audio_data_types - audio_function_calls diff --git a/Documentation/media/uapi/dvb/audio_data_types.rst b/Documentation/media/uapi/dvb/audio_data_types.rst deleted file mode 100644 index 5b032fe13b9d..000000000000 --- a/Documentation/media/uapi/dvb/audio_data_types.rst +++ /dev/null @@ -1,123 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _audio_data_types: - -**************** -Audio Data Types -**************** - -This section describes the structures, data types and defines used when -talking to the audio device. - -.. c:type:: audio_stream_source - -The audio stream source is set through the AUDIO_SELECT_SOURCE call -and can take the following values, depending on whether we are replaying -from an internal (demux) or external (user write) source. - - -.. code-block:: c - - typedef enum { - AUDIO_SOURCE_DEMUX, - AUDIO_SOURCE_MEMORY - } audio_stream_source_t; - -AUDIO_SOURCE_DEMUX selects the demultiplexer (fed either by the -frontend or the DVR device) as the source of the video stream. If -AUDIO_SOURCE_MEMORY is selected the stream comes from the application -through the ``write()`` system call. - - -.. c:type:: audio_play_state - -The following values can be returned by the AUDIO_GET_STATUS call -representing the state of audio playback. - - -.. code-block:: c - - typedef enum { - AUDIO_STOPPED, - AUDIO_PLAYING, - AUDIO_PAUSED - } audio_play_state_t; - - -.. c:type:: audio_channel_select - -The audio channel selected via AUDIO_CHANNEL_SELECT is determined by -the following values. - - -.. code-block:: c - - typedef enum { - AUDIO_STEREO, - AUDIO_MONO_LEFT, - AUDIO_MONO_RIGHT, - AUDIO_MONO, - AUDIO_STEREO_SWAPPED - } audio_channel_select_t; - - -.. c:type:: audio_status - -The AUDIO_GET_STATUS call returns the following structure informing -about various states of the playback operation. - - -.. code-block:: c - - typedef struct audio_status { - boolean AV_sync_state; - boolean mute_state; - audio_play_state_t play_state; - audio_stream_source_t stream_source; - audio_channel_select_t channel_select; - boolean bypass_mode; - audio_mixer_t mixer_state; - } audio_status_t; - - -.. c:type:: audio_mixer - -The following structure is used by the AUDIO_SET_MIXER call to set the -audio volume. - - -.. code-block:: c - - typedef struct audio_mixer { - unsigned int volume_left; - unsigned int volume_right; - } audio_mixer_t; - - -.. _audio_encodings: - -audio encodings -=============== - -A call to AUDIO_GET_CAPABILITIES returns an unsigned integer with the -following bits set according to the hardwares capabilities. - - -.. code-block:: c - - #define AUDIO_CAP_DTS 1 - #define AUDIO_CAP_LPCM 2 - #define AUDIO_CAP_MP1 4 - #define AUDIO_CAP_MP2 8 - #define AUDIO_CAP_MP3 16 - #define AUDIO_CAP_AAC 32 - #define AUDIO_CAP_OGG 64 - #define AUDIO_CAP_SDDS 128 - #define AUDIO_CAP_AC3 256 diff --git a/Documentation/media/uapi/dvb/audio_function_calls.rst b/Documentation/media/uapi/dvb/audio_function_calls.rst deleted file mode 100644 index 5478e78b085e..000000000000 --- a/Documentation/media/uapi/dvb/audio_function_calls.rst +++ /dev/null @@ -1,37 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _audio_function_calls: - -******************** -Audio Function Calls -******************** - -.. toctree:: - :maxdepth: 1 - - audio-fopen - audio-fclose - audio-fwrite - audio-stop - audio-play - audio-pause - audio-continue - audio-select-source - audio-set-mute - audio-set-av-sync - audio-set-bypass-mode - audio-channel-select - audio-bilingual-channel-select - audio-get-status - audio-get-capabilities - audio-clear-buffer - audio-set-id - audio-set-mixer - audio-set-streamtype diff --git a/Documentation/media/uapi/dvb/ca-fclose.rst b/Documentation/media/uapi/dvb/ca-fclose.rst deleted file mode 100644 index e273444ccc67..000000000000 --- a/Documentation/media/uapi/dvb/ca-fclose.rst +++ /dev/null @@ -1,50 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _ca_fclose: - -===================== -Digital TV CA close() -===================== - -Name ----- - -Digital TV CA close() - - -Synopsis --------- - -.. c:function:: int close(int fd) - :name: dvb-ca-close - - -Arguments ---------- - -``fd`` - File descriptor returned by a previous call to :c:func:`open() `. - -Description ------------ - -This system call closes a previously opened CA device. - - -Return Value ------------- - -On success 0 is returned. - -On error -1 is returned, and the ``errno`` variable is set -appropriately. - -Generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/dvb/ca-fopen.rst b/Documentation/media/uapi/dvb/ca-fopen.rst deleted file mode 100644 index e11ebeae5693..000000000000 --- a/Documentation/media/uapi/dvb/ca-fopen.rst +++ /dev/null @@ -1,84 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _ca_fopen: - -==================== -Digital TV CA open() -==================== - -Name ----- - -Digital TV CA open() - - -Synopsis --------- - -.. c:function:: int open(const char *name, int flags) - :name: dvb-ca-open - - -Arguments ---------- - -``name`` - Name of specific Digital TV CA device. - -``flags`` - A bit-wise OR of the following flags: - -.. tabularcolumns:: |p{2.5cm}|p{15.0cm}| - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - :widths: 1 16 - - - - ``O_RDONLY`` - - read-only access - - - - ``O_RDWR`` - - read/write access - - - - ``O_NONBLOCK`` - - open in non-blocking mode - (blocking mode is the default) - - -Description ------------ - -This system call opens a named ca device (e.g. ``/dev/dvb/adapter?/ca?``) -for subsequent use. - -When an ``open()`` call has succeeded, the device will be ready for use. The -significance of blocking or non-blocking mode is described in the -documentation for functions where there is a difference. It does not -affect the semantics of the ``open()`` call itself. A device opened in -blocking mode can later be put into non-blocking mode (and vice versa) -using the ``F_SETFL`` command of the ``fcntl`` system call. This is a -standard system call, documented in the Linux manual page for fcntl. -Only one user can open the CA Device in ``O_RDWR`` mode. All other -attempts to open the device in this mode will fail, and an error code -will be returned. - - -Return Value ------------- - - -On success 0 is returned. - -On error -1 is returned, and the ``errno`` variable is set -appropriately. - -Generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/dvb/ca-get-cap.rst b/Documentation/media/uapi/dvb/ca-get-cap.rst deleted file mode 100644 index 9e4fb5186373..000000000000 --- a/Documentation/media/uapi/dvb/ca-get-cap.rst +++ /dev/null @@ -1,53 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _CA_GET_CAP: - -========== -CA_GET_CAP -========== - -Name ----- - -CA_GET_CAP - - -Synopsis --------- - -.. c:function:: int ioctl(fd, CA_GET_CAP, struct ca_caps *caps) - :name: CA_GET_CAP - - -Arguments ---------- - -``fd`` - File descriptor returned by a previous call to :c:func:`open() `. - -``caps`` - Pointer to struct :c:type:`ca_caps`. - -Description ------------ - -Queries the Kernel for information about the available CA and descrambler -slots, and their types. - -Return Value ------------- - -On success 0 is returned and :c:type:`ca_caps` is filled. - -On error, -1 is returned and the ``errno`` variable is set -appropriately. - -The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/dvb/ca-get-descr-info.rst b/Documentation/media/uapi/dvb/ca-get-descr-info.rst deleted file mode 100644 index 80ef43a339df..000000000000 --- a/Documentation/media/uapi/dvb/ca-get-descr-info.rst +++ /dev/null @@ -1,49 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _CA_GET_DESCR_INFO: - -================= -CA_GET_DESCR_INFO -================= - -Name ----- - -CA_GET_DESCR_INFO - - -Synopsis --------- - -.. c:function:: int ioctl(fd, CA_GET_DESCR_INFO, struct ca_descr_info *desc) - :name: CA_GET_DESCR_INFO - -Arguments ---------- - -``fd`` - File descriptor returned by a previous call to :c:func:`open() `. - -``desc`` - Pointer to struct :c:type:`ca_descr_info`. - -Description ------------ - -Returns information about all descrambler slots. - -Return Value ------------- - -On success 0 is returned, and :c:type:`ca_descr_info` is filled. - -On error -1 is returned, and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/dvb/ca-get-msg.rst b/Documentation/media/uapi/dvb/ca-get-msg.rst deleted file mode 100644 index bcb7955a0ddc..000000000000 --- a/Documentation/media/uapi/dvb/ca-get-msg.rst +++ /dev/null @@ -1,59 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _CA_GET_MSG: - -========== -CA_GET_MSG -========== - -Name ----- - -CA_GET_MSG - - -Synopsis --------- - -.. c:function:: int ioctl(fd, CA_GET_MSG, struct ca_msg *msg) - :name: CA_GET_MSG - - -Arguments ---------- - -``fd`` - File descriptor returned by a previous call to :c:func:`open() `. - -``msg`` - Pointer to struct :c:type:`ca_msg`. - -Description ------------ - -Receives a message via a CI CA module. - -.. note:: - - Please notice that, on most drivers, this is done by reading from - the /dev/adapter?/ca? device node. - - -Return Value ------------- - - -On success 0 is returned. - -On error -1 is returned, and the ``errno`` variable is set -appropriately. - -Generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/dvb/ca-get-slot-info.rst b/Documentation/media/uapi/dvb/ca-get-slot-info.rst deleted file mode 100644 index 1ea5c497f2ea..000000000000 --- a/Documentation/media/uapi/dvb/ca-get-slot-info.rst +++ /dev/null @@ -1,64 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _CA_GET_SLOT_INFO: - -================ -CA_GET_SLOT_INFO -================ - -Name ----- - -CA_GET_SLOT_INFO - - -Synopsis --------- - -.. c:function:: int ioctl(fd, CA_GET_SLOT_INFO, struct ca_slot_info *info) - :name: CA_GET_SLOT_INFO - - -Arguments ---------- - -``fd`` - File descriptor returned by a previous call to :c:func:`open() `. - -``info`` - Pointer to struct :c:type:`ca_slot_info`. - -Description ------------ - -Returns information about a CA slot identified by -:c:type:`ca_slot_info`.slot_num. - - -Return Value ------------- - -On success 0 is returned, and :c:type:`ca_slot_info` is filled. - -On error -1 is returned, and the ``errno`` variable is set -appropriately. - -.. tabularcolumns:: |p{2.5cm}|p{15.0cm}| - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - :widths: 1 16 - - - - ``ENODEV`` - - the slot is not available. - -The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/dvb/ca-reset.rst b/Documentation/media/uapi/dvb/ca-reset.rst deleted file mode 100644 index 29fda19984be..000000000000 --- a/Documentation/media/uapi/dvb/ca-reset.rst +++ /dev/null @@ -1,51 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _CA_RESET: - -======== -CA_RESET -======== - -Name ----- - -CA_RESET - - -Synopsis --------- - -.. c:function:: int ioctl(fd, CA_RESET) - :name: CA_RESET - - -Arguments ---------- - -``fd`` - File descriptor returned by a previous call to :c:func:`open() `. - -Description ------------ - -Puts the Conditional Access hardware on its initial state. It should -be called before start using the CA hardware. - - -Return Value ------------- - -On success 0 is returned. - -On error -1 is returned, and the ``errno`` variable is set -appropriately. - -Generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/dvb/ca-send-msg.rst b/Documentation/media/uapi/dvb/ca-send-msg.rst deleted file mode 100644 index 5a3c4e8120c4..000000000000 --- a/Documentation/media/uapi/dvb/ca-send-msg.rst +++ /dev/null @@ -1,58 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _CA_SEND_MSG: - -=========== -CA_SEND_MSG -=========== - -Name ----- - -CA_SEND_MSG - - -Synopsis --------- - -.. c:function:: int ioctl(fd, CA_SEND_MSG, struct ca_msg *msg) - :name: CA_SEND_MSG - - -Arguments ---------- - -``fd`` - File descriptor returned by a previous call to :c:func:`open() `. - -``msg`` - Pointer to struct :c:type:`ca_msg`. - - -Description ------------ - -Sends a message via a CI CA module. - -.. note:: - - Please notice that, on most drivers, this is done by writing - to the /dev/adapter?/ca? device node. - -Return Value ------------- - -On success 0 is returned. - -On error -1 is returned, and the ``errno`` variable is set -appropriately. - -Generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/dvb/ca-set-descr.rst b/Documentation/media/uapi/dvb/ca-set-descr.rst deleted file mode 100644 index d36464ba2317..000000000000 --- a/Documentation/media/uapi/dvb/ca-set-descr.rst +++ /dev/null @@ -1,53 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _CA_SET_DESCR: - -============ -CA_SET_DESCR -============ - -Name ----- - -CA_SET_DESCR - - -Synopsis --------- - -.. c:function:: int ioctl(fd, CA_SET_DESCR, struct ca_descr *desc) - :name: CA_SET_DESCR - - -Arguments ---------- - -``fd`` - File descriptor returned by a previous call to :c:func:`open() `. - -``msg`` - Pointer to struct :c:type:`ca_descr`. - -Description ------------ - -CA_SET_DESCR is used for feeding descrambler CA slots with descrambling -keys (referred as control words). - -Return Value ------------- - -On success 0 is returned. - -On error -1 is returned, and the ``errno`` variable is set -appropriately. - -Generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/dvb/ca.rst b/Documentation/media/uapi/dvb/ca.rst deleted file mode 100644 index c6ee624b1234..000000000000 --- a/Documentation/media/uapi/dvb/ca.rst +++ /dev/null @@ -1,32 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _dvb_ca: - -#################### -Digital TV CA Device -#################### - -The Digital TV CA device controls the conditional access hardware. It -can be accessed through ``/dev/dvb/adapter?/ca?``. Data types and and ioctl -definitions can be accessed by including ``linux/dvb/ca.h`` in your -application. - -.. note:: - - There are three ioctls at this API that aren't documented: - :ref:`CA_GET_MSG`, :ref:`CA_SEND_MSG` and :ref:`CA_SET_DESCR`. - Documentation for them are welcome. - -.. toctree:: - :maxdepth: 1 - - ca_data_types - ca_function_calls - ca_high_level diff --git a/Documentation/media/uapi/dvb/ca_data_types.rst b/Documentation/media/uapi/dvb/ca_data_types.rst deleted file mode 100644 index 834c8ab4c300..000000000000 --- a/Documentation/media/uapi/dvb/ca_data_types.rst +++ /dev/null @@ -1,16 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _ca_data_types: - -************* -CA Data Types -************* - -.. kernel-doc:: include/uapi/linux/dvb/ca.h diff --git a/Documentation/media/uapi/dvb/ca_function_calls.rst b/Documentation/media/uapi/dvb/ca_function_calls.rst deleted file mode 100644 index 6985bebd0661..000000000000 --- a/Documentation/media/uapi/dvb/ca_function_calls.rst +++ /dev/null @@ -1,27 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _ca_function_calls: - -***************** -CA Function Calls -***************** - -.. toctree:: - :maxdepth: 1 - - ca-fopen - ca-fclose - ca-reset - ca-get-cap - ca-get-slot-info - ca-get-descr-info - ca-get-msg - ca-send-msg - ca-set-descr diff --git a/Documentation/media/uapi/dvb/ca_high_level.rst b/Documentation/media/uapi/dvb/ca_high_level.rst deleted file mode 100644 index a73f3691c31f..000000000000 --- a/Documentation/media/uapi/dvb/ca_high_level.rst +++ /dev/null @@ -1,157 +0,0 @@ -.. SPDX-License-Identifier: GPL-2.0 - -The High level CI API -===================== - -.. note:: - - This documentation is outdated. - -This document describes the high level CI API as in accordance to the -Linux DVB API. - - -With the High Level CI approach any new card with almost any random -architecture can be implemented with this style, the definitions -inside the switch statement can be easily adapted for any card, thereby -eliminating the need for any additional ioctls. - -The disadvantage is that the driver/hardware has to manage the rest. For -the application programmer it would be as simple as sending/receiving an -array to/from the CI ioctls as defined in the Linux DVB API. No changes -have been made in the API to accommodate this feature. - - -Why the need for another CI interface? -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -This is one of the most commonly asked question. Well a nice question. -Strictly speaking this is not a new interface. - -The CI interface is defined in the DVB API in ca.h as: - -.. code-block:: c - - typedef struct ca_slot_info { - int num; /* slot number */ - - int type; /* CA interface this slot supports */ - #define CA_CI 1 /* CI high level interface */ - #define CA_CI_LINK 2 /* CI link layer level interface */ - #define CA_CI_PHYS 4 /* CI physical layer level interface */ - #define CA_DESCR 8 /* built-in descrambler */ - #define CA_SC 128 /* simple smart card interface */ - - unsigned int flags; - #define CA_CI_MODULE_PRESENT 1 /* module (or card) inserted */ - #define CA_CI_MODULE_READY 2 - } ca_slot_info_t; - -This CI interface follows the CI high level interface, which is not -implemented by most applications. Hence this area is revisited. - -This CI interface is quite different in the case that it tries to -accommodate all other CI based devices, that fall into the other categories. - -This means that this CI interface handles the EN50221 style tags in the -Application layer only and no session management is taken care of by the -application. The driver/hardware will take care of all that. - -This interface is purely an EN50221 interface exchanging APDU's. This -means that no session management, link layer or a transport layer do -exist in this case in the application to driver communication. It is -as simple as that. The driver/hardware has to take care of that. - -With this High Level CI interface, the interface can be defined with the -regular ioctls. - -All these ioctls are also valid for the High level CI interface - -#define CA_RESET _IO('o', 128) -#define CA_GET_CAP _IOR('o', 129, ca_caps_t) -#define CA_GET_SLOT_INFO _IOR('o', 130, ca_slot_info_t) -#define CA_GET_DESCR_INFO _IOR('o', 131, ca_descr_info_t) -#define CA_GET_MSG _IOR('o', 132, ca_msg_t) -#define CA_SEND_MSG _IOW('o', 133, ca_msg_t) -#define CA_SET_DESCR _IOW('o', 134, ca_descr_t) - - -On querying the device, the device yields information thus: - -.. code-block:: none - - CA_GET_SLOT_INFO - ---------------------------- - Command = [info] - APP: Number=[1] - APP: Type=[1] - APP: flags=[1] - APP: CI High level interface - APP: CA/CI Module Present - - CA_GET_CAP - ---------------------------- - Command = [caps] - APP: Slots=[1] - APP: Type=[1] - APP: Descrambler keys=[16] - APP: Type=[1] - - CA_SEND_MSG - ---------------------------- - Descriptors(Program Level)=[ 09 06 06 04 05 50 ff f1] - Found CA descriptor @ program level - - (20) ES type=[2] ES pid=[201] ES length =[0 (0x0)] - (25) ES type=[4] ES pid=[301] ES length =[0 (0x0)] - ca_message length is 25 (0x19) bytes - EN50221 CA MSG=[ 9f 80 32 19 03 01 2d d1 f0 08 01 09 06 06 04 05 50 ff f1 02 e0 c9 00 00 04 e1 2d 00 00] - - -Not all ioctl's are implemented in the driver from the API, the other -features of the hardware that cannot be implemented by the API are achieved -using the CA_GET_MSG and CA_SEND_MSG ioctls. An EN50221 style wrapper is -used to exchange the data to maintain compatibility with other hardware. - -.. code-block:: c - - /* a message to/from a CI-CAM */ - typedef struct ca_msg { - unsigned int index; - unsigned int type; - unsigned int length; - unsigned char msg[256]; - } ca_msg_t; - - -The flow of data can be described thus, - -.. code-block:: none - - App (User) - ----- - parse - | - | - v - en50221 APDU (package) - -------------------------------------- - | | | High Level CI driver - | | | - | v | - | en50221 APDU (unpackage) | - | | | - | | | - | v | - | sanity checks | - | | | - | | | - | v | - | do (H/W dep) | - -------------------------------------- - | Hardware - | - v - -The High Level CI interface uses the EN50221 DVB standard, following a -standard ensures futureproofness. diff --git a/Documentation/media/uapi/dvb/demux.rst b/Documentation/media/uapi/dvb/demux.rst deleted file mode 100644 index d8c0ff4015fe..000000000000 --- a/Documentation/media/uapi/dvb/demux.rst +++ /dev/null @@ -1,30 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _dvb_demux: - -####################### -Digital TV Demux Device -####################### - -The Digital TV demux device controls the MPEG-TS filters for the -digital TV. If the driver and hardware supports, those filters are -implemented at the hardware. Otherwise, the Kernel provides a software -emulation. - -It can be accessed through ``/dev/adapter?/demux?``. Data types and and -ioctl definitions can be accessed by including ``linux/dvb/dmx.h`` in -your application. - - -.. toctree:: - :maxdepth: 1 - - dmx_types - dmx_fcalls diff --git a/Documentation/media/uapi/dvb/dmx-add-pid.rst b/Documentation/media/uapi/dvb/dmx-add-pid.rst deleted file mode 100644 index f483268e4ede..000000000000 --- a/Documentation/media/uapi/dvb/dmx-add-pid.rst +++ /dev/null @@ -1,56 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _DMX_ADD_PID: - -=========== -DMX_ADD_PID -=========== - -Name ----- - -DMX_ADD_PID - - -Synopsis --------- - -.. c:function:: int ioctl(fd, DMX_ADD_PID, __u16 *pid) - :name: DMX_ADD_PID - - -Arguments ---------- - -``fd`` - File descriptor returned by :c:func:`open() `. - -``pid`` - PID number to be filtered. - - -Description ------------ - -This ioctl call allows to add multiple PIDs to a transport stream filter -previously set up with :ref:`DMX_SET_PES_FILTER` and output equal to -:c:type:`DMX_OUT_TSDEMUX_TAP `. - - -Return Value ------------- - -On success 0 is returned. - -On error -1 is returned, and the ``errno`` variable is set -appropriately. - -Generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/dvb/dmx-expbuf.rst b/Documentation/media/uapi/dvb/dmx-expbuf.rst deleted file mode 100644 index d7f0658f3db3..000000000000 --- a/Documentation/media/uapi/dvb/dmx-expbuf.rst +++ /dev/null @@ -1,97 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _DMX_EXPBUF: - -**************** -ioctl DMX_EXPBUF -**************** - -Name -==== - -DMX_EXPBUF - Export a buffer as a DMABUF file descriptor. - -.. warning:: this API is still experimental - - -Synopsis -======== - -.. c:function:: int ioctl( int fd, DMX_EXPBUF, struct dmx_exportbuffer *argp ) - :name: DMX_EXPBUF - - -Arguments -========= - -``fd`` - File descriptor returned by :ref:`open() `. - -``argp`` - Pointer to struct :c:type:`dmx_exportbuffer`. - - -Description -=========== - -This ioctl is an extension to the memory mapping I/O method. -It can be used to export a buffer as a DMABUF file at any time after -buffers have been allocated with the :ref:`DMX_REQBUFS` ioctl. - -To export a buffer, applications fill struct :c:type:`dmx_exportbuffer`. -Applications must set the ``index`` field. Valid index numbers -range from zero to the number of buffers allocated with :ref:`DMX_REQBUFS` -(struct :c:type:`dmx_requestbuffers` ``count``) minus one. -Additional flags may be posted in the ``flags`` field. Refer to a manual -for open() for details. Currently only O_CLOEXEC, O_RDONLY, O_WRONLY, -and O_RDWR are supported. -All other fields must be set to zero. In the -case of multi-planar API, every plane is exported separately using -multiple :ref:`DMX_EXPBUF` calls. - -After calling :ref:`DMX_EXPBUF` the ``fd`` field will be set by a -driver, on success. This is a DMABUF file descriptor. The application may -pass it to other DMABUF-aware devices. It is recommended to close a DMABUF -file when it is no longer used to allow the associated memory to be reclaimed. - - -Examples -======== - - -.. code-block:: c - - int buffer_export(int v4lfd, enum dmx_buf_type bt, int index, int *dmafd) - { - struct dmx_exportbuffer expbuf; - - memset(&expbuf, 0, sizeof(expbuf)); - expbuf.type = bt; - expbuf.index = index; - if (ioctl(v4lfd, DMX_EXPBUF, &expbuf) == -1) { - perror("DMX_EXPBUF"); - return -1; - } - - *dmafd = expbuf.fd; - - return 0; - } - -Return Value -============ - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. - -EINVAL - A queue is not in MMAP mode or DMABUF exporting is not supported or - ``flags`` or ``index`` fields are invalid. diff --git a/Documentation/media/uapi/dvb/dmx-fclose.rst b/Documentation/media/uapi/dvb/dmx-fclose.rst deleted file mode 100644 index 05ff32270274..000000000000 --- a/Documentation/media/uapi/dvb/dmx-fclose.rst +++ /dev/null @@ -1,52 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _dmx_fclose: - -======================== -Digital TV demux close() -======================== - -Name ----- - -Digital TV demux close() - - -Synopsis --------- - -.. c:function:: int close(int fd) - :name: dvb-dmx-close - - -Arguments ---------- - -``fd`` - File descriptor returned by a previous call to - :c:func:`open() `. - -Description ------------ - -This system call deactivates and deallocates a filter that was -previously allocated via the :c:func:`open() ` call. - - -Return Value ------------- - -On success 0 is returned. - -On error, -1 is returned and the ``errno`` variable is set -appropriately. - -The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/dvb/dmx-fopen.rst b/Documentation/media/uapi/dvb/dmx-fopen.rst deleted file mode 100644 index 2700a2fad68b..000000000000 --- a/Documentation/media/uapi/dvb/dmx-fopen.rst +++ /dev/null @@ -1,98 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _dmx_fopen: - -======================= -Digital TV demux open() -======================= - -Name ----- - -Digital TV demux open() - - -Synopsis --------- - -.. c:function:: int open(const char *deviceName, int flags) - :name: dvb-dmx-open - -Arguments ---------- - -``name`` - Name of specific Digital TV demux device. - -``flags`` - A bit-wise OR of the following flags: - -.. tabularcolumns:: |p{2.5cm}|p{15.0cm}| - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - :widths: 1 16 - - - - - ``O_RDONLY`` - - read-only access - - - - - ``O_RDWR`` - - read/write access - - - - - ``O_NONBLOCK`` - - open in non-blocking mode - (blocking mode is the default) - - -Description ------------ - -This system call, used with a device name of ``/dev/dvb/adapter?/demux?``, -allocates a new filter and returns a handle which can be used for -subsequent control of that filter. This call has to be made for each -filter to be used, i.e. every returned file descriptor is a reference to -a single filter. ``/dev/dvb/adapter?/dvr?`` is a logical device to be used -for retrieving Transport Streams for digital video recording. When -reading from this device a transport stream containing the packets from -all PES filters set in the corresponding demux device -(``/dev/dvb/adapter?/demux?``) having the output set to ``DMX_OUT_TS_TAP``. -A recorded Transport Stream is replayed by writing to this device. - -The significance of blocking or non-blocking mode is described in the -documentation for functions where there is a difference. It does not -affect the semantics of the ``open()`` call itself. A device opened -in blocking mode can later be put into non-blocking mode (and vice versa) -using the ``F_SETFL`` command of the fcntl system call. - - -Return Value ------------- - -On success 0 is returned. - -On error -1 is returned, and the ``errno`` variable is set -appropriately. - -.. tabularcolumns:: |p{2.5cm}|p{15.0cm}| - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - :widths: 1 16 - - - - ``EMFILE`` - - “Too many open files”, i.e. no more filters available. - -The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/dvb/dmx-fread.rst b/Documentation/media/uapi/dvb/dmx-fread.rst deleted file mode 100644 index 292fa98f39ff..000000000000 --- a/Documentation/media/uapi/dvb/dmx-fread.rst +++ /dev/null @@ -1,87 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _dmx_fread: - -======================= -Digital TV demux read() -======================= - -Name ----- - -Digital TV demux read() - - -Synopsis --------- - -.. c:function:: size_t read(int fd, void *buf, size_t count) - :name: dvb-dmx-read - -Arguments ---------- - -``fd`` - File descriptor returned by a previous call to :c:func:`open() `. - - ``buf`` - Buffer to be filled - -``count`` - Max number of bytes to read - -Description ------------ - -This system call returns filtered data, which might be section or Packetized -Elementary Stream (PES) data. The filtered data is transferred from -the driver’s internal circular buffer to ``buf``. The maximum amount of data -to be transferred is implied by count. - -.. note:: - - if a section filter created with - :c:type:`DMX_CHECK_CRC ` flag set, - data that fails on CRC check will be silently ignored. - - -Return Value ------------- - -On success 0 is returned. - -On error -1 is returned, and the ``errno`` variable is set -appropriately. - -.. tabularcolumns:: |p{2.5cm}|p{15.0cm}| - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - :widths: 1 16 - - - - ``EWOULDBLOCK`` - - No data to return and ``O_NONBLOCK`` was specified. - - - - ``EOVERFLOW`` - - The filtered data was not read from the buffer in due time, - resulting in non-read data being lost. The buffer is flushed. - - - - ``ETIMEDOUT`` - - The section was not loaded within the stated timeout period. - See ioctl :ref:`DMX_SET_FILTER` for how to set a timeout. - - - - ``EFAULT`` - - The driver failed to write to the callers buffer due to an - invalid \*buf pointer. - - -The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/dvb/dmx-fwrite.rst b/Documentation/media/uapi/dvb/dmx-fwrite.rst deleted file mode 100644 index bdd4d4743bd5..000000000000 --- a/Documentation/media/uapi/dvb/dmx-fwrite.rst +++ /dev/null @@ -1,79 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _dmx_fwrite: - -======================== -Digital TV demux write() -======================== - -Name ----- - -Digital TV demux write() - - -Synopsis --------- - -.. c:function:: ssize_t write(int fd, const void *buf, size_t count) - :name: dvb-dmx-write - -Arguments ---------- - -``fd`` - File descriptor returned by a previous call to :c:func:`open() `. - -``buf`` - Buffer with data to be written - -``count`` - Number of bytes at the buffer - -Description ------------ - -This system call is only provided by the logical device -``/dev/dvb/adapter?/dvr?``, associated with the physical demux device that -provides the actual DVR functionality. It is used for replay of a -digitally recorded Transport Stream. Matching filters have to be defined -in the corresponding physical demux device, ``/dev/dvb/adapter?/demux?``. -The amount of data to be transferred is implied by count. - - -Return Value ------------- - -On success 0 is returned. - -On error -1 is returned, and the ``errno`` variable is set -appropriately. - -.. tabularcolumns:: |p{2.5cm}|p{15.0cm}| - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - :widths: 1 16 - - - - ``EWOULDBLOCK`` - - No data was written. This might happen if ``O_NONBLOCK`` was - specified and there is no more buffer space available (if - ``O_NONBLOCK`` is not specified the function will block until buffer - space is available). - - - - ``EBUSY`` - - This error code indicates that there are conflicting requests. The - corresponding demux device is setup to receive data from the - front- end. Make sure that these filters are stopped and that the - filters with input set to ``DMX_IN_DVR`` are started. - -The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/dvb/dmx-get-pes-pids.rst b/Documentation/media/uapi/dvb/dmx-get-pes-pids.rst deleted file mode 100644 index fcd3dc06c095..000000000000 --- a/Documentation/media/uapi/dvb/dmx-get-pes-pids.rst +++ /dev/null @@ -1,71 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _DMX_GET_PES_PIDS: - -================ -DMX_GET_PES_PIDS -================ - -Name ----- - -DMX_GET_PES_PIDS - - -Synopsis --------- - -.. c:function:: int ioctl(fd, DMX_GET_PES_PIDS, __u16 pids[5]) - :name: DMX_GET_PES_PIDS - -Arguments ---------- - -``fd`` - File descriptor returned by :c:func:`open() `. - -``pids`` - Array used to store 5 Program IDs. - - -Description ------------ - -This ioctl allows to query a DVB device to return the first PID used -by audio, video, textext, subtitle and PCR programs on a given service. -They're stored as: - -======================= ======== ======================================= -PID element position content -======================= ======== ======================================= -pids[DMX_PES_AUDIO] 0 first audio PID -pids[DMX_PES_VIDEO] 1 first video PID -pids[DMX_PES_TELETEXT] 2 first teletext PID -pids[DMX_PES_SUBTITLE] 3 first subtitle PID -pids[DMX_PES_PCR] 4 first Program Clock Reference PID -======================= ======== ======================================= - - -.. note:: - - A value equal to 0xffff means that the PID was not filled by the - Kernel. - - -Return Value ------------- - -On success 0 is returned. - -On error -1 is returned, and the ``errno`` variable is set -appropriately. - -The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/dvb/dmx-get-stc.rst b/Documentation/media/uapi/dvb/dmx-get-stc.rst deleted file mode 100644 index 2c81595f470a..000000000000 --- a/Documentation/media/uapi/dvb/dmx-get-stc.rst +++ /dev/null @@ -1,73 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _DMX_GET_STC: - -=========== -DMX_GET_STC -=========== - -Name ----- - -DMX_GET_STC - - -Synopsis --------- - -.. c:function:: int ioctl( int fd, DMX_GET_STC, struct dmx_stc *stc) - :name: DMX_GET_STC - -Arguments ---------- - -``fd`` - File descriptor returned by :c:func:`open() `. - -``stc`` - Pointer to :c:type:`dmx_stc` where the stc data is to be stored. - - -Description ------------ - -This ioctl call returns the current value of the system time counter -(which is driven by a PES filter of type :c:type:`DMX_PES_PCR `). -Some hardware supports more than one STC, so you must specify which one by -setting the :c:type:`num ` field of stc before the ioctl (range 0...n). -The result is returned in form of a ratio with a 64 bit numerator -and a 32 bit denominator, so the real 90kHz STC value is -``stc->stc / stc->base``. - - -Return Value ------------- - -On success 0 is returned. - -On error -1 is returned, and the ``errno`` variable is set -appropriately. - -.. tabularcolumns:: |p{2.5cm}|p{15.0cm}| - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - :widths: 1 16 - - - .. row 1 - - - ``EINVAL`` - - - Invalid stc number. - - -The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/dvb/dmx-mmap.rst b/Documentation/media/uapi/dvb/dmx-mmap.rst deleted file mode 100644 index 34bb7766718f..000000000000 --- a/Documentation/media/uapi/dvb/dmx-mmap.rst +++ /dev/null @@ -1,125 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _dmx-mmap: - -***************** -Digital TV mmap() -***************** - -Name -==== - -dmx-mmap - Map device memory into application address space - -.. warning:: this API is still experimental - -Synopsis -======== - -.. code-block:: c - - #include - #include - - -.. c:function:: void *mmap( void *start, size_t length, int prot, int flags, int fd, off_t offset ) - :name: dmx-mmap - -Arguments -========= - -``start`` - Map the buffer to this address in the application's address space. - When the ``MAP_FIXED`` flag is specified, ``start`` must be a - multiple of the pagesize and mmap will fail when the specified - address cannot be used. Use of this option is discouraged; - applications should just specify a ``NULL`` pointer here. - -``length`` - Length of the memory area to map. This must be a multiple of the - DVB packet length (188, on most drivers). - -``prot`` - The ``prot`` argument describes the desired memory protection. - Regardless of the device type and the direction of data exchange it - should be set to ``PROT_READ`` | ``PROT_WRITE``, permitting read - and write access to image buffers. Drivers should support at least - this combination of flags. - -``flags`` - The ``flags`` parameter specifies the type of the mapped object, - mapping options and whether modifications made to the mapped copy of - the page are private to the process or are to be shared with other - references. - - ``MAP_FIXED`` requests that the driver selects no other address than - the one specified. If the specified address cannot be used, - :ref:`mmap() ` will fail. If ``MAP_FIXED`` is specified, - ``start`` must be a multiple of the pagesize. Use of this option is - discouraged. - - One of the ``MAP_SHARED`` or ``MAP_PRIVATE`` flags must be set. - ``MAP_SHARED`` allows applications to share the mapped memory with - other (e. g. child-) processes. - - .. note:: - - The Linux Digital TV applications should not set the - ``MAP_PRIVATE``, ``MAP_DENYWRITE``, ``MAP_EXECUTABLE`` or ``MAP_ANON`` - flags. - -``fd`` - File descriptor returned by :ref:`open() `. - -``offset`` - Offset of the buffer in device memory, as returned by - :ref:`DMX_QUERYBUF` ioctl. - - -Description -=========== - -The :ref:`mmap() ` function asks to map ``length`` bytes starting at -``offset`` in the memory of the device specified by ``fd`` into the -application address space, preferably at address ``start``. This latter -address is a hint only, and is usually specified as 0. - -Suitable length and offset parameters are queried with the -:ref:`DMX_QUERYBUF` ioctl. Buffers must be allocated with the -:ref:`DMX_REQBUFS` ioctl before they can be queried. - -To unmap buffers the :ref:`munmap() ` function is used. - - -Return Value -============ - -On success :ref:`mmap() ` returns a pointer to the mapped buffer. On -error ``MAP_FAILED`` (-1) is returned, and the ``errno`` variable is set -appropriately. Possible error codes are: - -EBADF - ``fd`` is not a valid file descriptor. - -EACCES - ``fd`` is not open for reading and writing. - -EINVAL - The ``start`` or ``length`` or ``offset`` are not suitable. (E. g. - they are too large, or not aligned on a ``PAGESIZE`` boundary.) - - The ``flags`` or ``prot`` value is not supported. - - No buffers have been allocated with the - :ref:`DMX_REQBUFS` ioctl. - -ENOMEM - Not enough physical or virtual memory was available to complete the - request. diff --git a/Documentation/media/uapi/dvb/dmx-munmap.rst b/Documentation/media/uapi/dvb/dmx-munmap.rst deleted file mode 100644 index ef26b6f2b12b..000000000000 --- a/Documentation/media/uapi/dvb/dmx-munmap.rst +++ /dev/null @@ -1,63 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _dmx-munmap: - -************ -DVB munmap() -************ - -Name -==== - -dmx-munmap - Unmap device memory - -.. warning:: This API is still experimental. - - -Synopsis -======== - -.. code-block:: c - - #include - #include - - -.. c:function:: int munmap( void *start, size_t length ) - :name: dmx-munmap - -Arguments -========= - -``start`` - Address of the mapped buffer as returned by the - :ref:`mmap() ` function. - -``length`` - Length of the mapped buffer. This must be the same value as given to - :ref:`mmap() `. - - -Description -=========== - -Unmaps a previously with the :ref:`mmap() ` function mapped -buffer and frees it, if possible. - - -Return Value -============ - -On success :ref:`munmap() ` returns 0, on failure -1 and the -``errno`` variable is set appropriately: - -EINVAL - The ``start`` or ``length`` is incorrect, or no buffers have been - mapped yet. diff --git a/Documentation/media/uapi/dvb/dmx-qbuf.rst b/Documentation/media/uapi/dvb/dmx-qbuf.rst deleted file mode 100644 index 9dc845daa59d..000000000000 --- a/Documentation/media/uapi/dvb/dmx-qbuf.rst +++ /dev/null @@ -1,93 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _DMX_QBUF: - -************************* -ioctl DMX_QBUF, DMX_DQBUF -************************* - -Name -==== - -DMX_QBUF - DMX_DQBUF - Exchange a buffer with the driver - -.. warning:: this API is still experimental - - -Synopsis -======== - -.. c:function:: int ioctl( int fd, DMX_QBUF, struct dmx_buffer *argp ) - :name: DMX_QBUF - -.. c:function:: int ioctl( int fd, DMX_DQBUF, struct dmx_buffer *argp ) - :name: DMX_DQBUF - - -Arguments -========= - -``fd`` - File descriptor returned by :ref:`open() `. - -``argp`` - Pointer to struct :c:type:`dmx_buffer`. - - -Description -=========== - -Applications call the ``DMX_QBUF`` ioctl to enqueue an empty -(capturing) or filled (output) buffer in the driver's incoming queue. -The semantics depend on the selected I/O method. - -To enqueue a buffer applications set the ``index`` field. Valid index -numbers range from zero to the number of buffers allocated with -:ref:`DMX_REQBUFS` (struct :c:type:`dmx_requestbuffers` ``count``) minus -one. The contents of the struct :c:type:`dmx_buffer` returned -by a :ref:`DMX_QUERYBUF` ioctl will do as well. - -When ``DMX_QBUF`` is called with a pointer to this structure, it locks the -memory pages of the buffer in physical memory, so they cannot be swapped -out to disk. Buffers remain locked until dequeued, until the -the device is closed. - -Applications call the ``DMX_DQBUF`` ioctl to dequeue a filled -(capturing) buffer from the driver's outgoing queue. -They just set the ``index`` field with the buffer ID to be queued. -When ``DMX_DQBUF`` is called with a pointer to struct :c:type:`dmx_buffer`, -the driver fills the remaining fields or returns an error code. - -By default ``DMX_DQBUF`` blocks when no buffer is in the outgoing -queue. When the ``O_NONBLOCK`` flag was given to the -:ref:`open() ` function, ``DMX_DQBUF`` returns -immediately with an ``EAGAIN`` error code when no buffer is available. - -The struct :c:type:`dmx_buffer` structure is specified in -:ref:`buffer`. - - -Return Value -============ - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. - -EAGAIN - Non-blocking I/O has been selected using ``O_NONBLOCK`` and no - buffer was in the outgoing queue. - -EINVAL - The ``index`` is out of bounds, or no buffers have been allocated yet. - -EIO - ``DMX_DQBUF`` failed due to an internal error. Can also indicate - temporary problems like signal loss or CRC errors. diff --git a/Documentation/media/uapi/dvb/dmx-querybuf.rst b/Documentation/media/uapi/dvb/dmx-querybuf.rst deleted file mode 100644 index 4cf36e821696..000000000000 --- a/Documentation/media/uapi/dvb/dmx-querybuf.rst +++ /dev/null @@ -1,72 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _DMX_QUERYBUF: - -****************** -ioctl DMX_QUERYBUF -****************** - -Name -==== - -DMX_QUERYBUF - Query the status of a buffer - -.. warning:: this API is still experimental - - -Synopsis -======== - -.. c:function:: int ioctl( int fd, DMX_QUERYBUF, struct dvb_buffer *argp ) - :name: DMX_QUERYBUF - - -Arguments -========= - -``fd`` - File descriptor returned by :ref:`open() `. - -``argp`` - Pointer to struct :c:type:`dvb_buffer`. - - -Description -=========== - -This ioctl is part of the mmap streaming I/O method. It can -be used to query the status of a buffer at any time after buffers have -been allocated with the :ref:`DMX_REQBUFS` ioctl. - -Applications set the ``index`` field. Valid index numbers range from zero -to the number of buffers allocated with :ref:`DMX_REQBUFS` -(struct :c:type:`dvb_requestbuffers` ``count``) minus one. - -After calling :ref:`DMX_QUERYBUF` with a pointer to this structure, -drivers return an error code or fill the rest of the structure. - -On success, the ``offset`` will contain the offset of the buffer from the -start of the device memory, the ``length`` field its size, and the -``bytesused`` the number of bytes occupied by data in the buffer (payload). - -Return Value -============ - -On success 0 is returned, the ``offset`` will contain the offset of the -buffer from the start of the device memory, the ``length`` field its size, -and the ``bytesused`` the number of bytes occupied by data in the buffer -(payload). - -On error it returns -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. - -EINVAL - The ``index`` is out of bounds. diff --git a/Documentation/media/uapi/dvb/dmx-remove-pid.rst b/Documentation/media/uapi/dvb/dmx-remove-pid.rst deleted file mode 100644 index be992f44f306..000000000000 --- a/Documentation/media/uapi/dvb/dmx-remove-pid.rst +++ /dev/null @@ -1,57 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _DMX_REMOVE_PID: - -============== -DMX_REMOVE_PID -============== - -Name ----- - -DMX_REMOVE_PID - - -Synopsis --------- - -.. c:function:: int ioctl(fd, DMX_REMOVE_PID, __u16 *pid) - :name: DMX_REMOVE_PID - - -Arguments ---------- - -``fd`` - File descriptor returned by :c:func:`open() `. - -``pid`` - PID of the PES filter to be removed. - - -Description ------------ - -This ioctl call allows to remove a PID when multiple PIDs are set on a -transport stream filter, e. g. a filter previously set up with output -equal to :c:type:`DMX_OUT_TSDEMUX_TAP `, created via either -:ref:`DMX_SET_PES_FILTER` or :ref:`DMX_ADD_PID`. - - -Return Value ------------- - -On success 0 is returned. - -On error -1 is returned, and the ``errno`` variable is set -appropriately. - -The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/dvb/dmx-reqbufs.rst b/Documentation/media/uapi/dvb/dmx-reqbufs.rst deleted file mode 100644 index b302785bf678..000000000000 --- a/Documentation/media/uapi/dvb/dmx-reqbufs.rst +++ /dev/null @@ -1,83 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _DMX_REQBUFS: - -***************** -ioctl DMX_REQBUFS -***************** - -Name -==== - -DMX_REQBUFS - Initiate Memory Mapping and/or DMA buffer I/O - -.. warning:: this API is still experimental - - -Synopsis -======== - -.. c:function:: int ioctl( int fd, DMX_REQBUFS, struct dmx_requestbuffers *argp ) - :name: DMX_REQBUFS - - -Arguments -========= - -``fd`` - File descriptor returned by :ref:`open() `. - -``argp`` - Pointer to struct :c:type:`dmx_requestbuffers`. - -Description -=========== - -This ioctl is used to initiate a memory mapped or DMABUF based demux I/O. - -Memory mapped buffers are located in device memory and must be allocated -with this ioctl before they can be mapped into the application's address -space. User buffers are allocated by applications themselves, and this -ioctl is merely used to switch the driver into user pointer I/O mode and -to setup some internal structures. Similarly, DMABUF buffers are -allocated by applications through a device driver, and this ioctl only -configures the driver into DMABUF I/O mode without performing any direct -allocation. - -To allocate device buffers applications initialize all fields of the -struct :c:type:`dmx_requestbuffers` structure. They set the ``count`` field -to the desired number of buffers, and ``size`` to the size of each -buffer. - -When the ioctl is called with a pointer to this structure, the driver will -attempt to allocate the requested number of buffers and it stores the actual -number allocated in the ``count`` field. The ``count`` can be smaller than the number requested, even zero, when the driver runs out of free memory. A larger -number is also possible when the driver requires more buffers to -function correctly. The actual allocated buffer size can is returned -at ``size``, and can be smaller than what's requested. - -When this I/O method is not supported, the ioctl returns an ``EOPNOTSUPP`` -error code. - -Applications can call :ref:`DMX_REQBUFS` again to change the number of -buffers, however this cannot succeed when any buffers are still mapped. -A ``count`` value of zero frees all buffers, after aborting or finishing -any DMA in progress. - - -Return Value -============ - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. - -EOPNOTSUPP - The the requested I/O method is not supported. diff --git a/Documentation/media/uapi/dvb/dmx-set-buffer-size.rst b/Documentation/media/uapi/dvb/dmx-set-buffer-size.rst deleted file mode 100644 index 2dee0fb11f62..000000000000 --- a/Documentation/media/uapi/dvb/dmx-set-buffer-size.rst +++ /dev/null @@ -1,57 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _DMX_SET_BUFFER_SIZE: - -=================== -DMX_SET_BUFFER_SIZE -=================== - -Name ----- - -DMX_SET_BUFFER_SIZE - - -Synopsis --------- - -.. c:function:: int ioctl( int fd, DMX_SET_BUFFER_SIZE, unsigned long size) - :name: DMX_SET_BUFFER_SIZE - - -Arguments ---------- - -``fd`` - File descriptor returned by :c:func:`open() `. - -``size`` - Unsigned long size - -Description ------------ - -This ioctl call is used to set the size of the circular buffer used for -filtered data. The default size is two maximum sized sections, i.e. if -this function is not called a buffer size of ``2 * 4096`` bytes will be -used. - - -Return Value ------------- - - -On success 0 is returned. - -On error -1 is returned, and the ``errno`` variable is set -appropriately. - -The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/dvb/dmx-set-filter.rst b/Documentation/media/uapi/dvb/dmx-set-filter.rst deleted file mode 100644 index 66afbb9f2fe4..000000000000 --- a/Documentation/media/uapi/dvb/dmx-set-filter.rst +++ /dev/null @@ -1,64 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _DMX_SET_FILTER: - -============== -DMX_SET_FILTER -============== - -Name ----- - -DMX_SET_FILTER - - -Synopsis --------- - -.. c:function:: int ioctl( int fd, DMX_SET_FILTER, struct dmx_sct_filter_params *params) - :name: DMX_SET_FILTER - -Arguments ---------- - -``fd`` - File descriptor returned by :c:func:`open() `. - -``params`` - - Pointer to structure containing filter parameters. - - -Description ------------ - -This ioctl call sets up a filter according to the filter and mask -parameters provided. A timeout may be defined stating number of seconds -to wait for a section to be loaded. A value of 0 means that no timeout -should be applied. Finally there is a flag field where it is possible to -state whether a section should be CRC-checked, whether the filter should -be a ”one-shot” filter, i.e. if the filtering operation should be -stopped after the first section is received, and whether the filtering -operation should be started immediately (without waiting for a -:ref:`DMX_START` ioctl call). If a filter was previously set-up, this -filter will be canceled, and the receive buffer will be flushed. - - -Return Value ------------- - - -On success 0 is returned. - -On error -1 is returned, and the ``errno`` variable is set -appropriately. - -The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/dvb/dmx-set-pes-filter.rst b/Documentation/media/uapi/dvb/dmx-set-pes-filter.rst deleted file mode 100644 index dae5ab7878e5..000000000000 --- a/Documentation/media/uapi/dvb/dmx-set-pes-filter.rst +++ /dev/null @@ -1,76 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _DMX_SET_PES_FILTER: - -================== -DMX_SET_PES_FILTER -================== - -Name ----- - -DMX_SET_PES_FILTER - - -Synopsis --------- - -.. c:function:: int ioctl( int fd, DMX_SET_PES_FILTER, struct dmx_pes_filter_params *params) - :name: DMX_SET_PES_FILTER - - -Arguments ---------- - - -``fd`` - File descriptor returned by :c:func:`open() `. - -``params`` - Pointer to structure containing filter parameters. - - -Description ------------ - -This ioctl call sets up a PES filter according to the parameters -provided. By a PES filter is meant a filter that is based just on the -packet identifier (PID), i.e. no PES header or payload filtering -capability is supported. - - -Return Value ------------- - -On success 0 is returned. - -On error -1 is returned, and the ``errno`` variable is set -appropriately. - -.. tabularcolumns:: |p{2.5cm}|p{15.0cm}| - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - :widths: 1 16 - - - - .. row 1 - - - ``EBUSY`` - - - This error code indicates that there are conflicting requests. - There are active filters filtering data from another input source. - Make sure that these filters are stopped before starting this - filter. - - -The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/dvb/dmx-start.rst b/Documentation/media/uapi/dvb/dmx-start.rst deleted file mode 100644 index 488289d02504..000000000000 --- a/Documentation/media/uapi/dvb/dmx-start.rst +++ /dev/null @@ -1,75 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _DMX_START: - -========= -DMX_START -========= - -Name ----- - -DMX_START - - -Synopsis --------- - -.. c:function:: int ioctl( int fd, DMX_START) - :name: DMX_START - - -Arguments ---------- - -``fd`` - File descriptor returned by :c:func:`open() `. - -Description ------------ - -This ioctl call is used to start the actual filtering operation defined -via the ioctl calls :ref:`DMX_SET_FILTER` or :ref:`DMX_SET_PES_FILTER`. - - -Return Value ------------- - -On success 0 is returned. - -On error -1 is returned, and the ``errno`` variable is set -appropriately. - -.. tabularcolumns:: |p{2.5cm}|p{15.0cm}| - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - - .. row 1 - - - ``EINVAL`` - - - Invalid argument, i.e. no filtering parameters provided via the - :ref:`DMX_SET_FILTER` or :ref:`DMX_SET_PES_FILTER` ioctls. - - - .. row 2 - - - ``EBUSY`` - - - This error code indicates that there are conflicting requests. - There are active filters filtering data from another input source. - Make sure that these filters are stopped before starting this - filter. - - -The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/dvb/dmx-stop.rst b/Documentation/media/uapi/dvb/dmx-stop.rst deleted file mode 100644 index 982384d12923..000000000000 --- a/Documentation/media/uapi/dvb/dmx-stop.rst +++ /dev/null @@ -1,52 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _DMX_STOP: - -======== -DMX_STOP -======== - -Name ----- - -DMX_STOP - - -Synopsis --------- - -.. c:function:: int ioctl( int fd, DMX_STOP) - :name: DMX_STOP - - -Arguments ---------- - -``fd`` - File descriptor returned by :c:func:`open() `. - -Description ------------ - -This ioctl call is used to stop the actual filtering operation defined -via the ioctl calls :ref:`DMX_SET_FILTER` or :ref:`DMX_SET_PES_FILTER` and -started via the :ref:`DMX_START` command. - - -Return Value ------------- - -On success 0 is returned. - -On error -1 is returned, and the ``errno`` variable is set -appropriately. - -The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/dvb/dmx_fcalls.rst b/Documentation/media/uapi/dvb/dmx_fcalls.rst deleted file mode 100644 index 67312ab65f94..000000000000 --- a/Documentation/media/uapi/dvb/dmx_fcalls.rst +++ /dev/null @@ -1,37 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _dmx_fcalls: - -******************** -Demux Function Calls -******************** - -.. toctree:: - :maxdepth: 1 - - dmx-fopen - dmx-fclose - dmx-fread - dmx-fwrite - dmx-mmap - dmx-munmap - dmx-start - dmx-stop - dmx-set-filter - dmx-set-pes-filter - dmx-set-buffer-size - dmx-get-stc - dmx-get-pes-pids - dmx-add-pid - dmx-remove-pid - dmx-reqbufs - dmx-querybuf - dmx-expbuf - dmx-qbuf diff --git a/Documentation/media/uapi/dvb/dmx_types.rst b/Documentation/media/uapi/dvb/dmx_types.rst deleted file mode 100644 index b5cf704199e5..000000000000 --- a/Documentation/media/uapi/dvb/dmx_types.rst +++ /dev/null @@ -1,16 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _dmx_types: - -**************** -Demux Data Types -**************** - -.. kernel-doc:: include/uapi/linux/dvb/dmx.h diff --git a/Documentation/media/uapi/dvb/dvb-fe-read-status.rst b/Documentation/media/uapi/dvb/dvb-fe-read-status.rst deleted file mode 100644 index 172783b75fb7..000000000000 --- a/Documentation/media/uapi/dvb/dvb-fe-read-status.rst +++ /dev/null @@ -1,32 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _dvb-fe-read-status: - -*************************************** -Querying frontend status and statistics -*************************************** - -Once :ref:`FE_SET_PROPERTY ` is called, the -frontend will run a kernel thread that will periodically check for the -tuner lock status and provide statistics about the quality of the -signal. - -The information about the frontend tuner locking status can be queried -using :ref:`FE_READ_STATUS`. - -Signal statistics are provided via -:ref:`FE_GET_PROPERTY`. - -.. note:: - - Most statistics require the demodulator to be fully locked - (e. g. with :c:type:`FE_HAS_LOCK ` bit set). See - :ref:`Frontend statistics indicators ` for - more details. diff --git a/Documentation/media/uapi/dvb/dvb-frontend-event.rst b/Documentation/media/uapi/dvb/dvb-frontend-event.rst deleted file mode 100644 index ad4af66040c7..000000000000 --- a/Documentation/media/uapi/dvb/dvb-frontend-event.rst +++ /dev/null @@ -1,22 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. c:type:: dvb_frontend_event - -*************** -frontend events -*************** - - -.. code-block:: c - - struct dvb_frontend_event { - fe_status_t status; - struct dvb_frontend_parameters parameters; - }; diff --git a/Documentation/media/uapi/dvb/dvb-frontend-parameters.rst b/Documentation/media/uapi/dvb/dvb-frontend-parameters.rst deleted file mode 100644 index 67c2a316019f..000000000000 --- a/Documentation/media/uapi/dvb/dvb-frontend-parameters.rst +++ /dev/null @@ -1,126 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. c:type:: dvb_frontend_parameters - -******************* -frontend parameters -******************* - -The kind of parameters passed to the frontend device for tuning depend -on the kind of hardware you are using. - -The struct ``dvb_frontend_parameters`` uses a union with specific -per-system parameters. However, as newer delivery systems required more -data, the structure size weren't enough to fit, and just extending its -size would break the existing applications. So, those parameters were -replaced by the usage of -:ref:`FE_GET_PROPERTY/FE_SET_PROPERTY ` -ioctl's. The new API is flexible enough to add new parameters to -existing delivery systems, and to add newer delivery systems. - -So, newer applications should use -:ref:`FE_GET_PROPERTY/FE_SET_PROPERTY ` -instead, in order to be able to support the newer System Delivery like -DVB-S2, DVB-T2, DVB-C2, ISDB, etc. - -All kinds of parameters are combined as a union in the -``dvb_frontend_parameters`` structure: - - -.. code-block:: c - - struct dvb_frontend_parameters { - uint32_t frequency; /* (absolute) frequency in Hz for QAM/OFDM */ - /* intermediate frequency in kHz for QPSK */ - fe_spectral_inversion_t inversion; - union { - struct dvb_qpsk_parameters qpsk; - struct dvb_qam_parameters qam; - struct dvb_ofdm_parameters ofdm; - struct dvb_vsb_parameters vsb; - } u; - }; - -In the case of QPSK frontends the ``frequency`` field specifies the -intermediate frequency, i.e. the offset which is effectively added to -the local oscillator frequency (LOF) of the LNB. The intermediate -frequency has to be specified in units of kHz. For QAM and OFDM -frontends the ``frequency`` specifies the absolute frequency and is -given in Hz. - - -.. c:type:: dvb_qpsk_parameters - -QPSK parameters -=============== - -For satellite QPSK frontends you have to use the ``dvb_qpsk_parameters`` -structure: - - -.. code-block:: c - - struct dvb_qpsk_parameters { - uint32_t symbol_rate; /* symbol rate in Symbols per second */ - fe_code_rate_t fec_inner; /* forward error correction (see above) */ - }; - - -.. c:type:: dvb_qam_parameters - -QAM parameters -============== - -for cable QAM frontend you use the ``dvb_qam_parameters`` structure: - - -.. code-block:: c - - struct dvb_qam_parameters { - uint32_t symbol_rate; /* symbol rate in Symbols per second */ - fe_code_rate_t fec_inner; /* forward error correction (see above) */ - fe_modulation_t modulation; /* modulation type (see above) */ - }; - - -.. c:type:: dvb_vsb_parameters - -VSB parameters -============== - -ATSC frontends are supported by the ``dvb_vsb_parameters`` structure: - - -.. code-block:: c - - struct dvb_vsb_parameters { - fe_modulation_t modulation; /* modulation type (see above) */ - }; - - -.. c:type:: dvb_ofdm_parameters - -OFDM parameters -=============== - -DVB-T frontends are supported by the ``dvb_ofdm_parameters`` structure: - - -.. code-block:: c - - struct dvb_ofdm_parameters { - fe_bandwidth_t bandwidth; - fe_code_rate_t code_rate_HP; /* high priority stream code rate */ - fe_code_rate_t code_rate_LP; /* low priority stream code rate */ - fe_modulation_t constellation; /* modulation type (see above) */ - fe_transmit_mode_t transmission_mode; - fe_guard_interval_t guard_interval; - fe_hierarchy_t hierarchy_information; - }; diff --git a/Documentation/media/uapi/dvb/dvbapi.rst b/Documentation/media/uapi/dvb/dvbapi.rst deleted file mode 100644 index 0fcc01f182f9..000000000000 --- a/Documentation/media/uapi/dvb/dvbapi.rst +++ /dev/null @@ -1,126 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. include:: - -.. _dvbapi: - -######################## -Part II - Digital TV API -######################## - -.. note:: - - This API is also known as Linux **DVB API**. - - It it was originally written to support the European digital TV - standard (DVB), and later extended to support all digital TV standards. - - In order to avoid confusion, within this document, it was opted to refer to - it, and to associated hardware as **Digital TV**. - - The word **DVB** is reserved to be used for: - - - the Digital TV API version - (e. g. DVB API version 3 or DVB API version 5); - - digital TV data types (enums, structs, defines, etc); - - digital TV device nodes (``/dev/dvb/...``); - - the European DVB standard. - -**Version 5.10** - -.. only:: html - - .. class:: toc-title - - Table of Contents - -.. toctree:: - :maxdepth: 5 - :numbered: - - intro - frontend - demux - ca - net - legacy_dvb_apis - examples - headers - - -********************** -Revision and Copyright -********************** - -Authors: - -- J. K. Metzler, Ralph - - - Original author of the Digital TV API documentation. - -- O. C. Metzler, Marcus - - - Original author of the Digital TV API documentation. - -- Carvalho Chehab, Mauro - - - Ported document to Docbook XML, addition of DVBv5 API, documentation gaps fix. - -**Copyright** |copy| 2002-2003 : Convergence GmbH - -**Copyright** |copy| 2009-2017 : Mauro Carvalho Chehab - -**************** -Revision History -**************** - -:revision: 2.2.0 / 2017-09-01 (*mcc*) - -Most gaps between the uAPI document and the Kernel implementation -got fixed for the non-legacy API. - -:revision: 2.1.0 / 2015-05-29 (*mcc*) - -DocBook improvements and cleanups, in order to document the system calls -on a more standard way and provide more description about the current -Digital TV API. - -:revision: 2.0.4 / 2011-05-06 (*mcc*) - -Add more information about DVBv5 API, better describing the frontend -GET/SET props ioctl's. - - -:revision: 2.0.3 / 2010-07-03 (*mcc*) - -Add some frontend capabilities flags, present on kernel, but missing at -the specs. - - -:revision: 2.0.2 / 2009-10-25 (*mcc*) - -documents FE_SET_FRONTEND_TUNE_MODE and -FE_DISHETWORK_SEND_LEGACY_CMD ioctls. - - -:revision: 2.0.1 / 2009-09-16 (*mcc*) - -Added ISDB-T test originally written by Patrick Boettcher - - -:revision: 2.0.0 / 2009-09-06 (*mcc*) - -Conversion from LaTex to DocBook XML. The contents is the same as the -original LaTex version. - - -:revision: 1.0.0 / 2003-07-24 (*rjkm*) - -Initial revision on LaTEX. diff --git a/Documentation/media/uapi/dvb/dvbproperty.rst b/Documentation/media/uapi/dvb/dvbproperty.rst deleted file mode 100644 index 0c4f5598f2be..000000000000 --- a/Documentation/media/uapi/dvb/dvbproperty.rst +++ /dev/null @@ -1,133 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _frontend-properties: - -************** -Property types -************** - -Tuning into a Digital TV physical channel and starting decoding it -requires changing a set of parameters, in order to control the tuner, -the demodulator, the Linear Low-noise Amplifier (LNA) and to set the -antenna subsystem via Satellite Equipment Control - SEC (on satellite -systems). The actual parameters are specific to each particular digital -TV standards, and may change as the digital TV specs evolves. - -In the past (up to DVB API version 3 - DVBv3), the strategy used was to have a -union with the parameters needed to tune for DVB-S, DVB-C, DVB-T and -ATSC delivery systems grouped there. The problem is that, as the second -generation standards appeared, the size of such union was not big -enough to group the structs that would be required for those new -standards. Also, extending it would break userspace. - -So, the legacy union/struct based approach was deprecated, in favor -of a properties set approach. On such approach, -:ref:`FE_GET_PROPERTY and FE_SET_PROPERTY ` are used -to setup the frontend and read its status. - -The actual action is determined by a set of dtv_property cmd/data pairs. -With one single ioctl, is possible to get/set up to 64 properties. - -This section describes the new and recommended way to set the frontend, -with supports all digital TV delivery systems. - -.. note:: - - 1. On Linux DVB API version 3, setting a frontend was done via - struct :c:type:`dvb_frontend_parameters`. - - 2. Don't use DVB API version 3 calls on hardware with supports - newer standards. Such API provides no support or a very limited - support to new standards and/or new hardware. - - 3. Nowadays, most frontends support multiple delivery systems. - Only with DVB API version 5 calls it is possible to switch between - the multiple delivery systems supported by a frontend. - - 4. DVB API version 5 is also called *S2API*, as the first - new standard added to it was DVB-S2. - -**Example**: in order to set the hardware to tune into a DVB-C channel -at 651 kHz, modulated with 256-QAM, FEC 3/4 and symbol rate of 5.217 -Mbauds, those properties should be sent to -:ref:`FE_SET_PROPERTY ` ioctl: - - :ref:`DTV_DELIVERY_SYSTEM ` = SYS_DVBC_ANNEX_A - - :ref:`DTV_FREQUENCY ` = 651000000 - - :ref:`DTV_MODULATION ` = QAM_256 - - :ref:`DTV_INVERSION ` = INVERSION_AUTO - - :ref:`DTV_SYMBOL_RATE ` = 5217000 - - :ref:`DTV_INNER_FEC ` = FEC_3_4 - - :ref:`DTV_TUNE ` - -The code that would that would do the above is show in -:ref:`dtv-prop-example`. - -.. code-block:: c - :caption: Example: Setting digital TV frontend properties - :name: dtv-prop-example - - #include - #include - #include - #include - - static struct dtv_property props[] = { - { .cmd = DTV_DELIVERY_SYSTEM, .u.data = SYS_DVBC_ANNEX_A }, - { .cmd = DTV_FREQUENCY, .u.data = 651000000 }, - { .cmd = DTV_MODULATION, .u.data = QAM_256 }, - { .cmd = DTV_INVERSION, .u.data = INVERSION_AUTO }, - { .cmd = DTV_SYMBOL_RATE, .u.data = 5217000 }, - { .cmd = DTV_INNER_FEC, .u.data = FEC_3_4 }, - { .cmd = DTV_TUNE } - }; - - static struct dtv_properties dtv_prop = { - .num = 6, .props = props - }; - - int main(void) - { - int fd = open("/dev/dvb/adapter0/frontend0", O_RDWR); - - if (!fd) { - perror ("open"); - return -1; - } - if (ioctl(fd, FE_SET_PROPERTY, &dtv_prop) == -1) { - perror("ioctl"); - return -1; - } - printf("Frontend set\\n"); - return 0; - } - -.. attention:: While it is possible to directly call the Kernel code like the - above example, it is strongly recommended to use - `libdvbv5 `__, as it - provides abstraction to work with the supported digital TV standards and - provides methods for usual operations like program scanning and to - read/write channel descriptor files. - -.. toctree:: - :maxdepth: 1 - - fe_property_parameters - frontend-stat-properties - frontend-property-terrestrial-systems - frontend-property-cable-systems - frontend-property-satellite-systems - frontend-header diff --git a/Documentation/media/uapi/dvb/dvbstb.svg b/Documentation/media/uapi/dvb/dvbstb.svg deleted file mode 100644 index c7672148d6ff..000000000000 --- a/Documentation/media/uapi/dvb/dvbstb.svg +++ /dev/null @@ -1,43 +0,0 @@ - - -image/svg+xmlAntena -Frontend -CA -Demux -SEC -Audio -Video -TV -Decoder -Decoder - diff --git a/Documentation/media/uapi/dvb/examples.rst b/Documentation/media/uapi/dvb/examples.rst deleted file mode 100644 index eaa41bc8d173..000000000000 --- a/Documentation/media/uapi/dvb/examples.rst +++ /dev/null @@ -1,23 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _dvb_examples: - -******** -Examples -******** - -In the past, we used to have a set of examples here. However, those -examples got out of date and doesn't even compile nowadays. - -Also, nowadays, the best is to use the libdvbv5 DVB API nowadays, -with is fully documented. - -Please refer to the `libdvbv5 `__ -for updated/recommended examples. diff --git a/Documentation/media/uapi/dvb/fe-bandwidth-t.rst b/Documentation/media/uapi/dvb/fe-bandwidth-t.rst deleted file mode 100644 index c3d7837b5f87..000000000000 --- a/Documentation/media/uapi/dvb/fe-bandwidth-t.rst +++ /dev/null @@ -1,81 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -****************** -Frontend bandwidth -****************** - -.. c:type:: fe_bandwidth - -.. flat-table:: enum fe_bandwidth - :header-rows: 1 - :stub-columns: 0 - - - - .. row 1 - - - ID - - - Description - - - .. row 2 - - - .. _BANDWIDTH-AUTO: - - ``BANDWIDTH_AUTO`` - - - Autodetect bandwidth (if supported) - - - .. row 3 - - - .. _BANDWIDTH-1-712-MHZ: - - ``BANDWIDTH_1_712_MHZ`` - - - 1.712 MHz - - - .. row 4 - - - .. _BANDWIDTH-5-MHZ: - - ``BANDWIDTH_5_MHZ`` - - - 5 MHz - - - .. row 5 - - - .. _BANDWIDTH-6-MHZ: - - ``BANDWIDTH_6_MHZ`` - - - 6 MHz - - - .. row 6 - - - .. _BANDWIDTH-7-MHZ: - - ``BANDWIDTH_7_MHZ`` - - - 7 MHz - - - .. row 7 - - - .. _BANDWIDTH-8-MHZ: - - ``BANDWIDTH_8_MHZ`` - - - 8 MHz - - - .. row 8 - - - .. _BANDWIDTH-10-MHZ: - - ``BANDWIDTH_10_MHZ`` - - - 10 MHz diff --git a/Documentation/media/uapi/dvb/fe-diseqc-recv-slave-reply.rst b/Documentation/media/uapi/dvb/fe-diseqc-recv-slave-reply.rst deleted file mode 100644 index 88fd2186ca4d..000000000000 --- a/Documentation/media/uapi/dvb/fe-diseqc-recv-slave-reply.rst +++ /dev/null @@ -1,55 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _FE_DISEQC_RECV_SLAVE_REPLY: - -******************************** -ioctl FE_DISEQC_RECV_SLAVE_REPLY -******************************** - -Name -==== - -FE_DISEQC_RECV_SLAVE_REPLY - Receives reply from a DiSEqC 2.0 command - - -Synopsis -======== - -.. c:function:: int ioctl( int fd, FE_DISEQC_RECV_SLAVE_REPLY, struct dvb_diseqc_slave_reply *argp ) - :name: FE_DISEQC_RECV_SLAVE_REPLY - - -Arguments -========= - -``fd`` - File descriptor returned by :ref:`open() `. - -``argp`` - pointer to struct :c:type:`dvb_diseqc_slave_reply`. - - -Description -=========== - -Receives reply from a DiSEqC 2.0 command. - -The received message is stored at the buffer pointed by ``argp``. - -Return Value -============ - -On success 0 is returned. - -On error -1 is returned, and the ``errno`` variable is set -appropriately. - -Generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/dvb/fe-diseqc-reset-overload.rst b/Documentation/media/uapi/dvb/fe-diseqc-reset-overload.rst deleted file mode 100644 index 92929c2e75db..000000000000 --- a/Documentation/media/uapi/dvb/fe-diseqc-reset-overload.rst +++ /dev/null @@ -1,53 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _FE_DISEQC_RESET_OVERLOAD: - -****************************** -ioctl FE_DISEQC_RESET_OVERLOAD -****************************** - -Name -==== - -FE_DISEQC_RESET_OVERLOAD - Restores the power to the antenna subsystem, if it was powered off due - to power overload. - - -Synopsis -======== - -.. c:function:: int ioctl( int fd, FE_DISEQC_RESET_OVERLOAD, NULL ) - :name: FE_DISEQC_RESET_OVERLOAD - - -Arguments -========= - -``fd`` - File descriptor returned by :ref:`open() `. - -Description -=========== - -If the bus has been automatically powered off due to power overload, -this ioctl call restores the power to the bus. The call requires -read/write access to the device. This call has no effect if the device -is manually powered off. Not all Digital TV adapters support this ioctl. - - -Return Value -============ - -On success 0 is returned. - -On error -1 is returned, and the ``errno`` variable is set -appropriately. - -Generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/dvb/fe-diseqc-send-burst.rst b/Documentation/media/uapi/dvb/fe-diseqc-send-burst.rst deleted file mode 100644 index 8af872d306aa..000000000000 --- a/Documentation/media/uapi/dvb/fe-diseqc-send-burst.rst +++ /dev/null @@ -1,59 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _FE_DISEQC_SEND_BURST: - -************************** -ioctl FE_DISEQC_SEND_BURST -************************** - -Name -==== - -FE_DISEQC_SEND_BURST - Sends a 22KHz tone burst for 2x1 mini DiSEqC satellite selection. - - -Synopsis -======== - -.. c:function:: int ioctl( int fd, FE_DISEQC_SEND_BURST, enum fe_sec_mini_cmd tone ) - :name: FE_DISEQC_SEND_BURST - - -Arguments -========= - -``fd`` - File descriptor returned by :ref:`open() `. - -``tone`` - An integer enumered value described at :c:type:`fe_sec_mini_cmd`. - - -Description -=========== - -This ioctl is used to set the generation of a 22kHz tone burst for mini -DiSEqC satellite selection for 2x1 switches. This call requires -read/write permissions. - -It provides support for what's specified at -`Digital Satellite Equipment Control (DiSEqC) - Simple "ToneBurst" Detection Circuit specification. `__ - - -Return Value -============ - -On success 0 is returned. - -On error -1 is returned, and the ``errno`` variable is set -appropriately. - -Generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/dvb/fe-diseqc-send-master-cmd.rst b/Documentation/media/uapi/dvb/fe-diseqc-send-master-cmd.rst deleted file mode 100644 index 30a48114153c..000000000000 --- a/Documentation/media/uapi/dvb/fe-diseqc-send-master-cmd.rst +++ /dev/null @@ -1,56 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _FE_DISEQC_SEND_MASTER_CMD: - -******************************* -ioctl FE_DISEQC_SEND_MASTER_CMD -******************************* - -Name -==== - -FE_DISEQC_SEND_MASTER_CMD - Sends a DiSEqC command - - -Synopsis -======== - -.. c:function:: int ioctl( int fd, FE_DISEQC_SEND_MASTER_CMD, struct dvb_diseqc_master_cmd *argp ) - :name: FE_DISEQC_SEND_MASTER_CMD - - -Arguments -========= - -``fd`` - File descriptor returned by :ref:`open() `. - -``argp`` - pointer to struct - :c:type:`dvb_diseqc_master_cmd` - - -Description -=========== - -Sends the DiSEqC command pointed by :c:type:`dvb_diseqc_master_cmd` -to the antenna subsystem. - -Return Value -============ - -On success 0 is returned. - -On error -1 is returned, and the ``errno`` variable is set -appropriately. - -Generic error codes are described at the -:ref:`Generic Error Codes ` chapter. - diff --git a/Documentation/media/uapi/dvb/fe-dishnetwork-send-legacy-cmd.rst b/Documentation/media/uapi/dvb/fe-dishnetwork-send-legacy-cmd.rst deleted file mode 100644 index 13811289971b..000000000000 --- a/Documentation/media/uapi/dvb/fe-dishnetwork-send-legacy-cmd.rst +++ /dev/null @@ -1,62 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _FE_DISHNETWORK_SEND_LEGACY_CMD: - -****************************** -FE_DISHNETWORK_SEND_LEGACY_CMD -****************************** - -Name -==== - -FE_DISHNETWORK_SEND_LEGACY_CMD - - -Synopsis -======== - -.. c:function:: int ioctl(int fd, FE_DISHNETWORK_SEND_LEGACY_CMD, unsigned long cmd) - :name: FE_DISHNETWORK_SEND_LEGACY_CMD - - -Arguments -========= - -``fd`` - File descriptor returned by :c:func:`open() `. - -``cmd`` - Sends the specified raw cmd to the dish via DISEqC. - - -Description -=========== - -.. warning:: - This is a very obscure legacy command, used only at stv0299 - driver. Should not be used on newer drivers. - -It provides a non-standard method for selecting Diseqc voltage on the -frontend, for Dish Network legacy switches. - -As support for this ioctl were added in 2004, this means that such -dishes were already legacy in 2004. - - -Return Value -============ - -On success 0 is returned. - -On error -1 is returned, and the ``errno`` variable is set -appropriately. - -Generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/dvb/fe-enable-high-lnb-voltage.rst b/Documentation/media/uapi/dvb/fe-enable-high-lnb-voltage.rst deleted file mode 100644 index 32b7d140d80b..000000000000 --- a/Documentation/media/uapi/dvb/fe-enable-high-lnb-voltage.rst +++ /dev/null @@ -1,61 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _FE_ENABLE_HIGH_LNB_VOLTAGE: - -******************************** -ioctl FE_ENABLE_HIGH_LNB_VOLTAGE -******************************** - -Name -==== - -FE_ENABLE_HIGH_LNB_VOLTAGE - Select output DC level between normal LNBf voltages or higher LNBf - voltages. - - -Synopsis -======== - -.. c:function:: int ioctl( int fd, FE_ENABLE_HIGH_LNB_VOLTAGE, unsigned int high ) - :name: FE_ENABLE_HIGH_LNB_VOLTAGE - - -Arguments -========= - -``fd`` - File descriptor returned by :ref:`open() `. - -``high`` - Valid flags: - - - 0 - normal 13V and 18V. - - - >0 - enables slightly higher voltages instead of 13/18V, in order - to compensate for long antenna cables. - - -Description -=========== - -Select output DC level between normal LNBf voltages or higher LNBf -voltages between 0 (normal) or a value grater than 0 for higher -voltages. - - -Return Value -============ - -On success 0 is returned. - -On error -1 is returned, and the ``errno`` variable is set -appropriately. - -Generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/dvb/fe-get-event.rst b/Documentation/media/uapi/dvb/fe-get-event.rst deleted file mode 100644 index 2573d5b9b636..000000000000 --- a/Documentation/media/uapi/dvb/fe-get-event.rst +++ /dev/null @@ -1,78 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _FE_GET_EVENT: - -************ -FE_GET_EVENT -************ - -Name -==== - -FE_GET_EVENT - -.. attention:: This ioctl is deprecated. - - -Synopsis -======== - -.. c:function:: int ioctl(int fd, FE_GET_EVENT, struct dvb_frontend_event *ev) - :name: FE_GET_EVENT - - -Arguments -========= - -``fd`` - File descriptor returned by :c:func:`open() `. - -``ev`` - Points to the location where the event, if any, is to be stored. - - -Description -=========== - -This ioctl call returns a frontend event if available. If an event is -not available, the behavior depends on whether the device is in blocking -or non-blocking mode. In the latter case, the call fails immediately -with errno set to ``EWOULDBLOCK``. In the former case, the call blocks until -an event becomes available. - - -Return Value -============ - -On success 0 is returned. - -On error -1 is returned, and the ``errno`` variable is set -appropriately. - - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - - .. row 1 - - - ``EWOULDBLOCK`` - - - There is no event pending, and the device is in non-blocking mode. - - - .. row 2 - - - ``EOVERFLOW`` - - - Overflow in event queue - one or more events were lost. - -Generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/dvb/fe-get-frontend.rst b/Documentation/media/uapi/dvb/fe-get-frontend.rst deleted file mode 100644 index 6cd5250d1832..000000000000 --- a/Documentation/media/uapi/dvb/fe-get-frontend.rst +++ /dev/null @@ -1,69 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _FE_GET_FRONTEND: - -*************** -FE_GET_FRONTEND -*************** - -Name -==== - -FE_GET_FRONTEND - -.. attention:: This ioctl is deprecated. - - -Synopsis -======== - -.. c:function:: int ioctl(int fd, FE_GET_FRONTEND, struct dvb_frontend_parameters *p) - :name: FE_GET_FRONTEND - - -Arguments -========= - -``fd`` - File descriptor returned by :c:func:`open() `. - - -``p`` - Points to parameters for tuning operation. - - -Description -=========== - -This ioctl call queries the currently effective frontend parameters. For -this command, read-only access to the device is sufficient. - - -Return Value -============ - -On success 0 is returned. - -On error -1 is returned, and the ``errno`` variable is set -appropriately. - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - - .. row 1 - - - ``EINVAL`` - - - Maximum supported symbol rate reached. - -Generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/dvb/fe-get-info.rst b/Documentation/media/uapi/dvb/fe-get-info.rst deleted file mode 100644 index 551e68b11528..000000000000 --- a/Documentation/media/uapi/dvb/fe-get-info.rst +++ /dev/null @@ -1,70 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _FE_GET_INFO: - -***************** -ioctl FE_GET_INFO -***************** - -Name -==== - -FE_GET_INFO - Query Digital TV frontend capabilities and returns information -about the - front-end. This call only requires read-only access to the device. - - -Synopsis -======== - -.. c:function:: int ioctl( int fd, FE_GET_INFO, struct dvb_frontend_info *argp ) - :name: FE_GET_INFO - - -Arguments -========= - -``fd`` - File descriptor returned by :ref:`open() `. - -``argp`` - pointer to struct struct - :c:type:`dvb_frontend_info` - - -Description -=========== - -All Digital TV frontend devices support the :ref:`FE_GET_INFO` ioctl. It is -used to identify kernel devices compatible with this specification and to -obtain information about driver and hardware capabilities. The ioctl -takes a pointer to dvb_frontend_info which is filled by the driver. -When the driver is not compatible with this specification the ioctl -returns an error. - - -frontend capabilities -===================== - -Capabilities describe what a frontend can do. Some capabilities are -supported only on some specific frontend types. - -The frontend capabilities are described at :c:type:`fe_caps`. - - -Return Value -============ - -On success 0 is returned. - -On error -1 is returned, and the ``errno`` variable is set -appropriately. - -Generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/dvb/fe-get-property.rst b/Documentation/media/uapi/dvb/fe-get-property.rst deleted file mode 100644 index 99386c7461b3..000000000000 --- a/Documentation/media/uapi/dvb/fe-get-property.rst +++ /dev/null @@ -1,83 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _FE_GET_PROPERTY: - -************************************** -ioctl FE_SET_PROPERTY, FE_GET_PROPERTY -************************************** - -Name -==== - -FE_SET_PROPERTY - FE_GET_PROPERTY - FE_SET_PROPERTY sets one or more frontend properties. - FE_GET_PROPERTY returns one or more frontend properties. - - -Synopsis -======== - -.. c:function:: int ioctl( int fd, FE_GET_PROPERTY, struct dtv_properties *argp ) - :name: FE_GET_PROPERTY - -.. c:function:: int ioctl( int fd, FE_SET_PROPERTY, struct dtv_properties *argp ) - :name: FE_SET_PROPERTY - - -Arguments -========= - -``fd`` - File descriptor returned by :ref:`open() `. - -``argp`` - Pointer to struct :c:type:`dtv_properties`. - - -Description -=========== - -All Digital TV frontend devices support the ``FE_SET_PROPERTY`` and -``FE_GET_PROPERTY`` ioctls. The supported properties and statistics -depends on the delivery system and on the device: - -- ``FE_SET_PROPERTY:`` - - - This ioctl is used to set one or more frontend properties. - - - This is the basic command to request the frontend to tune into - some frequency and to start decoding the digital TV signal. - - - This call requires read/write access to the device. - -.. note:: - - At return, the values aren't updated to reflect the actual - parameters used. If the actual parameters are needed, an explicit - call to ``FE_GET_PROPERTY`` is needed. - -- ``FE_GET_PROPERTY:`` - - - This ioctl is used to get properties and statistics from the - frontend. - - - No properties are changed, and statistics aren't reset. - - - This call only requires read-only access to the device. - - -Return Value -============ - -On success 0 is returned. - -On error -1 is returned, and the ``errno`` variable is set -appropriately. - -Generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/dvb/fe-read-ber.rst b/Documentation/media/uapi/dvb/fe-read-ber.rst deleted file mode 100644 index e579d648687e..000000000000 --- a/Documentation/media/uapi/dvb/fe-read-ber.rst +++ /dev/null @@ -1,57 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _FE_READ_BER: - -*********** -FE_READ_BER -*********** - -Name -==== - -FE_READ_BER - -.. attention:: This ioctl is deprecated. - -Synopsis -======== - -.. c:function:: int ioctl(int fd, FE_READ_BER, uint32_t *ber) - :name: FE_READ_BER - - -Arguments -========= - -``fd`` - File descriptor returned by :c:func:`open() `. - -``ber`` - The bit error rate is stored into \*ber. - - -Description -=========== - -This ioctl call returns the bit error rate for the signal currently -received/demodulated by the front-end. For this command, read-only -access to the device is sufficient. - - -Return Value -============ - -On success 0 is returned. - -On error -1 is returned, and the ``errno`` variable is set -appropriately. - -Generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/dvb/fe-read-signal-strength.rst b/Documentation/media/uapi/dvb/fe-read-signal-strength.rst deleted file mode 100644 index 0a0c0c2ff207..000000000000 --- a/Documentation/media/uapi/dvb/fe-read-signal-strength.rst +++ /dev/null @@ -1,57 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _FE_READ_SIGNAL_STRENGTH: - -*********************** -FE_READ_SIGNAL_STRENGTH -*********************** - -Name -==== - -FE_READ_SIGNAL_STRENGTH - -.. attention:: This ioctl is deprecated. - -Synopsis -======== - -.. c:function:: int ioctl( int fd, FE_READ_SIGNAL_STRENGTH, uint16_t *strength) - :name: FE_READ_SIGNAL_STRENGTH - - -Arguments -========= - -``fd`` - File descriptor returned by :c:func:`open() `. - -``strength`` - The signal strength value is stored into \*strength. - - -Description -=========== - -This ioctl call returns the signal strength value for the signal -currently received by the front-end. For this command, read-only access -to the device is sufficient. - - -Return Value -============ - -On success 0 is returned. - -On error -1 is returned, and the ``errno`` variable is set -appropriately. - -Generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/dvb/fe-read-snr.rst b/Documentation/media/uapi/dvb/fe-read-snr.rst deleted file mode 100644 index 2a7a0d8f1fd5..000000000000 --- a/Documentation/media/uapi/dvb/fe-read-snr.rst +++ /dev/null @@ -1,57 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _FE_READ_SNR: - -*********** -FE_READ_SNR -*********** - -Name -==== - -FE_READ_SNR - -.. attention:: This ioctl is deprecated. - -Synopsis -======== - -.. c:function:: int ioctl(int fd, FE_READ_SNR, int16_t *snr) - :name: FE_READ_SNR - - -Arguments -========= - -``fd`` - File descriptor returned by :c:func:`open() `. - -``snr`` - The signal-to-noise ratio is stored into \*snr. - - -Description -=========== - -This ioctl call returns the signal-to-noise ratio for the signal -currently received by the front-end. For this command, read-only access -to the device is sufficient. - - -Return Value -============ - -On success 0 is returned. - -On error -1 is returned, and the ``errno`` variable is set -appropriately. - -Generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/dvb/fe-read-status.rst b/Documentation/media/uapi/dvb/fe-read-status.rst deleted file mode 100644 index 0dfc9fdf568f..000000000000 --- a/Documentation/media/uapi/dvb/fe-read-status.rst +++ /dev/null @@ -1,72 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _FE_READ_STATUS: - -******************** -ioctl FE_READ_STATUS -******************** - -Name -==== - -FE_READ_STATUS - Returns status information about the front-end. This call only requires - read-only access to the device - - -Synopsis -======== - -.. c:function:: int ioctl( int fd, FE_READ_STATUS, unsigned int *status ) - :name: FE_READ_STATUS - - -Arguments -========= - -``fd`` - File descriptor returned by :ref:`open() `. - -``status`` - pointer to a bitmask integer filled with the values defined by enum - :c:type:`fe_status`. - - -Description -=========== - -All Digital TV frontend devices support the ``FE_READ_STATUS`` ioctl. It is -used to check about the locking status of the frontend after being -tuned. The ioctl takes a pointer to an integer where the status will be -written. - -.. note:: - - The size of status is actually sizeof(enum fe_status), with - varies according with the architecture. This needs to be fixed in the - future. - - -int fe_status -============= - -The fe_status parameter is used to indicate the current state and/or -state changes of the frontend hardware. It is produced using the enum -:c:type:`fe_status` values on a bitmask - - -Return Value -============ - -On success 0 is returned. - -On error -1 is returned, and the ``errno`` variable is set -appropriately. - -Generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/dvb/fe-read-uncorrected-blocks.rst b/Documentation/media/uapi/dvb/fe-read-uncorrected-blocks.rst deleted file mode 100644 index 19c532f750aa..000000000000 --- a/Documentation/media/uapi/dvb/fe-read-uncorrected-blocks.rst +++ /dev/null @@ -1,59 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _FE_READ_UNCORRECTED_BLOCKS: - -************************** -FE_READ_UNCORRECTED_BLOCKS -************************** - -Name -==== - -FE_READ_UNCORRECTED_BLOCKS - -.. attention:: This ioctl is deprecated. - -Synopsis -======== - -.. c:function:: int ioctl( int fd, FE_READ_UNCORRECTED_BLOCKS, uint32_t *ublocks) - :name: FE_READ_UNCORRECTED_BLOCKS - - -Arguments -========= - -``fd`` - File descriptor returned by :c:func:`open() `. - -``ublocks`` - The total number of uncorrected blocks seen by the driver so far. - - -Description -=========== - -This ioctl call returns the number of uncorrected blocks detected by the -device driver during its lifetime. For meaningful measurements, the -increment in block count during a specific time interval should be -calculated. For this command, read-only access to the device is -sufficient. - - -Return Value -============ - -On success 0 is returned. - -On error -1 is returned, and the ``errno`` variable is set -appropriately. - -Generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/dvb/fe-set-frontend-tune-mode.rst b/Documentation/media/uapi/dvb/fe-set-frontend-tune-mode.rst deleted file mode 100644 index 36e8913170e1..000000000000 --- a/Documentation/media/uapi/dvb/fe-set-frontend-tune-mode.rst +++ /dev/null @@ -1,64 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _FE_SET_FRONTEND_TUNE_MODE: - -******************************* -ioctl FE_SET_FRONTEND_TUNE_MODE -******************************* - -Name -==== - -FE_SET_FRONTEND_TUNE_MODE - Allow setting tuner mode flags to the frontend. - - -Synopsis -======== - -.. c:function:: int ioctl( int fd, FE_SET_FRONTEND_TUNE_MODE, unsigned int flags ) - :name: FE_SET_FRONTEND_TUNE_MODE - - -Arguments -========= - -``fd`` - File descriptor returned by :ref:`open() `. - -``flags`` - Valid flags: - - - 0 - normal tune mode - - - ``FE_TUNE_MODE_ONESHOT`` - When set, this flag will disable any - zigzagging or other "normal" tuning behaviour. Additionally, - there will be no automatic monitoring of the lock status, and - hence no frontend events will be generated. If a frontend device - is closed, this flag will be automatically turned off when the - device is reopened read-write. - - -Description -=========== - -Allow setting tuner mode flags to the frontend, between 0 (normal) or -``FE_TUNE_MODE_ONESHOT`` mode - - -Return Value -============ - -On success 0 is returned. - -On error -1 is returned, and the ``errno`` variable is set -appropriately. - -Generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/dvb/fe-set-frontend.rst b/Documentation/media/uapi/dvb/fe-set-frontend.rst deleted file mode 100644 index 23caae2588d2..000000000000 --- a/Documentation/media/uapi/dvb/fe-set-frontend.rst +++ /dev/null @@ -1,78 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _FE_SET_FRONTEND: - -*************** -FE_SET_FRONTEND -*************** - -.. attention:: This ioctl is deprecated. - -Name -==== - -FE_SET_FRONTEND - - -Synopsis -======== - -.. c:function:: int ioctl(int fd, FE_SET_FRONTEND, struct dvb_frontend_parameters *p) - :name: FE_SET_FRONTEND - - -Arguments -========= - -``fd`` - File descriptor returned by :c:func:`open() `. - -``p`` - Points to parameters for tuning operation. - - -Description -=========== - -This ioctl call starts a tuning operation using specified parameters. -The result of this call will be successful if the parameters were valid -and the tuning could be initiated. The result of the tuning operation in -itself, however, will arrive asynchronously as an event (see -documentation for :ref:`FE_GET_EVENT` and -FrontendEvent.) If a new :ref:`FE_SET_FRONTEND` -operation is initiated before the previous one was completed, the -previous operation will be aborted in favor of the new one. This command -requires read/write access to the device. - - -Return Value -============ - -On success 0 is returned. - -On error -1 is returned, and the ``errno`` variable is set -appropriately. - -.. tabularcolumns:: |p{2.5cm}|p{15.0cm}| - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - :widths: 1 16 - - - .. row 1 - - - ``EINVAL`` - - - Maximum supported symbol rate reached. - - -Generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/dvb/fe-set-tone.rst b/Documentation/media/uapi/dvb/fe-set-tone.rst deleted file mode 100644 index fb605e8c9fc4..000000000000 --- a/Documentation/media/uapi/dvb/fe-set-tone.rst +++ /dev/null @@ -1,65 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _FE_SET_TONE: - -***************** -ioctl FE_SET_TONE -***************** - -Name -==== - -FE_SET_TONE - Sets/resets the generation of the continuous 22kHz tone. - - -Synopsis -======== - -.. c:function:: int ioctl( int fd, FE_SET_TONE, enum fe_sec_tone_mode tone ) - :name: FE_SET_TONE - - -Arguments -========= - -``fd`` - File descriptor returned by :ref:`open() `. - -``tone`` - an integer enumered value described at :c:type:`fe_sec_tone_mode` - - -Description -=========== - -This ioctl is used to set the generation of the continuous 22kHz tone. -This call requires read/write permissions. - -Usually, satellite antenna subsystems require that the digital TV device -to send a 22kHz tone in order to select between high/low band on some -dual-band LNBf. It is also used to send signals to DiSEqC equipment, but -this is done using the DiSEqC ioctls. - -.. attention:: If more than one device is connected to the same antenna, - setting a tone may interfere on other devices, as they may lose the - capability of selecting the band. So, it is recommended that applications - would change to SEC_TONE_OFF when the device is not used. - - -Return Value -============ - -On success 0 is returned. - -On error -1 is returned, and the ``errno`` variable is set -appropriately. - -Generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/dvb/fe-set-voltage.rst b/Documentation/media/uapi/dvb/fe-set-voltage.rst deleted file mode 100644 index c81a8e6a59aa..000000000000 --- a/Documentation/media/uapi/dvb/fe-set-voltage.rst +++ /dev/null @@ -1,69 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _FE_SET_VOLTAGE: - -******************** -ioctl FE_SET_VOLTAGE -******************** - -Name -==== - -FE_SET_VOLTAGE - Allow setting the DC level sent to the antenna subsystem. - - -Synopsis -======== - -.. c:function:: int ioctl( int fd, FE_SET_VOLTAGE, enum fe_sec_voltage voltage ) - :name: FE_SET_VOLTAGE - - -Arguments -========= - -``fd`` - File descriptor returned by :ref:`open() `. - -``voltage`` - an integer enumered value described at :c:type:`fe_sec_voltage` - - -Description -=========== - -This ioctl allows to set the DC voltage level sent through the antenna -cable to 13V, 18V or off. - -Usually, a satellite antenna subsystems require that the digital TV -device to send a DC voltage to feed power to the LNBf. Depending on the -LNBf type, the polarization or the intermediate frequency (IF) of the -LNBf can controlled by the voltage level. Other devices (for example, -the ones that implement DISEqC and multipoint LNBf's don't need to -control the voltage level, provided that either 13V or 18V is sent to -power up the LNBf. - -.. attention:: if more than one device is connected to the same antenna, - setting a voltage level may interfere on other devices, as they may lose - the capability of setting polarization or IF. So, on those cases, setting - the voltage to SEC_VOLTAGE_OFF while the device is not is used is - recommended. - - -Return Value -============ - -On success 0 is returned. - -On error -1 is returned, and the ``errno`` variable is set -appropriately. - -Generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/dvb/fe-type-t.rst b/Documentation/media/uapi/dvb/fe-type-t.rst deleted file mode 100644 index 9720d2f7ba35..000000000000 --- a/Documentation/media/uapi/dvb/fe-type-t.rst +++ /dev/null @@ -1,98 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -************* -Frontend type -************* - -For historical reasons, frontend types are named by the type of -modulation used in transmission. The fontend types are given by -fe_type_t type, defined as: - - -.. c:type:: fe_type - -.. tabularcolumns:: |p{6.6cm}|p{2.2cm}|p{8.7cm}| - -.. flat-table:: Frontend types - :header-rows: 1 - :stub-columns: 0 - :widths: 3 1 4 - - - - .. row 1 - - - fe_type - - - Description - - - :ref:`DTV_DELIVERY_SYSTEM ` equivalent - type - - - .. row 2 - - - .. _FE-QPSK: - - ``FE_QPSK`` - - - For DVB-S standard - - - ``SYS_DVBS`` - - - .. row 3 - - - .. _FE-QAM: - - ``FE_QAM`` - - - For DVB-C annex A standard - - - ``SYS_DVBC_ANNEX_A`` - - - .. row 4 - - - .. _FE-OFDM: - - ``FE_OFDM`` - - - For DVB-T standard - - - ``SYS_DVBT`` - - - .. row 5 - - - .. _FE-ATSC: - - ``FE_ATSC`` - - - For ATSC standard (terrestrial) or for DVB-C Annex B (cable) used - in US. - - - ``SYS_ATSC`` (terrestrial) or ``SYS_DVBC_ANNEX_B`` (cable) - - -Newer formats like DVB-S2, ISDB-T, ISDB-S and DVB-T2 are not described -at the above, as they're supported via the new -:ref:`FE_GET_PROPERTY/FE_GET_SET_PROPERTY ` -ioctl's, using the :ref:`DTV_DELIVERY_SYSTEM ` -parameter. - -In the old days, struct :c:type:`dvb_frontend_info` -used to contain ``fe_type_t`` field to indicate the delivery systems, -filled with either ``FE_QPSK, FE_QAM, FE_OFDM`` or ``FE_ATSC``. While this -is still filled to keep backward compatibility, the usage of this field -is deprecated, as it can report just one delivery system, but some -devices support multiple delivery systems. Please use -:ref:`DTV_ENUM_DELSYS ` instead. - -On devices that support multiple delivery systems, struct -:c:type:`dvb_frontend_info`::``fe_type_t`` is -filled with the currently standard, as selected by the last call to -:ref:`FE_SET_PROPERTY ` using the -:ref:`DTV_DELIVERY_SYSTEM ` property. diff --git a/Documentation/media/uapi/dvb/fe_property_parameters.rst b/Documentation/media/uapi/dvb/fe_property_parameters.rst deleted file mode 100644 index 2fd2954d8dae..000000000000 --- a/Documentation/media/uapi/dvb/fe_property_parameters.rst +++ /dev/null @@ -1,1014 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _fe_property_parameters: - -****************************** -Digital TV property parameters -****************************** - -There are several different Digital TV parameters that can be used by -:ref:`FE_SET_PROPERTY and FE_GET_PROPERTY ioctls`. -This section describes each of them. Please notice, however, that only -a subset of them are needed to setup a frontend. - - -.. _DTV-UNDEFINED: - -DTV_UNDEFINED -============= - -Used internally. A GET/SET operation for it won't change or return -anything. - - -.. _DTV-TUNE: - -DTV_TUNE -======== - -Interpret the cache of data, build either a traditional frontend -tunerequest so we can pass validation in the ``FE_SET_FRONTEND`` ioctl. - - -.. _DTV-CLEAR: - -DTV_CLEAR -========= - -Reset a cache of data specific to the frontend here. This does not -effect hardware. - - -.. _DTV-FREQUENCY: - -DTV_FREQUENCY -============= - -Frequency of the digital TV transponder/channel. - -.. note:: - - #. For satellite delivery systems, the frequency is in kHz. - - #. For cable and terrestrial delivery systems, the frequency is in - Hz. - - #. On most delivery systems, the frequency is the center frequency - of the transponder/channel. The exception is for ISDB-T, where - the main carrier has a 1/7 offset from the center. - - #. For ISDB-T, the channels are usually transmitted with an offset of - about 143kHz. E.g. a valid frequency could be 474,143 kHz. The - stepping is bound to the bandwidth of the channel which is - typically 6MHz. - - #. In ISDB-Tsb, the channel consists of only one or three segments the - frequency step is 429kHz, 3*429 respectively. - - -.. _DTV-MODULATION: - -DTV_MODULATION -============== - -Specifies the frontend modulation type for delivery systems that -supports more multiple modulations. - -The modulation can be one of the types defined by enum :c:type:`fe_modulation`. - -Most of the digital TV standards offers more than one possible -modulation type. - -The table below presents a summary of the types of modulation types -supported by each delivery system, as currently defined by specs. - -======================= ======================================================= -Standard Modulation types -======================= ======================================================= -ATSC (version 1) 8-VSB and 16-VSB. -DMTB 4-QAM, 16-QAM, 32-QAM, 64-QAM and 4-QAM-NR. -DVB-C Annex A/C 16-QAM, 32-QAM, 64-QAM and 256-QAM. -DVB-C Annex B 64-QAM. -DVB-T QPSK, 16-QAM and 64-QAM. -DVB-T2 QPSK, 16-QAM, 64-QAM and 256-QAM. -DVB-S No need to set. It supports only QPSK. -DVB-S2 QPSK, 8-PSK, 16-APSK and 32-APSK. -ISDB-T QPSK, DQPSK, 16-QAM and 64-QAM. -ISDB-S 8-PSK, QPSK and BPSK. -======================= ======================================================= - -.. note:: - - Please notice that some of the above modulation types may not be - defined currently at the Kernel. The reason is simple: no driver - needed such definition yet. - - -.. _DTV-BANDWIDTH-HZ: - -DTV_BANDWIDTH_HZ -================ - -Bandwidth for the channel, in HZ. - -Should be set only for terrestrial delivery systems. - -Possible values: ``1712000``, ``5000000``, ``6000000``, ``7000000``, -``8000000``, ``10000000``. - -======================= ======================================================= -Terrestrial Standard Possible values for bandwidth -======================= ======================================================= -ATSC (version 1) No need to set. It is always 6MHz. -DMTB No need to set. It is always 8MHz. -DVB-T 6MHz, 7MHz and 8MHz. -DVB-T2 1.172 MHz, 5MHz, 6MHz, 7MHz, 8MHz and 10MHz -ISDB-T 5MHz, 6MHz, 7MHz and 8MHz, although most places - use 6MHz. -======================= ======================================================= - - -.. note:: - - - #. For ISDB-Tsb, the bandwidth can vary depending on the number of - connected segments. - - It can be easily derived from other parameters - (DTV_ISDBT_SB_SEGMENT_IDX, DTV_ISDBT_SB_SEGMENT_COUNT). - - #. On Satellite and Cable delivery systems, the bandwidth depends on - the symbol rate. So, the Kernel will silently ignore any setting - :ref:`DTV-BANDWIDTH-HZ`. I will however fill it back with a - bandwidth estimation. - - Such bandwidth estimation takes into account the symbol rate set with - :ref:`DTV-SYMBOL-RATE`, and the rolloff factor, with is fixed for - DVB-C and DVB-S. - - For DVB-S2, the rolloff should also be set via :ref:`DTV-ROLLOFF`. - - -.. _DTV-INVERSION: - -DTV_INVERSION -============= - -Specifies if the frontend should do spectral inversion or not. - -The acceptable values are defined by :c:type:`fe_spectral_inversion`. - - -.. _DTV-DISEQC-MASTER: - -DTV_DISEQC_MASTER -================= - -Currently not implemented. - - -.. _DTV-SYMBOL-RATE: - -DTV_SYMBOL_RATE -=============== - -Used on cable and satellite delivery systems. - -Digital TV symbol rate, in bauds (symbols/second). - - -.. _DTV-INNER-FEC: - -DTV_INNER_FEC -============= - -Used on cable and satellite delivery systems. - -The acceptable values are defined by :c:type:`fe_code_rate`. - - -.. _DTV-VOLTAGE: - -DTV_VOLTAGE -=========== - -Used on satellite delivery systems. - -The voltage is usually used with non-DiSEqC capable LNBs to switch the -polarzation (horizontal/vertical). When using DiSEqC epuipment this -voltage has to be switched consistently to the DiSEqC commands as -described in the DiSEqC spec. - -The acceptable values are defined by :c:type:`fe_sec_voltage`. - - -.. _DTV-TONE: - -DTV_TONE -======== - -Currently not used. - - -.. _DTV-PILOT: - -DTV_PILOT -========= - -Used on DVB-S2. - -Sets DVB-S2 pilot. - -The acceptable values are defined by :c:type:`fe_pilot`. - - -.. _DTV-ROLLOFF: - -DTV_ROLLOFF -=========== - -Used on DVB-S2. - -Sets DVB-S2 rolloff. - -The acceptable values are defined by :c:type:`fe_rolloff`. - - -.. _DTV-DISEQC-SLAVE-REPLY: - -DTV_DISEQC_SLAVE_REPLY -====================== - -Currently not implemented. - - -.. _DTV-FE-CAPABILITY-COUNT: - -DTV_FE_CAPABILITY_COUNT -======================= - -Currently not implemented. - - -.. _DTV-FE-CAPABILITY: - -DTV_FE_CAPABILITY -================= - -Currently not implemented. - - -.. _DTV-DELIVERY-SYSTEM: - -DTV_DELIVERY_SYSTEM -=================== - -Specifies the type of the delivery system. - -The acceptable values are defined by :c:type:`fe_delivery_system`. - - -.. _DTV-ISDBT-PARTIAL-RECEPTION: - -DTV_ISDBT_PARTIAL_RECEPTION -=========================== - -Used only on ISDB. - -If ``DTV_ISDBT_SOUND_BROADCASTING`` is '0' this bit-field represents -whether the channel is in partial reception mode or not. - -If '1' ``DTV_ISDBT_LAYERA_*`` values are assigned to the center segment -and ``DTV_ISDBT_LAYERA_SEGMENT_COUNT`` has to be '1'. - -If in addition ``DTV_ISDBT_SOUND_BROADCASTING`` is '1' -``DTV_ISDBT_PARTIAL_RECEPTION`` represents whether this ISDB-Tsb channel -is consisting of one segment and layer or three segments and two layers. - -Possible values: 0, 1, -1 (AUTO) - - -.. _DTV-ISDBT-SOUND-BROADCASTING: - -DTV_ISDBT_SOUND_BROADCASTING -============================ - -Used only on ISDB. - -This field represents whether the other DTV_ISDBT_*-parameters are -referring to an ISDB-T and an ISDB-Tsb channel. (See also -``DTV_ISDBT_PARTIAL_RECEPTION``). - -Possible values: 0, 1, -1 (AUTO) - - -.. _DTV-ISDBT-SB-SUBCHANNEL-ID: - -DTV_ISDBT_SB_SUBCHANNEL_ID -========================== - -Used only on ISDB. - -This field only applies if ``DTV_ISDBT_SOUND_BROADCASTING`` is '1'. - -(Note of the author: This might not be the correct description of the -``SUBCHANNEL-ID`` in all details, but it is my understanding of the -technical background needed to program a device) - -An ISDB-Tsb channel (1 or 3 segments) can be broadcasted alone or in a -set of connected ISDB-Tsb channels. In this set of channels every -channel can be received independently. The number of connected ISDB-Tsb -segment can vary, e.g. depending on the frequency spectrum bandwidth -available. - -Example: Assume 8 ISDB-Tsb connected segments are broadcasted. The -broadcaster has several possibilities to put those channels in the air: -Assuming a normal 13-segment ISDB-T spectrum he can align the 8 segments -from position 1-8 to 5-13 or anything in between. - -The underlying layer of segments are subchannels: each segment is -consisting of several subchannels with a predefined IDs. A sub-channel -is used to help the demodulator to synchronize on the channel. - -An ISDB-T channel is always centered over all sub-channels. As for the -example above, in ISDB-Tsb it is no longer as simple as that. - -``The DTV_ISDBT_SB_SUBCHANNEL_ID`` parameter is used to give the -sub-channel ID of the segment to be demodulated. - -Possible values: 0 .. 41, -1 (AUTO) - - -.. _DTV-ISDBT-SB-SEGMENT-IDX: - -DTV_ISDBT_SB_SEGMENT_IDX -======================== - -Used only on ISDB. - -This field only applies if ``DTV_ISDBT_SOUND_BROADCASTING`` is '1'. - -``DTV_ISDBT_SB_SEGMENT_IDX`` gives the index of the segment to be -demodulated for an ISDB-Tsb channel where several of them are -transmitted in the connected manner. - -Possible values: 0 .. ``DTV_ISDBT_SB_SEGMENT_COUNT`` - 1 - -Note: This value cannot be determined by an automatic channel search. - - -.. _DTV-ISDBT-SB-SEGMENT-COUNT: - -DTV_ISDBT_SB_SEGMENT_COUNT -========================== - -Used only on ISDB. - -This field only applies if ``DTV_ISDBT_SOUND_BROADCASTING`` is '1'. - -``DTV_ISDBT_SB_SEGMENT_COUNT`` gives the total count of connected -ISDB-Tsb channels. - -Possible values: 1 .. 13 - -Note: This value cannot be determined by an automatic channel search. - - -.. _isdb-hierq-layers: - -DTV-ISDBT-LAYER[A-C] parameters -=============================== - -Used only on ISDB. - -ISDB-T channels can be coded hierarchically. As opposed to DVB-T in -ISDB-T hierarchical layers can be decoded simultaneously. For that -reason a ISDB-T demodulator has 3 Viterbi and 3 Reed-Solomon decoders. - -ISDB-T has 3 hierarchical layers which each can use a part of the -available segments. The total number of segments over all layers has to -13 in ISDB-T. - -There are 3 parameter sets, for Layers A, B and C. - - -.. _DTV-ISDBT-LAYER-ENABLED: - -DTV_ISDBT_LAYER_ENABLED ------------------------ - -Used only on ISDB. - -Hierarchical reception in ISDB-T is achieved by enabling or disabling -layers in the decoding process. Setting all bits of -``DTV_ISDBT_LAYER_ENABLED`` to '1' forces all layers (if applicable) to -be demodulated. This is the default. - -If the channel is in the partial reception mode -(``DTV_ISDBT_PARTIAL_RECEPTION`` = 1) the central segment can be decoded -independently of the other 12 segments. In that mode layer A has to have -a ``SEGMENT_COUNT`` of 1. - -In ISDB-Tsb only layer A is used, it can be 1 or 3 in ISDB-Tsb according -to ``DTV_ISDBT_PARTIAL_RECEPTION``. ``SEGMENT_COUNT`` must be filled -accordingly. - -Only the values of the first 3 bits are used. Other bits will be silently ignored: - -``DTV_ISDBT_LAYER_ENABLED`` bit 0: layer A enabled - -``DTV_ISDBT_LAYER_ENABLED`` bit 1: layer B enabled - -``DTV_ISDBT_LAYER_ENABLED`` bit 2: layer C enabled - -``DTV_ISDBT_LAYER_ENABLED`` bits 3-31: unused - - -.. _DTV-ISDBT-LAYER-FEC: - -DTV_ISDBT_LAYER[A-C]_FEC ------------------------- - -Used only on ISDB. - -The Forward Error Correction mechanism used by a given ISDB Layer, as -defined by :c:type:`fe_code_rate`. - - -Possible values are: ``FEC_AUTO``, ``FEC_1_2``, ``FEC_2_3``, ``FEC_3_4``, -``FEC_5_6``, ``FEC_7_8`` - - -.. _DTV-ISDBT-LAYER-MODULATION: - -DTV_ISDBT_LAYER[A-C]_MODULATION -------------------------------- - -Used only on ISDB. - -The modulation used by a given ISDB Layer, as defined by -:c:type:`fe_modulation`. - -Possible values are: ``QAM_AUTO``, ``QPSK``, ``QAM_16``, ``QAM_64``, ``DQPSK`` - -.. note:: - - #. If layer C is ``DQPSK``, then layer B has to be ``DQPSK``. - - #. If layer B is ``DQPSK`` and ``DTV_ISDBT_PARTIAL_RECEPTION``\ = 0, - then layer has to be ``DQPSK``. - - -.. _DTV-ISDBT-LAYER-SEGMENT-COUNT: - -DTV_ISDBT_LAYER[A-C]_SEGMENT_COUNT ----------------------------------- - -Used only on ISDB. - -Possible values: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, -1 (AUTO) - -Note: Truth table for ``DTV_ISDBT_SOUND_BROADCASTING`` and -``DTV_ISDBT_PARTIAL_RECEPTION`` and ``LAYER[A-C]_SEGMENT_COUNT`` - -.. _isdbt-layer_seg-cnt-table: - -.. flat-table:: Truth table for ISDB-T Sound Broadcasting - :header-rows: 1 - :stub-columns: 0 - - - - .. row 1 - - - Partial Reception - - - Sound Broadcasting - - - Layer A width - - - Layer B width - - - Layer C width - - - total width - - - .. row 2 - - - 0 - - - 0 - - - 1 .. 13 - - - 1 .. 13 - - - 1 .. 13 - - - 13 - - - .. row 3 - - - 1 - - - 0 - - - 1 - - - 1 .. 13 - - - 1 .. 13 - - - 13 - - - .. row 4 - - - 0 - - - 1 - - - 1 - - - 0 - - - 0 - - - 1 - - - .. row 5 - - - 1 - - - 1 - - - 1 - - - 2 - - - 0 - - - 13 - - - -.. _DTV-ISDBT-LAYER-TIME-INTERLEAVING: - -DTV_ISDBT_LAYER[A-C]_TIME_INTERLEAVING --------------------------------------- - -Used only on ISDB. - -Valid values: 0, 1, 2, 4, -1 (AUTO) - -when DTV_ISDBT_SOUND_BROADCASTING is active, value 8 is also valid. - -Note: The real time interleaving length depends on the mode (fft-size). -The values here are referring to what can be found in the -TMCC-structure, as shown in the table below. - - -.. c:type:: isdbt_layer_interleaving_table - -.. flat-table:: ISDB-T time interleaving modes - :header-rows: 1 - :stub-columns: 0 - - - - .. row 1 - - - ``DTV_ISDBT_LAYER[A-C]_TIME_INTERLEAVING`` - - - Mode 1 (2K FFT) - - - Mode 2 (4K FFT) - - - Mode 3 (8K FFT) - - - .. row 2 - - - 0 - - - 0 - - - 0 - - - 0 - - - .. row 3 - - - 1 - - - 4 - - - 2 - - - 1 - - - .. row 4 - - - 2 - - - 8 - - - 4 - - - 2 - - - .. row 5 - - - 4 - - - 16 - - - 8 - - - 4 - - - -.. _DTV-ATSCMH-FIC-VER: - -DTV_ATSCMH_FIC_VER ------------------- - -Used only on ATSC-MH. - -Version number of the FIC (Fast Information Channel) signaling data. - -FIC is used for relaying information to allow rapid service acquisition -by the receiver. - -Possible values: 0, 1, 2, 3, ..., 30, 31 - - -.. _DTV-ATSCMH-PARADE-ID: - -DTV_ATSCMH_PARADE_ID --------------------- - -Used only on ATSC-MH. - -Parade identification number - -A parade is a collection of up to eight MH groups, conveying one or two -ensembles. - -Possible values: 0, 1, 2, 3, ..., 126, 127 - - -.. _DTV-ATSCMH-NOG: - -DTV_ATSCMH_NOG --------------- - -Used only on ATSC-MH. - -Number of MH groups per MH subframe for a designated parade. - -Possible values: 1, 2, 3, 4, 5, 6, 7, 8 - - -.. _DTV-ATSCMH-TNOG: - -DTV_ATSCMH_TNOG ---------------- - -Used only on ATSC-MH. - -Total number of MH groups including all MH groups belonging to all MH -parades in one MH subframe. - -Possible values: 0, 1, 2, 3, ..., 30, 31 - - -.. _DTV-ATSCMH-SGN: - -DTV_ATSCMH_SGN --------------- - -Used only on ATSC-MH. - -Start group number. - -Possible values: 0, 1, 2, 3, ..., 14, 15 - - -.. _DTV-ATSCMH-PRC: - -DTV_ATSCMH_PRC --------------- - -Used only on ATSC-MH. - -Parade repetition cycle. - -Possible values: 1, 2, 3, 4, 5, 6, 7, 8 - - -.. _DTV-ATSCMH-RS-FRAME-MODE: - -DTV_ATSCMH_RS_FRAME_MODE ------------------------- - -Used only on ATSC-MH. - -Reed Solomon (RS) frame mode. - -The acceptable values are defined by :c:type:`atscmh_rs_frame_mode`. - - -.. _DTV-ATSCMH-RS-FRAME-ENSEMBLE: - -DTV_ATSCMH_RS_FRAME_ENSEMBLE ----------------------------- - -Used only on ATSC-MH. - -Reed Solomon(RS) frame ensemble. - -The acceptable values are defined by :c:type:`atscmh_rs_frame_ensemble`. - - -.. _DTV-ATSCMH-RS-CODE-MODE-PRI: - -DTV_ATSCMH_RS_CODE_MODE_PRI ---------------------------- - -Used only on ATSC-MH. - -Reed Solomon (RS) code mode (primary). - -The acceptable values are defined by :c:type:`atscmh_rs_code_mode`. - - -.. _DTV-ATSCMH-RS-CODE-MODE-SEC: - -DTV_ATSCMH_RS_CODE_MODE_SEC ---------------------------- - -Used only on ATSC-MH. - -Reed Solomon (RS) code mode (secondary). - -The acceptable values are defined by :c:type:`atscmh_rs_code_mode`. - - -.. _DTV-ATSCMH-SCCC-BLOCK-MODE: - -DTV_ATSCMH_SCCC_BLOCK_MODE --------------------------- - -Used only on ATSC-MH. - -Series Concatenated Convolutional Code Block Mode. - -The acceptable values are defined by :c:type:`atscmh_sccc_block_mode`. - - -.. _DTV-ATSCMH-SCCC-CODE-MODE-A: - -DTV_ATSCMH_SCCC_CODE_MODE_A ---------------------------- - -Used only on ATSC-MH. - -Series Concatenated Convolutional Code Rate. - -The acceptable values are defined by :c:type:`atscmh_sccc_code_mode`. - -.. _DTV-ATSCMH-SCCC-CODE-MODE-B: - -DTV_ATSCMH_SCCC_CODE_MODE_B ---------------------------- - -Used only on ATSC-MH. - -Series Concatenated Convolutional Code Rate. - -Possible values are the same as documented on enum -:c:type:`atscmh_sccc_code_mode`. - - -.. _DTV-ATSCMH-SCCC-CODE-MODE-C: - -DTV_ATSCMH_SCCC_CODE_MODE_C ---------------------------- - -Used only on ATSC-MH. - -Series Concatenated Convolutional Code Rate. - -Possible values are the same as documented on enum -:c:type:`atscmh_sccc_code_mode`. - - -.. _DTV-ATSCMH-SCCC-CODE-MODE-D: - -DTV_ATSCMH_SCCC_CODE_MODE_D ---------------------------- - -Used only on ATSC-MH. - -Series Concatenated Convolutional Code Rate. - -Possible values are the same as documented on enum -:c:type:`atscmh_sccc_code_mode`. - - -.. _DTV-API-VERSION: - -DTV_API_VERSION -=============== - -Returns the major/minor version of the Digital TV API - - -.. _DTV-CODE-RATE-HP: - -DTV_CODE_RATE_HP -================ - -Used on terrestrial transmissions. - -The acceptable values are defined by :c:type:`fe_transmit_mode`. - - -.. _DTV-CODE-RATE-LP: - -DTV_CODE_RATE_LP -================ - -Used on terrestrial transmissions. - -The acceptable values are defined by :c:type:`fe_transmit_mode`. - - -.. _DTV-GUARD-INTERVAL: - -DTV_GUARD_INTERVAL -================== - -The acceptable values are defined by :c:type:`fe_guard_interval`. - -.. note:: - - #. If ``DTV_GUARD_INTERVAL`` is set the ``GUARD_INTERVAL_AUTO`` the - hardware will try to find the correct guard interval (if capable) and - will use TMCC to fill in the missing parameters. - #. Intervals ``GUARD_INTERVAL_1_128``, ``GUARD_INTERVAL_19_128`` - and ``GUARD_INTERVAL_19_256`` are used only for DVB-T2 at - present. - #. Intervals ``GUARD_INTERVAL_PN420``, ``GUARD_INTERVAL_PN595`` and - ``GUARD_INTERVAL_PN945`` are used only for DMTB at the present. - On such standard, only those intervals and ``GUARD_INTERVAL_AUTO`` - are valid. - -.. _DTV-TRANSMISSION-MODE: - -DTV_TRANSMISSION_MODE -===================== - - -Used only on OFTM-based standards, e. g. DVB-T/T2, ISDB-T, DTMB. - -Specifies the FFT size (with corresponds to the approximate number of -carriers) used by the standard. - -The acceptable values are defined by :c:type:`fe_transmit_mode`. - -.. note:: - - #. ISDB-T supports three carrier/symbol-size: 8K, 4K, 2K. It is called - **mode** on such standard, and are numbered from 1 to 3: - - ==== ======== ======================== - Mode FFT size Transmission mode - ==== ======== ======================== - 1 2K ``TRANSMISSION_MODE_2K`` - 2 4K ``TRANSMISSION_MODE_4K`` - 3 8K ``TRANSMISSION_MODE_8K`` - ==== ======== ======================== - - #. If ``DTV_TRANSMISSION_MODE`` is set the ``TRANSMISSION_MODE_AUTO`` - the hardware will try to find the correct FFT-size (if capable) and - will use TMCC to fill in the missing parameters. - - #. DVB-T specifies 2K and 8K as valid sizes. - - #. DVB-T2 specifies 1K, 2K, 4K, 8K, 16K and 32K. - - #. DTMB specifies C1 and C3780. - - -.. _DTV-HIERARCHY: - -DTV_HIERARCHY -============= - -Used only on DVB-T and DVB-T2. - -Frontend hierarchy. - -The acceptable values are defined by :c:type:`fe_hierarchy`. - - -.. _DTV-STREAM-ID: - -DTV_STREAM_ID -============= - -Used on DVB-S2, DVB-T2 and ISDB-S. - -DVB-S2, DVB-T2 and ISDB-S support the transmission of several streams on -a single transport stream. This property enables the digital TV driver to -handle substream filtering, when supported by the hardware. By default, -substream filtering is disabled. - -For DVB-S2 and DVB-T2, the valid substream id range is from 0 to 255. - -For ISDB, the valid substream id range is from 1 to 65535. - -To disable it, you should use the special macro NO_STREAM_ID_FILTER. - -Note: any value outside the id range also disables filtering. - - -.. _DTV-DVBT2-PLP-ID-LEGACY: - -DTV_DVBT2_PLP_ID_LEGACY -======================= - -Obsolete, replaced with DTV_STREAM_ID. - - -.. _DTV-ENUM-DELSYS: - -DTV_ENUM_DELSYS -=============== - -A Multi standard frontend needs to advertise the delivery systems -provided. Applications need to enumerate the provided delivery systems, -before using any other operation with the frontend. Prior to it's -introduction, FE_GET_INFO was used to determine a frontend type. A -frontend which provides more than a single delivery system, -FE_GET_INFO doesn't help much. Applications which intends to use a -multistandard frontend must enumerate the delivery systems associated -with it, rather than trying to use FE_GET_INFO. In the case of a -legacy frontend, the result is just the same as with FE_GET_INFO, but -in a more structured format - -The acceptable values are defined by :c:type:`fe_delivery_system`. - - -.. _DTV-INTERLEAVING: - -DTV_INTERLEAVING -================ - -Time interleaving to be used. - -The acceptable values are defined by :c:type:`fe_interleaving`. - - -.. _DTV-LNA: - -DTV_LNA -======= - -Low-noise amplifier. - -Hardware might offer controllable LNA which can be set manually using -that parameter. Usually LNA could be found only from terrestrial devices -if at all. - -Possible values: 0, 1, LNA_AUTO - -0, LNA off - -1, LNA on - -use the special macro LNA_AUTO to set LNA auto - - -.. _DTV-SCRAMBLING-SEQUENCE-INDEX: - -DTV_SCRAMBLING_SEQUENCE_INDEX -============================= - -Used on DVB-S2. - -This 18 bit field, when present, carries the index of the DVB-S2 physical -layer scrambling sequence as defined in clause 5.5.4 of EN 302 307. -There is no explicit signalling method to convey scrambling sequence index -to the receiver. If S2 satellite delivery system descriptor is available -it can be used to read the scrambling sequence index (EN 300 468 table 41). - -By default, gold scrambling sequence index 0 is used. - -The valid scrambling sequence index range is from 0 to 262142. diff --git a/Documentation/media/uapi/dvb/frontend-header.rst b/Documentation/media/uapi/dvb/frontend-header.rst deleted file mode 100644 index 635fb4251214..000000000000 --- a/Documentation/media/uapi/dvb/frontend-header.rst +++ /dev/null @@ -1,13 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -Frontend uAPI data types -======================== - -.. kernel-doc:: include/uapi/linux/dvb/frontend.h diff --git a/Documentation/media/uapi/dvb/frontend-property-cable-systems.rst b/Documentation/media/uapi/dvb/frontend-property-cable-systems.rst deleted file mode 100644 index 97fbfc228c10..000000000000 --- a/Documentation/media/uapi/dvb/frontend-property-cable-systems.rst +++ /dev/null @@ -1,82 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _frontend-property-cable-systems: - -***************************************** -Properties used on cable delivery systems -***************************************** - - -.. _dvbc-params: - -DVB-C delivery system -===================== - -The DVB-C Annex-A is the widely used cable standard. Transmission uses -QAM modulation. - -The DVB-C Annex-C is optimized for 6MHz, and is used in Japan. It -supports a subset of the Annex A modulation types, and a roll-off of -0.13, instead of 0.15 - -The following parameters are valid for DVB-C Annex A/C: - -- :ref:`DTV_API_VERSION ` - -- :ref:`DTV_DELIVERY_SYSTEM ` - -- :ref:`DTV_TUNE ` - -- :ref:`DTV_CLEAR ` - -- :ref:`DTV_FREQUENCY ` - -- :ref:`DTV_MODULATION ` - -- :ref:`DTV_INVERSION ` - -- :ref:`DTV_SYMBOL_RATE ` - -- :ref:`DTV_INNER_FEC ` - -- :ref:`DTV_LNA ` - -In addition, the :ref:`DTV QoS statistics ` -are also valid. - - -.. _dvbc-annex-b-params: - -DVB-C Annex B delivery system -============================= - -The DVB-C Annex-B is only used on a few Countries like the United -States. - -The following parameters are valid for DVB-C Annex B: - -- :ref:`DTV_API_VERSION ` - -- :ref:`DTV_DELIVERY_SYSTEM ` - -- :ref:`DTV_TUNE ` - -- :ref:`DTV_CLEAR ` - -- :ref:`DTV_FREQUENCY ` - -- :ref:`DTV_MODULATION ` - -- :ref:`DTV_INVERSION ` - -- :ref:`DTV_LNA ` - -In addition, the :ref:`DTV QoS statistics ` -are also valid. diff --git a/Documentation/media/uapi/dvb/frontend-property-satellite-systems.rst b/Documentation/media/uapi/dvb/frontend-property-satellite-systems.rst deleted file mode 100644 index 2bc880a3c826..000000000000 --- a/Documentation/media/uapi/dvb/frontend-property-satellite-systems.rst +++ /dev/null @@ -1,112 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _frontend-property-satellite-systems: - -********************************************* -Properties used on satellite delivery systems -********************************************* - - -.. _dvbs-params: - -DVB-S delivery system -===================== - -The following parameters are valid for DVB-S: - -- :ref:`DTV_API_VERSION ` - -- :ref:`DTV_DELIVERY_SYSTEM ` - -- :ref:`DTV_TUNE ` - -- :ref:`DTV_CLEAR ` - -- :ref:`DTV_FREQUENCY ` - -- :ref:`DTV_INVERSION ` - -- :ref:`DTV_SYMBOL_RATE ` - -- :ref:`DTV_INNER_FEC ` - -- :ref:`DTV_VOLTAGE ` - -- :ref:`DTV_TONE ` - -In addition, the :ref:`DTV QoS statistics ` -are also valid. - -Future implementations might add those two missing parameters: - -- :ref:`DTV_DISEQC_MASTER ` - -- :ref:`DTV_DISEQC_SLAVE_REPLY ` - - -.. _dvbs2-params: - -DVB-S2 delivery system -====================== - -In addition to all parameters valid for DVB-S, DVB-S2 supports the -following parameters: - -- :ref:`DTV_MODULATION ` - -- :ref:`DTV_PILOT ` - -- :ref:`DTV_ROLLOFF ` - -- :ref:`DTV_STREAM_ID ` - -- :ref:`DTV_SCRAMBLING_SEQUENCE_INDEX ` - -In addition, the :ref:`DTV QoS statistics ` -are also valid. - - -.. _turbo-params: - -Turbo code delivery system -========================== - -In addition to all parameters valid for DVB-S, turbo code supports the -following parameters: - -- :ref:`DTV_MODULATION ` - - -.. _isdbs-params: - -ISDB-S delivery system -====================== - -The following parameters are valid for ISDB-S: - -- :ref:`DTV_API_VERSION ` - -- :ref:`DTV_DELIVERY_SYSTEM ` - -- :ref:`DTV_TUNE ` - -- :ref:`DTV_CLEAR ` - -- :ref:`DTV_FREQUENCY ` - -- :ref:`DTV_INVERSION ` - -- :ref:`DTV_SYMBOL_RATE ` - -- :ref:`DTV_INNER_FEC ` - -- :ref:`DTV_VOLTAGE ` - -- :ref:`DTV_STREAM_ID ` diff --git a/Documentation/media/uapi/dvb/frontend-property-terrestrial-systems.rst b/Documentation/media/uapi/dvb/frontend-property-terrestrial-systems.rst deleted file mode 100644 index c20af13297e5..000000000000 --- a/Documentation/media/uapi/dvb/frontend-property-terrestrial-systems.rst +++ /dev/null @@ -1,301 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _frontend-property-terrestrial-systems: - -*********************************************** -Properties used on terrestrial delivery systems -*********************************************** - - -.. _dvbt-params: - -DVB-T delivery system -===================== - -The following parameters are valid for DVB-T: - -- :ref:`DTV_API_VERSION ` - -- :ref:`DTV_DELIVERY_SYSTEM ` - -- :ref:`DTV_TUNE ` - -- :ref:`DTV_CLEAR ` - -- :ref:`DTV_FREQUENCY ` - -- :ref:`DTV_MODULATION ` - -- :ref:`DTV_BANDWIDTH_HZ ` - -- :ref:`DTV_INVERSION ` - -- :ref:`DTV_CODE_RATE_HP ` - -- :ref:`DTV_CODE_RATE_LP ` - -- :ref:`DTV_GUARD_INTERVAL ` - -- :ref:`DTV_TRANSMISSION_MODE ` - -- :ref:`DTV_HIERARCHY ` - -- :ref:`DTV_LNA ` - -In addition, the :ref:`DTV QoS statistics ` -are also valid. - - -.. _dvbt2-params: - -DVB-T2 delivery system -====================== - -DVB-T2 support is currently in the early stages of development, so -expect that this section maygrow and become more detailed with time. - -The following parameters are valid for DVB-T2: - -- :ref:`DTV_API_VERSION ` - -- :ref:`DTV_DELIVERY_SYSTEM ` - -- :ref:`DTV_TUNE ` - -- :ref:`DTV_CLEAR ` - -- :ref:`DTV_FREQUENCY ` - -- :ref:`DTV_MODULATION ` - -- :ref:`DTV_BANDWIDTH_HZ ` - -- :ref:`DTV_INVERSION ` - -- :ref:`DTV_CODE_RATE_HP ` - -- :ref:`DTV_CODE_RATE_LP ` - -- :ref:`DTV_GUARD_INTERVAL ` - -- :ref:`DTV_TRANSMISSION_MODE ` - -- :ref:`DTV_HIERARCHY ` - -- :ref:`DTV_STREAM_ID ` - -- :ref:`DTV_LNA ` - -In addition, the :ref:`DTV QoS statistics ` -are also valid. - - -.. _isdbt: - -ISDB-T delivery system -====================== - -This ISDB-T/ISDB-Tsb API extension should reflect all information needed -to tune any ISDB-T/ISDB-Tsb hardware. Of course it is possible that some -very sophisticated devices won't need certain parameters to tune. - -The information given here should help application writers to know how -to handle ISDB-T and ISDB-Tsb hardware using the Linux Digital TV API. - -The details given here about ISDB-T and ISDB-Tsb are just enough to -basically show the dependencies between the needed parameter values, but -surely some information is left out. For more detailed information see -the following documents: - -ARIB STD-B31 - "Transmission System for Digital Terrestrial Television -Broadcasting" and - -ARIB TR-B14 - "Operational Guidelines for Digital Terrestrial Television -Broadcasting". - -In order to understand the ISDB specific parameters, one has to have -some knowledge the channel structure in ISDB-T and ISDB-Tsb. I.e. it has -to be known to the reader that an ISDB-T channel consists of 13 -segments, that it can have up to 3 layer sharing those segments, and -things like that. - -The following parameters are valid for ISDB-T: - -- :ref:`DTV_API_VERSION ` - -- :ref:`DTV_DELIVERY_SYSTEM ` - -- :ref:`DTV_TUNE ` - -- :ref:`DTV_CLEAR ` - -- :ref:`DTV_FREQUENCY ` - -- :ref:`DTV_BANDWIDTH_HZ ` - -- :ref:`DTV_INVERSION ` - -- :ref:`DTV_GUARD_INTERVAL ` - -- :ref:`DTV_TRANSMISSION_MODE ` - -- :ref:`DTV_ISDBT_LAYER_ENABLED ` - -- :ref:`DTV_ISDBT_PARTIAL_RECEPTION ` - -- :ref:`DTV_ISDBT_SOUND_BROADCASTING ` - -- :ref:`DTV_ISDBT_SB_SUBCHANNEL_ID ` - -- :ref:`DTV_ISDBT_SB_SEGMENT_IDX ` - -- :ref:`DTV_ISDBT_SB_SEGMENT_COUNT ` - -- :ref:`DTV_ISDBT_LAYERA_FEC ` - -- :ref:`DTV_ISDBT_LAYERA_MODULATION ` - -- :ref:`DTV_ISDBT_LAYERA_SEGMENT_COUNT ` - -- :ref:`DTV_ISDBT_LAYERA_TIME_INTERLEAVING ` - -- :ref:`DTV_ISDBT_LAYERB_FEC ` - -- :ref:`DTV_ISDBT_LAYERB_MODULATION ` - -- :ref:`DTV_ISDBT_LAYERB_SEGMENT_COUNT ` - -- :ref:`DTV_ISDBT_LAYERB_TIME_INTERLEAVING ` - -- :ref:`DTV_ISDBT_LAYERC_FEC ` - -- :ref:`DTV_ISDBT_LAYERC_MODULATION ` - -- :ref:`DTV_ISDBT_LAYERC_SEGMENT_COUNT ` - -- :ref:`DTV_ISDBT_LAYERC_TIME_INTERLEAVING ` - -In addition, the :ref:`DTV QoS statistics ` -are also valid. - - -.. _atsc-params: - -ATSC delivery system -==================== - -The following parameters are valid for ATSC: - -- :ref:`DTV_API_VERSION ` - -- :ref:`DTV_DELIVERY_SYSTEM ` - -- :ref:`DTV_TUNE ` - -- :ref:`DTV_CLEAR ` - -- :ref:`DTV_FREQUENCY ` - -- :ref:`DTV_MODULATION ` - -- :ref:`DTV_BANDWIDTH_HZ ` - -In addition, the :ref:`DTV QoS statistics ` -are also valid. - - -.. _atscmh-params: - -ATSC-MH delivery system -======================= - -The following parameters are valid for ATSC-MH: - -- :ref:`DTV_API_VERSION ` - -- :ref:`DTV_DELIVERY_SYSTEM ` - -- :ref:`DTV_TUNE ` - -- :ref:`DTV_CLEAR ` - -- :ref:`DTV_FREQUENCY ` - -- :ref:`DTV_BANDWIDTH_HZ ` - -- :ref:`DTV_ATSCMH_FIC_VER ` - -- :ref:`DTV_ATSCMH_PARADE_ID ` - -- :ref:`DTV_ATSCMH_NOG ` - -- :ref:`DTV_ATSCMH_TNOG ` - -- :ref:`DTV_ATSCMH_SGN ` - -- :ref:`DTV_ATSCMH_PRC ` - -- :ref:`DTV_ATSCMH_RS_FRAME_MODE ` - -- :ref:`DTV_ATSCMH_RS_FRAME_ENSEMBLE ` - -- :ref:`DTV_ATSCMH_RS_CODE_MODE_PRI ` - -- :ref:`DTV_ATSCMH_RS_CODE_MODE_SEC ` - -- :ref:`DTV_ATSCMH_SCCC_BLOCK_MODE ` - -- :ref:`DTV_ATSCMH_SCCC_CODE_MODE_A ` - -- :ref:`DTV_ATSCMH_SCCC_CODE_MODE_B ` - -- :ref:`DTV_ATSCMH_SCCC_CODE_MODE_C ` - -- :ref:`DTV_ATSCMH_SCCC_CODE_MODE_D ` - -In addition, the :ref:`DTV QoS statistics ` -are also valid. - - -.. _dtmb-params: - -DTMB delivery system -==================== - -The following parameters are valid for DTMB: - -- :ref:`DTV_API_VERSION ` - -- :ref:`DTV_DELIVERY_SYSTEM ` - -- :ref:`DTV_TUNE ` - -- :ref:`DTV_CLEAR ` - -- :ref:`DTV_FREQUENCY ` - -- :ref:`DTV_MODULATION ` - -- :ref:`DTV_BANDWIDTH_HZ ` - -- :ref:`DTV_INVERSION ` - -- :ref:`DTV_INNER_FEC ` - -- :ref:`DTV_GUARD_INTERVAL ` - -- :ref:`DTV_TRANSMISSION_MODE ` - -- :ref:`DTV_INTERLEAVING ` - -- :ref:`DTV_LNA ` - -In addition, the :ref:`DTV QoS statistics ` -are also valid. diff --git a/Documentation/media/uapi/dvb/frontend-stat-properties.rst b/Documentation/media/uapi/dvb/frontend-stat-properties.rst deleted file mode 100644 index 546464db04b5..000000000000 --- a/Documentation/media/uapi/dvb/frontend-stat-properties.rst +++ /dev/null @@ -1,252 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _frontend-stat-properties: - -****************************** -Frontend statistics indicators -****************************** - -The values are returned via ``dtv_property.stat``. If the property is -supported, ``dtv_property.stat.len`` is bigger than zero. - -For most delivery systems, ``dtv_property.stat.len`` will be 1 if the -stats is supported, and the properties will return a single value for -each parameter. - -It should be noted, however, that new OFDM delivery systems like ISDB -can use different modulation types for each group of carriers. On such -standards, up to 3 groups of statistics can be provided, and -``dtv_property.stat.len`` is updated to reflect the "global" metrics, -plus one metric per each carrier group (called "layer" on ISDB). - -So, in order to be consistent with other delivery systems, the first -value at :c:type:`dtv_property.stat.dtv_stats ` array refers -to the global metric. The other elements of the array represent each -layer, starting from layer A(index 1), layer B (index 2) and so on. - -The number of filled elements are stored at ``dtv_property.stat.len``. - -Each element of the ``dtv_property.stat.dtv_stats`` array consists on -two elements: - -- ``svalue`` or ``uvalue``, where ``svalue`` is for signed values of - the measure (dB measures) and ``uvalue`` is for unsigned values - (counters, relative scale) - -- ``scale`` - Scale for the value. It can be: - - - ``FE_SCALE_NOT_AVAILABLE`` - The parameter is supported by the - frontend, but it was not possible to collect it (could be a - transitory or permanent condition) - - - ``FE_SCALE_DECIBEL`` - parameter is a signed value, measured in - 1/1000 dB - - - ``FE_SCALE_RELATIVE`` - parameter is a unsigned value, where 0 - means 0% and 65535 means 100%. - - - ``FE_SCALE_COUNTER`` - parameter is a unsigned value that counts - the occurrence of an event, like bit error, block error, or lapsed - time. - - -.. _DTV-STAT-SIGNAL-STRENGTH: - -DTV_STAT_SIGNAL_STRENGTH -======================== - -Indicates the signal strength level at the analog part of the tuner or -of the demod. - -Possible scales for this metric are: - -- ``FE_SCALE_NOT_AVAILABLE`` - it failed to measure it, or the - measurement was not complete yet. - -- ``FE_SCALE_DECIBEL`` - signal strength is in 0.001 dBm units, power - measured in miliwatts. This value is generally negative. - -- ``FE_SCALE_RELATIVE`` - The frontend provides a 0% to 100% - measurement for power (actually, 0 to 65535). - - -.. _DTV-STAT-CNR: - -DTV_STAT_CNR -============ - -Indicates the Signal to Noise ratio for the main carrier. - -Possible scales for this metric are: - -- ``FE_SCALE_NOT_AVAILABLE`` - it failed to measure it, or the - measurement was not complete yet. - -- ``FE_SCALE_DECIBEL`` - Signal/Noise ratio is in 0.001 dB units. - -- ``FE_SCALE_RELATIVE`` - The frontend provides a 0% to 100% - measurement for Signal/Noise (actually, 0 to 65535). - - -.. _DTV-STAT-PRE-ERROR-BIT-COUNT: - -DTV_STAT_PRE_ERROR_BIT_COUNT -============================ - -Measures the number of bit errors before the forward error correction -(FEC) on the inner coding block (before Viterbi, LDPC or other inner -code). - -This measure is taken during the same interval as -``DTV_STAT_PRE_TOTAL_BIT_COUNT``. - -In order to get the BER (Bit Error Rate) measurement, it should be -divided by -:ref:`DTV_STAT_PRE_TOTAL_BIT_COUNT `. - -This measurement is monotonically increased, as the frontend gets more -bit count measurements. The frontend may reset it when a -channel/transponder is tuned. - -Possible scales for this metric are: - -- ``FE_SCALE_NOT_AVAILABLE`` - it failed to measure it, or the - measurement was not complete yet. - -- ``FE_SCALE_COUNTER`` - Number of error bits counted before the inner - coding. - - -.. _DTV-STAT-PRE-TOTAL-BIT-COUNT: - -DTV_STAT_PRE_TOTAL_BIT_COUNT -============================ - -Measures the amount of bits received before the inner code block, during -the same period as -:ref:`DTV_STAT_PRE_ERROR_BIT_COUNT ` -measurement was taken. - -It should be noted that this measurement can be smaller than the total -amount of bits on the transport stream, as the frontend may need to -manually restart the measurement, losing some data between each -measurement interval. - -This measurement is monotonically increased, as the frontend gets more -bit count measurements. The frontend may reset it when a -channel/transponder is tuned. - -Possible scales for this metric are: - -- ``FE_SCALE_NOT_AVAILABLE`` - it failed to measure it, or the - measurement was not complete yet. - -- ``FE_SCALE_COUNTER`` - Number of bits counted while measuring - :ref:`DTV_STAT_PRE_ERROR_BIT_COUNT `. - - -.. _DTV-STAT-POST-ERROR-BIT-COUNT: - -DTV_STAT_POST_ERROR_BIT_COUNT -============================= - -Measures the number of bit errors after the forward error correction -(FEC) done by inner code block (after Viterbi, LDPC or other inner -code). - -This measure is taken during the same interval as -``DTV_STAT_POST_TOTAL_BIT_COUNT``. - -In order to get the BER (Bit Error Rate) measurement, it should be -divided by -:ref:`DTV_STAT_POST_TOTAL_BIT_COUNT `. - -This measurement is monotonically increased, as the frontend gets more -bit count measurements. The frontend may reset it when a -channel/transponder is tuned. - -Possible scales for this metric are: - -- ``FE_SCALE_NOT_AVAILABLE`` - it failed to measure it, or the - measurement was not complete yet. - -- ``FE_SCALE_COUNTER`` - Number of error bits counted after the inner - coding. - - -.. _DTV-STAT-POST-TOTAL-BIT-COUNT: - -DTV_STAT_POST_TOTAL_BIT_COUNT -============================= - -Measures the amount of bits received after the inner coding, during the -same period as -:ref:`DTV_STAT_POST_ERROR_BIT_COUNT ` -measurement was taken. - -It should be noted that this measurement can be smaller than the total -amount of bits on the transport stream, as the frontend may need to -manually restart the measurement, losing some data between each -measurement interval. - -This measurement is monotonically increased, as the frontend gets more -bit count measurements. The frontend may reset it when a -channel/transponder is tuned. - -Possible scales for this metric are: - -- ``FE_SCALE_NOT_AVAILABLE`` - it failed to measure it, or the - measurement was not complete yet. - -- ``FE_SCALE_COUNTER`` - Number of bits counted while measuring - :ref:`DTV_STAT_POST_ERROR_BIT_COUNT `. - - -.. _DTV-STAT-ERROR-BLOCK-COUNT: - -DTV_STAT_ERROR_BLOCK_COUNT -========================== - -Measures the number of block errors after the outer forward error -correction coding (after Reed-Solomon or other outer code). - -This measurement is monotonically increased, as the frontend gets more -bit count measurements. The frontend may reset it when a -channel/transponder is tuned. - -Possible scales for this metric are: - -- ``FE_SCALE_NOT_AVAILABLE`` - it failed to measure it, or the - measurement was not complete yet. - -- ``FE_SCALE_COUNTER`` - Number of error blocks counted after the outer - coding. - - -.. _DTV-STAT-TOTAL-BLOCK-COUNT: - -DTV-STAT_TOTAL_BLOCK_COUNT -========================== - -Measures the total number of blocks received during the same period as -:ref:`DTV_STAT_ERROR_BLOCK_COUNT ` -measurement was taken. - -It can be used to calculate the PER indicator, by dividing -:ref:`DTV_STAT_ERROR_BLOCK_COUNT ` by -:ref:`DTV-STAT-TOTAL-BLOCK-COUNT`. - -Possible scales for this metric are: - -- ``FE_SCALE_NOT_AVAILABLE`` - it failed to measure it, or the - measurement was not complete yet. - -- ``FE_SCALE_COUNTER`` - Number of blocks counted while measuring - :ref:`DTV_STAT_ERROR_BLOCK_COUNT `. diff --git a/Documentation/media/uapi/dvb/frontend.rst b/Documentation/media/uapi/dvb/frontend.rst deleted file mode 100644 index 7ff225dfe11c..000000000000 --- a/Documentation/media/uapi/dvb/frontend.rst +++ /dev/null @@ -1,63 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _dvb_frontend: - -####################### -Digital TV Frontend API -####################### - -The Digital TV frontend API was designed to support three groups of delivery -systems: Terrestrial, cable and Satellite. Currently, the following -delivery systems are supported: - -- Terrestrial systems: DVB-T, DVB-T2, ATSC, ATSC M/H, ISDB-T, DVB-H, - DTMB, CMMB - -- Cable systems: DVB-C Annex A/C, ClearQAM (DVB-C Annex B) - -- Satellite systems: DVB-S, DVB-S2, DVB Turbo, ISDB-S, DSS - -The Digital TV frontend controls several sub-devices including: - -- Tuner - -- Digital TV demodulator - -- Low noise amplifier (LNA) - -- Satellite Equipment Control (SEC) [#f1]_. - -The frontend can be accessed through ``/dev/dvb/adapter?/frontend?``. -Data types and ioctl definitions can be accessed by including -``linux/dvb/frontend.h`` in your application. - -.. note:: - - Transmission via the internet (DVB-IP) and MMT (MPEG Media Transport) - is not yet handled by this API but a future extension is possible. - -.. [#f1] - - On Satellite systems, the API support for the Satellite Equipment - Control (SEC) allows to power control and to send/receive signals to - control the antenna subsystem, selecting the polarization and choosing - the Intermediate Frequency IF) of the Low Noise Block Converter Feed - Horn (LNBf). It supports the DiSEqC and V-SEC protocols. The DiSEqC - (digital SEC) specification is available at - `Eutelsat `__. - - -.. toctree:: - :maxdepth: 1 - - query-dvb-frontend-info - dvb-fe-read-status - dvbproperty - frontend_fcalls diff --git a/Documentation/media/uapi/dvb/frontend_f_close.rst b/Documentation/media/uapi/dvb/frontend_f_close.rst deleted file mode 100644 index af87c2a83719..000000000000 --- a/Documentation/media/uapi/dvb/frontend_f_close.rst +++ /dev/null @@ -1,57 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _frontend_f_close: - -*************************** -Digital TV frontend close() -*************************** - -Name -==== - -fe-close - Close a frontend device - - -Synopsis -======== - -.. code-block:: c - - #include - - -.. c:function:: int close( int fd ) - :name: dvb-fe-close - -Arguments -========= - -``fd`` - File descriptor returned by :c:func:`open() `. - - -Description -=========== - -This system call closes a previously opened front-end device. After -closing a front-end device, its corresponding hardware might be powered -down automatically. - - -Return Value -============ - -On success 0 is returned. - -On error -1 is returned, and the ``errno`` variable is set -appropriately. - -Generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/dvb/frontend_f_open.rst b/Documentation/media/uapi/dvb/frontend_f_open.rst deleted file mode 100644 index 6a46ec5acf7b..000000000000 --- a/Documentation/media/uapi/dvb/frontend_f_open.rst +++ /dev/null @@ -1,117 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _frontend_f_open: - -*************************** -Digital TV frontend open() -*************************** - -Name -==== - -fe-open - Open a frontend device - - -Synopsis -======== - -.. code-block:: c - - #include - - -.. c:function:: int open( const char *device_name, int flags ) - :name: dvb-fe-open - -Arguments -========= - -``device_name`` - Device to be opened. - -``flags`` - Open flags. Access can either be ``O_RDWR`` or ``O_RDONLY``. - - Multiple opens are allowed with ``O_RDONLY``. In this mode, only - query and read ioctls are allowed. - - Only one open is allowed in ``O_RDWR``. In this mode, all ioctls are - allowed. - - When the ``O_NONBLOCK`` flag is given, the system calls may return - ``EAGAIN`` error code when no data is available or when the device - driver is temporarily busy. - - Other flags have no effect. - - -Description -=========== - -This system call opens a named frontend device -(``/dev/dvb/adapter?/frontend?``) for subsequent use. Usually the first -thing to do after a successful open is to find out the frontend type -with :ref:`FE_GET_INFO`. - -The device can be opened in read-only mode, which only allows monitoring -of device status and statistics, or read/write mode, which allows any -kind of use (e.g. performing tuning operations.) - -In a system with multiple front-ends, it is usually the case that -multiple devices cannot be open in read/write mode simultaneously. As -long as a front-end device is opened in read/write mode, other open() -calls in read/write mode will either fail or block, depending on whether -non-blocking or blocking mode was specified. A front-end device opened -in blocking mode can later be put into non-blocking mode (and vice -versa) using the F_SETFL command of the fcntl system call. This is a -standard system call, documented in the Linux manual page for fcntl. -When an open() call has succeeded, the device will be ready for use in -the specified mode. This implies that the corresponding hardware is -powered up, and that other front-ends may have been powered down to make -that possible. - - -Return Value -============ - -On success :ref:`open() ` returns the new file descriptor. -On error, -1 is returned, and the ``errno`` variable is set appropriately. - -Possible error codes are: - - -On success 0 is returned, and :c:type:`ca_slot_info` is filled. - -On error -1 is returned, and the ``errno`` variable is set -appropriately. - -.. tabularcolumns:: |p{2.5cm}|p{15.0cm}| - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - :widths: 1 16 - - - - ``EPERM`` - - The caller has no permission to access the device. - - - - ``EBUSY`` - - The the device driver is already in use. - - - - ``EMFILE`` - - The process already has the maximum number of files open. - - - - ``ENFILE`` - - The limit on the total number of files open on the system has been - reached. - - -The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/dvb/frontend_fcalls.rst b/Documentation/media/uapi/dvb/frontend_fcalls.rst deleted file mode 100644 index 9b3586f538ea..000000000000 --- a/Documentation/media/uapi/dvb/frontend_fcalls.rst +++ /dev/null @@ -1,31 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _frontend_fcalls: - -####################### -Frontend Function Calls -####################### - -.. toctree:: - :maxdepth: 1 - - frontend_f_open - frontend_f_close - fe-get-info - fe-read-status - fe-get-property - fe-diseqc-reset-overload - fe-diseqc-send-master-cmd - fe-diseqc-recv-slave-reply - fe-diseqc-send-burst - fe-set-tone - fe-set-voltage - fe-enable-high-lnb-voltage - fe-set-frontend-tune-mode diff --git a/Documentation/media/uapi/dvb/frontend_legacy_api.rst b/Documentation/media/uapi/dvb/frontend_legacy_api.rst deleted file mode 100644 index 1ea749d09ca2..000000000000 --- a/Documentation/media/uapi/dvb/frontend_legacy_api.rst +++ /dev/null @@ -1,45 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _frontend_legacy_types: - -Frontend Legacy Data Types -========================== - - -.. toctree:: - :maxdepth: 1 - - fe-type-t - fe-bandwidth-t - dvb-frontend-parameters - dvb-frontend-event - - -.. _frontend_legacy_fcalls: - -Frontend Legacy Function Calls -============================== - -Those functions are defined at DVB version 3. The support is kept in the -kernel due to compatibility issues only. Their usage is strongly not -recommended - - -.. toctree:: - :maxdepth: 1 - - fe-read-ber - fe-read-snr - fe-read-signal-strength - fe-read-uncorrected-blocks - fe-set-frontend - fe-get-frontend - fe-get-event - fe-dishnetwork-send-legacy-cmd diff --git a/Documentation/media/uapi/dvb/frontend_legacy_dvbv3_api.rst b/Documentation/media/uapi/dvb/frontend_legacy_dvbv3_api.rst deleted file mode 100644 index 1567bc73855a..000000000000 --- a/Documentation/media/uapi/dvb/frontend_legacy_dvbv3_api.rst +++ /dev/null @@ -1,25 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _frontend_legacy_dvbv3_api: - -*********************************************** -Digital TV Frontend legacy API (a. k. a. DVBv3) -*********************************************** - -The usage of this API is deprecated, as it doesn't support all digital -TV standards, doesn't provide good statistics measurements and provides -incomplete information. This is kept only to support legacy -applications. - - -.. toctree:: - :maxdepth: 1 - - frontend_legacy_api diff --git a/Documentation/media/uapi/dvb/headers.rst b/Documentation/media/uapi/dvb/headers.rst deleted file mode 100644 index edeabd9e8e90..000000000000 --- a/Documentation/media/uapi/dvb/headers.rst +++ /dev/null @@ -1,30 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -**************************** -Digital TV uAPI header files -**************************** - -Digital TV uAPI headers -*********************** - -.. kernel-include:: $BUILDDIR/frontend.h.rst - -.. kernel-include:: $BUILDDIR/dmx.h.rst - -.. kernel-include:: $BUILDDIR/ca.h.rst - -.. kernel-include:: $BUILDDIR/net.h.rst - -Legacy uAPI -*********** - -.. kernel-include:: $BUILDDIR/audio.h.rst - -.. kernel-include:: $BUILDDIR/video.h.rst diff --git a/Documentation/media/uapi/dvb/intro.rst b/Documentation/media/uapi/dvb/intro.rst deleted file mode 100644 index f1384616ac4e..000000000000 --- a/Documentation/media/uapi/dvb/intro.rst +++ /dev/null @@ -1,190 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _dvb_introdution: - -************ -Introduction -************ - - -.. _requisites: - -What you need to know -===================== - -The reader of this document is required to have some knowledge in the -area of digital video broadcasting (Digital TV) and should be familiar with -part I of the MPEG2 specification ISO/IEC 13818 (aka ITU-T H.222), i.e -you should know what a program/transport stream (PS/TS) is and what is -meant by a packetized elementary stream (PES) or an I-frame. - -Various Digital TV standards documents are available for download at: - -- European standards (DVB): http://www.dvb.org and/or http://www.etsi.org. -- American standards (ATSC): https://www.atsc.org/standards/ -- Japanese standards (ISDB): http://www.dibeg.org/ - -It is also necessary to know how to access Linux devices and how to -use ioctl calls. This also includes the knowledge of C or C++. - - -.. _history: - -History -======= - -The first API for Digital TV cards we used at Convergence in late 1999 was an -extension of the Video4Linux API which was primarily developed for frame -grabber cards. As such it was not really well suited to be used for Digital -TV cards and their new features like recording MPEG streams and filtering -several section and PES data streams at the same time. - -In early 2000, Convergence was approached by Nokia with a proposal for a new -standard Linux Digital TV API. As a commitment to the development of terminals -based on open standards, Nokia and Convergence made it available to all -Linux developers and published it on https://linuxtv.org in September -2000. With the Linux driver for the Siemens/Hauppauge DVB PCI card, -Convergence provided a first implementation of the Linux Digital TV API. -Convergence was the maintainer of the Linux Digital TV API in the early -days. - -Now, the API is maintained by the LinuxTV community (i.e. you, the reader -of this document). The Linux Digital TV API is constantly reviewed and -improved together with the improvements at the subsystem's core at the -Kernel. - - -.. _overview: - -Overview -======== - - -.. _stb_components: - -.. kernel-figure:: dvbstb.svg - :alt: dvbstb.svg - :align: center - - Components of a Digital TV card/STB - -A Digital TV card or set-top-box (STB) usually consists of the -following main hardware components: - -Frontend consisting of tuner and digital TV demodulator - Here the raw signal reaches the digital TV hardware from a satellite dish or - antenna or directly from cable. The frontend down-converts and - demodulates this signal into an MPEG transport stream (TS). In case - of a satellite frontend, this includes a facility for satellite - equipment control (SEC), which allows control of LNB polarization, - multi feed switches or dish rotors. - -Conditional Access (CA) hardware like CI adapters and smartcard slots - The complete TS is passed through the CA hardware. Programs to which - the user has access (controlled by the smart card) are decoded in - real time and re-inserted into the TS. - - .. note:: - - Not every digital TV hardware provides conditional access hardware. - -Demultiplexer which filters the incoming Digital TV MPEG-TS stream - The demultiplexer splits the TS into its components like audio and - video streams. Besides usually several of such audio and video - streams it also contains data streams with information about the - programs offered in this or other streams of the same provider. - -Audio and video decoder - The main targets of the demultiplexer are audio and video - decoders. After decoding, they pass on the uncompressed audio and - video to the computer screen or to a TV set. - - .. note:: - - Modern hardware usually doesn't have a separate decoder hardware, as - such functionality can be provided by the main CPU, by the graphics - adapter of the system or by a signal processing hardware embedded on - a Systems on a Chip (SoC) integrated circuit. - - It may also not be needed for certain usages (e.g. for data-only - uses like “internet over satellite”). - -:ref:`stb_components` shows a crude schematic of the control and data -flow between those components. - - - -.. _dvb_devices: - -Linux Digital TV Devices -======================== - -The Linux Digital TV API lets you control these hardware components through -currently six Unix-style character devices for video, audio, frontend, -demux, CA and IP-over-DVB networking. The video and audio devices -control the MPEG2 decoder hardware, the frontend device the tuner and -the Digital TV demodulator. The demux device gives you control over the PES -and section filters of the hardware. If the hardware does not support -filtering these filters can be implemented in software. Finally, the CA -device controls all the conditional access capabilities of the hardware. -It can depend on the individual security requirements of the platform, -if and how many of the CA functions are made available to the -application through this device. - -All devices can be found in the ``/dev`` tree under ``/dev/dvb``. The -individual devices are called: - -- ``/dev/dvb/adapterN/audioM``, - -- ``/dev/dvb/adapterN/videoM``, - -- ``/dev/dvb/adapterN/frontendM``, - -- ``/dev/dvb/adapterN/netM``, - -- ``/dev/dvb/adapterN/demuxM``, - -- ``/dev/dvb/adapterN/dvrM``, - -- ``/dev/dvb/adapterN/caM``, - -where ``N`` enumerates the Digital TV cards in a system starting from 0, and -``M`` enumerates the devices of each type within each adapter, starting -from 0, too. We will omit the “``/dev/dvb/adapterN/``\ ” in the further -discussion of these devices. - -More details about the data structures and function calls of all the -devices are described in the following chapters. - - -.. _include_files: - -API include files -================= - -For each of the Digital TV devices a corresponding include file exists. The -Digital TV API include files should be included in application sources with a -partial path like: - - -.. code-block:: c - - #include - - #include - - #include - - #include - - -To enable applications to support different API version, an additional -include file ``linux/dvb/version.h`` exists, which defines the constant -``DVB_API_VERSION``. This document describes ``DVB_API_VERSION 5.10``. diff --git a/Documentation/media/uapi/dvb/legacy_dvb_apis.rst b/Documentation/media/uapi/dvb/legacy_dvb_apis.rst deleted file mode 100644 index a43b4c36d935..000000000000 --- a/Documentation/media/uapi/dvb/legacy_dvb_apis.rst +++ /dev/null @@ -1,39 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _legacy_dvb_apis: - -*************************** -Digital TV Deprecated APIs -*************************** - -The APIs described here **should not** be used on new drivers or applications. - -The DVBv3 frontend API has issues with new delivery systems, including -DVB-S2, DVB-T2, ISDB, etc. - -There's just one driver for a very legacy hardware using the Digital TV -audio and video APIs. No modern drivers should use it. Instead, audio and -video should be using the V4L2 and ALSA APIs, and the pipelines should -be set via the Media Controller API. - -.. attention:: - - The APIs described here doesn't necessarily reflect the current - code implementation, as this section of the document was written - for DVB version 1, while the code reflects DVB version 3 - implementation. - - -.. toctree:: - :maxdepth: 1 - - frontend_legacy_dvbv3_api - video - audio diff --git a/Documentation/media/uapi/dvb/net-add-if.rst b/Documentation/media/uapi/dvb/net-add-if.rst deleted file mode 100644 index 1188641b453e..000000000000 --- a/Documentation/media/uapi/dvb/net-add-if.rst +++ /dev/null @@ -1,60 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _NET_ADD_IF: - -**************** -ioctl NET_ADD_IF -**************** - -Name -==== - -NET_ADD_IF - Creates a new network interface for a given Packet ID. - - -Synopsis -======== - -.. c:function:: int ioctl( int fd, NET_ADD_IF, struct dvb_net_if *net_if ) - :name: NET_ADD_IF - - -Arguments -========= - -``fd`` - File descriptor returned by :ref:`open() `. - -``net_if`` - pointer to struct :c:type:`dvb_net_if` - - -Description -=========== - -The NET_ADD_IF ioctl system call selects the Packet ID (PID) that -contains a TCP/IP traffic, the type of encapsulation to be used (MPE or -ULE) and the interface number for the new interface to be created. When -the system call successfully returns, a new virtual network interface is -created. - -The struct :c:type:`dvb_net_if`::ifnum field will be -filled with the number of the created interface. - -Return Value -============ - -On success 0 is returned, and :c:type:`ca_slot_info` is filled. - -On error -1 is returned, and the ``errno`` variable is set -appropriately. - -The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/dvb/net-get-if.rst b/Documentation/media/uapi/dvb/net-get-if.rst deleted file mode 100644 index 7c4ef4b9d6cc..000000000000 --- a/Documentation/media/uapi/dvb/net-get-if.rst +++ /dev/null @@ -1,59 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _NET_GET_IF: - -**************** -ioctl NET_GET_IF -**************** - -Name -==== - -NET_GET_IF - Read the configuration data of an interface created via - :ref:`NET_ADD_IF `. - - -Synopsis -======== - -.. c:function:: int ioctl( int fd, NET_GET_IF, struct dvb_net_if *net_if ) - :name: NET_GET_IF - - -Arguments -========= - -``fd`` - File descriptor returned by :ref:`open() `. - -``net_if`` - pointer to struct :c:type:`dvb_net_if` - - -Description -=========== - -The NET_GET_IF ioctl uses the interface number given by the struct -:c:type:`dvb_net_if`::ifnum field and fills the content of -struct :c:type:`dvb_net_if` with the packet ID and -encapsulation type used on such interface. If the interface was not -created yet with :ref:`NET_ADD_IF `, it will return -1 and fill -the ``errno`` with ``EINVAL`` error code. - - -Return Value -============ - -On success 0 is returned, and :c:type:`ca_slot_info` is filled. - -On error -1 is returned, and the ``errno`` variable is set -appropriately. - -The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/dvb/net-remove-if.rst b/Documentation/media/uapi/dvb/net-remove-if.rst deleted file mode 100644 index bf9a1602eeec..000000000000 --- a/Documentation/media/uapi/dvb/net-remove-if.rst +++ /dev/null @@ -1,55 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _NET_REMOVE_IF: - -******************* -ioctl NET_REMOVE_IF -******************* - -Name -==== - -NET_REMOVE_IF - Removes a network interface. - - -Synopsis -======== - -.. c:function:: int ioctl( int fd, NET_REMOVE_IF, int ifnum ) - :name: NET_REMOVE_IF - - -Arguments -========= - -``fd`` - File descriptor returned by :ref:`open() `. - -``net_if`` - number of the interface to be removed - - -Description -=========== - -The NET_REMOVE_IF ioctl deletes an interface previously created via -:ref:`NET_ADD_IF `. - - -Return Value -============ - -On success 0 is returned, and :c:type:`ca_slot_info` is filled. - -On error -1 is returned, and the ``errno`` variable is set -appropriately. - -The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/dvb/net-types.rst b/Documentation/media/uapi/dvb/net-types.rst deleted file mode 100644 index 9e16462a1ef4..000000000000 --- a/Documentation/media/uapi/dvb/net-types.rst +++ /dev/null @@ -1,16 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _net_types: - -************** -Net Data Types -************** - -.. kernel-doc:: include/uapi/linux/dvb/net.h diff --git a/Documentation/media/uapi/dvb/net.rst b/Documentation/media/uapi/dvb/net.rst deleted file mode 100644 index 833daa381968..000000000000 --- a/Documentation/media/uapi/dvb/net.rst +++ /dev/null @@ -1,48 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _net: - -###################### -Digital TV Network API -###################### - -The Digital TV net device controls the mapping of data packages that are part -of a transport stream to be mapped into a virtual network interface, -visible through the standard Linux network protocol stack. - -Currently, two encapsulations are supported: - -- `Multi Protocol Encapsulation (MPE) `__ - -- `Ultra Lightweight Encapsulation (ULE) `__ - -In order to create the Linux virtual network interfaces, an application -needs to tell to the Kernel what are the PIDs and the encapsulation -types that are present on the transport stream. This is done through -``/dev/dvb/adapter?/net?`` device node. The data will be available via -virtual ``dvb?_?`` network interfaces, and will be controlled/routed via -the standard ip tools (like ip, route, netstat, ifconfig, etc). - -Data types and and ioctl definitions are defined via ``linux/dvb/net.h`` -header. - - -.. _net_fcalls: - -Digital TV net Function Calls -############################# - -.. toctree:: - :maxdepth: 1 - - net-types - net-add-if - net-remove-if - net-get-if diff --git a/Documentation/media/uapi/dvb/query-dvb-frontend-info.rst b/Documentation/media/uapi/dvb/query-dvb-frontend-info.rst deleted file mode 100644 index 9a6badc1d295..000000000000 --- a/Documentation/media/uapi/dvb/query-dvb-frontend-info.rst +++ /dev/null @@ -1,20 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _query-dvb-frontend-info: - -***************************** -Querying frontend information -***************************** - -Usually, the first thing to do when the frontend is opened is to check -the frontend capabilities. This is done using -:ref:`FE_GET_INFO`. This ioctl will enumerate the -Digital TV API version and other characteristics about the frontend, and can -be opened either in read only or read/write mode. diff --git a/Documentation/media/uapi/dvb/video-clear-buffer.rst b/Documentation/media/uapi/dvb/video-clear-buffer.rst deleted file mode 100644 index 5eb5546e8ce4..000000000000 --- a/Documentation/media/uapi/dvb/video-clear-buffer.rst +++ /dev/null @@ -1,63 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _VIDEO_CLEAR_BUFFER: - -================== -VIDEO_CLEAR_BUFFER -================== - -Name ----- - -VIDEO_CLEAR_BUFFER - -.. attention:: This ioctl is deprecated. - -Synopsis --------- - -.. c:function:: int ioctl(fd, VIDEO_CLEAR_BUFFER) - :name: VIDEO_CLEAR_BUFFER - - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - - .. row 1 - - - int fd - - - File descriptor returned by a previous call to open(). - - - .. row 2 - - - int request - - - Equals VIDEO_CLEAR_BUFFER for this command. - - -Description ------------ - -This ioctl call clears all video buffers in the driver and in the -decoder hardware. - - -Return Value ------------- - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/dvb/video-command.rst b/Documentation/media/uapi/dvb/video-command.rst deleted file mode 100644 index 020b49645c6b..000000000000 --- a/Documentation/media/uapi/dvb/video-command.rst +++ /dev/null @@ -1,105 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _VIDEO_COMMAND: - -============= -VIDEO_COMMAND -============= - -Name ----- - -VIDEO_COMMAND - -.. attention:: This ioctl is deprecated. - -Synopsis --------- - -.. c:function:: int ioctl(int fd, VIDEO_COMMAND, struct video_command *cmd) - :name: VIDEO_COMMAND - - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - - .. row 1 - - - int fd - - - File descriptor returned by a previous call to open(). - - - .. row 2 - - - int request - - - Equals VIDEO_COMMAND for this command. - - - .. row 3 - - - struct video_command \*cmd - - - Commands the decoder. - - -Description ------------ - -This ioctl is obsolete. Do not use in new drivers. For V4L2 decoders -this ioctl has been replaced by the -:ref:`VIDIOC_DECODER_CMD` ioctl. - -This ioctl commands the decoder. The ``video_command`` struct is a -subset of the ``v4l2_decoder_cmd`` struct, so refer to the -:ref:`VIDIOC_DECODER_CMD` documentation for -more information. - -.. c:type:: struct video_command - -.. code-block:: c - - /* The structure must be zeroed before use by the application - This ensures it can be extended safely in the future. */ - struct video_command { - __u32 cmd; - __u32 flags; - union { - struct { - __u64 pts; - } stop; - - struct { - /* 0 or 1000 specifies normal speed, - 1 specifies forward single stepping, - -1 specifies backward single stepping, - >1: playback at speed/1000 of the normal speed, - <-1: reverse playback at (-speed/1000) of the normal speed. */ - __s32 speed; - __u32 format; - } play; - - struct { - __u32 data[16]; - } raw; - }; - }; - - -Return Value ------------- - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/dvb/video-continue.rst b/Documentation/media/uapi/dvb/video-continue.rst deleted file mode 100644 index 2ae2067dfba8..000000000000 --- a/Documentation/media/uapi/dvb/video-continue.rst +++ /dev/null @@ -1,66 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _VIDEO_CONTINUE: - -============== -VIDEO_CONTINUE -============== - -Name ----- - -VIDEO_CONTINUE - -.. attention:: This ioctl is deprecated. - -Synopsis --------- - -.. c:function:: int ioctl(fd, VIDEO_CONTINUE) - :name: VIDEO_CONTINUE - - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - - .. row 1 - - - int fd - - - File descriptor returned by a previous call to open(). - - - .. row 2 - - - int request - - - Equals VIDEO_CONTINUE for this command. - - -Description ------------ - -This ioctl is for Digital TV devices only. To control a V4L2 decoder use the -V4L2 :ref:`VIDIOC_DECODER_CMD` instead. - -This ioctl call restarts decoding and playing processes of the video -stream which was played before a call to VIDEO_FREEZE was made. - - -Return Value ------------- - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/dvb/video-fast-forward.rst b/Documentation/media/uapi/dvb/video-fast-forward.rst deleted file mode 100644 index 3f805f334ae1..000000000000 --- a/Documentation/media/uapi/dvb/video-fast-forward.rst +++ /dev/null @@ -1,83 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _VIDEO_FAST_FORWARD: - -================== -VIDEO_FAST_FORWARD -================== - -Name ----- - -VIDEO_FAST_FORWARD - -.. attention:: This ioctl is deprecated. - -Synopsis --------- - -.. c:function:: int ioctl(fd, VIDEO_FAST_FORWARD, int nFrames) - :name: VIDEO_FAST_FORWARD - - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - - .. row 1 - - - int fd - - - File descriptor returned by a previous call to open(). - - - .. row 2 - - - int request - - - Equals VIDEO_FAST_FORWARD for this command. - - - .. row 3 - - - int nFrames - - - The number of frames to skip. - - -Description ------------ - -This ioctl call asks the Video Device to skip decoding of N number of -I-frames. This call can only be used if VIDEO_SOURCE_MEMORY is -selected. - - -Return Value ------------- - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. - - - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - - .. row 1 - - - ``EPERM`` - - - Mode VIDEO_SOURCE_MEMORY not selected. diff --git a/Documentation/media/uapi/dvb/video-fclose.rst b/Documentation/media/uapi/dvb/video-fclose.rst deleted file mode 100644 index 3b0285b96a3c..000000000000 --- a/Documentation/media/uapi/dvb/video-fclose.rst +++ /dev/null @@ -1,62 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _video_fclose: - -================= -dvb video close() -================= - -Name ----- - -dvb video close() - -.. attention:: This ioctl is deprecated. - -Synopsis --------- - -.. c:function:: int close(int fd) - - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - - .. row 1 - - - int fd - - - File descriptor returned by a previous call to open(). - - -Description ------------ - -This system call closes a previously opened video device. - - -Return Value ------------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - - .. row 1 - - - ``EBADF`` - - - fd is not a valid open file descriptor. diff --git a/Documentation/media/uapi/dvb/video-fopen.rst b/Documentation/media/uapi/dvb/video-fopen.rst deleted file mode 100644 index 7b2a8c750e6a..000000000000 --- a/Documentation/media/uapi/dvb/video-fopen.rst +++ /dev/null @@ -1,122 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _video_fopen: - -================ -dvb video open() -================ - -Name ----- - -dvb video open() - -.. attention:: This ioctl is deprecated. - -Synopsis --------- - -.. c:function:: int open(const char *deviceName, int flags) - - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - - .. row 1 - - - const char \*deviceName - - - Name of specific video device. - - - .. row 2 - - - int flags - - - A bit-wise OR of the following flags: - - - .. row 3 - - - - - O_RDONLY read-only access - - - .. row 4 - - - - - O_RDWR read/write access - - - .. row 5 - - - - - O_NONBLOCK open in non-blocking mode - - - .. row 6 - - - - - (blocking mode is the default) - - -Description ------------ - -This system call opens a named video device (e.g. -/dev/dvb/adapter0/video0) for subsequent use. - -When an open() call has succeeded, the device will be ready for use. The -significance of blocking or non-blocking mode is described in the -documentation for functions where there is a difference. It does not -affect the semantics of the open() call itself. A device opened in -blocking mode can later be put into non-blocking mode (and vice versa) -using the F_SETFL command of the fcntl system call. This is a standard -system call, documented in the Linux manual page for fcntl. Only one -user can open the Video Device in O_RDWR mode. All other attempts to -open the device in this mode will fail, and an error-code will be -returned. If the Video Device is opened in O_RDONLY mode, the only -ioctl call that can be used is VIDEO_GET_STATUS. All other call will -return an error code. - - -Return Value ------------- - -.. tabularcolumns:: |p{2.5cm}|p{15.0cm}| - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - - .. row 1 - - - ``ENODEV`` - - - Device driver not loaded/available. - - - .. row 2 - - - ``EINTERNAL`` - - - Internal error. - - - .. row 3 - - - ``EBUSY`` - - - Device or resource busy. - - - .. row 4 - - - ``EINVAL`` - - - Invalid argument. diff --git a/Documentation/media/uapi/dvb/video-freeze.rst b/Documentation/media/uapi/dvb/video-freeze.rst deleted file mode 100644 index 6b31a4755d2c..000000000000 --- a/Documentation/media/uapi/dvb/video-freeze.rst +++ /dev/null @@ -1,70 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _VIDEO_FREEZE: - -============ -VIDEO_FREEZE -============ - -Name ----- - -VIDEO_FREEZE - -.. attention:: This ioctl is deprecated. - -Synopsis --------- - -.. c:function:: int ioctl(fd, VIDEO_FREEZE) - :name: VIDEO_FREEZE - - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - - .. row 1 - - - int fd - - - File descriptor returned by a previous call to open(). - - - .. row 2 - - - int request - - - Equals VIDEO_FREEZE for this command. - - -Description ------------ - -This ioctl is for Digital TV devices only. To control a V4L2 decoder use the -V4L2 :ref:`VIDIOC_DECODER_CMD` instead. - -This ioctl call suspends the live video stream being played. Decoding -and playing are frozen. It is then possible to restart the decoding and -playing process of the video stream using the VIDEO_CONTINUE command. -If VIDEO_SOURCE_MEMORY is selected in the ioctl call -VIDEO_SELECT_SOURCE, the Digital TV subsystem will not decode any more data -until the ioctl call VIDEO_CONTINUE or VIDEO_PLAY is performed. - - -Return Value ------------- - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/dvb/video-fwrite.rst b/Documentation/media/uapi/dvb/video-fwrite.rst deleted file mode 100644 index eb35b79eb85c..000000000000 --- a/Documentation/media/uapi/dvb/video-fwrite.rst +++ /dev/null @@ -1,90 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _video_fwrite: - -================= -dvb video write() -================= - -Name ----- - -dvb video write() - -.. attention:: This ioctl is deprecated. - -Synopsis --------- - -.. c:function:: size_t write(int fd, const void *buf, size_t count) - - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - - .. row 1 - - - int fd - - - File descriptor returned by a previous call to open(). - - - .. row 2 - - - void \*buf - - - Pointer to the buffer containing the PES data. - - - .. row 3 - - - size_t count - - - Size of buf. - - -Description ------------ - -This system call can only be used if VIDEO_SOURCE_MEMORY is selected -in the ioctl call VIDEO_SELECT_SOURCE. The data provided shall be in -PES format, unless the capability allows other formats. If O_NONBLOCK -is not specified the function will block until buffer space is -available. The amount of data to be transferred is implied by count. - - -Return Value ------------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - - .. row 1 - - - ``EPERM`` - - - Mode VIDEO_SOURCE_MEMORY not selected. - - - .. row 2 - - - ``ENOMEM`` - - - Attempted to write more data than the internal buffer can hold. - - - .. row 3 - - - ``EBADF`` - - - fd is not a valid open file descriptor. diff --git a/Documentation/media/uapi/dvb/video-get-capabilities.rst b/Documentation/media/uapi/dvb/video-get-capabilities.rst deleted file mode 100644 index 971fdab70e15..000000000000 --- a/Documentation/media/uapi/dvb/video-get-capabilities.rst +++ /dev/null @@ -1,70 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _VIDEO_GET_CAPABILITIES: - -====================== -VIDEO_GET_CAPABILITIES -====================== - -Name ----- - -VIDEO_GET_CAPABILITIES - -.. attention:: This ioctl is deprecated. - -Synopsis --------- - -.. c:function:: int ioctl(fd, VIDEO_GET_CAPABILITIES, unsigned int *cap) - :name: VIDEO_GET_CAPABILITIES - - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - - .. row 1 - - - int fd - - - File descriptor returned by a previous call to open(). - - - .. row 2 - - - int request - - - Equals VIDEO_GET_CAPABILITIES for this command. - - - .. row 3 - - - unsigned int \*cap - - - Pointer to a location where to store the capability information. - - -Description ------------ - -This ioctl call asks the video device about its decoding capabilities. -On success it returns and integer which has bits set according to the -defines in section ??. - - -Return Value ------------- - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/dvb/video-get-event.rst b/Documentation/media/uapi/dvb/video-get-event.rst deleted file mode 100644 index 7f03fbe3d3b0..000000000000 --- a/Documentation/media/uapi/dvb/video-get-event.rst +++ /dev/null @@ -1,114 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _VIDEO_GET_EVENT: - -=============== -VIDEO_GET_EVENT -=============== - -Name ----- - -VIDEO_GET_EVENT - -.. attention:: This ioctl is deprecated. - -Synopsis --------- - -.. c:function:: int ioctl(fd, VIDEO_GET_EVENT, struct video_event *ev) - :name: VIDEO_GET_EVENT - - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - - .. row 1 - - - int fd - - - File descriptor returned by a previous call to open(). - - - .. row 2 - - - int request - - - Equals VIDEO_GET_EVENT for this command. - - - .. row 3 - - - struct video_event \*ev - - - Points to the location where the event, if any, is to be stored. - - -Description ------------ - -This ioctl is for Digital TV devices only. To get events from a V4L2 decoder -use the V4L2 :ref:`VIDIOC_DQEVENT` ioctl instead. - -This ioctl call returns an event of type video_event if available. If -an event is not available, the behavior depends on whether the device is -in blocking or non-blocking mode. In the latter case, the call fails -immediately with errno set to ``EWOULDBLOCK``. In the former case, the call -blocks until an event becomes available. The standard Linux poll() -and/or select() system calls can be used with the device file descriptor -to watch for new events. For select(), the file descriptor should be -included in the exceptfds argument, and for poll(), POLLPRI should be -specified as the wake-up condition. Read-only permissions are sufficient -for this ioctl call. - -.. c:type:: video_event - -.. code-block:: c - - struct video_event { - __s32 type; - #define VIDEO_EVENT_SIZE_CHANGED 1 - #define VIDEO_EVENT_FRAME_RATE_CHANGED 2 - #define VIDEO_EVENT_DECODER_STOPPED 3 - #define VIDEO_EVENT_VSYNC 4 - long timestamp; - union { - video_size_t size; - unsigned int frame_rate; /* in frames per 1000sec */ - unsigned char vsync_field; /* unknown/odd/even/progressive */ - } u; - }; - -Return Value ------------- - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - - .. row 1 - - - ``EWOULDBLOCK`` - - - There is no event pending, and the device is in non-blocking mode. - - - .. row 2 - - - ``EOVERFLOW`` - - - Overflow in event queue - one or more events were lost. diff --git a/Documentation/media/uapi/dvb/video-get-frame-count.rst b/Documentation/media/uapi/dvb/video-get-frame-count.rst deleted file mode 100644 index ef35da7d4861..000000000000 --- a/Documentation/media/uapi/dvb/video-get-frame-count.rst +++ /dev/null @@ -1,74 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _VIDEO_GET_FRAME_COUNT: - -===================== -VIDEO_GET_FRAME_COUNT -===================== - -Name ----- - -VIDEO_GET_FRAME_COUNT - -.. attention:: This ioctl is deprecated. - -Synopsis --------- - -.. c:function:: int ioctl(int fd, VIDEO_GET_FRAME_COUNT, __u64 *pts) - :name: VIDEO_GET_FRAME_COUNT - - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - - .. row 1 - - - int fd - - - File descriptor returned by a previous call to open(). - - - .. row 2 - - - int request - - - Equals VIDEO_GET_FRAME_COUNT for this command. - - - .. row 3 - - - __u64 \*pts - - - Returns the number of frames displayed since the decoder was - started. - - -Description ------------ - -This ioctl is obsolete. Do not use in new drivers. For V4L2 decoders -this ioctl has been replaced by the ``V4L2_CID_MPEG_VIDEO_DEC_FRAME`` -control. - -This ioctl call asks the Video Device to return the number of displayed -frames since the decoder was started. - - -Return Value ------------- - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/dvb/video-get-pts.rst b/Documentation/media/uapi/dvb/video-get-pts.rst deleted file mode 100644 index 86ceefff7834..000000000000 --- a/Documentation/media/uapi/dvb/video-get-pts.rst +++ /dev/null @@ -1,78 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _VIDEO_GET_PTS: - -============= -VIDEO_GET_PTS -============= - -Name ----- - -VIDEO_GET_PTS - -.. attention:: This ioctl is deprecated. - -Synopsis --------- - -.. c:function:: int ioctl(int fd, VIDEO_GET_PTS, __u64 *pts) - :name: VIDEO_GET_PTS - - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - - .. row 1 - - - int fd - - - File descriptor returned by a previous call to open(). - - - .. row 2 - - - int request - - - Equals VIDEO_GET_PTS for this command. - - - .. row 3 - - - __u64 \*pts - - - Returns the 33-bit timestamp as defined in ITU T-REC-H.222.0 / - ISO/IEC 13818-1. - - The PTS should belong to the currently played frame if possible, - but may also be a value close to it like the PTS of the last - decoded frame or the last PTS extracted by the PES parser. - - -Description ------------ - -This ioctl is obsolete. Do not use in new drivers. For V4L2 decoders -this ioctl has been replaced by the ``V4L2_CID_MPEG_VIDEO_DEC_PTS`` -control. - -This ioctl call asks the Video Device to return the current PTS -timestamp. - - -Return Value ------------- - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/dvb/video-get-size.rst b/Documentation/media/uapi/dvb/video-get-size.rst deleted file mode 100644 index cc92189d31fd..000000000000 --- a/Documentation/media/uapi/dvb/video-get-size.rst +++ /dev/null @@ -1,78 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _VIDEO_GET_SIZE: - -============== -VIDEO_GET_SIZE -============== - -Name ----- - -VIDEO_GET_SIZE - -.. attention:: This ioctl is deprecated. - -Synopsis --------- - -.. c:function:: int ioctl(int fd, VIDEO_GET_SIZE, video_size_t *size) - :name: VIDEO_GET_SIZE - - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - - .. row 1 - - - int fd - - - File descriptor returned by a previous call to open(). - - - .. row 2 - - - int request - - - Equals VIDEO_GET_SIZE for this command. - - - .. row 3 - - - video_size_t \*size - - - Returns the size and aspect ratio. - - -Description ------------ - -This ioctl returns the size and aspect ratio. - -.. c:type:: video_size_t - -.. code-block::c - - typedef struct { - int w; - int h; - video_format_t aspect_ratio; - } video_size_t; - - -Return Value ------------- - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/dvb/video-get-status.rst b/Documentation/media/uapi/dvb/video-get-status.rst deleted file mode 100644 index 8bfcf8fc3e19..000000000000 --- a/Documentation/media/uapi/dvb/video-get-status.rst +++ /dev/null @@ -1,80 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _VIDEO_GET_STATUS: - -================ -VIDEO_GET_STATUS -================ - -Name ----- - -VIDEO_GET_STATUS - -.. attention:: This ioctl is deprecated. - -Synopsis --------- - -.. c:function:: int ioctl(fd, VIDEO_GET_STATUS, struct video_status *status) - :name: VIDEO_GET_STATUS - - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - - .. row 1 - - - int fd - - - File descriptor returned by a previous call to open(). - - - .. row 2 - - - int request - - - Equals VIDEO_GET_STATUS for this command. - - - .. row 3 - - - struct video_status \*status - - - Returns the current status of the Video Device. - - -Description ------------ - -This ioctl call asks the Video Device to return the current status of -the device. - -.. c:type:: video_status - -.. code-block:: c - - struct video_status { - int video_blank; /* blank video on freeze? */ - video_play_state_t play_state; /* current state of playback */ - video_stream_source_t stream_source; /* current source (demux/memory) */ - video_format_t video_format; /* current aspect ratio of stream*/ - video_displayformat_t display_format;/* selected cropping mode */ - }; - -Return Value ------------- - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/dvb/video-play.rst b/Documentation/media/uapi/dvb/video-play.rst deleted file mode 100644 index fb3f4f168814..000000000000 --- a/Documentation/media/uapi/dvb/video-play.rst +++ /dev/null @@ -1,66 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _VIDEO_PLAY: - -========== -VIDEO_PLAY -========== - -Name ----- - -VIDEO_PLAY - -.. attention:: This ioctl is deprecated. - -Synopsis --------- - -.. c:function:: int ioctl(fd, VIDEO_PLAY) - :name: VIDEO_PLAY - - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - - .. row 1 - - - int fd - - - File descriptor returned by a previous call to open(). - - - .. row 2 - - - int request - - - Equals VIDEO_PLAY for this command. - - -Description ------------ - -This ioctl is for Digital TV devices only. To control a V4L2 decoder use the -V4L2 :ref:`VIDIOC_DECODER_CMD` instead. - -This ioctl call asks the Video Device to start playing a video stream -from the selected source. - - -Return Value ------------- - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/dvb/video-select-source.rst b/Documentation/media/uapi/dvb/video-select-source.rst deleted file mode 100644 index 32cf025356dc..000000000000 --- a/Documentation/media/uapi/dvb/video-select-source.rst +++ /dev/null @@ -1,84 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _VIDEO_SELECT_SOURCE: - -=================== -VIDEO_SELECT_SOURCE -=================== - -Name ----- - -VIDEO_SELECT_SOURCE - -.. attention:: This ioctl is deprecated. - -Synopsis --------- - -.. c:function:: int ioctl(fd, VIDEO_SELECT_SOURCE, video_stream_source_t source) - :name: VIDEO_SELECT_SOURCE - - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - - .. row 1 - - - int fd - - - File descriptor returned by a previous call to open(). - - - .. row 2 - - - int request - - - Equals VIDEO_SELECT_SOURCE for this command. - - - .. row 3 - - - video_stream_source_t source - - - Indicates which source shall be used for the Video stream. - - -Description ------------ - -This ioctl is for Digital TV devices only. This ioctl was also supported by the -V4L2 ivtv driver, but that has been replaced by the ivtv-specific -``IVTV_IOC_PASSTHROUGH_MODE`` ioctl. - -This ioctl call informs the video device which source shall be used for -the input data. The possible sources are demux or memory. If memory is -selected, the data is fed to the video device through the write command. - -.. c:type:: video_stream_source_t - -.. code-block:: c - - typedef enum { - VIDEO_SOURCE_DEMUX, /* Select the demux as the main source */ - VIDEO_SOURCE_MEMORY /* If this source is selected, the stream - comes from the user through the write - system call */ - } video_stream_source_t; - -Return Value ------------- - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/dvb/video-set-blank.rst b/Documentation/media/uapi/dvb/video-set-blank.rst deleted file mode 100644 index 901c3c80f167..000000000000 --- a/Documentation/media/uapi/dvb/video-set-blank.rst +++ /dev/null @@ -1,73 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _VIDEO_SET_BLANK: - -=============== -VIDEO_SET_BLANK -=============== - -Name ----- - -VIDEO_SET_BLANK - -.. attention:: This ioctl is deprecated. - -Synopsis --------- - -.. c:function:: int ioctl(fd, VIDEO_SET_BLANK, boolean mode) - :name: VIDEO_SET_BLANK - - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - - .. row 1 - - - int fd - - - File descriptor returned by a previous call to open(). - - - .. row 2 - - - int request - - - Equals VIDEO_SET_BLANK for this command. - - - .. row 3 - - - boolean mode - - - TRUE: Blank screen when stop. - - - .. row 4 - - - - - FALSE: Show last decoded frame. - - -Description ------------ - -This ioctl call asks the Video Device to blank out the picture. - - -Return Value ------------- - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/dvb/video-set-display-format.rst b/Documentation/media/uapi/dvb/video-set-display-format.rst deleted file mode 100644 index ffdefa341207..000000000000 --- a/Documentation/media/uapi/dvb/video-set-display-format.rst +++ /dev/null @@ -1,69 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _VIDEO_SET_DISPLAY_FORMAT: - -======================== -VIDEO_SET_DISPLAY_FORMAT -======================== - -Name ----- - -VIDEO_SET_DISPLAY_FORMAT - -.. attention:: This ioctl is deprecated. - -Synopsis --------- - -.. c:function:: int ioctl(fd, VIDEO_SET_DISPLAY_FORMAT) - :name: VIDEO_SET_DISPLAY_FORMAT - - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - - .. row 1 - - - int fd - - - File descriptor returned by a previous call to open(). - - - .. row 2 - - - int request - - - Equals VIDEO_SET_DISPLAY_FORMAT for this command. - - - .. row 3 - - - video_display_format_t format - - - Selects the video format to be used. - - -Description ------------ - -This ioctl call asks the Video Device to select the video format to be -applied by the MPEG chip on the video. - - -Return Value ------------- - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/dvb/video-set-format.rst b/Documentation/media/uapi/dvb/video-set-format.rst deleted file mode 100644 index 63e60214ab37..000000000000 --- a/Documentation/media/uapi/dvb/video-set-format.rst +++ /dev/null @@ -1,92 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _VIDEO_SET_FORMAT: - -================ -VIDEO_SET_FORMAT -================ - -Name ----- - -VIDEO_SET_FORMAT - -.. attention:: This ioctl is deprecated. - -Synopsis --------- - -.. c:function:: int ioctl(fd, VIDEO_SET_FORMAT, video_format_t format) - :name: VIDEO_SET_FORMAT - - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - - .. row 1 - - - int fd - - - File descriptor returned by a previous call to open(). - - - .. row 2 - - - int request - - - Equals VIDEO_SET_FORMAT for this command. - - - .. row 3 - - - video_format_t format - - - video format of TV as defined in section ??. - - -Description ------------ - -This ioctl sets the screen format (aspect ratio) of the connected output -device (TV) so that the output of the decoder can be adjusted -accordingly. - -.. c:type:: video_format_t - -.. code-block:: c - - typedef enum { - VIDEO_FORMAT_4_3, /* Select 4:3 format */ - VIDEO_FORMAT_16_9, /* Select 16:9 format. */ - VIDEO_FORMAT_221_1 /* 2.21:1 */ - } video_format_t; - -Return Value ------------- - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. - - - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - - .. row 1 - - - ``EINVAL`` - - - format is not a valid video format. diff --git a/Documentation/media/uapi/dvb/video-set-streamtype.rst b/Documentation/media/uapi/dvb/video-set-streamtype.rst deleted file mode 100644 index 845486a6e049..000000000000 --- a/Documentation/media/uapi/dvb/video-set-streamtype.rst +++ /dev/null @@ -1,70 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _VIDEO_SET_STREAMTYPE: - -==================== -VIDEO_SET_STREAMTYPE -==================== - -Name ----- - -VIDEO_SET_STREAMTYPE - -.. attention:: This ioctl is deprecated. - -Synopsis --------- - -.. c:function:: int ioctl(fd, VIDEO_SET_STREAMTYPE, int type) - :name: VIDEO_SET_STREAMTYPE - - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - - .. row 1 - - - int fd - - - File descriptor returned by a previous call to open(). - - - .. row 2 - - - int request - - - Equals VIDEO_SET_STREAMTYPE for this command. - - - .. row 3 - - - int type - - - stream type - - -Description ------------ - -This ioctl tells the driver which kind of stream to expect being written -to it. If this call is not used the default of video PES is used. Some -drivers might not support this call and always expect PES. - - -Return Value ------------- - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/dvb/video-slowmotion.rst b/Documentation/media/uapi/dvb/video-slowmotion.rst deleted file mode 100644 index 32c934aaf2ba..000000000000 --- a/Documentation/media/uapi/dvb/video-slowmotion.rst +++ /dev/null @@ -1,83 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _VIDEO_SLOWMOTION: - -================ -VIDEO_SLOWMOTION -================ - -Name ----- - -VIDEO_SLOWMOTION - -.. attention:: This ioctl is deprecated. - -Synopsis --------- - -.. c:function:: int ioctl(fd, VIDEO_SLOWMOTION, int nFrames) - :name: VIDEO_SLOWMOTION - - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - - .. row 1 - - - int fd - - - File descriptor returned by a previous call to open(). - - - .. row 2 - - - int request - - - Equals VIDEO_SLOWMOTION for this command. - - - .. row 3 - - - int nFrames - - - The number of times to repeat each frame. - - -Description ------------ - -This ioctl call asks the video device to repeat decoding frames N number -of times. This call can only be used if VIDEO_SOURCE_MEMORY is -selected. - - -Return Value ------------- - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. - - - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - - .. row 1 - - - ``EPERM`` - - - Mode VIDEO_SOURCE_MEMORY not selected. diff --git a/Documentation/media/uapi/dvb/video-stillpicture.rst b/Documentation/media/uapi/dvb/video-stillpicture.rst deleted file mode 100644 index 58035a7630e6..000000000000 --- a/Documentation/media/uapi/dvb/video-stillpicture.rst +++ /dev/null @@ -1,70 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _VIDEO_STILLPICTURE: - -================== -VIDEO_STILLPICTURE -================== - -Name ----- - -VIDEO_STILLPICTURE - -.. attention:: This ioctl is deprecated. - -Synopsis --------- - -.. c:function:: int ioctl(fd, VIDEO_STILLPICTURE, struct video_still_picture *sp) - :name: VIDEO_STILLPICTURE - - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - - .. row 1 - - - int fd - - - File descriptor returned by a previous call to open(). - - - .. row 2 - - - int request - - - Equals VIDEO_STILLPICTURE for this command. - - - .. row 3 - - - struct video_still_picture \*sp - - - Pointer to a location where an I-frame and size is stored. - - -Description ------------ - -This ioctl call asks the Video Device to display a still picture -(I-frame). The input data shall contain an I-frame. If the pointer is -NULL, then the current displayed still picture is blanked. - - -Return Value ------------- - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/dvb/video-stop.rst b/Documentation/media/uapi/dvb/video-stop.rst deleted file mode 100644 index 732ace05e34b..000000000000 --- a/Documentation/media/uapi/dvb/video-stop.rst +++ /dev/null @@ -1,83 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _VIDEO_STOP: - -========== -VIDEO_STOP -========== - -Name ----- - -VIDEO_STOP - -.. attention:: This ioctl is deprecated. - -Synopsis --------- - -.. c:function:: int ioctl(fd, VIDEO_STOP, boolean mode) - :name: VIDEO_STOP - - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - - .. row 1 - - - int fd - - - File descriptor returned by a previous call to open(). - - - .. row 2 - - - int request - - - Equals VIDEO_STOP for this command. - - - .. row 3 - - - Boolean mode - - - Indicates how the screen shall be handled. - - - .. row 4 - - - - - TRUE: Blank screen when stop. - - - .. row 5 - - - - - FALSE: Show last decoded frame. - - -Description ------------ - -This ioctl is for Digital TV devices only. To control a V4L2 decoder use the -V4L2 :ref:`VIDIOC_DECODER_CMD` instead. - -This ioctl call asks the Video Device to stop playing the current -stream. Depending on the input parameter, the screen can be blanked out -or displaying the last decoded frame. - - -Return Value ------------- - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/dvb/video-try-command.rst b/Documentation/media/uapi/dvb/video-try-command.rst deleted file mode 100644 index 37ecf8e91eb8..000000000000 --- a/Documentation/media/uapi/dvb/video-try-command.rst +++ /dev/null @@ -1,75 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _VIDEO_TRY_COMMAND: - -================= -VIDEO_TRY_COMMAND -================= - -Name ----- - -VIDEO_TRY_COMMAND - -.. attention:: This ioctl is deprecated. - -Synopsis --------- - -.. c:function:: int ioctl(int fd, VIDEO_TRY_COMMAND, struct video_command *cmd) - :name: VIDEO_TRY_COMMAND - - -Arguments ---------- - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - - .. row 1 - - - int fd - - - File descriptor returned by a previous call to open(). - - - .. row 2 - - - int request - - - Equals VIDEO_TRY_COMMAND for this command. - - - .. row 3 - - - struct video_command \*cmd - - - Try a decoder command. - - -Description ------------ - -This ioctl is obsolete. Do not use in new drivers. For V4L2 decoders -this ioctl has been replaced by the -:ref:`VIDIOC_TRY_DECODER_CMD ` ioctl. - -This ioctl tries a decoder command. The ``video_command`` struct is a -subset of the ``v4l2_decoder_cmd`` struct, so refer to the -:ref:`VIDIOC_TRY_DECODER_CMD ` documentation -for more information. - - -Return Value ------------- - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/dvb/video.rst b/Documentation/media/uapi/dvb/video.rst deleted file mode 100644 index 6d72ed0e2b2d..000000000000 --- a/Documentation/media/uapi/dvb/video.rst +++ /dev/null @@ -1,43 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _dvb_video: - -####################### -Digital TV Video Device -####################### - -The Digital TV video device controls the MPEG2 video decoder of the Digital -TV hardware. It can be accessed through **/dev/dvb/adapter0/video0**. Data -types and and ioctl definitions can be accessed by including -**linux/dvb/video.h** in your application. - -Note that the Digital TV video device only controls decoding of the MPEG video -stream, not its presentation on the TV or computer screen. On PCs this -is typically handled by an associated video4linux device, e.g. -**/dev/video**, which allows scaling and defining output windows. - -Some Digital TV cards don’t have their own MPEG decoder, which results in the -omission of the audio and video device as well as the video4linux -device. - -The ioctls that deal with SPUs (sub picture units) and navigation -packets are only supported on some MPEG decoders made for DVD playback. - -These ioctls were also used by V4L2 to control MPEG decoders implemented -in V4L2. The use of these ioctls for that purpose has been made obsolete -and proper V4L2 ioctls or controls have been created to replace that -functionality. - - -.. toctree:: - :maxdepth: 1 - - video_types - video_function_calls diff --git a/Documentation/media/uapi/dvb/video_function_calls.rst b/Documentation/media/uapi/dvb/video_function_calls.rst deleted file mode 100644 index 9e8e49e52b19..000000000000 --- a/Documentation/media/uapi/dvb/video_function_calls.rst +++ /dev/null @@ -1,42 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _video_function_calls: - -******************** -Video Function Calls -******************** - -.. toctree:: - :maxdepth: 1 - - video-fopen - video-fclose - video-fwrite - video-stop - video-play - video-freeze - video-continue - video-select-source - video-set-blank - video-get-status - video-get-frame-count - video-get-pts - video-get-event - video-command - video-try-command - video-get-size - video-set-display-format - video-stillpicture - video-fast-forward - video-slowmotion - video-get-capabilities - video-clear-buffer - video-set-streamtype - video-set-format diff --git a/Documentation/media/uapi/dvb/video_types.rst b/Documentation/media/uapi/dvb/video_types.rst deleted file mode 100644 index 2697400ccf62..000000000000 --- a/Documentation/media/uapi/dvb/video_types.rst +++ /dev/null @@ -1,255 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _video_types: - -**************** -Video Data Types -**************** - - -.. _video-format-t: - -video_format_t -============== - -The ``video_format_t`` data type defined by - - -.. code-block:: c - - typedef enum { - VIDEO_FORMAT_4_3, /* Select 4:3 format */ - VIDEO_FORMAT_16_9, /* Select 16:9 format. */ - VIDEO_FORMAT_221_1 /* 2.21:1 */ - } video_format_t; - -is used in the VIDEO_SET_FORMAT function (??) to tell the driver which -aspect ratio the output hardware (e.g. TV) has. It is also used in the -data structures video_status (??) returned by VIDEO_GET_STATUS (??) -and video_event (??) returned by VIDEO_GET_EVENT (??) which report -about the display format of the current video stream. - - -.. _video-displayformat-t: - -video_displayformat_t -===================== - -In case the display format of the video stream and of the display -hardware differ the application has to specify how to handle the -cropping of the picture. This can be done using the -VIDEO_SET_DISPLAY_FORMAT call (??) which accepts - - -.. code-block:: c - - typedef enum { - VIDEO_PAN_SCAN, /* use pan and scan format */ - VIDEO_LETTER_BOX, /* use letterbox format */ - VIDEO_CENTER_CUT_OUT /* use center cut out format */ - } video_displayformat_t; - -as argument. - - -.. _video-stream-source-t: - -video_stream_source_t -===================== - -The video stream source is set through the VIDEO_SELECT_SOURCE call -and can take the following values, depending on whether we are replaying -from an internal (demuxer) or external (user write) source. - - -.. code-block:: c - - typedef enum { - VIDEO_SOURCE_DEMUX, /* Select the demux as the main source */ - VIDEO_SOURCE_MEMORY /* If this source is selected, the stream - comes from the user through the write - system call */ - } video_stream_source_t; - -VIDEO_SOURCE_DEMUX selects the demultiplexer (fed either by the -frontend or the DVR device) as the source of the video stream. If -VIDEO_SOURCE_MEMORY is selected the stream comes from the application -through the **write()** system call. - - -.. _video-play-state-t: - -video_play_state_t -================== - -The following values can be returned by the VIDEO_GET_STATUS call -representing the state of video playback. - - -.. code-block:: c - - typedef enum { - VIDEO_STOPPED, /* Video is stopped */ - VIDEO_PLAYING, /* Video is currently playing */ - VIDEO_FREEZED /* Video is freezed */ - } video_play_state_t; - - -.. c:type:: video_command - -struct video_command -==================== - -The structure must be zeroed before use by the application This ensures -it can be extended safely in the future. - - -.. code-block:: c - - struct video_command { - __u32 cmd; - __u32 flags; - union { - struct { - __u64 pts; - } stop; - - struct { - /* 0 or 1000 specifies normal speed, - 1 specifies forward single stepping, - -1 specifies backward single stepping, - >>1: playback at speed/1000 of the normal speed, - <-1: reverse playback at (-speed/1000) of the normal speed. */ - __s32 speed; - __u32 format; - } play; - - struct { - __u32 data[16]; - } raw; - }; - }; - - -.. _video-size-t: - -video_size_t -============ - - -.. code-block:: c - - typedef struct { - int w; - int h; - video_format_t aspect_ratio; - } video_size_t; - - -.. c:type:: video_event - -struct video_event -================== - -The following is the structure of a video event as it is returned by the -VIDEO_GET_EVENT call. - - -.. code-block:: c - - struct video_event { - __s32 type; - #define VIDEO_EVENT_SIZE_CHANGED 1 - #define VIDEO_EVENT_FRAME_RATE_CHANGED 2 - #define VIDEO_EVENT_DECODER_STOPPED 3 - #define VIDEO_EVENT_VSYNC 4 - long timestamp; - union { - video_size_t size; - unsigned int frame_rate; /* in frames per 1000sec */ - unsigned char vsync_field; /* unknown/odd/even/progressive */ - } u; - }; - - -.. c:type:: video_status - -struct video_status -=================== - -The VIDEO_GET_STATUS call returns the following structure informing -about various states of the playback operation. - - -.. code-block:: c - - struct video_status { - int video_blank; /* blank video on freeze? */ - video_play_state_t play_state; /* current state of playback */ - video_stream_source_t stream_source; /* current source (demux/memory) */ - video_format_t video_format; /* current aspect ratio of stream */ - video_displayformat_t display_format;/* selected cropping mode */ - }; - -If video_blank is set video will be blanked out if the channel is -changed or if playback is stopped. Otherwise, the last picture will be -displayed. play_state indicates if the video is currently frozen, -stopped, or being played back. The stream_source corresponds to the -selected source for the video stream. It can come either from the -demultiplexer or from memory. The video_format indicates the aspect -ratio (one of 4:3 or 16:9) of the currently played video stream. -Finally, display_format corresponds to the selected cropping mode in -case the source video format is not the same as the format of the output -device. - - -.. c:type:: video_still_picture - -struct video_still_picture -========================== - -An I-frame displayed via the VIDEO_STILLPICTURE call is passed on -within the following structure. - - -.. code-block:: c - - /* pointer to and size of a single iframe in memory */ - struct video_still_picture { - char *iFrame; /* pointer to a single iframe in memory */ - int32_t size; - }; - - -.. _video_caps: - -video capabilities -================== - -A call to VIDEO_GET_CAPABILITIES returns an unsigned integer with the -following bits set according to the hardwares capabilities. - - -.. code-block:: c - - /* bit definitions for capabilities: */ - /* can the hardware decode MPEG1 and/or MPEG2? */ - #define VIDEO_CAP_MPEG1 1 - #define VIDEO_CAP_MPEG2 2 - /* can you send a system and/or program stream to video device? - (you still have to open the video and the audio device but only - send the stream to the video device) */ - #define VIDEO_CAP_SYS 4 - #define VIDEO_CAP_PROG 8 - /* can the driver also handle SPU, NAVI and CSS encoded data? - (CSS API is not present yet) */ - #define VIDEO_CAP_SPU 16 - #define VIDEO_CAP_NAVI 32 - #define VIDEO_CAP_CSS 64 diff --git a/Documentation/media/uapi/fdl-appendix.rst b/Documentation/media/uapi/fdl-appendix.rst deleted file mode 100644 index 9316b8617502..000000000000 --- a/Documentation/media/uapi/fdl-appendix.rst +++ /dev/null @@ -1,478 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _fdl: - -****************************** -GNU Free Documentation License -****************************** - - -.. _fdl-preamble: - -0. PREAMBLE -=========== - -The purpose of this License is to make a manual, textbook, or other -written document “free” in the sense of freedom: to assure everyone the -effective freedom to copy and redistribute it, with or without modifying -it, either commercially or noncommercially. Secondarily, this License -preserves for the author and publisher a way to get credit for their -work, while not being considered responsible for modifications made by -others. - -This License is a kind of “copyleft”, which means that derivative works -of the document must themselves be free in the same sense. It -complements the GNU General Public License, which is a copyleft license -designed for free software. - -We have designed this License in order to use it for manuals for free -software, because free software needs free documentation: a free program -should come with manuals providing the same freedoms that the software -does. But this License is not limited to software manuals; it can be -used for any textual work, regardless of subject matter or whether it is -published as a printed book. We recommend this License principally for -works whose purpose is instruction or reference. - - -.. _fdl-section1: - -1. APPLICABILITY AND DEFINITIONS -================================ - - -.. _fdl-document: - -This License applies to any manual or other work that contains a notice -placed by the copyright holder saying it can be distributed under the -terms of this License. The “Document”, below, refers to any such manual -or work. Any member of the public is a licensee, and is addressed as -“you”. - - -.. _fdl-modified: - -A “Modified Version” of the Document means any work containing the -Document or a portion of it, either copied verbatim, or with -modifications and/or translated into another language. - - -.. _fdl-secondary: - -A “Secondary Section” is a named appendix or a front-matter section of -the :ref:`Document ` that deals exclusively with the -relationship of the publishers or authors of the Document to the -Document's overall subject (or to related matters) and contains nothing -that could fall directly within that overall subject. (For example, if -the Document is in part a textbook of mathematics, a Secondary Section -may not explain any mathematics.) The relationship could be a matter of -historical connection with the subject or with related matters, or of -legal, commercial, philosophical, ethical or political position -regarding them. - - -.. _fdl-invariant: - -The “Invariant Sections” are certain -:ref:`Secondary Sections ` whose titles are designated, -as being those of Invariant Sections, in the notice that says that the -:ref:`Document ` is released under this License. - - -.. _fdl-cover-texts: - -The “Cover Texts” are certain short passages of text that are listed, as -Front-Cover Texts or Back-Cover Texts, in the notice that says that the -:ref:`Document ` is released under this License. - - -.. _fdl-transparent: - -A “Transparent” copy of the :ref:`Document ` means a -machine-readable copy, represented in a format whose specification is -available to the general public, whose contents can be viewed and edited -directly and straightforwardly with generic text editors or (for images -composed of pixels) generic paint programs or (for drawings) some widely -available drawing editor, and that is suitable for input to text -formatters or for automatic translation to a variety of formats suitable -for input to text formatters. A copy made in an otherwise Transparent -file format whose markup has been designed to thwart or discourage -subsequent modification by readers is not Transparent. A copy that is -not “Transparent” is called “Opaque”. - -Examples of suitable formats for Transparent copies include plain ASCII -without markup, Texinfo input format, LaTeX input format, SGML or XML -using a publicly available DTD, and standard-conforming simple HTML -designed for human modification. Opaque formats include PostScript, PDF, -proprietary formats that can be read and edited only by proprietary word -processors, SGML or XML for which the DTD and/or processing tools are -not generally available, and the machine-generated HTML produced by some -word processors for output purposes only. - - -.. _fdl-title-page: - -The “Title Page” means, for a printed book, the title page itself, plus -such following pages as are needed to hold, legibly, the material this -License requires to appear in the title page. For works in formats which -do not have any title page as such, “Title Page” means the text near the -most prominent appearance of the work's title, preceding the beginning -of the body of the text. - - -.. _fdl-section2: - -2. VERBATIM COPYING -=================== - -You may copy and distribute the :ref:`Document ` in any -medium, either commercially or noncommercially, provided that this -License, the copyright notices, and the license notice saying this -License applies to the Document are reproduced in all copies, and that -you add no other conditions whatsoever to those of this License. You may -not use technical measures to obstruct or control the reading or further -copying of the copies you make or distribute. However, you may accept -compensation in exchange for copies. If you distribute a large enough -number of copies you must also follow the conditions in -:ref:`section 3 `. - -You may also lend copies, under the same conditions stated above, and -you may publicly display copies. - - -.. _fdl-section3: - -3. COPYING IN QUANTITY -====================== - -If you publish printed copies of the :ref:`Document ` -numbering more than 100, and the Document's license notice requires -:ref:`Cover Texts `, you must enclose the copies in -covers that carry, clearly and legibly, all these Cover Texts: -Front-Cover Texts on the front cover, and Back-Cover Texts on the back -cover. Both covers must also clearly and legibly identify you as the -publisher of these copies. The front cover must present the full title -with all words of the title equally prominent and visible. You may add -other material on the covers in addition. Copying with changes limited -to the covers, as long as they preserve the title of the -:ref:`Document ` and satisfy these conditions, can be -treated as verbatim copying in other respects. - -If the required texts for either cover are too voluminous to fit -legibly, you should put the first ones listed (as many as fit -reasonably) on the actual cover, and continue the rest onto adjacent -pages. - -If you publish or distribute :ref:`Opaque ` copies of -the :ref:`Document ` numbering more than 100, you must -either include a machine-readable :ref:`Transparent ` -copy along with each Opaque copy, or state in or with each Opaque copy a -publicly-accessible computer-network location containing a complete -Transparent copy of the Document, free of added material, which the -general network-using public has access to download anonymously at no -charge using public-standard network protocols. If you use the latter -option, you must take reasonably prudent steps, when you begin -distribution of Opaque copies in quantity, to ensure that this -Transparent copy will remain thus accessible at the stated location -until at least one year after the last time you distribute an Opaque -copy (directly or through your agents or retailers) of that edition to -the public. - -It is requested, but not required, that you contact the authors of the -:ref:`Document ` well before redistributing any large -number of copies, to give them a chance to provide you with an updated -version of the Document. - - -.. _fdl-section4: - -4. MODIFICATIONS -================ - -You may copy and distribute a :ref:`Modified Version ` -of the :ref:`Document ` under the conditions of sections -:ref:`2 ` and :ref:`3 ` above, provided -that you release the Modified Version under precisely this License, with -the Modified Version filling the role of the Document, thus licensing -distribution and modification of the Modified Version to whoever -possesses a copy of it. In addition, you must do these things in the -Modified Version: - -- **A.** - Use in the :ref:`Title Page ` (and on the covers, - if any) a title distinct from that of the - :ref:`Document `, and from those of previous versions - (which should, if there were any, be listed in the History section of - the Document). You may use the same title as a previous version if - the original publisher of that version gives permission. - -- **B.** - List on the :ref:`Title Page `, as authors, one or - more persons or entities responsible for authorship of the - modifications in the :ref:`Modified Version `, - together with at least five of the principal authors of the - :ref:`Document ` (all of its principal authors, if it - has less than five). - -- **C.** - State on the :ref:`Title Page ` the name of the - publisher of the :ref:`Modified Version `, as the - publisher. - -- **D.** - Preserve all the copyright notices of the - :ref:`Document `. - -- **E.** - Add an appropriate copyright notice for your modifications adjacent - to the other copyright notices. - -- **F.** - Include, immediately after the copyright notices, a license notice - giving the public permission to use the - :ref:`Modified Version ` under the terms of this - License, in the form shown in the Addendum below. - -- **G.** - Preserve in that license notice the full lists of - :ref:`Invariant Sections ` and required - :ref:`Cover Texts ` given in the - :ref:`Document's ` license notice. - -- **H.** - Include an unaltered copy of this License. - -- **I.** - Preserve the section entitled “History”, and its title, and add to it - an item stating at least the title, year, new authors, and publisher - of the :ref:`Modified Version ` as given on the - :ref:`Title Page `. If there is no section entitled - “History” in the :ref:`Document `, create one stating - the title, year, authors, and publisher of the Document as given on - its Title Page, then add an item describing the Modified Version as - stated in the previous sentence. - -- **J.** - Preserve the network location, if any, given in the - :ref:`Document ` for public access to a - :ref:`Transparent ` copy of the Document, and - likewise the network locations given in the Document for previous - versions it was based on. These may be placed in the “History” - section. You may omit a network location for a work that was - published at least four years before the Document itself, or if the - original publisher of the version it refers to gives permission. - -- **K.** - In any section entitled “Acknowledgements” or “Dedications”, preserve - the section's title, and preserve in the section all the substance - and tone of each of the contributor acknowledgements and/or - dedications given therein. - -- **L.** - Preserve all the :ref:`Invariant Sections ` of the - :ref:`Document `, unaltered in their text and in - their titles. Section numbers or the equivalent are not considered - part of the section titles. - -- **M.** - Delete any section entitled “Endorsements”. Such a section may not be - included in the :ref:`Modified Version `. - -- **N.** - Do not retitle any existing section as “Endorsements” or to conflict - in title with any :ref:`Invariant Section `. - -If the :ref:`Modified Version ` includes new -front-matter sections or appendices that qualify as -:ref:`Secondary Sections ` and contain no material -copied from the Document, you may at your option designate some or all -of these sections as invariant. To do this, add their titles to the list -of :ref:`Invariant Sections ` in the Modified Version's -license notice. These titles must be distinct from any other section -titles. - -You may add a section entitled “Endorsements”, provided it contains -nothing but endorsements of your -:ref:`Modified Version ` by various parties--for -example, statements of peer review or that the text has been approved by -an organization as the authoritative definition of a standard. - -You may add a passage of up to five words as a -:ref:`Front-Cover Text `, and a passage of up to 25 -words as a :ref:`Back-Cover Text `, to the end of the -list of :ref:`Cover Texts ` in the -:ref:`Modified Version `. Only one passage of -Front-Cover Text and one of Back-Cover Text may be added by (or through -arrangements made by) any one entity. If the -:ref:`Document ` already includes a cover text for the -same cover, previously added by you or by arrangement made by the same -entity you are acting on behalf of, you may not add another; but you may -replace the old one, on explicit permission from the previous publisher -that added the old one. - -The author(s) and publisher(s) of the :ref:`Document ` -do not by this License give permission to use their names for publicity -for or to assert or imply endorsement of any -:ref:`Modified Version `. - - -.. _fdl-section5: - -5. COMBINING DOCUMENTS -====================== - -You may combine the :ref:`Document ` with other -documents released under this License, under the terms defined in -:ref:`section 4 ` above for modified versions, provided -that you include in the combination all of the -:ref:`Invariant Sections ` of all of the original -documents, unmodified, and list them all as Invariant Sections of your -combined work in its license notice. - -The combined work need only contain one copy of this License, and -multiple identical :ref:`Invariant Sections ` may be -replaced with a single copy. If there are multiple Invariant Sections -with the same name but different contents, make the title of each such -section unique by adding at the end of it, in parentheses, the name of -the original author or publisher of that section if known, or else a -unique number. Make the same adjustment to the section titles in the -list of Invariant Sections in the license notice of the combined work. - -In the combination, you must combine any sections entitled “History” in -the various original documents, forming one section entitled “History”; -likewise combine any sections entitled “Acknowledgements”, and any -sections entitled “Dedications”. You must delete all sections entitled -“Endorsements.” - - -.. _fdl-section6: - -6. COLLECTIONS OF DOCUMENTS -=========================== - -You may make a collection consisting of the -:ref:`Document ` and other documents released under this -License, and replace the individual copies of this License in the -various documents with a single copy that is included in the collection, -provided that you follow the rules of this License for verbatim copying -of each of the documents in all other respects. - -You may extract a single document from such a collection, and distribute -it individually under this License, provided you insert a copy of this -License into the extracted document, and follow this License in all -other respects regarding verbatim copying of that document. - - -.. _fdl-section7: - -7. AGGREGATION WITH INDEPENDENT WORKS -===================================== - -A compilation of the :ref:`Document ` or its derivatives -with other separate and independent documents or works, in or on a -volume of a storage or distribution medium, does not as a whole count as -a :ref:`Modified Version ` of the Document, provided no -compilation copyright is claimed for the compilation. Such a compilation -is called an “aggregate”, and this License does not apply to the other -self-contained works thus compiled with the Document , on account of -their being thus compiled, if they are not themselves derivative works -of the Document. If the :ref:`Cover Text ` -requirement of :ref:`section 3 ` is applicable to these -copies of the Document, then if the Document is less than one quarter of -the entire aggregate, the Document's Cover Texts may be placed on covers -that surround only the Document within the aggregate. Otherwise they -must appear on covers around the whole aggregate. - - -.. _fdl-section8: - -8. TRANSLATION -============== - -Translation is considered a kind of modification, so you may distribute -translations of the :ref:`Document ` under the terms of -:ref:`section 4 `. Replacing -:ref:`Invariant Sections ` with translations requires -special permission from their copyright holders, but you may include -translations of some or all Invariant Sections in addition to the -original versions of these Invariant Sections. You may include a -translation of this License provided that you also include the original -English version of this License. In case of a disagreement between the -translation and the original English version of this License, the -original English version will prevail. - - -.. _fdl-section9: - -9. TERMINATION -============== - -You may not copy, modify, sublicense, or distribute the -:ref:`Document ` except as expressly provided for under -this License. Any other attempt to copy, modify, sublicense or -distribute the Document is void, and will automatically terminate your -rights under this License. However, parties who have received copies, or -rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - -.. _fdl-section10: - -10. FUTURE REVISIONS OF THIS LICENSE -==================================== - -The `Free Software Foundation `__ -may publish new, revised versions of the GNU Free Documentation License -from time to time. Such new versions will be similar in spirit to the -present version, but may differ in detail to address new problems or -concerns. See -`http://www.gnu.org/copyleft/ `__. - -Each version of the License is given a distinguishing version number. If -the :ref:`Document ` specifies that a particular -numbered version of this License “or any later version” applies to it, -you have the option of following the terms and conditions either of that -specified version or of any later version that has been published (not -as a draft) by the Free Software Foundation. If the Document does not -specify a version number of this License, you may choose any version -ever published (not as a draft) by the Free Software Foundation. - - -.. _fdl-using: - -Addendum -======== - -To use this License in a document you have written, include a copy of -the License in the document and put the following copyright and license -notices just after the title page: - - Copyright © YEAR YOUR NAME. - - Permission is granted to copy, distribute and/or modify this - document under the terms of the GNU Free Documentation License, - Version 1.1 or any later version published by the Free Software - Foundation; with the :ref:`Invariant Sections ` - being LIST THEIR TITLES, with the - :ref:`Front-Cover Texts ` being LIST, and with - the :ref:`Back-Cover Texts ` being LIST. A copy - of the license is included in the section entitled “GNU Free - Documentation License”. - -If you have no :ref:`Invariant Sections `, write “with -no Invariant Sections” instead of saying which ones are invariant. If -you have no :ref:`Front-Cover Texts `, write “no -Front-Cover Texts” instead of “Front-Cover Texts being LIST”; likewise -for :ref:`Back-Cover Texts `. - -If your document contains nontrivial examples of program code, we -recommend releasing these examples in parallel under your choice of free -software license, such as the -`GNU General Public License `__, -to permit their use in free software. diff --git a/Documentation/media/uapi/gen-errors.rst b/Documentation/media/uapi/gen-errors.rst deleted file mode 100644 index 043c312dc06d..000000000000 --- a/Documentation/media/uapi/gen-errors.rst +++ /dev/null @@ -1,103 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _gen_errors: - -******************* -Generic Error Codes -******************* - - -.. _gen-errors: - -.. tabularcolumns:: |p{2.5cm}|p{15.0cm}| - -.. flat-table:: Generic error codes - :header-rows: 0 - :stub-columns: 0 - :widths: 1 16 - - - - - ``EAGAIN`` (aka ``EWOULDBLOCK``) - - - The ioctl can't be handled because the device is in state where it - can't perform it. This could happen for example in case where - device is sleeping and ioctl is performed to query statistics. It - is also returned when the ioctl would need to wait for an event, - but the device was opened in non-blocking mode. - - - - ``EBADF`` - - - The file descriptor is not a valid. - - - - ``EBUSY`` - - - The ioctl can't be handled because the device is busy. This is - typically return while device is streaming, and an ioctl tried to - change something that would affect the stream, or would require - the usage of a hardware resource that was already allocated. The - ioctl must not be retried without performing another action to fix - the problem first (typically: stop the stream before retrying). - - - - ``EFAULT`` - - - There was a failure while copying data from/to userspace, probably - caused by an invalid pointer reference. - - - - ``EINVAL`` - - - One or more of the ioctl parameters are invalid or out of the - allowed range. This is a widely used error code. See the - individual ioctl requests for specific causes. - - - - ``ENODEV`` - - - Device not found or was removed. - - - - ``ENOMEM`` - - - There's not enough memory to handle the desired operation. - - - - ``ENOTTY`` - - - The ioctl is not supported by the driver, actually meaning that - the required functionality is not available, or the file - descriptor is not for a media device. - - - - ``ENOSPC`` - - - On USB devices, the stream ioctl's can return this error, meaning - that this request would overcommit the usb bandwidth reserved for - periodic transfers (up to 80% of the USB bandwidth). - - - - ``EPERM`` - - - Permission denied. Can be returned if the device needs write - permission, or some special capabilities is needed (e. g. root) - - - - ``EIO`` - - - I/O error. Typically used when there are problems communicating with - a hardware device. This could indicate broken or flaky hardware. - It's a 'Something is wrong, I give up!' type of error. - - - - ``ENXIO`` - - - No device corresponding to this device special file exists. - - -.. note:: - - #. This list is not exhaustive; ioctls may return other error codes. - Since errors may have side effects such as a driver reset, - applications should abort on unexpected errors, or otherwise - assume that the device is in a bad state. - - #. Request-specific error codes are listed in the individual - requests descriptions. diff --git a/Documentation/media/uapi/mediactl/media-controller-intro.rst b/Documentation/media/uapi/mediactl/media-controller-intro.rst deleted file mode 100644 index 281c559c2f3c..000000000000 --- a/Documentation/media/uapi/mediactl/media-controller-intro.rst +++ /dev/null @@ -1,40 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _media-controller-intro: - -Introduction -============ - -Media devices increasingly handle multiple related functions. Many USB -cameras include microphones, video capture hardware can also output -video, or SoC camera interfaces also perform memory-to-memory operations -similar to video codecs. - -Independent functions, even when implemented in the same hardware, can -be modelled as separate devices. A USB camera with a microphone will be -presented to userspace applications as V4L2 and ALSA capture devices. -The devices' relationships (when using a webcam, end-users shouldn't -have to manually select the associated USB microphone), while not made -available directly to applications by the drivers, can usually be -retrieved from sysfs. - -With more and more advanced SoC devices being introduced, the current -approach will not scale. Device topologies are getting increasingly -complex and can't always be represented by a tree structure. Hardware -blocks are shared between different functions, creating dependencies -between seemingly unrelated devices. - -Kernel abstraction APIs such as V4L2 and ALSA provide means for -applications to access hardware parameters. As newer hardware expose an -increasingly high number of those parameters, drivers need to guess what -applications really require based on limited information, thereby -implementing policies that belong to userspace. - -The media controller API aims at solving those problems. diff --git a/Documentation/media/uapi/mediactl/media-controller-model.rst b/Documentation/media/uapi/mediactl/media-controller-model.rst deleted file mode 100644 index b6d5902b556d..000000000000 --- a/Documentation/media/uapi/mediactl/media-controller-model.rst +++ /dev/null @@ -1,42 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _media-controller-model: - -Media device model -================== - -Discovering a device internal topology, and configuring it at runtime, -is one of the goals of the media controller API. To achieve this, -hardware devices and Linux Kernel interfaces are modelled as graph -objects on an oriented graph. The object types that constitute the graph -are: - -- An **entity** is a basic media hardware or software building block. - It can correspond to a large variety of logical blocks such as - physical hardware devices (CMOS sensor for instance), logical - hardware devices (a building block in a System-on-Chip image - processing pipeline), DMA channels or physical connectors. - -- An **interface** is a graph representation of a Linux Kernel - userspace API interface, like a device node or a sysfs file that - controls one or more entities in the graph. - -- A **pad** is a data connection endpoint through which an entity can - interact with other entities. Data (not restricted to video) produced - by an entity flows from the entity's output to one or more entity - inputs. Pads should not be confused with physical pins at chip - boundaries. - -- A **data link** is a point-to-point oriented connection between two - pads, either on the same entity or on different entities. Data flows - from a source pad to a sink pad. - -- An **interface link** is a point-to-point bidirectional control - connection between a Linux Kernel interface and an entity. diff --git a/Documentation/media/uapi/mediactl/media-controller.rst b/Documentation/media/uapi/mediactl/media-controller.rst deleted file mode 100644 index 6e624f690331..000000000000 --- a/Documentation/media/uapi/mediactl/media-controller.rst +++ /dev/null @@ -1,62 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. include:: - -.. _media_controller: - -############################## -Part IV - Media Controller API -############################## - -.. only:: html - - .. class:: toc-title - - Table of Contents - -.. toctree:: - :maxdepth: 5 - :numbered: - - media-controller-intro - media-controller-model - media-types - request-api - media-funcs - media-header - - -********************** -Revision and Copyright -********************** - -Authors: - -- Pinchart, Laurent - - - Initial version. - -- Carvalho Chehab, Mauro - - - MEDIA_IOC_G_TOPOLOGY documentation and documentation improvements. - -**Copyright** |copy| 2010 : Laurent Pinchart - -**Copyright** |copy| 2015-2016 : Mauro Carvalho Chehab - -**************** -Revision History -**************** - -:revision: 1.1.0 / 2015-12-12 (*mcc*) - -:revision: 1.0.0 / 2010-11-10 (*lp*) - -Initial revision diff --git a/Documentation/media/uapi/mediactl/media-func-close.rst b/Documentation/media/uapi/mediactl/media-func-close.rst deleted file mode 100644 index 369ccd4dee56..000000000000 --- a/Documentation/media/uapi/mediactl/media-func-close.rst +++ /dev/null @@ -1,54 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _media-func-close: - -************* -media close() -************* - -Name -==== - -media-close - Close a media device - - -Synopsis -======== - -.. code-block:: c - - #include - - -.. c:function:: int close( int fd ) - :name: mc-close - -Arguments -========= - -``fd`` - File descriptor returned by :c:func:`open() `. - - -Description -=========== - -Closes the media device. Resources associated with the file descriptor -are freed. The device configuration remain unchanged. - - -Return Value -============ - -:ref:`close() ` returns 0 on success. On error, -1 is returned, and -``errno`` is set appropriately. Possible error codes are: - -EBADF - ``fd`` is not a valid open file descriptor. diff --git a/Documentation/media/uapi/mediactl/media-func-ioctl.rst b/Documentation/media/uapi/mediactl/media-func-ioctl.rst deleted file mode 100644 index 9a990d6480f5..000000000000 --- a/Documentation/media/uapi/mediactl/media-func-ioctl.rst +++ /dev/null @@ -1,74 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _media-func-ioctl: - -************* -media ioctl() -************* - -Name -==== - -media-ioctl - Control a media device - - -Synopsis -======== - -.. code-block:: c - - #include - - -.. c:function:: int ioctl( int fd, int request, void *argp ) - :name: mc-ioctl - -Arguments -========= - -``fd`` - File descriptor returned by :c:func:`open() `. - -``request`` - Media ioctl request code as defined in the media.h header file, for - example MEDIA_IOC_SETUP_LINK. - -``argp`` - Pointer to a request-specific structure. - - -Description -=========== - -The :ref:`ioctl() ` function manipulates media device -parameters. The argument ``fd`` must be an open file descriptor. - -The ioctl ``request`` code specifies the media function to be called. It -has encoded in it whether the argument is an input, output or read/write -parameter, and the size of the argument ``argp`` in bytes. - -Macros and structures definitions specifying media ioctl requests and -their parameters are located in the media.h header file. All media ioctl -requests, their respective function and parameters are specified in -:ref:`media-user-func`. - - -Return Value -============ - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. - -Request-specific error codes are listed in the individual requests -descriptions. - -When an ioctl that takes an output or read/write parameter fails, the -parameter remains unmodified. diff --git a/Documentation/media/uapi/mediactl/media-func-open.rst b/Documentation/media/uapi/mediactl/media-func-open.rst deleted file mode 100644 index cd2f840ddf73..000000000000 --- a/Documentation/media/uapi/mediactl/media-func-open.rst +++ /dev/null @@ -1,76 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _media-func-open: - -************ -media open() -************ - -Name -==== - -media-open - Open a media device - - -Synopsis -======== - -.. code-block:: c - - #include - - -.. c:function:: int open( const char *device_name, int flags ) - :name: mc-open - -Arguments -========= - -``device_name`` - Device to be opened. - -``flags`` - Open flags. Access mode must be either ``O_RDONLY`` or ``O_RDWR``. - Other flags have no effect. - - -Description -=========== - -To open a media device applications call :ref:`open() ` with the -desired device name. The function has no side effects; the device -configuration remain unchanged. - -When the device is opened in read-only mode, attempts to modify its -configuration will result in an error, and ``errno`` will be set to -EBADF. - - -Return Value -============ - -:ref:`open() ` returns the new file descriptor on success. On error, --1 is returned, and ``errno`` is set appropriately. Possible error codes -are: - -EACCES - The requested access to the file is not allowed. - -EMFILE - The process already has the maximum number of files open. - -ENFILE - The system limit on the total number of open files has been reached. - -ENOMEM - Insufficient kernel memory was available. - -ENXIO - No device corresponding to this device special file exists. diff --git a/Documentation/media/uapi/mediactl/media-funcs.rst b/Documentation/media/uapi/mediactl/media-funcs.rst deleted file mode 100644 index 87b65df8252a..000000000000 --- a/Documentation/media/uapi/mediactl/media-funcs.rst +++ /dev/null @@ -1,33 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _media-user-func: - -****************** -Function Reference -****************** - - -.. toctree:: - :maxdepth: 1 - - media-func-open - media-func-close - media-func-ioctl - media-ioc-device-info - media-ioc-g-topology - media-ioc-enum-entities - media-ioc-enum-links - media-ioc-setup-link - media-ioc-request-alloc - request-func-close - request-func-ioctl - request-func-poll - media-request-ioc-queue - media-request-ioc-reinit diff --git a/Documentation/media/uapi/mediactl/media-header.rst b/Documentation/media/uapi/mediactl/media-header.rst deleted file mode 100644 index 1cb7c88aeff0..000000000000 --- a/Documentation/media/uapi/mediactl/media-header.rst +++ /dev/null @@ -1,17 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _media_header: - -**************************** -Media Controller Header File -**************************** - -.. kernel-include:: $BUILDDIR/media.h.rst - diff --git a/Documentation/media/uapi/mediactl/media-ioc-device-info.rst b/Documentation/media/uapi/mediactl/media-ioc-device-info.rst deleted file mode 100644 index f8038cfb708c..000000000000 --- a/Documentation/media/uapi/mediactl/media-ioc-device-info.rst +++ /dev/null @@ -1,118 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _media_ioc_device_info: - -*************************** -ioctl MEDIA_IOC_DEVICE_INFO -*************************** - -Name -==== - -MEDIA_IOC_DEVICE_INFO - Query device information - - -Synopsis -======== - -.. c:function:: int ioctl( int fd, MEDIA_IOC_DEVICE_INFO, struct media_device_info *argp ) - :name: MEDIA_IOC_DEVICE_INFO - - -Arguments -========= - -``fd`` - File descriptor returned by :ref:`open() `. - -``argp`` - Pointer to struct :c:type:`media_device_info`. - - -Description -=========== - -All media devices must support the ``MEDIA_IOC_DEVICE_INFO`` ioctl. To -query device information, applications call the ioctl with a pointer to -a struct :c:type:`media_device_info`. The driver -fills the structure and returns the information to the application. The -ioctl never fails. - - -.. c:type:: media_device_info - -.. tabularcolumns:: |p{4.4cm}|p{4.4cm}|p{8.7cm}| - -.. flat-table:: struct media_device_info - :header-rows: 0 - :stub-columns: 0 - :widths: 1 1 2 - - - * - char - - ``driver``\ [16] - - Name of the driver implementing the media API as a NUL-terminated - ASCII string. The driver version is stored in the - ``driver_version`` field. - - Driver specific applications can use this information to verify - the driver identity. It is also useful to work around known bugs, - or to identify drivers in error reports. - - * - char - - ``model``\ [32] - - Device model name as a NUL-terminated UTF-8 string. The device - version is stored in the ``device_version`` field and is not be - appended to the model name. - - * - char - - ``serial``\ [40] - - Serial number as a NUL-terminated ASCII string. - - * - char - - ``bus_info``\ [32] - - Location of the device in the system as a NUL-terminated ASCII - string. This includes the bus type name (PCI, USB, ...) and a - bus-specific identifier. - - * - __u32 - - ``media_version`` - - Media API version, formatted with the ``KERNEL_VERSION()`` macro. - - * - __u32 - - ``hw_revision`` - - Hardware device revision in a driver-specific format. - - * - __u32 - - ``driver_version`` - - Media device driver version, formatted with the - ``KERNEL_VERSION()`` macro. Together with the ``driver`` field - this identifies a particular driver. - - * - __u32 - - ``reserved``\ [31] - - Reserved for future extensions. Drivers and applications must set - this array to zero. - - -The ``serial`` and ``bus_info`` fields can be used to distinguish -between multiple instances of otherwise identical hardware. The serial -number takes precedence when provided and can be assumed to be unique. -If the serial number is an empty string, the ``bus_info`` field can be -used instead. The ``bus_info`` field is guaranteed to be unique, but can -vary across reboots or device unplug/replug. - - -Return Value -============ - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/mediactl/media-ioc-enum-entities.rst b/Documentation/media/uapi/mediactl/media-ioc-enum-entities.rst deleted file mode 100644 index 33e2b110145c..000000000000 --- a/Documentation/media/uapi/mediactl/media-ioc-enum-entities.rst +++ /dev/null @@ -1,156 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _media_ioc_enum_entities: - -***************************** -ioctl MEDIA_IOC_ENUM_ENTITIES -***************************** - -Name -==== - -MEDIA_IOC_ENUM_ENTITIES - Enumerate entities and their properties - - -Synopsis -======== - -.. c:function:: int ioctl( int fd, MEDIA_IOC_ENUM_ENTITIES, struct media_entity_desc *argp ) - :name: MEDIA_IOC_ENUM_ENTITIES - - -Arguments -========= - -``fd`` - File descriptor returned by :ref:`open() `. - -``argp`` - Pointer to struct :c:type:`media_entity_desc`. - - -Description -=========== - -To query the attributes of an entity, applications set the id field of a -struct :c:type:`media_entity_desc` structure and -call the MEDIA_IOC_ENUM_ENTITIES ioctl with a pointer to this -structure. The driver fills the rest of the structure or returns an -EINVAL error code when the id is invalid. - -.. _media-ent-id-flag-next: - -Entities can be enumerated by or'ing the id with the -``MEDIA_ENT_ID_FLAG_NEXT`` flag. The driver will return information -about the entity with the smallest id strictly larger than the requested -one ('next entity'), or the ``EINVAL`` error code if there is none. - -Entity IDs can be non-contiguous. Applications must *not* try to -enumerate entities by calling MEDIA_IOC_ENUM_ENTITIES with increasing -id's until they get an error. - - -.. c:type:: media_entity_desc - -.. tabularcolumns:: |p{1.5cm}|p{1.7cm}|p{1.6cm}|p{1.5cm}|p{11.2cm}| - -.. flat-table:: struct media_entity_desc - :header-rows: 0 - :stub-columns: 0 - :widths: 2 2 1 8 - - * - __u32 - - ``id`` - - - - Entity ID, set by the application. When the ID is or'ed with - ``MEDIA_ENT_ID_FLAG_NEXT``, the driver clears the flag and returns - the first entity with a larger ID. Do not expect that the ID will - always be the same for each instance of the device. In other words, - do not hardcode entity IDs in an application. - - * - char - - ``name``\ [32] - - - - Entity name as an UTF-8 NULL-terminated string. This name must be unique - within the media topology. - - * - __u32 - - ``type`` - - - - Entity type, see :ref:`media-entity-functions` for details. - - * - __u32 - - ``revision`` - - - - Entity revision. Always zero (obsolete) - - * - __u32 - - ``flags`` - - - - Entity flags, see :ref:`media-entity-flag` for details. - - * - __u32 - - ``group_id`` - - - - Entity group ID. Always zero (obsolete) - - * - __u16 - - ``pads`` - - - - Number of pads - - * - __u16 - - ``links`` - - - - Total number of outbound links. Inbound links are not counted in - this field. - - * - __u32 - - ``reserved[4]`` - - - - Reserved for future extensions. Drivers and applications must set - the array to zero. - - * - union { - - (anonymous) - - * - struct - - ``dev`` - - - - Valid for (sub-)devices that create a single device node. - - * - - - __u32 - - ``major`` - - Device node major number. - - * - - - __u32 - - ``minor`` - - Device node minor number. - - * - __u8 - - ``raw``\ [184] - - - - - * - } - - - - -Return Value -============ - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. - -EINVAL - The struct :c:type:`media_entity_desc` ``id`` - references a non-existing entity. diff --git a/Documentation/media/uapi/mediactl/media-ioc-enum-links.rst b/Documentation/media/uapi/mediactl/media-ioc-enum-links.rst deleted file mode 100644 index b827ebc398f8..000000000000 --- a/Documentation/media/uapi/mediactl/media-ioc-enum-links.rst +++ /dev/null @@ -1,157 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _media_ioc_enum_links: - -************************** -ioctl MEDIA_IOC_ENUM_LINKS -************************** - -Name -==== - -MEDIA_IOC_ENUM_LINKS - Enumerate all pads and links for a given entity - - -Synopsis -======== - -.. c:function:: int ioctl( int fd, MEDIA_IOC_ENUM_LINKS, struct media_links_enum *argp ) - :name: MEDIA_IOC_ENUM_LINKS - - -Arguments -========= - -``fd`` - File descriptor returned by :ref:`open() `. - -``argp`` - Pointer to struct :c:type:`media_links_enum`. - - -Description -=========== - -To enumerate pads and/or links for a given entity, applications set the -entity field of a struct :c:type:`media_links_enum` -structure and initialize the struct -:c:type:`media_pad_desc` and struct -:c:type:`media_link_desc` structure arrays pointed by -the ``pads`` and ``links`` fields. They then call the -MEDIA_IOC_ENUM_LINKS ioctl with a pointer to this structure. - -If the ``pads`` field is not NULL, the driver fills the ``pads`` array -with information about the entity's pads. The array must have enough -room to store all the entity's pads. The number of pads can be retrieved -with :ref:`MEDIA_IOC_ENUM_ENTITIES`. - -If the ``links`` field is not NULL, the driver fills the ``links`` array -with information about the entity's outbound links. The array must have -enough room to store all the entity's outbound links. The number of -outbound links can be retrieved with :ref:`MEDIA_IOC_ENUM_ENTITIES`. - -Only forward links that originate at one of the entity's source pads are -returned during the enumeration process. - - -.. c:type:: media_links_enum - -.. tabularcolumns:: |p{4.4cm}|p{4.4cm}|p{8.7cm}| - -.. flat-table:: struct media_links_enum - :header-rows: 0 - :stub-columns: 0 - :widths: 1 1 2 - - * - __u32 - - ``entity`` - - Entity id, set by the application. - - * - struct :c:type:`media_pad_desc` - - \*\ ``pads`` - - Pointer to a pads array allocated by the application. Ignored if - NULL. - - * - struct :c:type:`media_link_desc` - - \*\ ``links`` - - Pointer to a links array allocated by the application. Ignored if - NULL. - - * - __u32 - - ``reserved[4]`` - - Reserved for future extensions. Drivers and applications must set - the array to zero. - - -.. c:type:: media_pad_desc - -.. tabularcolumns:: |p{4.4cm}|p{4.4cm}|p{8.7cm}| - -.. flat-table:: struct media_pad_desc - :header-rows: 0 - :stub-columns: 0 - :widths: 1 1 2 - - * - __u32 - - ``entity`` - - ID of the entity this pad belongs to. - - * - __u16 - - ``index`` - - Pad index, starts at 0. - - * - __u32 - - ``flags`` - - Pad flags, see :ref:`media-pad-flag` for more details. - - * - __u32 - - ``reserved[2]`` - - Reserved for future extensions. Drivers and applications must set - the array to zero. - - - -.. c:type:: media_link_desc - -.. tabularcolumns:: |p{4.4cm}|p{4.4cm}|p{8.7cm}| - -.. flat-table:: struct media_link_desc - :header-rows: 0 - :stub-columns: 0 - :widths: 1 1 2 - - * - struct :c:type:`media_pad_desc` - - ``source`` - - Pad at the origin of this link. - - * - struct :c:type:`media_pad_desc` - - ``sink`` - - Pad at the target of this link. - - * - __u32 - - ``flags`` - - Link flags, see :ref:`media-link-flag` for more details. - - * - __u32 - - ``reserved[2]`` - - Reserved for future extensions. Drivers and applications must set - the array to zero. - - -Return Value -============ - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. - -EINVAL - The struct :c:type:`media_links_enum` ``id`` - references a non-existing entity. diff --git a/Documentation/media/uapi/mediactl/media-ioc-g-topology.rst b/Documentation/media/uapi/mediactl/media-ioc-g-topology.rst deleted file mode 100644 index 0a7d76ac8ded..000000000000 --- a/Documentation/media/uapi/mediactl/media-ioc-g-topology.rst +++ /dev/null @@ -1,307 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _media_ioc_g_topology: - -************************** -ioctl MEDIA_IOC_G_TOPOLOGY -************************** - -Name -==== - -MEDIA_IOC_G_TOPOLOGY - Enumerate the graph topology and graph element properties - - -Synopsis -======== - -.. c:function:: int ioctl( int fd, MEDIA_IOC_G_TOPOLOGY, struct media_v2_topology *argp ) - :name: MEDIA_IOC_G_TOPOLOGY - - -Arguments -========= - -``fd`` - File descriptor returned by :ref:`open() `. - -``argp`` - Pointer to struct :c:type:`media_v2_topology`. - - -Description -=========== - -The typical usage of this ioctl is to call it twice. On the first call, -the structure defined at struct -:c:type:`media_v2_topology` should be zeroed. At -return, if no errors happen, this ioctl will return the -``topology_version`` and the total number of entities, interfaces, pads -and links. - -Before the second call, the userspace should allocate arrays to store -the graph elements that are desired, putting the pointers to them at the -ptr_entities, ptr_interfaces, ptr_links and/or ptr_pads, keeping the -other values untouched. - -If the ``topology_version`` remains the same, the ioctl should fill the -desired arrays with the media graph elements. - -.. tabularcolumns:: |p{1.6cm}|p{3.4cm}|p{12.5cm}| - -.. c:type:: media_v2_topology - -.. flat-table:: struct media_v2_topology - :header-rows: 0 - :stub-columns: 0 - :widths: 1 2 8 - - * - __u64 - - ``topology_version`` - - Version of the media graph topology. When the graph is created, - this field starts with zero. Every time a graph element is added - or removed, this field is incremented. - - * - __u32 - - ``num_entities`` - - Number of entities in the graph - - * - __u32 - - ``reserved1`` - - Applications and drivers shall set this to 0. - - * - __u64 - - ``ptr_entities`` - - A pointer to a memory area where the entities array will be - stored, converted to a 64-bits integer. It can be zero. if zero, - the ioctl won't store the entities. It will just update - ``num_entities`` - - * - __u32 - - ``num_interfaces`` - - Number of interfaces in the graph - - * - __u32 - - ``reserved2`` - - Applications and drivers shall set this to 0. - - * - __u64 - - ``ptr_interfaces`` - - A pointer to a memory area where the interfaces array will be - stored, converted to a 64-bits integer. It can be zero. if zero, - the ioctl won't store the interfaces. It will just update - ``num_interfaces`` - - * - __u32 - - ``num_pads`` - - Total number of pads in the graph - - * - __u32 - - ``reserved3`` - - Applications and drivers shall set this to 0. - - * - __u64 - - ``ptr_pads`` - - A pointer to a memory area where the pads array will be stored, - converted to a 64-bits integer. It can be zero. if zero, the ioctl - won't store the pads. It will just update ``num_pads`` - - * - __u32 - - ``num_links`` - - Total number of data and interface links in the graph - - * - __u32 - - ``reserved4`` - - Applications and drivers shall set this to 0. - - * - __u64 - - ``ptr_links`` - - A pointer to a memory area where the links array will be stored, - converted to a 64-bits integer. It can be zero. if zero, the ioctl - won't store the links. It will just update ``num_links`` - - -.. tabularcolumns:: |p{1.6cm}|p{3.2cm}|p{12.7cm}| - -.. c:type:: media_v2_entity - -.. flat-table:: struct media_v2_entity - :header-rows: 0 - :stub-columns: 0 - :widths: 1 2 8 - - * - __u32 - - ``id`` - - Unique ID for the entity. Do not expect that the ID will - always be the same for each instance of the device. In other words, - do not hardcode entity IDs in an application. - - * - char - - ``name``\ [64] - - Entity name as an UTF-8 NULL-terminated string. This name must be unique - within the media topology. - - * - __u32 - - ``function`` - - Entity main function, see :ref:`media-entity-functions` for details. - - * - __u32 - - ``flags`` - - Entity flags, see :ref:`media-entity-flag` for details. - Only valid if ``MEDIA_V2_ENTITY_HAS_FLAGS(media_version)`` - returns true. The ``media_version`` is defined in struct - :c:type:`media_device_info` and can be retrieved using - :ref:`MEDIA_IOC_DEVICE_INFO`. - - * - __u32 - - ``reserved``\ [5] - - Reserved for future extensions. Drivers and applications must set - this array to zero. - - -.. tabularcolumns:: |p{1.6cm}|p{3.2cm}|p{12.7cm}| - -.. c:type:: media_v2_interface - -.. flat-table:: struct media_v2_interface - :header-rows: 0 - :stub-columns: 0 - :widths: 1 2 8 - - * - __u32 - - ``id`` - - Unique ID for the interface. Do not expect that the ID will - always be the same for each instance of the device. In other words, - do not hardcode interface IDs in an application. - - * - __u32 - - ``intf_type`` - - Interface type, see :ref:`media-intf-type` for details. - - * - __u32 - - ``flags`` - - Interface flags. Currently unused. - - * - __u32 - - ``reserved``\ [9] - - Reserved for future extensions. Drivers and applications must set - this array to zero. - - * - struct media_v2_intf_devnode - - ``devnode`` - - Used only for device node interfaces. See - :c:type:`media_v2_intf_devnode` for details. - - -.. tabularcolumns:: |p{1.6cm}|p{3.2cm}|p{12.7cm}| - -.. c:type:: media_v2_intf_devnode - -.. flat-table:: struct media_v2_intf_devnode - :header-rows: 0 - :stub-columns: 0 - :widths: 1 2 8 - - * - __u32 - - ``major`` - - Device node major number. - - * - __u32 - - ``minor`` - - Device node minor number. - -.. tabularcolumns:: |p{1.6cm}|p{3.2cm}|p{12.7cm}| - -.. c:type:: media_v2_pad - -.. flat-table:: struct media_v2_pad - :header-rows: 0 - :stub-columns: 0 - :widths: 1 2 8 - - * - __u32 - - ``id`` - - Unique ID for the pad. Do not expect that the ID will - always be the same for each instance of the device. In other words, - do not hardcode pad IDs in an application. - - * - __u32 - - ``entity_id`` - - Unique ID for the entity where this pad belongs. - - * - __u32 - - ``flags`` - - Pad flags, see :ref:`media-pad-flag` for more details. - - * - __u32 - - ``index`` - - Pad index, starts at 0. Only valid if ``MEDIA_V2_PAD_HAS_INDEX(media_version)`` - returns true. The ``media_version`` is defined in struct - :c:type:`media_device_info` and can be retrieved using - :ref:`MEDIA_IOC_DEVICE_INFO`. - - * - __u32 - - ``reserved``\ [4] - - Reserved for future extensions. Drivers and applications must set - this array to zero. - - -.. tabularcolumns:: |p{1.6cm}|p{3.2cm}|p{12.7cm}| - -.. c:type:: media_v2_link - -.. flat-table:: struct media_v2_link - :header-rows: 0 - :stub-columns: 0 - :widths: 1 2 8 - - * - __u32 - - ``id`` - - Unique ID for the link. Do not expect that the ID will - always be the same for each instance of the device. In other words, - do not hardcode link IDs in an application. - - * - __u32 - - ``source_id`` - - On pad to pad links: unique ID for the source pad. - - On interface to entity links: unique ID for the interface. - - * - __u32 - - ``sink_id`` - - On pad to pad links: unique ID for the sink pad. - - On interface to entity links: unique ID for the entity. - - * - __u32 - - ``flags`` - - Link flags, see :ref:`media-link-flag` for more details. - - * - __u32 - - ``reserved``\ [6] - - Reserved for future extensions. Drivers and applications must set - this array to zero. - - -Return Value -============ - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. - -ENOSPC - This is returned when either one or more of the num_entities, - num_interfaces, num_links or num_pads are non-zero and are - smaller than the actual number of elements inside the graph. This - may happen if the ``topology_version`` changed when compared to the - last time this ioctl was called. Userspace should usually free the - area for the pointers, zero the struct elements and call this ioctl - again. diff --git a/Documentation/media/uapi/mediactl/media-ioc-request-alloc.rst b/Documentation/media/uapi/mediactl/media-ioc-request-alloc.rst deleted file mode 100644 index 6d4ca4ada2e0..000000000000 --- a/Documentation/media/uapi/mediactl/media-ioc-request-alloc.rst +++ /dev/null @@ -1,90 +0,0 @@ -.. This file is dual-licensed: you can use it either under the terms -.. of the GPL 2.0 or the GFDL 1.1+ license, at your option. Note that this -.. dual licensing only applies to this file, and not this project as a -.. whole. -.. -.. a) This file is free software; you can redistribute it and/or -.. modify it under the terms of the GNU General Public License as -.. published by the Free Software Foundation version 2 of -.. the License. -.. -.. This file is distributed in the hope that it will be useful, -.. but WITHOUT ANY WARRANTY; without even the implied warranty of -.. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -.. GNU General Public License for more details. -.. -.. Or, alternatively, -.. -.. b) Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GPL-2.0 OR GFDL-1.1-or-later WITH no-invariant-sections - -.. _media_ioc_request_alloc: - -***************************** -ioctl MEDIA_IOC_REQUEST_ALLOC -***************************** - -Name -==== - -MEDIA_IOC_REQUEST_ALLOC - Allocate a request - - -Synopsis -======== - -.. c:function:: int ioctl( int fd, MEDIA_IOC_REQUEST_ALLOC, int *argp ) - :name: MEDIA_IOC_REQUEST_ALLOC - - -Arguments -========= - -``fd`` - File descriptor returned by :ref:`open() `. - -``argp`` - Pointer to an integer. - - -Description -=========== - -If the media device supports :ref:`requests `, then -this ioctl can be used to allocate a request. If it is not supported, then -``errno`` is set to ``ENOTTY``. A request is accessed through a file descriptor -that is returned in ``*argp``. - -If the request was successfully allocated, then the request file descriptor -can be passed to the :ref:`VIDIOC_QBUF `, -:ref:`VIDIOC_G_EXT_CTRLS `, -:ref:`VIDIOC_S_EXT_CTRLS ` and -:ref:`VIDIOC_TRY_EXT_CTRLS ` ioctls. - -In addition, the request can be queued by calling -:ref:`MEDIA_REQUEST_IOC_QUEUE` and re-initialized by calling -:ref:`MEDIA_REQUEST_IOC_REINIT`. - -Finally, the file descriptor can be :ref:`polled ` to wait -for the request to complete. - -The request will remain allocated until all the file descriptors associated -with it are closed by :ref:`close() ` and the driver no -longer uses the request internally. See also -:ref:`here ` for more information. - -Return Value -============ - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. - -ENOTTY - The driver has no support for requests. diff --git a/Documentation/media/uapi/mediactl/media-ioc-setup-link.rst b/Documentation/media/uapi/mediactl/media-ioc-setup-link.rst deleted file mode 100644 index ae39dbbe48a0..000000000000 --- a/Documentation/media/uapi/mediactl/media-ioc-setup-link.rst +++ /dev/null @@ -1,74 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _media_ioc_setup_link: - -************************** -ioctl MEDIA_IOC_SETUP_LINK -************************** - -Name -==== - -MEDIA_IOC_SETUP_LINK - Modify the properties of a link - - -Synopsis -======== - -.. c:function:: int ioctl( int fd, MEDIA_IOC_SETUP_LINK, struct media_link_desc *argp ) - :name: MEDIA_IOC_SETUP_LINK - - -Arguments -========= - -``fd`` - File descriptor returned by :ref:`open() `. - -``argp`` - Pointer to struct :c:type:`media_link_desc`. - - -Description -=========== - -To change link properties applications fill a struct -:c:type:`media_link_desc` with link identification -information (source and sink pad) and the new requested link flags. They -then call the MEDIA_IOC_SETUP_LINK ioctl with a pointer to that -structure. - -The only configurable property is the ``ENABLED`` link flag to -enable/disable a link. Links marked with the ``IMMUTABLE`` link flag can -not be enabled or disabled. - -Link configuration has no side effect on other links. If an enabled link -at the sink pad prevents the link from being enabled, the driver returns -with an ``EBUSY`` error code. - -Only links marked with the ``DYNAMIC`` link flag can be enabled/disabled -while streaming media data. Attempting to enable or disable a streaming -non-dynamic link will return an ``EBUSY`` error code. - -If the specified link can't be found the driver returns with an ``EINVAL`` -error code. - - -Return Value -============ - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. - -EINVAL - The struct :c:type:`media_link_desc` references a - non-existing link, or the link is immutable and an attempt to modify - its configuration was made. diff --git a/Documentation/media/uapi/mediactl/media-request-ioc-queue.rst b/Documentation/media/uapi/mediactl/media-request-ioc-queue.rst deleted file mode 100644 index fc8458746d51..000000000000 --- a/Documentation/media/uapi/mediactl/media-request-ioc-queue.rst +++ /dev/null @@ -1,102 +0,0 @@ -.. This file is dual-licensed: you can use it either under the terms -.. of the GPL 2.0 or the GFDL 1.1+ license, at your option. Note that this -.. dual licensing only applies to this file, and not this project as a -.. whole. -.. -.. a) This file is free software; you can redistribute it and/or -.. modify it under the terms of the GNU General Public License as -.. published by the Free Software Foundation version 2 of -.. the License. -.. -.. This file is distributed in the hope that it will be useful, -.. but WITHOUT ANY WARRANTY; without even the implied warranty of -.. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -.. GNU General Public License for more details. -.. -.. Or, alternatively, -.. -.. b) Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GPL-2.0 OR GFDL-1.1-or-later WITH no-invariant-sections - -.. _media_request_ioc_queue: - -***************************** -ioctl MEDIA_REQUEST_IOC_QUEUE -***************************** - -Name -==== - -MEDIA_REQUEST_IOC_QUEUE - Queue a request - - -Synopsis -======== - -.. c:function:: int ioctl( int request_fd, MEDIA_REQUEST_IOC_QUEUE ) - :name: MEDIA_REQUEST_IOC_QUEUE - - -Arguments -========= - -``request_fd`` - File descriptor returned by :ref:`MEDIA_IOC_REQUEST_ALLOC`. - - -Description -=========== - -If the media device supports :ref:`requests `, then -this request ioctl can be used to queue a previously allocated request. - -If the request was successfully queued, then the file descriptor can be -:ref:`polled ` to wait for the request to complete. - -If the request was already queued before, then ``EBUSY`` is returned. -Other errors can be returned if the contents of the request contained -invalid or inconsistent data, see the next section for a list of -common error codes. On error both the request and driver state are unchanged. - -Once a request is queued, then the driver is required to gracefully handle -errors that occur when the request is applied to the hardware. The -exception is the ``EIO`` error which signals a fatal error that requires -the application to stop streaming to reset the hardware state. - -It is not allowed to mix queuing requests with queuing buffers directly -(without a request). ``EBUSY`` will be returned if the first buffer was -queued directly and you next try to queue a request, or vice versa. - -A request must contain at least one buffer, otherwise this ioctl will -return an ``ENOENT`` error. - -Return Value -============ - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. - -EBUSY - The request was already queued or the application queued the first - buffer directly, but later attempted to use a request. It is not permitted - to mix the two APIs. -ENOENT - The request did not contain any buffers. All requests are required - to have at least one buffer. This can also be returned if some required - configuration is missing in the request. -ENOMEM - Out of memory when allocating internal data structures for this - request. -EINVAL - The request has invalid data. -EIO - The hardware is in a bad state. To recover, the application needs to - stop streaming to reset the hardware state and then try to restart - streaming. diff --git a/Documentation/media/uapi/mediactl/media-request-ioc-reinit.rst b/Documentation/media/uapi/mediactl/media-request-ioc-reinit.rst deleted file mode 100644 index 61381e87665a..000000000000 --- a/Documentation/media/uapi/mediactl/media-request-ioc-reinit.rst +++ /dev/null @@ -1,75 +0,0 @@ -.. This file is dual-licensed: you can use it either under the terms -.. of the GPL 2.0 or the GFDL 1.1+ license, at your option. Note that this -.. dual licensing only applies to this file, and not this project as a -.. whole. -.. -.. a) This file is free software; you can redistribute it and/or -.. modify it under the terms of the GNU General Public License as -.. published by the Free Software Foundation version 2 of -.. the License. -.. -.. This file is distributed in the hope that it will be useful, -.. but WITHOUT ANY WARRANTY; without even the implied warranty of -.. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -.. GNU General Public License for more details. -.. -.. Or, alternatively, -.. -.. b) Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GPL-2.0 OR GFDL-1.1-or-later WITH no-invariant-sections - -.. _media_request_ioc_reinit: - -****************************** -ioctl MEDIA_REQUEST_IOC_REINIT -****************************** - -Name -==== - -MEDIA_REQUEST_IOC_REINIT - Re-initialize a request - - -Synopsis -======== - -.. c:function:: int ioctl( int request_fd, MEDIA_REQUEST_IOC_REINIT ) - :name: MEDIA_REQUEST_IOC_REINIT - - -Arguments -========= - -``request_fd`` - File descriptor returned by :ref:`MEDIA_IOC_REQUEST_ALLOC`. - -Description -=========== - -If the media device supports :ref:`requests `, then -this request ioctl can be used to re-initialize a previously allocated -request. - -Re-initializing a request will clear any existing data from the request. -This avoids having to :ref:`close() ` a completed -request and allocate a new request. Instead the completed request can just -be re-initialized and it is ready to be used again. - -A request can only be re-initialized if it either has not been queued -yet, or if it was queued and completed. Otherwise it will set ``errno`` -to ``EBUSY``. No other error codes can be returned. - -Return Value -============ - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. - -EBUSY - The request is queued but not yet completed. diff --git a/Documentation/media/uapi/mediactl/media-types.rst b/Documentation/media/uapi/mediactl/media-types.rst deleted file mode 100644 index 3af6a414b501..000000000000 --- a/Documentation/media/uapi/mediactl/media-types.rst +++ /dev/null @@ -1,425 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _media-controller-types: - -Types and flags used to represent the media graph elements -========================================================== - -.. tabularcolumns:: |p{8.2cm}|p{10.3cm}| - -.. _media-entity-functions: -.. _MEDIA-ENT-F-UNKNOWN: -.. _MEDIA-ENT-F-V4L2-SUBDEV-UNKNOWN: -.. _MEDIA-ENT-F-IO-V4L: -.. _MEDIA-ENT-F-IO-VBI: -.. _MEDIA-ENT-F-IO-SWRADIO: -.. _MEDIA-ENT-F-IO-DTV: -.. _MEDIA-ENT-F-DTV-DEMOD: -.. _MEDIA-ENT-F-TS-DEMUX: -.. _MEDIA-ENT-F-DTV-CA: -.. _MEDIA-ENT-F-DTV-NET-DECAP: -.. _MEDIA-ENT-F-CONN-RF: -.. _MEDIA-ENT-F-CONN-SVIDEO: -.. _MEDIA-ENT-F-CONN-COMPOSITE: -.. _MEDIA-ENT-F-CAM-SENSOR: -.. _MEDIA-ENT-F-FLASH: -.. _MEDIA-ENT-F-LENS: -.. _MEDIA-ENT-F-ATV-DECODER: -.. _MEDIA-ENT-F-TUNER: -.. _MEDIA-ENT-F-IF-VID-DECODER: -.. _MEDIA-ENT-F-IF-AUD-DECODER: -.. _MEDIA-ENT-F-AUDIO-CAPTURE: -.. _MEDIA-ENT-F-AUDIO-PLAYBACK: -.. _MEDIA-ENT-F-AUDIO-MIXER: -.. _MEDIA-ENT-F-PROC-VIDEO-COMPOSER: -.. _MEDIA-ENT-F-PROC-VIDEO-PIXEL-FORMATTER: -.. _MEDIA-ENT-F-PROC-VIDEO-PIXEL-ENC-CONV: -.. _MEDIA-ENT-F-PROC-VIDEO-LUT: -.. _MEDIA-ENT-F-PROC-VIDEO-SCALER: -.. _MEDIA-ENT-F-PROC-VIDEO-STATISTICS: -.. _MEDIA-ENT-F-PROC-VIDEO-ENCODER: -.. _MEDIA-ENT-F-PROC-VIDEO-DECODER: -.. _MEDIA-ENT-F-VID-MUX: -.. _MEDIA-ENT-F-VID-IF-BRIDGE: -.. _MEDIA-ENT-F-DV-DECODER: -.. _MEDIA-ENT-F-DV-ENCODER: - -.. cssclass:: longtable - -.. flat-table:: Media entity functions - :header-rows: 0 - :stub-columns: 0 - - * - ``MEDIA_ENT_F_UNKNOWN`` and - ``MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN`` - - Unknown entity. That generally indicates that a driver didn't - initialize properly the entity, which is a Kernel bug - - * - ``MEDIA_ENT_F_IO_V4L`` - - Data streaming input and/or output entity. - - * - ``MEDIA_ENT_F_IO_VBI`` - - V4L VBI streaming input or output entity - - * - ``MEDIA_ENT_F_IO_SWRADIO`` - - V4L Software Digital Radio (SDR) streaming input or output entity - - * - ``MEDIA_ENT_F_IO_DTV`` - - DVB Digital TV streaming input or output entity - - * - ``MEDIA_ENT_F_DTV_DEMOD`` - - Digital TV demodulator entity. - - * - ``MEDIA_ENT_F_TS_DEMUX`` - - MPEG Transport stream demux entity. Could be implemented on - hardware or in Kernelspace by the Linux DVB subsystem. - - * - ``MEDIA_ENT_F_DTV_CA`` - - Digital TV Conditional Access module (CAM) entity - - * - ``MEDIA_ENT_F_DTV_NET_DECAP`` - - Digital TV network ULE/MLE desencapsulation entity. Could be - implemented on hardware or in Kernelspace - - * - ``MEDIA_ENT_F_CONN_RF`` - - Connector for a Radio Frequency (RF) signal. - - * - ``MEDIA_ENT_F_CONN_SVIDEO`` - - Connector for a S-Video signal. - - * - ``MEDIA_ENT_F_CONN_COMPOSITE`` - - Connector for a RGB composite signal. - - * - ``MEDIA_ENT_F_CAM_SENSOR`` - - Camera video sensor entity. - - * - ``MEDIA_ENT_F_FLASH`` - - Flash controller entity. - - * - ``MEDIA_ENT_F_LENS`` - - Lens controller entity. - - * - ``MEDIA_ENT_F_ATV_DECODER`` - - Analog video decoder, the basic function of the video decoder is - to accept analogue video from a wide variety of sources such as - broadcast, DVD players, cameras and video cassette recorders, in - either NTSC, PAL, SECAM or HD format, separating the stream into - its component parts, luminance and chrominance, and output it in - some digital video standard, with appropriate timing signals. - - * - ``MEDIA_ENT_F_TUNER`` - - Digital TV, analog TV, radio and/or software radio tuner, with - consists on a PLL tuning stage that converts radio frequency (RF) - signal into an Intermediate Frequency (IF). Modern tuners have - internally IF-PLL decoders for audio and video, but older models - have those stages implemented on separate entities. - - * - ``MEDIA_ENT_F_IF_VID_DECODER`` - - IF-PLL video decoder. It receives the IF from a PLL and decodes - the analog TV video signal. This is commonly found on some very - old analog tuners, like Philips MK3 designs. They all contain a - tda9887 (or some software compatible similar chip, like tda9885). - Those devices use a different I2C address than the tuner PLL. - - * - ``MEDIA_ENT_F_IF_AUD_DECODER`` - - IF-PLL sound decoder. It receives the IF from a PLL and decodes - the analog TV audio signal. This is commonly found on some very - old analog hardware, like Micronas msp3400, Philips tda9840, - tda985x, etc. Those devices use a different I2C address than the - tuner PLL and should be controlled together with the IF-PLL video - decoder. - - * - ``MEDIA_ENT_F_AUDIO_CAPTURE`` - - Audio Capture Function Entity. - - * - ``MEDIA_ENT_F_AUDIO_PLAYBACK`` - - Audio Playback Function Entity. - - * - ``MEDIA_ENT_F_AUDIO_MIXER`` - - Audio Mixer Function Entity. - - * - ``MEDIA_ENT_F_PROC_VIDEO_COMPOSER`` - - Video composer (blender). An entity capable of video - composing must have at least two sink pads and one source - pad, and composes input video frames onto output video - frames. Composition can be performed using alpha blending, - color keying, raster operations (ROP), stitching or any other - means. - - * - ``MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER`` - - Video pixel formatter. An entity capable of pixel formatting - must have at least one sink pad and one source pad. Read - pixel formatters read pixels from memory and perform a subset - of unpacking, cropping, color keying, alpha multiplication - and pixel encoding conversion. Write pixel formatters perform - a subset of dithering, pixel encoding conversion and packing - and write pixels to memory. - - * - ``MEDIA_ENT_F_PROC_VIDEO_PIXEL_ENC_CONV`` - - Video pixel encoding converter. An entity capable of pixel - encoding conversion must have at least one sink pad and one - source pad, and convert the encoding of pixels received on - its sink pad(s) to a different encoding output on its source - pad(s). Pixel encoding conversion includes but isn't limited - to RGB to/from HSV, RGB to/from YUV and CFA (Bayer) to RGB - conversions. - - * - ``MEDIA_ENT_F_PROC_VIDEO_LUT`` - - Video look-up table. An entity capable of video lookup table - processing must have one sink pad and one source pad. It uses - the values of the pixels received on its sink pad to look up - entries in internal tables and output them on its source pad. - The lookup processing can be performed on all components - separately or combine them for multi-dimensional table - lookups. - - * - ``MEDIA_ENT_F_PROC_VIDEO_SCALER`` - - Video scaler. An entity capable of video scaling must have - at least one sink pad and one source pad, and scale the - video frame(s) received on its sink pad(s) to a different - resolution output on its source pad(s). The range of - supported scaling ratios is entity-specific and can differ - between the horizontal and vertical directions (in particular - scaling can be supported in one direction only). Binning and - sub-sampling (occasionally also referred to as skipping) are - considered as scaling. - - * - ``MEDIA_ENT_F_PROC_VIDEO_STATISTICS`` - - Video statistics computation (histogram, 3A, etc.). An entity - capable of statistics computation must have one sink pad and - one source pad. It computes statistics over the frames - received on its sink pad and outputs the statistics data on - its source pad. - - * - ``MEDIA_ENT_F_PROC_VIDEO_ENCODER`` - - Video (MPEG, HEVC, VPx, etc.) encoder. An entity capable of - compressing video frames. Must have one sink pad and at least - one source pad. - - * - ``MEDIA_ENT_F_PROC_VIDEO_DECODER`` - - Video (MPEG, HEVC, VPx, etc.) decoder. An entity capable of - decompressing a compressed video stream into uncompressed video - frames. Must have one sink pad and at least one source pad. - - * - ``MEDIA_ENT_F_VID_MUX`` - - Video multiplexer. An entity capable of multiplexing must have at - least two sink pads and one source pad, and must pass the video - frame(s) received from the active sink pad to the source pad. - - * - ``MEDIA_ENT_F_VID_IF_BRIDGE`` - - Video interface bridge. A video interface bridge entity must have at - least one sink pad and at least one source pad. It receives video - frames on its sink pad from an input video bus of one type (HDMI, eDP, - MIPI CSI-2, etc.), and outputs them on its source pad to an output - video bus of another type (eDP, MIPI CSI-2, parallel, etc.). - - * - ``MEDIA_ENT_F_DV_DECODER`` - - Digital video decoder. The basic function of the video decoder is - to accept digital video from a wide variety of sources - and output it in some digital video standard, with appropriate - timing signals. - - * - ``MEDIA_ENT_F_DV_ENCODER`` - - Digital video encoder. The basic function of the video encoder is - to accept digital video from some digital video standard with - appropriate timing signals (usually a parallel video bus with sync - signals) and output this to a digital video output connector such - as HDMI or DisplayPort. - -.. tabularcolumns:: |p{5.5cm}|p{12.0cm}| - -.. _media-entity-flag: -.. _MEDIA-ENT-FL-DEFAULT: -.. _MEDIA-ENT-FL-CONNECTOR: - -.. flat-table:: Media entity flags - :header-rows: 0 - :stub-columns: 0 - - * - ``MEDIA_ENT_FL_DEFAULT`` - - Default entity for its type. Used to discover the default audio, - VBI and video devices, the default camera sensor, etc. - - * - ``MEDIA_ENT_FL_CONNECTOR`` - - The entity represents a connector. - - -.. tabularcolumns:: |p{6.5cm}|p{6.0cm}|p{5.0cm}| - -.. _media-intf-type: -.. _MEDIA-INTF-T-DVB-FE: -.. _MEDIA-INTF-T-DVB-DEMUX: -.. _MEDIA-INTF-T-DVB-DVR: -.. _MEDIA-INTF-T-DVB-CA: -.. _MEDIA-INTF-T-DVB-NET: -.. _MEDIA-INTF-T-V4L-VIDEO: -.. _MEDIA-INTF-T-V4L-VBI: -.. _MEDIA-INTF-T-V4L-RADIO: -.. _MEDIA-INTF-T-V4L-SUBDEV: -.. _MEDIA-INTF-T-V4L-SWRADIO: -.. _MEDIA-INTF-T-V4L-TOUCH: -.. _MEDIA-INTF-T-ALSA-PCM-CAPTURE: -.. _MEDIA-INTF-T-ALSA-PCM-PLAYBACK: -.. _MEDIA-INTF-T-ALSA-CONTROL: -.. _MEDIA-INTF-T-ALSA-COMPRESS: -.. _MEDIA-INTF-T-ALSA-RAWMIDI: -.. _MEDIA-INTF-T-ALSA-HWDEP: -.. _MEDIA-INTF-T-ALSA-SEQUENCER: -.. _MEDIA-INTF-T-ALSA-TIMER: - -.. flat-table:: Media interface types - :header-rows: 0 - :stub-columns: 0 - - * - ``MEDIA_INTF_T_DVB_FE`` - - Device node interface for the Digital TV frontend - - typically, /dev/dvb/adapter?/frontend? - - * - ``MEDIA_INTF_T_DVB_DEMUX`` - - Device node interface for the Digital TV demux - - typically, /dev/dvb/adapter?/demux? - - * - ``MEDIA_INTF_T_DVB_DVR`` - - Device node interface for the Digital TV DVR - - typically, /dev/dvb/adapter?/dvr? - - * - ``MEDIA_INTF_T_DVB_CA`` - - Device node interface for the Digital TV Conditional Access - - typically, /dev/dvb/adapter?/ca? - - * - ``MEDIA_INTF_T_DVB_NET`` - - Device node interface for the Digital TV network control - - typically, /dev/dvb/adapter?/net? - - * - ``MEDIA_INTF_T_V4L_VIDEO`` - - Device node interface for video (V4L) - - typically, /dev/video? - - * - ``MEDIA_INTF_T_V4L_VBI`` - - Device node interface for VBI (V4L) - - typically, /dev/vbi? - - * - ``MEDIA_INTF_T_V4L_RADIO`` - - Device node interface for radio (V4L) - - typically, /dev/radio? - - * - ``MEDIA_INTF_T_V4L_SUBDEV`` - - Device node interface for a V4L subdevice - - typically, /dev/v4l-subdev? - - * - ``MEDIA_INTF_T_V4L_SWRADIO`` - - Device node interface for Software Defined Radio (V4L) - - typically, /dev/swradio? - - * - ``MEDIA_INTF_T_V4L_TOUCH`` - - Device node interface for Touch device (V4L) - - typically, /dev/v4l-touch? - - * - ``MEDIA_INTF_T_ALSA_PCM_CAPTURE`` - - Device node interface for ALSA PCM Capture - - typically, /dev/snd/pcmC?D?c - - * - ``MEDIA_INTF_T_ALSA_PCM_PLAYBACK`` - - Device node interface for ALSA PCM Playback - - typically, /dev/snd/pcmC?D?p - - * - ``MEDIA_INTF_T_ALSA_CONTROL`` - - Device node interface for ALSA Control - - typically, /dev/snd/controlC? - - * - ``MEDIA_INTF_T_ALSA_COMPRESS`` - - Device node interface for ALSA Compress - - typically, /dev/snd/compr? - - * - ``MEDIA_INTF_T_ALSA_RAWMIDI`` - - Device node interface for ALSA Raw MIDI - - typically, /dev/snd/midi? - - * - ``MEDIA_INTF_T_ALSA_HWDEP`` - - Device node interface for ALSA Hardware Dependent - - typically, /dev/snd/hwC?D? - - * - ``MEDIA_INTF_T_ALSA_SEQUENCER`` - - Device node interface for ALSA Sequencer - - typically, /dev/snd/seq - - * - ``MEDIA_INTF_T_ALSA_TIMER`` - - Device node interface for ALSA Timer - - typically, /dev/snd/timer - - -.. tabularcolumns:: |p{5.5cm}|p{12.0cm}| - -.. _media-pad-flag: -.. _MEDIA-PAD-FL-SINK: -.. _MEDIA-PAD-FL-SOURCE: -.. _MEDIA-PAD-FL-MUST-CONNECT: - -.. flat-table:: Media pad flags - :header-rows: 0 - :stub-columns: 0 - - * - ``MEDIA_PAD_FL_SINK`` - - Input pad, relative to the entity. Input pads sink data and are - targets of links. - - * - ``MEDIA_PAD_FL_SOURCE`` - - Output pad, relative to the entity. Output pads source data and - are origins of links. - - * - ``MEDIA_PAD_FL_MUST_CONNECT`` - - If this flag is set and the pad is linked to any other pad, then - at least one of those links must be enabled for the entity to be - able to stream. There could be temporary reasons (e.g. device - configuration dependent) for the pad to need enabled links even - when this flag isn't set; the absence of the flag doesn't imply - there is none. - - -One and only one of ``MEDIA_PAD_FL_SINK`` and ``MEDIA_PAD_FL_SOURCE`` -must be set for every pad. - -.. tabularcolumns:: |p{5.5cm}|p{12.0cm}| - -.. _media-link-flag: -.. _MEDIA-LNK-FL-ENABLED: -.. _MEDIA-LNK-FL-IMMUTABLE: -.. _MEDIA-LNK-FL-DYNAMIC: -.. _MEDIA-LNK-FL-LINK-TYPE: - -.. flat-table:: Media link flags - :header-rows: 0 - :stub-columns: 0 - - * - ``MEDIA_LNK_FL_ENABLED`` - - The link is enabled and can be used to transfer media data. When - two or more links target a sink pad, only one of them can be - enabled at a time. - - * - ``MEDIA_LNK_FL_IMMUTABLE`` - - The link enabled state can't be modified at runtime. An immutable - link is always enabled. - - * - ``MEDIA_LNK_FL_DYNAMIC`` - - The link enabled state can be modified during streaming. This flag - is set by drivers and is read-only for applications. - - * - ``MEDIA_LNK_FL_LINK_TYPE`` - - This is a bitmask that defines the type of the link. Currently, - two types of links are supported: - - .. _MEDIA-LNK-FL-DATA-LINK: - - ``MEDIA_LNK_FL_DATA_LINK`` if the link is between two pads - - .. _MEDIA-LNK-FL-INTERFACE-LINK: - - ``MEDIA_LNK_FL_INTERFACE_LINK`` if the link is between an - interface and an entity diff --git a/Documentation/media/uapi/mediactl/request-api.rst b/Documentation/media/uapi/mediactl/request-api.rst deleted file mode 100644 index 01abe8103bdd..000000000000 --- a/Documentation/media/uapi/mediactl/request-api.rst +++ /dev/null @@ -1,276 +0,0 @@ -.. This file is dual-licensed: you can use it either under the terms -.. of the GPL 2.0 or the GFDL 1.1+ license, at your option. Note that this -.. dual licensing only applies to this file, and not this project as a -.. whole. -.. -.. a) This file is free software; you can redistribute it and/or -.. modify it under the terms of the GNU General Public License as -.. published by the Free Software Foundation version 2 of -.. the License. -.. -.. This file is distributed in the hope that it will be useful, -.. but WITHOUT ANY WARRANTY; without even the implied warranty of -.. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -.. GNU General Public License for more details. -.. -.. Or, alternatively, -.. -.. b) Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GPL-2.0 OR GFDL-1.1-or-later WITH no-invariant-sections - -.. _media-request-api: - -Request API -=========== - -The Request API has been designed to allow V4L2 to deal with requirements of -modern devices (stateless codecs, complex camera pipelines, ...) and APIs -(Android Codec v2). One such requirement is the ability for devices belonging to -the same pipeline to reconfigure and collaborate closely on a per-frame basis. -Another is support of stateless codecs, which require controls to be applied -to specific frames (aka 'per-frame controls') in order to be used efficiently. - -While the initial use-case was V4L2, it can be extended to other subsystems -as well, as long as they use the media controller. - -Supporting these features without the Request API is not always possible and if -it is, it is terribly inefficient: user-space would have to flush all activity -on the media pipeline, reconfigure it for the next frame, queue the buffers to -be processed with that configuration, and wait until they are all available for -dequeuing before considering the next frame. This defeats the purpose of having -buffer queues since in practice only one buffer would be queued at a time. - -The Request API allows a specific configuration of the pipeline (media -controller topology + configuration for each media entity) to be associated with -specific buffers. This allows user-space to schedule several tasks ("requests") -with different configurations in advance, knowing that the configuration will be -applied when needed to get the expected result. Configuration values at the time -of request completion are also available for reading. - -General Usage -------------- - -The Request API extends the Media Controller API and cooperates with -subsystem-specific APIs to support request usage. At the Media Controller -level, requests are allocated from the supporting Media Controller device -node. Their life cycle is then managed through the request file descriptors in -an opaque way. Configuration data, buffer handles and processing results -stored in requests are accessed through subsystem-specific APIs extended for -request support, such as V4L2 APIs that take an explicit ``request_fd`` -parameter. - -Request Allocation ------------------- - -User-space allocates requests using :ref:`MEDIA_IOC_REQUEST_ALLOC` -for the media device node. This returns a file descriptor representing the -request. Typically, several such requests will be allocated. - -Request Preparation -------------------- - -Standard V4L2 ioctls can then receive a request file descriptor to express the -fact that the ioctl is part of said request, and is not to be applied -immediately. See :ref:`MEDIA_IOC_REQUEST_ALLOC` for a list of ioctls that -support this. Configurations set with a ``request_fd`` parameter are stored -instead of being immediately applied, and buffers queued to a request do not -enter the regular buffer queue until the request itself is queued. - -Request Submission ------------------- - -Once the configuration and buffers of the request are specified, it can be -queued by calling :ref:`MEDIA_REQUEST_IOC_QUEUE` on the request file descriptor. -A request must contain at least one buffer, otherwise ``ENOENT`` is returned. -A queued request cannot be modified anymore. - -.. caution:: - For :ref:`memory-to-memory devices ` you can use requests only for - output buffers, not for capture buffers. Attempting to add a capture buffer - to a request will result in an ``EBADR`` error. - -If the request contains configurations for multiple entities, individual drivers -may synchronize so the requested pipeline's topology is applied before the -buffers are processed. Media controller drivers do a best effort implementation -since perfect atomicity may not be possible due to hardware limitations. - -.. caution:: - - It is not allowed to mix queuing requests with directly queuing buffers: - whichever method is used first locks this in place until - :ref:`VIDIOC_STREAMOFF ` is called or the device is - :ref:`closed `. Attempts to directly queue a buffer when earlier - a buffer was queued via a request or vice versa will result in an ``EBUSY`` - error. - -Controls can still be set without a request and are applied immediately, -regardless of whether a request is in use or not. - -.. caution:: - - Setting the same control through a request and also directly can lead to - undefined behavior! - -User-space can :ref:`poll() ` a request file descriptor in -order to wait until the request completes. A request is considered complete -once all its associated buffers are available for dequeuing and all the -associated controls have been updated with the values at the time of completion. -Note that user-space does not need to wait for the request to complete to -dequeue its buffers: buffers that are available halfway through a request can -be dequeued independently of the request's state. - -A completed request contains the state of the device after the request was -executed. User-space can query that state by calling -:ref:`ioctl VIDIOC_G_EXT_CTRLS ` with the request file -descriptor. Calling :ref:`ioctl VIDIOC_G_EXT_CTRLS ` for a -request that has been queued but not yet completed will return ``EBUSY`` -since the control values might be changed at any time by the driver while the -request is in flight. - -.. _media-request-life-time: - -Recycling and Destruction -------------------------- - -Finally, a completed request can either be discarded or be reused. Calling -:ref:`close() ` on a request file descriptor will make -that file descriptor unusable and the request will be freed once it is no -longer in use by the kernel. That is, if the request is queued and then the -file descriptor is closed, then it won't be freed until the driver completed -the request. - -The :ref:`MEDIA_REQUEST_IOC_REINIT` will clear a request's state and make it -available again. No state is retained by this operation: the request is as -if it had just been allocated. - -Example for a Codec Device --------------------------- - -For use-cases such as :ref:`codecs `, the request API can be used -to associate specific controls to -be applied by the driver for the OUTPUT buffer, allowing user-space -to queue many such buffers in advance. It can also take advantage of requests' -ability to capture the state of controls when the request completes to read back -information that may be subject to change. - -Put into code, after obtaining a request, user-space can assign controls and one -OUTPUT buffer to it: - -.. code-block:: c - - struct v4l2_buffer buf; - struct v4l2_ext_controls ctrls; - int req_fd; - ... - if (ioctl(media_fd, MEDIA_IOC_REQUEST_ALLOC, &req_fd)) - return errno; - ... - ctrls.which = V4L2_CTRL_WHICH_REQUEST_VAL; - ctrls.request_fd = req_fd; - if (ioctl(codec_fd, VIDIOC_S_EXT_CTRLS, &ctrls)) - return errno; - ... - buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; - buf.flags |= V4L2_BUF_FLAG_REQUEST_FD; - buf.request_fd = req_fd; - if (ioctl(codec_fd, VIDIOC_QBUF, &buf)) - return errno; - -Note that it is not allowed to use the Request API for CAPTURE buffers -since there are no per-frame settings to report there. - -Once the request is fully prepared, it can be queued to the driver: - -.. code-block:: c - - if (ioctl(req_fd, MEDIA_REQUEST_IOC_QUEUE)) - return errno; - -User-space can then either wait for the request to complete by calling poll() on -its file descriptor, or start dequeuing CAPTURE buffers. Most likely, it will -want to get CAPTURE buffers as soon as possible and this can be done using a -regular :ref:`VIDIOC_DQBUF `: - -.. code-block:: c - - struct v4l2_buffer buf; - - memset(&buf, 0, sizeof(buf)); - buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - if (ioctl(codec_fd, VIDIOC_DQBUF, &buf)) - return errno; - -Note that this example assumes for simplicity that for every OUTPUT buffer -there will be one CAPTURE buffer, but this does not have to be the case. - -We can then, after ensuring that the request is completed via polling the -request file descriptor, query control values at the time of its completion via -a call to :ref:`VIDIOC_G_EXT_CTRLS `. -This is particularly useful for volatile controls for which we want to -query values as soon as the capture buffer is produced. - -.. code-block:: c - - struct pollfd pfd = { .events = POLLPRI, .fd = req_fd }; - poll(&pfd, 1, -1); - ... - ctrls.which = V4L2_CTRL_WHICH_REQUEST_VAL; - ctrls.request_fd = req_fd; - if (ioctl(codec_fd, VIDIOC_G_EXT_CTRLS, &ctrls)) - return errno; - -Once we don't need the request anymore, we can either recycle it for reuse with -:ref:`MEDIA_REQUEST_IOC_REINIT`... - -.. code-block:: c - - if (ioctl(req_fd, MEDIA_REQUEST_IOC_REINIT)) - return errno; - -... or close its file descriptor to completely dispose of it. - -.. code-block:: c - - close(req_fd); - -Example for a Simple Capture Device ------------------------------------ - -With a simple capture device, requests can be used to specify controls to apply -for a given CAPTURE buffer. - -.. code-block:: c - - struct v4l2_buffer buf; - struct v4l2_ext_controls ctrls; - int req_fd; - ... - if (ioctl(media_fd, MEDIA_IOC_REQUEST_ALLOC, &req_fd)) - return errno; - ... - ctrls.which = V4L2_CTRL_WHICH_REQUEST_VAL; - ctrls.request_fd = req_fd; - if (ioctl(camera_fd, VIDIOC_S_EXT_CTRLS, &ctrls)) - return errno; - ... - buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - buf.flags |= V4L2_BUF_FLAG_REQUEST_FD; - buf.request_fd = req_fd; - if (ioctl(camera_fd, VIDIOC_QBUF, &buf)) - return errno; - -Once the request is fully prepared, it can be queued to the driver: - -.. code-block:: c - - if (ioctl(req_fd, MEDIA_REQUEST_IOC_QUEUE)) - return errno; - -User-space can then dequeue buffers, wait for the request completion, query -controls and recycle the request as in the M2M example above. diff --git a/Documentation/media/uapi/mediactl/request-func-close.rst b/Documentation/media/uapi/mediactl/request-func-close.rst deleted file mode 100644 index 2cff7770558e..000000000000 --- a/Documentation/media/uapi/mediactl/request-func-close.rst +++ /dev/null @@ -1,73 +0,0 @@ -.. This file is dual-licensed: you can use it either under the terms -.. of the GPL 2.0 or the GFDL 1.1+ license, at your option. Note that this -.. dual licensing only applies to this file, and not this project as a -.. whole. -.. -.. a) This file is free software; you can redistribute it and/or -.. modify it under the terms of the GNU General Public License as -.. published by the Free Software Foundation version 2 of -.. the License. -.. -.. This file is distributed in the hope that it will be useful, -.. but WITHOUT ANY WARRANTY; without even the implied warranty of -.. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -.. GNU General Public License for more details. -.. -.. Or, alternatively, -.. -.. b) Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GPL-2.0 OR GFDL-1.1-or-later WITH no-invariant-sections - -.. _request-func-close: - -*************** -request close() -*************** - -Name -==== - -request-close - Close a request file descriptor - - -Synopsis -======== - -.. code-block:: c - - #include - - -.. c:function:: int close( int fd ) - :name: req-close - -Arguments -========= - -``fd`` - File descriptor returned by :ref:`MEDIA_IOC_REQUEST_ALLOC`. - - -Description -=========== - -Closes the request file descriptor. Resources associated with the request -are freed once all file descriptors associated with the request are closed -and the driver has completed the request. -See :ref:`here ` for more information. - - -Return Value -============ - -:ref:`close() ` returns 0 on success. On error, -1 is -returned, and ``errno`` is set appropriately. Possible error codes are: - -EBADF - ``fd`` is not a valid open file descriptor. diff --git a/Documentation/media/uapi/mediactl/request-func-ioctl.rst b/Documentation/media/uapi/mediactl/request-func-ioctl.rst deleted file mode 100644 index de0781c61873..000000000000 --- a/Documentation/media/uapi/mediactl/request-func-ioctl.rst +++ /dev/null @@ -1,91 +0,0 @@ -.. This file is dual-licensed: you can use it either under the terms -.. of the GPL 2.0 or the GFDL 1.1+ license, at your option. Note that this -.. dual licensing only applies to this file, and not this project as a -.. whole. -.. -.. a) This file is free software; you can redistribute it and/or -.. modify it under the terms of the GNU General Public License as -.. published by the Free Software Foundation version 2 of -.. the License. -.. -.. This file is distributed in the hope that it will be useful, -.. but WITHOUT ANY WARRANTY; without even the implied warranty of -.. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -.. GNU General Public License for more details. -.. -.. Or, alternatively, -.. -.. b) Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GPL-2.0 OR GFDL-1.1-or-later WITH no-invariant-sections - -.. _request-func-ioctl: - -*************** -request ioctl() -*************** - -Name -==== - -request-ioctl - Control a request file descriptor - - -Synopsis -======== - -.. code-block:: c - - #include - - -.. c:function:: int ioctl( int fd, int cmd, void *argp ) - :name: req-ioctl - -Arguments -========= - -``fd`` - File descriptor returned by :ref:`MEDIA_IOC_REQUEST_ALLOC`. - -``cmd`` - The request ioctl command code as defined in the media.h header file, for - example :ref:`MEDIA_REQUEST_IOC_QUEUE`. - -``argp`` - Pointer to a request-specific structure. - - -Description -=========== - -The :ref:`ioctl() ` function manipulates request -parameters. The argument ``fd`` must be an open file descriptor. - -The ioctl ``cmd`` code specifies the request function to be called. It -has encoded in it whether the argument is an input, output or read/write -parameter, and the size of the argument ``argp`` in bytes. - -Macros and structures definitions specifying request ioctl commands and -their parameters are located in the media.h header file. All request ioctl -commands, their respective function and parameters are specified in -:ref:`media-user-func`. - - -Return Value -============ - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. - -Command-specific error codes are listed in the individual command -descriptions. - -When an ioctl that takes an output or read/write parameter fails, the -parameter remains unmodified. diff --git a/Documentation/media/uapi/mediactl/request-func-poll.rst b/Documentation/media/uapi/mediactl/request-func-poll.rst deleted file mode 100644 index ebaf33e21873..000000000000 --- a/Documentation/media/uapi/mediactl/request-func-poll.rst +++ /dev/null @@ -1,101 +0,0 @@ -.. This file is dual-licensed: you can use it either under the terms -.. of the GPL 2.0 or the GFDL 1.1+ license, at your option. Note that this -.. dual licensing only applies to this file, and not this project as a -.. whole. -.. -.. a) This file is free software; you can redistribute it and/or -.. modify it under the terms of the GNU General Public License as -.. published by the Free Software Foundation version 2 of -.. the License. -.. -.. This file is distributed in the hope that it will be useful, -.. but WITHOUT ANY WARRANTY; without even the implied warranty of -.. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -.. GNU General Public License for more details. -.. -.. Or, alternatively, -.. -.. b) Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GPL-2.0 OR GFDL-1.1-or-later WITH no-invariant-sections - -.. _request-func-poll: - -************** -request poll() -************** - -Name -==== - -request-poll - Wait for some event on a file descriptor - - -Synopsis -======== - -.. code-block:: c - - #include - - -.. c:function:: int poll( struct pollfd *ufds, unsigned int nfds, int timeout ) - :name: request-poll - -Arguments -========= - -``ufds`` - List of file descriptor events to be watched - -``nfds`` - Number of file descriptor events at the \*ufds array - -``timeout`` - Timeout to wait for events - - -Description -=========== - -With the :c:func:`poll() ` function applications can wait -for a request to complete. - -On success :c:func:`poll() ` returns the number of file -descriptors that have been selected (that is, file descriptors for which the -``revents`` field of the respective struct :c:type:`pollfd` -is non-zero). Request file descriptor set the ``POLLPRI`` flag in ``revents`` -when the request was completed. When the function times out it returns -a value of zero, on failure it returns -1 and the ``errno`` variable is -set appropriately. - -Attempting to poll for a request that is not yet queued will -set the ``POLLERR`` flag in ``revents``. - - -Return Value -============ - -On success, :c:func:`poll() ` returns the number of -structures which have non-zero ``revents`` fields, or zero if the call -timed out. On error -1 is returned, and the ``errno`` variable is set -appropriately: - -``EBADF`` - One or more of the ``ufds`` members specify an invalid file - descriptor. - -``EFAULT`` - ``ufds`` references an inaccessible memory area. - -``EINTR`` - The call was interrupted by a signal. - -``EINVAL`` - The ``nfds`` value exceeds the ``RLIMIT_NOFILE`` value. Use - ``getrlimit()`` to obtain this value. diff --git a/Documentation/media/uapi/rc/keytable.c.rst b/Documentation/media/uapi/rc/keytable.c.rst deleted file mode 100644 index 46f98569e999..000000000000 --- a/Documentation/media/uapi/rc/keytable.c.rst +++ /dev/null @@ -1,183 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -file: uapi/v4l/keytable.c -========================= - -.. code-block:: c - - /* keytable.c - This program allows checking/replacing keys at IR - - Copyright (C) 2006-2009 Mauro Carvalho Chehab - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, version 2 of the License. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - */ - - #include - #include - #include - #include - #include - #include - #include - #include - - #include "parse.h" - - void prtcode (int *codes) - { - struct parse_key *p; - - for (p=keynames;p->name!=NULL;p++) { - if (p->value == (unsigned)codes[1]) { - printf("scancode 0x%04x = %s (0x%02x)\\n", codes[0], p->name, codes[1]); - return; - } - } - - if (isprint (codes[1])) - printf("scancode %d = '%c' (0x%02x)\\n", codes[0], codes[1], codes[1]); - else - printf("scancode %d = 0x%02x\\n", codes[0], codes[1]); - } - - int parse_code(char *string) - { - struct parse_key *p; - - for (p=keynames;p->name!=NULL;p++) { - if (!strcasecmp(p->name, string)) { - return p->value; - } - } - return -1; - } - - int main (int argc, char *argv[]) - { - int fd; - unsigned int i, j; - int codes[2]; - - if (argc<2 || argc>4) { - printf ("usage: %s to get table; or\\n" - " %s \\n" - " %s n",*argv,*argv,*argv); - return -1; - } - - if ((fd = open(argv[1], O_RDONLY)) < 0) { - perror("Couldn't open input device"); - return(-1); - } - - if (argc==4) { - int value; - - value=parse_code(argv[3]); - - if (value==-1) { - value = strtol(argv[3], NULL, 0); - if (errno) - perror("value"); - } - - codes [0] = (unsigned) strtol(argv[2], NULL, 0); - codes [1] = (unsigned) value; - - if(ioctl(fd, EVIOCSKEYCODE, codes)) - perror ("EVIOCSKEYCODE"); - - if(ioctl(fd, EVIOCGKEYCODE, codes)==0) - prtcode(codes); - return 0; - } - - if (argc==3) { - FILE *fin; - int value; - char *scancode, *keycode, s[2048]; - - fin=fopen(argv[2],"r"); - if (fin==NULL) { - perror ("opening keycode file"); - return -1; - } - - /* Clears old table */ - for (j = 0; j < 256; j++) { - for (i = 0; i < 256; i++) { - codes[0] = (j << 8) | i; - codes[1] = KEY_RESERVED; - ioctl(fd, EVIOCSKEYCODE, codes); - } - } - - while (fgets(s,sizeof(s),fin)) { - scancode=strtok(s,"\\n\\t =:"); - if (!scancode) { - perror ("parsing input file scancode"); - return -1; - } - if (!strcasecmp(scancode, "scancode")) { - scancode = strtok(NULL,"\\n\\t =:"); - if (!scancode) { - perror ("parsing input file scancode"); - return -1; - } - } - - keycode=strtok(NULL,"\\n\\t =:("); - if (!keycode) { - perror ("parsing input file keycode"); - return -1; - } - - // printf ("parsing %s=%s:", scancode, keycode); - value=parse_code(keycode); - // printf ("\\tvalue=%d\\n",value); - - if (value==-1) { - value = strtol(keycode, NULL, 0); - if (errno) - perror("value"); - } - - codes [0] = (unsigned) strtol(scancode, NULL, 0); - codes [1] = (unsigned) value; - - // printf("\\t%04x=%04x\\n",codes[0], codes[1]); - if(ioctl(fd, EVIOCSKEYCODE, codes)) { - fprintf(stderr, "Setting scancode 0x%04x with 0x%04x via ",codes[0], codes[1]); - perror ("EVIOCSKEYCODE"); - } - - if(ioctl(fd, EVIOCGKEYCODE, codes)==0) - prtcode(codes); - } - return 0; - } - - /* Get scancode table */ - for (j = 0; j < 256; j++) { - for (i = 0; i < 256; i++) { - codes[0] = (j << 8) | i; - if (!ioctl(fd, EVIOCGKEYCODE, codes) && codes[1] != KEY_RESERVED) - prtcode(codes); - } - } - return 0; - } diff --git a/Documentation/media/uapi/rc/lirc-dev-intro.rst b/Documentation/media/uapi/rc/lirc-dev-intro.rst deleted file mode 100644 index b68c01693939..000000000000 --- a/Documentation/media/uapi/rc/lirc-dev-intro.rst +++ /dev/null @@ -1,171 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _lirc_dev_intro: - -************ -Introduction -************ - -LIRC stands for Linux Infrared Remote Control. The LIRC device interface is -a bi-directional interface for transporting raw IR and decoded scancodes -data between userspace and kernelspace. Fundamentally, it is just a chardev -(/dev/lircX, for X = 0, 1, 2, ...), with a number of standard struct -file_operations defined on it. With respect to transporting raw IR and -decoded scancodes to and fro, the essential fops are read, write and ioctl. - -It is also possible to attach a BPF program to a LIRC device for decoding -raw IR into scancodes. - -Example dmesg output upon a driver registering w/LIRC: - -.. code-block:: none - - $ dmesg |grep lirc_dev - rc rc0: lirc_dev: driver mceusb registered at minor = 0, raw IR receiver, raw IR transmitter - -What you should see for a chardev: - -.. code-block:: none - - $ ls -l /dev/lirc* - crw-rw---- 1 root root 248, 0 Jul 2 22:20 /dev/lirc0 - -Note that the package `v4l-utils `_ -contains tools for working with LIRC devices: - - - ir-ctl: can receive raw IR and transmit IR, as well as query LIRC - device features. - - - ir-keytable: can load keymaps; allows you to set IR kernel protocols; load - BPF IR decoders and test IR decoding. Some BPF IR decoders are also - provided. - -.. _lirc_modes: - -********** -LIRC modes -********** - -LIRC supports some modes of receiving and sending IR codes, as shown -on the following table. - -.. _lirc-mode-scancode: -.. _lirc-scancode-flag-toggle: -.. _lirc-scancode-flag-repeat: - -``LIRC_MODE_SCANCODE`` - - This mode is for both sending and receiving IR. - - For transmitting (aka sending), create a ``struct lirc_scancode`` with - the desired scancode set in the ``scancode`` member, :c:type:`rc_proto` - set to the :ref:`IR protocol `, and all other - members set to 0. Write this struct to the lirc device. - - For receiving, you read ``struct lirc_scancode`` from the LIRC device. - The ``scancode`` field is set to the received scancode and the - :ref:`IR protocol ` is set in - :c:type:`rc_proto`. If the scancode maps to a valid key code, this is set - in the ``keycode`` field, else it is set to ``KEY_RESERVED``. - - The ``flags`` can have ``LIRC_SCANCODE_FLAG_TOGGLE`` set if the toggle - bit is set in protocols that support it (e.g. rc-5 and rc-6), or - ``LIRC_SCANCODE_FLAG_REPEAT`` for when a repeat is received for protocols - that support it (e.g. nec). - - In the Sanyo and NEC protocol, if you hold a button on remote, rather than - repeating the entire scancode, the remote sends a shorter message with - no scancode, which just means button is held, a "repeat". When this is - received, the ``LIRC_SCANCODE_FLAG_REPEAT`` is set and the scancode and - keycode is repeated. - - With nec, there is no way to distinguish "button hold" from "repeatedly - pressing the same button". The rc-5 and rc-6 protocols have a toggle bit. - When a button is released and pressed again, the toggle bit is inverted. - If the toggle bit is set, the ``LIRC_SCANCODE_FLAG_TOGGLE`` is set. - - The ``timestamp`` field is filled with the time nanoseconds - (in ``CLOCK_MONOTONIC``) when the scancode was decoded. - -.. _lirc-mode-mode2: - -``LIRC_MODE_MODE2`` - - The driver returns a sequence of pulse and space codes to userspace, - as a series of u32 values. - - This mode is used only for IR receive. - - The upper 8 bits determine the packet type, and the lower 24 bits - the payload. Use ``LIRC_VALUE()`` macro to get the payload, and - the macro ``LIRC_MODE2()`` will give you the type, which - is one of: - - ``LIRC_MODE2_PULSE`` - - Signifies the presence of IR in microseconds. - - ``LIRC_MODE2_SPACE`` - - Signifies absence of IR in microseconds. - - ``LIRC_MODE2_FREQUENCY`` - - If measurement of the carrier frequency was enabled with - :ref:`lirc_set_measure_carrier_mode` then this packet gives you - the carrier frequency in Hertz. - - ``LIRC_MODE2_TIMEOUT`` - - If timeout reports are enabled with - :ref:`lirc_set_rec_timeout_reports`, when the timeout set with - :ref:`lirc_set_rec_timeout` expires due to no IR being detected, - this packet will be sent, with the number of microseconds with - no IR. - -.. _lirc-mode-pulse: - -``LIRC_MODE_PULSE`` - - In pulse mode, a sequence of pulse/space integer values are written to the - lirc device using :ref:`lirc-write`. - - The values are alternating pulse and space lengths, in microseconds. The - first and last entry must be a pulse, so there must be an odd number - of entries. - - This mode is used only for IR send. - -******************** -BPF based IR decoder -******************** - -The kernel has support for decoding the most common -:ref:`IR protocols `, but there -are many protocols which are not supported. To support these, it is possible -to load an BPF program which does the decoding. This can only be done on -LIRC devices which support reading raw IR. - -First, using the `bpf(2)`_ syscall with the ``BPF_LOAD_PROG`` argument, -program must be loaded of type ``BPF_PROG_TYPE_LIRC_MODE2``. Once attached -to the LIRC device, this program will be called for each pulse, space or -timeout event on the LIRC device. The context for the BPF program is a -pointer to a unsigned int, which is a :ref:`LIRC_MODE_MODE2 ` -value. When the program has decoded the scancode, it can be submitted using -the BPF functions ``bpf_rc_keydown()`` or ``bpf_rc_repeat()``. Mouse or pointer -movements can be reported using ``bpf_rc_pointer_rel()``. - -Once you have the file descriptor for the ``BPF_PROG_TYPE_LIRC_MODE2`` BPF -program, it can be attached to the LIRC device using the `bpf(2)`_ syscall. -The target must be the file descriptor for the LIRC device, and the -attach type must be ``BPF_LIRC_MODE2``. No more than 64 BPF programs can be -attached to a single LIRC device at a time. - -.. _bpf(2): http://man7.org/linux/man-pages/man2/bpf.2.html diff --git a/Documentation/media/uapi/rc/lirc-dev.rst b/Documentation/media/uapi/rc/lirc-dev.rst deleted file mode 100644 index 7058e0b2296a..000000000000 --- a/Documentation/media/uapi/rc/lirc-dev.rst +++ /dev/null @@ -1,21 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _lirc_dev: - -LIRC Device Interface -===================== - - -.. toctree:: - :maxdepth: 1 - - lirc-dev-intro - lirc-func - lirc-header diff --git a/Documentation/media/uapi/rc/lirc-func.rst b/Documentation/media/uapi/rc/lirc-func.rst deleted file mode 100644 index 25058369f724..000000000000 --- a/Documentation/media/uapi/rc/lirc-func.rst +++ /dev/null @@ -1,34 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _lirc_func: - -LIRC Function Reference -======================= - - -.. toctree:: - :maxdepth: 1 - - lirc-read - lirc-write - lirc-get-features - lirc-get-send-mode - lirc-get-rec-mode - lirc-get-rec-resolution - lirc-set-send-duty-cycle - lirc-get-timeout - lirc-set-rec-timeout - lirc-set-rec-carrier - lirc-set-rec-carrier-range - lirc-set-send-carrier - lirc-set-transmitter-mask - lirc-set-rec-timeout-reports - lirc-set-measure-carrier-mode - lirc-set-wideband-receiver diff --git a/Documentation/media/uapi/rc/lirc-get-features.rst b/Documentation/media/uapi/rc/lirc-get-features.rst deleted file mode 100644 index 1d590df8164a..000000000000 --- a/Documentation/media/uapi/rc/lirc-get-features.rst +++ /dev/null @@ -1,200 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _lirc_get_features: - -*********************** -ioctl LIRC_GET_FEATURES -*********************** - -Name -==== - -LIRC_GET_FEATURES - Get the underlying hardware device's features - -Synopsis -======== - -.. c:function:: int ioctl( int fd, LIRC_GET_FEATURES, __u32 *features) - :name: LIRC_GET_FEATURES - -Arguments -========= - -``fd`` - File descriptor returned by open(). - -``features`` - Bitmask with the LIRC features. - - -Description -=========== - - -Get the underlying hardware device's features. If a driver does not -announce support of certain features, calling of the corresponding ioctls -is undefined. - -LIRC features -============= - -.. _LIRC-CAN-REC-RAW: - -``LIRC_CAN_REC_RAW`` - - Unused. Kept just to avoid breaking uAPI. - -.. _LIRC-CAN-REC-PULSE: - -``LIRC_CAN_REC_PULSE`` - - Unused. Kept just to avoid breaking uAPI. - :ref:`LIRC_MODE_PULSE ` can only be used for transmitting. - -.. _LIRC-CAN-REC-MODE2: - -``LIRC_CAN_REC_MODE2`` - - This is raw IR driver for receiving. This means that - :ref:`LIRC_MODE_MODE2 ` is used. This also implies - that :ref:`LIRC_MODE_SCANCODE ` is also supported, - as long as the kernel is recent enough. Use the - :ref:`lirc_set_rec_mode` to switch modes. - -.. _LIRC-CAN-REC-LIRCCODE: - -``LIRC_CAN_REC_LIRCCODE`` - - Unused. Kept just to avoid breaking uAPI. - -.. _LIRC-CAN-REC-SCANCODE: - -``LIRC_CAN_REC_SCANCODE`` - - This is a scancode driver for receiving. This means that - :ref:`LIRC_MODE_SCANCODE ` is used. - -.. _LIRC-CAN-SET-SEND-CARRIER: - -``LIRC_CAN_SET_SEND_CARRIER`` - - The driver supports changing the modulation frequency via - :ref:`ioctl LIRC_SET_SEND_CARRIER `. - -.. _LIRC-CAN-SET-SEND-DUTY-CYCLE: - -``LIRC_CAN_SET_SEND_DUTY_CYCLE`` - - The driver supports changing the duty cycle using - :ref:`ioctl LIRC_SET_SEND_DUTY_CYCLE `. - -.. _LIRC-CAN-SET-TRANSMITTER-MASK: - -``LIRC_CAN_SET_TRANSMITTER_MASK`` - - The driver supports changing the active transmitter(s) using - :ref:`ioctl LIRC_SET_TRANSMITTER_MASK `. - -.. _LIRC-CAN-SET-REC-CARRIER: - -``LIRC_CAN_SET_REC_CARRIER`` - - The driver supports setting the receive carrier frequency using - :ref:`ioctl LIRC_SET_REC_CARRIER `. - -.. _LIRC-CAN-SET-REC-DUTY-CYCLE-RANGE: - -``LIRC_CAN_SET_REC_DUTY_CYCLE_RANGE`` - - Unused. Kept just to avoid breaking uAPI. - -.. _LIRC-CAN-SET-REC-CARRIER-RANGE: - -``LIRC_CAN_SET_REC_CARRIER_RANGE`` - - The driver supports - :ref:`ioctl LIRC_SET_REC_CARRIER_RANGE `. - -.. _LIRC-CAN-GET-REC-RESOLUTION: - -``LIRC_CAN_GET_REC_RESOLUTION`` - - The driver supports - :ref:`ioctl LIRC_GET_REC_RESOLUTION `. - -.. _LIRC-CAN-SET-REC-TIMEOUT: - -``LIRC_CAN_SET_REC_TIMEOUT`` - - The driver supports - :ref:`ioctl LIRC_SET_REC_TIMEOUT `. - -.. _LIRC-CAN-SET-REC-FILTER: - -``LIRC_CAN_SET_REC_FILTER`` - - Unused. Kept just to avoid breaking uAPI. - -.. _LIRC-CAN-MEASURE-CARRIER: - -``LIRC_CAN_MEASURE_CARRIER`` - - The driver supports measuring of the modulation frequency using - :ref:`ioctl LIRC_SET_MEASURE_CARRIER_MODE `. - -.. _LIRC-CAN-USE-WIDEBAND-RECEIVER: - -``LIRC_CAN_USE_WIDEBAND_RECEIVER`` - - The driver supports learning mode using - :ref:`ioctl LIRC_SET_WIDEBAND_RECEIVER `. - -.. _LIRC-CAN-NOTIFY-DECODE: - -``LIRC_CAN_NOTIFY_DECODE`` - - Unused. Kept just to avoid breaking uAPI. - -.. _LIRC-CAN-SEND-RAW: - -``LIRC_CAN_SEND_RAW`` - - Unused. Kept just to avoid breaking uAPI. - -.. _LIRC-CAN-SEND-PULSE: - -``LIRC_CAN_SEND_PULSE`` - - The driver supports sending (also called as IR blasting or IR TX) using - :ref:`LIRC_MODE_PULSE `. This implies that - :ref:`LIRC_MODE_SCANCODE ` is also supported for - transmit, as long as the kernel is recent enough. Use the - :ref:`lirc_set_send_mode` to switch modes. - -.. _LIRC-CAN-SEND-MODE2: - -``LIRC_CAN_SEND_MODE2`` - - Unused. Kept just to avoid breaking uAPI. - :ref:`LIRC_MODE_MODE2 ` can only be used for receiving. - -.. _LIRC-CAN-SEND-LIRCCODE: - -``LIRC_CAN_SEND_LIRCCODE`` - - Unused. Kept just to avoid breaking uAPI. - - -Return Value -============ - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/rc/lirc-get-rec-mode.rst b/Documentation/media/uapi/rc/lirc-get-rec-mode.rst deleted file mode 100644 index 0a3e02aca80e..000000000000 --- a/Documentation/media/uapi/rc/lirc-get-rec-mode.rst +++ /dev/null @@ -1,74 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _lirc_get_rec_mode: -.. _lirc_set_rec_mode: - -********************************************** -ioctls LIRC_GET_REC_MODE and LIRC_SET_REC_MODE -********************************************** - -Name -==== - -LIRC_GET_REC_MODE/LIRC_SET_REC_MODE - Get/set current receive mode. - -Synopsis -======== - -.. c:function:: int ioctl( int fd, LIRC_GET_REC_MODE, __u32 *mode) - :name: LIRC_GET_REC_MODE - -.. c:function:: int ioctl( int fd, LIRC_SET_REC_MODE, __u32 *mode) - :name: LIRC_SET_REC_MODE - -Arguments -========= - -``fd`` - File descriptor returned by open(). - -``mode`` - Mode used for receive. - -Description -=========== - -Get and set the current receive mode. Only -:ref:`LIRC_MODE_MODE2 ` and -:ref:`LIRC_MODE_SCANCODE ` are supported. -Use :ref:`lirc_get_features` to find out which modes the driver supports. - -Return Value -============ - -.. tabularcolumns:: |p{2.5cm}|p{15.0cm}| - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - - .. row 1 - - - ``ENODEV`` - - - Device not available. - - - .. row 2 - - - ``ENOTTY`` - - - Device does not support receiving. - - - .. row 3 - - - ``EINVAL`` - - - Invalid mode or invalid mode for this device. diff --git a/Documentation/media/uapi/rc/lirc-get-rec-resolution.rst b/Documentation/media/uapi/rc/lirc-get-rec-resolution.rst deleted file mode 100644 index f560b694ccf2..000000000000 --- a/Documentation/media/uapi/rc/lirc-get-rec-resolution.rst +++ /dev/null @@ -1,54 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _lirc_get_rec_resolution: - -***************************** -ioctl LIRC_GET_REC_RESOLUTION -***************************** - -Name -==== - -LIRC_GET_REC_RESOLUTION - Obtain the value of receive resolution, in microseconds. - -Synopsis -======== - -.. c:function:: int ioctl( int fd, LIRC_GET_REC_RESOLUTION, __u32 *microseconds) - :name: LIRC_GET_REC_RESOLUTION - -Arguments -========= - -``fd`` - File descriptor returned by open(). - -``microseconds`` - Resolution, in microseconds. - - -Description -=========== - -Some receivers have maximum resolution which is defined by internal -sample rate or data format limitations. E.g. it's common that -signals can only be reported in 50 microsecond steps. - -This ioctl returns the integer value with such resolution, with can be -used by userspace applications like lircd to automatically adjust the -tolerance value. - - -Return Value -============ - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/rc/lirc-get-send-mode.rst b/Documentation/media/uapi/rc/lirc-get-send-mode.rst deleted file mode 100644 index 4f440c697052..000000000000 --- a/Documentation/media/uapi/rc/lirc-get-send-mode.rst +++ /dev/null @@ -1,78 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _lirc_get_send_mode: -.. _lirc_set_send_mode: - -************************************************ -ioctls LIRC_GET_SEND_MODE and LIRC_SET_SEND_MODE -************************************************ - -Name -==== - -LIRC_GET_SEND_MODE/LIRC_SET_SEND_MODE - Get/set current transmit mode. - -Synopsis -======== - -.. c:function:: int ioctl( int fd, LIRC_GET_SEND_MODE, __u32 *mode ) - :name: LIRC_GET_SEND_MODE - -.. c:function:: int ioctl( int fd, LIRC_SET_SEND_MODE, __u32 *mode ) - :name: LIRC_SET_SEND_MODE - -Arguments -========= - -``fd`` - File descriptor returned by open(). - -``mode`` - The mode used for transmitting. - - -Description -=========== - -Get/set current transmit mode. - -Only :ref:`LIRC_MODE_PULSE ` and -:ref:`LIRC_MODE_SCANCODE ` are supported by for IR send, -depending on the driver. Use :ref:`lirc_get_features` to find out which -modes the driver supports. - -Return Value -============ - - -.. tabularcolumns:: |p{2.5cm}|p{15.0cm}| - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - - - .. row 1 - - - ``ENODEV`` - - - Device not available. - - - .. row 2 - - - ``ENOTTY`` - - - Device does not support transmitting. - - - .. row 3 - - - ``EINVAL`` - - - Invalid mode or invalid mode for this device. diff --git a/Documentation/media/uapi/rc/lirc-get-timeout.rst b/Documentation/media/uapi/rc/lirc-get-timeout.rst deleted file mode 100644 index 1de214529f27..000000000000 --- a/Documentation/media/uapi/rc/lirc-get-timeout.rst +++ /dev/null @@ -1,63 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _lirc_get_min_timeout: -.. _lirc_get_max_timeout: - -**************************************************** -ioctls LIRC_GET_MIN_TIMEOUT and LIRC_GET_MAX_TIMEOUT -**************************************************** - -Name -==== - -LIRC_GET_MIN_TIMEOUT / LIRC_GET_MAX_TIMEOUT - Obtain the possible timeout -range for IR receive. - -Synopsis -======== - -.. c:function:: int ioctl( int fd, LIRC_GET_MIN_TIMEOUT, __u32 *timeout) - :name: LIRC_GET_MIN_TIMEOUT - -.. c:function:: int ioctl( int fd, LIRC_GET_MAX_TIMEOUT, __u32 *timeout) - :name: LIRC_GET_MAX_TIMEOUT - -Arguments -========= - -``fd`` - File descriptor returned by open(). - -``timeout`` - Timeout, in microseconds. - - -Description -=========== - -Some devices have internal timers that can be used to detect when -there's no IR activity for a long time. This can help lircd in -detecting that a IR signal is finished and can speed up the decoding -process. Returns an integer value with the minimum/maximum timeout -that can be set. - -.. note:: - - Some devices have a fixed timeout, in that case - both ioctls will return the same value even though the timeout - cannot be changed via :ref:`LIRC_SET_REC_TIMEOUT`. - - -Return Value -============ - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/rc/lirc-header.rst b/Documentation/media/uapi/rc/lirc-header.rst deleted file mode 100644 index c9b4f33e1031..000000000000 --- a/Documentation/media/uapi/rc/lirc-header.rst +++ /dev/null @@ -1,17 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _lirc_header: - -**************** -LIRC Header File -**************** - -.. kernel-include:: $BUILDDIR/lirc.h.rst - diff --git a/Documentation/media/uapi/rc/lirc-read.rst b/Documentation/media/uapi/rc/lirc-read.rst deleted file mode 100644 index 256e520bc27e..000000000000 --- a/Documentation/media/uapi/rc/lirc-read.rst +++ /dev/null @@ -1,76 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _lirc-read: - -*********** -LIRC read() -*********** - -Name -==== - -lirc-read - Read from a LIRC device - - -Synopsis -======== - -.. code-block:: c - - #include - - -.. c:function:: ssize_t read( int fd, void *buf, size_t count ) - :name: lirc-read - - -Arguments -========= - -``fd`` - File descriptor returned by ``open()``. - -``buf`` - Buffer to be filled - -``count`` - Max number of bytes to read - -Description -=========== - -:ref:`read() ` attempts to read up to ``count`` bytes from file -descriptor ``fd`` into the buffer starting at ``buf``. If ``count`` is zero, -:ref:`read() ` returns zero and has no other results. If ``count`` -is greater than ``SSIZE_MAX``, the result is unspecified. - -The exact format of the data depends on what :ref:`lirc_modes` a driver -uses. Use :ref:`lirc_get_features` to get the supported mode, and use -:ref:`lirc_set_rec_mode` set the current active mode. - -The mode :ref:`LIRC_MODE_MODE2 ` is for raw IR, -in which packets containing an unsigned int value describing an IR signal are -read from the chardev. - -Alternatively, :ref:`LIRC_MODE_SCANCODE ` can be available, -in this mode scancodes which are either decoded by software decoders, or -by hardware decoders. The :c:type:`rc_proto` member is set to the -:ref:`IR protocol ` -used for transmission, and ``scancode`` to the decoded scancode, -and the ``keycode`` set to the keycode or ``KEY_RESERVED``. - - -Return Value -============ - -On success, the number of bytes read is returned. It is not an error if -this number is smaller than the number of bytes requested, or the amount -of data required for one frame. On error, -1 is returned, and the ``errno`` -variable is set appropriately. diff --git a/Documentation/media/uapi/rc/lirc-set-measure-carrier-mode.rst b/Documentation/media/uapi/rc/lirc-set-measure-carrier-mode.rst deleted file mode 100644 index c80acd85e369..000000000000 --- a/Documentation/media/uapi/rc/lirc-set-measure-carrier-mode.rst +++ /dev/null @@ -1,53 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _lirc_set_measure_carrier_mode: - -*********************************** -ioctl LIRC_SET_MEASURE_CARRIER_MODE -*********************************** - -Name -==== - -LIRC_SET_MEASURE_CARRIER_MODE - enable or disable measure mode - -Synopsis -======== - -.. c:function:: int ioctl( int fd, LIRC_SET_MEASURE_CARRIER_MODE, __u32 *enable ) - :name: LIRC_SET_MEASURE_CARRIER_MODE - -Arguments -========= - -``fd`` - File descriptor returned by open(). - -``enable`` - enable = 1 means enable measure mode, enable = 0 means disable measure - mode. - - -Description -=========== - -.. _lirc-mode2-frequency: - -Enable or disable measure mode. If enabled, from the next key -press on, the driver will send ``LIRC_MODE2_FREQUENCY`` packets. By -default this should be turned off. - - -Return Value -============ - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/rc/lirc-set-rec-carrier-range.rst b/Documentation/media/uapi/rc/lirc-set-rec-carrier-range.rst deleted file mode 100644 index 443681d5cc10..000000000000 --- a/Documentation/media/uapi/rc/lirc-set-rec-carrier-range.rst +++ /dev/null @@ -1,54 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _lirc_set_rec_carrier_range: - -******************************** -ioctl LIRC_SET_REC_CARRIER_RANGE -******************************** - -Name -==== - -LIRC_SET_REC_CARRIER_RANGE - Set lower bound of the carrier used to modulate -IR receive. - -Synopsis -======== - -.. c:function:: int ioctl( int fd, LIRC_SET_REC_CARRIER_RANGE, __u32 *frequency ) - :name: LIRC_SET_REC_CARRIER_RANGE - -Arguments -========= - -``fd`` - File descriptor returned by open(). - -``frequency`` - Frequency of the carrier that modulates PWM data, in Hz. - -Description -=========== - -This ioctl sets the upper range of carrier frequency that will be recognized -by the IR receiver. - -.. note:: - - To set a range use :ref:`LIRC_SET_REC_CARRIER_RANGE - ` with the lower bound first and later call - :ref:`LIRC_SET_REC_CARRIER ` with the upper bound. - -Return Value -============ - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/rc/lirc-set-rec-carrier.rst b/Documentation/media/uapi/rc/lirc-set-rec-carrier.rst deleted file mode 100644 index cbe1e48b2a4a..000000000000 --- a/Documentation/media/uapi/rc/lirc-set-rec-carrier.rst +++ /dev/null @@ -1,53 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _lirc_set_rec_carrier: - -************************** -ioctl LIRC_SET_REC_CARRIER -************************** - -Name -==== - -LIRC_SET_REC_CARRIER - Set carrier used to modulate IR receive. - - -Synopsis -======== - -.. c:function:: int ioctl( int fd, LIRC_SET_REC_CARRIER, __u32 *frequency ) - :name: LIRC_SET_REC_CARRIER - -Arguments -========= - -``fd`` - File descriptor returned by open(). - -``frequency`` - Frequency of the carrier that modulates PWM data, in Hz. - -Description -=========== - -Set receive carrier used to modulate IR PWM pulses and spaces. - -.. note:: - - If called together with :ref:`LIRC_SET_REC_CARRIER_RANGE`, this ioctl - sets the upper bound frequency that will be recognized by the device. - - -Return Value -============ - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/rc/lirc-set-rec-timeout-reports.rst b/Documentation/media/uapi/rc/lirc-set-rec-timeout-reports.rst deleted file mode 100644 index d06d69414c1e..000000000000 --- a/Documentation/media/uapi/rc/lirc-set-rec-timeout-reports.rst +++ /dev/null @@ -1,56 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _lirc_set_rec_timeout_reports: - -********************************** -ioctl LIRC_SET_REC_TIMEOUT_REPORTS -********************************** - -Name -==== - -LIRC_SET_REC_TIMEOUT_REPORTS - enable or disable timeout reports for IR receive - -Synopsis -======== - -.. c:function:: int ioctl( int fd, LIRC_SET_REC_TIMEOUT_REPORTS, __u32 *enable ) - :name: LIRC_SET_REC_TIMEOUT_REPORTS - -Arguments -========= - -``fd`` - File descriptor returned by open(). - -``enable`` - enable = 1 means enable timeout report, enable = 0 means disable timeout - reports. - - -Description -=========== - -.. _lirc-mode2-timeout: - -Enable or disable timeout reports for IR receive. By default, timeout reports -should be turned off. - -.. note:: - - This ioctl is only valid for :ref:`LIRC_MODE_MODE2 `. - - -Return Value -============ - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/rc/lirc-set-rec-timeout.rst b/Documentation/media/uapi/rc/lirc-set-rec-timeout.rst deleted file mode 100644 index 163ac6065737..000000000000 --- a/Documentation/media/uapi/rc/lirc-set-rec-timeout.rst +++ /dev/null @@ -1,61 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _lirc_set_rec_timeout: -.. _lirc_get_rec_timeout: - -*************************************************** -ioctl LIRC_GET_REC_TIMEOUT and LIRC_SET_REC_TIMEOUT -*************************************************** - -Name -==== - -LIRC_GET_REC_TIMEOUT/LIRC_SET_REC_TIMEOUT - Get/set the integer value for IR inactivity timeout. - -Synopsis -======== - -.. c:function:: int ioctl( int fd, LIRC_GET_REC_TIMEOUT, __u32 *timeout ) - :name: LIRC_GET_REC_TIMEOUT - -.. c:function:: int ioctl( int fd, LIRC_SET_REC_TIMEOUT, __u32 *timeout ) - :name: LIRC_SET_REC_TIMEOUT - -Arguments -========= - -``fd`` - File descriptor returned by open(). - -``timeout`` - Timeout, in microseconds. - - -Description -=========== - -Get and set the integer value for IR inactivity timeout. - -If supported by the hardware, setting it to 0 disables all hardware timeouts -and data should be reported as soon as possible. If the exact value -cannot be set, then the next possible value _greater_ than the -given value should be set. - -.. note:: - - The range of supported timeout is given by :ref:`LIRC_GET_MIN_TIMEOUT`. - - -Return Value -============ - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/rc/lirc-set-send-carrier.rst b/Documentation/media/uapi/rc/lirc-set-send-carrier.rst deleted file mode 100644 index cffc6c1e15cc..000000000000 --- a/Documentation/media/uapi/rc/lirc-set-send-carrier.rst +++ /dev/null @@ -1,48 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _lirc_set_send_carrier: - -*************************** -ioctl LIRC_SET_SEND_CARRIER -*************************** - -Name -==== - -LIRC_SET_SEND_CARRIER - Set send carrier used to modulate IR TX. - - -Synopsis -======== - -.. c:function:: int ioctl( int fd, LIRC_SET_SEND_CARRIER, __u32 *frequency ) - :name: LIRC_SET_SEND_CARRIER - -Arguments -========= - -``fd`` - File descriptor returned by open(). - -``frequency`` - Frequency of the carrier to be modulated, in Hz. - -Description -=========== - -Set send carrier used to modulate IR PWM pulses and spaces. - - -Return Value -============ - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/rc/lirc-set-send-duty-cycle.rst b/Documentation/media/uapi/rc/lirc-set-send-duty-cycle.rst deleted file mode 100644 index 08ab3d1a96cd..000000000000 --- a/Documentation/media/uapi/rc/lirc-set-send-duty-cycle.rst +++ /dev/null @@ -1,54 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _lirc_set_send_duty_cycle: - -****************************** -ioctl LIRC_SET_SEND_DUTY_CYCLE -****************************** - -Name -==== - -LIRC_SET_SEND_DUTY_CYCLE - Set the duty cycle of the carrier signal for -IR transmit. - -Synopsis -======== - -.. c:function:: int ioctl( int fd, LIRC_SET_SEND_DUTY_CYCLE, __u32 *duty_cycle) - :name: LIRC_SET_SEND_DUTY_CYCLE - -Arguments -========= - -``fd`` - File descriptor returned by open(). - -``duty_cycle`` - Duty cicle, describing the pulse width in percent (from 1 to 99) of - the total cycle. Values 0 and 100 are reserved. - - -Description -=========== - -Get/set the duty cycle of the carrier signal for IR transmit. - -Currently, no special meaning is defined for 0 or 100, but this -could be used to switch off carrier generation in the future, so -these values should be reserved. - - -Return Value -============ - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/rc/lirc-set-transmitter-mask.rst b/Documentation/media/uapi/rc/lirc-set-transmitter-mask.rst deleted file mode 100644 index 889a739eaf0d..000000000000 --- a/Documentation/media/uapi/rc/lirc-set-transmitter-mask.rst +++ /dev/null @@ -1,58 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _lirc_set_transmitter_mask: - -******************************* -ioctl LIRC_SET_TRANSMITTER_MASK -******************************* - -Name -==== - -LIRC_SET_TRANSMITTER_MASK - Enables send codes on a given set of transmitters - -Synopsis -======== - -.. c:function:: int ioctl( int fd, LIRC_SET_TRANSMITTER_MASK, __u32 *mask ) - :name: LIRC_SET_TRANSMITTER_MASK - -Arguments -========= - -``fd`` - File descriptor returned by open(). - -``mask`` - Mask with channels to enable tx. Channel 0 is the least significant bit. - - -Description -=========== - -Some IR TX devices have multiple output channels, in such case, -:ref:`LIRC_CAN_SET_TRANSMITTER_MASK ` is -returned via :ref:`LIRC_GET_FEATURES` and this ioctl sets what channels will -send IR codes. - -This ioctl enables the given set of transmitters. The first transmitter is -encoded by the least significant bit and so on. - -When an invalid bit mask is given, i.e. a bit is set, even though the device -does not have so many transitters, then this ioctl returns the number of -available transitters and does nothing otherwise. - - -Return Value -============ - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/rc/lirc-set-wideband-receiver.rst b/Documentation/media/uapi/rc/lirc-set-wideband-receiver.rst deleted file mode 100644 index 592715452fce..000000000000 --- a/Documentation/media/uapi/rc/lirc-set-wideband-receiver.rst +++ /dev/null @@ -1,63 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _lirc_set_wideband_receiver: - -******************************** -ioctl LIRC_SET_WIDEBAND_RECEIVER -******************************** - -Name -==== - -LIRC_SET_WIDEBAND_RECEIVER - enable wide band receiver. - -Synopsis -======== - -.. c:function:: int ioctl( int fd, LIRC_SET_WIDEBAND_RECEIVER, __u32 *enable ) - :name: LIRC_SET_WIDEBAND_RECEIVER - -Arguments -========= - -``fd`` - File descriptor returned by open(). - -``enable`` - enable = 1 means enable wideband receiver, enable = 0 means disable - wideband receiver. - - -Description -=========== - -Some receivers are equipped with special wide band receiver which is -intended to be used to learn output of existing remote. This ioctl -allows enabling or disabling it. - -This might be useful of receivers that have otherwise narrow band receiver -that prevents them to be used with some remotes. Wide band receiver might -also be more precise. On the other hand its disadvantage it usually -reduced range of reception. - -.. note:: - - Wide band receiver might be implictly enabled if you enable - carrier reports. In that case it will be disabled as soon as you disable - carrier reports. Trying to disable wide band receiver while carrier - reports are active will do nothing. - - -Return Value -============ - -On success 0 is returned, on error -1 and the ``errno`` variable is set -appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/rc/lirc-write.rst b/Documentation/media/uapi/rc/lirc-write.rst deleted file mode 100644 index eafe13203ea3..000000000000 --- a/Documentation/media/uapi/rc/lirc-write.rst +++ /dev/null @@ -1,82 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _lirc-write: - -************ -LIRC write() -************ - -Name -==== - -lirc-write - Write to a LIRC device - - -Synopsis -======== - -.. code-block:: c - - #include - - -.. c:function:: ssize_t write( int fd, void *buf, size_t count ) - :name: lirc-write - -Arguments -========= - -``fd`` - File descriptor returned by ``open()``. - -``buf`` - Buffer with data to be written - -``count`` - Number of bytes at the buffer - -Description -=========== - -:ref:`write() ` writes up to ``count`` bytes to the device -referenced by the file descriptor ``fd`` from the buffer starting at -``buf``. - -The exact format of the data depends on what mode a driver is in, use -:ref:`lirc_get_features` to get the supported modes and use -:ref:`lirc_set_send_mode` set the mode. - -When in :ref:`LIRC_MODE_PULSE ` mode, the data written to -the chardev is a pulse/space sequence of integer values. Pulses and spaces -are only marked implicitly by their position. The data must start and end -with a pulse, therefore, the data must always include an uneven number of -samples. The write function blocks until the data has been transmitted -by the hardware. If more data is provided than the hardware can send, the -driver returns ``EINVAL``. - -When in :ref:`LIRC_MODE_SCANCODE ` mode, one -``struct lirc_scancode`` must be written to the chardev at a time, else -``EINVAL`` is returned. Set the desired scancode in the ``scancode`` member, -and the :ref:`IR protocol ` in the -:c:type:`rc_proto`: member. All other members must be -set to 0, else ``EINVAL`` is returned. If there is no protocol encoder -for the protocol or the scancode is not valid for the specified protocol, -``EINVAL`` is returned. The write function blocks until the scancode -is transmitted by the hardware. - - -Return Value -============ - -On success, the number of bytes written is returned. It is not an error if -this number is smaller than the number of bytes requested, or the amount -of data required for one frame. On error, -1 is returned, and the ``errno`` -variable is set appropriately. The generic error codes are described at the -:ref:`Generic Error Codes ` chapter. diff --git a/Documentation/media/uapi/rc/rc-intro.rst b/Documentation/media/uapi/rc/rc-intro.rst deleted file mode 100644 index 37c5f90c76e7..000000000000 --- a/Documentation/media/uapi/rc/rc-intro.rst +++ /dev/null @@ -1,31 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _Remote_controllers_Intro: - -************ -Introduction -************ - -Currently, most analog and digital devices have a Infrared input for -remote controllers. Each manufacturer has their own type of control. It -is not rare for the same manufacturer to ship different types of -controls, depending on the device. - -A Remote Controller interface is mapped as a normal evdev/input -interface, just like a keyboard or a mouse. So, it uses all ioctls -already defined for any other input devices. - -However, remove controllers are more flexible than a normal input -device, as the IR receiver (and/or transmitter) can be used in -conjunction with a wide variety of different IR remotes. - -In order to allow flexibility, the Remote Controller subsystem allows -controlling the RC-specific attributes via -:ref:`the sysfs class nodes `. diff --git a/Documentation/media/uapi/rc/rc-protos.rst b/Documentation/media/uapi/rc/rc-protos.rst deleted file mode 100644 index b250ebe301d5..000000000000 --- a/Documentation/media/uapi/rc/rc-protos.rst +++ /dev/null @@ -1,456 +0,0 @@ -.. SPDX-License-Identifier: GPL-2.0 -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _Remote_controllers_Protocols: - -***************************************** -Remote Controller Protocols and Scancodes -***************************************** - -IR is encoded as a series of pulses and spaces, using a protocol. These -protocols can encode e.g. an address (which device should respond) and a -command: what it should do. The values for these are not always consistent -across different devices for a given protocol. - -Therefore out the output of the IR decoder is a scancode; a single u32 -value. Using keymap tables this can be mapped to linux key codes. - -Other things can be encoded too. Some IR protocols encode a toggle bit; this -is to distinguish whether the same button is being held down, or has been -released and pressed again. If has been released and pressed again, the -toggle bit will invert from one IR message to the next. - -Some remotes have a pointer-type device which can used to control the -mouse; some air conditioning systems can have their target temperature -target set in IR. - -The following are the protocols the kernel knows about and also lists -how scancodes are encoded for each protocol. - -rc-5 (RC_PROTO_RC5) -------------------- - -This IR protocol uses manchester encoding to encode 14 bits. There is a -detailed description here https://www.sbprojects.net/knowledge/ir/rc5.php. - -The scancode encoding is *not* consistent with the lirc daemon (lircd) rc5 -protocol, or the manchester BPF decoder. - -.. flat-table:: rc5 bits scancode mapping - :widths: 1 1 2 - - * - rc-5 bit - - - scancode bit - - - description - - * - 1 - - - none - - - Start bit, always set - - * - 1 - - - 6 (inverted) - - - 2nd start bit in rc5, re-used as 6th command bit - - * - 1 - - - none - - - Toggle bit - - * - 5 - - - 8 to 13 - - - Address - - * - 6 - - - 0 to 5 - - - Command - -There is a variant of rc5 called either rc5x or extended rc5 -where there the second stop bit is the 6th commmand bit, but inverted. -This is done so it the scancodes and encoding is compatible with existing -schemes. This bit is stored in bit 6 of the scancode, inverted. This is -done to keep it compatible with plain rc-5 where there are two start bits. - -rc-5-sz (RC_PROTO_RC5_SZ) -------------------------- -This is much like rc-5 but one bit longer. The scancode is encoded -differently. - -.. flat-table:: rc-5-sz bits scancode mapping - :widths: 1 1 2 - - * - rc-5-sz bits - - - scancode bit - - - description - - * - 1 - - - none - - - Start bit, always set - - * - 1 - - - 13 - - - Address bit - - * - 1 - - - none - - - Toggle bit - - * - 6 - - - 6 to 11 - - - Address - - * - 6 - - - 0 to 5 - - - Command - -rc-5x-20 (RC_PROTO_RC5X_20) ---------------------------- - -This rc-5 extended to encoded 20 bits. The is a 3555 microseconds space -after the 8th bit. - -.. flat-table:: rc-5x-20 bits scancode mapping - :widths: 1 1 2 - - * - rc-5-sz bits - - - scancode bit - - - description - - * - 1 - - - none - - - Start bit, always set - - * - 1 - - - 14 - - - Address bit - - * - 1 - - - none - - - Toggle bit - - * - 5 - - - 16 to 20 - - - Address - - * - 6 - - - 8 to 13 - - - Address - - * - 6 - - - 0 to 5 - - - Command - - -jvc (RC_PROTO_JVC) ------------------- - -The jvc protocol is much like nec, without the inverted values. It is -described here https://www.sbprojects.net/knowledge/ir/jvc.php. - -The scancode is a 16 bits value, where the address is the lower 8 bits -and the command the higher 8 bits; this is reversed from IR order. - -sony-12 (RC_PROTO_SONY12) -------------------------- - -The sony protocol is a pulse-width encoding. There are three variants, -which just differ in number of bits and scancode encoding. - -.. flat-table:: sony-12 bits scancode mapping - :widths: 1 1 2 - - * - sony-12 bits - - - scancode bit - - - description - - * - 5 - - - 16 to 20 - - - device - - * - 7 - - - 0 to 6 - - - function - -sony-15 (RC_PROTO_SONY15) -------------------------- - -The sony protocol is a pulse-width encoding. There are three variants, -which just differ in number of bits and scancode encoding. - -.. flat-table:: sony-12 bits scancode mapping - :widths: 1 1 2 - - * - sony-12 bits - - - scancode bit - - - description - - * - 8 - - - 16 to 23 - - - device - - * - 7 - - - 0 to 6 - - - function - -sony-20 (RC_PROTO_SONY20) -------------------------- - -The sony protocol is a pulse-width encoding. There are three variants, -which just differ in number of bits and scancode encoding. - -.. flat-table:: sony-20 bits scancode mapping - :widths: 1 1 2 - - * - sony-20 bits - - - scancode bit - - - description - - * - 5 - - - 16 to 20 - - - device - - * - 7 - - - 0 to 7 - - - device - - * - 8 - - - 8 to 15 - - - extended bits - -nec (RC_PROTO_NEC) ------------------- - -The nec protocol encodes an 8 bit address and an 8 bit command. It is -described here https://www.sbprojects.net/knowledge/ir/nec.php. Note -that the protocol sends least significant bit first. - -As a check, the nec protocol sends the address and command twice; the -second time it is inverted. This is done for verification. - -A plain nec IR message has 16 bits; the high 8 bits are the address -and the low 8 bits are the command. - -nec-x (RC_PROTO_NECX) ---------------------- - -Extended nec has a 16 bit address and a 8 bit command. This is encoded -as a 24 bit value as you would expect, with the lower 8 bits the command -and the upper 16 bits the address. - -nec-32 (RC_PROTO_NEC32) ------------------------ - -nec-32 does not send an inverted address or an inverted command; the -entire message, all 32 bits, are used. - -For this to be decoded correctly, the second 8 bits must not be the -inverted value of the first, and also the last 8 bits must not be the -inverted value of the third 8 bit value. - -The scancode has a somewhat unusual encoding. - -.. flat-table:: nec-32 bits scancode mapping - - * - nec-32 bits - - - scancode bit - - * - First 8 bits - - - 16 to 23 - - * - Second 8 bits - - - 24 to 31 - - * - Third 8 bits - - - 0 to 7 - - * - Fourth 8 bits - - - 8 to 15 - -sanyo (RC_PROTO_SANYO) ----------------------- - -The sanyo protocol is like the nec protocol, but with 13 bits address -rather than 8 bits. Both the address and the command are followed by -their inverted versions, but these are not present in the scancodes. - -Bis 8 to 20 of the scancode is the 13 bits address, and the lower 8 -bits are the command. - -mcir2-kbd (RC_PROTO_MCIR2_KBD) ------------------------------- - -This protocol is generated by the Microsoft MCE keyboard for keyboard -events. Refer to the ir-mce_kbd-decoder.c to see how it is encoded. - -mcir2-mse (RC_PROTO_MCIR2_MSE) ------------------------------- - -This protocol is generated by the Microsoft MCE keyboard for pointer -events. Refer to the ir-mce_kbd-decoder.c to see how it is encoded. - -rc-6-0 (RC_PROTO_RC6_0) ------------------------ - -This is the rc-6 in mode 0. rc-6 is described here -https://www.sbprojects.net/knowledge/ir/rc6.php. -The scancode is the exact 16 bits as in the protocol. There is also a -toggle bit. - -rc-6-6a-20 (RC_PROTO_RC6_6A_20) -------------------------------- - -This is the rc-6 in mode 6a, 20 bits. rc-6 is described here -https://www.sbprojects.net/knowledge/ir/rc6.php. -The scancode is the exact 20 bits -as in the protocol. There is also a toggle bit. - -rc-6-6a-24 (RC_PROTO_RC6_6A_24) -------------------------------- - -This is the rc-6 in mode 6a, 24 bits. rc-6 is described here -https://www.sbprojects.net/knowledge/ir/rc6.php. -The scancode is the exact 24 bits -as in the protocol. There is also a toggle bit. - -rc-6-6a-32 (RC_PROTO_RC6_6A_32) -------------------------------- - -This is the rc-6 in mode 6a, 32 bits. rc-6 is described here -https://www.sbprojects.net/knowledge/ir/rc6.php. -The upper 16 bits are the vendor, -and the lower 16 bits are the vendor-specific bits. This protocol is -for the non-Microsoft MCE variant (vendor != 0x800f). - - -rc-6-mce (RC_PROTO_RC6_MCE) ---------------------------- - -This is the rc-6 in mode 6a, 32 bits. The upper 16 bits are the vendor, -and the lower 16 bits are the vendor-specific bits. This protocol is -for the Microsoft MCE variant (vendor = 0x800f). The toggle bit in the -protocol itself is ignored, and the 16th bit should be takes as the toggle -bit. - -sharp (RC_PROTO_SHARP) ----------------------- - -This is a protocol used by Sharp VCRs, is described here -https://www.sbprojects.net/knowledge/ir/sharp.php. There is a very long -(40ms) space between the normal and inverted values, and some IR receivers -cannot decode this. - -There is a 5 bit address and a 8 bit command. In the scancode the address is -in bits 8 to 12, and the command in bits 0 to 7. - -xmp (RC_PROTO_XMP) ------------------- - -This protocol has several versions and only version 1 is supported. Refer -to the decoder (ir-xmp-decoder.c) to see how it is encoded. - - -cec (RC_PROTO_CEC) ------------------- - -This is not an IR protocol, this is a protocol over CEC. The CEC -infrastructure uses rc-core for handling CEC commands, so that they -can easily be remapped. - -imon (RC_PROTO_IMON) --------------------- - -This protocol is used by Antec Veris/SoundGraph iMON remotes. - -The protocol -describes both button presses and pointer movements. The protocol encodes -31 bits, and the scancode is simply the 31 bits with the top bit always 0. - -rc-mm-12 (RC_PROTO_RCMM12) --------------------------- - -The rc-mm protocol is described here -https://www.sbprojects.net/knowledge/ir/rcmm.php. The scancode is simply -the 12 bits. - -rc-mm-24 (RC_PROTO_RCMM24) --------------------------- - -The rc-mm protocol is described here -https://www.sbprojects.net/knowledge/ir/rcmm.php. The scancode is simply -the 24 bits. - -rc-mm-32 (RC_PROTO_RCMM32) --------------------------- - -The rc-mm protocol is described here -https://www.sbprojects.net/knowledge/ir/rcmm.php. The scancode is simply -the 32 bits. - -xbox-dvd (RC_PROTO_XBOX_DVD) ----------------------------- - -This protocol is used by XBox DVD Remote, which was made for the original -XBox. There is no in-kernel decoder or encoder for this protocol. The usb -device decodes the protocol. There is a BPF decoder available in v4l-utils. diff --git a/Documentation/media/uapi/rc/rc-sysfs-nodes.rst b/Documentation/media/uapi/rc/rc-sysfs-nodes.rst deleted file mode 100644 index b8e8319e3317..000000000000 --- a/Documentation/media/uapi/rc/rc-sysfs-nodes.rst +++ /dev/null @@ -1,151 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _remote_controllers_sysfs_nodes: - -******************************* -Remote Controller's sysfs nodes -******************************* - -As defined at ``Documentation/ABI/testing/sysfs-class-rc``, those are -the sysfs nodes that control the Remote Controllers: - - -.. _sys_class_rc: - -/sys/class/rc/ -============== - -The ``/sys/class/rc/`` class sub-directory belongs to the Remote -Controller core and provides a sysfs interface for configuring infrared -remote controller receivers. - - -.. _sys_class_rc_rcN: - -/sys/class/rc/rcN/ -================== - -A ``/sys/class/rc/rcN`` directory is created for each remote control -receiver device where N is the number of the receiver. - - -.. _sys_class_rc_rcN_protocols: - -/sys/class/rc/rcN/protocols -=========================== - -Reading this file returns a list of available protocols, something like:: - - rc5 [rc6] nec jvc [sony] - -Enabled protocols are shown in [] brackets. - -Writing "+proto" will add a protocol to the list of enabled protocols. - -Writing "-proto" will remove a protocol from the list of enabled -protocols. - -Writing "proto" will enable only "proto". - -Writing "none" will disable all protocols. - -Write fails with ``EINVAL`` if an invalid protocol combination or unknown -protocol name is used. - - -.. _sys_class_rc_rcN_filter: - -/sys/class/rc/rcN/filter -======================== - -Sets the scancode filter expected value. - -Use in combination with ``/sys/class/rc/rcN/filter_mask`` to set the -expected value of the bits set in the filter mask. If the hardware -supports it then scancodes which do not match the filter will be -ignored. Otherwise the write will fail with an error. - -This value may be reset to 0 if the current protocol is altered. - - -.. _sys_class_rc_rcN_filter_mask: - -/sys/class/rc/rcN/filter_mask -============================= - -Sets the scancode filter mask of bits to compare. Use in combination -with ``/sys/class/rc/rcN/filter`` to set the bits of the scancode which -should be compared against the expected value. A value of 0 disables the -filter to allow all valid scancodes to be processed. - -If the hardware supports it then scancodes which do not match the filter -will be ignored. Otherwise the write will fail with an error. - -This value may be reset to 0 if the current protocol is altered. - - -.. _sys_class_rc_rcN_wakeup_protocols: - -/sys/class/rc/rcN/wakeup_protocols -================================== - -Reading this file returns a list of available protocols to use for the -wakeup filter, something like:: - - rc-5 nec nec-x rc-6-0 rc-6-6a-24 [rc-6-6a-32] rc-6-mce - -Note that protocol variants are listed, so ``nec``, ``sony``, ``rc-5``, ``rc-6`` -have their different bit length encodings listed if available. - -Note that all protocol variants are listed. - -The enabled wakeup protocol is shown in [] brackets. - -Only one protocol can be selected at a time. - -Writing "proto" will use "proto" for wakeup events. - -Writing "none" will disable wakeup. - -Write fails with ``EINVAL`` if an invalid protocol combination or unknown -protocol name is used, or if wakeup is not supported by the hardware. - - -.. _sys_class_rc_rcN_wakeup_filter: - -/sys/class/rc/rcN/wakeup_filter -=============================== - -Sets the scancode wakeup filter expected value. Use in combination with -``/sys/class/rc/rcN/wakeup_filter_mask`` to set the expected value of -the bits set in the wakeup filter mask to trigger a system wake event. - -If the hardware supports it and wakeup_filter_mask is not 0 then -scancodes which match the filter will wake the system from e.g. suspend -to RAM or power off. Otherwise the write will fail with an error. - -This value may be reset to 0 if the wakeup protocol is altered. - - -.. _sys_class_rc_rcN_wakeup_filter_mask: - -/sys/class/rc/rcN/wakeup_filter_mask -==================================== - -Sets the scancode wakeup filter mask of bits to compare. Use in -combination with ``/sys/class/rc/rcN/wakeup_filter`` to set the bits of -the scancode which should be compared against the expected value to -trigger a system wake event. - -If the hardware supports it and wakeup_filter_mask is not 0 then -scancodes which match the filter will wake the system from e.g. suspend -to RAM or power off. Otherwise the write will fail with an error. - -This value may be reset to 0 if the wakeup protocol is altered. diff --git a/Documentation/media/uapi/rc/rc-table-change.rst b/Documentation/media/uapi/rc/rc-table-change.rst deleted file mode 100644 index 4a2e601b89fb..000000000000 --- a/Documentation/media/uapi/rc/rc-table-change.rst +++ /dev/null @@ -1,25 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _Remote_controllers_table_change: - -******************************************* -Changing default Remote Controller mappings -******************************************* - -The event interface provides two ioctls to be used against the -/dev/input/event device, to allow changing the default keymapping. - -This program demonstrates how to replace the keymap tables. - - -.. toctree:: - :maxdepth: 1 - - keytable.c diff --git a/Documentation/media/uapi/rc/rc-tables.rst b/Documentation/media/uapi/rc/rc-tables.rst deleted file mode 100644 index 20d7c686922b..000000000000 --- a/Documentation/media/uapi/rc/rc-tables.rst +++ /dev/null @@ -1,766 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _Remote_controllers_tables: - -************************ -Remote controller tables -************************ - -Unfortunately, for several years, there was no effort to create uniform -IR keycodes for different devices. This caused the same IR keyname to be -mapped completely differently on different IR devices. This resulted -that the same IR keyname to be mapped completely different on different -IR's. Due to that, V4L2 API now specifies a standard for mapping Media -keys on IR. - -This standard should be used by both V4L/DVB drivers and userspace -applications - -The modules register the remote as keyboard within the linux input -layer. This means that the IR key strokes will look like normal keyboard -key strokes (if CONFIG_INPUT_KEYBOARD is enabled). Using the event -devices (CONFIG_INPUT_EVDEV) it is possible for applications to access -the remote via /dev/input/event devices. - - -.. _rc_standard_keymap: - -.. tabularcolumns:: |p{4.4cm}|p{4.4cm}|p{8.7cm}| - -.. flat-table:: IR default keymapping - :header-rows: 0 - :stub-columns: 0 - :widths: 1 1 2 - - - - .. row 1 - - - Key code - - - Meaning - - - Key examples on IR - - - .. row 2 - - - **Numeric keys** - - - .. row 3 - - - ``KEY_NUMERIC_0`` - - - Keyboard digit 0 - - - 0 - - - .. row 4 - - - ``KEY_NUMERIC_1`` - - - Keyboard digit 1 - - - 1 - - - .. row 5 - - - ``KEY_NUMERIC_2`` - - - Keyboard digit 2 - - - 2 - - - .. row 6 - - - ``KEY_NUMERIC_3`` - - - Keyboard digit 3 - - - 3 - - - .. row 7 - - - ``KEY_NUMERIC_4`` - - - Keyboard digit 4 - - - 4 - - - .. row 8 - - - ``KEY_NUMERIC_5`` - - - Keyboard digit 5 - - - 5 - - - .. row 9 - - - ``KEY_NUMERIC_6`` - - - Keyboard digit 6 - - - 6 - - - .. row 10 - - - ``KEY_NUMERIC_7`` - - - Keyboard digit 7 - - - 7 - - - .. row 11 - - - ``KEY_NUMERIC_8`` - - - Keyboard digit 8 - - - 8 - - - .. row 12 - - - ``KEY_NUMERIC_9`` - - - Keyboard digit 9 - - - 9 - - - .. row 13 - - - **Movie play control** - - - .. row 14 - - - ``KEY_FORWARD`` - - - Instantly advance in time - - - >> / FORWARD - - - .. row 15 - - - ``KEY_BACK`` - - - Instantly go back in time - - - <<< / BACK - - - .. row 16 - - - ``KEY_FASTFORWARD`` - - - Play movie faster - - - >>> / FORWARD - - - .. row 17 - - - ``KEY_REWIND`` - - - Play movie back - - - REWIND / BACKWARD - - - .. row 18 - - - ``KEY_NEXT`` - - - Select next chapter / sub-chapter / interval - - - NEXT / SKIP - - - .. row 19 - - - ``KEY_PREVIOUS`` - - - Select previous chapter / sub-chapter / interval - - - << / PREV / PREVIOUS - - - .. row 20 - - - ``KEY_AGAIN`` - - - Repeat the video or a video interval - - - REPEAT / LOOP / RECALL - - - .. row 21 - - - ``KEY_PAUSE`` - - - Pause stream - - - PAUSE / FREEZE - - - .. row 22 - - - ``KEY_PLAY`` - - - Play movie at the normal timeshift - - - NORMAL TIMESHIFT / LIVE / > - - - .. row 23 - - - ``KEY_PLAYPAUSE`` - - - Alternate between play and pause - - - PLAY / PAUSE - - - .. row 24 - - - ``KEY_STOP`` - - - Stop stream - - - STOP - - - .. row 25 - - - ``KEY_RECORD`` - - - Start/stop recording stream - - - CAPTURE / REC / RECORD/PAUSE - - - .. row 26 - - - ``KEY_CAMERA`` - - - Take a picture of the image - - - CAMERA ICON / CAPTURE / SNAPSHOT - - - .. row 27 - - - ``KEY_SHUFFLE`` - - - Enable shuffle mode - - - SHUFFLE - - - .. row 28 - - - ``KEY_TIME`` - - - Activate time shift mode - - - TIME SHIFT - - - .. row 29 - - - ``KEY_TITLE`` - - - Allow changing the chapter - - - CHAPTER - - - .. row 30 - - - ``KEY_SUBTITLE`` - - - Allow changing the subtitle - - - SUBTITLE - - - .. row 31 - - - **Image control** - - - .. row 32 - - - ``KEY_BRIGHTNESSDOWN`` - - - Decrease Brightness - - - BRIGHTNESS DECREASE - - - .. row 33 - - - ``KEY_BRIGHTNESSUP`` - - - Increase Brightness - - - BRIGHTNESS INCREASE - - - .. row 34 - - - ``KEY_ANGLE`` - - - Switch video camera angle (on videos with more than one angle - stored) - - - ANGLE / SWAP - - - .. row 35 - - - ``KEY_EPG`` - - - Open the Elecrowonic Play Guide (EPG) - - - EPG / GUIDE - - - .. row 36 - - - ``KEY_TEXT`` - - - Activate/change closed caption mode - - - CLOSED CAPTION/TELETEXT / DVD TEXT / TELETEXT / TTX - - - .. row 37 - - - **Audio control** - - - .. row 38 - - - ``KEY_AUDIO`` - - - Change audio source - - - AUDIO SOURCE / AUDIO / MUSIC - - - .. row 39 - - - ``KEY_MUTE`` - - - Mute/unmute audio - - - MUTE / DEMUTE / UNMUTE - - - .. row 40 - - - ``KEY_VOLUMEDOWN`` - - - Decrease volume - - - VOLUME- / VOLUME DOWN - - - .. row 41 - - - ``KEY_VOLUMEUP`` - - - Increase volume - - - VOLUME+ / VOLUME UP - - - .. row 42 - - - ``KEY_MODE`` - - - Change sound mode - - - MONO/STEREO - - - .. row 43 - - - ``KEY_LANGUAGE`` - - - Select Language - - - 1ST / 2ND LANGUAGE / DVD LANG / MTS/SAP / MTS SEL - - - .. row 44 - - - **Channel control** - - - .. row 45 - - - ``KEY_CHANNEL`` - - - Go to the next favorite channel - - - ALT / CHANNEL / CH SURFING / SURF / FAV - - - .. row 46 - - - ``KEY_CHANNELDOWN`` - - - Decrease channel sequentially - - - CHANNEL - / CHANNEL DOWN / DOWN - - - .. row 47 - - - ``KEY_CHANNELUP`` - - - Increase channel sequentially - - - CHANNEL + / CHANNEL UP / UP - - - .. row 48 - - - ``KEY_DIGITS`` - - - Use more than one digit for channel - - - PLUS / 100/ 1xx / xxx / -/-- / Single Double Triple Digit - - - .. row 49 - - - ``KEY_SEARCH`` - - - Start channel autoscan - - - SCAN / AUTOSCAN - - - .. row 50 - - - **Colored keys** - - - .. row 51 - - - ``KEY_BLUE`` - - - IR Blue key - - - BLUE - - - .. row 52 - - - ``KEY_GREEN`` - - - IR Green Key - - - GREEN - - - .. row 53 - - - ``KEY_RED`` - - - IR Red key - - - RED - - - .. row 54 - - - ``KEY_YELLOW`` - - - IR Yellow key - - - YELLOW - - - .. row 55 - - - **Media selection** - - - .. row 56 - - - ``KEY_CD`` - - - Change input source to Compact Disc - - - CD - - - .. row 57 - - - ``KEY_DVD`` - - - Change input to DVD - - - DVD / DVD MENU - - - .. row 58 - - - ``KEY_EJECTCLOSECD`` - - - Open/close the CD/DVD player - - - -> ) / CLOSE / OPEN - - - .. row 59 - - - ``KEY_MEDIA`` - - - Turn on/off Media application - - - PC/TV / TURN ON/OFF APP - - - .. row 60 - - - ``KEY_PC`` - - - Selects from TV to PC - - - PC - - - .. row 61 - - - ``KEY_RADIO`` - - - Put into AM/FM radio mode - - - RADIO / TV/FM / TV/RADIO / FM / FM/RADIO - - - .. row 62 - - - ``KEY_TV`` - - - Select tv mode - - - TV / LIVE TV - - - .. row 63 - - - ``KEY_TV2`` - - - Select Cable mode - - - AIR/CBL - - - .. row 64 - - - ``KEY_VCR`` - - - Select VCR mode - - - VCR MODE / DTR - - - .. row 65 - - - ``KEY_VIDEO`` - - - Alternate between input modes - - - SOURCE / SELECT / DISPLAY / SWITCH INPUTS / VIDEO - - - .. row 66 - - - **Power control** - - - .. row 67 - - - ``KEY_POWER`` - - - Turn on/off computer - - - SYSTEM POWER / COMPUTER POWER - - - .. row 68 - - - ``KEY_POWER2`` - - - Turn on/off application - - - TV ON/OFF / POWER - - - .. row 69 - - - ``KEY_SLEEP`` - - - Activate sleep timer - - - SLEEP / SLEEP TIMER - - - .. row 70 - - - ``KEY_SUSPEND`` - - - Put computer into suspend mode - - - STANDBY / SUSPEND - - - .. row 71 - - - **Window control** - - - .. row 72 - - - ``KEY_CLEAR`` - - - Stop stream and return to default input video/audio - - - CLEAR / RESET / BOSS KEY - - - .. row 73 - - - ``KEY_CYCLEWINDOWS`` - - - Minimize windows and move to the next one - - - ALT-TAB / MINIMIZE / DESKTOP - - - .. row 74 - - - ``KEY_FAVORITES`` - - - Open the favorites stream window - - - TV WALL / Favorites - - - .. row 75 - - - ``KEY_MENU`` - - - Call application menu - - - 2ND CONTROLS (USA: MENU) / DVD/MENU / SHOW/HIDE CTRL - - - .. row 76 - - - ``KEY_NEW`` - - - Open/Close Picture in Picture - - - PIP - - - .. row 77 - - - ``KEY_OK`` - - - Send a confirmation code to application - - - OK / ENTER / RETURN - - - .. row 78 - - - ``KEY_ASPECT_RATIO`` - - - Select screen aspect ratio - - - 4:3 16:9 SELECT - - - .. row 79 - - - ``KEY_FULL_SCREEN`` - - - Put device into zoom/full screen mode - - - ZOOM / FULL SCREEN / ZOOM+ / HIDE PANNEL / SWITCH - - - .. row 80 - - - **Navigation keys** - - - .. row 81 - - - ``KEY_ESC`` - - - Cancel current operation - - - CANCEL / BACK - - - .. row 82 - - - ``KEY_HELP`` - - - Open a Help window - - - HELP - - - .. row 83 - - - ``KEY_HOMEPAGE`` - - - Navigate to Homepage - - - HOME - - - .. row 84 - - - ``KEY_INFO`` - - - Open On Screen Display - - - DISPLAY INFORMATION / OSD - - - .. row 85 - - - ``KEY_WWW`` - - - Open the default browser - - - WEB - - - .. row 86 - - - ``KEY_UP`` - - - Up key - - - UP - - - .. row 87 - - - ``KEY_DOWN`` - - - Down key - - - DOWN - - - .. row 88 - - - ``KEY_LEFT`` - - - Left key - - - LEFT - - - .. row 89 - - - ``KEY_RIGHT`` - - - Right key - - - RIGHT - - - .. row 90 - - - **Miscellaneous keys** - - - .. row 91 - - - ``KEY_DOT`` - - - Return a dot - - - . - - - .. row 92 - - - ``KEY_FN`` - - - Select a function - - - FUNCTION - - -It should be noted that, sometimes, there some fundamental missing keys -at some cheaper IR's. Due to that, it is recommended to: - - -.. _rc_keymap_notes: - -.. flat-table:: Notes - :header-rows: 0 - :stub-columns: 0 - - - - .. row 1 - - - On simpler IR's, without separate channel keys, you need to map UP - as ``KEY_CHANNELUP`` - - - .. row 2 - - - On simpler IR's, without separate channel keys, you need to map - DOWN as ``KEY_CHANNELDOWN`` - - - .. row 3 - - - On simpler IR's, without separate volume keys, you need to map - LEFT as ``KEY_VOLUMEDOWN`` - - - .. row 4 - - - On simpler IR's, without separate volume keys, you need to map - RIGHT as ``KEY_VOLUMEUP`` diff --git a/Documentation/media/uapi/rc/remote_controllers.rst b/Documentation/media/uapi/rc/remote_controllers.rst deleted file mode 100644 index 20e0f986df49..000000000000 --- a/Documentation/media/uapi/rc/remote_controllers.rst +++ /dev/null @@ -1,59 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. include:: - -.. _remote_controllers: - -################################ -Part III - Remote Controller API -################################ - -.. only:: html - - .. class:: toc-title - - Table of Contents - -.. toctree:: - :maxdepth: 5 - :numbered: - - rc-intro - rc-sysfs-nodes - rc-protos - rc-tables - rc-table-change - lirc-dev - - -********************** -Revision and Copyright -********************** - -Authors: - -- Carvalho Chehab, Mauro - - - Initial version. - -**Copyright** |copy| 2009-2016 : Mauro Carvalho Chehab - -**************** -Revision History -**************** - -:revision: 3.15 / 2014-02-06 (*mcc*) - -Added the interface description and the RC sysfs class description. - - -:revision: 1.0 / 2009-09-06 (*mcc*) - -Initial revision diff --git a/Documentation/media/uapi/v4l/app-pri.rst b/Documentation/media/uapi/v4l/app-pri.rst deleted file mode 100644 index c25c1271b4f6..000000000000 --- a/Documentation/media/uapi/v4l/app-pri.rst +++ /dev/null @@ -1,37 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _app-pri: - -******************** -Application Priority -******************** - -When multiple applications share a device it may be desirable to assign -them different priorities. Contrary to the traditional "rm -rf /" school -of thought, a video recording application could for example block other -applications from changing video controls or switching the current TV -channel. Another objective is to permit low priority applications -working in background, which can be preempted by user controlled -applications and automatically regain control of the device at a later -time. - -Since these features cannot be implemented entirely in user space V4L2 -defines the :ref:`VIDIOC_G_PRIORITY ` and -:ref:`VIDIOC_S_PRIORITY ` ioctls to request and -query the access priority associate with a file descriptor. Opening a -device assigns a medium priority, compatible with earlier versions of -V4L2 and drivers not supporting these ioctls. Applications requiring a -different priority will usually call :ref:`VIDIOC_S_PRIORITY -` after verifying the device with the -:ref:`VIDIOC_QUERYCAP` ioctl. - -Ioctls changing driver properties, such as -:ref:`VIDIOC_S_INPUT `, return an ``EBUSY`` error code -after another application obtained higher priority. diff --git a/Documentation/media/uapi/v4l/async.rst b/Documentation/media/uapi/v4l/async.rst deleted file mode 100644 index be9539313f60..000000000000 --- a/Documentation/media/uapi/v4l/async.rst +++ /dev/null @@ -1,16 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _async: - -**************** -Asynchronous I/O -**************** - -This method is not defined yet. diff --git a/Documentation/media/uapi/v4l/audio.rst b/Documentation/media/uapi/v4l/audio.rst deleted file mode 100644 index 4c7fdbc8a860..000000000000 --- a/Documentation/media/uapi/v4l/audio.rst +++ /dev/null @@ -1,104 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _audio: - -************************ -Audio Inputs and Outputs -************************ - -Audio inputs and outputs are physical connectors of a device. Video -capture devices have inputs, output devices have outputs, zero or more -each. Radio devices have no audio inputs or outputs. They have exactly -one tuner which in fact *is* an audio source, but this API associates -tuners with video inputs or outputs only, and radio devices have none of -these. [#f1]_ A connector on a TV card to loop back the received audio -signal to a sound card is not considered an audio output. - -Audio and video inputs and outputs are associated. Selecting a video -source also selects an audio source. This is most evident when the video -and audio source is a tuner. Further audio connectors can combine with -more than one video input or output. Assumed two composite video inputs -and two audio inputs exist, there may be up to four valid combinations. -The relation of video and audio connectors is defined in the -``audioset`` field of the respective struct -:c:type:`v4l2_input` or struct -:c:type:`v4l2_output`, where each bit represents the index -number, starting at zero, of one audio input or output. - -To learn about the number and attributes of the available inputs and -outputs applications can enumerate them with the -:ref:`VIDIOC_ENUMAUDIO` and -:ref:`VIDIOC_ENUMAUDOUT ` ioctl, respectively. -The struct :c:type:`v4l2_audio` returned by the -:ref:`VIDIOC_ENUMAUDIO` ioctl also contains signal -status information applicable when the current audio input is queried. - -The :ref:`VIDIOC_G_AUDIO ` and -:ref:`VIDIOC_G_AUDOUT ` ioctls report the current -audio input and output, respectively. - -.. note:: - - Note that, unlike :ref:`VIDIOC_G_INPUT ` and - :ref:`VIDIOC_G_OUTPUT ` these ioctls return a - structure as :ref:`VIDIOC_ENUMAUDIO` and - :ref:`VIDIOC_ENUMAUDOUT ` do, not just an index. - -To select an audio input and change its properties applications call the -:ref:`VIDIOC_S_AUDIO ` ioctl. To select an audio -output (which presently has no changeable properties) applications call -the :ref:`VIDIOC_S_AUDOUT ` ioctl. - -Drivers must implement all audio input ioctls when the device has -multiple selectable audio inputs, all audio output ioctls when the -device has multiple selectable audio outputs. When the device has any -audio inputs or outputs the driver must set the ``V4L2_CAP_AUDIO`` flag -in the struct :c:type:`v4l2_capability` returned by -the :ref:`VIDIOC_QUERYCAP` ioctl. - - -Example: Information about the current audio input -================================================== - -.. code-block:: c - - struct v4l2_audio audio; - - memset(&audio, 0, sizeof(audio)); - - if (-1 == ioctl(fd, VIDIOC_G_AUDIO, &audio)) { - perror("VIDIOC_G_AUDIO"); - exit(EXIT_FAILURE); - } - - printf("Current input: %s\\n", audio.name); - - -Example: Switching to the first audio input -=========================================== - -.. code-block:: c - - struct v4l2_audio audio; - - memset(&audio, 0, sizeof(audio)); /* clear audio.mode, audio.reserved */ - - audio.index = 0; - - if (-1 == ioctl(fd, VIDIOC_S_AUDIO, &audio)) { - perror("VIDIOC_S_AUDIO"); - exit(EXIT_FAILURE); - } - -.. [#f1] - Actually struct :c:type:`v4l2_audio` ought to have a - ``tuner`` field like struct :c:type:`v4l2_input`, not - only making the API more consistent but also permitting radio devices - with multiple tuners. diff --git a/Documentation/media/uapi/v4l/bayer.svg b/Documentation/media/uapi/v4l/bayer.svg deleted file mode 100644 index c5bf85103901..000000000000 --- a/Documentation/media/uapi/v4l/bayer.svg +++ /dev/null @@ -1,56 +0,0 @@ - - -image/svg+xmlB -G -G -R -BGGR -B -G -G -R -GBRG -B -G -G -R -RGGB -B -G -G -R -GRBG - diff --git a/Documentation/media/uapi/v4l/biblio.rst b/Documentation/media/uapi/v4l/biblio.rst deleted file mode 100644 index 8095f57d3d75..000000000000 --- a/Documentation/media/uapi/v4l/biblio.rst +++ /dev/null @@ -1,416 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -********** -References -********** - - -.. _cea608: - -CEA 608-E -========= - - -:title: CEA-608-E R-2014 "Line 21 Data Services" - -:author: Consumer Electronics Association (http://www.ce.org) - -.. _en300294: - -EN 300 294 -========== - - -:title: EN 300 294 "625-line television Wide Screen Signalling (WSS)" - -:author: European Telecommunication Standards Institute (http://www.etsi.org) - -.. _ets300231: - -ETS 300 231 -=========== - - -:title: ETS 300 231 "Specification of the domestic video Programme Delivery Control system (PDC)" - -:author: European Telecommunication Standards Institute (http://www.etsi.org) - -.. _ets300706: - -ETS 300 706 -=========== - - -:title: ETS 300 706 "Enhanced Teletext specification" - -:author: European Telecommunication Standards Institute (http://www.etsi.org) - -.. _mpeg2part1: - -ISO 13818-1 -=========== - - -:title: ITU-T Rec. H.222.0 | ISO/IEC 13818-1 "Information technology — Generic coding of moving pictures and associated audio information: Systems" - -:author: International Telecommunication Union (http://www.itu.ch), International Organisation for Standardisation (http://www.iso.ch) - -.. _mpeg2part2: - -ISO 13818-2 -=========== - - -:title: ITU-T Rec. H.262 | ISO/IEC 13818-2 "Information technology — Generic coding of moving pictures and associated audio information: Video" - -:author: International Telecommunication Union (http://www.itu.ch), International Organisation for Standardisation (http://www.iso.ch) - -.. _itu470: - -ITU BT.470 -========== - - -:title: ITU-R Recommendation BT.470-6 "Conventional Television Systems" - -:author: International Telecommunication Union (http://www.itu.ch) - -.. _itu601: - -ITU BT.601 -========== - - -:title: ITU-R Recommendation BT.601-5 "Studio Encoding Parameters of Digital Television for Standard 4:3 and Wide-Screen 16:9 Aspect Ratios" - -:author: International Telecommunication Union (http://www.itu.ch) - -.. _itu653: - -ITU BT.653 -========== - - -:title: ITU-R Recommendation BT.653-3 "Teletext systems" - -:author: International Telecommunication Union (http://www.itu.ch) - -.. _itu709: - -ITU BT.709 -========== - - -:title: ITU-R Recommendation BT.709-5 "Parameter values for the HDTV standards for production and international programme exchange" - -:author: International Telecommunication Union (http://www.itu.ch) - -.. _itu1119: - -ITU BT.1119 -=========== - - -:title: ITU-R Recommendation BT.1119 "625-line television Wide Screen Signalling (WSS)" - -:author: International Telecommunication Union (http://www.itu.ch) - -.. _h264: - -ITU-T Rec. H.264 Specification (04/2017 Edition) -================================================ - -:title: ITU-T Recommendation H.264 "Advanced Video Coding for Generic Audiovisual Services" - -:author: International Telecommunication Union (http://www.itu.ch) - -.. _hevc: - -ITU H.265/HEVC -============== - -:title: ITU-T Rec. H.265 | ISO/IEC 23008-2 "High Efficiency Video Coding" - -:author: International Telecommunication Union (http://www.itu.ch), International Organisation for Standardisation (http://www.iso.ch) - -.. _jfif: - -JFIF -==== - - -:title: JPEG File Interchange Format -:subtitle: Version 1.02 - -:author: Independent JPEG Group (http://www.ijg.org) - -.. _itu-t81: - -ITU-T.81 -======== - - -:title: ITU-T Recommendation T.81 "Information Technology — Digital Compression and Coding of Continous-Tone Still Images — Requirements and Guidelines" - -:author: International Telecommunication Union (http://www.itu.int) - -.. _w3c-jpeg-jfif: - -W3C JPEG JFIF -============= - - -:title: JPEG JFIF - -:author: The World Wide Web Consortium (http://www.w3.org) - -.. _smpte12m: - -SMPTE 12M -========= - - -:title: SMPTE 12M-1999 "Television, Audio and Film - Time and Control Code" - -:author: Society of Motion Picture and Television Engineers (http://www.smpte.org) - -.. _smpte170m: - -SMPTE 170M -========== - - -:title: SMPTE 170M-1999 "Television - Composite Analog Video Signal - NTSC for Studio Applications" - -:author: Society of Motion Picture and Television Engineers (http://www.smpte.org) - -.. _smpte240m: - -SMPTE 240M -========== - - -:title: SMPTE 240M-1999 "Television - Signal Parameters - 1125-Line High-Definition Production" - -:author: Society of Motion Picture and Television Engineers (http://www.smpte.org) - -.. _smpte431: - -SMPTE RP 431-2 -============== - - -:title: SMPTE RP 431-2:2011 "D-Cinema Quality - Reference Projector and Environment" - -:author: Society of Motion Picture and Television Engineers (http://www.smpte.org) - -.. _smpte2084: - -SMPTE ST 2084 -============= - - -:title: SMPTE ST 2084:2014 "High Dynamic Range Electro-Optical Transfer Function of Master Reference Displays" - -:author: Society of Motion Picture and Television Engineers (http://www.smpte.org) - -.. _srgb: - -sRGB -==== - - -:title: IEC 61966-2-1 ed1.0 "Multimedia systems and equipment - Colour measurement and management - Part 2-1: Colour management - Default RGB colour space - sRGB" - -:author: International Electrotechnical Commission (http://www.iec.ch) - -.. _sycc: - -sYCC -==== - - -:title: IEC 61966-2-1-am1 ed1.0 "Amendment 1 - Multimedia systems and equipment - Colour measurement and management - Part 2-1: Colour management - Default RGB colour space - sRGB" - -:author: International Electrotechnical Commission (http://www.iec.ch) - -.. _xvycc: - -xvYCC -===== - - -:title: IEC 61966-2-4 ed1.0 "Multimedia systems and equipment - Colour measurement and management - Part 2-4: Colour management - Extended-gamut YCC colour space for video applications - xvYCC" - -:author: International Electrotechnical Commission (http://www.iec.ch) - -.. _oprgb: - -opRGB -===== - - -:title: IEC 61966-2-5 "Multimedia systems and equipment - Colour measurement and management - Part 2-5: Colour management - Optional RGB colour space - opRGB" - -:author: International Electrotechnical Commission (http://www.iec.ch) - -.. _itu2020: - -ITU BT.2020 -=========== - - -:title: ITU-R Recommendation BT.2020 (08/2012) "Parameter values for ultra-high definition television systems for production and international programme exchange" - -:author: International Telecommunication Union (http://www.itu.ch) - -.. _tech3213: - -EBU Tech 3213 -============= - - -:title: E.B.U. Standard for Chromaticity Tolerances for Studio Monitors" - -:author: European Broadcast Union (http://www.ebu.ch) - -.. _iec62106: - -IEC 62106 -========= - - -:title: Specification of the radio data system (RDS) for VHF/FM sound broadcasting in the frequency range from 87,5 to 108,0 MHz - -:author: International Electrotechnical Commission (http://www.iec.ch) - -.. _nrsc4: - -NRSC-4-B -======== - - -:title: NRSC-4-B: United States RBDS Standard - -:author: National Radio Systems Committee (http://www.nrscstandards.org) - -.. _iso12232: - -ISO 12232:2006 -============== - - -:title: Photography — Digital still cameras — Determination of exposure index, ISO speed ratings, standard output sensitivity, and recommended exposure index - -:author: International Organization for Standardization (http://www.iso.org) - -.. _cea861: - -CEA-861-E -========= - - -:title: A DTV Profile for Uncompressed High Speed Digital Interfaces - -:author: Consumer Electronics Association (http://www.ce.org) - -.. _vesadmt: - -VESA DMT -======== - - -:title: VESA and Industry Standards and Guidelines for Computer Display Monitor Timing (DMT) - -:author: Video Electronics Standards Association (http://www.vesa.org) - -.. _vesaedid: - -EDID -==== - - -:title: VESA Enhanced Extended Display Identification Data Standard -:subtitle: Release A, Revision 2 - -:author: Video Electronics Standards Association (http://www.vesa.org) - -.. _hdcp: - -HDCP -==== - - -:title: High-bandwidth Digital Content Protection System -:subtitle: Revision 1.3 - -:author: Digital Content Protection LLC (http://www.digital-cp.com) - -.. _hdmi: - -HDMI -==== - - -:title: High-Definition Multimedia Interface -:subtitle: Specification Version 1.4a - -:author: HDMI Licensing LLC (http://www.hdmi.org) - -.. _hdmi2: - -HDMI2 -===== - -:title: High-Definition Multimedia Interface -:subtitle: Specification Version 2.0 - -:author: HDMI Licensing LLC (http://www.hdmi.org) - -.. _dp: - -DP -== - - -:title: VESA DisplayPort Standard -:subtitle: Version 1, Revision 2 - -:author: Video Electronics Standards Association (http://www.vesa.org) - -.. _poynton: - -poynton -======= - - -:title: Digital Video and HDTV, Algorithms and Interfaces - -:author: Charles Poynton - -.. _colimg: - -colimg -====== - - -:title: Color Imaging: Fundamentals and Applications - -:author: Erik Reinhard et al. - -.. _vp8: - -VP8 -=== - - -:title: RFC 6386: "VP8 Data Format and Decoding Guide" - -:author: J. Bankoski et al. diff --git a/Documentation/media/uapi/v4l/buffer.rst b/Documentation/media/uapi/v4l/buffer.rst deleted file mode 100644 index 3112300c2fa0..000000000000 --- a/Documentation/media/uapi/v4l/buffer.rst +++ /dev/null @@ -1,817 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _buffer: - -******* -Buffers -******* - -A buffer contains data exchanged by application and driver using one of -the Streaming I/O methods. In the multi-planar API, the data is held in -planes, while the buffer structure acts as a container for the planes. -Only pointers to buffers (planes) are exchanged, the data itself is not -copied. These pointers, together with meta-information like timestamps -or field parity, are stored in a struct :c:type:`v4l2_buffer`, -argument to the :ref:`VIDIOC_QUERYBUF`, -:ref:`VIDIOC_QBUF ` and -:ref:`VIDIOC_DQBUF ` ioctl. In the multi-planar API, -some plane-specific members of struct :c:type:`v4l2_buffer`, -such as pointers and sizes for each plane, are stored in struct -struct :c:type:`v4l2_plane` instead. In that case, struct -struct :c:type:`v4l2_buffer` contains an array of plane structures. - -Dequeued video buffers come with timestamps. The driver decides at which -part of the frame and with which clock the timestamp is taken. Please -see flags in the masks ``V4L2_BUF_FLAG_TIMESTAMP_MASK`` and -``V4L2_BUF_FLAG_TSTAMP_SRC_MASK`` in :ref:`buffer-flags`. These flags -are always valid and constant across all buffers during the whole video -stream. Changes in these flags may take place as a side effect of -:ref:`VIDIOC_S_INPUT ` or -:ref:`VIDIOC_S_OUTPUT ` however. The -``V4L2_BUF_FLAG_TIMESTAMP_COPY`` timestamp type which is used by e.g. on -mem-to-mem devices is an exception to the rule: the timestamp source -flags are copied from the OUTPUT video buffer to the CAPTURE video -buffer. - - -Interactions between formats, controls and buffers -================================================== - -V4L2 exposes parameters that influence the buffer size, or the way data is -laid out in the buffer. Those parameters are exposed through both formats and -controls. One example of such a control is the ``V4L2_CID_ROTATE`` control -that modifies the direction in which pixels are stored in the buffer, as well -as the buffer size when the selected format includes padding at the end of -lines. - -The set of information needed to interpret the content of a buffer (e.g. the -pixel format, the line stride, the tiling orientation or the rotation) is -collectively referred to in the rest of this section as the buffer layout. - -Controls that can modify the buffer layout shall set the -``V4L2_CTRL_FLAG_MODIFY_LAYOUT`` flag. - -Modifying formats or controls that influence the buffer size or layout require -the stream to be stopped. Any attempt at such a modification while the stream -is active shall cause the ioctl setting the format or the control to return -the ``EBUSY`` error code. In that case drivers shall also set the -``V4L2_CTRL_FLAG_GRABBED`` flag when calling -:c:func:`VIDIOC_QUERYCTRL` or :c:func:`VIDIOC_QUERY_EXT_CTRL` for such a -control while the stream is active. - -.. note:: - - The :c:func:`VIDIOC_S_SELECTION` ioctl can, depending on the hardware (for - instance if the device doesn't include a scaler), modify the format in - addition to the selection rectangle. Similarly, the - :c:func:`VIDIOC_S_INPUT`, :c:func:`VIDIOC_S_OUTPUT`, :c:func:`VIDIOC_S_STD` - and :c:func:`VIDIOC_S_DV_TIMINGS` ioctls can also modify the format and - selection rectangles. When those ioctls result in a buffer size or layout - change, drivers shall handle that condition as they would handle it in the - :c:func:`VIDIOC_S_FMT` ioctl in all cases described in this section. - -Controls that only influence the buffer layout can be modified at any time -when the stream is stopped. As they don't influence the buffer size, no -special handling is needed to synchronize those controls with buffer -allocation and the ``V4L2_CTRL_FLAG_GRABBED`` flag is cleared once the -stream is stopped. - -Formats and controls that influence the buffer size interact with buffer -allocation. The simplest way to handle this is for drivers to always require -buffers to be reallocated in order to change those formats or controls. In -that case, to perform such changes, userspace applications shall first stop -the video stream with the :c:func:`VIDIOC_STREAMOFF` ioctl if it is running -and free all buffers with the :c:func:`VIDIOC_REQBUFS` ioctl if they are -allocated. After freeing all buffers the ``V4L2_CTRL_FLAG_GRABBED`` flag -for controls is cleared. The format or controls can then be modified, and -buffers shall then be reallocated and the stream restarted. A typical ioctl -sequence is - - #. VIDIOC_STREAMOFF - #. VIDIOC_REQBUFS(0) - #. VIDIOC_S_EXT_CTRLS - #. VIDIOC_S_FMT - #. VIDIOC_REQBUFS(n) - #. VIDIOC_QBUF - #. VIDIOC_STREAMON - -The second :c:func:`VIDIOC_REQBUFS` call will take the new format and control -value into account to compute the buffer size to allocate. Applications can -also retrieve the size by calling the :c:func:`VIDIOC_G_FMT` ioctl if needed. - -.. note:: - - The API doesn't mandate the above order for control (3.) and format (4.) - changes. Format and controls can be set in a different order, or even - interleaved, depending on the device and use case. For instance some - controls might behave differently for different pixel formats, in which - case the format might need to be set first. - -When reallocation is required, any attempt to modify format or controls that -influences the buffer size while buffers are allocated shall cause the format -or control set ioctl to return the ``EBUSY`` error. Any attempt to queue a -buffer too small for the current format or controls shall cause the -:c:func:`VIDIOC_QBUF` ioctl to return a ``EINVAL`` error. - -Buffer reallocation is an expensive operation. To avoid that cost, drivers can -(and are encouraged to) allow format or controls that influence the buffer -size to be changed with buffers allocated. In that case, a typical ioctl -sequence to modify format and controls is - - #. VIDIOC_STREAMOFF - #. VIDIOC_S_EXT_CTRLS - #. VIDIOC_S_FMT - #. VIDIOC_QBUF - #. VIDIOC_STREAMON - -For this sequence to operate correctly, queued buffers need to be large enough -for the new format or controls. Drivers shall return a ``ENOSPC`` error in -response to format change (:c:func:`VIDIOC_S_FMT`) or control changes -(:c:func:`VIDIOC_S_CTRL` or :c:func:`VIDIOC_S_EXT_CTRLS`) if buffers too small -for the new format are currently queued. As a simplification, drivers are -allowed to return a ``EBUSY`` error from these ioctls if any buffer is -currently queued, without checking the queued buffers sizes. - -Additionally, drivers shall return a ``EINVAL`` error from the -:c:func:`VIDIOC_QBUF` ioctl if the buffer being queued is too small for the -current format or controls. Together, these requirements ensure that queued -buffers will always be large enough for the configured format and controls. - -Userspace applications can query the buffer size required for a given format -and controls by first setting the desired control values and then trying the -desired format. The :c:func:`VIDIOC_TRY_FMT` ioctl will return the required -buffer size. - - #. VIDIOC_S_EXT_CTRLS(x) - #. VIDIOC_TRY_FMT() - #. VIDIOC_S_EXT_CTRLS(y) - #. VIDIOC_TRY_FMT() - -The :c:func:`VIDIOC_CREATE_BUFS` ioctl can then be used to allocate buffers -based on the queried sizes (for instance by allocating a set of buffers large -enough for all the desired formats and controls, or by allocating separate set -of appropriately sized buffers for each use case). - - -.. c:type:: v4l2_buffer - -struct v4l2_buffer -================== - -.. tabularcolumns:: |p{2.8cm}|p{2.5cm}|p{1.6cm}|p{10.2cm}| - -.. cssclass:: longtable - -.. flat-table:: struct v4l2_buffer - :header-rows: 0 - :stub-columns: 0 - :widths: 1 2 10 - - * - __u32 - - ``index`` - - Number of the buffer, set by the application except when calling - :ref:`VIDIOC_DQBUF `, then it is set by the - driver. This field can range from zero to the number of buffers - allocated with the :ref:`VIDIOC_REQBUFS` ioctl - (struct :c:type:`v4l2_requestbuffers` - ``count``), plus any buffers allocated with - :ref:`VIDIOC_CREATE_BUFS` minus one. - * - __u32 - - ``type`` - - Type of the buffer, same as struct - :c:type:`v4l2_format` ``type`` or struct - :c:type:`v4l2_requestbuffers` ``type``, set - by the application. See :c:type:`v4l2_buf_type` - * - __u32 - - ``bytesused`` - - The number of bytes occupied by the data in the buffer. It depends - on the negotiated data format and may change with each buffer for - compressed variable size data like JPEG images. Drivers must set - this field when ``type`` refers to a capture stream, applications - when it refers to an output stream. If the application sets this - to 0 for an output stream, then ``bytesused`` will be set to the - size of the buffer (see the ``length`` field of this struct) by - the driver. For multiplanar formats this field is ignored and the - ``planes`` pointer is used instead. - * - __u32 - - ``flags`` - - Flags set by the application or driver, see :ref:`buffer-flags`. - * - __u32 - - ``field`` - - Indicates the field order of the image in the buffer, see - :c:type:`v4l2_field`. This field is not used when the buffer - contains VBI data. Drivers must set it when ``type`` refers to a - capture stream, applications when it refers to an output stream. - * - struct timeval - - ``timestamp`` - - For capture streams this is time when the first data byte was - captured, as returned by the :c:func:`clock_gettime()` function - for the relevant clock id; see ``V4L2_BUF_FLAG_TIMESTAMP_*`` in - :ref:`buffer-flags`. For output streams the driver stores the - time at which the last data byte was actually sent out in the - ``timestamp`` field. This permits applications to monitor the - drift between the video and system clock. For output streams that - use ``V4L2_BUF_FLAG_TIMESTAMP_COPY`` the application has to fill - in the timestamp which will be copied by the driver to the capture - stream. - * - struct :c:type:`v4l2_timecode` - - ``timecode`` - - When the ``V4L2_BUF_FLAG_TIMECODE`` flag is set in ``flags``, this - structure contains a frame timecode. In - :c:type:`V4L2_FIELD_ALTERNATE ` mode the top and - bottom field contain the same timecode. Timecodes are intended to - help video editing and are typically recorded on video tapes, but - also embedded in compressed formats like MPEG. This field is - independent of the ``timestamp`` and ``sequence`` fields. - * - __u32 - - ``sequence`` - - Set by the driver, counting the frames (not fields!) in sequence. - This field is set for both input and output devices. - * - :cspan:`2` - - In :c:type:`V4L2_FIELD_ALTERNATE ` mode the top and - bottom field have the same sequence number. The count starts at - zero and includes dropped or repeated frames. A dropped frame was - received by an input device but could not be stored due to lack of - free buffer space. A repeated frame was displayed again by an - output device because the application did not pass new data in - time. - - .. note:: - - This may count the frames received e.g. over USB, without - taking into account the frames dropped by the remote hardware due - to limited compression throughput or bus bandwidth. These devices - identify by not enumerating any video standards, see - :ref:`standard`. - - * - __u32 - - ``memory`` - - This field must be set by applications and/or drivers in - accordance with the selected I/O method. See :c:type:`v4l2_memory` - * - union { - - ``m`` - * - __u32 - - ``offset`` - - For the single-planar API and when ``memory`` is - ``V4L2_MEMORY_MMAP`` this is the offset of the buffer from the - start of the device memory. The value is returned by the driver - and apart of serving as parameter to the - :ref:`mmap() ` function not useful for applications. - See :ref:`mmap` for details - * - unsigned long - - ``userptr`` - - For the single-planar API and when ``memory`` is - ``V4L2_MEMORY_USERPTR`` this is a pointer to the buffer (casted to - unsigned long type) in virtual memory, set by the application. See - :ref:`userp` for details. - * - struct v4l2_plane - - ``*planes`` - - When using the multi-planar API, contains a userspace pointer to - an array of struct :c:type:`v4l2_plane`. The size of - the array should be put in the ``length`` field of this - struct :c:type:`v4l2_buffer` structure. - * - int - - ``fd`` - - For the single-plane API and when ``memory`` is - ``V4L2_MEMORY_DMABUF`` this is the file descriptor associated with - a DMABUF buffer. - * - } - - - * - __u32 - - ``length`` - - Size of the buffer (not the payload) in bytes for the - single-planar API. This is set by the driver based on the calls to - :ref:`VIDIOC_REQBUFS` and/or - :ref:`VIDIOC_CREATE_BUFS`. For the - multi-planar API the application sets this to the number of - elements in the ``planes`` array. The driver will fill in the - actual number of valid elements in that array. - * - __u32 - - ``reserved2`` - - A place holder for future extensions. Drivers and applications - must set this to 0. - * - __u32 - - ``request_fd`` - - The file descriptor of the request to queue the buffer to. If the flag - ``V4L2_BUF_FLAG_REQUEST_FD`` is set, then the buffer will be - queued to this request. If the flag is not set, then this field will - be ignored. - - The ``V4L2_BUF_FLAG_REQUEST_FD`` flag and this field are only used by - :ref:`ioctl VIDIOC_QBUF ` and ignored by other ioctls that - take a :c:type:`v4l2_buffer` as argument. - - Applications should not set ``V4L2_BUF_FLAG_REQUEST_FD`` for any ioctls - other than :ref:`VIDIOC_QBUF `. - - If the device does not support requests, then ``EBADR`` will be returned. - If requests are supported but an invalid request file descriptor is - given, then ``EINVAL`` will be returned. - - - -.. c:type:: v4l2_plane - -struct v4l2_plane -================= - -.. tabularcolumns:: |p{3.5cm}|p{3.5cm}|p{3.5cm}|p{7.0cm}| - -.. cssclass:: longtable - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - :widths: 1 1 2 - - * - __u32 - - ``bytesused`` - - The number of bytes occupied by data in the plane (its payload). - Drivers must set this field when ``type`` refers to a capture - stream, applications when it refers to an output stream. If the - application sets this to 0 for an output stream, then - ``bytesused`` will be set to the size of the plane (see the - ``length`` field of this struct) by the driver. - - .. note:: - - Note that the actual image data starts at ``data_offset`` - which may not be 0. - * - __u32 - - ``length`` - - Size in bytes of the plane (not its payload). This is set by the - driver based on the calls to - :ref:`VIDIOC_REQBUFS` and/or - :ref:`VIDIOC_CREATE_BUFS`. - * - union { - - ``m`` - * - __u32 - - ``mem_offset`` - - When the memory type in the containing struct - :c:type:`v4l2_buffer` is ``V4L2_MEMORY_MMAP``, this - is the value that should be passed to :ref:`mmap() `, - similar to the ``offset`` field in struct - :c:type:`v4l2_buffer`. - * - unsigned long - - ``userptr`` - - When the memory type in the containing struct - :c:type:`v4l2_buffer` is ``V4L2_MEMORY_USERPTR``, - this is a userspace pointer to the memory allocated for this plane - by an application. - * - int - - ``fd`` - - When the memory type in the containing struct - :c:type:`v4l2_buffer` is ``V4L2_MEMORY_DMABUF``, - this is a file descriptor associated with a DMABUF buffer, similar - to the ``fd`` field in struct :c:type:`v4l2_buffer`. - * - } - - - * - __u32 - - ``data_offset`` - - Offset in bytes to video data in the plane. Drivers must set this - field when ``type`` refers to a capture stream, applications when - it refers to an output stream. - - .. note:: - - That data_offset is included in ``bytesused``. So the - size of the image in the plane is ``bytesused``-``data_offset`` - at offset ``data_offset`` from the start of the plane. - * - __u32 - - ``reserved[11]`` - - Reserved for future use. Should be zeroed by drivers and - applications. - - - -.. c:type:: v4l2_buf_type - -enum v4l2_buf_type -================== - -.. cssclass:: longtable - -.. tabularcolumns:: |p{7.8cm}|p{0.6cm}|p{9.1cm}| - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - :widths: 4 1 9 - - * - ``V4L2_BUF_TYPE_VIDEO_CAPTURE`` - - 1 - - Buffer of a single-planar video capture stream, see - :ref:`capture`. - * - ``V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE`` - - 9 - - Buffer of a multi-planar video capture stream, see - :ref:`capture`. - * - ``V4L2_BUF_TYPE_VIDEO_OUTPUT`` - - 2 - - Buffer of a single-planar video output stream, see - :ref:`output`. - * - ``V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE`` - - 10 - - Buffer of a multi-planar video output stream, see :ref:`output`. - * - ``V4L2_BUF_TYPE_VIDEO_OVERLAY`` - - 3 - - Buffer for video overlay, see :ref:`overlay`. - * - ``V4L2_BUF_TYPE_VBI_CAPTURE`` - - 4 - - Buffer of a raw VBI capture stream, see :ref:`raw-vbi`. - * - ``V4L2_BUF_TYPE_VBI_OUTPUT`` - - 5 - - Buffer of a raw VBI output stream, see :ref:`raw-vbi`. - * - ``V4L2_BUF_TYPE_SLICED_VBI_CAPTURE`` - - 6 - - Buffer of a sliced VBI capture stream, see :ref:`sliced`. - * - ``V4L2_BUF_TYPE_SLICED_VBI_OUTPUT`` - - 7 - - Buffer of a sliced VBI output stream, see :ref:`sliced`. - * - ``V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY`` - - 8 - - Buffer for video output overlay (OSD), see :ref:`osd`. - * - ``V4L2_BUF_TYPE_SDR_CAPTURE`` - - 11 - - Buffer for Software Defined Radio (SDR) capture stream, see - :ref:`sdr`. - * - ``V4L2_BUF_TYPE_SDR_OUTPUT`` - - 12 - - Buffer for Software Defined Radio (SDR) output stream, see - :ref:`sdr`. - * - ``V4L2_BUF_TYPE_META_CAPTURE`` - - 13 - - Buffer for metadata capture, see :ref:`metadata`. - * - ``V4L2_BUF_TYPE_META_OUTPUT`` - - 14 - - Buffer for metadata output, see :ref:`metadata`. - - - -.. _buffer-flags: - -Buffer Flags -============ - -.. raw:: latex - - \small - -.. tabularcolumns:: |p{7.0cm}|p{2.1cm}|p{8.4cm}| - -.. cssclass:: longtable - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - :widths: 3 1 4 - - * .. _`V4L2-BUF-FLAG-MAPPED`: - - - ``V4L2_BUF_FLAG_MAPPED`` - - 0x00000001 - - The buffer resides in device memory and has been mapped into the - application's address space, see :ref:`mmap` for details. - Drivers set or clear this flag when the - :ref:`VIDIOC_QUERYBUF`, - :ref:`VIDIOC_QBUF` or - :ref:`VIDIOC_DQBUF ` ioctl is called. Set by the - driver. - * .. _`V4L2-BUF-FLAG-QUEUED`: - - - ``V4L2_BUF_FLAG_QUEUED`` - - 0x00000002 - - Internally drivers maintain two buffer queues, an incoming and - outgoing queue. When this flag is set, the buffer is currently on - the incoming queue. It automatically moves to the outgoing queue - after the buffer has been filled (capture devices) or displayed - (output devices). Drivers set or clear this flag when the - ``VIDIOC_QUERYBUF`` ioctl is called. After (successful) calling - the ``VIDIOC_QBUF``\ ioctl it is always set and after - ``VIDIOC_DQBUF`` always cleared. - * .. _`V4L2-BUF-FLAG-DONE`: - - - ``V4L2_BUF_FLAG_DONE`` - - 0x00000004 - - When this flag is set, the buffer is currently on the outgoing - queue, ready to be dequeued from the driver. Drivers set or clear - this flag when the ``VIDIOC_QUERYBUF`` ioctl is called. After - calling the ``VIDIOC_QBUF`` or ``VIDIOC_DQBUF`` it is always - cleared. Of course a buffer cannot be on both queues at the same - time, the ``V4L2_BUF_FLAG_QUEUED`` and ``V4L2_BUF_FLAG_DONE`` flag - are mutually exclusive. They can be both cleared however, then the - buffer is in "dequeued" state, in the application domain so to - say. - * .. _`V4L2-BUF-FLAG-ERROR`: - - - ``V4L2_BUF_FLAG_ERROR`` - - 0x00000040 - - When this flag is set, the buffer has been dequeued successfully, - although the data might have been corrupted. This is recoverable, - streaming may continue as normal and the buffer may be reused - normally. Drivers set this flag when the ``VIDIOC_DQBUF`` ioctl is - called. - * .. _`V4L2-BUF-FLAG-IN-REQUEST`: - - - ``V4L2_BUF_FLAG_IN_REQUEST`` - - 0x00000080 - - This buffer is part of a request that hasn't been queued yet. - * .. _`V4L2-BUF-FLAG-KEYFRAME`: - - - ``V4L2_BUF_FLAG_KEYFRAME`` - - 0x00000008 - - Drivers set or clear this flag when calling the ``VIDIOC_DQBUF`` - ioctl. It may be set by video capture devices when the buffer - contains a compressed image which is a key frame (or field), i. e. - can be decompressed on its own. Also known as an I-frame. - Applications can set this bit when ``type`` refers to an output - stream. - * .. _`V4L2-BUF-FLAG-PFRAME`: - - - ``V4L2_BUF_FLAG_PFRAME`` - - 0x00000010 - - Similar to ``V4L2_BUF_FLAG_KEYFRAME`` this flags predicted frames - or fields which contain only differences to a previous key frame. - Applications can set this bit when ``type`` refers to an output - stream. - * .. _`V4L2-BUF-FLAG-BFRAME`: - - - ``V4L2_BUF_FLAG_BFRAME`` - - 0x00000020 - - Similar to ``V4L2_BUF_FLAG_KEYFRAME`` this flags a bi-directional - predicted frame or field which contains only the differences - between the current frame and both the preceding and following key - frames to specify its content. Applications can set this bit when - ``type`` refers to an output stream. - * .. _`V4L2-BUF-FLAG-TIMECODE`: - - - ``V4L2_BUF_FLAG_TIMECODE`` - - 0x00000100 - - The ``timecode`` field is valid. Drivers set or clear this flag - when the ``VIDIOC_DQBUF`` ioctl is called. Applications can set - this bit and the corresponding ``timecode`` structure when - ``type`` refers to an output stream. - * .. _`V4L2-BUF-FLAG-PREPARED`: - - - ``V4L2_BUF_FLAG_PREPARED`` - - 0x00000400 - - The buffer has been prepared for I/O and can be queued by the - application. Drivers set or clear this flag when the - :ref:`VIDIOC_QUERYBUF`, - :ref:`VIDIOC_PREPARE_BUF `, - :ref:`VIDIOC_QBUF` or - :ref:`VIDIOC_DQBUF ` ioctl is called. - * .. _`V4L2-BUF-FLAG-NO-CACHE-INVALIDATE`: - - - ``V4L2_BUF_FLAG_NO_CACHE_INVALIDATE`` - - 0x00000800 - - Caches do not have to be invalidated for this buffer. Typically - applications shall use this flag if the data captured in the - buffer is not going to be touched by the CPU, instead the buffer - will, probably, be passed on to a DMA-capable hardware unit for - further processing or output. - * .. _`V4L2-BUF-FLAG-NO-CACHE-CLEAN`: - - - ``V4L2_BUF_FLAG_NO_CACHE_CLEAN`` - - 0x00001000 - - Caches do not have to be cleaned for this buffer. Typically - applications shall use this flag for output buffers if the data in - this buffer has not been created by the CPU but by some - DMA-capable unit, in which case caches have not been used. - * .. _`V4L2-BUF-FLAG-M2M-HOLD-CAPTURE-BUF`: - - - ``V4L2_BUF_FLAG_M2M_HOLD_CAPTURE_BUF`` - - 0x00000200 - - Only valid if ``V4L2_BUF_CAP_SUPPORTS_M2M_HOLD_CAPTURE_BUF`` is - set. It is typically used with stateless decoders where multiple - output buffers each decode to a slice of the decoded frame. - Applications can set this flag when queueing the output buffer - to prevent the driver from dequeueing the capture buffer after - the output buffer has been decoded (i.e. the capture buffer is - 'held'). If the timestamp of this output buffer differs from that - of the previous output buffer, then that indicates the start of a - new frame and the previously held capture buffer is dequeued. - * .. _`V4L2-BUF-FLAG-LAST`: - - - ``V4L2_BUF_FLAG_LAST`` - - 0x00100000 - - Last buffer produced by the hardware. mem2mem codec drivers set - this flag on the capture queue for the last buffer when the - :ref:`VIDIOC_QUERYBUF` or - :ref:`VIDIOC_DQBUF ` ioctl is called. Due to - hardware limitations, the last buffer may be empty. In this case - the driver will set the ``bytesused`` field to 0, regardless of - the format. Any Any subsequent call to the - :ref:`VIDIOC_DQBUF ` ioctl will not block anymore, - but return an ``EPIPE`` error code. - * .. _`V4L2-BUF-FLAG-REQUEST-FD`: - - - ``V4L2_BUF_FLAG_REQUEST_FD`` - - 0x00800000 - - The ``request_fd`` field contains a valid file descriptor. - * .. _`V4L2-BUF-FLAG-TIMESTAMP-MASK`: - - - ``V4L2_BUF_FLAG_TIMESTAMP_MASK`` - - 0x0000e000 - - Mask for timestamp types below. To test the timestamp type, mask - out bits not belonging to timestamp type by performing a logical - and operation with buffer flags and timestamp mask. - * .. _`V4L2-BUF-FLAG-TIMESTAMP-UNKNOWN`: - - - ``V4L2_BUF_FLAG_TIMESTAMP_UNKNOWN`` - - 0x00000000 - - Unknown timestamp type. This type is used by drivers before Linux - 3.9 and may be either monotonic (see below) or realtime (wall - clock). Monotonic clock has been favoured in embedded systems - whereas most of the drivers use the realtime clock. Either kinds - of timestamps are available in user space via - :c:func:`clock_gettime` using clock IDs ``CLOCK_MONOTONIC`` - and ``CLOCK_REALTIME``, respectively. - * .. _`V4L2-BUF-FLAG-TIMESTAMP-MONOTONIC`: - - - ``V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC`` - - 0x00002000 - - The buffer timestamp has been taken from the ``CLOCK_MONOTONIC`` - clock. To access the same clock outside V4L2, use - :c:func:`clock_gettime`. - * .. _`V4L2-BUF-FLAG-TIMESTAMP-COPY`: - - - ``V4L2_BUF_FLAG_TIMESTAMP_COPY`` - - 0x00004000 - - The CAPTURE buffer timestamp has been taken from the corresponding - OUTPUT buffer. This flag applies only to mem2mem devices. - * .. _`V4L2-BUF-FLAG-TSTAMP-SRC-MASK`: - - - ``V4L2_BUF_FLAG_TSTAMP_SRC_MASK`` - - 0x00070000 - - Mask for timestamp sources below. The timestamp source defines the - point of time the timestamp is taken in relation to the frame. - Logical 'and' operation between the ``flags`` field and - ``V4L2_BUF_FLAG_TSTAMP_SRC_MASK`` produces the value of the - timestamp source. Applications must set the timestamp source when - ``type`` refers to an output stream and - ``V4L2_BUF_FLAG_TIMESTAMP_COPY`` is set. - * .. _`V4L2-BUF-FLAG-TSTAMP-SRC-EOF`: - - - ``V4L2_BUF_FLAG_TSTAMP_SRC_EOF`` - - 0x00000000 - - End Of Frame. The buffer timestamp has been taken when the last - pixel of the frame has been received or the last pixel of the - frame has been transmitted. In practice, software generated - timestamps will typically be read from the clock a small amount of - time after the last pixel has been received or transmitten, - depending on the system and other activity in it. - * .. _`V4L2-BUF-FLAG-TSTAMP-SRC-SOE`: - - - ``V4L2_BUF_FLAG_TSTAMP_SRC_SOE`` - - 0x00010000 - - Start Of Exposure. The buffer timestamp has been taken when the - exposure of the frame has begun. This is only valid for the - ``V4L2_BUF_TYPE_VIDEO_CAPTURE`` buffer type. - -.. raw:: latex - - \normalsize - - -.. c:type:: v4l2_memory - -enum v4l2_memory -================ - -.. tabularcolumns:: |p{5.0cm}|p{0.8cm}|p{11.7cm}| - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - :widths: 3 1 4 - - * - ``V4L2_MEMORY_MMAP`` - - 1 - - The buffer is used for :ref:`memory mapping ` I/O. - * - ``V4L2_MEMORY_USERPTR`` - - 2 - - The buffer is used for :ref:`user pointer ` I/O. - * - ``V4L2_MEMORY_OVERLAY`` - - 3 - - [to do] - * - ``V4L2_MEMORY_DMABUF`` - - 4 - - The buffer is used for :ref:`DMA shared buffer ` I/O. - - - -Timecodes -========= - -The :c:type:`v4l2_buffer_timecode` structure is designed to hold a -:ref:`smpte12m` or similar timecode. -(struct :c:type:`timeval` timestamps are stored in the struct -:c:type:`v4l2_buffer` ``timestamp`` field.) - - -.. c:type:: v4l2_timecode - -struct v4l2_timecode --------------------- - -.. tabularcolumns:: |p{1.4cm}|p{2.8cm}|p{12.3cm}| - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - :widths: 1 1 2 - - * - __u32 - - ``type`` - - Frame rate the timecodes are based on, see :ref:`timecode-type`. - * - __u32 - - ``flags`` - - Timecode flags, see :ref:`timecode-flags`. - * - __u8 - - ``frames`` - - Frame count, 0 ... 23/24/29/49/59, depending on the type of - timecode. - * - __u8 - - ``seconds`` - - Seconds count, 0 ... 59. This is a binary, not BCD number. - * - __u8 - - ``minutes`` - - Minutes count, 0 ... 59. This is a binary, not BCD number. - * - __u8 - - ``hours`` - - Hours count, 0 ... 29. This is a binary, not BCD number. - * - __u8 - - ``userbits``\ [4] - - The "user group" bits from the timecode. - - - -.. _timecode-type: - -Timecode Types --------------- - -.. tabularcolumns:: |p{5.6cm}|p{0.8cm}|p{11.1cm}| - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - :widths: 3 1 4 - - * - ``V4L2_TC_TYPE_24FPS`` - - 1 - - 24 frames per second, i. e. film. - * - ``V4L2_TC_TYPE_25FPS`` - - 2 - - 25 frames per second, i. e. PAL or SECAM video. - * - ``V4L2_TC_TYPE_30FPS`` - - 3 - - 30 frames per second, i. e. NTSC video. - * - ``V4L2_TC_TYPE_50FPS`` - - 4 - - - * - ``V4L2_TC_TYPE_60FPS`` - - 5 - - - - - -.. _timecode-flags: - -Timecode Flags --------------- - -.. tabularcolumns:: |p{6.6cm}|p{1.4cm}|p{9.5cm}| - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - :widths: 3 1 4 - - * - ``V4L2_TC_FLAG_DROPFRAME`` - - 0x0001 - - Indicates "drop frame" semantics for counting frames in 29.97 fps - material. When set, frame numbers 0 and 1 at the start of each - minute, except minutes 0, 10, 20, 30, 40, 50 are omitted from the - count. - * - ``V4L2_TC_FLAG_COLORFRAME`` - - 0x0002 - - The "color frame" flag. - * - ``V4L2_TC_USERBITS_field`` - - 0x000C - - Field mask for the "binary group flags". - * - ``V4L2_TC_USERBITS_USERDEFINED`` - - 0x0000 - - Unspecified format. - * - ``V4L2_TC_USERBITS_8BITCHARS`` - - 0x0008 - - 8-bit ISO characters. diff --git a/Documentation/media/uapi/v4l/capture-example.rst b/Documentation/media/uapi/v4l/capture-example.rst deleted file mode 100644 index 130ca47ef796..000000000000 --- a/Documentation/media/uapi/v4l/capture-example.rst +++ /dev/null @@ -1,20 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _capture-example: - -********************* -Video Capture Example -********************* - - -.. toctree:: - :maxdepth: 1 - - capture.c diff --git a/Documentation/media/uapi/v4l/capture.c.rst b/Documentation/media/uapi/v4l/capture.c.rst deleted file mode 100644 index b4652c2351f2..000000000000 --- a/Documentation/media/uapi/v4l/capture.c.rst +++ /dev/null @@ -1,671 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -file: media/v4l/capture.c -========================= - -.. code-block:: c - - /* - * V4L2 video capture example - * - * This program can be used and distributed without restrictions. - * - * This program is provided with the V4L2 API - * see https://linuxtv.org/docs.php for more information - */ - - #include - #include - #include - #include - - #include /* getopt_long() */ - - #include /* low-level i/o */ - #include - #include - #include - #include - #include - #include - #include - - #include - - #define CLEAR(x) memset(&(x), 0, sizeof(x)) - - enum io_method { - IO_METHOD_READ, - IO_METHOD_MMAP, - IO_METHOD_USERPTR, - }; - - struct buffer { - void *start; - size_t length; - }; - - static char *dev_name; - static enum io_method io = IO_METHOD_MMAP; - static int fd = -1; - struct buffer *buffers; - static unsigned int n_buffers; - static int out_buf; - static int force_format; - static int frame_count = 70; - - static void errno_exit(const char *s) - { - fprintf(stderr, "%s error %d, %s\\n", s, errno, strerror(errno)); - exit(EXIT_FAILURE); - } - - static int xioctl(int fh, int request, void *arg) - { - int r; - - do { - r = ioctl(fh, request, arg); - } while (-1 == r && EINTR == errno); - - return r; - } - - static void process_image(const void *p, int size) - { - if (out_buf) - fwrite(p, size, 1, stdout); - - fflush(stderr); - fprintf(stderr, "."); - fflush(stdout); - } - - static int read_frame(void) - { - struct v4l2_buffer buf; - unsigned int i; - - switch (io) { - case IO_METHOD_READ: - if (-1 == read(fd, buffers[0].start, buffers[0].length)) { - switch (errno) { - case EAGAIN: - return 0; - - case EIO: - /* Could ignore EIO, see spec. */ - - /* fall through */ - - default: - errno_exit("read"); - } - } - - process_image(buffers[0].start, buffers[0].length); - break; - - case IO_METHOD_MMAP: - CLEAR(buf); - - buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - buf.memory = V4L2_MEMORY_MMAP; - - if (-1 == xioctl(fd, VIDIOC_DQBUF, &buf)) { - switch (errno) { - case EAGAIN: - return 0; - - case EIO: - /* Could ignore EIO, see spec. */ - - /* fall through */ - - default: - errno_exit("VIDIOC_DQBUF"); - } - } - - assert(buf.index < n_buffers); - - process_image(buffers[buf.index].start, buf.bytesused); - - if (-1 == xioctl(fd, VIDIOC_QBUF, &buf)) - errno_exit("VIDIOC_QBUF"); - break; - - case IO_METHOD_USERPTR: - CLEAR(buf); - - buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - buf.memory = V4L2_MEMORY_USERPTR; - - if (-1 == xioctl(fd, VIDIOC_DQBUF, &buf)) { - switch (errno) { - case EAGAIN: - return 0; - - case EIO: - /* Could ignore EIO, see spec. */ - - /* fall through */ - - default: - errno_exit("VIDIOC_DQBUF"); - } - } - - for (i = 0; i < n_buffers; ++i) - if (buf.m.userptr == (unsigned long)buffers[i].start - && buf.length == buffers[i].length) - break; - - assert(i < n_buffers); - - process_image((void *)buf.m.userptr, buf.bytesused); - - if (-1 == xioctl(fd, VIDIOC_QBUF, &buf)) - errno_exit("VIDIOC_QBUF"); - break; - } - - return 1; - } - - static void mainloop(void) - { - unsigned int count; - - count = frame_count; - - while (count-- > 0) { - for (;;) { - fd_set fds; - struct timeval tv; - int r; - - FD_ZERO(&fds); - FD_SET(fd, &fds); - - /* Timeout. */ - tv.tv_sec = 2; - tv.tv_usec = 0; - - r = select(fd + 1, &fds, NULL, NULL, &tv); - - if (-1 == r) { - if (EINTR == errno) - continue; - errno_exit("select"); - } - - if (0 == r) { - fprintf(stderr, "select timeout\\n"); - exit(EXIT_FAILURE); - } - - if (read_frame()) - break; - /* EAGAIN - continue select loop. */ - } - } - } - - static void stop_capturing(void) - { - enum v4l2_buf_type type; - - switch (io) { - case IO_METHOD_READ: - /* Nothing to do. */ - break; - - case IO_METHOD_MMAP: - case IO_METHOD_USERPTR: - type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - if (-1 == xioctl(fd, VIDIOC_STREAMOFF, &type)) - errno_exit("VIDIOC_STREAMOFF"); - break; - } - } - - static void start_capturing(void) - { - unsigned int i; - enum v4l2_buf_type type; - - switch (io) { - case IO_METHOD_READ: - /* Nothing to do. */ - break; - - case IO_METHOD_MMAP: - for (i = 0; i < n_buffers; ++i) { - struct v4l2_buffer buf; - - CLEAR(buf); - buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - buf.memory = V4L2_MEMORY_MMAP; - buf.index = i; - - if (-1 == xioctl(fd, VIDIOC_QBUF, &buf)) - errno_exit("VIDIOC_QBUF"); - } - type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - if (-1 == xioctl(fd, VIDIOC_STREAMON, &type)) - errno_exit("VIDIOC_STREAMON"); - break; - - case IO_METHOD_USERPTR: - for (i = 0; i < n_buffers; ++i) { - struct v4l2_buffer buf; - - CLEAR(buf); - buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - buf.memory = V4L2_MEMORY_USERPTR; - buf.index = i; - buf.m.userptr = (unsigned long)buffers[i].start; - buf.length = buffers[i].length; - - if (-1 == xioctl(fd, VIDIOC_QBUF, &buf)) - errno_exit("VIDIOC_QBUF"); - } - type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - if (-1 == xioctl(fd, VIDIOC_STREAMON, &type)) - errno_exit("VIDIOC_STREAMON"); - break; - } - } - - static void uninit_device(void) - { - unsigned int i; - - switch (io) { - case IO_METHOD_READ: - free(buffers[0].start); - break; - - case IO_METHOD_MMAP: - for (i = 0; i < n_buffers; ++i) - if (-1 == munmap(buffers[i].start, buffers[i].length)) - errno_exit("munmap"); - break; - - case IO_METHOD_USERPTR: - for (i = 0; i < n_buffers; ++i) - free(buffers[i].start); - break; - } - - free(buffers); - } - - static void init_read(unsigned int buffer_size) - { - buffers = calloc(1, sizeof(*buffers)); - - if (!buffers) { - fprintf(stderr, "Out of memory\\n"); - exit(EXIT_FAILURE); - } - - buffers[0].length = buffer_size; - buffers[0].start = malloc(buffer_size); - - if (!buffers[0].start) { - fprintf(stderr, "Out of memory\\n"); - exit(EXIT_FAILURE); - } - } - - static void init_mmap(void) - { - struct v4l2_requestbuffers req; - - CLEAR(req); - - req.count = 4; - req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - req.memory = V4L2_MEMORY_MMAP; - - if (-1 == xioctl(fd, VIDIOC_REQBUFS, &req)) { - if (EINVAL == errno) { - fprintf(stderr, "%s does not support " - "memory mappingn", dev_name); - exit(EXIT_FAILURE); - } else { - errno_exit("VIDIOC_REQBUFS"); - } - } - - if (req.count < 2) { - fprintf(stderr, "Insufficient buffer memory on %s\\n", - dev_name); - exit(EXIT_FAILURE); - } - - buffers = calloc(req.count, sizeof(*buffers)); - - if (!buffers) { - fprintf(stderr, "Out of memory\\n"); - exit(EXIT_FAILURE); - } - - for (n_buffers = 0; n_buffers < req.count; ++n_buffers) { - struct v4l2_buffer buf; - - CLEAR(buf); - - buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - buf.memory = V4L2_MEMORY_MMAP; - buf.index = n_buffers; - - if (-1 == xioctl(fd, VIDIOC_QUERYBUF, &buf)) - errno_exit("VIDIOC_QUERYBUF"); - - buffers[n_buffers].length = buf.length; - buffers[n_buffers].start = - mmap(NULL /* start anywhere */, - buf.length, - PROT_READ | PROT_WRITE /* required */, - MAP_SHARED /* recommended */, - fd, buf.m.offset); - - if (MAP_FAILED == buffers[n_buffers].start) - errno_exit("mmap"); - } - } - - static void init_userp(unsigned int buffer_size) - { - struct v4l2_requestbuffers req; - - CLEAR(req); - - req.count = 4; - req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - req.memory = V4L2_MEMORY_USERPTR; - - if (-1 == xioctl(fd, VIDIOC_REQBUFS, &req)) { - if (EINVAL == errno) { - fprintf(stderr, "%s does not support " - "user pointer i/on", dev_name); - exit(EXIT_FAILURE); - } else { - errno_exit("VIDIOC_REQBUFS"); - } - } - - buffers = calloc(4, sizeof(*buffers)); - - if (!buffers) { - fprintf(stderr, "Out of memory\\n"); - exit(EXIT_FAILURE); - } - - for (n_buffers = 0; n_buffers < 4; ++n_buffers) { - buffers[n_buffers].length = buffer_size; - buffers[n_buffers].start = malloc(buffer_size); - - if (!buffers[n_buffers].start) { - fprintf(stderr, "Out of memory\\n"); - exit(EXIT_FAILURE); - } - } - } - - static void init_device(void) - { - struct v4l2_capability cap; - struct v4l2_cropcap cropcap; - struct v4l2_crop crop; - struct v4l2_format fmt; - unsigned int min; - - if (-1 == xioctl(fd, VIDIOC_QUERYCAP, &cap)) { - if (EINVAL == errno) { - fprintf(stderr, "%s is no V4L2 device\\n", - dev_name); - exit(EXIT_FAILURE); - } else { - errno_exit("VIDIOC_QUERYCAP"); - } - } - - if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) { - fprintf(stderr, "%s is no video capture device\\n", - dev_name); - exit(EXIT_FAILURE); - } - - switch (io) { - case IO_METHOD_READ: - if (!(cap.capabilities & V4L2_CAP_READWRITE)) { - fprintf(stderr, "%s does not support read i/o\\n", - dev_name); - exit(EXIT_FAILURE); - } - break; - - case IO_METHOD_MMAP: - case IO_METHOD_USERPTR: - if (!(cap.capabilities & V4L2_CAP_STREAMING)) { - fprintf(stderr, "%s does not support streaming i/o\\n", - dev_name); - exit(EXIT_FAILURE); - } - break; - } - - - /* Select video input, video standard and tune here. */ - - - CLEAR(cropcap); - - cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - - if (0 == xioctl(fd, VIDIOC_CROPCAP, &cropcap)) { - crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - crop.c = cropcap.defrect; /* reset to default */ - - if (-1 == xioctl(fd, VIDIOC_S_CROP, &crop)) { - switch (errno) { - case EINVAL: - /* Cropping not supported. */ - break; - default: - /* Errors ignored. */ - break; - } - } - } else { - /* Errors ignored. */ - } - - - CLEAR(fmt); - - fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - if (force_format) { - fmt.fmt.pix.width = 640; - fmt.fmt.pix.height = 480; - fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; - fmt.fmt.pix.field = V4L2_FIELD_INTERLACED; - - if (-1 == xioctl(fd, VIDIOC_S_FMT, &fmt)) - errno_exit("VIDIOC_S_FMT"); - - /* Note VIDIOC_S_FMT may change width and height. */ - } else { - /* Preserve original settings as set by v4l2-ctl for example */ - if (-1 == xioctl(fd, VIDIOC_G_FMT, &fmt)) - errno_exit("VIDIOC_G_FMT"); - } - - /* Buggy driver paranoia. */ - min = fmt.fmt.pix.width * 2; - if (fmt.fmt.pix.bytesperline < min) - fmt.fmt.pix.bytesperline = min; - min = fmt.fmt.pix.bytesperline * fmt.fmt.pix.height; - if (fmt.fmt.pix.sizeimage < min) - fmt.fmt.pix.sizeimage = min; - - switch (io) { - case IO_METHOD_READ: - init_read(fmt.fmt.pix.sizeimage); - break; - - case IO_METHOD_MMAP: - init_mmap(); - break; - - case IO_METHOD_USERPTR: - init_userp(fmt.fmt.pix.sizeimage); - break; - } - } - - static void close_device(void) - { - if (-1 == close(fd)) - errno_exit("close"); - - fd = -1; - } - - static void open_device(void) - { - struct stat st; - - if (-1 == stat(dev_name, &st)) { - fprintf(stderr, "Cannot identify '%s': %d, %s\\n", - dev_name, errno, strerror(errno)); - exit(EXIT_FAILURE); - } - - if (!S_ISCHR(st.st_mode)) { - fprintf(stderr, "%s is no devicen", dev_name); - exit(EXIT_FAILURE); - } - - fd = open(dev_name, O_RDWR /* required */ | O_NONBLOCK, 0); - - if (-1 == fd) { - fprintf(stderr, "Cannot open '%s': %d, %s\\n", - dev_name, errno, strerror(errno)); - exit(EXIT_FAILURE); - } - } - - static void usage(FILE *fp, int argc, char **argv) - { - fprintf(fp, - "Usage: %s [options]\\n\\n" - "Version 1.3\\n" - "Options:\\n" - "-d | --device name Video device name [%s]n" - "-h | --help Print this messagen" - "-m | --mmap Use memory mapped buffers [default]n" - "-r | --read Use read() callsn" - "-u | --userp Use application allocated buffersn" - "-o | --output Outputs stream to stdoutn" - "-f | --format Force format to 640x480 YUYVn" - "-c | --count Number of frames to grab [%i]n" - "", - argv[0], dev_name, frame_count); - } - - static const char short_options[] = "d:hmruofc:"; - - static const struct option - long_options[] = { - { "device", required_argument, NULL, 'd' }, - { "help", no_argument, NULL, 'h' }, - { "mmap", no_argument, NULL, 'm' }, - { "read", no_argument, NULL, 'r' }, - { "userp", no_argument, NULL, 'u' }, - { "output", no_argument, NULL, 'o' }, - { "format", no_argument, NULL, 'f' }, - { "count", required_argument, NULL, 'c' }, - { 0, 0, 0, 0 } - }; - - int main(int argc, char **argv) - { - dev_name = "/dev/video0"; - - for (;;) { - int idx; - int c; - - c = getopt_long(argc, argv, - short_options, long_options, &idx); - - if (-1 == c) - break; - - switch (c) { - case 0: /* getopt_long() flag */ - break; - - case 'd': - dev_name = optarg; - break; - - case 'h': - usage(stdout, argc, argv); - exit(EXIT_SUCCESS); - - case 'm': - io = IO_METHOD_MMAP; - break; - - case 'r': - io = IO_METHOD_READ; - break; - - case 'u': - io = IO_METHOD_USERPTR; - break; - - case 'o': - out_buf++; - break; - - case 'f': - force_format++; - break; - - case 'c': - errno = 0; - frame_count = strtol(optarg, NULL, 0); - if (errno) - errno_exit(optarg); - break; - - default: - usage(stderr, argc, argv); - exit(EXIT_FAILURE); - } - } - - open_device(); - init_device(); - start_capturing(); - mainloop(); - stop_capturing(); - uninit_device(); - close_device(); - fprintf(stderr, "\\n"); - return 0; - } diff --git a/Documentation/media/uapi/v4l/colorspaces-defs.rst b/Documentation/media/uapi/v4l/colorspaces-defs.rst deleted file mode 100644 index e122bbe3d799..000000000000 --- a/Documentation/media/uapi/v4l/colorspaces-defs.rst +++ /dev/null @@ -1,183 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -**************************** -Defining Colorspaces in V4L2 -**************************** - -In V4L2 colorspaces are defined by four values. The first is the -colorspace identifier (enum :c:type:`v4l2_colorspace`) -which defines the chromaticities, the default transfer function, the -default Y'CbCr encoding and the default quantization method. The second -is the transfer function identifier (enum -:c:type:`v4l2_xfer_func`) to specify non-standard -transfer functions. The third is the Y'CbCr encoding identifier (enum -:c:type:`v4l2_ycbcr_encoding`) to specify -non-standard Y'CbCr encodings and the fourth is the quantization -identifier (enum :c:type:`v4l2_quantization`) to -specify non-standard quantization methods. Most of the time only the -colorspace field of struct :c:type:`v4l2_pix_format` -or struct :c:type:`v4l2_pix_format_mplane` -needs to be filled in. - -.. _hsv-colorspace: - -On :ref:`HSV formats ` the *Hue* is defined as the angle on -the cylindrical color representation. Usually this angle is measured in -degrees, i.e. 0-360. When we map this angle value into 8 bits, there are -two basic ways to do it: Divide the angular value by 2 (0-179), or use the -whole range, 0-255, dividing the angular value by 1.41. The enum -:c:type:`v4l2_hsv_encoding` specifies which encoding is used. - -.. note:: The default R'G'B' quantization is full range for all - colorspaces except for BT.2020 which uses limited range R'G'B' - quantization. - -.. tabularcolumns:: |p{6.7cm}|p{10.8cm}| - -.. c:type:: v4l2_colorspace - -.. flat-table:: V4L2 Colorspaces - :header-rows: 1 - :stub-columns: 0 - - * - Identifier - - Details - * - ``V4L2_COLORSPACE_DEFAULT`` - - The default colorspace. This can be used by applications to let - the driver fill in the colorspace. - * - ``V4L2_COLORSPACE_SMPTE170M`` - - See :ref:`col-smpte-170m`. - * - ``V4L2_COLORSPACE_REC709`` - - See :ref:`col-rec709`. - * - ``V4L2_COLORSPACE_SRGB`` - - See :ref:`col-srgb`. - * - ``V4L2_COLORSPACE_OPRGB`` - - See :ref:`col-oprgb`. - * - ``V4L2_COLORSPACE_BT2020`` - - See :ref:`col-bt2020`. - * - ``V4L2_COLORSPACE_DCI_P3`` - - See :ref:`col-dcip3`. - * - ``V4L2_COLORSPACE_SMPTE240M`` - - See :ref:`col-smpte-240m`. - * - ``V4L2_COLORSPACE_470_SYSTEM_M`` - - See :ref:`col-sysm`. - * - ``V4L2_COLORSPACE_470_SYSTEM_BG`` - - See :ref:`col-sysbg`. - * - ``V4L2_COLORSPACE_JPEG`` - - See :ref:`col-jpeg`. - * - ``V4L2_COLORSPACE_RAW`` - - The raw colorspace. This is used for raw image capture where the - image is minimally processed and is using the internal colorspace - of the device. The software that processes an image using this - 'colorspace' will have to know the internals of the capture - device. - - - -.. c:type:: v4l2_xfer_func - -.. tabularcolumns:: |p{5.5cm}|p{12.0cm}| - -.. flat-table:: V4L2 Transfer Function - :header-rows: 1 - :stub-columns: 0 - - * - Identifier - - Details - * - ``V4L2_XFER_FUNC_DEFAULT`` - - Use the default transfer function as defined by the colorspace. - * - ``V4L2_XFER_FUNC_709`` - - Use the Rec. 709 transfer function. - * - ``V4L2_XFER_FUNC_SRGB`` - - Use the sRGB transfer function. - * - ``V4L2_XFER_FUNC_OPRGB`` - - Use the opRGB transfer function. - * - ``V4L2_XFER_FUNC_SMPTE240M`` - - Use the SMPTE 240M transfer function. - * - ``V4L2_XFER_FUNC_NONE`` - - Do not use a transfer function (i.e. use linear RGB values). - * - ``V4L2_XFER_FUNC_DCI_P3`` - - Use the DCI-P3 transfer function. - * - ``V4L2_XFER_FUNC_SMPTE2084`` - - Use the SMPTE 2084 transfer function. See :ref:`xf-smpte-2084`. - - - -.. c:type:: v4l2_ycbcr_encoding - -.. tabularcolumns:: |p{7.2cm}|p{10.3cm}| - -.. flat-table:: V4L2 Y'CbCr Encodings - :header-rows: 1 - :stub-columns: 0 - - * - Identifier - - Details - * - ``V4L2_YCBCR_ENC_DEFAULT`` - - Use the default Y'CbCr encoding as defined by the colorspace. - * - ``V4L2_YCBCR_ENC_601`` - - Use the BT.601 Y'CbCr encoding. - * - ``V4L2_YCBCR_ENC_709`` - - Use the Rec. 709 Y'CbCr encoding. - * - ``V4L2_YCBCR_ENC_XV601`` - - Use the extended gamut xvYCC BT.601 encoding. - * - ``V4L2_YCBCR_ENC_XV709`` - - Use the extended gamut xvYCC Rec. 709 encoding. - * - ``V4L2_YCBCR_ENC_BT2020`` - - Use the default non-constant luminance BT.2020 Y'CbCr encoding. - * - ``V4L2_YCBCR_ENC_BT2020_CONST_LUM`` - - Use the constant luminance BT.2020 Yc'CbcCrc encoding. - * - ``V4L2_YCBCR_ENC_SMPTE_240M`` - - Use the SMPTE 240M Y'CbCr encoding. - - - -.. c:type:: v4l2_hsv_encoding - -.. tabularcolumns:: |p{6.5cm}|p{11.0cm}| - -.. flat-table:: V4L2 HSV Encodings - :header-rows: 1 - :stub-columns: 0 - - * - Identifier - - Details - * - ``V4L2_HSV_ENC_180`` - - For the Hue, each LSB is two degrees. - * - ``V4L2_HSV_ENC_256`` - - For the Hue, the 360 degrees are mapped into 8 bits, i.e. each - LSB is roughly 1.41 degrees. - - - -.. c:type:: v4l2_quantization - -.. tabularcolumns:: |p{6.5cm}|p{11.0cm}| - -.. flat-table:: V4L2 Quantization Methods - :header-rows: 1 - :stub-columns: 0 - - * - Identifier - - Details - * - ``V4L2_QUANTIZATION_DEFAULT`` - - Use the default quantization encoding as defined by the - colorspace. This is always full range for R'G'B' (except for the - BT.2020 colorspace) and HSV. It is usually limited range for Y'CbCr. - * - ``V4L2_QUANTIZATION_FULL_RANGE`` - - Use the full range quantization encoding. I.e. the range [0…1] is - mapped to [0…255] (with possible clipping to [1…254] to avoid the - 0x00 and 0xff values). Cb and Cr are mapped from [-0.5…0.5] to - [0…255] (with possible clipping to [1…254] to avoid the 0x00 and - 0xff values). - * - ``V4L2_QUANTIZATION_LIM_RANGE`` - - Use the limited range quantization encoding. I.e. the range [0…1] - is mapped to [16…235]. Cb and Cr are mapped from [-0.5…0.5] to - [16…240]. diff --git a/Documentation/media/uapi/v4l/colorspaces-details.rst b/Documentation/media/uapi/v4l/colorspaces-details.rst deleted file mode 100644 index 8b0ba3668101..000000000000 --- a/Documentation/media/uapi/v4l/colorspaces-details.rst +++ /dev/null @@ -1,813 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -******************************** -Detailed Colorspace Descriptions -******************************** - - -.. _col-smpte-170m: - -Colorspace SMPTE 170M (V4L2_COLORSPACE_SMPTE170M) -================================================= - -The :ref:`smpte170m` standard defines the colorspace used by NTSC and -PAL and by SDTV in general. The default transfer function is -``V4L2_XFER_FUNC_709``. The default Y'CbCr encoding is -``V4L2_YCBCR_ENC_601``. The default Y'CbCr quantization is limited -range. The chromaticities of the primary colors and the white reference -are: - - - -.. tabularcolumns:: |p{4.4cm}|p{4.4cm}|p{8.7cm}| - -.. flat-table:: SMPTE 170M Chromaticities - :header-rows: 1 - :stub-columns: 0 - :widths: 1 1 2 - - * - Color - - x - - y - * - Red - - 0.630 - - 0.340 - * - Green - - 0.310 - - 0.595 - * - Blue - - 0.155 - - 0.070 - * - White Reference (D65) - - 0.3127 - - 0.3290 - - -The red, green and blue chromaticities are also often referred to as the -SMPTE C set, so this colorspace is sometimes called SMPTE C as well. - -The transfer function defined for SMPTE 170M is the same as the one -defined in Rec. 709. - -.. math:: - - L' = -1.099(-L)^{0.45} + 0.099 \text{, for } L \le-0.018 - - L' = 4.5L \text{, for } -0.018 < L < 0.018 - - L' = 1.099L^{0.45} - 0.099 \text{, for } L \ge 0.018 - -Inverse Transfer function: - -.. math:: - - L = -\left( \frac{L' - 0.099}{-1.099} \right) ^{\frac{1}{0.45}} \text{, for } L' \le -0.081 - - L = \frac{L'}{4.5} \text{, for } -0.081 < L' < 0.081 - - L = \left(\frac{L' + 0.099}{1.099}\right)^{\frac{1}{0.45} } \text{, for } L' \ge 0.081 - -The luminance (Y') and color difference (Cb and Cr) are obtained with -the following ``V4L2_YCBCR_ENC_601`` encoding: - -.. math:: - - Y' = 0.2990R' + 0.5870G' + 0.1140B' - - Cb = -0.1687R' - 0.3313G' + 0.5B' - - Cr = 0.5R' - 0.4187G' - 0.0813B' - -Y' is clamped to the range [0…1] and Cb and Cr are clamped to the range -[-0.5…0.5]. This conversion to Y'CbCr is identical to the one defined in -the :ref:`itu601` standard and this colorspace is sometimes called -BT.601 as well, even though BT.601 does not mention any color primaries. - -The default quantization is limited range, but full range is possible -although rarely seen. - - -.. _col-rec709: - -Colorspace Rec. 709 (V4L2_COLORSPACE_REC709) -============================================ - -The :ref:`itu709` standard defines the colorspace used by HDTV in -general. The default transfer function is ``V4L2_XFER_FUNC_709``. The -default Y'CbCr encoding is ``V4L2_YCBCR_ENC_709``. The default Y'CbCr -quantization is limited range. The chromaticities of the primary colors -and the white reference are: - - - -.. tabularcolumns:: |p{4.4cm}|p{4.4cm}|p{8.7cm}| - -.. flat-table:: Rec. 709 Chromaticities - :header-rows: 1 - :stub-columns: 0 - :widths: 1 1 2 - - * - Color - - x - - y - * - Red - - 0.640 - - 0.330 - * - Green - - 0.300 - - 0.600 - * - Blue - - 0.150 - - 0.060 - * - White Reference (D65) - - 0.3127 - - 0.3290 - - -The full name of this standard is Rec. ITU-R BT.709-5. - -Transfer function. Normally L is in the range [0…1], but for the -extended gamut xvYCC encoding values outside that range are allowed. - -.. math:: - - L' = -1.099(-L)^{0.45} + 0.099 \text{, for } L \le -0.018 - - L' = 4.5L \text{, for } -0.018 < L < 0.018 - - L' = 1.099L^{0.45} - 0.099 \text{, for } L \ge 0.018 - -Inverse Transfer function: - -.. math:: - - L = -\left( \frac{L' - 0.099}{-1.099} \right)^\frac{1}{0.45} \text{, for } L' \le -0.081 - - L = \frac{L'}{4.5}\text{, for } -0.081 < L' < 0.081 - - L = \left(\frac{L' + 0.099}{1.099}\right)^{\frac{1}{0.45} } \text{, for } L' \ge 0.081 - -The luminance (Y') and color difference (Cb and Cr) are obtained with -the following ``V4L2_YCBCR_ENC_709`` encoding: - -.. math:: - - Y' = 0.2126R' + 0.7152G' + 0.0722B' - - Cb = -0.1146R' - 0.3854G' + 0.5B' - - Cr = 0.5R' - 0.4542G' - 0.0458B' - -Y' is clamped to the range [0…1] and Cb and Cr are clamped to the range -[-0.5…0.5]. - -The default quantization is limited range, but full range is possible -although rarely seen. - -The ``V4L2_YCBCR_ENC_709`` encoding described above is the default for -this colorspace, but it can be overridden with ``V4L2_YCBCR_ENC_601``, -in which case the BT.601 Y'CbCr encoding is used. - -Two additional extended gamut Y'CbCr encodings are also possible with -this colorspace: - -The xvYCC 709 encoding (``V4L2_YCBCR_ENC_XV709``, :ref:`xvycc`) is -similar to the Rec. 709 encoding, but it allows for R', G' and B' values -that are outside the range [0…1]. The resulting Y', Cb and Cr values are -scaled and offset according to the limited range formula: - -.. math:: - - Y' = \frac{219}{256} * (0.2126R' + 0.7152G' + 0.0722B') + \frac{16}{256} - - Cb = \frac{224}{256} * (-0.1146R' - 0.3854G' + 0.5B') - - Cr = \frac{224}{256} * (0.5R' - 0.4542G' - 0.0458B') - -The xvYCC 601 encoding (``V4L2_YCBCR_ENC_XV601``, :ref:`xvycc`) is -similar to the BT.601 encoding, but it allows for R', G' and B' values -that are outside the range [0…1]. The resulting Y', Cb and Cr values are -scaled and offset according to the limited range formula: - -.. math:: - - Y' = \frac{219}{256} * (0.2990R' + 0.5870G' + 0.1140B') + \frac{16}{256} - - Cb = \frac{224}{256} * (-0.1687R' - 0.3313G' + 0.5B') - - Cr = \frac{224}{256} * (0.5R' - 0.4187G' - 0.0813B') - -Y' is clamped to the range [0…1] and Cb and Cr are clamped to the range -[-0.5…0.5] and quantized without further scaling or offsets. -The non-standard xvYCC 709 or xvYCC 601 encodings can be -used by selecting ``V4L2_YCBCR_ENC_XV709`` or ``V4L2_YCBCR_ENC_XV601``. -As seen by the xvYCC formulas these encodings always use limited range quantization, -there is no full range variant. The whole point of these extended gamut encodings -is that values outside the limited range are still valid, although they -map to R', G' and B' values outside the [0…1] range and are therefore outside -the Rec. 709 colorspace gamut. - - -.. _col-srgb: - -Colorspace sRGB (V4L2_COLORSPACE_SRGB) -====================================== - -The :ref:`srgb` standard defines the colorspace used by most webcams -and computer graphics. The default transfer function is -``V4L2_XFER_FUNC_SRGB``. The default Y'CbCr encoding is -``V4L2_YCBCR_ENC_601``. The default Y'CbCr quantization is limited range. - -Note that the :ref:`sycc` standard specifies full range quantization, -however all current capture hardware supported by the kernel convert -R'G'B' to limited range Y'CbCr. So choosing full range as the default -would break how applications interpret the quantization range. - -The chromaticities of the primary colors and the white reference are: - - - -.. tabularcolumns:: |p{4.4cm}|p{4.4cm}|p{8.7cm}| - -.. flat-table:: sRGB Chromaticities - :header-rows: 1 - :stub-columns: 0 - :widths: 1 1 2 - - * - Color - - x - - y - * - Red - - 0.640 - - 0.330 - * - Green - - 0.300 - - 0.600 - * - Blue - - 0.150 - - 0.060 - * - White Reference (D65) - - 0.3127 - - 0.3290 - - -These chromaticities are identical to the Rec. 709 colorspace. - -Transfer function. Note that negative values for L are only used by the -Y'CbCr conversion. - -.. math:: - - L' = -1.055(-L)^{\frac{1}{2.4} } + 0.055\text{, for }L < -0.0031308 - - L' = 12.92L\text{, for }-0.0031308 \le L \le 0.0031308 - - L' = 1.055L ^{\frac{1}{2.4} } - 0.055\text{, for }0.0031308 < L \le 1 - -Inverse Transfer function: - -.. math:: - - L = -((-L' + 0.055) / 1.055) ^{2.4}\text{, for }L' < -0.04045 - - L = L' / 12.92\text{, for }-0.04045 \le L' \le 0.04045 - - L = ((L' + 0.055) / 1.055) ^{2.4}\text{, for }L' > 0.04045 - -The luminance (Y') and color difference (Cb and Cr) are obtained with -the following ``V4L2_YCBCR_ENC_601`` encoding as defined by :ref:`sycc`: - -.. math:: - - Y' = 0.2990R' + 0.5870G' + 0.1140B' - - Cb = -0.1687R' - 0.3313G' + 0.5B' - - Cr = 0.5R' - 0.4187G' - 0.0813B' - -Y' is clamped to the range [0…1] and Cb and Cr are clamped to the range -[-0.5…0.5]. This transform is identical to one defined in SMPTE -170M/BT.601. The Y'CbCr quantization is limited range. - - -.. _col-oprgb: - -Colorspace opRGB (V4L2_COLORSPACE_OPRGB) -=============================================== - -The :ref:`oprgb` standard defines the colorspace used by computer -graphics that use the opRGB colorspace. The default transfer function is -``V4L2_XFER_FUNC_OPRGB``. The default Y'CbCr encoding is -``V4L2_YCBCR_ENC_601``. The default Y'CbCr quantization is limited -range. - -Note that the :ref:`oprgb` standard specifies full range quantization, -however all current capture hardware supported by the kernel convert -R'G'B' to limited range Y'CbCr. So choosing full range as the default -would break how applications interpret the quantization range. - -The chromaticities of the primary colors and the white reference are: - - -.. tabularcolumns:: |p{4.4cm}|p{4.4cm}|p{8.7cm}| - -.. flat-table:: opRGB Chromaticities - :header-rows: 1 - :stub-columns: 0 - :widths: 1 1 2 - - * - Color - - x - - y - * - Red - - 0.6400 - - 0.3300 - * - Green - - 0.2100 - - 0.7100 - * - Blue - - 0.1500 - - 0.0600 - * - White Reference (D65) - - 0.3127 - - 0.3290 - - - -Transfer function: - -.. math:: - - L' = L ^{\frac{1}{2.19921875}} - -Inverse Transfer function: - -.. math:: - - L = L'^{(2.19921875)} - -The luminance (Y') and color difference (Cb and Cr) are obtained with -the following ``V4L2_YCBCR_ENC_601`` encoding: - -.. math:: - - Y' = 0.2990R' + 0.5870G' + 0.1140B' - - Cb = -0.1687R' - 0.3313G' + 0.5B' - - Cr = 0.5R' - 0.4187G' - 0.0813B' - -Y' is clamped to the range [0…1] and Cb and Cr are clamped to the range -[-0.5…0.5]. This transform is identical to one defined in SMPTE -170M/BT.601. The Y'CbCr quantization is limited range. - - -.. _col-bt2020: - -Colorspace BT.2020 (V4L2_COLORSPACE_BT2020) -=========================================== - -The :ref:`itu2020` standard defines the colorspace used by Ultra-high -definition television (UHDTV). The default transfer function is -``V4L2_XFER_FUNC_709``. The default Y'CbCr encoding is -``V4L2_YCBCR_ENC_BT2020``. The default R'G'B' quantization is limited -range (!), and so is the default Y'CbCr quantization. The chromaticities -of the primary colors and the white reference are: - - - -.. tabularcolumns:: |p{4.4cm}|p{4.4cm}|p{8.7cm}| - -.. flat-table:: BT.2020 Chromaticities - :header-rows: 1 - :stub-columns: 0 - :widths: 1 1 2 - - * - Color - - x - - y - * - Red - - 0.708 - - 0.292 - * - Green - - 0.170 - - 0.797 - * - Blue - - 0.131 - - 0.046 - * - White Reference (D65) - - 0.3127 - - 0.3290 - - - -Transfer function (same as Rec. 709): - -.. math:: - - L' = 4.5L\text{, for }0 \le L < 0.018 - - L' = 1.099L ^{0.45} - 0.099\text{, for } 0.018 \le L \le 1 - -Inverse Transfer function: - -.. math:: - - L = L' / 4.5\text{, for } L' < 0.081 - - L = \left( \frac{L' + 0.099}{1.099}\right) ^{\frac{1}{0.45} }\text{, for } L' \ge 0.081 - -Please note that while Rec. 709 is defined as the default transfer function -by the :ref:`itu2020` standard, in practice this colorspace is often used -with the :ref:`xf-smpte-2084`. In particular Ultra HD Blu-ray discs use -this combination. - -The luminance (Y') and color difference (Cb and Cr) are obtained with -the following ``V4L2_YCBCR_ENC_BT2020`` encoding: - -.. math:: - - Y' = 0.2627R' + 0.6780G' + 0.0593B' - - Cb = -0.1396R' - 0.3604G' + 0.5B' - - Cr = 0.5R' - 0.4598G' - 0.0402B' - -Y' is clamped to the range [0…1] and Cb and Cr are clamped to the range -[-0.5…0.5]. The Y'CbCr quantization is limited range. - -There is also an alternate constant luminance R'G'B' to Yc'CbcCrc -(``V4L2_YCBCR_ENC_BT2020_CONST_LUM``) encoding: - -Luma: - -.. math:: - :nowrap: - - \begin{align*} - Yc' = (0.2627R + 0.6780G + 0.0593B)'& \\ - B' - Yc' \le 0:& \\ - &Cbc = (B' - Yc') / 1.9404 \\ - B' - Yc' > 0: & \\ - &Cbc = (B' - Yc') / 1.5816 \\ - R' - Yc' \le 0:& \\ - &Crc = (R' - Y') / 1.7184 \\ - R' - Yc' > 0:& \\ - &Crc = (R' - Y') / 0.9936 - \end{align*} - -Yc' is clamped to the range [0…1] and Cbc and Crc are clamped to the -range [-0.5…0.5]. The Yc'CbcCrc quantization is limited range. - - -.. _col-dcip3: - -Colorspace DCI-P3 (V4L2_COLORSPACE_DCI_P3) -========================================== - -The :ref:`smpte431` standard defines the colorspace used by cinema -projectors that use the DCI-P3 colorspace. The default transfer function -is ``V4L2_XFER_FUNC_DCI_P3``. The default Y'CbCr encoding is -``V4L2_YCBCR_ENC_709``. The default Y'CbCr quantization is limited range. - -.. note:: - - Note that this colorspace standard does not specify a - Y'CbCr encoding since it is not meant to be encoded to Y'CbCr. So this - default Y'CbCr encoding was picked because it is the HDTV encoding. - -The chromaticities of the primary colors and the white reference are: - - - -.. tabularcolumns:: |p{4.4cm}|p{4.4cm}|p{8.7cm}| - -.. flat-table:: DCI-P3 Chromaticities - :header-rows: 1 - :stub-columns: 0 - :widths: 1 1 2 - - * - Color - - x - - y - * - Red - - 0.6800 - - 0.3200 - * - Green - - 0.2650 - - 0.6900 - * - Blue - - 0.1500 - - 0.0600 - * - White Reference - - 0.3140 - - 0.3510 - - - -Transfer function: - -.. math:: - - L' = L^{\frac{1}{2.6}} - -Inverse Transfer function: - -.. math:: - - L = L'^{(2.6)} - -Y'CbCr encoding is not specified. V4L2 defaults to Rec. 709. - - -.. _col-smpte-240m: - -Colorspace SMPTE 240M (V4L2_COLORSPACE_SMPTE240M) -================================================= - -The :ref:`smpte240m` standard was an interim standard used during the -early days of HDTV (1988-1998). It has been superseded by Rec. 709. The -default transfer function is ``V4L2_XFER_FUNC_SMPTE240M``. The default -Y'CbCr encoding is ``V4L2_YCBCR_ENC_SMPTE240M``. The default Y'CbCr -quantization is limited range. The chromaticities of the primary colors -and the white reference are: - - - -.. tabularcolumns:: |p{4.4cm}|p{4.4cm}|p{8.7cm}| - -.. flat-table:: SMPTE 240M Chromaticities - :header-rows: 1 - :stub-columns: 0 - :widths: 1 1 2 - - * - Color - - x - - y - * - Red - - 0.630 - - 0.340 - * - Green - - 0.310 - - 0.595 - * - Blue - - 0.155 - - 0.070 - * - White Reference (D65) - - 0.3127 - - 0.3290 - - -These chromaticities are identical to the SMPTE 170M colorspace. - -Transfer function: - -.. math:: - - L' = 4L\text{, for } 0 \le L < 0.0228 - - L' = 1.1115L ^{0.45} - 0.1115\text{, for } 0.0228 \le L \le 1 - -Inverse Transfer function: - -.. math:: - - L = \frac{L'}{4}\text{, for } 0 \le L' < 0.0913 - - L = \left( \frac{L' + 0.1115}{1.1115}\right) ^{\frac{1}{0.45} }\text{, for } L' \ge 0.0913 - -The luminance (Y') and color difference (Cb and Cr) are obtained with -the following ``V4L2_YCBCR_ENC_SMPTE240M`` encoding: - -.. math:: - - Y' = 0.2122R' + 0.7013G' + 0.0865B' - - Cb = -0.1161R' - 0.3839G' + 0.5B' - - Cr = 0.5R' - 0.4451G' - 0.0549B' - -Y' is clamped to the range [0…1] and Cb and Cr are clamped to the -range [-0.5…0.5]. The Y'CbCr quantization is limited range. - - -.. _col-sysm: - -Colorspace NTSC 1953 (V4L2_COLORSPACE_470_SYSTEM_M) -=================================================== - -This standard defines the colorspace used by NTSC in 1953. In practice -this colorspace is obsolete and SMPTE 170M should be used instead. The -default transfer function is ``V4L2_XFER_FUNC_709``. The default Y'CbCr -encoding is ``V4L2_YCBCR_ENC_601``. The default Y'CbCr quantization is -limited range. The chromaticities of the primary colors and the white -reference are: - - - -.. tabularcolumns:: |p{4.4cm}|p{4.4cm}|p{8.7cm}| - -.. flat-table:: NTSC 1953 Chromaticities - :header-rows: 1 - :stub-columns: 0 - :widths: 1 1 2 - - * - Color - - x - - y - * - Red - - 0.67 - - 0.33 - * - Green - - 0.21 - - 0.71 - * - Blue - - 0.14 - - 0.08 - * - White Reference (C) - - 0.310 - - 0.316 - - -.. note:: - - This colorspace uses Illuminant C instead of D65 as the white - reference. To correctly convert an image in this colorspace to another - that uses D65 you need to apply a chromatic adaptation algorithm such as - the Bradford method. - -The transfer function was never properly defined for NTSC 1953. The Rec. -709 transfer function is recommended in the literature: - -.. math:: - - L' = 4.5L\text{, for } 0 \le L < 0.018 - - L' = 1.099L ^{0.45} - 0.099\text{, for } 0.018 \le L \le 1 - -Inverse Transfer function: - -.. math:: - - L = \frac{L'}{4.5} \text{, for } L' < 0.081 - - L = \left( \frac{L' + 0.099}{1.099}\right) ^{\frac{1}{0.45} }\text{, for } L' \ge 0.081 - -The luminance (Y') and color difference (Cb and Cr) are obtained with -the following ``V4L2_YCBCR_ENC_601`` encoding: - -.. math:: - - Y' = 0.2990R' + 0.5870G' + 0.1140B' - - Cb = -0.1687R' - 0.3313G' + 0.5B' - - Cr = 0.5R' - 0.4187G' - 0.0813B' - -Y' is clamped to the range [0…1] and Cb and Cr are clamped to the range -[-0.5…0.5]. The Y'CbCr quantization is limited range. This transform is -identical to one defined in SMPTE 170M/BT.601. - - -.. _col-sysbg: - -Colorspace EBU Tech. 3213 (V4L2_COLORSPACE_470_SYSTEM_BG) -========================================================= - -The :ref:`tech3213` standard defines the colorspace used by PAL/SECAM -in 1975. In practice this colorspace is obsolete and SMPTE 170M should -be used instead. The default transfer function is -``V4L2_XFER_FUNC_709``. The default Y'CbCr encoding is -``V4L2_YCBCR_ENC_601``. The default Y'CbCr quantization is limited -range. The chromaticities of the primary colors and the white reference -are: - - - -.. tabularcolumns:: |p{4.4cm}|p{4.4cm}|p{8.7cm}| - -.. flat-table:: EBU Tech. 3213 Chromaticities - :header-rows: 1 - :stub-columns: 0 - :widths: 1 1 2 - - * - Color - - x - - y - * - Red - - 0.64 - - 0.33 - * - Green - - 0.29 - - 0.60 - * - Blue - - 0.15 - - 0.06 - * - White Reference (D65) - - 0.3127 - - 0.3290 - - - -The transfer function was never properly defined for this colorspace. -The Rec. 709 transfer function is recommended in the literature: - -.. math:: - - L' = 4.5L\text{, for } 0 \le L < 0.018 - - L' = 1.099L ^{0.45} - 0.099\text{, for } 0.018 \le L \le 1 - -Inverse Transfer function: - -.. math:: - - L = \frac{L'}{4.5} \text{, for } L' < 0.081 - - L = \left(\frac{L' + 0.099}{1.099} \right) ^{\frac{1}{0.45} }\text{, for } L' \ge 0.081 - -The luminance (Y') and color difference (Cb and Cr) are obtained with -the following ``V4L2_YCBCR_ENC_601`` encoding: - -.. math:: - - Y' = 0.2990R' + 0.5870G' + 0.1140B' - - Cb = -0.1687R' - 0.3313G' + 0.5B' - - Cr = 0.5R' - 0.4187G' - 0.0813B' - -Y' is clamped to the range [0…1] and Cb and Cr are clamped to the range -[-0.5…0.5]. The Y'CbCr quantization is limited range. This transform is -identical to one defined in SMPTE 170M/BT.601. - - -.. _col-jpeg: - -Colorspace JPEG (V4L2_COLORSPACE_JPEG) -====================================== - -This colorspace defines the colorspace used by most (Motion-)JPEG -formats. The chromaticities of the primary colors and the white -reference are identical to sRGB. The transfer function use is -``V4L2_XFER_FUNC_SRGB``. The Y'CbCr encoding is ``V4L2_YCBCR_ENC_601`` -with full range quantization where Y' is scaled to [0…255] and Cb/Cr are -scaled to [-128…128] and then clipped to [-128…127]. - -.. note:: - - The JPEG standard does not actually store colorspace - information. So if something other than sRGB is used, then the driver - will have to set that information explicitly. Effectively - ``V4L2_COLORSPACE_JPEG`` can be considered to be an abbreviation for - ``V4L2_COLORSPACE_SRGB``, ``V4L2_YCBCR_ENC_601`` and - ``V4L2_QUANTIZATION_FULL_RANGE``. - -*************************************** -Detailed Transfer Function Descriptions -*************************************** - -.. _xf-smpte-2084: - -Transfer Function SMPTE 2084 (V4L2_XFER_FUNC_SMPTE2084) -======================================================= - -The :ref:`smpte2084` standard defines the transfer function used by -High Dynamic Range content. - -Constants: - m1 = (2610 / 4096) / 4 - - m2 = (2523 / 4096) * 128 - - c1 = 3424 / 4096 - - c2 = (2413 / 4096) * 32 - - c3 = (2392 / 4096) * 32 - -Transfer function: - L' = ((c1 + c2 * L\ :sup:`m1`) / (1 + c3 * L\ :sup:`m1`))\ :sup:`m2` - -Inverse Transfer function: - L = (max(L':sup:`1/m2` - c1, 0) / (c2 - c3 * - L'\ :sup:`1/m2`))\ :sup:`1/m1` - -Take care when converting between this transfer function and non-HDR transfer -functions: the linear RGB values [0…1] of HDR content map to a luminance range -of 0 to 10000 cd/m\ :sup:`2` whereas the linear RGB values of non-HDR (aka -Standard Dynamic Range or SDR) map to a luminance range of 0 to 100 cd/m\ :sup:`2`. - -To go from SDR to HDR you will have to divide L by 100 first. To go in the other -direction you will have to multiply L by 100. Of course, this clamps all -luminance values over 100 cd/m\ :sup:`2` to 100 cd/m\ :sup:`2`. - -There are better methods, see e.g. :ref:`colimg` for more in-depth information -about this. diff --git a/Documentation/media/uapi/v4l/colorspaces.rst b/Documentation/media/uapi/v4l/colorspaces.rst deleted file mode 100644 index 4f6c82fa057f..000000000000 --- a/Documentation/media/uapi/v4l/colorspaces.rst +++ /dev/null @@ -1,170 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _colorspaces: - -*********** -Colorspaces -*********** - -'Color' is a very complex concept and depends on physics, chemistry and -biology. Just because you have three numbers that describe the 'red', -'green' and 'blue' components of the color of a pixel does not mean that -you can accurately display that color. A colorspace defines what it -actually *means* to have an RGB value of e.g. (255, 0, 0). That is, -which color should be reproduced on the screen in a perfectly calibrated -environment. - -In order to do that we first need to have a good definition of color, -i.e. some way to uniquely and unambiguously define a color so that -someone else can reproduce it. Human color vision is trichromatic since -the human eye has color receptors that are sensitive to three different -wavelengths of light. Hence the need to use three numbers to describe -color. Be glad you are not a mantis shrimp as those are sensitive to 12 -different wavelengths, so instead of RGB we would be using the -ABCDEFGHIJKL colorspace... - -Color exists only in the eye and brain and is the result of how strongly -color receptors are stimulated. This is based on the Spectral Power -Distribution (SPD) which is a graph showing the intensity (radiant -power) of the light at wavelengths covering the visible spectrum as it -enters the eye. The science of colorimetry is about the relationship -between the SPD and color as perceived by the human brain. - -Since the human eye has only three color receptors it is perfectly -possible that different SPDs will result in the same stimulation of -those receptors and are perceived as the same color, even though the SPD -of the light is different. - -In the 1920s experiments were devised to determine the relationship -between SPDs and the perceived color and that resulted in the CIE 1931 -standard that defines spectral weighting functions that model the -perception of color. Specifically that standard defines functions that -can take an SPD and calculate the stimulus for each color receptor. -After some further mathematical transforms these stimuli are known as -the *CIE XYZ tristimulus* values and these X, Y and Z values describe a -color as perceived by a human unambiguously. These X, Y and Z values are -all in the range [0…1]. - -The Y value in the CIE XYZ colorspace corresponds to luminance. Often -the CIE XYZ colorspace is transformed to the normalized CIE xyY -colorspace: - - x = X / (X + Y + Z) - - y = Y / (X + Y + Z) - -The x and y values are the chromaticity coordinates and can be used to -define a color without the luminance component Y. It is very confusing -to have such similar names for these colorspaces. Just be aware that if -colors are specified with lower case 'x' and 'y', then the CIE xyY -colorspace is used. Upper case 'X' and 'Y' refer to the CIE XYZ -colorspace. Also, y has nothing to do with luminance. Together x and y -specify a color, and Y the luminance. That is really all you need to -remember from a practical point of view. At the end of this section you -will find reading resources that go into much more detail if you are -interested. - -A monitor or TV will reproduce colors by emitting light at three -different wavelengths, the combination of which will stimulate the color -receptors in the eye and thus cause the perception of color. -Historically these wavelengths were defined by the red, green and blue -phosphors used in the displays. These *color primaries* are part of what -defines a colorspace. - -Different display devices will have different primaries and some -primaries are more suitable for some display technologies than others. -This has resulted in a variety of colorspaces that are used for -different display technologies or uses. To define a colorspace you need -to define the three color primaries (these are typically defined as x, y -chromaticity coordinates from the CIE xyY colorspace) but also the white -reference: that is the color obtained when all three primaries are at -maximum power. This determines the relative power or energy of the -primaries. This is usually chosen to be close to daylight which has been -defined as the CIE D65 Illuminant. - -To recapitulate: the CIE XYZ colorspace uniquely identifies colors. -Other colorspaces are defined by three chromaticity coordinates defined -in the CIE xyY colorspace. Based on those a 3x3 matrix can be -constructed that transforms CIE XYZ colors to colors in the new -colorspace. - -Both the CIE XYZ and the RGB colorspace that are derived from the -specific chromaticity primaries are linear colorspaces. But neither the -eye, nor display technology is linear. Doubling the values of all -components in the linear colorspace will not be perceived as twice the -intensity of the color. So each colorspace also defines a transfer -function that takes a linear color component value and transforms it to -the non-linear component value, which is a closer match to the -non-linear performance of both the eye and displays. Linear component -values are denoted RGB, non-linear are denoted as R'G'B'. In general -colors used in graphics are all R'G'B', except in openGL which uses -linear RGB. Special care should be taken when dealing with openGL to -provide linear RGB colors or to use the built-in openGL support to apply -the inverse transfer function. - -The final piece that defines a colorspace is a function that transforms -non-linear R'G'B' to non-linear Y'CbCr. This function is determined by -the so-called luma coefficients. There may be multiple possible Y'CbCr -encodings allowed for the same colorspace. Many encodings of color -prefer to use luma (Y') and chroma (CbCr) instead of R'G'B'. Since the -human eye is more sensitive to differences in luminance than in color -this encoding allows one to reduce the amount of color information -compared to the luma data. Note that the luma (Y') is unrelated to the Y -in the CIE XYZ colorspace. Also note that Y'CbCr is often called YCbCr -or YUV even though these are strictly speaking wrong. - -Sometimes people confuse Y'CbCr as being a colorspace. This is not -correct, it is just an encoding of an R'G'B' color into luma and chroma -values. The underlying colorspace that is associated with the R'G'B' -color is also associated with the Y'CbCr color. - -The final step is how the RGB, R'G'B' or Y'CbCr values are quantized. -The CIE XYZ colorspace where X, Y and Z are in the range [0…1] describes -all colors that humans can perceive, but the transform to another -colorspace will produce colors that are outside the [0…1] range. Once -clamped to the [0…1] range those colors can no longer be reproduced in -that colorspace. This clamping is what reduces the extent or gamut of -the colorspace. How the range of [0…1] is translated to integer values -in the range of [0…255] (or higher, depending on the color depth) is -called the quantization. This is *not* part of the colorspace -definition. In practice RGB or R'G'B' values are full range, i.e. they -use the full [0…255] range. Y'CbCr values on the other hand are limited -range with Y' using [16…235] and Cb and Cr using [16…240]. - -Unfortunately, in some cases limited range RGB is also used where the -components use the range [16…235]. And full range Y'CbCr also exists -using the [0…255] range. - -In order to correctly interpret a color you need to know the -quantization range, whether it is R'G'B' or Y'CbCr, the used Y'CbCr -encoding and the colorspace. From that information you can calculate the -corresponding CIE XYZ color and map that again to whatever colorspace -your display device uses. - -The colorspace definition itself consists of the three chromaticity -primaries, the white reference chromaticity, a transfer function and the -luma coefficients needed to transform R'G'B' to Y'CbCr. While some -colorspace standards correctly define all four, quite often the -colorspace standard only defines some, and you have to rely on other -standards for the missing pieces. The fact that colorspaces are often a -mix of different standards also led to very confusing naming conventions -where the name of a standard was used to name a colorspace when in fact -that standard was part of various other colorspaces as well. - -If you want to read more about colors and colorspaces, then the -following resources are useful: :ref:`poynton` is a good practical -book for video engineers, :ref:`colimg` has a much broader scope and -describes many more aspects of color (physics, chemistry, biology, -etc.). The -`http://www.brucelindbloom.com `__ -website is an excellent resource, especially with respect to the -mathematics behind colorspace conversions. The wikipedia -`CIE 1931 colorspace `__ -article is also very useful. diff --git a/Documentation/media/uapi/v4l/common-defs.rst b/Documentation/media/uapi/v4l/common-defs.rst deleted file mode 100644 index 504c6c93c9b0..000000000000 --- a/Documentation/media/uapi/v4l/common-defs.rst +++ /dev/null @@ -1,20 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _common-defs: - -****************************************************** -Common definitions for V4L2 and V4L2 subdev interfaces -****************************************************** - - -.. toctree:: - :maxdepth: 1 - - selections-common diff --git a/Documentation/media/uapi/v4l/common.rst b/Documentation/media/uapi/v4l/common.rst deleted file mode 100644 index 5e87ae24e4b4..000000000000 --- a/Documentation/media/uapi/v4l/common.rst +++ /dev/null @@ -1,64 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _common: - -################### -Common API Elements -################### -Programming a V4L2 device consists of these steps: - -- Opening the device - -- Changing device properties, selecting a video and audio input, video - standard, picture brightness a. o. - -- Negotiating a data format - -- Negotiating an input/output method - -- The actual input/output loop - -- Closing the device - -In practice most steps are optional and can be executed out of order. It -depends on the V4L2 device type, you can read about the details in -:ref:`devices`. In this chapter we will discuss the basic concepts -applicable to all devices. - - -.. toctree:: - :maxdepth: 1 - - open - querycap - app-pri - video - audio - tuner - standard - dv-timings - control - extended-controls - ext-ctrls-camera - ext-ctrls-flash - ext-ctrls-image-source - ext-ctrls-image-process - ext-ctrls-codec - ext-ctrls-jpeg - ext-ctrls-dv - ext-ctrls-rf-tuner - ext-ctrls-fm-tx - ext-ctrls-fm-rx - ext-ctrls-detect - format - planar-apis - selection-api - crop - streaming-par diff --git a/Documentation/media/uapi/v4l/compat.rst b/Documentation/media/uapi/v4l/compat.rst deleted file mode 100644 index f35575a300b4..000000000000 --- a/Documentation/media/uapi/v4l/compat.rst +++ /dev/null @@ -1,25 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _compat: - -******* -Changes -******* - -The following chapters document the evolution of the V4L2 API, errata or -extensions. They are also intended to help application and driver -writers to port or update their code. - - -.. toctree:: - :maxdepth: 1 - - diff-v4l - hist-v4l2 diff --git a/Documentation/media/uapi/v4l/constraints.svg b/Documentation/media/uapi/v4l/constraints.svg deleted file mode 100644 index 08f9f8b0985e..000000000000 --- a/Documentation/media/uapi/v4l/constraints.svg +++ /dev/null @@ -1,37 +0,0 @@ - - -image/svg+xmlV4L2_SEL_FLAG_GE -ORIGINAL -V4L2_SEL_FLAG_LE - diff --git a/Documentation/media/uapi/v4l/control.rst b/Documentation/media/uapi/v4l/control.rst deleted file mode 100644 index ef62e088ff7a..000000000000 --- a/Documentation/media/uapi/v4l/control.rst +++ /dev/null @@ -1,512 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _control: - -************* -User Controls -************* - -Devices typically have a number of user-settable controls such as -brightness, saturation and so on, which would be presented to the user -on a graphical user interface. But, different devices will have -different controls available, and furthermore, the range of possible -values, and the default value will vary from device to device. The -control ioctls provide the information and a mechanism to create a nice -user interface for these controls that will work correctly with any -device. - -All controls are accessed using an ID value. V4L2 defines several IDs -for specific purposes. Drivers can also implement their own custom -controls using ``V4L2_CID_PRIVATE_BASE`` [#f1]_ and higher values. The -pre-defined control IDs have the prefix ``V4L2_CID_``, and are listed in -:ref:`control-id`. The ID is used when querying the attributes of a -control, and when getting or setting the current value. - -Generally applications should present controls to the user without -assumptions about their purpose. Each control comes with a name string -the user is supposed to understand. When the purpose is non-intuitive -the driver writer should provide a user manual, a user interface plug-in -or a driver specific panel application. Predefined IDs were introduced -to change a few controls programmatically, for example to mute a device -during a channel switch. - -Drivers may enumerate different controls after switching the current -video input or output, tuner or modulator, or audio input or output. -Different in the sense of other bounds, another default and current -value, step size or other menu items. A control with a certain *custom* -ID can also change name and type. - -If a control is not applicable to the current configuration of the -device (for example, it doesn't apply to the current video input) -drivers set the ``V4L2_CTRL_FLAG_INACTIVE`` flag. - -Control values are stored globally, they do not change when switching -except to stay within the reported bounds. They also do not change e. g. -when the device is opened or closed, when the tuner radio frequency is -changed or generally never without application request. - -V4L2 specifies an event mechanism to notify applications when controls -change value (see -:ref:`VIDIOC_SUBSCRIBE_EVENT`, event -``V4L2_EVENT_CTRL``), panel applications might want to make use of that -in order to always reflect the correct control value. - -All controls use machine endianness. - - -.. _control-id: - -Control IDs -=========== - -``V4L2_CID_BASE`` - First predefined ID, equal to ``V4L2_CID_BRIGHTNESS``. - -``V4L2_CID_USER_BASE`` - Synonym of ``V4L2_CID_BASE``. - -``V4L2_CID_BRIGHTNESS`` ``(integer)`` - Picture brightness, or more precisely, the black level. - -``V4L2_CID_CONTRAST`` ``(integer)`` - Picture contrast or luma gain. - -``V4L2_CID_SATURATION`` ``(integer)`` - Picture color saturation or chroma gain. - -``V4L2_CID_HUE`` ``(integer)`` - Hue or color balance. - -``V4L2_CID_AUDIO_VOLUME`` ``(integer)`` - Overall audio volume. Note some drivers also provide an OSS or ALSA - mixer interface. - -``V4L2_CID_AUDIO_BALANCE`` ``(integer)`` - Audio stereo balance. Minimum corresponds to all the way left, - maximum to right. - -``V4L2_CID_AUDIO_BASS`` ``(integer)`` - Audio bass adjustment. - -``V4L2_CID_AUDIO_TREBLE`` ``(integer)`` - Audio treble adjustment. - -``V4L2_CID_AUDIO_MUTE`` ``(boolean)`` - Mute audio, i. e. set the volume to zero, however without affecting - ``V4L2_CID_AUDIO_VOLUME``. Like ALSA drivers, V4L2 drivers must mute - at load time to avoid excessive noise. Actually the entire device - should be reset to a low power consumption state. - -``V4L2_CID_AUDIO_LOUDNESS`` ``(boolean)`` - Loudness mode (bass boost). - -``V4L2_CID_BLACK_LEVEL`` ``(integer)`` - Another name for brightness (not a synonym of - ``V4L2_CID_BRIGHTNESS``). This control is deprecated and should not - be used in new drivers and applications. - -``V4L2_CID_AUTO_WHITE_BALANCE`` ``(boolean)`` - Automatic white balance (cameras). - -``V4L2_CID_DO_WHITE_BALANCE`` ``(button)`` - This is an action control. When set (the value is ignored), the - device will do a white balance and then hold the current setting. - Contrast this with the boolean ``V4L2_CID_AUTO_WHITE_BALANCE``, - which, when activated, keeps adjusting the white balance. - -``V4L2_CID_RED_BALANCE`` ``(integer)`` - Red chroma balance. - -``V4L2_CID_BLUE_BALANCE`` ``(integer)`` - Blue chroma balance. - -``V4L2_CID_GAMMA`` ``(integer)`` - Gamma adjust. - -``V4L2_CID_WHITENESS`` ``(integer)`` - Whiteness for grey-scale devices. This is a synonym for - ``V4L2_CID_GAMMA``. This control is deprecated and should not be - used in new drivers and applications. - -``V4L2_CID_EXPOSURE`` ``(integer)`` - Exposure (cameras). [Unit?] - -``V4L2_CID_AUTOGAIN`` ``(boolean)`` - Automatic gain/exposure control. - -``V4L2_CID_GAIN`` ``(integer)`` - Gain control. - - Primarily used to control gain on e.g. TV tuners but also on - webcams. Most devices control only digital gain with this control - but on some this could include analogue gain as well. Devices that - recognise the difference between digital and analogue gain use - controls ``V4L2_CID_DIGITAL_GAIN`` and ``V4L2_CID_ANALOGUE_GAIN``. - -``V4L2_CID_HFLIP`` ``(boolean)`` - Mirror the picture horizontally. - -``V4L2_CID_VFLIP`` ``(boolean)`` - Mirror the picture vertically. - -.. _v4l2-power-line-frequency: - -``V4L2_CID_POWER_LINE_FREQUENCY`` ``(enum)`` - Enables a power line frequency filter to avoid flicker. Possible - values for ``enum v4l2_power_line_frequency`` are: - ``V4L2_CID_POWER_LINE_FREQUENCY_DISABLED`` (0), - ``V4L2_CID_POWER_LINE_FREQUENCY_50HZ`` (1), - ``V4L2_CID_POWER_LINE_FREQUENCY_60HZ`` (2) and - ``V4L2_CID_POWER_LINE_FREQUENCY_AUTO`` (3). - -``V4L2_CID_HUE_AUTO`` ``(boolean)`` - Enables automatic hue control by the device. The effect of setting - ``V4L2_CID_HUE`` while automatic hue control is enabled is - undefined, drivers should ignore such request. - -``V4L2_CID_WHITE_BALANCE_TEMPERATURE`` ``(integer)`` - This control specifies the white balance settings as a color - temperature in Kelvin. A driver should have a minimum of 2800 - (incandescent) to 6500 (daylight). For more information about color - temperature see - `Wikipedia `__. - -``V4L2_CID_SHARPNESS`` ``(integer)`` - Adjusts the sharpness filters in a camera. The minimum value - disables the filters, higher values give a sharper picture. - -``V4L2_CID_BACKLIGHT_COMPENSATION`` ``(integer)`` - Adjusts the backlight compensation in a camera. The minimum value - disables backlight compensation. - -``V4L2_CID_CHROMA_AGC`` ``(boolean)`` - Chroma automatic gain control. - -``V4L2_CID_CHROMA_GAIN`` ``(integer)`` - Adjusts the Chroma gain control (for use when chroma AGC is - disabled). - -``V4L2_CID_COLOR_KILLER`` ``(boolean)`` - Enable the color killer (i. e. force a black & white image in case - of a weak video signal). - -.. _v4l2-colorfx: - -``V4L2_CID_COLORFX`` ``(enum)`` - Selects a color effect. The following values are defined: - - - -.. tabularcolumns:: |p{5.5cm}|p{12cm}| - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - :widths: 11 24 - - * - ``V4L2_COLORFX_NONE`` - - Color effect is disabled. - * - ``V4L2_COLORFX_ANTIQUE`` - - An aging (old photo) effect. - * - ``V4L2_COLORFX_ART_FREEZE`` - - Frost color effect. - * - ``V4L2_COLORFX_AQUA`` - - Water color, cool tone. - * - ``V4L2_COLORFX_BW`` - - Black and white. - * - ``V4L2_COLORFX_EMBOSS`` - - Emboss, the highlights and shadows replace light/dark boundaries - and low contrast areas are set to a gray background. - * - ``V4L2_COLORFX_GRASS_GREEN`` - - Grass green. - * - ``V4L2_COLORFX_NEGATIVE`` - - Negative. - * - ``V4L2_COLORFX_SEPIA`` - - Sepia tone. - * - ``V4L2_COLORFX_SKETCH`` - - Sketch. - * - ``V4L2_COLORFX_SKIN_WHITEN`` - - Skin whiten. - * - ``V4L2_COLORFX_SKY_BLUE`` - - Sky blue. - * - ``V4L2_COLORFX_SOLARIZATION`` - - Solarization, the image is partially reversed in tone, only color - values above or below a certain threshold are inverted. - * - ``V4L2_COLORFX_SILHOUETTE`` - - Silhouette (outline). - * - ``V4L2_COLORFX_VIVID`` - - Vivid colors. - * - ``V4L2_COLORFX_SET_CBCR`` - - The Cb and Cr chroma components are replaced by fixed coefficients - determined by ``V4L2_CID_COLORFX_CBCR`` control. - - - -``V4L2_CID_COLORFX_CBCR`` ``(integer)`` - Determines the Cb and Cr coefficients for ``V4L2_COLORFX_SET_CBCR`` - color effect. Bits [7:0] of the supplied 32 bit value are - interpreted as Cr component, bits [15:8] as Cb component and bits - [31:16] must be zero. - -``V4L2_CID_AUTOBRIGHTNESS`` ``(boolean)`` - Enable Automatic Brightness. - -``V4L2_CID_ROTATE`` ``(integer)`` - Rotates the image by specified angle. Common angles are 90, 270 and - 180. Rotating the image to 90 and 270 will reverse the height and - width of the display window. It is necessary to set the new height - and width of the picture using the - :ref:`VIDIOC_S_FMT ` ioctl according to the - rotation angle selected. - -``V4L2_CID_BG_COLOR`` ``(integer)`` - Sets the background color on the current output device. Background - color needs to be specified in the RGB24 format. The supplied 32 bit - value is interpreted as bits 0-7 Red color information, bits 8-15 - Green color information, bits 16-23 Blue color information and bits - 24-31 must be zero. - -``V4L2_CID_ILLUMINATORS_1 V4L2_CID_ILLUMINATORS_2`` ``(boolean)`` - Switch on or off the illuminator 1 or 2 of the device (usually a - microscope). - -``V4L2_CID_MIN_BUFFERS_FOR_CAPTURE`` ``(integer)`` - This is a read-only control that can be read by the application and - used as a hint to determine the number of CAPTURE buffers to pass to - REQBUFS. The value is the minimum number of CAPTURE buffers that is - necessary for hardware to work. - -``V4L2_CID_MIN_BUFFERS_FOR_OUTPUT`` ``(integer)`` - This is a read-only control that can be read by the application and - used as a hint to determine the number of OUTPUT buffers to pass to - REQBUFS. The value is the minimum number of OUTPUT buffers that is - necessary for hardware to work. - -.. _v4l2-alpha-component: - -``V4L2_CID_ALPHA_COMPONENT`` ``(integer)`` - Sets the alpha color component. When a capture device (or capture - queue of a mem-to-mem device) produces a frame format that includes - an alpha component (e.g. - :ref:`packed RGB image formats `) and the alpha value - is not defined by the device or the mem-to-mem input data this - control lets you select the alpha component value of all pixels. - When an output device (or output queue of a mem-to-mem device) - consumes a frame format that doesn't include an alpha component and - the device supports alpha channel processing this control lets you - set the alpha component value of all pixels for further processing - in the device. - -``V4L2_CID_LASTP1`` - End of the predefined control IDs (currently - ``V4L2_CID_ALPHA_COMPONENT`` + 1). - -``V4L2_CID_PRIVATE_BASE`` - ID of the first custom (driver specific) control. Applications - depending on particular custom controls should check the driver name - and version, see :ref:`querycap`. - -Applications can enumerate the available controls with the -:ref:`VIDIOC_QUERYCTRL` and -:ref:`VIDIOC_QUERYMENU ` ioctls, get and set a -control value with the :ref:`VIDIOC_G_CTRL ` and -:ref:`VIDIOC_S_CTRL ` ioctls. Drivers must implement -``VIDIOC_QUERYCTRL``, ``VIDIOC_G_CTRL`` and ``VIDIOC_S_CTRL`` when the -device has one or more controls, ``VIDIOC_QUERYMENU`` when it has one or -more menu type controls. - - -.. _enum_all_controls: - -Example: Enumerating all controls -================================= - -.. code-block:: c - - struct v4l2_queryctrl queryctrl; - struct v4l2_querymenu querymenu; - - static void enumerate_menu(__u32 id) - { - printf(" Menu items:\\n"); - - memset(&querymenu, 0, sizeof(querymenu)); - querymenu.id = id; - - for (querymenu.index = queryctrl.minimum; - querymenu.index <= queryctrl.maximum; - querymenu.index++) { - if (0 == ioctl(fd, VIDIOC_QUERYMENU, &querymenu)) { - printf(" %s\\n", querymenu.name); - } - } - } - - memset(&queryctrl, 0, sizeof(queryctrl)); - - queryctrl.id = V4L2_CTRL_FLAG_NEXT_CTRL; - while (0 == ioctl(fd, VIDIOC_QUERYCTRL, &queryctrl)) { - if (!(queryctrl.flags & V4L2_CTRL_FLAG_DISABLED)) { - printf("Control %s\\n", queryctrl.name); - - if (queryctrl.type == V4L2_CTRL_TYPE_MENU) - enumerate_menu(queryctrl.id); - } - - queryctrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL; - } - if (errno != EINVAL) { - perror("VIDIOC_QUERYCTRL"); - exit(EXIT_FAILURE); - } - -Example: Enumerating all controls including compound controls -============================================================= - -.. code-block:: c - - struct v4l2_query_ext_ctrl query_ext_ctrl; - - memset(&query_ext_ctrl, 0, sizeof(query_ext_ctrl)); - - query_ext_ctrl.id = V4L2_CTRL_FLAG_NEXT_CTRL | V4L2_CTRL_FLAG_NEXT_COMPOUND; - while (0 == ioctl(fd, VIDIOC_QUERY_EXT_CTRL, &query_ext_ctrl)) { - if (!(query_ext_ctrl.flags & V4L2_CTRL_FLAG_DISABLED)) { - printf("Control %s\\n", query_ext_ctrl.name); - - if (query_ext_ctrl.type == V4L2_CTRL_TYPE_MENU) - enumerate_menu(query_ext_ctrl.id); - } - - query_ext_ctrl.id |= V4L2_CTRL_FLAG_NEXT_CTRL | V4L2_CTRL_FLAG_NEXT_COMPOUND; - } - if (errno != EINVAL) { - perror("VIDIOC_QUERY_EXT_CTRL"); - exit(EXIT_FAILURE); - } - -Example: Enumerating all user controls (old style) -================================================== - -.. code-block:: c - - - memset(&queryctrl, 0, sizeof(queryctrl)); - - for (queryctrl.id = V4L2_CID_BASE; - queryctrl.id < V4L2_CID_LASTP1; - queryctrl.id++) { - if (0 == ioctl(fd, VIDIOC_QUERYCTRL, &queryctrl)) { - if (queryctrl.flags & V4L2_CTRL_FLAG_DISABLED) - continue; - - printf("Control %s\\n", queryctrl.name); - - if (queryctrl.type == V4L2_CTRL_TYPE_MENU) - enumerate_menu(queryctrl.id); - } else { - if (errno == EINVAL) - continue; - - perror("VIDIOC_QUERYCTRL"); - exit(EXIT_FAILURE); - } - } - - for (queryctrl.id = V4L2_CID_PRIVATE_BASE;; - queryctrl.id++) { - if (0 == ioctl(fd, VIDIOC_QUERYCTRL, &queryctrl)) { - if (queryctrl.flags & V4L2_CTRL_FLAG_DISABLED) - continue; - - printf("Control %s\\n", queryctrl.name); - - if (queryctrl.type == V4L2_CTRL_TYPE_MENU) - enumerate_menu(queryctrl.id); - } else { - if (errno == EINVAL) - break; - - perror("VIDIOC_QUERYCTRL"); - exit(EXIT_FAILURE); - } - } - - -Example: Changing controls -========================== - -.. code-block:: c - - struct v4l2_queryctrl queryctrl; - struct v4l2_control control; - - memset(&queryctrl, 0, sizeof(queryctrl)); - queryctrl.id = V4L2_CID_BRIGHTNESS; - - if (-1 == ioctl(fd, VIDIOC_QUERYCTRL, &queryctrl)) { - if (errno != EINVAL) { - perror("VIDIOC_QUERYCTRL"); - exit(EXIT_FAILURE); - } else { - printf("V4L2_CID_BRIGHTNESS is not supportedn"); - } - } else if (queryctrl.flags & V4L2_CTRL_FLAG_DISABLED) { - printf("V4L2_CID_BRIGHTNESS is not supportedn"); - } else { - memset(&control, 0, sizeof (control)); - control.id = V4L2_CID_BRIGHTNESS; - control.value = queryctrl.default_value; - - if (-1 == ioctl(fd, VIDIOC_S_CTRL, &control)) { - perror("VIDIOC_S_CTRL"); - exit(EXIT_FAILURE); - } - } - - memset(&control, 0, sizeof(control)); - control.id = V4L2_CID_CONTRAST; - - if (0 == ioctl(fd, VIDIOC_G_CTRL, &control)) { - control.value += 1; - - /* The driver may clamp the value or return ERANGE, ignored here */ - - if (-1 == ioctl(fd, VIDIOC_S_CTRL, &control) - && errno != ERANGE) { - perror("VIDIOC_S_CTRL"); - exit(EXIT_FAILURE); - } - /* Ignore if V4L2_CID_CONTRAST is unsupported */ - } else if (errno != EINVAL) { - perror("VIDIOC_G_CTRL"); - exit(EXIT_FAILURE); - } - - control.id = V4L2_CID_AUDIO_MUTE; - control.value = 1; /* silence */ - - /* Errors ignored */ - ioctl(fd, VIDIOC_S_CTRL, &control); - -.. [#f1] - The use of ``V4L2_CID_PRIVATE_BASE`` is problematic because different - drivers may use the same ``V4L2_CID_PRIVATE_BASE`` ID for different - controls. This makes it hard to programmatically set such controls - since the meaning of the control with that ID is driver dependent. In - order to resolve this drivers use unique IDs and the - ``V4L2_CID_PRIVATE_BASE`` IDs are mapped to those unique IDs by the - kernel. Consider these ``V4L2_CID_PRIVATE_BASE`` IDs as aliases to - the real IDs. - - Many applications today still use the ``V4L2_CID_PRIVATE_BASE`` IDs - instead of using :ref:`VIDIOC_QUERYCTRL` with - the ``V4L2_CTRL_FLAG_NEXT_CTRL`` flag to enumerate all IDs, so - support for ``V4L2_CID_PRIVATE_BASE`` is still around. diff --git a/Documentation/media/uapi/v4l/crop.rst b/Documentation/media/uapi/v4l/crop.rst deleted file mode 100644 index ada7c22e6291..000000000000 --- a/Documentation/media/uapi/v4l/crop.rst +++ /dev/null @@ -1,324 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _crop: - -***************************************************** -Image Cropping, Insertion and Scaling -- the CROP API -***************************************************** - -.. note:: - - The CROP API is mostly superseded by the newer :ref:`SELECTION API - `. The new API should be preferred in most cases, - with the exception of pixel aspect ratio detection, which is - implemented by :ref:`VIDIOC_CROPCAP ` and has no - equivalent in the SELECTION API. See :ref:`selection-vs-crop` for a - comparison of the two APIs. - -Some video capture devices can sample a subsection of the picture and -shrink or enlarge it to an image of arbitrary size. We call these -abilities cropping and scaling. Some video output devices can scale an -image up or down and insert it at an arbitrary scan line and horizontal -offset into a video signal. - -Applications can use the following API to select an area in the video -signal, query the default area and the hardware limits. - -.. note:: - - Despite their name, the :ref:`VIDIOC_CROPCAP `, - :ref:`VIDIOC_G_CROP ` and :ref:`VIDIOC_S_CROP - ` ioctls apply to input as well as output devices. - -Scaling requires a source and a target. On a video capture or overlay -device the source is the video signal, and the cropping ioctls determine -the area actually sampled. The target are images read by the application -or overlaid onto the graphics screen. Their size (and position for an -overlay) is negotiated with the :ref:`VIDIOC_G_FMT ` -and :ref:`VIDIOC_S_FMT ` ioctls. - -On a video output device the source are the images passed in by the -application, and their size is again negotiated with the -:ref:`VIDIOC_G_FMT ` and :ref:`VIDIOC_S_FMT ` -ioctls, or may be encoded in a compressed video stream. The target is -the video signal, and the cropping ioctls determine the area where the -images are inserted. - -Source and target rectangles are defined even if the device does not -support scaling or the :ref:`VIDIOC_G_CROP ` and -:ref:`VIDIOC_S_CROP ` ioctls. Their size (and position -where applicable) will be fixed in this case. - -.. note:: - - All capture and output devices that support the CROP or SELECTION - API will also support the :ref:`VIDIOC_CROPCAP ` - ioctl. - -Cropping Structures -=================== - - -.. _crop-scale: - -.. kernel-figure:: crop.svg - :alt: crop.svg - :align: center - - Image Cropping, Insertion and Scaling - - The cropping, insertion and scaling process - - - -For capture devices the coordinates of the top left corner, width and -height of the area which can be sampled is given by the ``bounds`` -substructure of the struct :c:type:`v4l2_cropcap` returned -by the :ref:`VIDIOC_CROPCAP ` ioctl. To support a wide -range of hardware this specification does not define an origin or units. -However by convention drivers should horizontally count unscaled samples -relative to 0H (the leading edge of the horizontal sync pulse, see -:ref:`vbi-hsync`). Vertically ITU-R line numbers of the first field -(see ITU R-525 line numbering for :ref:`525 lines ` and for -:ref:`625 lines `), multiplied by two if the driver -can capture both fields. - -The top left corner, width and height of the source rectangle, that is -the area actually sampled, is given by struct -:c:type:`v4l2_crop` using the same coordinate system as -struct :c:type:`v4l2_cropcap`. Applications can use the -:ref:`VIDIOC_G_CROP ` and :ref:`VIDIOC_S_CROP ` -ioctls to get and set this rectangle. It must lie completely within the -capture boundaries and the driver may further adjust the requested size -and/or position according to hardware limitations. - -Each capture device has a default source rectangle, given by the -``defrect`` substructure of struct -:c:type:`v4l2_cropcap`. The center of this rectangle -shall align with the center of the active picture area of the video -signal, and cover what the driver writer considers the complete picture. -Drivers shall reset the source rectangle to the default when the driver -is first loaded, but not later. - -For output devices these structures and ioctls are used accordingly, -defining the *target* rectangle where the images will be inserted into -the video signal. - - -Scaling Adjustments -=================== - -Video hardware can have various cropping, insertion and scaling -limitations. It may only scale up or down, support only discrete scaling -factors, or have different scaling abilities in horizontal and vertical -direction. Also it may not support scaling at all. At the same time the -struct :c:type:`v4l2_crop` rectangle may have to be aligned, -and both the source and target rectangles may have arbitrary upper and -lower size limits. In particular the maximum ``width`` and ``height`` in -struct :c:type:`v4l2_crop` may be smaller than the struct -:c:type:`v4l2_cropcap`. ``bounds`` area. Therefore, as -usual, drivers are expected to adjust the requested parameters and -return the actual values selected. - -Applications can change the source or the target rectangle first, as -they may prefer a particular image size or a certain area in the video -signal. If the driver has to adjust both to satisfy hardware -limitations, the last requested rectangle shall take priority, and the -driver should preferably adjust the opposite one. The -:ref:`VIDIOC_TRY_FMT ` ioctl however shall not change -the driver state and therefore only adjust the requested rectangle. - -Suppose scaling on a video capture device is restricted to a factor 1:1 -or 2:1 in either direction and the target image size must be a multiple -of 16 × 16 pixels. The source cropping rectangle is set to defaults, -which are also the upper limit in this example, of 640 × 400 pixels at -offset 0, 0. An application requests an image size of 300 × 225 pixels, -assuming video will be scaled down from the "full picture" accordingly. -The driver sets the image size to the closest possible values 304 × 224, -then chooses the cropping rectangle closest to the requested size, that -is 608 × 224 (224 × 2:1 would exceed the limit 400). The offset 0, 0 is -still valid, thus unmodified. Given the default cropping rectangle -reported by :ref:`VIDIOC_CROPCAP ` the application can -easily propose another offset to center the cropping rectangle. - -Now the application may insist on covering an area using a picture -aspect ratio closer to the original request, so it asks for a cropping -rectangle of 608 × 456 pixels. The present scaling factors limit -cropping to 640 × 384, so the driver returns the cropping size 608 × 384 -and adjusts the image size to closest possible 304 × 192. - - -Examples -======== - -Source and target rectangles shall remain unchanged across closing and -reopening a device, such that piping data into or out of a device will -work without special preparations. More advanced applications should -ensure the parameters are suitable before starting I/O. - -.. note:: - - On the next two examples, a video capture device is assumed; - change ``V4L2_BUF_TYPE_VIDEO_CAPTURE`` for other types of device. - -Example: Resetting the cropping parameters -========================================== - -.. code-block:: c - - struct v4l2_cropcap cropcap; - struct v4l2_crop crop; - - memset (&cropcap, 0, sizeof (cropcap)); - cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - - if (-1 == ioctl (fd, VIDIOC_CROPCAP, &cropcap)) { - perror ("VIDIOC_CROPCAP"); - exit (EXIT_FAILURE); - } - - memset (&crop, 0, sizeof (crop)); - crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - crop.c = cropcap.defrect; - - /* Ignore if cropping is not supported (EINVAL). */ - - if (-1 == ioctl (fd, VIDIOC_S_CROP, &crop) - && errno != EINVAL) { - perror ("VIDIOC_S_CROP"); - exit (EXIT_FAILURE); - } - - -Example: Simple downscaling -=========================== - -.. code-block:: c - - struct v4l2_cropcap cropcap; - struct v4l2_format format; - - reset_cropping_parameters (); - - /* Scale down to 1/4 size of full picture. */ - - memset (&format, 0, sizeof (format)); /* defaults */ - - format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - - format.fmt.pix.width = cropcap.defrect.width >> 1; - format.fmt.pix.height = cropcap.defrect.height >> 1; - format.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; - - if (-1 == ioctl (fd, VIDIOC_S_FMT, &format)) { - perror ("VIDIOC_S_FORMAT"); - exit (EXIT_FAILURE); - } - - /* We could check the actual image size now, the actual scaling factor - or if the driver can scale at all. */ - -Example: Selecting an output area -================================= - -.. note:: This example assumes an output device. - -.. code-block:: c - - struct v4l2_cropcap cropcap; - struct v4l2_crop crop; - - memset (&cropcap, 0, sizeof (cropcap)); - cropcap.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; - - if (-1 == ioctl (fd, VIDIOC_CROPCAP;, &cropcap)) { - perror ("VIDIOC_CROPCAP"); - exit (EXIT_FAILURE); - } - - memset (&crop, 0, sizeof (crop)); - - crop.type = V4L2_BUF_TYPE_VIDEO_OUTPUT; - crop.c = cropcap.defrect; - - /* Scale the width and height to 50 % of their original size - and center the output. */ - - crop.c.width /= 2; - crop.c.height /= 2; - crop.c.left += crop.c.width / 2; - crop.c.top += crop.c.height / 2; - - /* Ignore if cropping is not supported (EINVAL). */ - - if (-1 == ioctl (fd, VIDIOC_S_CROP, &crop) - && errno != EINVAL) { - perror ("VIDIOC_S_CROP"); - exit (EXIT_FAILURE); - } - -Example: Current scaling factor and pixel aspect -================================================ - -.. note:: This example assumes a video capture device. - -.. code-block:: c - - struct v4l2_cropcap cropcap; - struct v4l2_crop crop; - struct v4l2_format format; - double hscale, vscale; - double aspect; - int dwidth, dheight; - - memset (&cropcap, 0, sizeof (cropcap)); - cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - - if (-1 == ioctl (fd, VIDIOC_CROPCAP, &cropcap)) { - perror ("VIDIOC_CROPCAP"); - exit (EXIT_FAILURE); - } - - memset (&crop, 0, sizeof (crop)); - crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - - if (-1 == ioctl (fd, VIDIOC_G_CROP, &crop)) { - if (errno != EINVAL) { - perror ("VIDIOC_G_CROP"); - exit (EXIT_FAILURE); - } - - /* Cropping not supported. */ - crop.c = cropcap.defrect; - } - - memset (&format, 0, sizeof (format)); - format.fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - - if (-1 == ioctl (fd, VIDIOC_G_FMT, &format)) { - perror ("VIDIOC_G_FMT"); - exit (EXIT_FAILURE); - } - - /* The scaling applied by the driver. */ - - hscale = format.fmt.pix.width / (double) crop.c.width; - vscale = format.fmt.pix.height / (double) crop.c.height; - - aspect = cropcap.pixelaspect.numerator / - (double) cropcap.pixelaspect.denominator; - aspect = aspect * hscale / vscale; - - /* Devices following ITU-R BT.601 do not capture - square pixels. For playback on a computer monitor - we should scale the images to this size. */ - - dwidth = format.fmt.pix.width / aspect; - dheight = format.fmt.pix.height; diff --git a/Documentation/media/uapi/v4l/crop.svg b/Documentation/media/uapi/v4l/crop.svg deleted file mode 100644 index 32d72598d135..000000000000 --- a/Documentation/media/uapi/v4l/crop.svg +++ /dev/null @@ -1,290 +0,0 @@ - - -image/svg+xmlv4l2_cropcap.bounds -v4l2_cropcap.defrect -v4l2_crop.c -v4l2_format - - diff --git a/Documentation/media/uapi/v4l/depth-formats.rst b/Documentation/media/uapi/v4l/depth-formats.rst deleted file mode 100644 index 1bfd0b82cb85..000000000000 --- a/Documentation/media/uapi/v4l/depth-formats.rst +++ /dev/null @@ -1,24 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _depth-formats: - -************* -Depth Formats -************* - -Depth data provides distance to points, mapped onto the image plane - - -.. toctree:: - :maxdepth: 1 - - pixfmt-inzi - pixfmt-z16 - pixfmt-cnf4 diff --git a/Documentation/media/uapi/v4l/dev-capture.rst b/Documentation/media/uapi/v4l/dev-capture.rst deleted file mode 100644 index 134e22b32338..000000000000 --- a/Documentation/media/uapi/v4l/dev-capture.rst +++ /dev/null @@ -1,111 +0,0 @@ -.. Permission is granted to copy, distribute and/or modify this -.. document under the terms of the GNU Free Documentation License, -.. Version 1.1 or any later version published by the Free Software -.. Foundation, with no Invariant Sections, no Front-Cover Texts -.. and no Back-Cover Texts. A copy of the license is included at -.. Documentation/media/uapi/fdl-appendix.rst. -.. -.. TODO: replace it to GFDL-1.1-or-later WITH no-invariant-sections - -.. _capture: - -*********************** -Video Capture Interface -*********************** - -Video capture devices sample an analog video signal and store the -digitized images in memory. Today nearly all devices can capture at full -25 or 30 frames/second. With this interface applications can control the -capture process and move images from the driver into user space. - -Conventionally V4L2 video capture devices are accessed through character -device special files named ``/dev/video`` and ``/dev/video0`` to -``/dev/video63`` with major number 81 and minor numbers 0 to 63. -``/dev/video`` is typically a symbolic link to the preferred video -device. - -.. note:: The same device file names are used for video output devices. - - -Querying Capabilities -===================== - -Devices supporting the video capture interface set the -``V4L2_CAP_VIDEO_CAPTURE`` or ``V4L2_CAP_VIDEO_CAPTURE_MPLANE`` flag in -the ``capabilities`` field of struct -:c:type:`v4l2_capability` returned by the -:ref:`VIDIOC_QUERYCAP` ioctl. As secondary device -functions they may also support the :ref:`video overlay ` -(``V4L2_CAP_VIDEO_OVERLAY``) and the :ref:`raw VBI capture ` -(``V4L2_CAP_VBI_CAPTURE``) interface. At least one of the read/write or -streaming I/O methods must be supported. Tuners and audio inputs are -optional. - - -Supplemental Functions -====================== - -Video capture devices shall support :ref:`audio input