diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2019-05-08 21:13:17 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2019-05-08 21:13:17 +0300 |
commit | e7a1414f9dc3498c4c35b9ca266d539e8bccab53 (patch) | |
tree | f50a78785859182f9916c93dcf97c6539dbe3f3e | |
parent | 85c1a25494837ff33fdfebe98b2e4cf5b0c78475 (diff) | |
parent | 0d672fffb447aa1699d76fdacd90dc31eeb66d97 (diff) | |
download | linux-e7a1414f9dc3498c4c35b9ca266d539e8bccab53.tar.xz |
Merge tag 'media/v5.1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media
Pull media updates from Mauro Carvalho Chehab:
- remove the deprecated Zoran driver from staging
- new I2C driver: ST MIPID02 CSI-2 camera bridge
- new platform driver: Amlogic Meson AO CEC G12A Controller
- add support for USB audio via the media controller
- au0828 driver is now supported via the media controller on both on
media and on usbaudio
- new kernel test for the media device allocator
- add support for stateless decoder at vicodec driver
- lots of other driver improvements fixes and cleanups
* tag 'media/v5.1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (218 commits)
media: dt-bindings: aspeed-video: Add missing memory-region property
media: platform: Aspeed: Make reserved memory optional
media: platform: Aspeed: Remove use of reset line
media: stm32-dcmi: return appropriate error codes during probe
media: vsp1: Add support for missing 16-bit RGB555 formats
media: vsp1: Add support for missing 16-bit RGB444 formats
media: vsp1: Add support for missing 32-bit RGB formats
media: v4l: Add definitions for missing 16-bit RGB555 formats
media: v4l: Add definitions for missing 16-bit RGB4444 formats
media: v4l: Add definitions for missing 32-bit RGB formats
media: zoran: remove deprecated driver
media: MAINTAINERS: Update AO CEC with ao-cec-g12a driver
media: platform: meson: Add Amlogic Meson G12A AO CEC Controller driver
media: dt-bindings: media: meson-ao-cec: Add G12A AO-CEC-B Compatible
media: cros-ec-cec: decrement HDMI device refcount
media: seco-cec: decrement HDMI device refcount
media: tegra_cec: use new cec_notifier_parse_hdmi_phandle helper
media: stih_cec: use new cec_notifier_parse_hdmi_phandle helper
media: s5p_cec: use new cec_notifier_parse_hdmi_phandle helper
media: meson: ao-cec: use new cec_notifier_parse_hdmi_phandle helper
...
324 files changed, 7625 insertions, 13909 deletions
diff --git a/Documentation/devicetree/bindings/media/aspeed-video.txt b/Documentation/devicetree/bindings/media/aspeed-video.txt index 78b464ae2672..ce2894506e1f 100644 --- a/Documentation/devicetree/bindings/media/aspeed-video.txt +++ b/Documentation/devicetree/bindings/media/aspeed-video.txt @@ -14,6 +14,11 @@ Required properties: the VE - interrupts: the interrupt associated with the VE on this platform +Optional properties: + - memory-region: + phandle to a memory region to allocate from, as defined in + Documentation/devicetree/bindings/reserved-memory/reserved-memory.txt + Example: video-engine@1e700000 { @@ -23,4 +28,5 @@ video-engine@1e700000 { clock-names = "vclk", "eclk"; resets = <&syscon ASPEED_RESET_VIDEO>; interrupts = <7>; + memory-region = <&video_engine_memory>; }; diff --git a/Documentation/devicetree/bindings/media/cedrus.txt b/Documentation/devicetree/bindings/media/cedrus.txt index bce0705df953..20c82fb0c343 100644 --- a/Documentation/devicetree/bindings/media/cedrus.txt +++ b/Documentation/devicetree/bindings/media/cedrus.txt @@ -13,6 +13,7 @@ Required properties: - "allwinner,sun8i-h3-video-engine" - "allwinner,sun50i-a64-video-engine" - "allwinner,sun50i-h5-video-engine" + - "allwinner,sun50i-h6-video-engine" - reg : register base and length of VE; - clocks : list of clock specifiers, corresponding to entries in the clock-names property; diff --git a/Documentation/devicetree/bindings/media/i2c/st,st-mipid02.txt b/Documentation/devicetree/bindings/media/i2c/st,st-mipid02.txt new file mode 100644 index 000000000000..7976e6c40a80 --- /dev/null +++ b/Documentation/devicetree/bindings/media/i2c/st,st-mipid02.txt @@ -0,0 +1,82 @@ +STMicroelectronics MIPID02 CSI-2 to PARALLEL bridge + +MIPID02 has two CSI-2 input ports, only one of those ports can be active at a +time. Active port input stream will be de-serialized and its content outputted +through PARALLEL output port. +CSI-2 first input port is a dual lane 800Mbps per lane whereas CSI-2 second +input port is a single lane 800Mbps. Both ports support clock and data lane +polarity swap. First port also supports data lane swap. +PARALLEL output port has a maximum width of 12 bits. +Supported formats are RAW6, RAW7, RAW8, RAW10, RAW12, RGB565, RGB888, RGB444, +YUV420 8-bit, YUV422 8-bit and YUV420 10-bit. + +Required Properties: +- compatible: shall be "st,st-mipid02" +- clocks: reference to the xclk input clock. +- clock-names: shall be "xclk". +- VDDE-supply: sensor digital IO supply. Must be 1.8 volts. +- VDDIN-supply: sensor internal regulator supply. Must be 1.8 volts. + +Optional Properties: +- reset-gpios: reference to the GPIO connected to the xsdn pin, if any. + This is an active low signal to the mipid02. + +Required subnodes: + - ports: A ports node with one port child node per device input and output + port, in accordance with the video interface bindings defined in + Documentation/devicetree/bindings/media/video-interfaces.txt. The + port nodes are numbered as follows: + + Port Description + ----------------------------- + 0 CSI-2 first input port + 1 CSI-2 second input port + 2 PARALLEL output + +Endpoint node required property for CSI-2 connection is: +- data-lanes: shall be <1> for Port 1. for Port 0 dual-lane operation shall be +<1 2> or <2 1>. For Port 0 single-lane operation shall be <1> or <2>. +Endpoint node optional property for CSI-2 connection is: +- lane-polarities: any lane can be inverted or not. + +Endpoint node required property for PARALLEL connection is: +- bus-width: shall be set to <6>, <7>, <8>, <10> or <12>. +Endpoint node optional properties for PARALLEL connection are: +- hsync-active: active state of the HSYNC signal, 0/1 for LOW/HIGH respectively. +LOW being the default. +- vsync-active: active state of the VSYNC signal, 0/1 for LOW/HIGH respectively. +LOW being the default. + +Example: + +mipid02: csi2rx@14 { + compatible = "st,st-mipid02"; + reg = <0x14>; + status = "okay"; + clocks = <&clk_ext_camera_12>; + clock-names = "xclk"; + VDDE-supply = <&vdd>; + VDDIN-supply = <&vdd>; + ports { + #address-cells = <1>; + #size-cells = <0>; + port@0 { + reg = <0>; + + ep0: endpoint { + data-lanes = <1 2>; + remote-endpoint = <&mipi_csi2_in>; + }; + }; + port@2 { + reg = <2>; + + ep2: endpoint { + bus-width = <8>; + hsync-active = <0>; + vsync-active = <0>; + remote-endpoint = <¶llel_out>; + }; + }; + }; +}; diff --git a/Documentation/devicetree/bindings/media/meson-ao-cec.txt b/Documentation/devicetree/bindings/media/meson-ao-cec.txt index 8671bdb08080..c67fc41d4aa2 100644 --- a/Documentation/devicetree/bindings/media/meson-ao-cec.txt +++ b/Documentation/devicetree/bindings/media/meson-ao-cec.txt @@ -4,16 +4,23 @@ The Amlogic Meson AO-CEC module is present is Amlogic SoCs and its purpose is to handle communication between HDMI connected devices over the CEC bus. Required properties: - - compatible : value should be following + - compatible : value should be following depending on the SoC : + For GXBB, GXL, GXM and G12A (AO_CEC_A module) : "amlogic,meson-gx-ao-cec" + For G12A (AO_CEC_B module) : + "amlogic,meson-g12a-ao-cec" - reg : Physical base address of the IP registers and length of memory mapped region. - interrupts : AO-CEC interrupt number to the CPU. - clocks : from common clock binding: handle to AO-CEC clock. - - clock-names : from common clock binding: must contain "core", - corresponding to entry in the clocks property. + - clock-names : from common clock binding, must contain : + For GXBB, GXL, GXM and G12A (AO_CEC_A module) : + - "core" + For G12A (AO_CEC_B module) : + - "oscin" + corresponding to entry in the clocks property. - hdmi-phandle: phandle to the HDMI controller Example: diff --git a/Documentation/devicetree/bindings/media/rcar_imr.txt b/Documentation/devicetree/bindings/media/rcar_imr.txt new file mode 100644 index 000000000000..b0614153ed36 --- /dev/null +++ b/Documentation/devicetree/bindings/media/rcar_imr.txt @@ -0,0 +1,31 @@ +Renesas R-Car Image Renderer (Distortion Correction Engine) +----------------------------------------------------------- + +The image renderer, or the distortion correction engine, is a drawing processor +with a simple instruction system capable of referencing video capture data or +data in an external memory as 2D texture data and performing texture mapping +and drawing with respect to any shape that is split into triangular objects. + +Required properties: + +- compatible: "renesas,<soctype>-imr-lx4", "renesas,imr-lx4" as a fallback for + the image renderer light extended 4 (IMR-LX4) found in the R-Car gen3 SoCs, + where the examples with <soctype> are: + - "renesas,r8a7795-imr-lx4" for R-Car H3, + - "renesas,r8a7796-imr-lx4" for R-Car M3-W. +- reg: offset and length of the register block; +- interrupts: single interrupt specifier; +- clocks: single clock phandle/specifier pair; +- power-domains: power domain phandle/specifier pair; +- resets: reset phandle/specifier pair. + +Example: + + imr-lx4@fe860000 { + compatible = "renesas,r8a7795-imr-lx4", "renesas,imr-lx4"; + reg = <0 0xfe860000 0 0x2000>; + interrupts = <GIC_SPI 192 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&cpg CPG_MOD 823>; + power-domains = <&sysc R8A7795_PD_A3VC>; + resets = <&cpg 823>; + }; diff --git a/Documentation/devicetree/bindings/media/rcar_vin.txt b/Documentation/devicetree/bindings/media/rcar_vin.txt index 224a4615b418..aa217b096279 100644 --- a/Documentation/devicetree/bindings/media/rcar_vin.txt +++ b/Documentation/devicetree/bindings/media/rcar_vin.txt @@ -13,6 +13,7 @@ on Gen3 and RZ/G2 platforms to a CSI-2 receiver. - "renesas,vin-r8a7743" for the R8A7743 device - "renesas,vin-r8a7744" for the R8A7744 device - "renesas,vin-r8a7745" for the R8A7745 device + - "renesas,vin-r8a774a1" for the R8A774A1 device - "renesas,vin-r8a774c0" for the R8A774C0 device - "renesas,vin-r8a7778" for the R8A7778 device - "renesas,vin-r8a7779" for the R8A7779 device diff --git a/Documentation/devicetree/bindings/media/renesas,rcar-csi2.txt b/Documentation/devicetree/bindings/media/renesas,rcar-csi2.txt index d63275e17afd..331409259752 100644 --- a/Documentation/devicetree/bindings/media/renesas,rcar-csi2.txt +++ b/Documentation/devicetree/bindings/media/renesas,rcar-csi2.txt @@ -8,6 +8,7 @@ R-Car VIN module, which provides the video capture capabilities. Mandatory properties -------------------- - compatible: Must be one or more of the following + - "renesas,r8a774a1-csi2" for the R8A774A1 device. - "renesas,r8a774c0-csi2" for the R8A774C0 device. - "renesas,r8a7795-csi2" for the R8A7795 device. - "renesas,r8a7796-csi2" for the R8A7796 device. @@ -18,7 +19,8 @@ Mandatory properties - reg: the register base and size for the device registers - interrupts: the interrupt for the device - - clocks: reference to the parent clock + - clocks: A phandle + clock specifier for the module clock + - resets: A phandle + reset specifier for the module reset The device node shall contain two 'port' child nodes according to the bindings defined in Documentation/devicetree/bindings/media/ diff --git a/Documentation/media/index.rst b/Documentation/media/index.rst index 0a222fc1d7ca..0301c25ff887 100644 --- a/Documentation/media/index.rst +++ b/Documentation/media/index.rst @@ -18,7 +18,7 @@ Linux Media Subsystem Documentation v4l-drivers/index cec-drivers/index -.. only:: subproject +.. only:: html and subproject Indices ======= diff --git a/Documentation/media/kapi/mc-core.rst b/Documentation/media/kapi/mc-core.rst index f930725e0d6b..05bba0b61748 100644 --- a/Documentation/media/kapi/mc-core.rst +++ b/Documentation/media/kapi/mc-core.rst @@ -259,6 +259,45 @@ Subsystems should facilitate link validation by providing subsystem specific helper functions to provide easy access for commonly needed information, and in the end provide a way to use driver-specific callbacks. +Media Controller Device Allocator API +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +When the media device belongs to more than one driver, the shared media +device is allocated with the shared struct device as the key for look ups. + +The shared media device should stay in registered state until the last +driver unregisters it. In addition, the media device should be released when +all the references are released. Each driver gets a reference to the media +device during probe, when it allocates the media device. If media device is +already allocated, the allocate API bumps up the refcount and returns the +existing media device. The driver puts the reference back in its disconnect +routine when it calls :c:func:`media_device_delete()`. + +The media device is unregistered and cleaned up from the kref put handler to +ensure that the media device stays in registered state until the last driver +unregisters the media device. + +**Driver Usage** + +Drivers should use the appropriate media-core routines to manage the shared +media device life-time handling the two states: +1. allocate -> register -> delete +2. get reference to already registered device -> delete + +call :c:func:`media_device_delete()` routine to make sure the shared media +device delete is handled correctly. + +**driver probe:** +Call :c:func:`media_device_usb_allocate()` to allocate or get a reference +Call :c:func:`media_device_register()`, if media devnode isn't registered + +**driver disconnect:** +Call :c:func:`media_device_delete()` to free the media_device. Freeing is +handled by the kref put handler. + +API Definitions +^^^^^^^^^^^^^^^ + .. kernel-doc:: include/media/media-device.h .. kernel-doc:: include/media/media-devnode.h @@ -266,3 +305,5 @@ in the end provide a way to use driver-specific callbacks. .. kernel-doc:: include/media/media-entity.h .. kernel-doc:: include/media/media-request.h + +.. kernel-doc:: include/media/media-dev-allocator.h diff --git a/Documentation/media/lirc.h.rst.exceptions b/Documentation/media/lirc.h.rst.exceptions index 7a8b8ff4f076..ac768d769113 100644 --- a/Documentation/media/lirc.h.rst.exceptions +++ b/Documentation/media/lirc.h.rst.exceptions @@ -63,6 +63,7 @@ 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 diff --git a/Documentation/media/uapi/mediactl/request-api.rst b/Documentation/media/uapi/mediactl/request-api.rst index 1ad631e549fe..a74c82d95609 100644 --- a/Documentation/media/uapi/mediactl/request-api.rst +++ b/Documentation/media/uapi/mediactl/request-api.rst @@ -93,7 +93,7 @@ A queued request cannot be modified anymore. .. caution:: For :ref:`memory-to-memory devices <mem2mem>` 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 ``EACCES`` error. + 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 diff --git a/Documentation/media/uapi/v4l/buffer.rst b/Documentation/media/uapi/v4l/buffer.rst index 81ffdcb89057..1cbd9cde57f3 100644 --- a/Documentation/media/uapi/v4l/buffer.rst +++ b/Documentation/media/uapi/v4l/buffer.rst @@ -165,7 +165,7 @@ of appropriately sized buffers for each use case). struct v4l2_buffer ================== -.. tabularcolumns:: |p{2.8cm}|p{2.5cm}|p{1.3cm}|p{10.5cm}| +.. tabularcolumns:: |p{2.8cm}|p{2.5cm}|p{1.6cm}|p{10.2cm}| .. cssclass:: longtable @@ -326,7 +326,7 @@ struct v4l2_buffer Applications should not set ``V4L2_BUF_FLAG_REQUEST_FD`` for any ioctls other than :ref:`VIDIOC_QBUF <VIDIOC_QBUF>`. - If the device does not support requests, then ``EACCES`` will be returned. + 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. @@ -420,7 +420,7 @@ enum v4l2_buf_type .. cssclass:: longtable -.. tabularcolumns:: |p{7.2cm}|p{0.6cm}|p{9.7cm}| +.. tabularcolumns:: |p{7.8cm}|p{0.6cm}|p{9.1cm}| .. flat-table:: :header-rows: 0 @@ -482,7 +482,11 @@ enum v4l2_buf_type Buffer Flags ============ -.. tabularcolumns:: |p{7.0cm}|p{2.2cm}|p{8.3cm}| +.. raw:: latex + + \small + +.. tabularcolumns:: |p{7.0cm}|p{2.1cm}|p{8.4cm}| .. cssclass:: longtable @@ -681,6 +685,9 @@ Buffer Flags 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 @@ -688,7 +695,7 @@ Buffer Flags enum v4l2_memory ================ -.. tabularcolumns:: |p{6.6cm}|p{2.2cm}|p{8.7cm}| +.. tabularcolumns:: |p{5.0cm}|p{0.8cm}|p{11.7cm}| .. flat-table:: :header-rows: 0 @@ -724,7 +731,7 @@ The :c:type:`v4l2_buffer_timecode` structure is designed to hold a struct v4l2_timecode -------------------- -.. tabularcolumns:: |p{4.4cm}|p{4.4cm}|p{8.7cm}| +.. tabularcolumns:: |p{1.4cm}|p{2.8cm}|p{12.3cm}| .. flat-table:: :header-rows: 0 @@ -761,7 +768,7 @@ struct v4l2_timecode Timecode Types -------------- -.. tabularcolumns:: |p{6.6cm}|p{2.2cm}|p{8.7cm}| +.. tabularcolumns:: |p{5.6cm}|p{0.8cm}|p{11.1cm}| .. flat-table:: :header-rows: 0 diff --git a/Documentation/media/uapi/v4l/colorspaces-defs.rst b/Documentation/media/uapi/v4l/colorspaces-defs.rst index c4e8fc620379..e122bbe3d799 100644 --- a/Documentation/media/uapi/v4l/colorspaces-defs.rst +++ b/Documentation/media/uapi/v4l/colorspaces-defs.rst @@ -39,7 +39,7 @@ whole range, 0-255, dividing the angular value by 1.41. The enum colorspaces except for BT.2020 which uses limited range R'G'B' quantization. -.. tabularcolumns:: |p{6.0cm}|p{11.5cm}| +.. tabularcolumns:: |p{6.7cm}|p{10.8cm}| .. c:type:: v4l2_colorspace @@ -112,7 +112,7 @@ whole range, 0-255, dividing the angular value by 1.41. The enum .. c:type:: v4l2_ycbcr_encoding -.. tabularcolumns:: |p{6.5cm}|p{11.0cm}| +.. tabularcolumns:: |p{7.2cm}|p{10.3cm}| .. flat-table:: V4L2 Y'CbCr Encodings :header-rows: 1 diff --git a/Documentation/media/uapi/v4l/colorspaces.rst b/Documentation/media/uapi/v4l/colorspaces.rst index c5a560f0c13d..4f6c82fa057f 100644 --- a/Documentation/media/uapi/v4l/colorspaces.rst +++ b/Documentation/media/uapi/v4l/colorspaces.rst @@ -56,9 +56,9 @@ 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) + x = X / (X + Y + Z) -y = Y / (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 diff --git a/Documentation/media/uapi/v4l/dev-raw-vbi.rst b/Documentation/media/uapi/v4l/dev-raw-vbi.rst index d6a707f0b24f..e06b03ca2ab2 100644 --- a/Documentation/media/uapi/v4l/dev-raw-vbi.rst +++ b/Documentation/media/uapi/v4l/dev-raw-vbi.rst @@ -106,7 +106,7 @@ VBI devices must implement both the :ref:`VIDIOC_G_FMT <VIDIOC_G_FMT>` and and always returns default parameters as :ref:`VIDIOC_G_FMT <VIDIOC_G_FMT>` does. :ref:`VIDIOC_TRY_FMT <VIDIOC_G_FMT>` is optional. -.. tabularcolumns:: |p{2.4cm}|p{4.4cm}|p{10.7cm}| +.. tabularcolumns:: |p{1.6cm}|p{4.2cm}|p{11.7cm}| .. c:type:: v4l2_vbi_format @@ -190,7 +190,7 @@ and always returns default parameters as :ref:`VIDIOC_G_FMT <VIDIOC_G_FMT>` does applications must set it to zero. -.. tabularcolumns:: |p{4.0cm}|p{1.5cm}|p{12.0cm}| +.. tabularcolumns:: |p{4.4cm}|p{1.5cm}|p{11.6cm}| .. _vbifmt-flags: diff --git a/Documentation/media/uapi/v4l/dev-rds.rst b/Documentation/media/uapi/v4l/dev-rds.rst index 624d6f95b842..64a724ef58f5 100644 --- a/Documentation/media/uapi/v4l/dev-rds.rst +++ b/Documentation/media/uapi/v4l/dev-rds.rst @@ -146,7 +146,7 @@ RDS datastructures .. _v4l2-rds-block-codes: -.. tabularcolumns:: |p{5.6cm}|p{2.0cm}|p{1.5cm}|p{7.0cm}| +.. tabularcolumns:: |p{6.4cm}|p{2.0cm}|p{1.2cm}|p{7.9cm}| .. flat-table:: Block defines :header-rows: 0 diff --git a/Documentation/media/uapi/v4l/dev-sliced-vbi.rst b/Documentation/media/uapi/v4l/dev-sliced-vbi.rst index 0aa6cb8a272b..e86346f66017 100644 --- a/Documentation/media/uapi/v4l/dev-sliced-vbi.rst +++ b/Documentation/media/uapi/v4l/dev-sliced-vbi.rst @@ -118,7 +118,7 @@ struct v4l2_sliced_vbi_format \scriptsize \setlength{\tabcolsep}{2pt} -.. tabularcolumns:: |p{.75cm}|p{3.3cm}|p{3.4cm}|p{3.4cm}|p{3.4cm}| +.. tabularcolumns:: |p{.85cm}|p{3.3cm}|p{4.4cm}|p{4.4cm}|p{4.4cm}| .. cssclass:: longtable @@ -223,7 +223,7 @@ Sliced VBI services .. raw:: latex - \footnotesize + \scriptsize .. tabularcolumns:: |p{4.1cm}|p{1.1cm}|p{2.4cm}|p{2.0cm}|p{7.3cm}| @@ -541,7 +541,7 @@ Magic Constants for struct v4l2_mpeg_vbi_fmt_ivtv magic field structs v4l2_mpeg_vbi_itv0 and v4l2_mpeg_vbi_ITV0 ------------------------------------------------- -.. tabularcolumns:: |p{4.9cm}|p{2.4cm}|p{10.2cm}| +.. tabularcolumns:: |p{5.2cm}|p{2.4cm}|p{9.9cm}| .. flat-table:: :header-rows: 0 @@ -561,12 +561,12 @@ structs v4l2_mpeg_vbi_itv0 and v4l2_mpeg_vbi_ITV0 :: - linemask[0] b0: line 6 first field - linemask[0] b17: line 23 first field - linemask[0] b18: line 6 second field - linemask[0] b31: line 19 second field - linemask[1] b0: line 20 second field - linemask[1] b3: line 23 second field + linemask[0] b0: line 6 first field + linemask[0] b17: line 23 first field + linemask[0] b18: line 6 second field + linemask[0] b31: line 19 second field + linemask[1] b0: line 20 second field + linemask[1] b3: line 23 second field linemask[1] b4-b31: unused and set to 0 * - struct :c:type:`v4l2_mpeg_vbi_itv0_line` @@ -590,7 +590,7 @@ structs v4l2_mpeg_vbi_itv0 and v4l2_mpeg_vbi_ITV0 struct v4l2_mpeg_vbi_ITV0 ------------------------- -.. tabularcolumns:: |p{4.9cm}|p{4.4cm}|p{8.2cm}| +.. tabularcolumns:: |p{5.2cm}|p{2.4cm}|p{9.9cm}| .. flat-table:: :header-rows: 0 @@ -635,7 +635,7 @@ struct v4l2_mpeg_vbi_itv0_line Line Identifiers for struct v4l2_mpeg_vbi_itv0_line id field ------------------------------------------------------------ -.. tabularcolumns:: |p{6.6cm}|p{2.2cm}|p{8.7cm}| +.. tabularcolumns:: |p{7.0cm}|p{1.8cm}|p{8.7cm}| .. flat-table:: :header-rows: 1 diff --git a/Documentation/media/uapi/v4l/dev-subdev.rst b/Documentation/media/uapi/v4l/dev-subdev.rst index 2c2768c7343b..029bb2d9928a 100644 --- a/Documentation/media/uapi/v4l/dev-subdev.rst +++ b/Documentation/media/uapi/v4l/dev-subdev.rst @@ -211,7 +211,7 @@ list entity names and pad numbers). .. raw:: latex - \tiny + \scriptsize .. tabularcolumns:: |p{2.0cm}|p{2.3cm}|p{2.3cm}|p{2.3cm}|p{2.3cm}|p{2.3cm}|p{2.3cm}| @@ -223,40 +223,80 @@ list entity names and pad numbers). :widths: 5 5 5 5 5 5 5 * - - - Sensor/0 format - - Frontend/0 format - - Frontend/1 format - - Scaler/0 format - - Scaler/0 compose selection rectangle - - Scaler/1 format + - Sensor/0 + + format + - Frontend/0 + + format + - Frontend/1 + + format + - Scaler/0 + + format + - Scaler/0 + + compose selection rectangle + - Scaler/1 + + format * - Initial state - - 2048x1536/SGRBG8_1X8 + - 2048x1536 + + SGRBG8_1X8 - (default) - (default) - (default) - (default) - (default) * - Configure frontend sink format - - 2048x1536/SGRBG8_1X8 - - *2048x1536/SGRBG8_1X8* - - *2046x1534/SGRBG8_1X8* + - 2048x1536 + + SGRBG8_1X8 + - *2048x1536* + + *SGRBG8_1X8* + - *2046x1534* + + *SGRBG8_1X8* - (default) - (default) - (default) * - Configure scaler sink format - - 2048x1536/SGRBG8_1X8 - - 2048x1536/SGRBG8_1X8 - - 2046x1534/SGRBG8_1X8 - - *2046x1534/SGRBG8_1X8* + - 2048x1536 + + SGRBG8_1X8 + - 2048x1536 + + SGRBG8_1X8 + - 2046x1534 + + SGRBG8_1X8 + - *2046x1534* + + *SGRBG8_1X8* - *0,0/2046x1534* - - *2046x1534/SGRBG8_1X8* + - *2046x1534* + + *SGRBG8_1X8* * - Configure scaler sink compose selection - - 2048x1536/SGRBG8_1X8 - - 2048x1536/SGRBG8_1X8 - - 2046x1534/SGRBG8_1X8 - - 2046x1534/SGRBG8_1X8 + - 2048x1536 + + SGRBG8_1X8 + - 2048x1536 + + SGRBG8_1X8 + - 2046x1534 + + SGRBG8_1X8 + - 2046x1534 + + SGRBG8_1X8 - *0,0/1280x960* - - *1280x960/SGRBG8_1X8* + - *1280x960* + + *SGRBG8_1X8* .. raw:: latex diff --git a/Documentation/media/uapi/v4l/ext-ctrls-camera.rst b/Documentation/media/uapi/v4l/ext-ctrls-camera.rst index d3a553cd86c9..51c1d5c9eb00 100644 --- a/Documentation/media/uapi/v4l/ext-ctrls-camera.rst +++ b/Documentation/media/uapi/v4l/ext-ctrls-camera.rst @@ -88,7 +88,7 @@ enum v4l2_exposure_metering - Determines how the camera measures the amount of light available for the frame exposure. Possible values are: -.. tabularcolumns:: |p{8.5cm}|p{9.0cm}| +.. tabularcolumns:: |p{8.7cm}|p{8.8cm}| .. flat-table:: :header-rows: 0 @@ -180,7 +180,7 @@ enum v4l2_exposure_metering - control may stop updates of the ``V4L2_CID_AUTO_FOCUS_STATUS`` control value. -.. tabularcolumns:: |p{6.5cm}|p{11.0cm}| +.. tabularcolumns:: |p{6.7cm}|p{10.8cm}| .. flat-table:: :header-rows: 0 @@ -206,7 +206,7 @@ enum v4l2_exposure_metering - enum v4l2_auto_focus_range - Determines auto focus distance range for which lens may be adjusted. -.. tabularcolumns:: |p{6.5cm}|p{11.0cm}| +.. tabularcolumns:: |p{6.8cm}|p{10.7cm}| .. flat-table:: :header-rows: 0 @@ -281,7 +281,7 @@ enum v4l2_auto_n_preset_white_balance - representation. The following white balance presets are listed in order of increasing color temperature. -.. tabularcolumns:: |p{7.0 cm}|p{10.5cm}| +.. tabularcolumns:: |p{7.2 cm}|p{10.3cm}| .. flat-table:: :header-rows: 0 @@ -387,7 +387,11 @@ enum v4l2_scene_mode - to ``V4L2_SCENE_MODE_NONE`` to make sure the other possibly related controls are accessible. The following scene programs are defined: -.. tabularcolumns:: |p{6.0cm}|p{11.5cm}| +.. raw:: latex + + \small + +.. tabularcolumns:: |p{5.9cm}|p{11.5cm}| .. flat-table:: :header-rows: 0 @@ -459,6 +463,9 @@ enum v4l2_scene_mode - may be switched to close-up mode and this setting may also involve some lens-distortion correction. +.. raw:: latex + + \normalsize ``V4L2_CID_3A_LOCK (bitmask)`` diff --git a/Documentation/media/uapi/v4l/ext-ctrls-codec.rst b/Documentation/media/uapi/v4l/ext-ctrls-codec.rst index c97fb7923be5..4a8446203085 100644 --- a/Documentation/media/uapi/v4l/ext-ctrls-codec.rst +++ b/Documentation/media/uapi/v4l/ext-ctrls-codec.rst @@ -105,7 +105,7 @@ enum v4l2_mpeg_stream_vbi_fmt - -.. tabularcolumns:: |p{6 cm}|p{11.5cm}| +.. tabularcolumns:: |p{6.6 cm}|p{10.9cm}| .. flat-table:: :header-rows: 0 @@ -477,7 +477,7 @@ enum v4l2_mpeg_audio_dec_playback - -.. tabularcolumns:: |p{9.0cm}|p{8.5cm}| +.. tabularcolumns:: |p{9.8cm}|p{7.7cm}| .. flat-table:: :header-rows: 0 @@ -888,7 +888,7 @@ enum v4l2_mpeg_video_multi_slice_mode - -.. tabularcolumns:: |p{8.7cm}|p{8.8cm}| +.. tabularcolumns:: |p{9.6cm}|p{7.9cm}| .. flat-table:: :header-rows: 0 @@ -923,9 +923,11 @@ enum v4l2_mpeg_video_multi_slice_mode - enum v4l2_mpeg_video_h264_loop_filter_mode - Loop filter mode for H264 encoder. Possible values are: +.. raw:: latex + \small -.. tabularcolumns:: |p{14.0cm}|p{3.5cm}| +.. tabularcolumns:: |p{13.6cm}|p{3.9cm}| .. flat-table:: :header-rows: 0 @@ -938,6 +940,9 @@ enum v4l2_mpeg_video_h264_loop_filter_mode - * - ``V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY`` - Loop filter is disabled at the slice boundary. +.. raw:: latex + + \normalsize ``V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_ALPHA (integer)`` @@ -964,6 +969,8 @@ enum v4l2_mpeg_video_h264_entropy_mode - encoder. Possible values are: +.. tabularcolumns:: |p{9.0cm}|p{8.5cm}| + .. flat-table:: :header-rows: 0 @@ -1048,6 +1055,30 @@ enum v4l2_mpeg_video_h264_entropy_mode - Quantization parameter for an B frame for H264. Valid range: from 0 to 51. +``V4L2_CID_MPEG_VIDEO_H264_I_FRAME_MIN_QP (integer)`` + Minimum quantization parameter for the H264 I frame to limit I frame + quality to a range. Valid range: from 0 to 51. If + V4L2_CID_MPEG_VIDEO_H264_MIN_QP is also set, the quantization parameter + should be chosen to meet both requirements. + +``V4L2_CID_MPEG_VIDEO_H264_I_FRAME_MAX_QP (integer)`` + Maximum quantization parameter for the H264 I frame to limit I frame + quality to a range. Valid range: from 0 to 51. If + V4L2_CID_MPEG_VIDEO_H264_MAX_QP is also set, the quantization parameter + should be chosen to meet both requirements. + +``V4L2_CID_MPEG_VIDEO_H264_P_FRAME_MIN_QP (integer)`` + Minimum quantization parameter for the H264 P frame to limit P frame + quality to a range. Valid range: from 0 to 51. If + V4L2_CID_MPEG_VIDEO_H264_MIN_QP is also set, the quantization parameter + should be chosen to meet both requirements. + +``V4L2_CID_MPEG_VIDEO_H264_P_FRAME_MAX_QP (integer)`` + Maximum quantization parameter for the H264 P frame to limit P frame + quality to a range. Valid range: from 0 to 51. If + V4L2_CID_MPEG_VIDEO_H264_MAX_QP is also set, the quantization parameter + should be chosen to meet both requirements. + ``V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP (integer)`` Quantization parameter for an I frame for MPEG4. Valid range: from 1 to 31. @@ -1129,7 +1160,9 @@ enum v4l2_mpeg_video_header_mode - it returned together with the first frame. Applicable to encoders. Possible values are: +.. raw:: latex + \small .. tabularcolumns:: |p{10.3cm}|p{7.2cm}| @@ -1143,6 +1176,9 @@ enum v4l2_mpeg_video_header_mode - - The stream header is returned together with the first encoded frame. +.. raw:: latex + + \normalsize ``V4L2_CID_MPEG_VIDEO_REPEAT_SEQ_HEADER (boolean)`` @@ -1181,6 +1217,10 @@ enum v4l2_mpeg_video_h264_sei_fp_arrangement_type - Frame packing arrangement type for H264 SEI. Applicable to the H264 encoder. Possible values are: +.. raw:: latex + + \small + .. tabularcolumns:: |p{12cm}|p{5.5cm}| .. flat-table:: @@ -1200,6 +1240,10 @@ enum v4l2_mpeg_video_h264_sei_fp_arrangement_type - * - ``V4L2_MPEG_VIDEO_H264_SEI_FP_ARRANGEMENT_TYPE_TEMPORAL`` - One view per frame. +.. raw:: latex + + \normalsize + ``V4L2_CID_MPEG_VIDEO_H264_FMO (boolean)`` @@ -1217,6 +1261,10 @@ enum v4l2_mpeg_video_h264_fmo_map_type - patterns of macroblocks. Applicable to the H264 encoder. Possible values are: +.. raw:: latex + + \small + .. tabularcolumns:: |p{12.5cm}|p{5.0cm}| .. flat-table:: @@ -1240,6 +1288,10 @@ enum v4l2_mpeg_video_h264_fmo_map_type - * - ``V4L2_MPEG_VIDEO_H264_FMO_MAP_TYPE_EXPLICIT`` - User defined map type. +.. raw:: latex + + \normalsize + ``V4L2_CID_MPEG_VIDEO_H264_FMO_SLICE_GROUP (integer)`` @@ -1361,6 +1413,8 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type - .. cssclass:: longtable +.. tabularcolumns:: |p{5.8cm}|p{4.8cm}|p{6.6cm}| + .. flat-table:: struct v4l2_ctrl_mpeg2_slice_params :header-rows: 0 :stub-columns: 0 @@ -1402,6 +1456,8 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type - .. cssclass:: longtable +.. tabularcolumns:: |p{1.5cm}|p{6.3cm}|p{9.4cm}| + .. flat-table:: struct v4l2_mpeg2_sequence :header-rows: 0 :stub-columns: 0 @@ -1433,6 +1489,8 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type - .. cssclass:: longtable +.. tabularcolumns:: |p{1.5cm}|p{6.3cm}|p{9.4cm}| + .. flat-table:: struct v4l2_mpeg2_picture :header-rows: 0 :stub-columns: 0 @@ -1492,6 +1550,12 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type - .. cssclass:: longtable +.. tabularcolumns:: |p{1.2cm}|p{8.0cm}|p{7.4cm}| + +.. raw:: latex + + \small + .. flat-table:: struct v4l2_ctrl_mpeg2_quantization :header-rows: 0 :stub-columns: 0 @@ -1537,6 +1601,19 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type - non-intra-coded frames, in zigzag scanning order. Only relevant for non-4:2:0 YUV formats. +``V4L2_CID_FWHT_I_FRAME_QP (integer)`` + Quantization parameter for an I frame for FWHT. Valid range: from 1 + to 31. + +``V4L2_CID_FWHT_P_FRAME_QP (integer)`` + Quantization parameter for a P frame for FWHT. Valid range: from 1 + to 31. + +.. raw:: latex + + \normalsize + + MFC 5.1 MPEG Controls ===================== @@ -1644,7 +1721,11 @@ enum v4l2_mpeg_mfc51_video_frame_skip_mode - are: -.. tabularcolumns:: |p{9.0cm}|p{8.5cm}| +.. tabularcolumns:: |p{9.2cm}|p{8.3cm}| + +.. raw:: latex + + \small .. flat-table:: :header-rows: 0 @@ -1659,7 +1740,9 @@ enum v4l2_mpeg_mfc51_video_frame_skip_mode - - Frame skip mode enabled and buffer limit is set by the VBV (MPEG1/2/4) or CPB (H264) buffer size control. +.. raw:: latex + \normalsize ``V4L2_CID_MPEG_MFC51_VIDEO_RC_FIXED_TARGET_BIT (integer)`` Enable rate-control with fixed target bit. If this setting is @@ -1682,7 +1765,7 @@ enum v4l2_mpeg_mfc51_video_force_frame_type - Force a frame type for the next queued buffer. Applicable to encoders. Possible values are: - +.. tabularcolumns:: |p{9.5cm}|p{8.0cm}| .. flat-table:: :header-rows: 0 @@ -1696,6 +1779,125 @@ enum v4l2_mpeg_mfc51_video_force_frame_type - - Force a non-coded frame. +.. _v4l2-mpeg-fwht: + +``V4L2_CID_MPEG_VIDEO_FWHT_PARAMS (struct)`` + Specifies the fwht parameters (as extracted from the bitstream) for the + associated FWHT data. This includes the necessary parameters for + configuring a stateless hardware decoding pipeline for FWHT. + + .. note:: + + This compound control is not yet part of the public kernel API and + it is expected to change. + +.. c:type:: v4l2_ctrl_fwht_params + +.. cssclass:: longtable + +.. tabularcolumns:: |p{1.4cm}|p{4.3cm}|p{11.8cm}| + +.. flat-table:: struct v4l2_ctrl_fwht_params + :header-rows: 0 + :stub-columns: 0 + :widths: 1 1 2 + + * - __u64 + - ``backward_ref_ts`` + - Timestamp of the V4L2 capture buffer to use as backward reference, used + with P-coded frames. The timestamp refers to the + ``timestamp`` field in struct :c:type:`v4l2_buffer`. Use the + :c:func:`v4l2_timeval_to_ns()` function to convert the struct + :c:type:`timeval` in struct :c:type:`v4l2_buffer` to a __u64. + * - __u32 + - ``version`` + - The version of the codec + * - __u32 + - ``width`` + - The width of the frame + * - __u32 + - ``height`` + - The height of the frame + * - __u32 + - ``flags`` + - The flags of the frame, see :ref:`fwht-flags`. + * - __u32 + - ``colorspace`` + - The colorspace of the frame, from enum :c:type:`v4l2_colorspace`. + * - __u32 + - ``xfer_func`` + - The transfer function, from enum :c:type:`v4l2_xfer_func`. + * - __u32 + - ``ycbcr_enc`` + - The Y'CbCr encoding, from enum :c:type:`v4l2_ycbcr_encoding`. + * - __u32 + - ``quantization`` + - The quantization range, from enum :c:type:`v4l2_quantization`. + + + +.. _fwht-flags: + +FWHT Flags +============ + +.. cssclass:: longtable + +.. tabularcolumns:: |p{6.8cm}|p{2.4cm}|p{8.3cm}| + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + :widths: 3 1 4 + + * - ``FWHT_FL_IS_INTERLACED`` + - 0x00000001 + - Set if this is an interlaced format + * - ``FWHT_FL_IS_BOTTOM_FIRST`` + - 0x00000002 + - Set if this is a bottom-first (NTSC) interlaced format + * - ``FWHT_FL_IS_ALTERNATE`` + - 0x00000004 + - Set if each 'frame' contains just one field + * - ``FWHT_FL_IS_BOTTOM_FIELD`` + - 0x00000008 + - If FWHT_FL_IS_ALTERNATE was set, then this is set if this 'frame' is the + bottom field, else it is the top field. + * - ``FWHT_FL_LUMA_IS_UNCOMPRESSED`` + - 0x00000010 + - Set if the luma plane is uncompressed + * - ``FWHT_FL_CB_IS_UNCOMPRESSED`` + - 0x00000020 + - Set if the cb plane is uncompressed + * - ``FWHT_FL_CR_IS_UNCOMPRESSED`` + - 0x00000040 + - Set if the cr plane is uncompressed + * - ``FWHT_FL_CHROMA_FULL_HEIGHT`` + - 0x00000080 + - Set if the chroma plane has the same height as the luma plane, + else the chroma plane is half the height of the luma plane + * - ``FWHT_FL_CHROMA_FULL_WIDTH`` + - 0x00000100 + - Set if the chroma plane has the same width as the luma plane, + else the chroma plane is half the width of the luma plane + * - ``FWHT_FL_ALPHA_IS_UNCOMPRESSED`` + - 0x00000200 + - Set if the alpha plane is uncompressed + * - ``FWHT_FL_I_FRAME`` + - 0x00000400 + - Set if this is an I-frame + * - ``FWHT_FL_COMPONENTS_NUM_MSK`` + - 0x00070000 + - A 4-values flag - the number of components - 1 + * - ``FWHT_FL_PIXENC_YUV`` + - 0x00080000 + - Set if the pixel encoding is YUV + * - ``FWHT_FL_PIXENC_RGB`` + - 0x00100000 + - Set if the pixel encoding is RGB + * - ``FWHT_FL_PIXENC_HSV`` + - 0x00180000 + - Set if the pixel encoding is HSV CX2341x MPEG Controls @@ -1745,9 +1947,11 @@ enum v4l2_mpeg_cx2341x_video_luma_spatial_filter_type - Select the algorithm to use for the Luma Spatial Filter (default ``1D_HOR``). Possible values: +.. tabularcolumns:: |p{14.5cm}|p{3.0cm}| +.. raw:: latex -.. tabularcolumns:: |p{14.5cm}|p{3.0cm}| + \small .. flat-table:: :header-rows: 0 @@ -1764,6 +1968,10 @@ enum v4l2_mpeg_cx2341x_video_luma_spatial_filter_type - * - ``V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_SYM_NON_SEPARABLE`` - Two-dimensional symmetrical non-separable +.. raw:: latex + + \normalsize + .. _chroma-spatial-filter-type: @@ -1776,6 +1984,7 @@ enum v4l2_mpeg_cx2341x_video_chroma_spatial_filter_type - ``1D_HOR``). Possible values are: +.. tabularcolumns:: |p{14.0cm}|p{3.5cm}| .. flat-table:: :header-rows: 0 @@ -1918,6 +2127,10 @@ enum v4l2_vp8_num_ref_frames - .. tabularcolumns:: |p{7.9cm}|p{9.6cm}| +.. raw:: latex + + \small + .. flat-table:: :header-rows: 0 :stub-columns: 0 @@ -1932,6 +2145,10 @@ enum v4l2_vp8_num_ref_frames - - The last encoded frame, the golden frame and the altref frame will be searched. +.. raw:: latex + + \normalsize + ``V4L2_CID_MPEG_VIDEO_VPX_FILTER_LEVEL (integer)`` @@ -1961,7 +2178,7 @@ enum v4l2_vp8_golden_frame_sel - .. raw:: latex - \footnotesize + \scriptsize .. tabularcolumns:: |p{9.0cm}|p{8.0cm}| @@ -2283,7 +2500,7 @@ enum v4l2_mpeg_video_hevc_loop_filter_mode - \footnotesize -.. tabularcolumns:: |p{10.7cm}|p{6.3cm}| +.. tabularcolumns:: |p{12.1cm}|p{5.4cm}| .. flat-table:: :header-rows: 0 diff --git a/Documentation/media/uapi/v4l/ext-ctrls-detect.rst b/Documentation/media/uapi/v4l/ext-ctrls-detect.rst index 8a45ce642829..80981d0cff42 100644 --- a/Documentation/media/uapi/v4l/ext-ctrls-detect.rst +++ b/Documentation/media/uapi/v4l/ext-ctrls-detect.rst @@ -30,7 +30,7 @@ Detect Control IDs ``V4L2_CID_DETECT_MD_MODE (menu)`` Sets the motion detection mode. -.. tabularcolumns:: |p{7.5cm}|p{10.0cm}| +.. tabularcolumns:: |p{7.7cm}|p{9.8cm}| .. flat-table:: :header-rows: 0 diff --git a/Documentation/media/uapi/v4l/ext-ctrls-dv.rst b/Documentation/media/uapi/v4l/ext-ctrls-dv.rst index 57edf211875c..5c70ac98f710 100644 --- a/Documentation/media/uapi/v4l/ext-ctrls-dv.rst +++ b/Documentation/media/uapi/v4l/ext-ctrls-dv.rst @@ -106,7 +106,7 @@ enum v4l2_dv_it_content_type - or an analog source. The enum v4l2_dv_it_content_type defines the possible content types: -.. tabularcolumns:: |p{7.0cm}|p{10.5cm}| +.. tabularcolumns:: |p{7.3cm}|p{10.4cm}| .. flat-table:: :header-rows: 0 diff --git a/Documentation/media/uapi/v4l/ext-ctrls-flash.rst b/Documentation/media/uapi/v4l/ext-ctrls-flash.rst index 5f30791c35b5..eff056b17167 100644 --- a/Documentation/media/uapi/v4l/ext-ctrls-flash.rst +++ b/Documentation/media/uapi/v4l/ext-ctrls-flash.rst @@ -87,7 +87,7 @@ Flash Control IDs ``V4L2_CID_FLASH_STROBE_SOURCE (menu)`` Defines the source of the flash LED strobe. -.. tabularcolumns:: |p{7.0cm}|p{10.5cm}| +.. tabularcolumns:: |p{7.5cm}|p{10.0cm}| .. flat-table:: :header-rows: 0 @@ -146,7 +146,7 @@ Flash Control IDs an effect is chip dependent. Reading the faults resets the control and returns the chip to a usable state if possible. -.. tabularcolumns:: |p{8.0cm}|p{9.5cm}| +.. tabularcolumns:: |p{8.4cm}|p{9.1cm}| .. flat-table:: :header-rows: 0 diff --git a/Documentation/media/uapi/v4l/ext-ctrls-jpeg.rst b/Documentation/media/uapi/v4l/ext-ctrls-jpeg.rst index cf9cd8a9f9b4..60ce3f949319 100644 --- a/Documentation/media/uapi/v4l/ext-ctrls-jpeg.rst +++ b/Documentation/media/uapi/v4l/ext-ctrls-jpeg.rst @@ -37,7 +37,7 @@ JPEG Control IDs how Cb and Cr components are downsampled after converting an input image from RGB to Y'CbCr color space. -.. tabularcolumns:: |p{7.0cm}|p{10.5cm}| +.. tabularcolumns:: |p{7.5cm}|p{10.0cm}| .. flat-table:: :header-rows: 0 diff --git a/Documentation/media/uapi/v4l/field-order.rst b/Documentation/media/uapi/v4l/field-order.rst index 8415268d439c..3fb473e3b8e2 100644 --- a/Documentation/media/uapi/v4l/field-order.rst +++ b/Documentation/media/uapi/v4l/field-order.rst @@ -64,7 +64,9 @@ enum v4l2_field .. c:type:: v4l2_field -.. tabularcolumns:: |p{6.6cm}|p{2.2cm}|p{8.7cm}| +.. tabularcolumns:: |p{5.8cm}|p{0.6cm}|p{11.1cm}| + +.. cssclass:: longtable .. flat-table:: :header-rows: 0 diff --git a/Documentation/media/uapi/v4l/pixfmt-compressed.rst b/Documentation/media/uapi/v4l/pixfmt-compressed.rst index 2675bef3eefe..6c961cfb74da 100644 --- a/Documentation/media/uapi/v4l/pixfmt-compressed.rst +++ b/Documentation/media/uapi/v4l/pixfmt-compressed.rst @@ -125,3 +125,9 @@ Compressed Formats - Video elementary stream using a codec based on the Fast Walsh Hadamard Transform. This codec is implemented by the vicodec ('Virtual Codec') driver. See the codec-fwht.h header for more details. + * .. _V4L2-PIX-FMT-FWHT-STATELESS: + + - ``V4L2_PIX_FMT_FWHT_STATELESS`` + - 'SFWH' + - Same format as V4L2_PIX_FMT_FWHT but requires stateless codec implementation. + See the :ref:`associated Codec Control IDs <v4l2-mpeg-fwht>`. diff --git a/Documentation/media/uapi/v4l/pixfmt-meta-d4xx.rst b/Documentation/media/uapi/v4l/pixfmt-meta-d4xx.rst index 862e1f327150..87e8fd7d5d02 100644 --- a/Documentation/media/uapi/v4l/pixfmt-meta-d4xx.rst +++ b/Documentation/media/uapi/v4l/pixfmt-meta-d4xx.rst @@ -36,13 +36,16 @@ per frame, therefore their headers cannot be larger than 255 bytes. Below are proprietary Microsoft style metadata types, used by D4xx cameras, where all fields are in little endian order: +.. tabularcolumns:: |p{5.0cm}|p{12.5cm}| + + .. flat-table:: D4xx metadata - :widths: 1 4 + :widths: 1 2 :header-rows: 1 :stub-columns: 0 - * - Field - - Description + * - **Field** + - **Description** * - :cspan:`1` *Depth Control* * - __u32 ID - 0x80000000 diff --git a/Documentation/media/uapi/v4l/pixfmt-meta-vsp1-hgt.rst b/Documentation/media/uapi/v4l/pixfmt-meta-vsp1-hgt.rst index 2ebccdcca95d..d1a341af9c48 100644 --- a/Documentation/media/uapi/v4l/pixfmt-meta-vsp1-hgt.rst +++ b/Documentation/media/uapi/v4l/pixfmt-meta-vsp1-hgt.rst @@ -41,6 +41,10 @@ The Hue position **m** (0 - 5) of the bucket in the matrix depends on how the HGT Hue areas are configured. There are 6 user configurable Hue Areas which can be configured to cover overlapping Hue values: +.. raw:: latex + + \small + :: Area 0 Area 1 Area 2 Area 3 Area 4 Area 5 @@ -53,6 +57,11 @@ Areas which can be configured to cover overlapping Hue values: 5U 0L 0U 1L 1U 2L 2U 3L 3U 4L 4U 5L 5U 0L <0..............................Hue Value............................255> + +.. raw:: latex + + \normalsize + When two consecutive areas don't overlap (n+1L is equal to nU) the boundary value is considered as part of the lower area. diff --git a/Documentation/media/uapi/v4l/pixfmt-packed-hsv.rst b/Documentation/media/uapi/v4l/pixfmt-packed-hsv.rst index 38b1895a509f..dfc4a8367b3d 100644 --- a/Documentation/media/uapi/v4l/pixfmt-packed-hsv.rst +++ b/Documentation/media/uapi/v4l/pixfmt-packed-hsv.rst @@ -31,7 +31,7 @@ The values are packed in 24 or 32 bit formats. \tiny \setlength{\tabcolsep}{2pt} -.. tabularcolumns:: |p{2.0cm}|p{0.54cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}| +.. tabularcolumns:: |p{2.6cm}|p{0.8cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}| .. _packed-hsv-formats: diff --git a/Documentation/media/uapi/v4l/pixfmt-packed-rgb.rst b/Documentation/media/uapi/v4l/pixfmt-packed-rgb.rst index 6b3781c04dd5..738bb14c0ee2 100644 --- a/Documentation/media/uapi/v4l/pixfmt-packed-rgb.rst +++ b/Documentation/media/uapi/v4l/pixfmt-packed-rgb.rst @@ -27,7 +27,7 @@ next to each other in memory. \tiny \setlength{\tabcolsep}{2pt} -.. tabularcolumns:: |p{2.3cm}|p{1.6cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}| +.. tabularcolumns:: |p{2.8cm}|p{2.0cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}| .. _rgb-formats: @@ -139,6 +139,144 @@ next to each other in memory. - r\ :sub:`1` - r\ :sub:`0` - + * .. _V4L2-PIX-FMT-RGBA444: + + - ``V4L2_PIX_FMT_RGBA444`` + - 'RA12' + + - b\ :sub:`3` + - b\ :sub:`2` + - b\ :sub:`1` + - b\ :sub:`0` + - a\ :sub:`3` + - a\ :sub:`2` + - a\ :sub:`1` + - a\ :sub:`0` + + - r\ :sub:`3` + - r\ :sub:`2` + - r\ :sub:`1` + - r\ :sub:`0` + - g\ :sub:`3` + - g\ :sub:`2` + - g\ :sub:`1` + - g\ :sub:`0` + - + * .. _V4L2-PIX-FMT-RGBX444: + + - ``V4L2_PIX_FMT_RGBX444`` + - 'RX12' + + - b\ :sub:`3` + - b\ :sub:`2` + - b\ :sub:`1` + - b\ :sub:`0` + - + - + - + - + + - r\ :sub:`3` + - r\ :sub:`2` + - r\ :sub:`1` + - r\ :sub:`0` + - g\ :sub:`3` + - g\ :sub:`2` + - g\ :sub:`1` + - g\ :sub:`0` + - + * .. _V4L2-PIX-FMT-ABGR444: + + - ``V4L2_PIX_FMT_ABGR444`` + - 'AB12' + + - g\ :sub:`3` + - g\ :sub:`2` + - g\ :sub:`1` + - g\ :sub:`0` + - r\ :sub:`3` + - r\ :sub:`2` + - r\ :sub:`1` + - r\ :sub:`0` + + - a\ :sub:`3` + - a\ :sub:`2` + - a\ :sub:`1` + - a\ :sub:`0` + - b\ :sub:`3` + - b\ :sub:`2` + - b\ :sub:`1` + - b\ :sub:`0` + - + * .. _V4L2-PIX-FMT-XBGR444: + + - ``V4L2_PIX_FMT_XBGR444`` + - 'XB12' + + - g\ :sub:`3` + - g\ :sub:`2` + - g\ :sub:`1` + - g\ :sub:`0` + - r\ :sub:`3` + - r\ :sub:`2` + - r\ :sub:`1` + - r\ :sub:`0` + + - + - + - + - + - b\ :sub:`3` + - b\ :sub:`2` + - b\ :sub:`1` + - b\ :sub:`0` + - + * .. _V4L2-PIX-FMT-BGRA444: + + - ``V4L2_PIX_FMT_BGRA444`` + - 'BA12' + + - r\ :sub:`3` + - r\ :sub:`2` + - r\ :sub:`1` + - r\ :sub:`0` + - a\ :sub:`3` + - a\ :sub:`2` + - a\ :sub:`1` + - a\ :sub:`0` + + - b\ :sub:`3` + - b\ :sub:`2` + - b\ :sub:`1` + - b\ :sub:`0` + - g\ :sub:`3` + - g\ :sub:`2` + - g\ :sub:`1` + - g\ :sub:`0` + - + * .. _V4L2-PIX-FMT-BGRX444: + + - ``V4L2_PIX_FMT_BGRX444`` + - 'BX12' + + - r\ :sub:`3` + - r\ :sub:`2` + - r\ :sub:`1` + - r\ :sub:`0` + - + - + - + - + + - b\ :sub:`3` + - b\ :sub:`2` + - b\ :sub:`1` + - b\ :sub:`0` + - g\ :sub:`3` + - g\ :sub:`2` + - g\ :sub:`1` + - g\ :sub:`0` + - * .. _V4L2-PIX-FMT-ARGB555: - ``V4L2_PIX_FMT_ARGB555`` @@ -185,6 +323,144 @@ next to each other in memory. - g\ :sub:`4` - g\ :sub:`3` - + * .. _V4L2-PIX-FMT-RGBA555: + + - ``V4L2_PIX_FMT_RGBA555`` + - 'RA15' + + - g\ :sub:`1` + - g\ :sub:`0` + - b\ :sub:`4` + - b\ :sub:`3` + - b\ :sub:`2` + - b\ :sub:`1` + - b\ :sub:`0` + - a + + - r\ :sub:`4` + - r\ :sub:`3` + - r\ :sub:`2` + - r\ :sub:`1` + - r\ :sub:`0` + - g\ :sub:`4` + - g\ :sub:`3` + - g\ :sub:`2` + - + * .. _V4L2-PIX-FMT-RGBX555: + + - ``V4L2_PIX_FMT_RGBX555`` + - 'RX15' + + - g\ :sub:`1` + - g\ :sub:`0` + - b\ :sub:`4` + - b\ :sub:`3` + - b\ :sub:`2` + - b\ :sub:`1` + - b\ :sub:`0` + - + + - r\ :sub:`4` + - r\ :sub:`3` + - r\ :sub:`2` + - r\ :sub:`1` + - r\ :sub:`0` + - g\ :sub:`4` + - g\ :sub:`3` + - g\ :sub:`2` + - + * .. _V4L2-PIX-FMT-ABGR555: + + - ``V4L2_PIX_FMT_ABGR555`` + - 'AB15' + + - g\ :sub:`2` + - g\ :sub:`1` + - g\ :sub:`0` + - r\ :sub:`4` + - r\ :sub:`3` + - r\ :sub:`2` + - r\ :sub:`1` + - r\ :sub:`0` + + - a + - b\ :sub:`4` + - b\ :sub:`3` + - b\ :sub:`2` + - b\ :sub:`1` + - b\ :sub:`0` + - g\ :sub:`4` + - g\ :sub:`3` + - + * .. _V4L2-PIX-FMT-XBGR555: + + - ``V4L2_PIX_FMT_XBGR555`` + - 'XB15' + + - g\ :sub:`2` + - g\ :sub:`1` + - g\ :sub:`0` + - r\ :sub:`4` + - r\ :sub:`3` + - r\ :sub:`2` + - r\ :sub:`1` + - r\ :sub:`0` + + - + - b\ :sub:`4` + - b\ :sub:`3` + - b\ :sub:`2` + - b\ :sub:`1` + - b\ :sub:`0` + - g\ :sub:`4` + - g\ :sub:`3` + - + * .. _V4L2-PIX-FMT-BGRA555: + + - ``V4L2_PIX_FMT_BGRA555`` + - 'BA15' + + - g\ :sub:`1` + - g\ :sub:`0` + - r\ :sub:`4` + - r\ :sub:`3` + - r\ :sub:`2` + - r\ :sub:`1` + - r\ :sub:`0` + - a + + - b\ :sub:`4` + - b\ :sub:`3` + - b\ :sub:`2` + - b\ :sub:`1` + - b\ :sub:`0` + - g\ :sub:`4` + - g\ :sub:`3` + - g\ :sub:`2` + - + * .. _V4L2-PIX-FMT-BGRX555: + + - ``V4L2_PIX_FMT_BGRX555`` + - 'BX15' + + - g\ :sub:`1` + - g\ :sub:`0` + - r\ :sub:`4` + - r\ :sub:`3` + - r\ :sub:`2` + - r\ :sub:`1` + - r\ :sub:`0` + - + + - b\ :sub:`4` + - b\ :sub:`3` + - b\ :sub:`2` + - b\ :sub:`1` + - b\ :sub:`0` + - g\ :sub:`4` + - g\ :sub:`3` + - g\ :sub:`2` + - * .. _V4L2-PIX-FMT-RGB565: - ``V4L2_PIX_FMT_RGB565`` @@ -461,6 +737,166 @@ next to each other in memory. - - - + * .. _V4L2-PIX-FMT-BGRA32: + + - ``V4L2_PIX_FMT_BGRA32`` + - 'RA24' + + - a\ :sub:`7` + - a\ :sub:`6` + - a\ :sub:`5` + - a\ :sub:`4` + - a\ :sub:`3` + - a\ :sub:`2` + - a\ :sub:`1` + - a\ :sub:`0` + + - b\ :sub:`7` + - b\ :sub:`6` + - b\ :sub:`5` + - b\ :sub:`4` + - b\ :sub:`3` + - b\ :sub:`2` + - b\ :sub:`1` + - b\ :sub:`0` + + - g\ :sub:`7` + - g\ :sub:`6` + - g\ :sub:`5` + - g\ :sub:`4` + - g\ :sub:`3` + - g\ :sub:`2` + - g\ :sub:`1` + - g\ :sub:`0` + + - r\ :sub:`7` + - r\ :sub:`6` + - r\ :sub:`5` + - r\ :sub:`4` + - r\ :sub:`3` + - r\ :sub:`2` + - r\ :sub:`1` + - r\ :sub:`0` + * .. _V4L2-PIX-FMT-BGRX32: + + - ``V4L2_PIX_FMT_BGRX32`` + - 'RX24' + + - + - + - + - + - + - + - + - + + - b\ :sub:`7` + - b\ :sub:`6` + - b\ :sub:`5` + - b\ :sub:`4` + - b\ :sub:`3` + - b\ :sub:`2` + - b\ :sub:`1` + - b\ :sub:`0` + + - g\ :sub:`7` + - g\ :sub:`6` + - g\ :sub:`5` + - g\ :sub:`4` + - g\ :sub:`3` + - g\ :sub:`2` + - g\ :sub:`1` + - g\ :sub:`0` + + - r\ :sub:`7` + - r\ :sub:`6` + - r\ :sub:`5` + - r\ :sub:`4` + - r\ :sub:`3` + - r\ :sub:`2` + - r\ :sub:`1` + - r\ :sub:`0` + * .. _V4L2-PIX-FMT-RGBA32: + + - ``V4L2_PIX_FMT_RGBA32`` + - 'AB24' + + - r\ :sub:`7` + - r\ :sub:`6` + - r\ :sub:`5` + - r\ :sub:`4` + - r\ :sub:`3` + - r\ :sub:`2` + - r\ :sub:`1` + - r\ :sub:`0` + + - g\ :sub:`7` + - g\ :sub:`6` + - g\ :sub:`5` + - g\ :sub:`4` + - g\ :sub:`3` + - g\ :sub:`2` + - g\ :sub:`1` + - g\ :sub:`0` + + - b\ :sub:`7` + - b\ :sub:`6` + - b\ :sub:`5` + - b\ :sub:`4` + - b\ :sub:`3` + - b\ :sub:`2` + - b\ :sub:`1` + - b\ :sub:`0` + + - a\ :sub:`7` + - a\ :sub:`6` + - a\ :sub:`5` + - a\ :sub:`4` + - a\ :sub:`3` + - a\ :sub:`2` + - a\ :sub:`1` + - a\ :sub:`0` + * .. _V4L2-PIX-FMT-RGBX32: + + - ``V4L2_PIX_FMT_RGBX32`` + - 'XB24' + + - r\ :sub:`7` + - r\ :sub:`6` + - r\ :sub:`5` + - r\ :sub:`4` + - r\ :sub:`3` + - r\ :sub:`2` + - r\ :sub:`1` + - r\ :sub:`0` + + - g\ :sub:`7` + - g\ :sub:`6` + - g\ :sub:`5` + - g\ :sub:`4` + - g\ :sub:`3` + - g\ :sub:`2` + - g\ :sub:`1` + - g\ :sub:`0` + + - b\ :sub:`7` + - b\ :sub:`6` + - b\ :sub:`5` + - b\ :sub:`4` + - b\ :sub:`3` + - b\ :sub:`2` + - b\ :sub:`1` + - b\ :sub:`0` + + - + - + - + - + - + - + - + - * .. _V4L2-PIX-FMT-ARGB32: - ``V4L2_PIX_FMT_ARGB32`` @@ -656,7 +1092,7 @@ either the corresponding ARGB or XRGB format, depending on the driver. \tiny \setlength{\tabcolsep}{2pt} -.. tabularcolumns:: |p{2.2cm}|p{0.60cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}| +.. tabularcolumns:: |p{2.6cm}|p{0.70cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}| .. _rgb-formats-deprecated: diff --git a/Documentation/media/uapi/v4l/pixfmt-packed-yuv.rst b/Documentation/media/uapi/v4l/pixfmt-packed-yuv.rst index 7fcee1c11ac4..41b60fae703a 100644 --- a/Documentation/media/uapi/v4l/pixfmt-packed-yuv.rst +++ b/Documentation/media/uapi/v4l/pixfmt-packed-yuv.rst @@ -28,7 +28,7 @@ component of each pixel in one 16 or 32 bit word. .. _packed-yuv-formats: -.. tabularcolumns:: |p{2.0cm}|p{0.67cm}|p{0.29cm}|p{0.29cm}|p{0.29cm}|p{0.29cm}|p{0.29cm}|p{0.29cm}|p{0.29cm}|p{0.29cm}|p{0.29cm}|p{0.29cm}|p{0.29cm}|p{0.29cm}|p{0.29cm}|p{0.29cm}|p{0.29cm}|p{0.29cm}|p{0.29cm}|p{0.29cm}|p{0.29cm}|p{0.29cm}|p{0.29cm}|p{0.29cm}|p{0.29cm}|p{0.29cm}|p{0.29cm}|p{0.29cm}|p{0.29cm}|p{0.29cm}|p{0.29cm}|p{0.29cm}|p{0.29cm}|p{0.29cm}| +.. tabularcolumns:: |p{2.5cm}|p{0.69cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}|p{0.31cm}| .. flat-table:: Packed YUV Image Formats :header-rows: 2 @@ -44,6 +44,7 @@ component of each pixel in one 16 or 32 bit word. - :cspan:`7` Byte 2 - :cspan:`7` Byte 3 + * - - - 7 @@ -81,6 +82,7 @@ component of each pixel in one 16 or 32 bit word. - 2 - 1 - 0 + * .. _V4L2-PIX-FMT-YUV444: - ``V4L2_PIX_FMT_YUV444`` @@ -103,7 +105,9 @@ component of each pixel in one 16 or 32 bit word. - Y'\ :sub:`2` - Y'\ :sub:`1` - Y'\ :sub:`0` - - + + - :cspan:`15` + * .. _V4L2-PIX-FMT-YUV555: - ``V4L2_PIX_FMT_YUV555`` @@ -126,7 +130,8 @@ component of each pixel in one 16 or 32 bit word. - Y'\ :sub:`0` - Cb\ :sub:`4` - Cb\ :sub:`3` - - + + - :cspan:`15` * .. _V4L2-PIX-FMT-YUV565: - ``V4L2_PIX_FMT_YUV565`` @@ -149,7 +154,9 @@ component of each pixel in one 16 or 32 bit word. - Cb\ :sub:`5` - Cb\ :sub:`4` - Cb\ :sub:`3` - - + + - :cspan:`15` + * .. _V4L2-PIX-FMT-YUV32: - ``V4L2_PIX_FMT_YUV32`` @@ -190,7 +197,7 @@ component of each pixel in one 16 or 32 bit word. - Cr\ :sub:`2` - Cr\ :sub:`1` - Cr\ :sub:`0` - - + * .. _V4L2-PIX-FMT-AYUV32: - ``V4L2_PIX_FMT_AYUV32`` @@ -231,7 +238,7 @@ component of each pixel in one 16 or 32 bit word. - Cr\ :sub:`2` - Cr\ :sub:`1` - Cr\ :sub:`0` - - + * .. _V4L2-PIX-FMT-XYUV32: - ``V4L2_PIX_FMT_XYUV32`` @@ -272,7 +279,7 @@ component of each pixel in one 16 or 32 bit word. - Cr\ :sub:`2` - Cr\ :sub:`1` - Cr\ :sub:`0` - - + * .. _V4L2-PIX-FMT-VUYA32: - ``V4L2_PIX_FMT_VUYA32`` @@ -313,7 +320,7 @@ component of each pixel in one 16 or 32 bit word. - a\ :sub:`2` - a\ :sub:`1` - a\ :sub:`0` - - + * .. _V4L2-PIX-FMT-VUYX32: - ``V4L2_PIX_FMT_VUYX32`` diff --git a/Documentation/media/uapi/v4l/pixfmt-srggb10p.rst b/Documentation/media/uapi/v4l/pixfmt-srggb10p.rst index cdb70ac26126..fd32660a3766 100644 --- a/Documentation/media/uapi/v4l/pixfmt-srggb10p.rst +++ b/Documentation/media/uapi/v4l/pixfmt-srggb10p.rst @@ -40,7 +40,7 @@ of a small V4L2_PIX_FMT_SBGGR10P image: **Byte Order.** Each cell is one byte. -.. tabularcolumns:: |p{2.0cm}|p{1.0cm}|p{1.0cm}|p{1.0cm}|p{1.0cm}|p{5.4cm}| +.. tabularcolumns:: |p{2.4cm}|p{1.4cm}|p{1.2cm}|p{1.2cm}|p{1.2cm}|p{6.4cm}| .. flat-table:: :header-rows: 0 diff --git a/Documentation/media/uapi/v4l/pixfmt-srggb12p.rst b/Documentation/media/uapi/v4l/pixfmt-srggb12p.rst index 01413be12916..960851275f23 100644 --- a/Documentation/media/uapi/v4l/pixfmt-srggb12p.rst +++ b/Documentation/media/uapi/v4l/pixfmt-srggb12p.rst @@ -18,6 +18,7 @@ V4L2_PIX_FMT_SRGGB12P ('pRAA'), V4L2_PIX_FMT_SGRBG12P ('pgAA'), V4L2_PIX_FMT_SGB 12-bit packed Bayer formats +--------------------------- Description @@ -37,7 +38,7 @@ Below is an example of a small V4L2_PIX_FMT_SBGGR12P image: **Byte Order.** Each cell is one byte. -.. tabularcolumns:: |p{2.0cm}|p{1.0cm}|p{1.0cm}|p{2.7cm}|p{1.0cm}|p{1.0cm}|p{2.7cm}| +.. tabularcolumns:: |p{2.2cm}|p{1.2cm}|p{1.2cm}|p{3.1cm}|p{1.2cm}|p{1.2cm}|p{3.1cm}| .. flat-table:: diff --git a/Documentation/media/uapi/v4l/pixfmt-srggb14p.rst b/Documentation/media/uapi/v4l/pixfmt-srggb14p.rst index b583531c2853..1a988d7e7ff8 100644 --- a/Documentation/media/uapi/v4l/pixfmt-srggb14p.rst +++ b/Documentation/media/uapi/v4l/pixfmt-srggb14p.rst @@ -41,17 +41,21 @@ of one of these formats: **Byte Order.** Each cell is one byte. +.. raw:: latex + \footnotesize + +.. tabularcolumns:: |p{1.8cm}|p{1.0cm}|p{1.0cm}|p{1.0cm}|p{1.1cm}|p{3.3cm}|p{3.3cm}|p{3.3cm}| .. flat-table:: :header-rows: 0 :stub-columns: 0 - :widths: 2 1 1 1 1 1 1 1 + :widths: 2 1 1 1 1 3 3 3 - .. row 1 - - start + 0: + - start + 0 - B\ :sub:`00high` @@ -62,17 +66,20 @@ Each cell is one byte. - G\ :sub:`03high` - G\ :sub:`01low bits 1--0`\ (bits 7--6) + B\ :sub:`00low bits 5--0`\ (bits 5--0) - R\ :sub:`02low bits 3--0`\ (bits 7--4) + G\ :sub:`01low bits 5--2`\ (bits 3--0) - G\ :sub:`03low bits 5--0`\ (bits 7--2) + R\ :sub:`02low bits 5--4`\ (bits 1--0) - .. row 2 - - start + 7: + - start + 7 - G\ :sub:`00high` @@ -83,12 +90,15 @@ Each cell is one byte. - R\ :sub:`03high` - R\ :sub:`01low bits 1--0`\ (bits 7--6) + G\ :sub:`00low bits 5--0`\ (bits 5--0) - G\ :sub:`02low bits 3--0`\ (bits 7--4) + R\ :sub:`01low bits 5--2`\ (bits 3--0) - R\ :sub:`03low bits 5--0`\ (bits 7--2) + G\ :sub:`02low bits 5--4`\ (bits 1--0) - .. row 3 @@ -104,12 +114,15 @@ Each cell is one byte. - G\ :sub:`23high` - G\ :sub:`21low bits 1--0`\ (bits 7--6) + B\ :sub:`20low bits 5--0`\ (bits 5--0) - R\ :sub:`22low bits 3--0`\ (bits 7--4) + G\ :sub:`21low bits 5--2`\ (bits 3--0) - G\ :sub:`23low bits 5--0`\ (bits 7--2) + R\ :sub:`22low bits 5--4`\ (bits 1--0) - .. row 4 @@ -132,3 +145,8 @@ Each cell is one byte. - R\ :sub:`33low bits 5--0`\ (bits 7--2) G\ :sub:`32low bits 5--4`\ (bits 1--0) + +.. raw:: latex + + \normalsize + diff --git a/Documentation/media/uapi/v4l/pixfmt-v4l2-mplane.rst b/Documentation/media/uapi/v4l/pixfmt-v4l2-mplane.rst index 7f82dad9013a..5688c816e334 100644 --- a/Documentation/media/uapi/v4l/pixfmt-v4l2-mplane.rst +++ b/Documentation/media/uapi/v4l/pixfmt-v4l2-mplane.rst @@ -19,6 +19,7 @@ array of struct :c:type:`v4l2_plane_pix_format` structures, describing all planes of that format. + .. tabularcolumns:: |p{4.4cm}|p{4.4cm}|p{8.7cm}| .. c:type:: v4l2_plane_pix_format @@ -41,6 +42,10 @@ describing all planes of that format. applications. +.. raw:: latex + + \small + .. tabularcolumns:: |p{4.4cm}|p{5.6cm}|p{7.5cm}| .. c:type:: v4l2_pix_format_mplane @@ -82,9 +87,7 @@ describing all planes of that format. * - __u8 - ``flags`` - Flags set by the application or driver, see :ref:`format-flags`. - * - union { - - (anonymous) - - + * - :cspan:`2` union { (anonymous) * - __u8 - ``ycbcr_enc`` - Y'CbCr encoding, from enum :c:type:`v4l2_ycbcr_encoding`. @@ -97,9 +100,7 @@ describing all planes of that format. This information supplements the ``colorspace`` and must be set by the driver for capture streams and by the application for output streams, see :ref:`colorspaces`. - * - } - - - - + * - :cspan:`2` } * - __u8 - ``quantization`` - Quantization range, from enum :c:type:`v4l2_quantization`. @@ -116,3 +117,7 @@ describing all planes of that format. - ``reserved[7]`` - Reserved for future extensions. Should be zeroed by drivers and applications. + +.. raw:: latex + + \normalsize diff --git a/Documentation/media/uapi/v4l/pixfmt-y10p.rst b/Documentation/media/uapi/v4l/pixfmt-y10p.rst index 7893642faee3..39cd789dcb59 100644 --- a/Documentation/media/uapi/v4l/pixfmt-y10p.rst +++ b/Documentation/media/uapi/v4l/pixfmt-y10p.rst @@ -27,6 +27,12 @@ in the same order. **Bit-packed representation.** +.. raw:: latex + + \small + +.. tabularcolumns:: |p{1.2cm}||p{1.2cm}||p{1.2cm}||p{1.2cm}|p{3.2cm}|p{3.2cm}| + .. flat-table:: :header-rows: 0 :stub-columns: 0 @@ -38,3 +44,7 @@ in the same order. - Y'\ :sub:`03[9:2]` - Y'\ :sub:`03[1:0]`\ (bits 7--6) Y'\ :sub:`02[1:0]`\ (bits 5--4) Y'\ :sub:`01[1:0]`\ (bits 3--2) Y'\ :sub:`00[1:0]`\ (bits 1--0) + +.. raw:: latex + + \normalsize diff --git a/Documentation/media/uapi/v4l/subdev-formats.rst b/Documentation/media/uapi/v4l/subdev-formats.rst index f5440d55d510..ab1a48a5ae80 100644 --- a/Documentation/media/uapi/v4l/subdev-formats.rst +++ b/Documentation/media/uapi/v4l/subdev-formats.rst @@ -980,6 +980,113 @@ The following tables list existing packed RGB formats. - r\ :sub:`2` - r\ :sub:`1` - r\ :sub:`0` + * .. _MEDIA-BUS-FMT-BGR888-3X8: + + - MEDIA_BUS_FMT_BGR888_3X8 + - 0x101b + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - b\ :sub:`7` + - b\ :sub:`6` + - b\ :sub:`5` + - b\ :sub:`4` + - b\ :sub:`3` + - b\ :sub:`2` + - b\ :sub:`1` + - b\ :sub:`0` + * - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - g\ :sub:`7` + - g\ :sub:`6` + - g\ :sub:`5` + - g\ :sub:`4` + - g\ :sub:`3` + - g\ :sub:`2` + - g\ :sub:`1` + - g\ :sub:`0` + * - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - r\ :sub:`7` + - r\ :sub:`6` + - r\ :sub:`5` + - r\ :sub:`4` + - r\ :sub:`3` + - r\ :sub:`2` + - r\ :sub:`1` + - r\ :sub:`0` * .. _MEDIA-BUS-FMT-GBR888-1X24: - MEDIA_BUS_FMT_GBR888_1X24 @@ -7414,7 +7521,7 @@ The following table lists existing HSV/HSL formats. \tiny \setlength{\tabcolsep}{2pt} -.. tabularcolumns:: |p{3.0cm}|p{0.60cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}| +.. tabularcolumns:: |p{3.9cm}|p{0.73cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}|p{0.22cm}| .. _v4l2-mbus-pixelcode-hsv: @@ -7524,7 +7631,7 @@ The following table lists existing JPEG compressed formats. .. _v4l2-mbus-pixelcode-jpeg: -.. tabularcolumns:: |p{5.4cm}|p{1.4cm}|p{10.7cm}| +.. tabularcolumns:: |p{6.0cm}|p{1.4cm}|p{10.1cm}| .. flat-table:: JPEG Formats :header-rows: 1 @@ -7557,7 +7664,7 @@ formats. .. _v4l2-mbus-pixelcode-vendor-specific: -.. tabularcolumns:: |p{6.8cm}|p{1.4cm}|p{9.3cm}| +.. tabularcolumns:: |p{8.0cm}|p{1.4cm}|p{7.7cm}| .. flat-table:: Vendor and device specific formats :header-rows: 1 diff --git a/Documentation/media/uapi/v4l/vidioc-qbuf.rst b/Documentation/media/uapi/v4l/vidioc-qbuf.rst index c138d149faea..dbf7b445a27b 100644 --- a/Documentation/media/uapi/v4l/vidioc-qbuf.rst +++ b/Documentation/media/uapi/v4l/vidioc-qbuf.rst @@ -111,7 +111,7 @@ in use. Setting it means that the buffer will not be passed to the driver until the request itself is queued. Also, the driver will apply any settings associated with the request for this buffer. This field will be ignored unless the ``V4L2_BUF_FLAG_REQUEST_FD`` flag is set. -If the device does not support requests, then ``EACCES`` will be returned. +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. @@ -125,7 +125,7 @@ then ``EINVAL`` will be returned. For :ref:`memory-to-memory devices <mem2mem>` you can specify the ``request_fd`` only for output buffers, not for capture buffers. Attempting - to specify this for a capture buffer will result in an ``EACCES`` error. + to specify this for a capture buffer will result in an ``EBADR`` error. Applications call the ``VIDIOC_DQBUF`` ioctl to dequeue a filled (capturing) or displayed (output) buffer from the driver's outgoing @@ -185,9 +185,11 @@ EPIPE codecs if a buffer with the ``V4L2_BUF_FLAG_LAST`` was already dequeued and no new buffers are expected to become available. -EACCES +EBADR The ``V4L2_BUF_FLAG_REQUEST_FD`` flag was set but the device does not - support requests for the given buffer type. + support requests for the given buffer type, or + the ``V4L2_BUF_FLAG_REQUEST_FD`` flag was not set but the device requires + that the buffer is part of a request. EBUSY The first buffer was queued via a request, but the application now tries diff --git a/Documentation/media/v4l-drivers/index.rst b/Documentation/media/v4l-drivers/index.rst index dfd4b205937c..33a055907258 100644 --- a/Documentation/media/v4l-drivers/index.rst +++ b/Documentation/media/v4l-drivers/index.rst @@ -65,5 +65,4 @@ For more details see the file COPYING in the source distribution of Linux. soc-camera uvcvideo vivid - zoran zr364xx diff --git a/Documentation/media/v4l-drivers/zoran.rst b/Documentation/media/v4l-drivers/zoran.rst deleted file mode 100644 index d2724a863d1d..000000000000 --- a/Documentation/media/v4l-drivers/zoran.rst +++ /dev/null @@ -1,583 +0,0 @@ -.. SPDX-License-Identifier: GPL-2.0 - -The Zoran driver -================ - -unified zoran driver (zr360x7, zoran, buz, dc10(+), dc30(+), lml33) - -website: http://mjpeg.sourceforge.net/driver-zoran/ - - -Frequently Asked Questions --------------------------- - -What cards are supported ------------------------- - -Iomega Buz, Linux Media Labs LML33/LML33R10, Pinnacle/Miro -DC10/DC10+/DC30/DC30+ and related boards (available under various names). - -Iomega Buz -~~~~~~~~~~ - -* Zoran zr36067 PCI controller -* Zoran zr36060 MJPEG codec -* Philips saa7111 TV decoder -* Philips saa7185 TV encoder - -Drivers to use: videodev, i2c-core, i2c-algo-bit, -videocodec, saa7111, saa7185, zr36060, zr36067 - -Inputs/outputs: Composite and S-video - -Norms: PAL, SECAM (720x576 @ 25 fps), NTSC (720x480 @ 29.97 fps) - -Card number: 7 - -AverMedia 6 Eyes AVS6EYES -~~~~~~~~~~~~~~~~~~~~~~~~~ - -* Zoran zr36067 PCI controller -* Zoran zr36060 MJPEG codec -* Samsung ks0127 TV decoder -* Conexant bt866 TV encoder - -Drivers to use: videodev, i2c-core, i2c-algo-bit, -videocodec, ks0127, bt866, zr36060, zr36067 - -Inputs/outputs: - Six physical inputs. 1-6 are composite, - 1-2, 3-4, 5-6 doubles as S-video, - 1-3 triples as component. - One composite output. - -Norms: PAL, SECAM (720x576 @ 25 fps), NTSC (720x480 @ 29.97 fps) - -Card number: 8 - -.. note:: - - Not autodetected, card=8 is necessary. - -Linux Media Labs LML33 -~~~~~~~~~~~~~~~~~~~~~~ - -* Zoran zr36067 PCI controller -* Zoran zr36060 MJPEG codec -* Brooktree bt819 TV decoder -* Brooktree bt856 TV encoder - -Drivers to use: videodev, i2c-core, i2c-algo-bit, -videocodec, bt819, bt856, zr36060, zr36067 - -Inputs/outputs: Composite and S-video - -Norms: PAL (720x576 @ 25 fps), NTSC (720x480 @ 29.97 fps) - -Card number: 5 - -Linux Media Labs LML33R10 -~~~~~~~~~~~~~~~~~~~~~~~~~ - -* Zoran zr36067 PCI controller -* Zoran zr36060 MJPEG codec -* Philips saa7114 TV decoder -* Analog Devices adv7170 TV encoder - -Drivers to use: videodev, i2c-core, i2c-algo-bit, -videocodec, saa7114, adv7170, zr36060, zr36067 - -Inputs/outputs: Composite and S-video - -Norms: PAL (720x576 @ 25 fps), NTSC (720x480 @ 29.97 fps) - -Card number: 6 - -Pinnacle/Miro DC10(new) -~~~~~~~~~~~~~~~~~~~~~~~ - -* Zoran zr36057 PCI controller -* Zoran zr36060 MJPEG codec -* Philips saa7110a TV decoder -* Analog Devices adv7176 TV encoder - -Drivers to use: videodev, i2c-core, i2c-algo-bit, -videocodec, saa7110, adv7175, zr36060, zr36067 - -Inputs/outputs: Composite, S-video and Internal - -Norms: PAL, SECAM (768x576 @ 25 fps), NTSC (640x480 @ 29.97 fps) - -Card number: 1 - -Pinnacle/Miro DC10+ -~~~~~~~~~~~~~~~~~~~ - -* Zoran zr36067 PCI controller -* Zoran zr36060 MJPEG codec -* Philips saa7110a TV decoder -* Analog Devices adv7176 TV encoder - -Drivers to use: videodev, i2c-core, i2c-algo-bit, -videocodec, sa7110, adv7175, zr36060, zr36067 - -Inputs/outputs: Composite, S-video and Internal - -Norms: PAL, SECAM (768x576 @ 25 fps), NTSC (640x480 @ 29.97 fps) - -Card number: 2 - -Pinnacle/Miro DC10(old) -~~~~~~~~~~~~~~~~~~~~~~~ - -* Zoran zr36057 PCI controller -* Zoran zr36050 MJPEG codec -* Zoran zr36016 Video Front End or Fuji md0211 Video Front End (clone?) -* Micronas vpx3220a TV decoder -* mse3000 TV encoder or Analog Devices adv7176 TV encoder - -Drivers to use: videodev, i2c-core, i2c-algo-bit, -videocodec, vpx3220, mse3000/adv7175, zr36050, zr36016, zr36067 - -Inputs/outputs: Composite, S-video and Internal - -Norms: PAL, SECAM (768x576 @ 25 fps), NTSC (640x480 @ 29.97 fps) - -Card number: 0 - -Pinnacle/Miro DC30 -~~~~~~~~~~~~~~~~~~ - -* Zoran zr36057 PCI controller -* Zoran zr36050 MJPEG codec -* Zoran zr36016 Video Front End -* Micronas vpx3225d/vpx3220a/vpx3216b TV decoder -* Analog Devices adv7176 TV encoder - -Drivers to use: videodev, i2c-core, i2c-algo-bit, -videocodec, vpx3220/vpx3224, adv7175, zr36050, zr36016, zr36067 - -Inputs/outputs: Composite, S-video and Internal - -Norms: PAL, SECAM (768x576 @ 25 fps), NTSC (640x480 @ 29.97 fps) - -Card number: 3 - -Pinnacle/Miro DC30+ -~~~~~~~~~~~~~~~~~~~ - -* Zoran zr36067 PCI controller -* Zoran zr36050 MJPEG codec -* Zoran zr36016 Video Front End -* Micronas vpx3225d/vpx3220a/vpx3216b TV decoder -* Analog Devices adv7176 TV encoder - -Drivers to use: videodev, i2c-core, i2c-algo-bit, -videocodec, vpx3220/vpx3224, adv7175, zr36050, zr36015, zr36067 - -Inputs/outputs: Composite, S-video and Internal - -Norms: PAL, SECAM (768x576 @ 25 fps), NTSC (640x480 @ 29.97 fps) - -Card number: 4 - -.. note:: - - #) No module for the mse3000 is available yet - #) No module for the vpx3224 is available yet - -1.1 What the TV decoder can do an what not ------------------------------------------- - -The best know TV standards are NTSC/PAL/SECAM. but for decoding a frame that -information is not enough. There are several formats of the TV standards. -And not every TV decoder is able to handle every format. Also the every -combination is supported by the driver. There are currently 11 different -tv broadcast formats all aver the world. - -The CCIR defines parameters needed for broadcasting the signal. -The CCIR has defined different standards: A,B,D,E,F,G,D,H,I,K,K1,L,M,N,... -The CCIR says not much about the colorsystem used !!! -And talking about a colorsystem says not to much about how it is broadcast. - -The CCIR standards A,E,F are not used any more. - -When you speak about NTSC, you usually mean the standard: CCIR - M using -the NTSC colorsystem which is used in the USA, Japan, Mexico, Canada -and a few others. - -When you talk about PAL, you usually mean: CCIR - B/G using the PAL -colorsystem which is used in many Countries. - -When you talk about SECAM, you mean: CCIR - L using the SECAM Colorsystem -which is used in France, and a few others. - -There the other version of SECAM, CCIR - D/K is used in Bulgaria, China, -Slovakai, Hungary, Korea (Rep.), Poland, Rumania and a others. - -The CCIR - H uses the PAL colorsystem (sometimes SECAM) and is used in -Egypt, Libya, Sri Lanka, Syrain Arab. Rep. - -The CCIR - I uses the PAL colorsystem, and is used in Great Britain, Hong Kong, -Ireland, Nigeria, South Africa. - -The CCIR - N uses the PAL colorsystem and PAL frame size but the NTSC framerate, -and is used in Argentinia, Uruguay, an a few others - -We do not talk about how the audio is broadcast ! - -A rather good sites about the TV standards are: -http://www.sony.jp/support/ -http://info.electronicwerkstatt.de/bereiche/fernsehtechnik/frequenzen_und_normen/Fernsehnormen/ -and http://www.cabl.com/restaurant/channel.html - -Other weird things around: NTSC 4.43 is a modificated NTSC, which is mainly -used in PAL VCR's that are able to play back NTSC. PAL 60 seems to be the same -as NTSC 4.43 . The Datasheets also talk about NTSC 44, It seems as if it would -be the same as NTSC 4.43. -NTSC Combs seems to be a decoder mode where the decoder uses a comb filter -to split coma and luma instead of a Delay line. - -But I did not defiantly find out what NTSC Comb is. - -Philips saa7111 TV decoder -~~~~~~~~~~~~~~~~~~~~~~~~~~ - -- was introduced in 1997, is used in the BUZ and -- can handle: PAL B/G/H/I, PAL N, PAL M, NTSC M, NTSC N, NTSC 4.43 and SECAM - -Philips saa7110a TV decoder -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -- was introduced in 1995, is used in the Pinnacle/Miro DC10(new), DC10+ and -- can handle: PAL B/G, NTSC M and SECAM - -Philips saa7114 TV decoder -~~~~~~~~~~~~~~~~~~~~~~~~~~ - -- was introduced in 2000, is used in the LML33R10 and -- can handle: PAL B/G/D/H/I/N, PAL N, PAL M, NTSC M, NTSC 4.43 and SECAM - -Brooktree bt819 TV decoder -~~~~~~~~~~~~~~~~~~~~~~~~~~ - -- was introduced in 1996, and is used in the LML33 and -- can handle: PAL B/D/G/H/I, NTSC M - -Micronas vpx3220a TV decoder -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -- was introduced in 1996, is used in the DC30 and DC30+ and -- can handle: PAL B/G/H/I, PAL N, PAL M, NTSC M, NTSC 44, PAL 60, SECAM,NTSC Comb - -Samsung ks0127 TV decoder -~~~~~~~~~~~~~~~~~~~~~~~~~ - -- is used in the AVS6EYES card and -- can handle: NTSC-M/N/44, PAL-M/N/B/G/H/I/D/K/L and SECAM - - -What the TV encoder can do an what not --------------------------------------- - -The TV encoder are doing the "same" as the decoder, but in the oder direction. -You feed them digital data and the generate a Composite or SVHS signal. -For information about the colorsystems and TV norm take a look in the -TV decoder section. - -Philips saa7185 TV Encoder -~~~~~~~~~~~~~~~~~~~~~~~~~~ - -- was introduced in 1996, is used in the BUZ -- can generate: PAL B/G, NTSC M - -Brooktree bt856 TV Encoder -~~~~~~~~~~~~~~~~~~~~~~~~~~ - -- was introduced in 1994, is used in the LML33 -- can generate: PAL B/D/G/H/I/N, PAL M, NTSC M, PAL-N (Argentina) - -Analog Devices adv7170 TV Encoder -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -- was introduced in 2000, is used in the LML300R10 -- can generate: PAL B/D/G/H/I/N, PAL M, NTSC M, PAL 60 - -Analog Devices adv7175 TV Encoder -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -- was introduced in 1996, is used in the DC10, DC10+, DC10 old, DC30, DC30+ -- can generate: PAL B/D/G/H/I/N, PAL M, NTSC M - -ITT mse3000 TV encoder -~~~~~~~~~~~~~~~~~~~~~~ - -- was introduced in 1991, is used in the DC10 old -- can generate: PAL , NTSC , SECAM - -Conexant bt866 TV encoder -~~~~~~~~~~~~~~~~~~~~~~~~~ - -- is used in AVS6EYES, and -- can generate: NTSC/PAL, PALÂM, PALÂN - -The adv717x, should be able to produce PAL N. But you find nothing PAL N -specific in the registers. Seem that you have to reuse a other standard -to generate PAL N, maybe it would work if you use the PAL M settings. - -How do I get this damn thing to work ------------------------------------- - -Load zr36067.o. If it can't autodetect your card, use the card=X insmod -option with X being the card number as given in the previous section. -To have more than one card, use card=X1[,X2[,X3,[X4[..]]]] - -To automate this, add the following to your /etc/modprobe.d/zoran.conf: - -options zr36067 card=X1[,X2[,X3[,X4[..]]]] -alias char-major-81-0 zr36067 - -One thing to keep in mind is that this doesn't load zr36067.o itself yet. It -just automates loading. If you start using xawtv, the device won't load on -some systems, since you're trying to load modules as a user, which is not -allowed ("permission denied"). A quick workaround is to add 'Load "v4l"' to -XF86Config-4 when you use X by default, or to run 'v4l-conf -c <device>' in -one of your startup scripts (normally rc.local) if you don't use X. Both -make sure that the modules are loaded on startup, under the root account. - -What mainboard should I use (or why doesn't my card work) ---------------------------------------------------------- - - -<insert lousy disclaimer here>. In short: good=SiS/Intel, bad=VIA. - -Experience tells us that people with a Buz, on average, have more problems -than users with a DC10+/LML33. Also, it tells us that people owning a VIA- -based mainboard (ktXXX, MVP3) have more problems than users with a mainboard -based on a different chipset. Here's some notes from Andrew Stevens: - -Here's my experience of using LML33 and Buz on various motherboards: - -- VIA MVP3 - - Forget it. Pointless. Doesn't work. -- Intel 430FX (Pentium 200) - - LML33 perfect, Buz tolerable (3 or 4 frames dropped per movie) -- Intel 440BX (early stepping) - - LML33 tolerable. Buz starting to get annoying (6-10 frames/hour) -- Intel 440BX (late stepping) - - Buz tolerable, LML3 almost perfect (occasional single frame drops) -- SiS735 - - LML33 perfect, Buz tolerable. -- VIA KT133(*) - - LML33 starting to get annoying, Buz poor enough that I have up. - -- Both 440BX boards were dual CPU versions. - -Bernhard Praschinger later added: - -- AMD 751 - - Buz perfect-tolerable -- AMD 760 - - Buz perfect-tolerable - -In general, people on the user mailinglist won't give you much of a chance -if you have a VIA-based motherboard. They may be cheap, but sometimes, you'd -rather want to spend some more money on better boards. In general, VIA -mainboard's IDE/PCI performance will also suck badly compared to others. -You'll noticed the DC10+/DC30+ aren't mentioned anywhere in the overview. -Basically, you can assume that if the Buz works, the LML33 will work too. If -the LML33 works, the DC10+/DC30+ will work too. They're most tolerant to -different mainboard chipsets from all of the supported cards. - -If you experience timeouts during capture, buy a better mainboard or lower -the quality/buffersize during capture (see 'Concerning buffer sizes, quality, -output size etc.'). If it hangs, there's little we can do as of now. Check -your IRQs and make sure the card has its own interrupts. - -Programming interface ---------------------- - -This driver conforms to video4linux2. Support for V4L1 and for the custom -zoran ioctls has been removed in kernel 2.6.38. - -For programming example, please, look at lavrec.c and lavplay.c code in -the MJPEG-tools (http://mjpeg.sf.net/). - -Additional notes for software developers: - - The driver returns maxwidth and maxheight parameters according to - the current TV standard (norm). Therefore, the software which - communicates with the driver and "asks" for these parameters should - first set the correct norm. Well, it seems logically correct: TV - standard is "more constant" for current country than geometry - settings of a variety of TV capture cards which may work in ITU or - square pixel format. - -Applications ------------- - -Applications known to work with this driver: - -TV viewing: - -* xawtv -* kwintv -* probably any TV application that supports video4linux or video4linux2. - -MJPEG capture/playback: - -* mjpegtools/lavtools (or Linux Video Studio) -* gstreamer -* mplayer - -General raw capture: - -* xawtv -* gstreamer -* probably any application that supports video4linux or video4linux2 - -Video editing: - -* Cinelerra -* MainActor -* mjpegtools (or Linux Video Studio) - - -Concerning buffer sizes, quality, output size etc. --------------------------------------------------- - - -The zr36060 can do 1:2 JPEG compression. This is really the theoretical -maximum that the chipset can reach. The driver can, however, limit compression -to a maximum (size) of 1:4. The reason for this is that some cards (e.g. Buz) -can't handle 1:2 compression without stopping capture after only a few minutes. -With 1:4, it'll mostly work. If you have a Buz, use 'low_bitrate=1' to go into -1:4 max. compression mode. - -100% JPEG quality is thus 1:2 compression in practice. So for a full PAL frame -(size 720x576). The JPEG fields are stored in YUY2 format, so the size of the -fields are 720x288x16/2 bits/field (2 fields/frame) = 207360 bytes/field x 2 = -414720 bytes/frame (add some more bytes for headers and DHT (huffman)/DQT -(quantization) tables, and you'll get to something like 512kB per frame for -1:2 compression. For 1:4 compression, you'd have frames of half this size. - -Some additional explanation by Martin Samuelsson, which also explains the -importance of buffer sizes: --- -> Hmm, I do not think it is really that way. With the current (downloaded -> at 18:00 Monday) driver I get that output sizes for 10 sec: -> -q 50 -b 128 : 24.283.332 Bytes -> -q 50 -b 256 : 48.442.368 -> -q 25 -b 128 : 24.655.992 -> -q 25 -b 256 : 25.859.820 - -I woke up, and can't go to sleep again. I'll kill some time explaining why -this doesn't look strange to me. - -Let's do some math using a width of 704 pixels. I'm not sure whether the Buz -actually use that number or not, but that's not too important right now. - -704x288 pixels, one field, is 202752 pixels. Divided by 64 pixels per block; -3168 blocks per field. Each pixel consist of two bytes; 128 bytes per block; -1024 bits per block. 100% in the new driver mean 1:2 compression; the maximum -output becomes 512 bits per block. Actually 510, but 512 is simpler to use -for calculations. - -Let's say that we specify d1q50. We thus want 256 bits per block; times 3168 -becomes 811008 bits; 101376 bytes per field. We're talking raw bits and bytes -here, so we don't need to do any fancy corrections for bits-per-pixel or such -things. 101376 bytes per field. - -d1 video contains two fields per frame. Those sum up to 202752 bytes per -frame, and one of those frames goes into each buffer. - -But wait a second! -b128 gives 128kB buffers! It's not possible to cram -202752 bytes of JPEG data into 128kB! - -This is what the driver notice and automatically compensate for in your -examples. Let's do some math using this information: - -128kB is 131072 bytes. In this buffer, we want to store two fields, which -leaves 65536 bytes for each field. Using 3168 blocks per field, we get -20.68686868... available bytes per block; 165 bits. We can't allow the -request for 256 bits per block when there's only 165 bits available! The -q50 -option is silently overridden, and the -b128 option takes precedence, leaving -us with the equivalence of -q32. - -This gives us a data rate of 165 bits per block, which, times 3168, sums up -to 65340 bytes per field, out of the allowed 65536. The current driver has -another level of rate limiting; it won't accept -q values that fill more than -6/8 of the specified buffers. (I'm not sure why. "Playing it safe" seem to be -a safe bet. Personally, I think I would have lowered requested-bits-per-block -by one, or something like that.) We can't use 165 bits per block, but have to -lower it again, to 6/8 of the available buffer space: We end up with 124 bits -per block, the equivalence of -q24. With 128kB buffers, you can't use greater -than -q24 at -d1. (And PAL, and 704 pixels width...) - -The third example is limited to -q24 through the same process. The second -example, using very similar calculations, is limited to -q48. The only -example that actually grab at the specified -q value is the last one, which -is clearly visible, looking at the file size. --- - -Conclusion: the quality of the resulting movie depends on buffer size, quality, -whether or not you use 'low_bitrate=1' as insmod option for the zr36060.c -module to do 1:4 instead of 1:2 compression, etc. - -If you experience timeouts, lowering the quality/buffersize or using -'low_bitrate=1 as insmod option for zr36060.o might actually help, as is -proven by the Buz. - -It hangs/crashes/fails/whatevers! Help! ---------------------------------------- - -Make sure that the card has its own interrupts (see /proc/interrupts), check -the output of dmesg at high verbosity (load zr36067.o with debug=2, -load all other modules with debug=1). Check that your mainboard is favorable -(see question 2) and if not, test the card in another computer. Also see the -notes given in question 3 and try lowering quality/buffersize/capturesize -if recording fails after a period of time. - -If all this doesn't help, give a clear description of the problem including -detailed hardware information (memory+brand, mainboard+chipset+brand, which -MJPEG card, processor, other PCI cards that might be of interest), give the -system PnP information (/proc/interrupts, /proc/dma, /proc/devices), and give -the kernel version, driver version, glibc version, gcc version and any other -information that might possibly be of interest. Also provide the dmesg output -at high verbosity. See 'Contacting' on how to contact the developers. - -Maintainers/Contacting ----------------------- - -The driver is currently maintained by Laurent Pinchart and Ronald Bultje -(<laurent.pinchart@skynet.be> and <rbultje@ronald.bitfreak.net>). For bug -reports or questions, please contact the mailinglist instead of the developers -individually. For user questions (i.e. bug reports or how-to questions), send -an email to <mjpeg-users@lists.sf.net>, for developers (i.e. if you want to -help programming), send an email to <mjpeg-developer@lists.sf.net>. See -http://www.sf.net/projects/mjpeg/ for subscription information. - -For bug reports, be sure to include all the information as described in -the section 'It hangs/crashes/fails/whatevers! Help!'. Please make sure -you're using the latest version (http://mjpeg.sf.net/driver-zoran/). - -Previous maintainers/developers of this driver include Serguei Miridonov -<mirsev@cicese.mx>, Wolfgang Scherr <scherr@net4you.net>, Dave Perks -<dperks@ibm.net> and Rainer Johanni <Rainer@Johanni.de>. - -Driver's License ----------------- - - This driver is distributed under the terms of the General Public License. - - 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. - - 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. - -See http://www.gnu.org/ for more information. diff --git a/MAINTAINERS b/MAINTAINERS index d58d215a7c9b..e897d9521000 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -10090,6 +10090,7 @@ L: linux-amlogic@lists.infradead.org W: http://linux-meson.com/ S: Supported F: drivers/media/platform/meson/ao-cec.c +F: drivers/media/platform/meson/ao-cec-g12a.c F: Documentation/devicetree/bindings/media/meson-ao-cec.txt T: git git://linuxtv.org/media_tree.git @@ -14401,9 +14402,8 @@ SOC-CAMERA V4L2 SUBSYSTEM L: linux-media@vger.kernel.org T: git git://linuxtv.org/media_tree.git S: Orphan -F: include/media/soc* -F: drivers/media/i2c/soc_camera/ -F: drivers/media/platform/soc_camera/ +F: include/media/soc_camera.h +F: drivers/staging/media/soc_camera/ SOCIONEXT SYNQUACER I2C DRIVER M: Ard Biesheuvel <ard.biesheuvel@linaro.org> @@ -14743,6 +14743,14 @@ S: Maintained F: drivers/iio/imu/st_lsm6dsx/ F: Documentation/devicetree/bindings/iio/imu/st_lsm6dsx.txt +ST MIPID02 CSI-2 TO PARALLEL BRIDGE DRIVER +M: Mickael Guene <mickael.guene@st.com> +L: linux-media@vger.kernel.org +T: git git://linuxtv.org/media_tree.git +S: Maintained +F: drivers/media/i2c/st-mipid02.c +F: Documentation/devicetree/bindings/media/i2c/st,st-mipid02.txt + ST STM32 I2C/SMBUS DRIVER M: Pierre-Yves MORDRET <pierre-yves.mordret@st.com> L: linux-i2c@vger.kernel.org diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index 102eb35fcf3f..8efaf99243e0 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -31,14 +31,14 @@ comment "Multimedia core support" # config MEDIA_CAMERA_SUPPORT bool "Cameras/video grabbers support" - ---help--- + 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" - ---help--- + help Enable analog TV support. Say Y when you have a TV board with analog support or with a @@ -50,7 +50,7 @@ config MEDIA_ANALOG_TV_SUPPORT config MEDIA_DIGITAL_TV_SUPPORT bool "Digital TV support" - ---help--- + help Enable digital TV support. Say Y when you have a board with digital support or a board with @@ -58,7 +58,7 @@ config MEDIA_DIGITAL_TV_SUPPORT config MEDIA_RADIO_SUPPORT bool "AM/FM radio receivers/transmitters support" - ---help--- + help Enable AM/FM radio support. Additional info and docs are available on the web at @@ -72,14 +72,14 @@ config MEDIA_RADIO_SUPPORT config MEDIA_SDR_SUPPORT bool "Software defined radio support" - ---help--- + help Enable software defined radio support. Say Y when you have a software defined radio device. config MEDIA_CEC_SUPPORT bool "HDMI CEC support" - ---help--- + help Enable support for HDMI CEC (Consumer Electronics Control), which is an optional HDMI feature. @@ -96,7 +96,7 @@ source "drivers/media/cec/Kconfig" config MEDIA_CONTROLLER bool "Media Controller API" depends on MEDIA_CAMERA_SUPPORT || MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT - ---help--- + help Enable the media controller API used to query media devices internal topology and configure it dynamically. @@ -105,7 +105,7 @@ config MEDIA_CONTROLLER config MEDIA_CONTROLLER_DVB bool "Enable Media controller for DVB (EXPERIMENTAL)" depends on MEDIA_CONTROLLER && DVB_CORE - ---help--- + help Enable the media controller API support for DVB. This is currently experimental. @@ -114,7 +114,7 @@ config MEDIA_CONTROLLER_REQUEST_API bool "Enable Media controller Request API (EXPERIMENTAL)" depends on MEDIA_CONTROLLER && STAGING_MEDIA default n - ---help--- + help DO NOT ENABLE THIS OPTION UNLESS YOU KNOW WHAT YOU'RE DOING. This option enables the Request API for the Media controller and V4L2 @@ -137,7 +137,7 @@ config VIDEO_DEV config VIDEO_V4L2_SUBDEV_API bool "V4L2 sub-device userspace API" depends on VIDEO_DEV && MEDIA_CONTROLLER - ---help--- + help Enables the V4L2 sub-device pad-level userspace API used to configure video format, size and frame rate between hardware blocks. diff --git a/drivers/media/Makefile b/drivers/media/Makefile index 985d35ec6b29..4a330d0e5e40 100644 --- a/drivers/media/Makefile +++ b/drivers/media/Makefile @@ -6,6 +6,12 @@ media-objs := media-device.o media-devnode.o media-entity.o \ media-request.o +ifeq ($(CONFIG_MEDIA_CONTROLLER),y) + ifeq ($(CONFIG_USB),y) + media-objs += media-dev-allocator.o + endif +endif + # # I2C drivers should come before other drivers, otherwise they'll fail # when compiled as builtin drivers diff --git a/drivers/media/cec/Kconfig b/drivers/media/cec/Kconfig index 9c2b108c613a..b5aadacf335a 100644 --- a/drivers/media/cec/Kconfig +++ b/drivers/media/cec/Kconfig @@ -2,11 +2,11 @@ config MEDIA_CEC_RC bool "HDMI CEC RC integration" depends on CEC_CORE && RC_CORE depends on CEC_CORE=m || RC_CORE=y - ---help--- + help Pass on CEC remote control messages to the RC framework. config CEC_PIN_ERROR_INJ bool "Enable CEC error injection support" depends on CEC_PIN && DEBUG_FS - ---help--- + help This option enables CEC error injection using debugfs. diff --git a/drivers/media/cec/cec-core.c b/drivers/media/cec/cec-core.c index cc875dabd765..f5d1578e256a 100644 --- a/drivers/media/cec/cec-core.c +++ b/drivers/media/cec/cec-core.c @@ -126,6 +126,7 @@ static int __must_check cec_devnode_register(struct cec_devnode *devnode, /* Part 2: Initialize and register the character device */ cdev_init(&devnode->cdev, &cec_devnode_fops); devnode->cdev.owner = owner; + kobject_set_name(&devnode->cdev.kobj, "cec%d", devnode->minor); ret = cdev_device_add(&devnode->cdev, &devnode->dev); if (ret) { diff --git a/drivers/media/cec/cec-notifier.c b/drivers/media/cec/cec-notifier.c index dd2078b27a41..9598c7778871 100644 --- a/drivers/media/cec/cec-notifier.c +++ b/drivers/media/cec/cec-notifier.c @@ -11,6 +11,7 @@ #include <linux/slab.h> #include <linux/list.h> #include <linux/kref.h> +#include <linux/of_platform.h> #include <media/cec.h> #include <media/cec-notifier.h> @@ -127,3 +128,32 @@ void cec_notifier_unregister(struct cec_notifier *n) cec_notifier_put(n); } EXPORT_SYMBOL_GPL(cec_notifier_unregister); + +struct device *cec_notifier_parse_hdmi_phandle(struct device *dev) +{ + struct platform_device *hdmi_pdev; + struct device *hdmi_dev = NULL; + struct device_node *np; + + np = of_parse_phandle(dev->of_node, "hdmi-phandle", 0); + + if (!np) { + dev_err(dev, "Failed to find HDMI node in device tree\n"); + return ERR_PTR(-ENODEV); + } + hdmi_pdev = of_find_device_by_node(np); + of_node_put(np); + if (hdmi_pdev) { + hdmi_dev = &hdmi_pdev->dev; + /* + * Note that the device struct is only used as a key into the + * cec_notifiers list, it is never actually accessed. + * So we decrement the reference here so we don't leak + * memory. + */ + put_device(hdmi_dev); + return hdmi_dev; + } + return ERR_PTR(-EPROBE_DEFER); +} +EXPORT_SYMBOL_GPL(cec_notifier_parse_hdmi_phandle); diff --git a/drivers/media/common/cx2341x.c b/drivers/media/common/cx2341x.c index 1dcc39b87bb7..121cda73ff88 100644 --- a/drivers/media/common/cx2341x.c +++ b/drivers/media/common/cx2341x.c @@ -1028,7 +1028,7 @@ static int cx2341x_api(void *priv, cx2341x_mbox_func func, return func(priv, cmd, args, 0, data); } -#define NEQ(field) (old->field != new->field) +#define CMP_FIELD(__old, __new, __field) (__old->__field != __new->__field) int cx2341x_update(void *priv, cx2341x_mbox_func func, const struct cx2341x_mpeg_params *old, @@ -1042,20 +1042,22 @@ int cx2341x_update(void *priv, cx2341x_mbox_func func, 11, /* VCD */ 12, /* SVCD */ }; - - int err = 0; - int force = (old == NULL); - u16 temporal = new->video_temporal_filter; + int err; cx2341x_api(priv, func, CX2341X_ENC_SET_OUTPUT_PORT, 2, new->port, 0); - if (force || NEQ(is_50hz)) { + if (!old || + CMP_FIELD(old, new, is_50hz)) { err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_RATE, 1, new->is_50hz); - if (err) return err; + if (err) + return err; } - if (force || NEQ(width) || NEQ(height) || NEQ(video_encoding)) { + if (!old || + CMP_FIELD(old, new, width) || + CMP_FIELD(old, new, height) || + CMP_FIELD(old, new, video_encoding)) { u16 w = new->width; u16 h = new->height; @@ -1065,94 +1067,127 @@ int cx2341x_update(void *priv, cx2341x_mbox_func func, } err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_SIZE, 2, h, w); - if (err) return err; + if (err) + return err; } - if (force || NEQ(stream_type)) { + if (!old || + CMP_FIELD(old, new, stream_type)) { err = cx2341x_api(priv, func, CX2341X_ENC_SET_STREAM_TYPE, 1, mpeg_stream_type[new->stream_type]); - if (err) return err; + if (err) + return err; } - if (force || NEQ(video_aspect)) { + if (!old || + CMP_FIELD(old, new, video_aspect)) { err = cx2341x_api(priv, func, CX2341X_ENC_SET_ASPECT_RATIO, 1, 1 + new->video_aspect); - if (err) return err; + if (err) + return err; } - if (force || NEQ(video_b_frames) || NEQ(video_gop_size)) { + if (!old || + CMP_FIELD(old, new, video_b_frames) || + CMP_FIELD(old, new, video_gop_size)) { err = cx2341x_api(priv, func, CX2341X_ENC_SET_GOP_PROPERTIES, 2, - new->video_gop_size, new->video_b_frames + 1); - if (err) return err; + new->video_gop_size, new->video_b_frames + 1); + if (err) + return err; } - if (force || NEQ(video_gop_closure)) { + if (!old || + CMP_FIELD(old, new, video_gop_closure)) { err = cx2341x_api(priv, func, CX2341X_ENC_SET_GOP_CLOSURE, 1, new->video_gop_closure); - if (err) return err; + if (err) + return err; } - if (force || NEQ(audio_properties)) { + if (!old || + CMP_FIELD(old, new, audio_properties)) { err = cx2341x_api(priv, func, CX2341X_ENC_SET_AUDIO_PROPERTIES, 1, new->audio_properties); - if (err) return err; + if (err) + return err; } - if (force || NEQ(audio_mute)) { + if (!old || + CMP_FIELD(old, new, audio_mute)) { err = cx2341x_api(priv, func, CX2341X_ENC_MUTE_AUDIO, 1, new->audio_mute); - if (err) return err; + if (err) + return err; } - if (force || NEQ(video_bitrate_mode) || NEQ(video_bitrate) || - NEQ(video_bitrate_peak)) { + if (!old || + CMP_FIELD(old, new, video_bitrate_mode) || + CMP_FIELD(old, new, video_bitrate) || + CMP_FIELD(old, new, video_bitrate_peak)) { err = cx2341x_api(priv, func, CX2341X_ENC_SET_BIT_RATE, 5, - new->video_bitrate_mode, new->video_bitrate, - new->video_bitrate_peak / 400, 0, 0); - if (err) return err; + new->video_bitrate_mode, new->video_bitrate, + new->video_bitrate_peak / 400, 0, 0); + if (err) + return err; } - if (force || NEQ(video_spatial_filter_mode) || - NEQ(video_temporal_filter_mode) || - NEQ(video_median_filter_type)) { + if (!old || + CMP_FIELD(old, new, video_spatial_filter_mode) || + CMP_FIELD(old, new, video_temporal_filter_mode) || + CMP_FIELD(old, new, video_median_filter_type)) { err = cx2341x_api(priv, func, CX2341X_ENC_SET_DNR_FILTER_MODE, - 2, new->video_spatial_filter_mode | + 2, + new->video_spatial_filter_mode | (new->video_temporal_filter_mode << 1), - new->video_median_filter_type); - if (err) return err; + new->video_median_filter_type); + if (err) + return err; } - if (force || NEQ(video_luma_median_filter_bottom) || - NEQ(video_luma_median_filter_top) || - NEQ(video_chroma_median_filter_bottom) || - NEQ(video_chroma_median_filter_top)) { + if (!old || + CMP_FIELD(old, new, video_luma_median_filter_bottom) || + CMP_FIELD(old, new, video_luma_median_filter_top) || + CMP_FIELD(old, new, video_chroma_median_filter_bottom) || + CMP_FIELD(old, new, video_chroma_median_filter_top)) { err = cx2341x_api(priv, func, CX2341X_ENC_SET_CORING_LEVELS, 4, - new->video_luma_median_filter_bottom, - new->video_luma_median_filter_top, - new->video_chroma_median_filter_bottom, - new->video_chroma_median_filter_top); - if (err) return err; + new->video_luma_median_filter_bottom, + new->video_luma_median_filter_top, + new->video_chroma_median_filter_bottom, + new->video_chroma_median_filter_top); + if (err) + return err; } - if (force || NEQ(video_luma_spatial_filter_type) || - NEQ(video_chroma_spatial_filter_type)) { + if (!old || + CMP_FIELD(old, new, video_luma_spatial_filter_type) || + CMP_FIELD(old, new, video_chroma_spatial_filter_type)) { err = cx2341x_api(priv, func, CX2341X_ENC_SET_SPATIAL_FILTER_TYPE, 2, new->video_luma_spatial_filter_type, new->video_chroma_spatial_filter_type); - if (err) return err; + if (err) + return err; } - if (force || NEQ(video_spatial_filter) || - old->video_temporal_filter != temporal) { + if (!old || + CMP_FIELD(old, new, video_spatial_filter) || + CMP_FIELD(old, new, video_temporal_filter)) { err = cx2341x_api(priv, func, CX2341X_ENC_SET_DNR_FILTER_PROPS, - 2, new->video_spatial_filter, temporal); - if (err) return err; + 2, new->video_spatial_filter, + new->video_temporal_filter); + if (err) + return err; } - if (force || NEQ(video_temporal_decimation)) { + if (!old || + CMP_FIELD(old, new, video_temporal_decimation)) { err = cx2341x_api(priv, func, CX2341X_ENC_SET_FRAME_DROP_RATE, 1, new->video_temporal_decimation); - if (err) return err; + if (err) + return err; } - if (force || NEQ(video_mute) || - (new->video_mute && NEQ(video_mute_yuv))) { + if (!old || + CMP_FIELD(old, new, video_mute) || + (new->video_mute && CMP_FIELD(old, new, video_mute_yuv))) { err = cx2341x_api(priv, func, CX2341X_ENC_MUTE_VIDEO, 1, - new->video_mute | (new->video_mute_yuv << 8)); - if (err) return err; + new->video_mute | (new->video_mute_yuv << 8)); + if (err) + return err; } - if (force || NEQ(stream_insert_nav_packets)) { + if (!old || + CMP_FIELD(old, new, stream_insert_nav_packets)) { err = cx2341x_api(priv, func, CX2341X_ENC_MISC, 2, - 7, new->stream_insert_nav_packets); - if (err) return err; + 7, new->stream_insert_nav_packets); + if (err) + return err; } return 0; } diff --git a/drivers/media/common/siano/Kconfig b/drivers/media/common/siano/Kconfig index 4bfbd5f463d1..577880b133eb 100644 --- a/drivers/media/common/siano/Kconfig +++ b/drivers/media/common/siano/Kconfig @@ -15,7 +15,7 @@ config SMS_SIANO_RC depends on SMS_USB_DRV || SMS_SDIO_DRV depends on MEDIA_COMMON_OPTIONS default y - ---help--- + help Choose Y to select Remote Controller support for Siano driver. config SMS_SIANO_DEBUGFS @@ -24,7 +24,7 @@ config SMS_SIANO_DEBUGFS depends on DEBUG_FS depends on SMS_USB_DRV = SMS_SDIO_DRV - ---help--- + help Choose Y to enable visualizing a dump of the frontend statistics response packets via debugfs. Currently, works only with Siano USB devices. diff --git a/drivers/media/common/videobuf2/videobuf2-core.c b/drivers/media/common/videobuf2/videobuf2-core.c index 15b6b9c0a2e4..7ebd58a1c431 100644 --- a/drivers/media/common/videobuf2/videobuf2-core.c +++ b/drivers/media/common/videobuf2/videobuf2-core.c @@ -672,6 +672,11 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory, return -EBUSY; } + if (q->waiting_in_dqbuf && *count) { + dprintk(1, "another dup()ped fd is waiting for a buffer\n"); + return -EBUSY; + } + if (*count == 0 || q->num_buffers != 0 || (q->memory != VB2_MEMORY_UNKNOWN && q->memory != memory)) { /* @@ -807,6 +812,10 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory, } if (!q->num_buffers) { + if (q->waiting_in_dqbuf && *count) { + dprintk(1, "another dup()ped fd is waiting for a buffer\n"); + return -EBUSY; + } memset(q->alloc_devs, 0, sizeof(q->alloc_devs)); q->memory = memory; q->waiting_for_buffers = !q->is_output; @@ -915,8 +924,7 @@ void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state) if (WARN_ON(state != VB2_BUF_STATE_DONE && state != VB2_BUF_STATE_ERROR && - state != VB2_BUF_STATE_QUEUED && - state != VB2_BUF_STATE_REQUEUEING)) + state != VB2_BUF_STATE_QUEUED)) state = VB2_BUF_STATE_ERROR; #ifdef CONFIG_VIDEO_ADV_DEBUG @@ -929,8 +937,7 @@ void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state) dprintk(4, "done processing on buffer %d, state: %d\n", vb->index, state); - if (state != VB2_BUF_STATE_QUEUED && - state != VB2_BUF_STATE_REQUEUEING) { + if (state != VB2_BUF_STATE_QUEUED) { /* sync buffers */ for (plane = 0; plane < vb->num_planes; ++plane) call_void_memop(vb, finish, vb->planes[plane].mem_priv); @@ -938,8 +945,7 @@ void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state) } spin_lock_irqsave(&q->done_lock, flags); - if (state == VB2_BUF_STATE_QUEUED || - state == VB2_BUF_STATE_REQUEUEING) { + if (state == VB2_BUF_STATE_QUEUED) { vb->state = VB2_BUF_STATE_QUEUED; } else { /* Add the buffer to the done buffers list */ @@ -949,8 +955,6 @@ void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state) atomic_dec(&q->owned_by_drv_count); if (state != VB2_BUF_STATE_QUEUED && vb->req_obj.req) { - /* This is not supported at the moment */ - WARN_ON(state == VB2_BUF_STATE_REQUEUEING); media_request_object_unbind(&vb->req_obj); media_request_object_put(&vb->req_obj); } @@ -962,10 +966,6 @@ void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state) switch (state) { case VB2_BUF_STATE_QUEUED: return; - case VB2_BUF_STATE_REQUEUEING: - if (q->start_streaming_called) - __enqueue_in_driver(vb); - return; default: /* Inform any processes that may be waiting for buffers */ wake_up(&q->done_wq); @@ -1516,6 +1516,12 @@ int vb2_core_qbuf(struct vb2_queue *q, unsigned int index, void *pb, vb = q->bufs[index]; + if (!req && vb->state != VB2_BUF_STATE_IN_REQUEST && + q->requires_requests) { + dprintk(1, "qbuf requires a request\n"); + return -EBADR; + } + if ((req && q->uses_qbuf) || (!req && vb->state != VB2_BUF_STATE_IN_REQUEST && q->uses_requests)) { @@ -1659,6 +1665,11 @@ static int __vb2_wait_for_done_vb(struct vb2_queue *q, int nonblocking) for (;;) { int ret; + if (q->waiting_in_dqbuf) { + dprintk(1, "another dup()ped fd is waiting for a buffer\n"); + return -EBUSY; + } + if (!q->streaming) { dprintk(1, "streaming off, will not wait for buffers\n"); return -EINVAL; @@ -1686,6 +1697,7 @@ static int __vb2_wait_for_done_vb(struct vb2_queue *q, int nonblocking) return -EAGAIN; } + q->waiting_in_dqbuf = 1; /* * We are streaming and blocking, wait for another buffer to * become ready or for streamoff. Driver's lock is released to @@ -1706,6 +1718,7 @@ static int __vb2_wait_for_done_vb(struct vb2_queue *q, int nonblocking) * the locks or return an error if one occurred. */ call_void_qop(q, wait_finish, q); + q->waiting_in_dqbuf = 0; if (ret) { dprintk(1, "sleep was interrupted\n"); return ret; @@ -2247,6 +2260,9 @@ int vb2_core_queue_init(struct vb2_queue *q) WARN_ON(!q->ops->buf_queue)) return -EINVAL; + if (WARN_ON(q->requires_requests && !q->supports_requests)) + return -EINVAL; + INIT_LIST_HEAD(&q->queued_list); INIT_LIST_HEAD(&q->done_list); spin_lock_init(&q->done_lock); @@ -2585,6 +2601,12 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_ if (!data) return -EINVAL; + if (q->waiting_in_dqbuf) { + dprintk(3, "another dup()ped fd is %s\n", + read ? "reading" : "writing"); + return -EBUSY; + } + /* * Initialize emulator on first call. */ diff --git a/drivers/media/common/videobuf2/videobuf2-v4l2.c b/drivers/media/common/videobuf2/videobuf2-v4l2.c index d09dee20e421..fb9ac7696fc6 100644 --- a/drivers/media/common/videobuf2/videobuf2-v4l2.c +++ b/drivers/media/common/videobuf2/videobuf2-v4l2.c @@ -122,9 +122,9 @@ static int __verify_length(struct vb2_buffer *vb, const struct v4l2_buffer *b) } /* - * __init_v4l2_vb2_buffer() - initialize the v4l2_vb2_buffer struct + * __init_vb2_v4l2_buffer() - initialize the vb2_v4l2_buffer struct */ -static void __init_v4l2_vb2_buffer(struct vb2_buffer *vb) +static void __init_vb2_v4l2_buffer(struct vb2_buffer *vb) { struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); @@ -368,6 +368,12 @@ static int vb2_queue_or_prepare_buf(struct vb2_queue *q, struct media_device *md if (ret) return ret; + if (!is_prepare && (b->flags & V4L2_BUF_FLAG_REQUEST_FD) && + vb->state != VB2_BUF_STATE_DEQUEUED) { + dprintk(1, "%s: buffer is not in dequeued state\n", opname); + return -EINVAL; + } + if (!vb->prepared) { /* Copy relevant information provided by the userspace */ memset(vbuf->planes, 0, @@ -381,6 +387,10 @@ static int vb2_queue_or_prepare_buf(struct vb2_queue *q, struct media_device *md return 0; if (!(b->flags & V4L2_BUF_FLAG_REQUEST_FD)) { + if (q->requires_requests) { + dprintk(1, "%s: queue requires requests\n", opname); + return -EBADR; + } if (q->uses_requests) { dprintk(1, "%s: queue uses requests\n", opname); return -EBUSY; @@ -388,7 +398,7 @@ static int vb2_queue_or_prepare_buf(struct vb2_queue *q, struct media_device *md return 0; } else if (!q->supports_requests) { dprintk(1, "%s: queue does not support requests\n", opname); - return -EACCES; + return -EBADR; } else if (q->uses_qbuf) { dprintk(1, "%s: queue does not use requests\n", opname); return -EBUSY; @@ -419,11 +429,6 @@ static int vb2_queue_or_prepare_buf(struct vb2_queue *q, struct media_device *md !q->ops->buf_out_validate)) return -EINVAL; - if (vb->state != VB2_BUF_STATE_DEQUEUED) { - dprintk(1, "%s: buffer is not in dequeued state\n", opname); - return -EINVAL; - } - if (b->request_fd < 0) { dprintk(1, "%s: request_fd < 0\n", opname); return -EINVAL; @@ -543,7 +548,6 @@ static void __fill_v4l2_buffer(struct vb2_buffer *vb, void *pb) break; case VB2_BUF_STATE_PREPARING: case VB2_BUF_STATE_DEQUEUED: - case VB2_BUF_STATE_REQUEUEING: /* nothing */ break; } @@ -592,7 +596,7 @@ static int __fill_vb2_buffer(struct vb2_buffer *vb, struct vb2_plane *planes) static const struct vb2_buf_ops v4l2_buf_ops = { .verify_planes_array = __verify_planes_array_core, - .init_buffer = __init_v4l2_vb2_buffer, + .init_buffer = __init_vb2_v4l2_buffer, .fill_user_buffer = __fill_v4l2_buffer, .fill_vb2_buffer = __fill_vb2_buffer, .copy_timestamp = __copy_timestamp, diff --git a/drivers/media/common/videobuf2/videobuf2-vmalloc.c b/drivers/media/common/videobuf2/videobuf2-vmalloc.c index 6dfbd5b05907..1c6659f7c394 100644 --- a/drivers/media/common/videobuf2/videobuf2-vmalloc.c +++ b/drivers/media/common/videobuf2/videobuf2-vmalloc.c @@ -46,17 +46,17 @@ static void *vb2_vmalloc_alloc(struct device *dev, unsigned long attrs, buf->size = size; buf->vaddr = vmalloc_user(buf->size); - buf->dma_dir = dma_dir; - buf->handler.refcount = &buf->refcount; - buf->handler.put = vb2_vmalloc_put; - buf->handler.arg = buf; - if (!buf->vaddr) { pr_debug("vmalloc of size %ld failed\n", buf->size); kfree(buf); return ERR_PTR(-ENOMEM); } + buf->dma_dir = dma_dir; + buf->handler.refcount = &buf->refcount; + buf->handler.put = vb2_vmalloc_put; + buf->handler.arg = buf; + refcount_set(&buf->refcount, 1); return buf; } diff --git a/drivers/media/dvb-core/dvbdev.c b/drivers/media/dvb-core/dvbdev.c index 4a5834a1c3b7..a3393cd4e584 100644 --- a/drivers/media/dvb-core/dvbdev.c +++ b/drivers/media/dvb-core/dvbdev.c @@ -526,7 +526,6 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, dvb_media_device_free(dvbdev); kfree(dvbdevfops); kfree(dvbdev); - up_write(&minor_rwsem); mutex_unlock(&dvbdev_register_lock); return ret; } diff --git a/drivers/media/dvb-frontends/as102_fe.c b/drivers/media/dvb-frontends/as102_fe.c index f59a102b0a64..9ba8f39fe310 100644 --- a/drivers/media/dvb-frontends/as102_fe.c +++ b/drivers/media/dvb-frontends/as102_fe.c @@ -467,7 +467,7 @@ struct dvb_frontend *as102_attach(const char *name, /* init frontend callback ops */ memcpy(&fe->ops, &as102_fe_ops, sizeof(struct dvb_frontend_ops)); - strncpy(fe->ops.info.name, name, sizeof(fe->ops.info.name)); + strscpy(fe->ops.info.name, name, sizeof(fe->ops.info.name)); return fe; diff --git a/drivers/media/dvb-frontends/dib7000p.c b/drivers/media/dvb-frontends/dib7000p.c index f8040f6def62..d869029ca87d 100644 --- a/drivers/media/dvb-frontends/dib7000p.c +++ b/drivers/media/dvb-frontends/dib7000p.c @@ -2774,7 +2774,8 @@ static struct dvb_frontend *dib7000p_init(struct i2c_adapter *i2c_adap, u8 i2c_a dibx000_init_i2c_master(&st->i2c_master, DIB7000P, st->i2c_adap, st->i2c_addr); /* init 7090 tuner adapter */ - strncpy(st->dib7090_tuner_adap.name, "DiB7090 tuner interface", sizeof(st->dib7090_tuner_adap.name)); + strscpy(st->dib7090_tuner_adap.name, "DiB7090 tuner interface", + sizeof(st->dib7090_tuner_adap.name)); st->dib7090_tuner_adap.algo = &dib7090_tuner_xfer_algo; st->dib7090_tuner_adap.algo_data = NULL; st->dib7090_tuner_adap.dev.parent = st->i2c_adap->dev.parent; diff --git a/drivers/media/dvb-frontends/dib8000.c b/drivers/media/dvb-frontends/dib8000.c index 85c429cce23e..564669338dc6 100644 --- a/drivers/media/dvb-frontends/dib8000.c +++ b/drivers/media/dvb-frontends/dib8000.c @@ -4458,8 +4458,8 @@ static struct dvb_frontend *dib8000_init(struct i2c_adapter *i2c_adap, u8 i2c_ad dibx000_init_i2c_master(&state->i2c_master, DIB8000, state->i2c.adap, state->i2c.addr); /* init 8096p tuner adapter */ - strncpy(state->dib8096p_tuner_adap.name, "DiB8096P tuner interface", - sizeof(state->dib8096p_tuner_adap.name)); + strscpy(state->dib8096p_tuner_adap.name, "DiB8096P tuner interface", + sizeof(state->dib8096p_tuner_adap.name)); state->dib8096p_tuner_adap.algo = &dib8096p_tuner_xfer_algo; state->dib8096p_tuner_adap.algo_data = NULL; state->dib8096p_tuner_adap.dev.parent = state->i2c.adap->dev.parent; diff --git a/drivers/media/dvb-frontends/dib9000.c b/drivers/media/dvb-frontends/dib9000.c index 1875da07c150..e7838926e6bc 100644 --- a/drivers/media/dvb-frontends/dib9000.c +++ b/drivers/media/dvb-frontends/dib9000.c @@ -2521,7 +2521,8 @@ struct dvb_frontend *dib9000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, c dibx000_init_i2c_master(&st->i2c_master, DIB7000MC, st->i2c.i2c_adap, st->i2c.i2c_addr); st->tuner_adap.dev.parent = i2c_adap->dev.parent; - strncpy(st->tuner_adap.name, "DIB9000_FW TUNER ACCESS", sizeof(st->tuner_adap.name)); + strscpy(st->tuner_adap.name, "DIB9000_FW TUNER ACCESS", + sizeof(st->tuner_adap.name)); st->tuner_adap.algo = &dib9000_tuner_algo; st->tuner_adap.algo_data = NULL; i2c_set_adapdata(&st->tuner_adap, st); @@ -2529,7 +2530,8 @@ struct dvb_frontend *dib9000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, c goto error; st->component_bus.dev.parent = i2c_adap->dev.parent; - strncpy(st->component_bus.name, "DIB9000_FW COMPONENT BUS ACCESS", sizeof(st->component_bus.name)); + strscpy(st->component_bus.name, "DIB9000_FW COMPONENT BUS ACCESS", + sizeof(st->component_bus.name)); st->component_bus.algo = &dib9000_component_bus_algo; st->component_bus.algo_data = NULL; st->component_bus_speed = 340; diff --git a/drivers/media/dvb-frontends/drxd_hard.c b/drivers/media/dvb-frontends/drxd_hard.c index 0a5b15bee1d7..c597d6fc3046 100644 --- a/drivers/media/dvb-frontends/drxd_hard.c +++ b/drivers/media/dvb-frontends/drxd_hard.c @@ -2263,61 +2263,41 @@ static int DRX_Start(struct drxd_state *state, s32 off) case DRX_CHANNEL_LOW: transmissionParams |= SC_RA_RAM_OP_PARAM_PRIO_LO; status = Write16(state, EC_SB_REG_PRIOR__A, EC_SB_REG_PRIOR_LO, 0x0000); - if (status < 0) - break; break; case DRX_CHANNEL_HIGH: transmissionParams |= SC_RA_RAM_OP_PARAM_PRIO_HI; status = Write16(state, EC_SB_REG_PRIOR__A, EC_SB_REG_PRIOR_HI, 0x0000); - if (status < 0) - break; break; - } switch (p->code_rate_HP) { case FEC_1_2: transmissionParams |= SC_RA_RAM_OP_PARAM_RATE_1_2; - if (state->type_A) { + if (state->type_A) status = Write16(state, EC_VD_REG_SET_CODERATE__A, EC_VD_REG_SET_CODERATE_C1_2, 0x0000); - if (status < 0) - break; - } break; default: operationMode |= SC_RA_RAM_OP_AUTO_RATE__M; /* fall through */ case FEC_2_3: transmissionParams |= SC_RA_RAM_OP_PARAM_RATE_2_3; - if (state->type_A) { + if (state->type_A) status = Write16(state, EC_VD_REG_SET_CODERATE__A, EC_VD_REG_SET_CODERATE_C2_3, 0x0000); - if (status < 0) - break; - } break; case FEC_3_4: transmissionParams |= SC_RA_RAM_OP_PARAM_RATE_3_4; - if (state->type_A) { + if (state->type_A) status = Write16(state, EC_VD_REG_SET_CODERATE__A, EC_VD_REG_SET_CODERATE_C3_4, 0x0000); - if (status < 0) - break; - } break; case FEC_5_6: transmissionParams |= SC_RA_RAM_OP_PARAM_RATE_5_6; - if (state->type_A) { + if (state->type_A) status = Write16(state, EC_VD_REG_SET_CODERATE__A, EC_VD_REG_SET_CODERATE_C5_6, 0x0000); - if (status < 0) - break; - } break; case FEC_7_8: transmissionParams |= SC_RA_RAM_OP_PARAM_RATE_7_8; - if (state->type_A) { + if (state->type_A) status = Write16(state, EC_VD_REG_SET_CODERATE__A, EC_VD_REG_SET_CODERATE_C7_8, 0x0000); - if (status < 0) - break; - } break; } if (status < 0) diff --git a/drivers/media/dvb-frontends/dvb-pll.c b/drivers/media/dvb-frontends/dvb-pll.c index 29836c1a40e9..da1b48a18515 100644 --- a/drivers/media/dvb-frontends/dvb-pll.c +++ b/drivers/media/dvb-frontends/dvb-pll.c @@ -839,7 +839,7 @@ struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, memcpy(&fe->ops.tuner_ops, &dvb_pll_tuner_ops, sizeof(struct dvb_tuner_ops)); - strncpy(fe->ops.tuner_ops.info.name, desc->name, + strscpy(fe->ops.tuner_ops.info.name, desc->name, sizeof(fe->ops.tuner_ops.info.name)); fe->ops.tuner_ops.info.frequency_min_hz = desc->min; diff --git a/drivers/media/dvb-frontends/m88ds3103.c b/drivers/media/dvb-frontends/m88ds3103.c index 123f2a33738b..b543e1c4c4f9 100644 --- a/drivers/media/dvb-frontends/m88ds3103.c +++ b/drivers/media/dvb-frontends/m88ds3103.c @@ -309,6 +309,9 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe) u16 u16tmp; u32 tuner_frequency_khz, target_mclk; s32 s32tmp; + static const struct reg_sequence reset_buf[] = { + {0x07, 0x80}, {0x07, 0x00} + }; dev_dbg(&client->dev, "delivery_system=%d modulation=%d frequency=%u symbol_rate=%d inversion=%d pilot=%d rolloff=%d\n", @@ -321,11 +324,7 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe) } /* reset */ - ret = regmap_write(dev->regmap, 0x07, 0x80); - if (ret) - goto err; - - ret = regmap_write(dev->regmap, 0x07, 0x00); + ret = regmap_multi_reg_write(dev->regmap, reset_buf, 2); if (ret) goto err; @@ -1470,7 +1469,7 @@ static int m88ds3103_probe(struct i2c_client *client, /* create dvb_frontend */ memcpy(&dev->fe.ops, &m88ds3103_ops, sizeof(struct dvb_frontend_ops)); if (dev->chip_id == M88RS6000_CHIP_ID) - strncpy(dev->fe.ops.info.name, "Montage Technology M88RS6000", + strscpy(dev->fe.ops.info.name, "Montage Technology M88RS6000", sizeof(dev->fe.ops.info.name)); if (!pdata->attach_in_use) dev->fe.ops.release = NULL; diff --git a/drivers/media/dvb-frontends/si2165.c b/drivers/media/dvb-frontends/si2165.c index feacd8da421d..c9bcd2e95417 100644 --- a/drivers/media/dvb-frontends/si2165.c +++ b/drivers/media/dvb-frontends/si2165.c @@ -275,18 +275,20 @@ static u32 si2165_get_fe_clk(struct si2165_state *state) static int si2165_wait_init_done(struct si2165_state *state) { - int ret = -EINVAL; + int ret; u8 val = 0; int i; for (i = 0; i < 3; ++i) { - si2165_readreg8(state, REG_INIT_DONE, &val); + ret = si2165_readreg8(state, REG_INIT_DONE, &val); + if (ret < 0) + return ret; if (val == 0x01) return 0; usleep_range(1000, 50000); } dev_err(&state->client->dev, "init_done was not set\n"); - return ret; + return -EINVAL; } static int si2165_upload_firmware_block(struct si2165_state *state, @@ -1299,7 +1301,6 @@ MODULE_DEVICE_TABLE(i2c, si2165_id_table); static struct i2c_driver si2165_driver = { .driver = { - .owner = THIS_MODULE, .name = "si2165", }, .probe = si2165_probe, diff --git a/drivers/media/dvb-frontends/ts2020.c b/drivers/media/dvb-frontends/ts2020.c index e5cd2cd414f4..0af9b335be12 100644 --- a/drivers/media/dvb-frontends/ts2020.c +++ b/drivers/media/dvb-frontends/ts2020.c @@ -180,6 +180,9 @@ static int ts2020_set_tuner_rf(struct dvb_frontend *fe) unsigned int utmp; ret = regmap_read(dev->regmap, 0x3d, &utmp); + if (ret) + return ret; + utmp &= 0x7f; if (utmp < 0x16) utmp = 0xa1; diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 6d32f8dcf83b..7793358ab8b3 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -8,7 +8,7 @@ config VIDEO_IR_I2C tristate "I2C module for IR" if !MEDIA_SUBDRV_AUTOSELECT depends on I2C && RC_CORE default y - ---help--- + help Most boards have an IR chip directly connected via GPIO. However, some video boards have the IR connected via I2C bus. @@ -29,7 +29,7 @@ comment "Audio decoders, processors and mixers" config VIDEO_TVAUDIO tristate "Simple audio decoder chips" depends on VIDEO_V4L2 && I2C - ---help--- + help Support for several audio decoder chips found on some bt8xx boards: Philips: tda9840, tda9873h, tda9874h/a, tda9850, tda985x, tea6300, tea6320, tea6420, tda8425, ta8874z. @@ -41,7 +41,7 @@ config VIDEO_TVAUDIO config VIDEO_TDA7432 tristate "Philips TDA7432 audio processor" depends on VIDEO_V4L2 && I2C - ---help--- + help Support for tda7432 audio decoder chip found on some bt8xx boards. To compile this driver as a module, choose M here: the @@ -50,7 +50,7 @@ config VIDEO_TDA7432 config VIDEO_TDA9840 tristate "Philips TDA9840 audio processor" depends on I2C - ---help--- + help Support for tda9840 audio decoder chip found on some Zoran boards. To compile this driver as a module, choose M here: the @@ -60,9 +60,10 @@ config VIDEO_TDA1997X tristate "NXP TDA1997x HDMI receiver" depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API depends on SND_SOC - select SND_PCM select HDMI - ---help--- + select SND_PCM + select V4L2_FWNODE + help V4L2 subdevice driver for the NXP TDA1997x HDMI receivers. To compile this driver as a module, choose M here: the @@ -71,7 +72,7 @@ config VIDEO_TDA1997X config VIDEO_TEA6415C tristate "Philips TEA6415C audio processor" depends on I2C - ---help--- + help Support for tea6415c audio decoder chip found on some bt8xx boards. To compile this driver as a module, choose M here: the @@ -80,7 +81,7 @@ config VIDEO_TEA6415C config VIDEO_TEA6420 tristate "Philips TEA6420 audio processor" depends on I2C - ---help--- + help Support for tea6420 audio decoder chip found on some bt8xx boards. To compile this driver as a module, choose M here: the @@ -89,7 +90,7 @@ config VIDEO_TEA6420 config VIDEO_MSP3400 tristate "Micronas MSP34xx audio decoders" depends on VIDEO_V4L2 && I2C - ---help--- + help Support for the Micronas MSP34xx series of audio decoders. To compile this driver as a module, choose M here: the @@ -98,7 +99,7 @@ config VIDEO_MSP3400 config VIDEO_CS3308 tristate "Cirrus Logic CS3308 audio ADC" depends on VIDEO_V4L2 && I2C - ---help--- + help Support for the Cirrus Logic CS3308 High Performance 8-Channel Analog Volume Control @@ -108,7 +109,7 @@ config VIDEO_CS3308 config VIDEO_CS5345 tristate "Cirrus Logic CS5345 audio ADC" depends on VIDEO_V4L2 && I2C - ---help--- + help Support for the Cirrus Logic CS5345 24-bit, 192 kHz stereo A/D converter. @@ -118,7 +119,7 @@ config VIDEO_CS5345 config VIDEO_CS53L32A tristate "Cirrus Logic CS53L32A audio ADC" depends on VIDEO_V4L2 && I2C - ---help--- + help Support for the Cirrus Logic CS53L32A low voltage stereo A/D converter. @@ -128,7 +129,7 @@ config VIDEO_CS53L32A config VIDEO_TLV320AIC23B tristate "Texas Instruments TLV320AIC23B audio codec" depends on VIDEO_V4L2 && I2C - ---help--- + help Support for the Texas Instruments TLV320AIC23B audio codec. To compile this driver as a module, choose M here: the @@ -137,7 +138,7 @@ config VIDEO_TLV320AIC23B config VIDEO_UDA1342 tristate "Philips UDA1342 audio codec" depends on VIDEO_V4L2 && I2C - ---help--- + help Support for the Philips UDA1342 audio codec. To compile this driver as a module, choose M here: the @@ -146,7 +147,7 @@ config VIDEO_UDA1342 config VIDEO_WM8775 tristate "Wolfson Microelectronics WM8775 audio ADC with input mixer" depends on VIDEO_V4L2 && I2C - ---help--- + help Support for the Wolfson Microelectronics WM8775 high performance stereo A/D Converter with a 4 channel input mixer. @@ -156,7 +157,7 @@ config VIDEO_WM8775 config VIDEO_WM8739 tristate "Wolfson Microelectronics WM8739 stereo audio ADC" depends on VIDEO_V4L2 && I2C - ---help--- + help Support for the Wolfson Microelectronics WM8739 stereo A/D Converter. @@ -166,7 +167,7 @@ config VIDEO_WM8739 config VIDEO_VP27SMPX tristate "Panasonic VP27's internal MPX" depends on VIDEO_V4L2 && I2C - ---help--- + help Support for the internal MPX of the Panasonic VP27s tuner. To compile this driver as a module, choose M here: the @@ -200,7 +201,7 @@ comment "Video decoders" config VIDEO_ADV7180 tristate "Analog Devices ADV7180 decoder" depends on GPIOLIB && VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API - ---help--- + help Support for the Analog Devices ADV7180 video decoder. To compile this driver as a module, choose M here: the @@ -209,7 +210,7 @@ config VIDEO_ADV7180 config VIDEO_ADV7183 tristate "Analog Devices ADV7183 decoder" depends on VIDEO_V4L2 && I2C - ---help--- + help V4l2 subdevice driver for the Analog Devices ADV7183 video decoder. @@ -221,7 +222,8 @@ config VIDEO_ADV748X depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API depends on OF select REGMAP_I2C - ---help--- + select V4L2_FWNODE + help V4L2 subdevice driver for the Analog Devices ADV7481 and ADV7482 HDMI/Analog video decoders. @@ -234,7 +236,7 @@ config VIDEO_ADV7604 depends on GPIOLIB || COMPILE_TEST select HDMI select V4L2_FWNODE - ---help--- + help Support for the Analog Devices ADV7604 video decoder. This is a Analog Devices Component/Graphics Digitizer @@ -247,7 +249,7 @@ config VIDEO_ADV7604_CEC bool "Enable Analog Devices ADV7604 CEC support" depends on VIDEO_ADV7604 select CEC_CORE - ---help--- + help When selected the adv7604 will support the optional HDMI CEC feature. @@ -255,7 +257,7 @@ config VIDEO_ADV7842 tristate "Analog Devices ADV7842 decoder" depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API select HDMI - ---help--- + help Support for the Analog Devices ADV7842 video decoder. This is a Analog Devices Component/Graphics/SD Digitizer @@ -268,14 +270,14 @@ config VIDEO_ADV7842_CEC bool "Enable Analog Devices ADV7842 CEC support" depends on VIDEO_ADV7842 select CEC_CORE - ---help--- + help When selected the adv7842 will support the optional HDMI CEC feature. config VIDEO_BT819 tristate "BT819A VideoStream decoder" depends on VIDEO_V4L2 && I2C - ---help--- + help Support for BT819A video decoder. To compile this driver as a module, choose M here: the @@ -284,7 +286,7 @@ config VIDEO_BT819 config VIDEO_BT856 tristate "BT856 VideoStream decoder" depends on VIDEO_V4L2 && I2C - ---help--- + help Support for BT856 video decoder. To compile this driver as a module, choose M here: the @@ -293,7 +295,7 @@ config VIDEO_BT856 config VIDEO_BT866 tristate "BT866 VideoStream decoder" depends on VIDEO_V4L2 && I2C - ---help--- + help Support for BT866 video decoder. To compile this driver as a module, choose M here: the @@ -302,7 +304,7 @@ config VIDEO_BT866 config VIDEO_KS0127 tristate "KS0127 video decoder" depends on VIDEO_V4L2 && I2C - ---help--- + help Support for KS0127 video decoder. This chip is used on AverMedia AVS6EYES Zoran-based MJPEG @@ -314,53 +316,16 @@ config VIDEO_KS0127 config VIDEO_ML86V7667 tristate "OKI ML86V7667 video decoder" depends on VIDEO_V4L2 && I2C - ---help--- + help Support for the OKI Semiconductor ML86V7667 video decoder. To compile this driver as a module, choose M here: the module will be called ml86v7667. -config VIDEO_AD5820 - tristate "AD5820 lens voice coil support" - depends on I2C && VIDEO_V4L2 && 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 - help - This is a driver for the AK7375 camera lens voice coil. - AK7375 is a 12 bit DAC with 120mA output current sink - capability. This is designed for linear control of - voice coil motors, controlled via I2C serial interface. - -config VIDEO_DW9714 - tristate "DW9714 lens voice coil support" - depends on I2C && VIDEO_V4L2 && MEDIA_CONTROLLER - depends on 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 - capability. This is designed for linear control of - voice coil motors, controlled via I2C serial interface. - -config VIDEO_DW9807_VCM - tristate "DW9807 lens voice coil support" - depends on I2C && VIDEO_V4L2 && MEDIA_CONTROLLER - depends on 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. - config VIDEO_SAA7110 tristate "Philips SAA7110 video decoder" depends on VIDEO_V4L2 && I2C - ---help--- + help Support for the Philips SAA7110 video decoders. To compile this driver as a module, choose M here: the @@ -369,7 +334,7 @@ config VIDEO_SAA7110 config VIDEO_SAA711X tristate "Philips SAA7111/3/4/5 video decoders" depends on VIDEO_V4L2 && I2C - ---help--- + help Support for the Philips SAA7111/3/4/5 video decoders. To compile this driver as a module, choose M here: the @@ -380,7 +345,7 @@ config VIDEO_TC358743 depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API select HDMI select V4L2_FWNODE - ---help--- + help Support for the Toshiba TC358743 HDMI to MIPI CSI-2 bridge. To compile this driver as a module, choose M here: the @@ -390,7 +355,7 @@ config VIDEO_TC358743_CEC bool "Enable Toshiba TC358743 CEC support" depends on VIDEO_TC358743 select CEC_CORE - ---help--- + help When selected the tc358743 will support the optional HDMI CEC feature. @@ -398,7 +363,7 @@ config VIDEO_TVP514X tristate "Texas Instruments TVP514x video decoder" depends on VIDEO_V4L2 && I2C select V4L2_FWNODE - ---help--- + help This is a Video4Linux2 sensor driver for the TI TVP5146/47 decoder. It is currently working with the TI OMAP3 camera controller. @@ -410,7 +375,7 @@ config VIDEO_TVP5150 tristate "Texas Instruments TVP5150 video decoder" depends on VIDEO_V4L2 && I2C select V4L2_FWNODE - ---help--- + help Support for the Texas Instruments TVP5150 video decoder. To compile this driver as a module, choose M here: the @@ -420,7 +385,7 @@ config VIDEO_TVP7002 tristate "Texas Instruments TVP7002 video decoder" depends on VIDEO_V4L2 && I2C select V4L2_FWNODE - ---help--- + help Support for the Texas Instruments TVP7002 video decoder. To compile this driver as a module, choose M here: the @@ -429,7 +394,7 @@ config VIDEO_TVP7002 config VIDEO_TW2804 tristate "Techwell TW2804 multiple video decoder" depends on VIDEO_V4L2 && I2C - ---help--- + help Support for the Techwell tw2804 multiple video decoder. To compile this driver as a module, choose M here: the @@ -438,7 +403,7 @@ config VIDEO_TW2804 config VIDEO_TW9903 tristate "Techwell TW9903 video decoder" depends on VIDEO_V4L2 && I2C - ---help--- + help Support for the Techwell tw9903 multi-standard video decoder with high quality down scaler. @@ -448,7 +413,7 @@ config VIDEO_TW9903 config VIDEO_TW9906 tristate "Techwell TW9906 video decoder" depends on VIDEO_V4L2 && I2C - ---help--- + help Support for the Techwell tw9906 enhanced multi-standard comb filter video decoder with YCbCr input support. @@ -458,7 +423,7 @@ config VIDEO_TW9906 config VIDEO_TW9910 tristate "Techwell TW9910 video decoder" depends on VIDEO_V4L2 && I2C - ---help--- + help Support for Techwell TW9910 NTSC/PAL/SECAM video decoder. To compile this driver as a module, choose M here: the @@ -467,7 +432,7 @@ config VIDEO_TW9910 config VIDEO_VPX3220 tristate "vpx3220a, vpx3216b & vpx3214c video decoders" depends on VIDEO_V4L2 && I2C - ---help--- + help Support for VPX322x video decoders. To compile this driver as a module, choose M here: the @@ -478,7 +443,7 @@ comment "Video and audio decoders" config VIDEO_SAA717X tristate "Philips SAA7171/3/4 audio/video decoders" depends on VIDEO_V4L2 && I2C - ---help--- + help Support for the Philips SAA7171/3/4 audio/video decoders. To compile this driver as a module, choose M here: the @@ -491,7 +456,7 @@ comment "Video encoders" config VIDEO_SAA7127 tristate "Philips SAA7127/9 digital video encoders" depends on VIDEO_V4L2 && I2C - ---help--- + help Support for the Philips SAA7127/9 digital video encoders. To compile this driver as a module, choose M here: the @@ -500,7 +465,7 @@ config VIDEO_SAA7127 config VIDEO_SAA7185 tristate "Philips SAA7185 video encoder" depends on VIDEO_V4L2 && I2C - ---help--- + help Support for the Philips SAA7185 video encoder. To compile this driver as a module, choose M here: the @@ -509,7 +474,7 @@ config VIDEO_SAA7185 config VIDEO_ADV7170 tristate "Analog Devices ADV7170 video encoder" depends on VIDEO_V4L2 && I2C - ---help--- + help Support for the Analog Devices ADV7170 video encoder driver To compile this driver as a module, choose M here: the @@ -518,7 +483,7 @@ config VIDEO_ADV7170 config VIDEO_ADV7175 tristate "Analog Devices ADV7175 video encoder" depends on VIDEO_V4L2 && I2C - ---help--- + help Support for the Analog Devices ADV7175 video encoder driver To compile this driver as a module, choose M here: the @@ -546,7 +511,7 @@ config VIDEO_ADV7511 tristate "Analog Devices ADV7511 encoder" depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API select HDMI - ---help--- + help Support for the Analog Devices ADV7511 video encoder. This is a Analog Devices HDMI transmitter. @@ -558,14 +523,14 @@ config VIDEO_ADV7511_CEC bool "Enable Analog Devices ADV7511 CEC support" depends on VIDEO_ADV7511 select CEC_CORE - ---help--- + help When selected the adv7511 will support the optional HDMI CEC feature. config VIDEO_AD9389B tristate "Analog Devices AD9389B encoder" depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API - ---help--- + help Support for the Analog Devices AD9389B video encoder. This is a Analog Devices HDMI transmitter. @@ -582,7 +547,7 @@ config VIDEO_AK881X config VIDEO_THS8200 tristate "Texas Instruments THS8200 video encoder" depends on VIDEO_V4L2 && I2C - ---help--- + help Support for the Texas Instruments THS8200 video encoder. To compile this driver as a module, choose M here: the @@ -612,7 +577,7 @@ config VIDEO_IMX258 tristate "Sony IMX258 sensor support" depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API depends on MEDIA_CAMERA_SUPPORT - ---help--- + help This is a Video4Linux2 sensor driver for the Sony IMX258 camera. @@ -624,7 +589,7 @@ config VIDEO_IMX274 depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API depends on MEDIA_CAMERA_SUPPORT select REGMAP_I2C - ---help--- + help This is a V4L2 sensor driver for the Sony IMX274 CMOS image sensor. @@ -666,7 +631,7 @@ config VIDEO_OV2659 depends on VIDEO_V4L2 && I2C depends on MEDIA_CAMERA_SUPPORT select V4L2_FWNODE - ---help--- + help This is a Video4Linux2 sensor driver for the OmniVision OV2659 camera. @@ -678,7 +643,7 @@ config VIDEO_OV2680 depends on VIDEO_V4L2 && I2C && MEDIA_CONTROLLER depends on MEDIA_CAMERA_SUPPORT select V4L2_FWNODE - ---help--- + help This is a Video4Linux2 sensor driver for the OmniVision OV2680 camera. @@ -690,7 +655,7 @@ config VIDEO_OV2685 depends on VIDEO_V4L2 && I2C && MEDIA_CONTROLLER depends on MEDIA_CAMERA_SUPPORT select V4L2_FWNODE - ---help--- + help This is a Video4Linux2 sensor driver for the OmniVision OV2685 camera. @@ -703,7 +668,7 @@ config VIDEO_OV5640 depends on GPIOLIB && VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API depends on MEDIA_CAMERA_SUPPORT select V4L2_FWNODE - ---help--- + help This is a Video4Linux2 sensor driver for the Omnivision OV5640 camera sensor with a MIPI CSI-2 interface. @@ -713,7 +678,7 @@ config VIDEO_OV5645 depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API depends on MEDIA_CAMERA_SUPPORT select V4L2_FWNODE - ---help--- + help This is a Video4Linux2 sensor driver for the OmniVision OV5645 camera. @@ -725,7 +690,7 @@ config VIDEO_OV5647 depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API depends on MEDIA_CAMERA_SUPPORT select V4L2_FWNODE - ---help--- + help This is a Video4Linux2 sensor driver for the OmniVision OV5647 camera. @@ -736,7 +701,7 @@ config VIDEO_OV6650 tristate "OmniVision OV6650 sensor support" depends on I2C && VIDEO_V4L2 depends on MEDIA_CAMERA_SUPPORT - ---help--- + help This is a Video4Linux2 sensor driver for the OmniVision OV6650 camera. @@ -749,7 +714,7 @@ config VIDEO_OV5670 depends on MEDIA_CAMERA_SUPPORT depends on MEDIA_CONTROLLER select V4L2_FWNODE - ---help--- + help This is a Video4Linux2 sensor driver for the OmniVision OV5670 camera. @@ -760,7 +725,7 @@ config VIDEO_OV5695 tristate "OmniVision OV5695 sensor support" depends on I2C && VIDEO_V4L2 depends on MEDIA_CAMERA_SUPPORT - ---help--- + help This is a Video4Linux2 sensor driver for the OmniVision OV5695 camera. @@ -784,7 +749,7 @@ config VIDEO_OV772X depends on I2C && VIDEO_V4L2 depends on MEDIA_CAMERA_SUPPORT select REGMAP_SCCB - ---help--- + help This is a Video4Linux2 sensor driver for the OmniVision OV772x camera. @@ -795,7 +760,7 @@ config VIDEO_OV7640 tristate "OmniVision OV7640 sensor support" depends on I2C && VIDEO_V4L2 depends on MEDIA_CAMERA_SUPPORT - ---help--- + help This is a Video4Linux2 sensor driver for the OmniVision OV7640 camera. @@ -807,7 +772,7 @@ config VIDEO_OV7670 depends on I2C && VIDEO_V4L2 depends on MEDIA_CAMERA_SUPPORT select V4L2_FWNODE - ---help--- + help This is a Video4Linux2 sensor driver for the OmniVision OV7670 VGA camera. It currently only works with the M88ALP01 controller. @@ -816,7 +781,7 @@ config VIDEO_OV7740 tristate "OmniVision OV7740 sensor support" depends on I2C && VIDEO_V4L2 depends on MEDIA_CAMERA_SUPPORT - ---help--- + help This is a Video4Linux2 sensor driver for the OmniVision OV7740 VGA camera sensor. @@ -843,7 +808,7 @@ config VIDEO_OV9650 tristate "OmniVision OV9650/OV9652 sensor support" depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API select REGMAP_SCCB - ---help--- + help This is a V4L2 sensor driver for the Omnivision OV9650 and OV9652 camera sensors. @@ -852,7 +817,7 @@ config VIDEO_OV13858 depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API depends on MEDIA_CAMERA_SUPPORT select V4L2_FWNODE - ---help--- + help This is a Video4Linux2 sensor driver for the OmniVision OV13858 camera. @@ -860,7 +825,7 @@ config VIDEO_VS6624 tristate "ST VS6624 sensor support" depends on VIDEO_V4L2 && I2C depends on MEDIA_CAMERA_SUPPORT - ---help--- + help This is a Video4Linux2 sensor driver for the ST VS6624 camera. @@ -880,7 +845,7 @@ config VIDEO_MT9M032 depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API depends on MEDIA_CAMERA_SUPPORT select VIDEO_APTINA_PLL - ---help--- + help This driver supports MT9M032 camera sensors from Aptina, monochrome models only. @@ -897,7 +862,7 @@ config VIDEO_MT9P031 depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API depends on MEDIA_CAMERA_SUPPORT select VIDEO_APTINA_PLL - ---help--- + help This is a Video4Linux2 sensor driver for the Aptina (Micron) mt9p031 5 Mpixel camera. @@ -905,7 +870,7 @@ config VIDEO_MT9T001 tristate "Aptina MT9T001 support" depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API depends on MEDIA_CAMERA_SUPPORT - ---help--- + help This is a Video4Linux2 sensor driver for the Aptina (Micron) mt0t001 3 Mpixel camera. @@ -913,7 +878,7 @@ config VIDEO_MT9T112 tristate "Aptina MT9T111/MT9T112 support" depends on I2C && VIDEO_V4L2 depends on MEDIA_CAMERA_SUPPORT - ---help--- + help This is a Video4Linux2 sensor driver for the Aptina (Micron) MT9T111 and MT9T112 3 Mpixel camera. @@ -924,7 +889,7 @@ config VIDEO_MT9V011 tristate "Micron mt9v011 sensor support" depends on I2C && VIDEO_V4L2 depends on MEDIA_CAMERA_SUPPORT - ---help--- + help This is a Video4Linux2 sensor driver for the Micron mt0v011 1.3 Mpixel camera. It currently only works with the em28xx driver. @@ -935,7 +900,7 @@ config VIDEO_MT9V032 depends on MEDIA_CAMERA_SUPPORT select REGMAP_I2C select V4L2_FWNODE - ---help--- + help This is a Video4Linux2 sensor driver for the Micron MT9V032 752x480 CMOS sensor. @@ -954,14 +919,14 @@ config VIDEO_SR030PC30 tristate "Siliconfile SR030PC30 sensor support" depends on I2C && VIDEO_V4L2 depends on MEDIA_CAMERA_SUPPORT - ---help--- + help This driver supports SR030PC30 VGA camera from Siliconfile config VIDEO_NOON010PC30 tristate "Siliconfile NOON010PC30 sensor support" depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API depends on MEDIA_CAMERA_SUPPORT - ---help--- + help This driver supports NOON010PC30 CIF camera from Siliconfile source "drivers/media/i2c/m5mols/Kconfig" @@ -981,7 +946,7 @@ config VIDEO_S5K6AA tristate "Samsung S5K6AAFX sensor support" depends on MEDIA_CAMERA_SUPPORT depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API - ---help--- + help This is a V4L2 sensor driver for Samsung S5K6AA(FX) 1.3M camera sensor with an embedded SoC image signal processor. @@ -989,7 +954,7 @@ config VIDEO_S5K6A3 tristate "Samsung S5K6A3 sensor support" depends on MEDIA_CAMERA_SUPPORT depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API - ---help--- + help This is a V4L2 sensor driver for Samsung S5K6A3 raw camera sensor. @@ -997,7 +962,7 @@ config VIDEO_S5K4ECGX tristate "Samsung S5K4ECGX sensor support" depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API select CRC32 - ---help--- + help This is a V4L2 sensor driver for Samsung S5K4ECGX 5M camera sensor with an embedded SoC image signal processor. @@ -1005,7 +970,7 @@ config VIDEO_S5K5BAF tristate "Samsung S5K5BAF sensor support" depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API select V4L2_FWNODE - ---help--- + help This is a V4L2 sensor driver for Samsung S5K5BAF 2M camera sensor with an embedded SoC image signal processor. @@ -1016,17 +981,56 @@ config VIDEO_S5C73M3 tristate "Samsung S5C73M3 sensor support" depends on I2C && SPI && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API select V4L2_FWNODE - ---help--- + help This is a V4L2 sensor driver for Samsung S5C73M3 8 Mpixel camera. +comment "Lens drivers" + +config VIDEO_AD5820 + tristate "AD5820 lens voice coil support" + depends on I2C && VIDEO_V4L2 && 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 + help + This is a driver for the AK7375 camera lens voice coil. + AK7375 is a 12 bit DAC with 120mA output current sink + capability. This is designed for linear control of + voice coil motors, controlled via I2C serial interface. + +config VIDEO_DW9714 + tristate "DW9714 lens voice coil support" + depends on I2C && VIDEO_V4L2 && MEDIA_CONTROLLER + depends on 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 + capability. This is designed for linear control of + voice coil motors, controlled via I2C serial interface. + +config VIDEO_DW9807_VCM + tristate "DW9807 lens voice coil support" + depends on I2C && VIDEO_V4L2 && MEDIA_CONTROLLER + depends on 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. + comment "Flash devices" config VIDEO_ADP1653 tristate "ADP1653 flash support" depends on I2C && VIDEO_V4L2 && MEDIA_CONTROLLER depends on MEDIA_CAMERA_SUPPORT - ---help--- + help This is a driver for the ADP1653 flash controller. It is used for example in Nokia N900. @@ -1035,7 +1039,7 @@ config VIDEO_LM3560 depends on I2C && VIDEO_V4L2 && MEDIA_CONTROLLER depends on MEDIA_CAMERA_SUPPORT select REGMAP_I2C - ---help--- + help This is a driver for the lm3560 dual flash controllers. It controls flash, torch LEDs. @@ -1044,7 +1048,7 @@ config VIDEO_LM3646 depends on I2C && VIDEO_V4L2 && MEDIA_CONTROLLER depends on MEDIA_CAMERA_SUPPORT select REGMAP_I2C - ---help--- + help This is a driver for the lm3646 dual flash controllers. It controls flash, torch LEDs. @@ -1053,7 +1057,7 @@ comment "Video improvement chips" config VIDEO_UPD64031A tristate "NEC Electronics uPD64031A Ghost Reduction" depends on VIDEO_V4L2 && I2C - ---help--- + 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 @@ -1065,7 +1069,7 @@ config VIDEO_UPD64031A config VIDEO_UPD64083 tristate "NEC Electronics uPD64083 3-Dimensional Y/C separation" depends on VIDEO_V4L2 && I2C - ---help--- + 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. @@ -1079,7 +1083,7 @@ config VIDEO_SAA6752HS tristate "Philips SAA6752HS MPEG-2 Audio/Video Encoder" depends on VIDEO_V4L2 && I2C select CRC32 - ---help--- + help Support for the Philips SAA6752HS MPEG-2 video and MPEG-audio/AC-3 audio encoder with multiplexer. @@ -1091,7 +1095,7 @@ comment "SDR tuner chips" config SDR_MAX2175 tristate "Maxim 2175 RF to Bits tuner" depends on VIDEO_V4L2 && MEDIA_SDR_SUPPORT && I2C - ---help--- + help Support for Maxim 2175 tuner. It is an advanced analog/digital radio receiver with RF-to-Bits front-end designed for SDR solutions. @@ -1112,7 +1116,7 @@ config VIDEO_THS7303 config VIDEO_M52790 tristate "Mitsubishi M52790 A/V switch" depends on VIDEO_V4L2 && I2C - ---help--- + help Support for the Mitsubishi M52790 A/V switch. To compile this driver as a module, choose M here: the @@ -1123,7 +1127,7 @@ config VIDEO_I2C depends on VIDEO_V4L2 && I2C select VIDEOBUF2_VMALLOC imply HWMON - ---help--- + help Enable the I2C transport video support which supports the following: * Panasonic AMG88xx Grid-Eye Sensors @@ -1132,6 +1136,19 @@ config VIDEO_I2C 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 && VIDEO_V4L2_SUBDEV_API + depends on MEDIA_CAMERA_SUPPORT + 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 diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile index a64fca82e0c4..d8ad9dad495d 100644 --- a/drivers/media/i2c/Makefile +++ b/drivers/media/i2c/Makefile @@ -113,5 +113,6 @@ obj-$(CONFIG_VIDEO_IMX258) += imx258.o obj-$(CONFIG_VIDEO_IMX274) += imx274.o obj-$(CONFIG_VIDEO_IMX319) += imx319.o obj-$(CONFIG_VIDEO_IMX355) += imx355.o +obj-$(CONFIG_VIDEO_ST_MIPID02) += st-mipid02.o obj-$(CONFIG_SDR_MAX2175) += max2175.o diff --git a/drivers/media/i2c/cx25840/Kconfig b/drivers/media/i2c/cx25840/Kconfig index 451133ad41ff..f4b31d7cb440 100644 --- a/drivers/media/i2c/cx25840/Kconfig +++ b/drivers/media/i2c/cx25840/Kconfig @@ -1,7 +1,7 @@ config VIDEO_CX25840 tristate "Conexant CX2584x audio/video decoders" depends on VIDEO_V4L2 && I2C - ---help--- + help Support for the Conexant CX2584x audio/video decoders. To compile this driver as a module, choose M here: the diff --git a/drivers/media/i2c/et8ek8/Kconfig b/drivers/media/i2c/et8ek8/Kconfig index 9fe409e95666..ab23b41bf353 100644 --- a/drivers/media/i2c/et8ek8/Kconfig +++ b/drivers/media/i2c/et8ek8/Kconfig @@ -2,6 +2,6 @@ config VIDEO_ET8EK8 tristate "ET8EK8 camera sensor support" depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API select V4L2_FWNODE - ---help--- + help This is a driver for the Toshiba ET8EK8 5 MP camera sensor. It is used for example in Nokia N900 (RX-51). diff --git a/drivers/media/i2c/imx214.c b/drivers/media/i2c/imx214.c index 9857e151db46..83e9961b0505 100644 --- a/drivers/media/i2c/imx214.c +++ b/drivers/media/i2c/imx214.c @@ -588,12 +588,10 @@ static int imx214_set_format(struct v4l2_subdev *sd, __crop = __imx214_get_pad_crop(imx214, cfg, format->pad, format->which); - if (format) - mode = v4l2_find_nearest_size(imx214_modes, - ARRAY_SIZE(imx214_modes), width, height, - format->format.width, format->format.height); - else - mode = &imx214_modes[0]; + mode = v4l2_find_nearest_size(imx214_modes, + ARRAY_SIZE(imx214_modes), width, height, + format->format.width, + format->format.height); __crop->width = mode->width; __crop->height = mode->height; diff --git a/drivers/media/i2c/m5mols/Kconfig b/drivers/media/i2c/m5mols/Kconfig index dc8c2505907e..be0bb3f1bc22 100644 --- a/drivers/media/i2c/m5mols/Kconfig +++ b/drivers/media/i2c/m5mols/Kconfig @@ -2,5 +2,5 @@ config VIDEO_M5MOLS tristate "Fujitsu M-5MOLS 8MP sensor support" depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API depends on MEDIA_CAMERA_SUPPORT - ---help--- + help This driver supports Fujitsu M-5MOLS camera sensor with ISP diff --git a/drivers/media/i2c/ov2659.c b/drivers/media/i2c/ov2659.c index 799acce803fe..5ed2413eac8a 100644 --- a/drivers/media/i2c/ov2659.c +++ b/drivers/media/i2c/ov2659.c @@ -1117,8 +1117,10 @@ static int ov2659_set_fmt(struct v4l2_subdev *sd, if (ov2659_formats[index].code == mf->code) break; - if (index < 0) - return -EINVAL; + if (index < 0) { + index = 0; + mf->code = ov2659_formats[index].code; + } mf->colorspace = V4L2_COLORSPACE_SRGB; mf->field = V4L2_FIELD_NONE; @@ -1130,7 +1132,7 @@ static int ov2659_set_fmt(struct v4l2_subdev *sd, mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad); *mf = fmt->format; #else - return -ENOTTY; + ret = -ENOTTY; #endif } else { s64 val; diff --git a/drivers/media/i2c/ov6650.c b/drivers/media/i2c/ov6650.c index c33fd584cb44..1b972e591b48 100644 --- a/drivers/media/i2c/ov6650.c +++ b/drivers/media/i2c/ov6650.c @@ -804,15 +804,25 @@ static int ov6650_prog_dflt(struct i2c_client *client) return ret; } -static int ov6650_video_probe(struct i2c_client *client) +static int ov6650_video_probe(struct v4l2_subdev *sd) { + struct i2c_client *client = v4l2_get_subdevdata(sd); struct ov6650 *priv = to_ov6650(client); u8 pidh, pidl, midh, midl; int ret; - ret = ov6650_s_power(&priv->subdev, 1); - if (ret < 0) + priv->clk = v4l2_clk_get(&client->dev, NULL); + if (IS_ERR(priv->clk)) { + ret = PTR_ERR(priv->clk); + dev_err(&client->dev, "v4l2_clk request err: %d\n", ret); return ret; + } + + ret = ov6650_s_power(sd, 1); + if (ret < 0) + goto eclkput; + + msleep(20); /* * check and show product ID and manufacturer ID @@ -846,7 +856,12 @@ static int ov6650_video_probe(struct i2c_client *client) ret = v4l2_ctrl_handler_setup(&priv->hdl); done: - ov6650_s_power(&priv->subdev, 0); + ov6650_s_power(sd, 0); + if (!ret) + return 0; +eclkput: + v4l2_clk_put(priv->clk); + return ret; } @@ -929,6 +944,10 @@ static const struct v4l2_subdev_ops ov6650_subdev_ops = { .pad = &ov6650_pad_ops, }; +static const struct v4l2_subdev_internal_ops ov6650_internal_ops = { + .registered = ov6650_video_probe, +}; + /* * i2c_driver function */ @@ -989,18 +1008,12 @@ static int ov6650_probe(struct i2c_client *client, priv->code = MEDIA_BUS_FMT_YUYV8_2X8; priv->colorspace = V4L2_COLORSPACE_JPEG; - priv->clk = v4l2_clk_get(&client->dev, NULL); - if (IS_ERR(priv->clk)) { - ret = PTR_ERR(priv->clk); - goto eclkget; - } + priv->subdev.internal_ops = &ov6650_internal_ops; + priv->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - ret = ov6650_video_probe(client); - if (ret) { - v4l2_clk_put(priv->clk); -eclkget: + ret = v4l2_async_register_subdev(&priv->subdev); + if (ret) v4l2_ctrl_handler_free(&priv->hdl); - } return ret; } @@ -1010,7 +1023,7 @@ static int ov6650_remove(struct i2c_client *client) struct ov6650 *priv = to_ov6650(client); v4l2_clk_put(priv->clk); - v4l2_device_unregister_subdev(&priv->subdev); + v4l2_async_unregister_subdev(&priv->subdev); v4l2_ctrl_handler_free(&priv->hdl); return 0; } diff --git a/drivers/media/i2c/ov7670.c b/drivers/media/i2c/ov7670.c index a7d26b294eb5..44c3eed8a858 100644 --- a/drivers/media/i2c/ov7670.c +++ b/drivers/media/i2c/ov7670.c @@ -864,7 +864,15 @@ static int ov7675_set_framerate(struct v4l2_subdev *sd, /* Recalculate frame rate */ ov7675_get_framerate(sd, tpf); - return ov7675_apply_framerate(sd); + /* + * If the device is not powered up by the host driver do + * not apply any changes to H/W at this time. Instead + * the framerate will be restored right after power-up. + */ + if (info->on) + return ov7675_apply_framerate(sd); + + return 0; } static void ov7670_get_framerate_legacy(struct v4l2_subdev *sd, @@ -895,7 +903,16 @@ static int ov7670_set_framerate_legacy(struct v4l2_subdev *sd, info->clkrc = (info->clkrc & 0x80) | div; tpf->numerator = 1; tpf->denominator = info->clock_speed / div; - return ov7670_write(sd, REG_CLKRC, info->clkrc); + + /* + * If the device is not powered up by the host driver do + * not apply any changes to H/W at this time. Instead + * the framerate will be restored right after power-up. + */ + if (info->on) + return ov7670_write(sd, REG_CLKRC, info->clkrc); + + return 0; } /* @@ -1105,9 +1122,13 @@ static int ov7670_set_fmt(struct v4l2_subdev *sd, if (ret) return ret; - ret = ov7670_apply_fmt(sd); - if (ret) - return ret; + /* + * If the device is not powered up by the host driver do + * not apply any changes to H/W at this time. Instead + * the frame format will be restored right after power-up. + */ + if (info->on) + return ov7670_apply_fmt(sd); return 0; } @@ -1664,6 +1685,7 @@ static int ov7670_s_power(struct v4l2_subdev *sd, int on) if (on) { ov7670_power_on (sd); + ov7670_init(sd, 0); ov7670_apply_fmt(sd); ov7675_apply_framerate(sd); v4l2_ctrl_handler_setup(&info->hdl); diff --git a/drivers/media/i2c/ov7740.c b/drivers/media/i2c/ov7740.c index dfece91ce96b..54e80a60aa57 100644 --- a/drivers/media/i2c/ov7740.c +++ b/drivers/media/i2c/ov7740.c @@ -448,6 +448,27 @@ static int ov7740_get_gain(struct ov7740 *ov7740, struct v4l2_ctrl *ctrl) return 0; } +static int ov7740_get_exp(struct ov7740 *ov7740, struct v4l2_ctrl *ctrl) +{ + struct regmap *regmap = ov7740->regmap; + unsigned int value0, value1; + int ret; + + if (ctrl->val == V4L2_EXPOSURE_MANUAL) + return 0; + + ret = regmap_read(regmap, REG_AEC, &value0); + if (ret) + return ret; + ret = regmap_read(regmap, REG_HAEC, &value1); + if (ret) + return ret; + + ov7740->exposure->val = (value1 << 8) | (value0 & 0xff); + + return 0; +} + static int ov7740_set_exp(struct regmap *regmap, int value) { int ret; @@ -494,6 +515,9 @@ static int ov7740_get_volatile_ctrl(struct v4l2_ctrl *ctrl) case V4L2_CID_AUTOGAIN: ret = ov7740_get_gain(ov7740, ctrl); break; + case V4L2_CID_EXPOSURE_AUTO: + ret = ov7740_get_exp(ov7740, ctrl); + break; default: ret = -EINVAL; break; @@ -991,8 +1015,6 @@ static int ov7740_init_controls(struct ov7740 *ov7740) ov7740->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &ov7740_ctrl_ops, V4L2_CID_EXPOSURE, 0, 65535, 1, 500); - if (ov7740->exposure) - ov7740->exposure->flags |= V4L2_CTRL_FLAG_VOLATILE; ov7740->auto_exposure = v4l2_ctrl_new_std_menu(ctrl_hdlr, &ov7740_ctrl_ops, @@ -1003,7 +1025,7 @@ static int ov7740_init_controls(struct ov7740 *ov7740) v4l2_ctrl_auto_cluster(3, &ov7740->auto_wb, 0, false); v4l2_ctrl_auto_cluster(2, &ov7740->auto_gain, 0, true); v4l2_ctrl_auto_cluster(2, &ov7740->auto_exposure, - V4L2_EXPOSURE_MANUAL, false); + V4L2_EXPOSURE_MANUAL, true); v4l2_ctrl_cluster(2, &ov7740->hflip); if (ctrl_hdlr->error) { diff --git a/drivers/media/i2c/smiapp/Kconfig b/drivers/media/i2c/smiapp/Kconfig index f59718d8e51e..26b54f2aa95b 100644 --- a/drivers/media/i2c/smiapp/Kconfig +++ b/drivers/media/i2c/smiapp/Kconfig @@ -4,5 +4,5 @@ config VIDEO_SMIAPP depends on MEDIA_CAMERA_SUPPORT select VIDEO_SMIAPP_PLL select V4L2_FWNODE - ---help--- + help This is a generic driver for SMIA++/SMIA camera modules. diff --git a/drivers/media/i2c/st-mipid02.c b/drivers/media/i2c/st-mipid02.c new file mode 100644 index 000000000000..9369f38dbf3d --- /dev/null +++ b/drivers/media/i2c/st-mipid02.c @@ -0,0 +1,1033 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Driver for ST MIPID02 CSI-2 to PARALLEL bridge + * + * Copyright (C) STMicroelectronics SA 2019 + * Authors: Mickael Guene <mickael.guene@st.com> + * for STMicroelectronics. + * + * + */ + +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/gpio/consumer.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/of_graph.h> +#include <linux/regulator/consumer.h> +#include <media/v4l2-async.h> +#include <media/v4l2-ctrls.h> +#include <media/v4l2-device.h> +#include <media/v4l2-fwnode.h> +#include <media/v4l2-subdev.h> + +#define MIPID02_CLK_LANE_WR_REG1 0x01 +#define MIPID02_CLK_LANE_REG1 0x02 +#define MIPID02_CLK_LANE_REG3 0x04 +#define MIPID02_DATA_LANE0_REG1 0x05 +#define MIPID02_DATA_LANE0_REG2 0x06 +#define MIPID02_DATA_LANE1_REG1 0x09 +#define MIPID02_DATA_LANE1_REG2 0x0a +#define MIPID02_MODE_REG1 0x14 +#define MIPID02_MODE_REG2 0x15 +#define MIPID02_DATA_ID_RREG 0x17 +#define MIPID02_DATA_SELECTION_CTRL 0x19 +#define MIPID02_PIX_WIDTH_CTRL 0x1e +#define MIPID02_PIX_WIDTH_CTRL_EMB 0x1f + +/* Bits definition for MIPID02_CLK_LANE_REG1 */ +#define CLK_ENABLE BIT(0) +/* Bits definition for MIPID02_CLK_LANE_REG3 */ +#define CLK_MIPI_CSI BIT(1) +/* Bits definition for MIPID02_DATA_LANE0_REG1 */ +#define DATA_ENABLE BIT(0) +/* Bits definition for MIPID02_DATA_LANEx_REG2 */ +#define DATA_MIPI_CSI BIT(0) +/* Bits definition for MIPID02_MODE_REG1 */ +#define MODE_DATA_SWAP BIT(2) +#define MODE_NO_BYPASS BIT(6) +/* Bits definition for MIPID02_MODE_REG2 */ +#define MODE_HSYNC_ACTIVE_HIGH BIT(1) +#define MODE_VSYNC_ACTIVE_HIGH BIT(2) +/* Bits definition for MIPID02_DATA_SELECTION_CTRL */ +#define SELECTION_MANUAL_DATA BIT(2) +#define SELECTION_MANUAL_WIDTH BIT(3) + +static const u32 mipid02_supported_fmt_codes[] = { + MEDIA_BUS_FMT_SBGGR8_1X8, MEDIA_BUS_FMT_SGBRG8_1X8, + MEDIA_BUS_FMT_SGRBG8_1X8, MEDIA_BUS_FMT_SRGGB8_1X8, + MEDIA_BUS_FMT_SBGGR10_1X10, MEDIA_BUS_FMT_SGBRG10_1X10, + MEDIA_BUS_FMT_SGRBG10_1X10, MEDIA_BUS_FMT_SRGGB10_1X10, + MEDIA_BUS_FMT_SBGGR12_1X12, MEDIA_BUS_FMT_SGBRG12_1X12, + MEDIA_BUS_FMT_SGRBG12_1X12, MEDIA_BUS_FMT_SRGGB12_1X12, + MEDIA_BUS_FMT_UYVY8_1X16, MEDIA_BUS_FMT_BGR888_1X24 +}; + +/* regulator supplies */ +static const char * const mipid02_supply_name[] = { + "VDDE", /* 1.8V digital I/O supply */ + "VDDIN", /* 1V8 voltage regulator supply */ +}; + +#define MIPID02_NUM_SUPPLIES ARRAY_SIZE(mipid02_supply_name) + +#define MIPID02_SINK_0 0 +#define MIPID02_SINK_1 1 +#define MIPID02_SOURCE 2 +#define MIPID02_PAD_NB 3 + +struct mipid02_dev { + struct i2c_client *i2c_client; + struct regulator_bulk_data supplies[MIPID02_NUM_SUPPLIES]; + struct v4l2_subdev sd; + struct media_pad pad[MIPID02_PAD_NB]; + struct clk *xclk; + struct gpio_desc *reset_gpio; + /* endpoints info */ + struct v4l2_fwnode_endpoint rx; + u64 link_frequency; + struct v4l2_fwnode_endpoint tx; + /* remote source */ + struct v4l2_async_subdev asd; + struct v4l2_async_notifier notifier; + struct v4l2_subdev *s_subdev; + /* registers */ + struct { + u8 clk_lane_reg1; + u8 data_lane0_reg1; + u8 data_lane1_reg1; + u8 mode_reg1; + u8 mode_reg2; + u8 data_id_rreg; + u8 pix_width_ctrl; + u8 pix_width_ctrl_emb; + } r; + /* lock to protect all members below */ + struct mutex lock; + bool streaming; + struct v4l2_mbus_framefmt fmt; +}; + +static int bpp_from_code(__u32 code) +{ + switch (code) { + case MEDIA_BUS_FMT_SBGGR8_1X8: + case MEDIA_BUS_FMT_SGBRG8_1X8: + case MEDIA_BUS_FMT_SGRBG8_1X8: + case MEDIA_BUS_FMT_SRGGB8_1X8: + return 8; + case MEDIA_BUS_FMT_SBGGR10_1X10: + case MEDIA_BUS_FMT_SGBRG10_1X10: + case MEDIA_BUS_FMT_SGRBG10_1X10: + case MEDIA_BUS_FMT_SRGGB10_1X10: + return 10; + case MEDIA_BUS_FMT_SBGGR12_1X12: + case MEDIA_BUS_FMT_SGBRG12_1X12: + case MEDIA_BUS_FMT_SGRBG12_1X12: + case MEDIA_BUS_FMT_SRGGB12_1X12: + return 12; + case MEDIA_BUS_FMT_UYVY8_1X16: + return 16; + case MEDIA_BUS_FMT_BGR888_1X24: + return 24; + default: + return 0; + } +} + +static u8 data_type_from_code(__u32 code) +{ + switch (code) { + case MEDIA_BUS_FMT_SBGGR8_1X8: + case MEDIA_BUS_FMT_SGBRG8_1X8: + case MEDIA_BUS_FMT_SGRBG8_1X8: + case MEDIA_BUS_FMT_SRGGB8_1X8: + return 0x2a; + case MEDIA_BUS_FMT_SBGGR10_1X10: + case MEDIA_BUS_FMT_SGBRG10_1X10: + case MEDIA_BUS_FMT_SGRBG10_1X10: + case MEDIA_BUS_FMT_SRGGB10_1X10: + return 0x2b; + case MEDIA_BUS_FMT_SBGGR12_1X12: + case MEDIA_BUS_FMT_SGBRG12_1X12: + case MEDIA_BUS_FMT_SGRBG12_1X12: + case MEDIA_BUS_FMT_SRGGB12_1X12: + return 0x2c; + case MEDIA_BUS_FMT_UYVY8_1X16: + return 0x1e; + case MEDIA_BUS_FMT_BGR888_1X24: + return 0x24; + default: + return 0; + } +} + +static void init_format(struct v4l2_mbus_framefmt *fmt) +{ + fmt->code = MEDIA_BUS_FMT_SBGGR8_1X8; + fmt->field = V4L2_FIELD_NONE; + fmt->colorspace = V4L2_COLORSPACE_SRGB; + fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(V4L2_COLORSPACE_SRGB); + fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE; + fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(V4L2_COLORSPACE_SRGB); + fmt->width = 640; + fmt->height = 480; +} + +static __u32 get_fmt_code(__u32 code) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(mipid02_supported_fmt_codes); i++) { + if (code == mipid02_supported_fmt_codes[i]) + return code; + } + + return mipid02_supported_fmt_codes[0]; +} + +static __u32 serial_to_parallel_code(__u32 serial) +{ + if (serial == MEDIA_BUS_FMT_UYVY8_1X16) + return MEDIA_BUS_FMT_UYVY8_2X8; + if (serial == MEDIA_BUS_FMT_BGR888_1X24) + return MEDIA_BUS_FMT_BGR888_3X8; + + return serial; +} + +static inline struct mipid02_dev *to_mipid02_dev(struct v4l2_subdev *sd) +{ + return container_of(sd, struct mipid02_dev, sd); +} + +static int mipid02_read_reg(struct mipid02_dev *bridge, u16 reg, u8 *val) +{ + struct i2c_client *client = bridge->i2c_client; + struct i2c_msg msg[2]; + u8 buf[2]; + int ret; + + buf[0] = reg >> 8; + buf[1] = reg & 0xff; + + msg[0].addr = client->addr; + msg[0].flags = client->flags; + msg[0].buf = buf; + msg[0].len = sizeof(buf); + + msg[1].addr = client->addr; + msg[1].flags = client->flags | I2C_M_RD; + msg[1].buf = val; + msg[1].len = 1; + + ret = i2c_transfer(client->adapter, msg, 2); + if (ret < 0) { + dev_dbg(&client->dev, "%s: %x i2c_transfer, reg: %x => %d\n", + __func__, client->addr, reg, ret); + return ret; + } + + return 0; +} + +static int mipid02_write_reg(struct mipid02_dev *bridge, u16 reg, u8 val) +{ + struct i2c_client *client = bridge->i2c_client; + struct i2c_msg msg; + u8 buf[3]; + int ret; + + buf[0] = reg >> 8; + buf[1] = reg & 0xff; + buf[2] = val; + + msg.addr = client->addr; + msg.flags = client->flags; + msg.buf = buf; + msg.len = sizeof(buf); + + ret = i2c_transfer(client->adapter, &msg, 1); + if (ret < 0) { + dev_dbg(&client->dev, "%s: i2c_transfer, reg: %x => %d\n", + __func__, reg, ret); + return ret; + } + + return 0; +} + +static int mipid02_get_regulators(struct mipid02_dev *bridge) +{ + unsigned int i; + + for (i = 0; i < MIPID02_NUM_SUPPLIES; i++) + bridge->supplies[i].supply = mipid02_supply_name[i]; + + return devm_regulator_bulk_get(&bridge->i2c_client->dev, + MIPID02_NUM_SUPPLIES, + bridge->supplies); +} + +static void mipid02_apply_reset(struct mipid02_dev *bridge) +{ + gpiod_set_value_cansleep(bridge->reset_gpio, 0); + usleep_range(5000, 10000); + gpiod_set_value_cansleep(bridge->reset_gpio, 1); + usleep_range(5000, 10000); + gpiod_set_value_cansleep(bridge->reset_gpio, 0); + usleep_range(5000, 10000); +} + +static int mipid02_set_power_on(struct mipid02_dev *bridge) +{ + struct i2c_client *client = bridge->i2c_client; + int ret; + + ret = clk_prepare_enable(bridge->xclk); + if (ret) { + dev_err(&client->dev, "%s: failed to enable clock\n", __func__); + return ret; + } + + ret = regulator_bulk_enable(MIPID02_NUM_SUPPLIES, + bridge->supplies); + if (ret) { + dev_err(&client->dev, "%s: failed to enable regulators\n", + __func__); + goto xclk_off; + } + + if (bridge->reset_gpio) { + dev_dbg(&client->dev, "apply reset"); + mipid02_apply_reset(bridge); + } else { + dev_dbg(&client->dev, "don't apply reset"); + usleep_range(5000, 10000); + } + + return 0; + +xclk_off: + clk_disable_unprepare(bridge->xclk); + return ret; +} + +static void mipid02_set_power_off(struct mipid02_dev *bridge) +{ + regulator_bulk_disable(MIPID02_NUM_SUPPLIES, bridge->supplies); + clk_disable_unprepare(bridge->xclk); +} + +static int mipid02_detect(struct mipid02_dev *bridge) +{ + u8 reg; + + /* + * There is no version registers. Just try to read register + * MIPID02_CLK_LANE_WR_REG1. + */ + return mipid02_read_reg(bridge, MIPID02_CLK_LANE_WR_REG1, ®); +} + +static u32 mipid02_get_link_freq_from_cid_pixel_rate(struct mipid02_dev *bridge, + struct v4l2_subdev *subdev) +{ + struct v4l2_fwnode_endpoint *ep = &bridge->rx; + struct v4l2_ctrl *ctrl; + u32 pixel_clock; + u32 bpp = bpp_from_code(bridge->fmt.code); + + ctrl = v4l2_ctrl_find(subdev->ctrl_handler, V4L2_CID_PIXEL_RATE); + if (!ctrl) + return 0; + pixel_clock = v4l2_ctrl_g_ctrl_int64(ctrl); + + return pixel_clock * bpp / (2 * ep->bus.mipi_csi2.num_data_lanes); +} + +/* + * We need to know link frequency to setup clk_lane_reg1 timings. Link frequency + * will be computed using connected device V4L2_CID_PIXEL_RATE, bit per pixel + * and number of lanes. + */ +static int mipid02_configure_from_rx_speed(struct mipid02_dev *bridge) +{ + struct i2c_client *client = bridge->i2c_client; + struct v4l2_subdev *subdev = bridge->s_subdev; + u32 link_freq; + + link_freq = mipid02_get_link_freq_from_cid_pixel_rate(bridge, subdev); + if (!link_freq) { + dev_err(&client->dev, "Failed to detect link frequency"); + return -EINVAL; + } + + dev_dbg(&client->dev, "detect link_freq = %d Hz", link_freq); + bridge->r.clk_lane_reg1 |= (2000000000 / link_freq) << 2; + + return 0; +} + +static int mipid02_configure_clk_lane(struct mipid02_dev *bridge) +{ + struct i2c_client *client = bridge->i2c_client; + struct v4l2_fwnode_endpoint *ep = &bridge->rx; + bool *polarities = ep->bus.mipi_csi2.lane_polarities; + + /* midid02 doesn't support clock lane remapping */ + if (ep->bus.mipi_csi2.clock_lane != 0) { + dev_err(&client->dev, "clk lane must be map to lane 0\n"); + return -EINVAL; + } + bridge->r.clk_lane_reg1 |= (polarities[0] << 1) | CLK_ENABLE; + + return 0; +} + +static int mipid02_configure_data0_lane(struct mipid02_dev *bridge, int nb, + bool are_lanes_swap, bool *polarities) +{ + bool are_pin_swap = are_lanes_swap ? polarities[2] : polarities[1]; + + if (nb == 1 && are_lanes_swap) + return 0; + + /* + * data lane 0 as pin swap polarity reversed compared to clock and + * data lane 1 + */ + if (!are_pin_swap) + bridge->r.data_lane0_reg1 = 1 << 1; + bridge->r.data_lane0_reg1 |= DATA_ENABLE; + + return 0; +} + +static int mipid02_configure_data1_lane(struct mipid02_dev *bridge, int nb, + bool are_lanes_swap, bool *polarities) +{ + bool are_pin_swap = are_lanes_swap ? polarities[1] : polarities[2]; + + if (nb == 1 && !are_lanes_swap) + return 0; + + if (are_pin_swap) + bridge->r.data_lane1_reg1 = 1 << 1; + bridge->r.data_lane1_reg1 |= DATA_ENABLE; + + return 0; +} + +static int mipid02_configure_from_rx(struct mipid02_dev *bridge) +{ + struct v4l2_fwnode_endpoint *ep = &bridge->rx; + bool are_lanes_swap = ep->bus.mipi_csi2.data_lanes[0] == 2; + bool *polarities = ep->bus.mipi_csi2.lane_polarities; + int nb = ep->bus.mipi_csi2.num_data_lanes; + int ret; + + ret = mipid02_configure_clk_lane(bridge); + if (ret) + return ret; + + ret = mipid02_configure_data0_lane(bridge, nb, are_lanes_swap, + polarities); + if (ret) + return ret; + + ret = mipid02_configure_data1_lane(bridge, nb, are_lanes_swap, + polarities); + if (ret) + return ret; + + bridge->r.mode_reg1 |= are_lanes_swap ? MODE_DATA_SWAP : 0; + bridge->r.mode_reg1 |= (nb - 1) << 1; + + return mipid02_configure_from_rx_speed(bridge); +} + +static int mipid02_configure_from_tx(struct mipid02_dev *bridge) +{ + struct v4l2_fwnode_endpoint *ep = &bridge->tx; + + bridge->r.pix_width_ctrl = ep->bus.parallel.bus_width; + bridge->r.pix_width_ctrl_emb = ep->bus.parallel.bus_width; + if (ep->bus.parallel.flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) + bridge->r.mode_reg2 |= MODE_HSYNC_ACTIVE_HIGH; + if (ep->bus.parallel.flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) + bridge->r.mode_reg2 |= MODE_VSYNC_ACTIVE_HIGH; + + return 0; +} + +static int mipid02_configure_from_code(struct mipid02_dev *bridge) +{ + u8 data_type; + + bridge->r.data_id_rreg = 0; + data_type = data_type_from_code(bridge->fmt.code); + if (!data_type) + return -EINVAL; + bridge->r.data_id_rreg = data_type; + + return 0; +} + +static int mipid02_stream_disable(struct mipid02_dev *bridge) +{ + struct i2c_client *client = bridge->i2c_client; + int ret; + + /* Disable all lanes */ + ret = mipid02_write_reg(bridge, MIPID02_CLK_LANE_REG1, 0); + if (ret) + goto error; + ret = mipid02_write_reg(bridge, MIPID02_DATA_LANE0_REG1, 0); + if (ret) + goto error; + ret = mipid02_write_reg(bridge, MIPID02_DATA_LANE1_REG1, 0); + if (ret) + goto error; +error: + if (ret) + dev_err(&client->dev, "failed to stream off %d", ret); + + return ret; +} + +static int mipid02_stream_enable(struct mipid02_dev *bridge) +{ + struct i2c_client *client = bridge->i2c_client; + int ret = -EINVAL; + + if (!bridge->s_subdev) + goto error; + + memset(&bridge->r, 0, sizeof(bridge->r)); + /* build registers content */ + ret = mipid02_configure_from_rx(bridge); + if (ret) + goto error; + ret = mipid02_configure_from_tx(bridge); + if (ret) + goto error; + ret = mipid02_configure_from_code(bridge); + if (ret) + goto error; + + /* write mipi registers */ + ret = mipid02_write_reg(bridge, MIPID02_CLK_LANE_REG1, + bridge->r.clk_lane_reg1); + if (ret) + goto error; + ret = mipid02_write_reg(bridge, MIPID02_CLK_LANE_REG3, CLK_MIPI_CSI); + if (ret) + goto error; + ret = mipid02_write_reg(bridge, MIPID02_DATA_LANE0_REG1, + bridge->r.data_lane0_reg1); + if (ret) + goto error; + ret = mipid02_write_reg(bridge, MIPID02_DATA_LANE0_REG2, + DATA_MIPI_CSI); + if (ret) + goto error; + ret = mipid02_write_reg(bridge, MIPID02_DATA_LANE1_REG1, + bridge->r.data_lane1_reg1); + if (ret) + goto error; + ret = mipid02_write_reg(bridge, MIPID02_DATA_LANE1_REG2, + DATA_MIPI_CSI); + if (ret) + goto error; + ret = mipid02_write_reg(bridge, MIPID02_MODE_REG1, + MODE_NO_BYPASS | bridge->r.mode_reg1); + if (ret) + goto error; + ret = mipid02_write_reg(bridge, MIPID02_MODE_REG2, + bridge->r.mode_reg2); + if (ret) + goto error; + ret = mipid02_write_reg(bridge, MIPID02_DATA_ID_RREG, + bridge->r.data_id_rreg); + if (ret) + goto error; + ret = mipid02_write_reg(bridge, MIPID02_DATA_SELECTION_CTRL, + SELECTION_MANUAL_DATA | SELECTION_MANUAL_WIDTH); + if (ret) + goto error; + ret = mipid02_write_reg(bridge, MIPID02_PIX_WIDTH_CTRL, + bridge->r.pix_width_ctrl); + if (ret) + goto error; + ret = mipid02_write_reg(bridge, MIPID02_PIX_WIDTH_CTRL_EMB, + bridge->r.pix_width_ctrl_emb); + if (ret) + goto error; + + return 0; + +error: + dev_err(&client->dev, "failed to stream on %d", ret); + mipid02_stream_disable(bridge); + + return ret; +} + +static int mipid02_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct mipid02_dev *bridge = to_mipid02_dev(sd); + struct i2c_client *client = bridge->i2c_client; + int ret = 0; + + dev_dbg(&client->dev, "%s : requested %d / current = %d", __func__, + enable, bridge->streaming); + mutex_lock(&bridge->lock); + + if (bridge->streaming == enable) + goto out; + + ret = enable ? mipid02_stream_enable(bridge) : + mipid02_stream_disable(bridge); + if (!ret) + bridge->streaming = enable; + +out: + dev_dbg(&client->dev, "%s current now = %d / %d", __func__, + bridge->streaming, ret); + mutex_unlock(&bridge->lock); + + return ret; +} + +static int mipid02_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) +{ + struct mipid02_dev *bridge = to_mipid02_dev(sd); + int ret = 0; + + switch (code->pad) { + case MIPID02_SINK_0: + if (code->index >= ARRAY_SIZE(mipid02_supported_fmt_codes)) + ret = -EINVAL; + else + code->code = mipid02_supported_fmt_codes[code->index]; + break; + case MIPID02_SOURCE: + if (code->index == 0) + code->code = serial_to_parallel_code(bridge->fmt.code); + else + ret = -EINVAL; + break; + default: + ret = -EINVAL; + } + + return ret; +} + +static int mipid02_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) +{ + struct v4l2_mbus_framefmt *mbus_fmt = &format->format; + struct mipid02_dev *bridge = to_mipid02_dev(sd); + struct i2c_client *client = bridge->i2c_client; + struct v4l2_mbus_framefmt *fmt; + + dev_dbg(&client->dev, "%s probe %d", __func__, format->pad); + + if (format->pad >= MIPID02_PAD_NB) + return -EINVAL; + /* second CSI-2 pad not yet supported */ + if (format->pad == MIPID02_SINK_1) + return -EINVAL; + + if (format->which == V4L2_SUBDEV_FORMAT_TRY) + fmt = v4l2_subdev_get_try_format(&bridge->sd, cfg, format->pad); + else + fmt = &bridge->fmt; + + mutex_lock(&bridge->lock); + + *mbus_fmt = *fmt; + /* code may need to be converted for source */ + if (format->pad == MIPID02_SOURCE) + mbus_fmt->code = serial_to_parallel_code(mbus_fmt->code); + + mutex_unlock(&bridge->lock); + + return 0; +} + +static void mipid02_set_fmt_source(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) +{ + struct mipid02_dev *bridge = to_mipid02_dev(sd); + + /* source pad mirror active sink pad */ + format->format = bridge->fmt; + /* but code may need to be converted */ + format->format.code = serial_to_parallel_code(format->format.code); + + /* only apply format for V4L2_SUBDEV_FORMAT_TRY case */ + if (format->which != V4L2_SUBDEV_FORMAT_TRY) + return; + + *v4l2_subdev_get_try_format(sd, cfg, format->pad) = format->format; +} + +static void mipid02_set_fmt_sink(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) +{ + struct mipid02_dev *bridge = to_mipid02_dev(sd); + struct v4l2_mbus_framefmt *fmt; + + format->format.code = get_fmt_code(format->format.code); + + if (format->which == V4L2_SUBDEV_FORMAT_TRY) + fmt = v4l2_subdev_get_try_format(sd, cfg, format->pad); + else + fmt = &bridge->fmt; + + *fmt = format->format; +} + +static int mipid02_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_format *format) +{ + struct mipid02_dev *bridge = to_mipid02_dev(sd); + struct i2c_client *client = bridge->i2c_client; + int ret = 0; + + dev_dbg(&client->dev, "%s for %d", __func__, format->pad); + + if (format->pad >= MIPID02_PAD_NB) + return -EINVAL; + /* second CSI-2 pad not yet supported */ + if (format->pad == MIPID02_SINK_1) + return -EINVAL; + + mutex_lock(&bridge->lock); + + if (bridge->streaming) { + ret = -EBUSY; + goto error; + } + + if (format->pad == MIPID02_SOURCE) + mipid02_set_fmt_source(sd, cfg, format); + else + mipid02_set_fmt_sink(sd, cfg, format); + +error: + mutex_unlock(&bridge->lock); + + return ret; +} + +static const struct v4l2_subdev_video_ops mipid02_video_ops = { + .s_stream = mipid02_s_stream, +}; + +static const struct v4l2_subdev_pad_ops mipid02_pad_ops = { + .enum_mbus_code = mipid02_enum_mbus_code, + .get_fmt = mipid02_get_fmt, + .set_fmt = mipid02_set_fmt, +}; + +static const struct v4l2_subdev_ops mipid02_subdev_ops = { + .video = &mipid02_video_ops, + .pad = &mipid02_pad_ops, +}; + +static const struct media_entity_operations mipid02_subdev_entity_ops = { + .link_validate = v4l2_subdev_link_validate, +}; + +static int mipid02_async_bound(struct v4l2_async_notifier *notifier, + struct v4l2_subdev *s_subdev, + struct v4l2_async_subdev *asd) +{ + struct mipid02_dev *bridge = to_mipid02_dev(notifier->sd); + struct i2c_client *client = bridge->i2c_client; + int source_pad; + int ret; + + dev_dbg(&client->dev, "sensor_async_bound call %p", s_subdev); + + source_pad = media_entity_get_fwnode_pad(&s_subdev->entity, + s_subdev->fwnode, + MEDIA_PAD_FL_SOURCE); + if (source_pad < 0) { + dev_err(&client->dev, "Couldn't find output pad for subdev %s\n", + s_subdev->name); + return source_pad; + } + + ret = media_create_pad_link(&s_subdev->entity, source_pad, + &bridge->sd.entity, 0, + MEDIA_LNK_FL_ENABLED | + MEDIA_LNK_FL_IMMUTABLE); + if (ret) { + dev_err(&client->dev, "Couldn't create media link %d", ret); + return ret; + } + + bridge->s_subdev = s_subdev; + + return 0; +} + +static void mipid02_async_unbind(struct v4l2_async_notifier *notifier, + struct v4l2_subdev *s_subdev, + struct v4l2_async_subdev *asd) +{ + struct mipid02_dev *bridge = to_mipid02_dev(notifier->sd); + + bridge->s_subdev = NULL; +} + +static const struct v4l2_async_notifier_operations mipid02_notifier_ops = { + .bound = mipid02_async_bound, + .unbind = mipid02_async_unbind, +}; + +static int mipid02_parse_rx_ep(struct mipid02_dev *bridge) +{ + struct v4l2_fwnode_endpoint ep = { .bus_type = V4L2_MBUS_CSI2_DPHY }; + struct i2c_client *client = bridge->i2c_client; + struct device_node *ep_node; + int ret; + + /* parse rx (endpoint 0) */ + ep_node = of_graph_get_endpoint_by_regs(bridge->i2c_client->dev.of_node, + 0, 0); + if (!ep_node) { + dev_err(&client->dev, "unable to find port0 ep"); + ret = -EINVAL; + goto error; + } + + ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep_node), &ep); + if (ret) { + dev_err(&client->dev, "Could not parse v4l2 endpoint %d\n", + ret); + goto error_of_node_put; + } + + /* do some sanity checks */ + if (ep.bus.mipi_csi2.num_data_lanes > 2) { + dev_err(&client->dev, "max supported data lanes is 2 / got %d", + ep.bus.mipi_csi2.num_data_lanes); + ret = -EINVAL; + goto error_of_node_put; + } + + /* register it for later use */ + bridge->rx = ep; + + /* register async notifier so we get noticed when sensor is connected */ + bridge->asd.match.fwnode = + fwnode_graph_get_remote_port_parent(of_fwnode_handle(ep_node)); + bridge->asd.match_type = V4L2_ASYNC_MATCH_FWNODE; + of_node_put(ep_node); + + v4l2_async_notifier_init(&bridge->notifier); + ret = v4l2_async_notifier_add_subdev(&bridge->notifier, &bridge->asd); + if (ret) { + dev_err(&client->dev, "fail to register asd to notifier %d", + ret); + fwnode_handle_put(bridge->asd.match.fwnode); + return ret; + } + bridge->notifier.ops = &mipid02_notifier_ops; + + ret = v4l2_async_subdev_notifier_register(&bridge->sd, + &bridge->notifier); + if (ret) + v4l2_async_notifier_cleanup(&bridge->notifier); + + return ret; + +error_of_node_put: + of_node_put(ep_node); +error: + + return ret; +} + +static int mipid02_parse_tx_ep(struct mipid02_dev *bridge) +{ + struct v4l2_fwnode_endpoint ep = { .bus_type = V4L2_MBUS_PARALLEL }; + struct i2c_client *client = bridge->i2c_client; + struct device_node *ep_node; + int ret; + + /* parse tx (endpoint 2) */ + ep_node = of_graph_get_endpoint_by_regs(bridge->i2c_client->dev.of_node, + 2, 0); + if (!ep_node) { + dev_err(&client->dev, "unable to find port1 ep"); + ret = -EINVAL; + goto error; + } + + ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep_node), &ep); + if (ret) { + dev_err(&client->dev, "Could not parse v4l2 endpoint\n"); + goto error_of_node_put; + } + + of_node_put(ep_node); + bridge->tx = ep; + + return 0; + +error_of_node_put: + of_node_put(ep_node); +error: + + return -EINVAL; +} + +static int mipid02_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct mipid02_dev *bridge; + u32 clk_freq; + int ret; + + bridge = devm_kzalloc(dev, sizeof(*bridge), GFP_KERNEL); + if (!bridge) + return -ENOMEM; + + init_format(&bridge->fmt); + + bridge->i2c_client = client; + v4l2_i2c_subdev_init(&bridge->sd, client, &mipid02_subdev_ops); + + /* got and check clock */ + bridge->xclk = devm_clk_get(dev, "xclk"); + if (IS_ERR(bridge->xclk)) { + dev_err(dev, "failed to get xclk\n"); + return PTR_ERR(bridge->xclk); + } + + clk_freq = clk_get_rate(bridge->xclk); + if (clk_freq < 6000000 || clk_freq > 27000000) { + dev_err(dev, "xclk freq must be in 6-27 Mhz range. got %d Hz\n", + clk_freq); + return -EINVAL; + } + + bridge->reset_gpio = devm_gpiod_get_optional(dev, "reset", + GPIOD_OUT_HIGH); + + ret = mipid02_get_regulators(bridge); + if (ret) { + dev_err(dev, "failed to get regulators %d", ret); + return ret; + } + + mutex_init(&bridge->lock); + bridge->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + bridge->sd.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; + bridge->sd.entity.ops = &mipid02_subdev_entity_ops; + bridge->pad[0].flags = MEDIA_PAD_FL_SINK; + bridge->pad[1].flags = MEDIA_PAD_FL_SINK; + bridge->pad[2].flags = MEDIA_PAD_FL_SOURCE; + ret = media_entity_pads_init(&bridge->sd.entity, MIPID02_PAD_NB, + bridge->pad); + if (ret) { + dev_err(&client->dev, "pads init failed %d", ret); + goto mutex_cleanup; + } + + /* enable clock, power and reset device if available */ + ret = mipid02_set_power_on(bridge); + if (ret) + goto entity_cleanup; + + ret = mipid02_detect(bridge); + if (ret) { + dev_err(&client->dev, "failed to detect mipid02 %d", ret); + goto power_off; + } + + ret = mipid02_parse_tx_ep(bridge); + if (ret) { + dev_err(&client->dev, "failed to parse tx %d", ret); + goto power_off; + } + + ret = mipid02_parse_rx_ep(bridge); + if (ret) { + dev_err(&client->dev, "failed to parse rx %d", ret); + goto power_off; + } + + ret = v4l2_async_register_subdev(&bridge->sd); + if (ret < 0) { + dev_err(&client->dev, "v4l2_async_register_subdev failed %d", + ret); + goto unregister_notifier; + } + + dev_info(&client->dev, "mipid02 device probe successfully"); + + return 0; + +unregister_notifier: + v4l2_async_notifier_unregister(&bridge->notifier); + v4l2_async_notifier_cleanup(&bridge->notifier); +power_off: + mipid02_set_power_off(bridge); +entity_cleanup: + media_entity_cleanup(&bridge->sd.entity); +mutex_cleanup: + mutex_destroy(&bridge->lock); + + return ret; +} + +static int mipid02_remove(struct i2c_client *client) +{ + struct v4l2_subdev *sd = i2c_get_clientdata(client); + struct mipid02_dev *bridge = to_mipid02_dev(sd); + + v4l2_async_notifier_unregister(&bridge->notifier); + v4l2_async_notifier_cleanup(&bridge->notifier); + v4l2_async_unregister_subdev(&bridge->sd); + mipid02_set_power_off(bridge); + media_entity_cleanup(&bridge->sd.entity); + mutex_destroy(&bridge->lock); + + return 0; +} + +static const struct of_device_id mipid02_dt_ids[] = { + { .compatible = "st,st-mipid02" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, mipid02_dt_ids); + +static struct i2c_driver mipid02_i2c_driver = { + .driver = { + .name = "st-mipid02", + .of_match_table = mipid02_dt_ids, + }, + .probe_new = mipid02_probe, + .remove = mipid02_remove, +}; + +module_i2c_driver(mipid02_i2c_driver); + +MODULE_AUTHOR("Mickael Guene <mickael.guene@st.com>"); +MODULE_DESCRIPTION("STMicroelectronics MIPID02 CSI-2 bridge driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/media-dev-allocator.c b/drivers/media/media-dev-allocator.c new file mode 100644 index 000000000000..ae17887dec59 --- /dev/null +++ b/drivers/media/media-dev-allocator.c @@ -0,0 +1,135 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * media-dev-allocator.c - Media Controller Device Allocator API + * + * Copyright (c) 2019 Shuah Khan <shuah@kernel.org> + * + * Credits: Suggested by Laurent Pinchart <laurent.pinchart@ideasonboard.com> + */ + +/* + * This file adds a global refcounted Media Controller Device Instance API. + * A system wide global media device list is managed and each media device + * includes a kref count. The last put on the media device releases the media + * device instance. + * + */ + +#include <linux/kref.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/usb.h> + +#include <media/media-device.h> +#include <media/media-dev-allocator.h> + +static LIST_HEAD(media_device_list); +static DEFINE_MUTEX(media_device_lock); + +struct media_device_instance { + struct media_device mdev; + struct module *owner; + struct list_head list; + struct kref refcount; +}; + +static inline struct media_device_instance * +to_media_device_instance(struct media_device *mdev) +{ + return container_of(mdev, struct media_device_instance, mdev); +} + +static void media_device_instance_release(struct kref *kref) +{ + struct media_device_instance *mdi = + container_of(kref, struct media_device_instance, refcount); + + dev_dbg(mdi->mdev.dev, "%s: releasing Media Device\n", __func__); + + mutex_lock(&media_device_lock); + + media_device_unregister(&mdi->mdev); + media_device_cleanup(&mdi->mdev); + + list_del(&mdi->list); + mutex_unlock(&media_device_lock); + + kfree(mdi); +} + +/* Callers should hold media_device_lock when calling this function */ +static struct media_device *__media_device_get(struct device *dev, + const char *module_name, + struct module *owner) +{ + struct media_device_instance *mdi; + + list_for_each_entry(mdi, &media_device_list, list) { + if (mdi->mdev.dev != dev) + continue; + + kref_get(&mdi->refcount); + + /* get module reference for the media_device owner */ + if (owner != mdi->owner && !try_module_get(mdi->owner)) + dev_err(dev, + "%s: module %s get owner reference error\n", + __func__, module_name); + else + dev_dbg(dev, "%s: module %s got owner reference\n", + __func__, module_name); + return &mdi->mdev; + } + + mdi = kzalloc(sizeof(*mdi), GFP_KERNEL); + if (!mdi) + return NULL; + + mdi->owner = owner; + kref_init(&mdi->refcount); + list_add_tail(&mdi->list, &media_device_list); + + dev_dbg(dev, "%s: Allocated media device for owner %s\n", + __func__, module_name); + return &mdi->mdev; +} + +struct media_device *media_device_usb_allocate(struct usb_device *udev, + const char *module_name, + struct module *owner) +{ + struct media_device *mdev; + + mutex_lock(&media_device_lock); + mdev = __media_device_get(&udev->dev, module_name, owner); + if (!mdev) { + mutex_unlock(&media_device_lock); + return ERR_PTR(-ENOMEM); + } + + /* check if media device is already initialized */ + if (!mdev->dev) + __media_device_usb_init(mdev, udev, udev->product, + module_name); + mutex_unlock(&media_device_lock); + return mdev; +} +EXPORT_SYMBOL_GPL(media_device_usb_allocate); + +void media_device_delete(struct media_device *mdev, const char *module_name, + struct module *owner) +{ + struct media_device_instance *mdi = to_media_device_instance(mdev); + + mutex_lock(&media_device_lock); + /* put module reference for the media_device owner */ + if (mdi->owner != owner) { + module_put(mdi->owner); + dev_dbg(mdi->mdev.dev, + "%s: module %s put owner module reference\n", + __func__, module_name); + } + mutex_unlock(&media_device_lock); + kref_put(&mdi->refcount, media_device_instance_release); +} +EXPORT_SYMBOL_GPL(media_device_delete); diff --git a/drivers/media/media-devnode.c b/drivers/media/media-devnode.c index 6b87a721dc49..d5aa30eeff4a 100644 --- a/drivers/media/media-devnode.c +++ b/drivers/media/media-devnode.c @@ -251,6 +251,7 @@ int __must_check media_devnode_register(struct media_device *mdev, /* Part 2: Initialize the character device */ cdev_init(&devnode->cdev, &media_devnode_fops); devnode->cdev.owner = owner; + kobject_set_name(&devnode->cdev.kobj, "media%d", devnode->minor); /* Part 3: Add the media and char device */ ret = cdev_device_add(&devnode->cdev, &devnode->dev); @@ -290,8 +291,9 @@ void media_devnode_unregister(struct media_devnode *devnode) mutex_lock(&media_devnode_lock); /* Delete the cdev on this minor as well */ cdev_device_del(&devnode->cdev, &devnode->dev); - mutex_unlock(&media_devnode_lock); devnode->media_dev = NULL; + mutex_unlock(&media_devnode_lock); + put_device(&devnode->dev); } diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c index 0b1cb3559140..a998a2e0ea1d 100644 --- a/drivers/media/media-entity.c +++ b/drivers/media/media-entity.c @@ -17,7 +17,6 @@ */ #include <linux/bitmap.h> -#include <linux/module.h> #include <linux/property.h> #include <linux/slab.h> #include <media/media-entity.h> @@ -436,7 +435,10 @@ __must_check int __media_pipeline_start(struct media_entity *entity, entity->stream_count++; - if (WARN_ON(entity->pipe && entity->pipe != pipe)) { + if (entity->pipe && entity->pipe != pipe) { + pr_err("Pipe active for %s. Can't start for %s\n", + entity->name, + entity_err->name); ret = -EBUSY; goto error; } @@ -588,33 +590,6 @@ void media_pipeline_stop(struct media_entity *entity) EXPORT_SYMBOL_GPL(media_pipeline_stop); /* ----------------------------------------------------------------------------- - * Module use count - */ - -struct media_entity *media_entity_get(struct media_entity *entity) -{ - if (entity == NULL) - return NULL; - - if (entity->graph_obj.mdev->dev && - !try_module_get(entity->graph_obj.mdev->dev->driver->owner)) - return NULL; - - return entity; -} -EXPORT_SYMBOL_GPL(media_entity_get); - -void media_entity_put(struct media_entity *entity) -{ - if (entity == NULL) - return; - - if (entity->graph_obj.mdev->dev) - module_put(entity->graph_obj.mdev->dev->driver->owner); -} -EXPORT_SYMBOL_GPL(media_entity_put); - -/* ----------------------------------------------------------------------------- * Links management */ diff --git a/drivers/media/media-request.c b/drivers/media/media-request.c index 9e5fd2ac769e..e3fca436c75b 100644 --- a/drivers/media/media-request.c +++ b/drivers/media/media-request.c @@ -251,7 +251,7 @@ media_request_get_by_fd(struct media_device *mdev, int request_fd) if (!mdev || !mdev->ops || !mdev->ops->req_validate || !mdev->ops->req_queue) - return ERR_PTR(-EACCES); + return ERR_PTR(-EBADR); f = fdget(request_fd); if (!f.file) @@ -407,7 +407,7 @@ int media_request_object_bind(struct media_request *req, int ret = -EBUSY; if (WARN_ON(!ops->release)) - return -EACCES; + return -EBADR; spin_lock_irqsave(&req->lock, flags); diff --git a/drivers/media/mmc/siano/Kconfig b/drivers/media/mmc/siano/Kconfig index 7693487e2f63..3941ee8352bb 100644 --- a/drivers/media/mmc/siano/Kconfig +++ b/drivers/media/mmc/siano/Kconfig @@ -9,5 +9,5 @@ config SMS_SDIO_DRV depends on !RC_CORE || RC_CORE select MEDIA_COMMON_OPTIONS select SMS_SIANO_MDTV - ---help--- + help Choose if you would like to have Siano's support for SDIO interface diff --git a/drivers/media/pci/bt8xx/Kconfig b/drivers/media/pci/bt8xx/Kconfig index bc89e37608cd..0f46db7d5ffc 100644 --- a/drivers/media/pci/bt8xx/Kconfig +++ b/drivers/media/pci/bt8xx/Kconfig @@ -13,7 +13,7 @@ config VIDEO_BT848 select VIDEO_SAA6588 if MEDIA_SUBDRV_AUTOSELECT select RADIO_ADAPTERS select RADIO_TEA575X - ---help--- + help Support for BT848 based frame grabber/overlay boards. This includes the Miro, Hauppauge and STB boards. Please read the material in <file:Documentation/media/v4l-drivers/bttv.rst> for more information. diff --git a/drivers/media/pci/bt8xx/dst.c b/drivers/media/pci/bt8xx/dst.c index c94318c71a0c..e929797206f6 100644 --- a/drivers/media/pci/bt8xx/dst.c +++ b/drivers/media/pci/bt8xx/dst.c @@ -1100,7 +1100,8 @@ static int dst_get_device_id(struct dst_state *state) /* Card capabilities */ state->dst_hw_cap = p_dst_type->dst_feature; pr_err("Recognise [%s]\n", p_dst_type->device_id); - strncpy(&state->fw_name[0], p_dst_type->device_id, 6); + strscpy(state->fw_name, p_dst_type->device_id, + sizeof(state->fw_name)); /* Multiple tuners */ if (p_dst_type->tuner_type & TUNER_TYPE_MULTI) { switch (use_dst_type) { diff --git a/drivers/media/pci/bt8xx/dst_common.h b/drivers/media/pci/bt8xx/dst_common.h index 6a2cfdd44e3e..79dec1b1722c 100644 --- a/drivers/media/pci/bt8xx/dst_common.h +++ b/drivers/media/pci/bt8xx/dst_common.h @@ -138,7 +138,7 @@ struct dst_state { u32 tuner_type; char *tuner_name; struct mutex dst_mutex; - u8 fw_name[8]; + char fw_name[8]; struct dvb_device *dst_ca; }; diff --git a/drivers/media/pci/cobalt/Kconfig b/drivers/media/pci/cobalt/Kconfig index aa35cbc0a904..9a544bab3178 100644 --- a/drivers/media/pci/cobalt/Kconfig +++ b/drivers/media/pci/cobalt/Kconfig @@ -11,7 +11,7 @@ config VIDEO_COBALT select VIDEO_ADV7511 select VIDEO_ADV7842 select VIDEOBUF2_DMA_SG - ---help--- + help This is a video4linux driver for the Cisco PCIe Cobalt card. This board is sadly not available outside of Cisco, but it is diff --git a/drivers/media/pci/cobalt/cobalt-irq.c b/drivers/media/pci/cobalt/cobalt-irq.c index 04783e78cc12..a518927abae1 100644 --- a/drivers/media/pci/cobalt/cobalt-irq.c +++ b/drivers/media/pci/cobalt/cobalt-irq.c @@ -128,7 +128,7 @@ done: cb->vb.sequence = s->sequence++; vb2_buffer_done(&cb->vb.vb2_buf, (skip || s->unstable_frame) ? - VB2_BUF_STATE_REQUEUEING : VB2_BUF_STATE_DONE); + VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE); } irqreturn_t cobalt_irq_handler(int irq, void *dev_id) diff --git a/drivers/media/pci/cx18/Kconfig b/drivers/media/pci/cx18/Kconfig index c675b83c43a9..96477bba0d5c 100644 --- a/drivers/media/pci/cx18/Kconfig +++ b/drivers/media/pci/cx18/Kconfig @@ -13,7 +13,7 @@ config VIDEO_CX18 select DVB_S5H1411 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_TDA18271 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_TDA8290 if MEDIA_SUBDRV_AUTOSELECT - ---help--- + help This is a video4linux driver for Conexant cx23418 based PCI combo video recorder devices. @@ -27,7 +27,7 @@ config VIDEO_CX18_ALSA tristate "Conexant 23418 DMA audio support" depends on VIDEO_CX18 && SND select SND_PCM - ---help--- + help This is a video4linux driver for direct (DMA) audio on Conexant 23418 based TV cards using ALSA. diff --git a/drivers/media/pci/cx18/cx18-fileops.c b/drivers/media/pci/cx18/cx18-fileops.c index f778965a2eb8..59e78fb17575 100644 --- a/drivers/media/pci/cx18/cx18-fileops.c +++ b/drivers/media/pci/cx18/cx18-fileops.c @@ -484,7 +484,7 @@ static ssize_t cx18_read_pos(struct cx18_stream *s, char __user *ubuf, CX18_DEBUG_HI_FILE("read %zd from %s, got %zd\n", count, s->name, rc); if (rc > 0) - pos += rc; + *pos += rc; return rc; } diff --git a/drivers/media/pci/cx23885/Kconfig b/drivers/media/pci/cx23885/Kconfig index 3435bbaa3167..1bba9e497915 100644 --- a/drivers/media/pci/cx23885/Kconfig +++ b/drivers/media/pci/cx23885/Kconfig @@ -43,7 +43,7 @@ config VIDEO_CX23885 select MEDIA_TUNER_SI2157 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_M88RS6000T if MEDIA_SUBDRV_AUTOSELECT select DVB_TUNER_DIB0070 if MEDIA_SUBDRV_AUTOSELECT - ---help--- + help This is a video4linux driver for Conexant 23885 based TV cards. @@ -54,7 +54,7 @@ config MEDIA_ALTERA_CI tristate "Altera FPGA based CI module" depends on VIDEO_CX23885 && DVB_CORE select ALTERA_STAPL - ---help--- + help An Altera FPGA CI module for NetUP Dual DVB-T/C RF CI card. To compile this driver as a module, choose M here: the diff --git a/drivers/media/pci/cx23885/cx23885-dvb.c b/drivers/media/pci/cx23885/cx23885-dvb.c index 0d0929c54f93..e2e63f05645e 100644 --- a/drivers/media/pci/cx23885/cx23885-dvb.c +++ b/drivers/media/pci/cx23885/cx23885-dvb.c @@ -1474,8 +1474,9 @@ static int dvb_register(struct cx23885_tsport *port) if (fe0->dvb.frontend != NULL) { struct i2c_adapter *tun_i2c; - fe0->dvb.frontend->sec_priv = kmalloc(sizeof(dib7000p_ops), GFP_KERNEL); - memcpy(fe0->dvb.frontend->sec_priv, &dib7000p_ops, sizeof(dib7000p_ops)); + fe0->dvb.frontend->sec_priv = kmemdup(&dib7000p_ops, sizeof(dib7000p_ops), GFP_KERNEL); + if (!fe0->dvb.frontend->sec_priv) + return -ENOMEM; tun_i2c = dib7000p_ops.get_i2c_master(fe0->dvb.frontend, DIBX000_I2C_INTERFACE_TUNER, 1); if (!dvb_attach(dib0070_attach, fe0->dvb.frontend, tun_i2c, &dib7070p_dib0070_config)) return -ENODEV; diff --git a/drivers/media/pci/cx25821/Kconfig b/drivers/media/pci/cx25821/Kconfig index 1755d3d2feaa..a64fa9a6d5d5 100644 --- a/drivers/media/pci/cx25821/Kconfig +++ b/drivers/media/pci/cx25821/Kconfig @@ -3,7 +3,7 @@ config VIDEO_CX25821 depends on VIDEO_DEV && PCI && I2C select I2C_ALGOBIT select VIDEOBUF2_DMA_SG - ---help--- + help This is a video4linux driver for Conexant 25821 based TV cards. @@ -14,7 +14,7 @@ config VIDEO_CX25821_ALSA tristate "Conexant 25821 DMA audio support" depends on VIDEO_CX25821 && SND select SND_PCM - ---help--- + help This is a video4linux driver for direct (DMA) audio on Conexant 25821 based capture cards using ALSA. diff --git a/drivers/media/pci/cx88/Kconfig b/drivers/media/pci/cx88/Kconfig index 14b813d634a8..fbb17ddb6bc3 100644 --- a/drivers/media/pci/cx88/Kconfig +++ b/drivers/media/pci/cx88/Kconfig @@ -6,7 +6,7 @@ config VIDEO_CX88 select VIDEO_TUNER select VIDEO_TVEEPROM select VIDEO_WM8775 if MEDIA_SUBDRV_AUTOSELECT - ---help--- + help This is a video4linux driver for Conexant 2388x based TV cards. @@ -17,7 +17,7 @@ config VIDEO_CX88_ALSA tristate "Conexant 2388x DMA audio support" depends on VIDEO_CX88 && SND select SND_PCM - ---help--- + help This is a video4linux driver for direct (DMA) audio on Conexant 2388x based TV cards using ALSA. @@ -33,7 +33,7 @@ config VIDEO_CX88_BLACKBIRD tristate "Blackbird MPEG encoder support (cx2388x + cx23416)" depends on VIDEO_CX88 select VIDEO_CX2341X - ---help--- + help This adds support for MPEG encoder cards based on the Blackbird reference design, using the Conexant 2388x and 23416 chips. @@ -64,7 +64,7 @@ config VIDEO_CX88_DVB select DVB_DS3000 if MEDIA_SUBDRV_AUTOSELECT select DVB_TS2020 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_SIMPLE if MEDIA_SUBDRV_AUTOSELECT - ---help--- + help This adds support for DVB/ATSC cards based on the Conexant 2388x chip. @@ -75,7 +75,7 @@ config VIDEO_CX88_ENABLE_VP3054 bool "VP-3054 Secondary I2C Bus Support" default y depends on VIDEO_CX88_DVB && DVB_MT352 - ---help--- + help This adds DVB-T support for cards based on the Conexant 2388x chip and the MT352 demodulator, which also require support for the VP-3054 diff --git a/drivers/media/pci/ddbridge/Kconfig b/drivers/media/pci/ddbridge/Kconfig index 16faef265e97..fc98b6d575d9 100644 --- a/drivers/media/pci/ddbridge/Kconfig +++ b/drivers/media/pci/ddbridge/Kconfig @@ -15,7 +15,7 @@ config DVB_DDBRIDGE select DVB_MXL5XX if MEDIA_SUBDRV_AUTOSELECT select DVB_CXD2099 if MEDIA_SUBDRV_AUTOSELECT select DVB_DUMMY_FE if MEDIA_SUBDRV_AUTOSELECT - ---help--- + help Support for cards with the Digital Devices PCI express bridge: - Octopus PCIe Bridge - Octopus mini PCIe Bridge @@ -36,7 +36,7 @@ config DVB_DDBRIDGE_MSIENABLE depends on DVB_DDBRIDGE depends on PCI_MSI default n - ---help--- + help Use PCI MSI (Message Signaled Interrupts) per default. Enabling this might lead to I2C errors originating from the bridge in conjunction with certain SATA controllers, requiring a reload of the ddbridge diff --git a/drivers/media/pci/dt3155/Kconfig b/drivers/media/pci/dt3155/Kconfig index 858b0f2f15be..d770eec541d4 100644 --- a/drivers/media/pci/dt3155/Kconfig +++ b/drivers/media/pci/dt3155/Kconfig @@ -3,7 +3,7 @@ config VIDEO_DT3155 depends on PCI && VIDEO_DEV && VIDEO_V4L2 select VIDEOBUF2_DMA_CONTIG default n - ---help--- + help Enables dt3155 device driver for the DataTranslation DT3155 frame grabber. Say Y here if you have this hardware. In doubt, say N. diff --git a/drivers/media/pci/intel/ipu3/Kconfig b/drivers/media/pci/intel/ipu3/Kconfig index 715f77651482..bd518bdc9f5f 100644 --- a/drivers/media/pci/intel/ipu3/Kconfig +++ b/drivers/media/pci/intel/ipu3/Kconfig @@ -7,7 +7,7 @@ config VIDEO_IPU3_CIO2 select V4L2_FWNODE select VIDEOBUF2_DMA_SG - ---help--- + help This is the Intel IPU3 CIO2 CSI-2 receiver unit, found in Intel Skylake and Kaby Lake SoCs and used for capturing images and video from a camera sensor. diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2.c b/drivers/media/pci/intel/ipu3/ipu3-cio2.c index f8020ebe9f05..2a52a393fe74 100644 --- a/drivers/media/pci/intel/ipu3/ipu3-cio2.c +++ b/drivers/media/pci/intel/ipu3/ipu3-cio2.c @@ -1601,6 +1601,7 @@ static int cio2_queue_init(struct cio2_device *cio2, struct cio2_queue *q) subdev->owner = THIS_MODULE; snprintf(subdev->name, sizeof(subdev->name), CIO2_ENTITY_NAME " %td", q - cio2->queue); + subdev->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; v4l2_set_subdevdata(subdev, cio2); r = v4l2_device_register_subdev(&cio2->v4l2_dev, subdev); if (r) { diff --git a/drivers/media/pci/ivtv/Kconfig b/drivers/media/pci/ivtv/Kconfig index 06ca4e23f9fb..e96b3c182a2f 100644 --- a/drivers/media/pci/ivtv/Kconfig +++ b/drivers/media/pci/ivtv/Kconfig @@ -18,7 +18,7 @@ config VIDEO_IVTV select VIDEO_VP27SMPX select VIDEO_UPD64031A select VIDEO_UPD64083 - ---help--- + help This is a video4linux driver for Conexant cx23416 or cx23415 based PCI personal video recorder devices. @@ -32,7 +32,7 @@ config VIDEO_IVTV_DEPRECATED_IOCTLS bool "enable the DVB ioctls abuse on ivtv driver" depends on VIDEO_IVTV default n - ---help--- + help Enable the usage of the a DVB set of ioctls that were abused by IVTV driver for a while. @@ -45,7 +45,7 @@ config VIDEO_IVTV_ALSA tristate "Conexant cx23415/cx23416 ALSA interface for PCM audio capture" depends on VIDEO_IVTV && SND select SND_PCM - ---help--- + help This driver provides an ALSA interface as another method for user applications to obtain PCM audio data from Conexant cx23415/cx23416 based PCI TV cards supported by the ivtv driver. @@ -63,7 +63,7 @@ config VIDEO_FB_IVTV select FB_CFB_FILLRECT select FB_CFB_COPYAREA select FB_CFB_IMAGEBLIT - ---help--- + help This is a framebuffer driver for the Conexant cx23415 MPEG encoder/decoder. @@ -77,7 +77,7 @@ config VIDEO_FB_IVTV_FORCE_PAT bool "force cx23415 framebuffer init with x86 PAT enabled" depends on VIDEO_FB_IVTV && X86_PAT default n - ---help--- + help With PAT enabled, the cx23415 framebuffer driver does not utilize write-combined caching on the framebuffer memory. For this reason, the driver will by default disable itself diff --git a/drivers/media/pci/ivtv/ivtv-fileops.c b/drivers/media/pci/ivtv/ivtv-fileops.c index 6196daae4b3e..043ac0ae9ed0 100644 --- a/drivers/media/pci/ivtv/ivtv-fileops.c +++ b/drivers/media/pci/ivtv/ivtv-fileops.c @@ -420,7 +420,7 @@ static ssize_t ivtv_read_pos(struct ivtv_stream *s, char __user *ubuf, size_t co IVTV_DEBUG_HI_FILE("read %zd from %s, got %zd\n", count, s->name, rc); if (rc > 0) - pos += rc; + *pos += rc; return rc; } diff --git a/drivers/media/pci/mantis/mantis_i2c.c b/drivers/media/pci/mantis/mantis_i2c.c index 6528a2180119..f8b503ef42bc 100644 --- a/drivers/media/pci/mantis/mantis_i2c.c +++ b/drivers/media/pci/mantis/mantis_i2c.c @@ -225,7 +225,7 @@ int mantis_i2c_init(struct mantis_pci *mantis) init_waitqueue_head(&mantis->i2c_wq); mutex_init(&mantis->i2c_lock); - strncpy(i2c_adapter->name, "Mantis I2C", sizeof(i2c_adapter->name)); + strscpy(i2c_adapter->name, "Mantis I2C", sizeof(i2c_adapter->name)); i2c_set_adapdata(i2c_adapter, mantis); i2c_adapter->owner = THIS_MODULE; diff --git a/drivers/media/pci/meye/Kconfig b/drivers/media/pci/meye/Kconfig index 9a50f54231ad..ce0463c81886 100644 --- a/drivers/media/pci/meye/Kconfig +++ b/drivers/media/pci/meye/Kconfig @@ -2,7 +2,7 @@ config VIDEO_MEYE tristate "Sony Vaio Picturebook Motion Eye Video For Linux" depends on PCI && VIDEO_V4L2 depends on SONY_LAPTOP || COMPILE_TEST - ---help--- + help This is the video4linux driver for the Motion Eye camera found in the Vaio Picturebook laptops. Please read the material in <file:Documentation/media/v4l-drivers/meye.rst> for more information. diff --git a/drivers/media/pci/netup_unidvb/Kconfig b/drivers/media/pci/netup_unidvb/Kconfig index b663154d0cc4..60057585f04c 100644 --- a/drivers/media/pci/netup_unidvb/Kconfig +++ b/drivers/media/pci/netup_unidvb/Kconfig @@ -8,7 +8,7 @@ config DVB_NETUP_UNIDVB select DVB_HELENE if MEDIA_SUBDRV_AUTOSELECT select DVB_LNBH25 if MEDIA_SUBDRV_AUTOSELECT select DVB_CXD2841ER if MEDIA_SUBDRV_AUTOSELECT - ---help--- + help Support for NetUP PCI express Universal DVB card. Say Y when you want to support NetUP Dual Universal DVB card. diff --git a/drivers/media/pci/ngene/Kconfig b/drivers/media/pci/ngene/Kconfig index e06d019996f3..8a80a5bab8e9 100644 --- a/drivers/media/pci/ngene/Kconfig +++ b/drivers/media/pci/ngene/Kconfig @@ -15,6 +15,6 @@ config DVB_NGENE select DVB_STV6111 if MEDIA_SUBDRV_AUTOSELECT select DVB_LNBH25 if MEDIA_SUBDRV_AUTOSELECT select DVB_CXD2099 if MEDIA_SUBDRV_AUTOSELECT - ---help--- + help Support for Micronas PCI express cards with nGene bridge. diff --git a/drivers/media/pci/saa7134/Kconfig b/drivers/media/pci/saa7134/Kconfig index b44e0d70907e..8b28783b3fcd 100644 --- a/drivers/media/pci/saa7134/Kconfig +++ b/drivers/media/pci/saa7134/Kconfig @@ -7,7 +7,7 @@ config VIDEO_SAA7134 select CRC32 select VIDEO_SAA6588 if MEDIA_SUBDRV_AUTOSELECT select VIDEO_SAA6752HS if MEDIA_SUBDRV_AUTOSELECT - ---help--- + help This is a video4linux driver for Philips SAA713x based TV cards. @@ -18,7 +18,7 @@ config VIDEO_SAA7134_ALSA tristate "Philips SAA7134 DMA audio support" depends on VIDEO_SAA7134 && SND select SND_PCM - ---help--- + help This is a video4linux driver for direct (DMA) audio in Philips SAA713x based TV cards using ALSA @@ -31,7 +31,7 @@ config VIDEO_SAA7134_RC depends on VIDEO_SAA7134 depends on !(RC_CORE=m && VIDEO_SAA7134=y) default y - ---help--- + help Enables Remote Controller support on saa7134 driver. config VIDEO_SAA7134_DVB @@ -57,7 +57,7 @@ config VIDEO_SAA7134_DVB select MEDIA_TUNER_TDA18271 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_TDA8290 if MEDIA_SUBDRV_AUTOSELECT select DVB_ZL10039 if MEDIA_SUBDRV_AUTOSELECT - ---help--- + help This adds support for DVB cards based on the Philips saa7134 chip. @@ -68,6 +68,6 @@ config VIDEO_SAA7134_GO7007 tristate "go7007 support for saa7134 based TV cards" depends on VIDEO_SAA7134 depends on VIDEO_GO7007 - ---help--- + help Enables saa7134 driver support for boards with go7007 MPEG encoder (WIS Voyager or compatible). diff --git a/drivers/media/pci/saa7134/saa7134-go7007.c b/drivers/media/pci/saa7134/saa7134-go7007.c index 275c5e151818..626e130a9770 100644 --- a/drivers/media/pci/saa7134/saa7134-go7007.c +++ b/drivers/media/pci/saa7134/saa7134-go7007.c @@ -444,7 +444,7 @@ static int saa7134_go7007_init(struct saa7134_dev *dev) sd = &saa->sd; v4l2_subdev_init(sd, &saa7134_go7007_sd_ops); v4l2_set_subdevdata(sd, saa); - strncpy(sd->name, "saa7134-go7007", sizeof(sd->name)); + strscpy(sd->name, "saa7134-go7007", sizeof(sd->name)); /* Allocate a couple pages for receiving the compressed stream */ saa->top = (u8 *)get_zeroed_page(GFP_KERNEL); diff --git a/drivers/media/pci/saa7146/Kconfig b/drivers/media/pci/saa7146/Kconfig index da88b77a916c..60d9862580ff 100644 --- a/drivers/media/pci/saa7146/Kconfig +++ b/drivers/media/pci/saa7146/Kconfig @@ -2,7 +2,7 @@ config VIDEO_HEXIUM_GEMINI tristate "Hexium Gemini frame grabber" depends on PCI && VIDEO_V4L2 && I2C select VIDEO_SAA7146_VV - ---help--- + help This is a video4linux driver for the Hexium Gemini frame grabber card by Hexium. Please note that the Gemini Dual card is *not* fully supported. @@ -14,7 +14,7 @@ config VIDEO_HEXIUM_ORION tristate "Hexium HV-PCI6 and Orion frame grabber" depends on PCI && VIDEO_V4L2 && I2C select VIDEO_SAA7146_VV - ---help--- + help This is a video4linux driver for the Hexium HV-PCI6 and Orion frame grabber cards by Hexium. @@ -30,7 +30,7 @@ config VIDEO_MXB select VIDEO_TDA9840 if MEDIA_SUBDRV_AUTOSELECT select VIDEO_TEA6415C if MEDIA_SUBDRV_AUTOSELECT select VIDEO_TEA6420 if MEDIA_SUBDRV_AUTOSELECT - ---help--- + help This is a video4linux driver for the 'Multimedia eXtension Board' TV card by Siemens-Nixdorf. diff --git a/drivers/media/pci/saa7146/hexium_gemini.c b/drivers/media/pci/saa7146/hexium_gemini.c index 5817d9cde4d0..6d8e4afe9673 100644 --- a/drivers/media/pci/saa7146/hexium_gemini.c +++ b/drivers/media/pci/saa7146/hexium_gemini.c @@ -270,9 +270,8 @@ static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_d /* enable i2c-port pins */ saa7146_write(dev, MC1, (MASK_08 | MASK_24 | MASK_10 | MASK_26)); - hexium->i2c_adapter = (struct i2c_adapter) { - .name = "hexium gemini", - }; + strscpy(hexium->i2c_adapter.name, "hexium gemini", + sizeof(hexium->i2c_adapter.name)); saa7146_i2c_adapter_prepare(dev, &hexium->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480); if (i2c_add_adapter(&hexium->i2c_adapter) < 0) { DEB_S("cannot register i2c-device. skipping.\n"); diff --git a/drivers/media/pci/saa7146/hexium_orion.c b/drivers/media/pci/saa7146/hexium_orion.c index 0a05176c18ab..a794f9e5f990 100644 --- a/drivers/media/pci/saa7146/hexium_orion.c +++ b/drivers/media/pci/saa7146/hexium_orion.c @@ -231,9 +231,8 @@ static int hexium_probe(struct saa7146_dev *dev) saa7146_write(dev, DD1_STREAM_B, 0x00000000); saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26)); - hexium->i2c_adapter = (struct i2c_adapter) { - .name = "hexium orion", - }; + strscpy(hexium->i2c_adapter.name, "hexium orion", + sizeof(hexium->i2c_adapter.name)); saa7146_i2c_adapter_prepare(dev, &hexium->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480); if (i2c_add_adapter(&hexium->i2c_adapter) < 0) { DEB_S("cannot register i2c-device. skipping.\n"); diff --git a/drivers/media/pci/saa7164/Kconfig b/drivers/media/pci/saa7164/Kconfig index 9098ef5feca4..265c5a4fd823 100644 --- a/drivers/media/pci/saa7164/Kconfig +++ b/drivers/media/pci/saa7164/Kconfig @@ -8,7 +8,7 @@ config VIDEO_SAA7164 select DVB_TDA10048 if MEDIA_SUBDRV_AUTOSELECT select DVB_S5H1411 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_TDA18271 if MEDIA_SUBDRV_AUTOSELECT - ---help--- + help This is a video4linux driver for NXP SAA7164 based TV cards. diff --git a/drivers/media/pci/solo6x10/Kconfig b/drivers/media/pci/solo6x10/Kconfig index d9e06a6bf1eb..2061d02a82d0 100644 --- a/drivers/media/pci/solo6x10/Kconfig +++ b/drivers/media/pci/solo6x10/Kconfig @@ -8,7 +8,7 @@ config VIDEO_SOLO6X10 select VIDEOBUF2_DMA_CONTIG select SND_PCM select FONT_8x16 - ---help--- + help This driver supports the Bluecherry H.264 and MPEG-4 hardware compression capture cards and other Softlogic-based ones. diff --git a/drivers/media/pci/tw5864/Kconfig b/drivers/media/pci/tw5864/Kconfig index 760fb11dfeae..e5d52f076232 100644 --- a/drivers/media/pci/tw5864/Kconfig +++ b/drivers/media/pci/tw5864/Kconfig @@ -2,7 +2,7 @@ config VIDEO_TW5864 tristate "Techwell TW5864 video/audio grabber and encoder" depends on VIDEO_DEV && PCI && VIDEO_V4L2 select VIDEOBUF2_DMA_CONTIG - ---help--- + help Support for boards based on Techwell TW5864 chip which provides multichannel video & audio grabbing and encoding (H.264, MJPEG, ADPCM G.726). diff --git a/drivers/media/pci/tw5864/tw5864-video.c b/drivers/media/pci/tw5864/tw5864-video.c index 5a1f3aa4101a..434d313a3c15 100644 --- a/drivers/media/pci/tw5864/tw5864-video.c +++ b/drivers/media/pci/tw5864/tw5864-video.c @@ -1395,13 +1395,13 @@ static void tw5864_handle_frame(struct tw5864_h264_frame *frame) input->vb = NULL; spin_unlock_irqrestore(&input->slock, flags); - v4l2_buf = to_vb2_v4l2_buffer(&vb->vb.vb2_buf); - if (!vb) { /* Gone because of disabling */ dev_dbg(&dev->pci->dev, "vb is empty, dropping frame\n"); return; } + v4l2_buf = to_vb2_v4l2_buffer(&vb->vb.vb2_buf); + /* * Check for space. * Mind the overhead of startcode emulation prevention. diff --git a/drivers/media/pci/tw68/Kconfig b/drivers/media/pci/tw68/Kconfig index 95d5d5202048..4bfc4fa416e5 100644 --- a/drivers/media/pci/tw68/Kconfig +++ b/drivers/media/pci/tw68/Kconfig @@ -2,7 +2,7 @@ config VIDEO_TW68 tristate "Techwell tw68x Video For Linux" depends on VIDEO_DEV && PCI && VIDEO_V4L2 select VIDEOBUF2_DMA_SG - ---help--- + help Support for Techwell tw68xx based frame grabber boards. To compile this driver as a module, choose M here: the diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index 4acbed189644..011c1c2fcf19 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -6,7 +6,7 @@ menuconfig V4L_PLATFORM_DRIVERS bool "V4L platform devices" depends on MEDIA_CAMERA_SUPPORT default n - ---help--- + help Say Y here to enable support for platform-specific V4L drivers. if V4L_PLATFORM_DRIVERS @@ -55,7 +55,7 @@ config VIDEO_VIU depends on VIDEO_V4L2 && (PPC_MPC512x || COMPILE_TEST) && I2C select VIDEOBUF_DMA_CONTIG default y - ---help--- + help Support for Freescale VIU video driver. This device captures video data, or overlays video on DIU frame buffer. @@ -80,13 +80,13 @@ config VIDEO_OMAP3 select VIDEOBUF2_DMA_CONTIG select MFD_SYSCON select V4L2_FWNODE - ---help--- + help Driver for an OMAP 3 camera controller. config VIDEO_OMAP3_DEBUG bool "OMAP 3 Camera debug messages" depends on VIDEO_OMAP3 - ---help--- + help Enable debug messages on OMAP 3 camera controller driver. config VIDEO_PXA27x @@ -96,7 +96,7 @@ config VIDEO_PXA27x select VIDEOBUF2_DMA_SG select SG_SPLIT select V4L2_FWNODE - ---help--- + help This is a v4l2 driver for the PXA27x Quick Capture Interface config VIDEO_QCOM_CAMSS @@ -112,7 +112,7 @@ config VIDEO_S3C_CAMIF depends on PM depends on ARCH_S3C64XX || PLAT_S3C24XX || COMPILE_TEST select VIDEOBUF2_DMA_CONTIG - ---help--- + help This is a v4l2 driver for s3c24xx and s3c64xx SoC series camera host interface (CAMIF). @@ -125,7 +125,7 @@ config VIDEO_STM32_DCMI depends on ARCH_STM32 || COMPILE_TEST select VIDEOBUF2_DMA_CONTIG select V4L2_FWNODE - ---help--- + help This module makes the STM32 Digital Camera Memory Interface (DCMI) available as a v4l2 device. @@ -138,7 +138,7 @@ config VIDEO_RENESAS_CEU depends on ARCH_SHMOBILE || ARCH_R7S72100 || COMPILE_TEST select VIDEOBUF2_DMA_CONTIG select V4L2_FWNODE - ---help--- + help This is a v4l2 driver for the Renesas CEU Interface source "drivers/media/platform/exynos4-is/Kconfig" @@ -155,7 +155,7 @@ config VIDEO_TI_CAL select VIDEOBUF2_DMA_CONTIG select V4L2_FWNODE default n - ---help--- + help Support for the TI CAL (Camera Adaptation Layer) block found on DRA72X SoC. In TI Technical Reference Manual this module is referred as @@ -168,7 +168,7 @@ menuconfig V4L_MEM2MEM_DRIVERS depends on VIDEO_V4L2 depends on MEDIA_CAMERA_SUPPORT default n - ---help--- + help Say Y here to enable selecting drivers for V4L devices that use system memory for both source and destination buffers, as opposed to capture and output drivers, which use memory buffers for just @@ -184,7 +184,7 @@ config VIDEO_CODA select VIDEOBUF2_VMALLOC select V4L2_MEM2MEM_DEV select GENERIC_ALLOCATOR - ---help--- + help Coda is a range of video codec IPs that supports H.264, MPEG-4, and other video formats. @@ -207,7 +207,7 @@ config VIDEO_MEDIATEK_JPEG depends on ARCH_MEDIATEK || COMPILE_TEST select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV - ---help--- + help Mediatek jpeg codec driver provides HW capability to decode JPEG format @@ -218,7 +218,7 @@ config VIDEO_MEDIATEK_VPU tristate "Mediatek Video Processor Unit" depends on VIDEO_DEV && VIDEO_V4L2 depends on ARCH_MEDIATEK || COMPILE_TEST - ---help--- + help This driver provides downloading VPU firmware and communicating with VPU. This driver for hw video codec embedded in Mediatek's MT8173 SOCs. It is able @@ -236,7 +236,7 @@ config VIDEO_MEDIATEK_MDP select V4L2_MEM2MEM_DEV select VIDEO_MEDIATEK_VPU default n - ---help--- + help It is a v4l2 driver and present in Mediatek MT8173 SoCs. The driver supports for scaling and color space conversion. @@ -252,7 +252,7 @@ config VIDEO_MEDIATEK_VCODEC select V4L2_MEM2MEM_DEV select VIDEO_MEDIATEK_VPU default n - ---help--- + help Mediatek video codec driver provides HW capability to encode and decode in a range of video formats This driver rely on VPU driver to communicate with VPU. @@ -276,7 +276,7 @@ config VIDEO_SAMSUNG_S5P_G2D select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV default n - ---help--- + help This is a v4l2 driver for Samsung S5P and EXYNOS4 G2D 2d graphics accelerator. @@ -286,7 +286,7 @@ config VIDEO_SAMSUNG_S5P_JPEG depends on ARCH_S5PV210 || ARCH_EXYNOS || COMPILE_TEST select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV - ---help--- + help This is a v4l2 driver for Samsung S5P, EXYNOS3250 and EXYNOS4 JPEG codec @@ -407,7 +407,7 @@ config VIDEO_RENESAS_FDP1 depends on (!ARM64 && !VIDEO_RENESAS_FCP) || VIDEO_RENESAS_FCP select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV - ---help--- + help This is a V4L2 driver for the Renesas Fine Display Processor providing colour space conversion, and de-interlacing features. @@ -420,7 +420,7 @@ config VIDEO_RENESAS_JPU depends on ARCH_RENESAS || COMPILE_TEST select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV - ---help--- + help This is a V4L2 driver for the Renesas JPEG Processing Unit. To compile this driver as a module, choose M here: the module @@ -430,7 +430,7 @@ config VIDEO_RENESAS_FCP tristate "Renesas Frame Compression Processor" depends on ARCH_RENESAS || COMPILE_TEST depends on OF - ---help--- + help This is a driver for the Renesas Frame Compression Processor (FCP). The FCP is a companion module of video processing modules in the Renesas R-Car Gen3 SoCs. It handles memory access for the codec, @@ -446,7 +446,7 @@ config VIDEO_RENESAS_VSP1 depends on (!ARM64 && !VIDEO_RENESAS_FCP) || VIDEO_RENESAS_FCP select VIDEOBUF2_DMA_CONTIG select VIDEOBUF2_VMALLOC - ---help--- + help This is a V4L2 driver for the Renesas VSP1 video processing engine. To compile this driver as a module, choose M here: the module @@ -459,7 +459,7 @@ config VIDEO_ROCKCHIP_RGA select VIDEOBUF2_DMA_SG select V4L2_MEM2MEM_DEV default n - ---help--- + help This is a v4l2 driver for Rockchip SOC RGA 2d graphics accelerator. Rockchip RGA is a separate 2D raster graphic acceleration unit. It accelerates 2D graphics operations, such as point/line drawing, @@ -477,14 +477,14 @@ config VIDEO_TI_VPE select VIDEO_TI_SC select VIDEO_TI_CSC default n - ---help--- + help Support for the TI VPE(Video Processing Engine) block found on DRA7XX SoC. config VIDEO_TI_VPE_DEBUG bool "VPE debug messages" depends on VIDEO_TI_VPE - ---help--- + help Enable debug messages on VPE driver. config VIDEO_QCOM_VENUS @@ -495,7 +495,7 @@ config VIDEO_QCOM_VENUS select QCOM_SCM if ARCH_QCOM select VIDEOBUF2_DMA_SG select V4L2_MEM2MEM_DEV - ---help--- + help This is a V4L2 driver for Qualcomm Venus video accelerator hardware. It accelerates encoding and decoding operations on various Qualcomm SoCs. @@ -530,7 +530,7 @@ config VIDEO_VIM2M select VIDEOBUF2_VMALLOC select V4L2_MEM2MEM_DEV default n - ---help--- + help This is a virtual test device for the memory-to-memory driver framework. @@ -542,7 +542,7 @@ menuconfig DVB_PLATFORM_DRIVERS bool "DVB platform devices" depends on MEDIA_DIGITAL_TV_SUPPORT default n - ---help--- + help Say Y here to enable support for platform-specific Digital TV drivers. if DVB_PLATFORM_DRIVERS @@ -562,7 +562,7 @@ config VIDEO_CROS_EC_CEC select CEC_NOTIFIER select CHROME_PLATFORMS select CROS_EC_PROTO - ---help--- + help If you say yes here you will get support for the ChromeOS Embedded Controller's CEC. The CEC bus is present in the HDMI connector and enables communication @@ -573,18 +573,34 @@ config VIDEO_MESON_AO_CEC depends on ARCH_MESON || COMPILE_TEST select CEC_CORE select CEC_NOTIFIER - ---help--- + help This is a driver for Amlogic Meson SoCs AO CEC interface. It uses the generic CEC framework interface. CEC bus is present in the HDMI connector and enables communication +config VIDEO_MESON_G12A_AO_CEC + tristate "Amlogic Meson G12A AO CEC driver" + depends on ARCH_MESON || COMPILE_TEST + depends on COMMON_CLK && OF + select REGMAP + select REGMAP_MMIO + select CEC_CORE + select CEC_NOTIFIER + ---help--- + This is a driver for Amlogic Meson G12A SoCs AO CEC interface. + This driver if for the new AO-CEC module found in G12A SoCs, + usually named AO_CEC_B in documentation. + It uses the generic CEC framework interface. + CEC bus is present in the HDMI connector and enables communication + between compatible devices. + config CEC_GPIO tristate "Generic GPIO-based CEC driver" depends on PREEMPT || COMPILE_TEST select CEC_CORE select CEC_PIN select GPIOLIB - ---help--- + help This is a generic GPIO-based CEC driver. The CEC bus is present in the HDMI connector and enables communication between compatible devices. @@ -594,7 +610,7 @@ config VIDEO_SAMSUNG_S5P_CEC depends on ARCH_EXYNOS || COMPILE_TEST select CEC_CORE select CEC_NOTIFIER - ---help--- + help This is a driver for Samsung S5P HDMI CEC interface. It uses the generic CEC framework interface. CEC bus is present in the HDMI connector and enables communication @@ -605,7 +621,7 @@ config VIDEO_STI_HDMI_CEC depends on ARCH_STI || COMPILE_TEST select CEC_CORE select CEC_NOTIFIER - ---help--- + help This is a driver for STIH4xx HDMI CEC interface. It uses the generic CEC framework interface. CEC bus is present in the HDMI connector and enables communication @@ -617,7 +633,7 @@ config VIDEO_STM32_HDMI_CEC select REGMAP select REGMAP_MMIO select CEC_CORE - ---help--- + help This is a driver for STM32 interface. It uses the generic CEC framework interface. CEC bus is present in the HDMI connector and enables communication @@ -628,7 +644,7 @@ config VIDEO_TEGRA_HDMI_CEC depends on ARCH_TEGRA || COMPILE_TEST select CEC_CORE select CEC_NOTIFIER - ---help--- + help This is a driver for the Tegra HDMI CEC interface. It uses the generic CEC framework interface. The CEC bus is present in the HDMI connector and enables communication @@ -649,7 +665,7 @@ config VIDEO_SECO_CEC config VIDEO_SECO_RC bool "SECO Boards IR RC5 support" depends on VIDEO_SECO_CEC - depends on RC_CORE + depends on RC_CORE=y || RC_CORE = VIDEO_SECO_CEC help If you say yes here you will get support for the SECO Boards Consumer-IR in seco-cec driver. @@ -662,7 +678,7 @@ menuconfig SDR_PLATFORM_DRIVERS bool "SDR platform devices" depends on MEDIA_SDR_SUPPORT default n - ---help--- + help Say Y here to enable support for platform-specific SDR Drivers. if SDR_PLATFORM_DRIVERS @@ -672,7 +688,7 @@ config VIDEO_RCAR_DRIF depends on VIDEO_V4L2 depends on ARCH_RENESAS || COMPILE_TEST select VIDEOBUF2_VMALLOC - ---help--- + help Say Y if you want to enable R-Car Gen3 DRIF support. DRIF is Digital Radio Interface that interfaces with an RF front end chip. It is a receiver of digital data which uses DMA to transfer received data to diff --git a/drivers/media/platform/am437x/am437x-vpfe.c b/drivers/media/platform/am437x/am437x-vpfe.c index 5c17624aaade..fe7b937eb5f2 100644 --- a/drivers/media/platform/am437x/am437x-vpfe.c +++ b/drivers/media/platform/am437x/am437x-vpfe.c @@ -1540,7 +1540,7 @@ static int vpfe_enum_fmt(struct file *file, void *priv, if (!fmt) return -EINVAL; - strncpy(f->description, fmt->name, sizeof(f->description) - 1); + strscpy(f->description, fmt->name, sizeof(f->description)); f->pixelformat = fmt->fourcc; f->type = vpfe->fmt.type; diff --git a/drivers/media/platform/aspeed-video.c b/drivers/media/platform/aspeed-video.c index 692e08ef38c0..8144fe36ad48 100644 --- a/drivers/media/platform/aspeed-video.c +++ b/drivers/media/platform/aspeed-video.c @@ -14,7 +14,6 @@ #include <linux/of_irq.h> #include <linux/of_reserved_mem.h> #include <linux/platform_device.h> -#include <linux/reset.h> #include <linux/sched.h> #include <linux/spinlock.h> #include <linux/string.h> @@ -208,7 +207,6 @@ struct aspeed_video { void __iomem *base; struct clk *eclk; struct clk *vclk; - struct reset_control *rst; struct device *dev; struct v4l2_ctrl_handler ctrl_handler; @@ -483,19 +481,10 @@ static void aspeed_video_enable_mode_detect(struct aspeed_video *video) aspeed_video_update(video, VE_SEQ_CTRL, 0, VE_SEQ_CTRL_TRIG_MODE_DET); } -static void aspeed_video_reset(struct aspeed_video *video) -{ - /* Reset the engine */ - reset_control_assert(video->rst); - - /* Don't usleep here; function may be called in interrupt context */ - udelay(100); - reset_control_deassert(video->rst); -} - static void aspeed_video_off(struct aspeed_video *video) { - aspeed_video_reset(video); + /* Disable interrupts */ + aspeed_video_write(video, VE_INTERRUPT_CTRL, 0); /* Turn off the relevant clocks */ clk_disable_unprepare(video->vclk); @@ -507,8 +496,6 @@ static void aspeed_video_on(struct aspeed_video *video) /* Turn on the relevant clocks */ clk_prepare_enable(video->eclk); clk_prepare_enable(video->vclk); - - aspeed_video_reset(video); } static void aspeed_video_bufs_done(struct aspeed_video *video, @@ -1464,7 +1451,9 @@ static void aspeed_video_stop_streaming(struct vb2_queue *q) * Need to force stop any DMA and try and get HW into a good * state for future calls to start streaming again. */ - aspeed_video_reset(video); + aspeed_video_off(video); + aspeed_video_on(video); + aspeed_video_init_regs(video); aspeed_video_get_resolution(video); @@ -1619,17 +1608,7 @@ static int aspeed_video_init(struct aspeed_video *video) return PTR_ERR(video->vclk); } - video->rst = devm_reset_control_get_exclusive(dev, NULL); - if (IS_ERR(video->rst)) { - dev_err(dev, "Unable to get VE reset\n"); - return PTR_ERR(video->rst); - } - - rc = of_reserved_mem_device_init(dev); - if (rc) { - dev_err(dev, "Unable to reserve memory\n"); - return rc; - } + of_reserved_mem_device_init(dev); rc = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32)); if (rc) { diff --git a/drivers/media/platform/atmel/Kconfig b/drivers/media/platform/atmel/Kconfig index a211ef20f77e..c3f6a47cdc0e 100644 --- a/drivers/media/platform/atmel/Kconfig +++ b/drivers/media/platform/atmel/Kconfig @@ -15,6 +15,6 @@ config VIDEO_ATMEL_ISI depends on ARCH_AT91 || COMPILE_TEST select VIDEOBUF2_DMA_CONTIG select V4L2_FWNODE - ---help--- + help This module makes the ATMEL Image Sensor Interface available as a v4l2 device. diff --git a/drivers/media/platform/atmel/atmel-isc-regs.h b/drivers/media/platform/atmel/atmel-isc-regs.h index 2aadc19235ea..d730693f299c 100644 --- a/drivers/media/platform/atmel/atmel-isc-regs.h +++ b/drivers/media/platform/atmel/atmel-isc-regs.h @@ -24,6 +24,8 @@ #define ISC_PFE_CFG0_HPOL_LOW BIT(0) #define ISC_PFE_CFG0_VPOL_LOW BIT(1) #define ISC_PFE_CFG0_PPOL_LOW BIT(2) +#define ISC_PFE_CFG0_CCIR656 BIT(9) +#define ISC_PFE_CFG0_CCIR_CRC BIT(10) #define ISC_PFE_CFG0_MODE_PROGRESSIVE (0x0 << 4) #define ISC_PFE_CFG0_MODE_MASK GENMASK(6, 4) diff --git a/drivers/media/platform/atmel/atmel-isc.c b/drivers/media/platform/atmel/atmel-isc.c index 50178968b8a6..4bba9da206e4 100644 --- a/drivers/media/platform/atmel/atmel-isc.c +++ b/drivers/media/platform/atmel/atmel-isc.c @@ -89,35 +89,25 @@ struct isc_subdev_entity { struct list_head list; }; -/* Indicate the format is generated by the sensor */ -#define FMT_FLAG_FROM_SENSOR BIT(0) -/* Indicate the format is produced by ISC itself */ -#define FMT_FLAG_FROM_CONTROLLER BIT(1) -/* Indicate a Raw Bayer format */ -#define FMT_FLAG_RAW_FORMAT BIT(2) - -#define FMT_FLAG_RAW_FROM_SENSOR (FMT_FLAG_FROM_SENSOR | \ - FMT_FLAG_RAW_FORMAT) - /* * struct isc_format - ISC media bus format information + This structure represents the interface between the ISC + and the sensor. It's the input format received by + the ISC. * @fourcc: Fourcc code for this format * @mbus_code: V4L2 media bus format code. - * flags: Indicate format from sensor or converted by controller - * @bpp: Bits per pixel (when stored in memory) - * (when transferred over a bus) - * @sd_support: Subdev supports this format - * @isc_support: ISC can convert raw format to this format + * @cfa_baycfg: If this format is RAW BAYER, indicate the type of bayer. + this is either BGBG, RGRG, etc. + * @pfe_cfg0_bps: Number of hardware data lines connected to the ISC */ struct isc_format { u32 fourcc; u32 mbus_code; - u32 flags; - u8 bpp; + u32 cfa_baycfg; bool sd_support; - bool isc_support; + u32 pfe_cfg0_bps; }; /* Pipeline bitmap */ @@ -135,16 +125,31 @@ struct isc_format { #define GAM_ENABLES (GAM_RENABLE | GAM_GENABLE | GAM_BENABLE | GAM_ENABLE) +/* + * struct fmt_config - ISC format configuration and internal pipeline + This structure represents the internal configuration + of the ISC. + It also holds the format that ISC will present to v4l2. + * @sd_format: Pointer to an isc_format struct that holds the sensor + configuration. + * @fourcc: Fourcc code for this format. + * @bpp: Bytes per pixel in the current format. + * @rlp_cfg_mode: Configuration of the RLP (rounding, limiting packaging) + * @dcfg_imode: Configuration of the input of the DMA module + * @dctrl_dview: Configuration of the output of the DMA module + * @bits_pipeline: Configuration of the pipeline, which modules are enabled + */ struct fmt_config { - u32 fourcc; + struct isc_format *sd_format; - u32 pfe_cfg0_bps; - u32 cfa_baycfg; - u32 rlp_cfg_mode; - u32 dcfg_imode; - u32 dctrl_dview; + u32 fourcc; + u8 bpp; - u32 bits_pipeline; + u32 rlp_cfg_mode; + u32 dcfg_imode; + u32 dctrl_dview; + + u32 bits_pipeline; }; #define HIST_ENTRIES 512 @@ -196,8 +201,9 @@ struct isc_device { struct v4l2_format fmt; struct isc_format **user_formats; unsigned int num_user_formats; - const struct isc_format *current_fmt; - const struct isc_format *raw_fmt; + + struct fmt_config config; + struct fmt_config try_config; struct isc_ctrls ctrls; struct work_struct awb_work; @@ -210,319 +216,125 @@ struct isc_device { struct list_head subdev_entities; }; -static struct isc_format formats_list[] = { - { - .fourcc = V4L2_PIX_FMT_SBGGR8, - .mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8, - .flags = FMT_FLAG_RAW_FROM_SENSOR, - .bpp = 8, - }, +/* This is a list of the formats that the ISC can *output* */ +static struct isc_format controller_formats[] = { { - .fourcc = V4L2_PIX_FMT_SGBRG8, - .mbus_code = MEDIA_BUS_FMT_SGBRG8_1X8, - .flags = FMT_FLAG_RAW_FROM_SENSOR, - .bpp = 8, - }, - { - .fourcc = V4L2_PIX_FMT_SGRBG8, - .mbus_code = MEDIA_BUS_FMT_SGRBG8_1X8, - .flags = FMT_FLAG_RAW_FROM_SENSOR, - .bpp = 8, - }, - { - .fourcc = V4L2_PIX_FMT_SRGGB8, - .mbus_code = MEDIA_BUS_FMT_SRGGB8_1X8, - .flags = FMT_FLAG_RAW_FROM_SENSOR, - .bpp = 8, - }, - { - .fourcc = V4L2_PIX_FMT_SBGGR10, - .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10, - .flags = FMT_FLAG_RAW_FROM_SENSOR, - .bpp = 16, - }, - { - .fourcc = V4L2_PIX_FMT_SGBRG10, - .mbus_code = MEDIA_BUS_FMT_SGBRG10_1X10, - .flags = FMT_FLAG_RAW_FROM_SENSOR, - .bpp = 16, - }, - { - .fourcc = V4L2_PIX_FMT_SGRBG10, - .mbus_code = MEDIA_BUS_FMT_SGRBG10_1X10, - .flags = FMT_FLAG_RAW_FROM_SENSOR, - .bpp = 16, + .fourcc = V4L2_PIX_FMT_ARGB444, }, { - .fourcc = V4L2_PIX_FMT_SRGGB10, - .mbus_code = MEDIA_BUS_FMT_SRGGB10_1X10, - .flags = FMT_FLAG_RAW_FROM_SENSOR, - .bpp = 16, + .fourcc = V4L2_PIX_FMT_ARGB555, }, { - .fourcc = V4L2_PIX_FMT_SBGGR12, - .mbus_code = MEDIA_BUS_FMT_SBGGR12_1X12, - .flags = FMT_FLAG_RAW_FROM_SENSOR, - .bpp = 16, + .fourcc = V4L2_PIX_FMT_RGB565, }, { - .fourcc = V4L2_PIX_FMT_SGBRG12, - .mbus_code = MEDIA_BUS_FMT_SGBRG12_1X12, - .flags = FMT_FLAG_RAW_FROM_SENSOR, - .bpp = 16, + .fourcc = V4L2_PIX_FMT_ABGR32, }, { - .fourcc = V4L2_PIX_FMT_SGRBG12, - .mbus_code = MEDIA_BUS_FMT_SGRBG12_1X12, - .flags = FMT_FLAG_RAW_FROM_SENSOR, - .bpp = 16, + .fourcc = V4L2_PIX_FMT_XBGR32, }, { - .fourcc = V4L2_PIX_FMT_SRGGB12, - .mbus_code = MEDIA_BUS_FMT_SRGGB12_1X12, - .flags = FMT_FLAG_RAW_FROM_SENSOR, - .bpp = 16, + .fourcc = V4L2_PIX_FMT_YUV420, }, { - .fourcc = V4L2_PIX_FMT_YUV420, - .mbus_code = 0x0, - .flags = FMT_FLAG_FROM_CONTROLLER, - .bpp = 12, + .fourcc = V4L2_PIX_FMT_YUYV, }, { .fourcc = V4L2_PIX_FMT_YUV422P, - .mbus_code = 0x0, - .flags = FMT_FLAG_FROM_CONTROLLER, - .bpp = 16, }, { .fourcc = V4L2_PIX_FMT_GREY, - .mbus_code = MEDIA_BUS_FMT_Y8_1X8, - .flags = FMT_FLAG_FROM_CONTROLLER | - FMT_FLAG_FROM_SENSOR, - .bpp = 8, - }, - { - .fourcc = V4L2_PIX_FMT_ARGB444, - .mbus_code = MEDIA_BUS_FMT_RGB444_2X8_PADHI_LE, - .flags = FMT_FLAG_FROM_CONTROLLER, - .bpp = 16, - }, - { - .fourcc = V4L2_PIX_FMT_ARGB555, - .mbus_code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE, - .flags = FMT_FLAG_FROM_CONTROLLER, - .bpp = 16, - }, - { - .fourcc = V4L2_PIX_FMT_RGB565, - .mbus_code = MEDIA_BUS_FMT_RGB565_2X8_LE, - .flags = FMT_FLAG_FROM_CONTROLLER, - .bpp = 16, - }, - { - .fourcc = V4L2_PIX_FMT_ARGB32, - .mbus_code = MEDIA_BUS_FMT_ARGB8888_1X32, - .flags = FMT_FLAG_FROM_CONTROLLER, - .bpp = 32, - }, - { - .fourcc = V4L2_PIX_FMT_YUYV, - .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, - .flags = FMT_FLAG_FROM_CONTROLLER | - FMT_FLAG_FROM_SENSOR, - .bpp = 16, }, }; -static struct fmt_config fmt_configs_list[] = { +/* This is a list of formats that the ISC can receive as *input* */ +static struct isc_format formats_list[] = { { .fourcc = V4L2_PIX_FMT_SBGGR8, + .mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8, .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, .cfa_baycfg = ISC_BAY_CFG_BGBG, - .rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT8, - .dcfg_imode = ISC_DCFG_IMODE_PACKED8, - .dctrl_dview = ISC_DCTRL_DVIEW_PACKED, - .bits_pipeline = 0x0, }, { .fourcc = V4L2_PIX_FMT_SGBRG8, + .mbus_code = MEDIA_BUS_FMT_SGBRG8_1X8, .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, .cfa_baycfg = ISC_BAY_CFG_GBGB, - .rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT8, - .dcfg_imode = ISC_DCFG_IMODE_PACKED8, - .dctrl_dview = ISC_DCTRL_DVIEW_PACKED, - .bits_pipeline = 0x0, }, { .fourcc = V4L2_PIX_FMT_SGRBG8, + .mbus_code = MEDIA_BUS_FMT_SGRBG8_1X8, .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, .cfa_baycfg = ISC_BAY_CFG_GRGR, - .rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT8, - .dcfg_imode = ISC_DCFG_IMODE_PACKED8, - .dctrl_dview = ISC_DCTRL_DVIEW_PACKED, - .bits_pipeline = 0x0, }, { .fourcc = V4L2_PIX_FMT_SRGGB8, + .mbus_code = MEDIA_BUS_FMT_SRGGB8_1X8, .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, .cfa_baycfg = ISC_BAY_CFG_RGRG, - .rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT8, - .dcfg_imode = ISC_DCFG_IMODE_PACKED8, - .dctrl_dview = ISC_DCTRL_DVIEW_PACKED, - .bits_pipeline = 0x0, }, { .fourcc = V4L2_PIX_FMT_SBGGR10, + .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10, .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN, - .cfa_baycfg = ISC_BAY_CFG_BGBG, - .rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT10, - .dcfg_imode = ISC_DCFG_IMODE_PACKED16, - .dctrl_dview = ISC_DCTRL_DVIEW_PACKED, - .bits_pipeline = 0x0, + .cfa_baycfg = ISC_BAY_CFG_RGRG, }, { .fourcc = V4L2_PIX_FMT_SGBRG10, + .mbus_code = MEDIA_BUS_FMT_SGBRG10_1X10, .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN, .cfa_baycfg = ISC_BAY_CFG_GBGB, - .rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT10, - .dcfg_imode = ISC_DCFG_IMODE_PACKED16, - .dctrl_dview = ISC_DCTRL_DVIEW_PACKED, - .bits_pipeline = 0x0, }, { .fourcc = V4L2_PIX_FMT_SGRBG10, + .mbus_code = MEDIA_BUS_FMT_SGRBG10_1X10, .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN, .cfa_baycfg = ISC_BAY_CFG_GRGR, - .rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT10, - .dcfg_imode = ISC_DCFG_IMODE_PACKED16, - .dctrl_dview = ISC_DCTRL_DVIEW_PACKED, - .bits_pipeline = 0x0, }, { .fourcc = V4L2_PIX_FMT_SRGGB10, + .mbus_code = MEDIA_BUS_FMT_SRGGB10_1X10, .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN, .cfa_baycfg = ISC_BAY_CFG_RGRG, - .rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT10, - .dcfg_imode = ISC_DCFG_IMODE_PACKED16, - .dctrl_dview = ISC_DCTRL_DVIEW_PACKED, - .bits_pipeline = 0x0, }, { .fourcc = V4L2_PIX_FMT_SBGGR12, + .mbus_code = MEDIA_BUS_FMT_SBGGR12_1X12, .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TWELVE, .cfa_baycfg = ISC_BAY_CFG_BGBG, - .rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT12, - .dcfg_imode = ISC_DCFG_IMODE_PACKED16, - .dctrl_dview = ISC_DCTRL_DVIEW_PACKED, - .bits_pipeline = 0x0, }, { .fourcc = V4L2_PIX_FMT_SGBRG12, + .mbus_code = MEDIA_BUS_FMT_SGBRG12_1X12, .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TWELVE, .cfa_baycfg = ISC_BAY_CFG_GBGB, - .rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT12, - .dcfg_imode = ISC_DCFG_IMODE_PACKED16, - .dctrl_dview = ISC_DCTRL_DVIEW_PACKED, - .bits_pipeline = 0x0 }, { .fourcc = V4L2_PIX_FMT_SGRBG12, + .mbus_code = MEDIA_BUS_FMT_SGRBG12_1X12, .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TWELVE, .cfa_baycfg = ISC_BAY_CFG_GRGR, - .rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT12, - .dcfg_imode = ISC_DCFG_IMODE_PACKED16, - .dctrl_dview = ISC_DCTRL_DVIEW_PACKED, - .bits_pipeline = 0x0, }, { .fourcc = V4L2_PIX_FMT_SRGGB12, + .mbus_code = MEDIA_BUS_FMT_SRGGB12_1X12, .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TWELVE, .cfa_baycfg = ISC_BAY_CFG_RGRG, - .rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT12, - .dcfg_imode = ISC_DCFG_IMODE_PACKED16, - .dctrl_dview = ISC_DCTRL_DVIEW_PACKED, - .bits_pipeline = 0x0, - }, - { - .fourcc = V4L2_PIX_FMT_YUV420, - .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, - .cfa_baycfg = ISC_BAY_CFG_BGBG, - .rlp_cfg_mode = ISC_RLP_CFG_MODE_YYCC, - .dcfg_imode = ISC_DCFG_IMODE_YC420P, - .dctrl_dview = ISC_DCTRL_DVIEW_PLANAR, - .bits_pipeline = SUB420_ENABLE | SUB422_ENABLE | - CBC_ENABLE | CSC_ENABLE | - GAM_ENABLES | - CFA_ENABLE | WB_ENABLE, - }, - { - .fourcc = V4L2_PIX_FMT_YUV422P, - .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, - .cfa_baycfg = ISC_BAY_CFG_BGBG, - .rlp_cfg_mode = ISC_RLP_CFG_MODE_YYCC, - .dcfg_imode = ISC_DCFG_IMODE_YC422P, - .dctrl_dview = ISC_DCTRL_DVIEW_PLANAR, - .bits_pipeline = SUB422_ENABLE | - CBC_ENABLE | CSC_ENABLE | - GAM_ENABLES | - CFA_ENABLE | WB_ENABLE, }, { .fourcc = V4L2_PIX_FMT_GREY, + .mbus_code = MEDIA_BUS_FMT_Y8_1X8, .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, - .cfa_baycfg = ISC_BAY_CFG_BGBG, - .rlp_cfg_mode = ISC_RLP_CFG_MODE_DATY8, - .dcfg_imode = ISC_DCFG_IMODE_PACKED8, - .dctrl_dview = ISC_DCTRL_DVIEW_PACKED, - .bits_pipeline = CBC_ENABLE | CSC_ENABLE | - GAM_ENABLES | - CFA_ENABLE | WB_ENABLE, - }, - { - .fourcc = V4L2_PIX_FMT_ARGB444, - .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, - .cfa_baycfg = ISC_BAY_CFG_BGBG, - .rlp_cfg_mode = ISC_RLP_CFG_MODE_ARGB444, - .dcfg_imode = ISC_DCFG_IMODE_PACKED16, - .dctrl_dview = ISC_DCTRL_DVIEW_PACKED, - .bits_pipeline = GAM_ENABLES | CFA_ENABLE | WB_ENABLE, }, { - .fourcc = V4L2_PIX_FMT_ARGB555, + .fourcc = V4L2_PIX_FMT_YUYV, + .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, - .cfa_baycfg = ISC_BAY_CFG_BGBG, - .rlp_cfg_mode = ISC_RLP_CFG_MODE_ARGB555, - .dcfg_imode = ISC_DCFG_IMODE_PACKED16, - .dctrl_dview = ISC_DCTRL_DVIEW_PACKED, - .bits_pipeline = GAM_ENABLES | CFA_ENABLE | WB_ENABLE, }, { .fourcc = V4L2_PIX_FMT_RGB565, + .mbus_code = MEDIA_BUS_FMT_RGB565_2X8_LE, .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, - .cfa_baycfg = ISC_BAY_CFG_BGBG, - .rlp_cfg_mode = ISC_RLP_CFG_MODE_RGB565, - .dcfg_imode = ISC_DCFG_IMODE_PACKED16, - .dctrl_dview = ISC_DCTRL_DVIEW_PACKED, - .bits_pipeline = GAM_ENABLES | CFA_ENABLE | WB_ENABLE, - }, - { - .fourcc = V4L2_PIX_FMT_ARGB32, - .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, - .cfa_baycfg = ISC_BAY_CFG_BGBG, - .rlp_cfg_mode = ISC_RLP_CFG_MODE_ARGB32, - .dcfg_imode = ISC_DCFG_IMODE_PACKED32, - .dctrl_dview = ISC_DCTRL_DVIEW_PACKED, - .bits_pipeline = GAM_ENABLES | CFA_ENABLE | WB_ENABLE, - }, - { - .fourcc = V4L2_PIX_FMT_YUYV, - .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT, - .cfa_baycfg = ISC_BAY_CFG_BGBG, - .rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT8, - .dcfg_imode = ISC_DCFG_IMODE_PACKED8, - .dctrl_dview = ISC_DCTRL_DVIEW_PACKED, - .bits_pipeline = 0x0 }, }; @@ -571,6 +383,13 @@ static const u32 isc_gamma_table[GAMMA_MAX + 1][GAMMA_ENTRIES] = { 0x3E20007, 0x3E90007, 0x3F00008, 0x3F80007 }, }; +#define ISC_IS_FORMAT_RAW(mbus_code) \ + (((mbus_code) & 0xf000) == 0x3000) + +static unsigned int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "debug level (0-2)"); + static unsigned int sensor_preferred = 1; module_param(sensor_preferred, uint, 0644); MODULE_PARM_DESC(sensor_preferred, @@ -896,40 +715,17 @@ static int isc_buffer_prepare(struct vb2_buffer *vb) return 0; } -static inline bool sensor_is_preferred(const struct isc_format *isc_fmt) -{ - return (sensor_preferred && isc_fmt->sd_support) || - !isc_fmt->isc_support; -} - -static struct fmt_config *get_fmt_config(u32 fourcc) -{ - struct fmt_config *config; - int i; - - config = &fmt_configs_list[0]; - for (i = 0; i < ARRAY_SIZE(fmt_configs_list); i++) { - if (config->fourcc == fourcc) - return config; - - config++; - } - return NULL; -} - static void isc_start_dma(struct isc_device *isc) { struct regmap *regmap = isc->regmap; - struct v4l2_pix_format *pixfmt = &isc->fmt.fmt.pix; - u32 sizeimage = pixfmt->sizeimage; - struct fmt_config *config = get_fmt_config(isc->current_fmt->fourcc); + u32 sizeimage = isc->fmt.fmt.pix.sizeimage; u32 dctrl_dview; dma_addr_t addr0; addr0 = vb2_dma_contig_plane_dma_addr(&isc->cur_frm->vb.vb2_buf, 0); regmap_write(regmap, ISC_DAD0, addr0); - switch (pixfmt->pixelformat) { + switch (isc->config.fourcc) { case V4L2_PIX_FMT_YUV420: regmap_write(regmap, ISC_DAD1, addr0 + (sizeimage * 2) / 3); regmap_write(regmap, ISC_DAD2, addr0 + (sizeimage * 5) / 6); @@ -942,10 +738,7 @@ static void isc_start_dma(struct isc_device *isc) break; } - if (sensor_is_preferred(isc->current_fmt)) - dctrl_dview = ISC_DCTRL_DVIEW_PACKED; - else - dctrl_dview = config->dctrl_dview; + dctrl_dview = isc->config.dctrl_dview; regmap_write(regmap, ISC_DCTRL, dctrl_dview | ISC_DCTRL_IE_IS); regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_CAPTURE); @@ -955,7 +748,6 @@ static void isc_set_pipeline(struct isc_device *isc, u32 pipeline) { struct regmap *regmap = isc->regmap; struct isc_ctrls *ctrls = &isc->ctrls; - struct fmt_config *config = get_fmt_config(isc->raw_fmt->fourcc); u32 val, bay_cfg; const u32 *gamma; unsigned int i; @@ -969,7 +761,7 @@ static void isc_set_pipeline(struct isc_device *isc, u32 pipeline) if (!pipeline) return; - bay_cfg = config->cfa_baycfg; + bay_cfg = isc->config.sd_format->cfa_baycfg; regmap_write(regmap, ISC_WB_CFG, bay_cfg); regmap_write(regmap, ISC_WB_O_RGR, 0x0); @@ -1011,24 +803,24 @@ static int isc_update_profile(struct isc_device *isc) } if (counter < 0) { - v4l2_warn(&isc->v4l2_dev, "Time out to update profie\n"); + v4l2_warn(&isc->v4l2_dev, "Time out to update profile\n"); return -ETIMEDOUT; } return 0; } -static void isc_set_histogram(struct isc_device *isc) +static void isc_set_histogram(struct isc_device *isc, bool enable) { struct regmap *regmap = isc->regmap; struct isc_ctrls *ctrls = &isc->ctrls; - struct fmt_config *config = get_fmt_config(isc->raw_fmt->fourcc); - if (ctrls->awb && (ctrls->hist_stat != HIST_ENABLED)) { + if (enable) { regmap_write(regmap, ISC_HIS_CFG, ISC_HIS_CFG_MODE_R | - (config->cfa_baycfg << ISC_HIS_CFG_BAYSEL_SHIFT) | - ISC_HIS_CFG_RAR); + (isc->config.sd_format->cfa_baycfg + << ISC_HIS_CFG_BAYSEL_SHIFT) | + ISC_HIS_CFG_RAR); regmap_write(regmap, ISC_HIS_CTRL, ISC_HIS_CTRL_EN); regmap_write(regmap, ISC_INTEN, ISC_INT_HISDONE); ctrls->hist_id = ISC_HIS_CFG_MODE_R; @@ -1036,7 +828,7 @@ static void isc_set_histogram(struct isc_device *isc) regmap_write(regmap, ISC_CTRLEN, ISC_CTRL_HISREQ); ctrls->hist_stat = HIST_ENABLED; - } else if (!ctrls->awb && (ctrls->hist_stat != HIST_DISABLED)) { + } else { regmap_write(regmap, ISC_INTDIS, ISC_INT_HISDONE); regmap_write(regmap, ISC_HIS_CTRL, ISC_HIS_CTRL_DIS); @@ -1044,58 +836,24 @@ static void isc_set_histogram(struct isc_device *isc) } } -static inline void isc_get_param(const struct isc_format *fmt, - u32 *rlp_mode, u32 *dcfg) -{ - struct fmt_config *config = get_fmt_config(fmt->fourcc); - - *dcfg = ISC_DCFG_YMBSIZE_BEATS8; - - switch (fmt->fourcc) { - case V4L2_PIX_FMT_SBGGR10: - case V4L2_PIX_FMT_SGBRG10: - case V4L2_PIX_FMT_SGRBG10: - case V4L2_PIX_FMT_SRGGB10: - case V4L2_PIX_FMT_SBGGR12: - case V4L2_PIX_FMT_SGBRG12: - case V4L2_PIX_FMT_SGRBG12: - case V4L2_PIX_FMT_SRGGB12: - *rlp_mode = config->rlp_cfg_mode; - *dcfg |= config->dcfg_imode; - break; - default: - *rlp_mode = ISC_RLP_CFG_MODE_DAT8; - *dcfg |= ISC_DCFG_IMODE_PACKED8; - break; - } -} - static int isc_configure(struct isc_device *isc) { struct regmap *regmap = isc->regmap; - const struct isc_format *current_fmt = isc->current_fmt; - struct fmt_config *curfmt_config = get_fmt_config(current_fmt->fourcc); - struct fmt_config *rawfmt_config = get_fmt_config(isc->raw_fmt->fourcc); - struct isc_subdev_entity *subdev = isc->current_subdev; u32 pfe_cfg0, rlp_mode, dcfg, mask, pipeline; + struct isc_subdev_entity *subdev = isc->current_subdev; - if (sensor_is_preferred(current_fmt)) { - pfe_cfg0 = curfmt_config->pfe_cfg0_bps; - pipeline = 0x0; - isc_get_param(current_fmt, &rlp_mode, &dcfg); - isc->ctrls.hist_stat = HIST_INIT; - } else { - pfe_cfg0 = rawfmt_config->pfe_cfg0_bps; - pipeline = curfmt_config->bits_pipeline; - rlp_mode = curfmt_config->rlp_cfg_mode; - dcfg = curfmt_config->dcfg_imode | + pfe_cfg0 = isc->config.sd_format->pfe_cfg0_bps; + rlp_mode = isc->config.rlp_cfg_mode; + pipeline = isc->config.bits_pipeline; + + dcfg = isc->config.dcfg_imode | ISC_DCFG_YMBSIZE_BEATS8 | ISC_DCFG_CMBSIZE_BEATS8; - } pfe_cfg0 |= subdev->pfe_cfg0 | ISC_PFE_CFG0_MODE_PROGRESSIVE; mask = ISC_PFE_CFG0_BPS_MASK | ISC_PFE_CFG0_HPOL_LOW | ISC_PFE_CFG0_VPOL_LOW | ISC_PFE_CFG0_PPOL_LOW | - ISC_PFE_CFG0_MODE_MASK; + ISC_PFE_CFG0_MODE_MASK | ISC_PFE_CFG0_CCIR_CRC | + ISC_PFE_CFG0_CCIR656; regmap_update_bits(regmap, ISC_PFE_CFG0, mask, pfe_cfg0); @@ -1107,8 +865,15 @@ static int isc_configure(struct isc_device *isc) /* Set the pipeline */ isc_set_pipeline(isc, pipeline); - if (pipeline) - isc_set_histogram(isc); + /* + * The current implemented histogram is available for RAW R, B, GB + * channels. We need to check if sensor is outputting RAW BAYER + */ + if (isc->ctrls.awb && + ISC_IS_FORMAT_RAW(isc->config.sd_format->mbus_code)) + isc_set_histogram(isc, true); + else + isc_set_histogram(isc, false); /* Update profile */ return isc_update_profile(isc); @@ -1125,7 +890,8 @@ static int isc_start_streaming(struct vb2_queue *vq, unsigned int count) /* Enable stream on the sub device */ ret = v4l2_subdev_call(isc->current_subdev->sd, video, s_stream, 1); if (ret && ret != -ENOIOCTLCMD) { - v4l2_err(&isc->v4l2_dev, "stream on failed in subdev\n"); + v4l2_err(&isc->v4l2_dev, "stream on failed in subdev %d\n", + ret); goto err_start_stream; } @@ -1223,6 +989,22 @@ static void isc_buffer_queue(struct vb2_buffer *vb) spin_unlock_irqrestore(&isc->dma_queue_lock, flags); } +static struct isc_format *find_format_by_fourcc(struct isc_device *isc, + unsigned int fourcc) +{ + unsigned int num_formats = isc->num_user_formats; + struct isc_format *fmt; + unsigned int i; + + for (i = 0; i < num_formats; i++) { + fmt = isc->user_formats[i]; + if (fmt->fourcc == fourcc) + return fmt; + } + + return NULL; +} + static const struct vb2_ops isc_vb2_ops = { .queue_setup = isc_queue_setup, .wait_prepare = vb2_ops_wait_prepare, @@ -1249,15 +1031,31 @@ static int isc_querycap(struct file *file, void *priv, static int isc_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f) { - struct isc_device *isc = video_drvdata(file); u32 index = f->index; + u32 i, supported_index; - if (index >= isc->num_user_formats) - return -EINVAL; + if (index < ARRAY_SIZE(controller_formats)) { + f->pixelformat = controller_formats[index].fourcc; + return 0; + } - f->pixelformat = isc->user_formats[index]->fourcc; + index -= ARRAY_SIZE(controller_formats); - return 0; + i = 0; + supported_index = 0; + + for (i = 0; i < ARRAY_SIZE(formats_list); i++) { + if (!ISC_IS_FORMAT_RAW(formats_list[i].mbus_code) || + !formats_list[i].sd_support) + continue; + if (supported_index == index) { + f->pixelformat = formats_list[i].fourcc; + return 0; + } + supported_index++; + } + + return -EINVAL; } static int isc_g_fmt_vid_cap(struct file *file, void *priv, @@ -1270,26 +1068,238 @@ static int isc_g_fmt_vid_cap(struct file *file, void *priv, return 0; } -static struct isc_format *find_format_by_fourcc(struct isc_device *isc, - unsigned int fourcc) +/* + * Checks the current configured format, if ISC can output it, + * considering which type of format the ISC receives from the sensor + */ +static int isc_try_validate_formats(struct isc_device *isc) { - unsigned int num_formats = isc->num_user_formats; - struct isc_format *fmt; - unsigned int i; + int ret; + bool bayer = false, yuv = false, rgb = false, grey = false; + + /* all formats supported by the RLP module are OK */ + switch (isc->try_config.fourcc) { + case V4L2_PIX_FMT_SBGGR8: + case V4L2_PIX_FMT_SGBRG8: + case V4L2_PIX_FMT_SGRBG8: + case V4L2_PIX_FMT_SRGGB8: + case V4L2_PIX_FMT_SBGGR10: + case V4L2_PIX_FMT_SGBRG10: + case V4L2_PIX_FMT_SGRBG10: + case V4L2_PIX_FMT_SRGGB10: + case V4L2_PIX_FMT_SBGGR12: + case V4L2_PIX_FMT_SGBRG12: + case V4L2_PIX_FMT_SGRBG12: + case V4L2_PIX_FMT_SRGGB12: + ret = 0; + bayer = true; + break; - for (i = 0; i < num_formats; i++) { - fmt = isc->user_formats[i]; - if (fmt->fourcc == fourcc) - return fmt; + case V4L2_PIX_FMT_YUV420: + case V4L2_PIX_FMT_YUV422P: + case V4L2_PIX_FMT_YUYV: + ret = 0; + yuv = true; + break; + + case V4L2_PIX_FMT_RGB565: + case V4L2_PIX_FMT_ABGR32: + case V4L2_PIX_FMT_XBGR32: + case V4L2_PIX_FMT_ARGB444: + case V4L2_PIX_FMT_ARGB555: + ret = 0; + rgb = true; + break; + case V4L2_PIX_FMT_GREY: + ret = 0; + grey = true; + break; + default: + /* any other different formats are not supported */ + ret = -EINVAL; } - return NULL; + /* we cannot output RAW/Grey if we do not receive RAW */ + if ((bayer || grey) && + !ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) + return -EINVAL; + + v4l2_dbg(1, debug, &isc->v4l2_dev, + "Format validation, requested rgb=%u, yuv=%u, grey=%u, bayer=%u\n", + rgb, yuv, grey, bayer); + + return ret; +} + +/* + * Configures the RLP and DMA modules, depending on the output format + * configured for the ISC. + * If direct_dump == true, just dump raw data 8 bits. + */ +static int isc_try_configure_rlp_dma(struct isc_device *isc, bool direct_dump) +{ + if (direct_dump) { + isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT8; + isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED8; + isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED; + isc->try_config.bpp = 16; + return 0; + } + + switch (isc->try_config.fourcc) { + case V4L2_PIX_FMT_SBGGR8: + case V4L2_PIX_FMT_SGBRG8: + case V4L2_PIX_FMT_SGRBG8: + case V4L2_PIX_FMT_SRGGB8: + isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT8; + isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED8; + isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED; + isc->try_config.bpp = 8; + break; + case V4L2_PIX_FMT_SBGGR10: + case V4L2_PIX_FMT_SGBRG10: + case V4L2_PIX_FMT_SGRBG10: + case V4L2_PIX_FMT_SRGGB10: + isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT10; + isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED16; + isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED; + isc->try_config.bpp = 16; + break; + case V4L2_PIX_FMT_SBGGR12: + case V4L2_PIX_FMT_SGBRG12: + case V4L2_PIX_FMT_SGRBG12: + case V4L2_PIX_FMT_SRGGB12: + isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_DAT12; + isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED16; + isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED; + isc->try_config.bpp = 16; + break; + case V4L2_PIX_FMT_RGB565: + isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_RGB565; + isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED16; + isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED; + isc->try_config.bpp = 16; + break; + case V4L2_PIX_FMT_ARGB444: + isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_ARGB444; + isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED16; + isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED; + isc->try_config.bpp = 16; + break; + case V4L2_PIX_FMT_ARGB555: + isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_ARGB555; + isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED16; + isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED; + isc->try_config.bpp = 16; + break; + case V4L2_PIX_FMT_ABGR32: + case V4L2_PIX_FMT_XBGR32: + isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_ARGB32; + isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED32; + isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED; + isc->try_config.bpp = 32; + break; + case V4L2_PIX_FMT_YUV420: + isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_YYCC; + isc->try_config.dcfg_imode = ISC_DCFG_IMODE_YC420P; + isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PLANAR; + isc->try_config.bpp = 12; + break; + case V4L2_PIX_FMT_YUV422P: + isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_YYCC; + isc->try_config.dcfg_imode = ISC_DCFG_IMODE_YC422P; + isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PLANAR; + isc->try_config.bpp = 16; + break; + case V4L2_PIX_FMT_YUYV: + isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_YYCC; + isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED32; + isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED; + isc->try_config.bpp = 16; + break; + case V4L2_PIX_FMT_GREY: + isc->try_config.rlp_cfg_mode = ISC_RLP_CFG_MODE_DATY8; + isc->try_config.dcfg_imode = ISC_DCFG_IMODE_PACKED8; + isc->try_config.dctrl_dview = ISC_DCTRL_DVIEW_PACKED; + isc->try_config.bpp = 8; + break; + default: + return -EINVAL; + } + return 0; +} + +/* + * Configuring pipeline modules, depending on which format the ISC outputs + * and considering which format it has as input from the sensor. + */ +static int isc_try_configure_pipeline(struct isc_device *isc) +{ + switch (isc->try_config.fourcc) { + case V4L2_PIX_FMT_RGB565: + case V4L2_PIX_FMT_ARGB555: + case V4L2_PIX_FMT_ARGB444: + case V4L2_PIX_FMT_ABGR32: + case V4L2_PIX_FMT_XBGR32: + /* if sensor format is RAW, we convert inside ISC */ + if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) { + isc->try_config.bits_pipeline = CFA_ENABLE | + WB_ENABLE | GAM_ENABLES; + } else { + isc->try_config.bits_pipeline = 0x0; + } + break; + case V4L2_PIX_FMT_YUV420: + /* if sensor format is RAW, we convert inside ISC */ + if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) { + isc->try_config.bits_pipeline = CFA_ENABLE | + CSC_ENABLE | WB_ENABLE | GAM_ENABLES | + SUB420_ENABLE | SUB422_ENABLE | CBC_ENABLE; + } else { + isc->try_config.bits_pipeline = 0x0; + } + break; + case V4L2_PIX_FMT_YUV422P: + /* if sensor format is RAW, we convert inside ISC */ + if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) { + isc->try_config.bits_pipeline = CFA_ENABLE | + CSC_ENABLE | WB_ENABLE | GAM_ENABLES | + SUB422_ENABLE | CBC_ENABLE; + } else { + isc->try_config.bits_pipeline = 0x0; + } + break; + case V4L2_PIX_FMT_YUYV: + /* if sensor format is RAW, we convert inside ISC */ + if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) { + isc->try_config.bits_pipeline = CFA_ENABLE | + CSC_ENABLE | WB_ENABLE | GAM_ENABLES | + SUB422_ENABLE | CBC_ENABLE; + } else { + isc->try_config.bits_pipeline = 0x0; + } + break; + case V4L2_PIX_FMT_GREY: + if (ISC_IS_FORMAT_RAW(isc->try_config.sd_format->mbus_code)) { + /* if sensor format is RAW, we convert inside ISC */ + isc->try_config.bits_pipeline = CFA_ENABLE | + CSC_ENABLE | WB_ENABLE | GAM_ENABLES | + CBC_ENABLE; + } else { + isc->try_config.bits_pipeline = 0x0; + } + break; + default: + isc->try_config.bits_pipeline = 0x0; + } + return 0; } static int isc_try_fmt(struct isc_device *isc, struct v4l2_format *f, - struct isc_format **current_fmt, u32 *code) + u32 *code) { - struct isc_format *isc_fmt; + int i; + struct isc_format *sd_fmt = NULL, *direct_fmt = NULL; struct v4l2_pix_format *pixfmt = &f->fmt.pix; struct v4l2_subdev_pad_config pad_cfg; struct v4l2_subdev_format format = { @@ -1297,48 +1307,119 @@ static int isc_try_fmt(struct isc_device *isc, struct v4l2_format *f, }; u32 mbus_code; int ret; + bool rlp_dma_direct_dump = false; if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; - isc_fmt = find_format_by_fourcc(isc, pixfmt->pixelformat); - if (!isc_fmt) { - v4l2_warn(&isc->v4l2_dev, "Format 0x%x not found\n", - pixfmt->pixelformat); - isc_fmt = isc->user_formats[isc->num_user_formats - 1]; - pixfmt->pixelformat = isc_fmt->fourcc; + /* Step 1: find a RAW format that is supported */ + for (i = 0; i < isc->num_user_formats; i++) { + if (ISC_IS_FORMAT_RAW(isc->user_formats[i]->mbus_code)) { + sd_fmt = isc->user_formats[i]; + break; + } + } + /* Step 2: We can continue with this RAW format, or we can look + * for better: maybe sensor supports directly what we need. + */ + direct_fmt = find_format_by_fourcc(isc, pixfmt->pixelformat); + + /* Step 3: We have both. We decide given the module parameter which + * one to use. + */ + if (direct_fmt && sd_fmt && sensor_preferred) + sd_fmt = direct_fmt; + + /* Step 4: we do not have RAW but we have a direct format. Use it. */ + if (direct_fmt && !sd_fmt) + sd_fmt = direct_fmt; + + /* Step 5: if we are using a direct format, we need to package + * everything as 8 bit data and just dump it + */ + if (sd_fmt == direct_fmt) + rlp_dma_direct_dump = true; + + /* Step 6: We have no format. This can happen if the userspace + * requests some weird/invalid format. + * In this case, default to whatever we have + */ + if (!sd_fmt && !direct_fmt) { + sd_fmt = isc->user_formats[isc->num_user_formats - 1]; + v4l2_dbg(1, debug, &isc->v4l2_dev, + "Sensor not supporting %.4s, using %.4s\n", + (char *)&pixfmt->pixelformat, (char *)&sd_fmt->fourcc); + } + + if (!sd_fmt) { + ret = -EINVAL; + goto isc_try_fmt_err; } + /* Step 7: Print out what we decided for debugging */ + v4l2_dbg(1, debug, &isc->v4l2_dev, + "Preferring to have sensor using format %.4s\n", + (char *)&sd_fmt->fourcc); + + /* Step 8: at this moment we decided which format the subdev will use */ + isc->try_config.sd_format = sd_fmt; + /* Limit to Atmel ISC hardware capabilities */ if (pixfmt->width > ISC_MAX_SUPPORT_WIDTH) pixfmt->width = ISC_MAX_SUPPORT_WIDTH; if (pixfmt->height > ISC_MAX_SUPPORT_HEIGHT) pixfmt->height = ISC_MAX_SUPPORT_HEIGHT; - if (sensor_is_preferred(isc_fmt)) - mbus_code = isc_fmt->mbus_code; - else - mbus_code = isc->raw_fmt->mbus_code; + /* + * The mbus format is the one the subdev outputs. + * The pixels will be transferred in this format Sensor -> ISC + */ + mbus_code = sd_fmt->mbus_code; + + /* + * Validate formats. If the required format is not OK, default to raw. + */ + + isc->try_config.fourcc = pixfmt->pixelformat; + + if (isc_try_validate_formats(isc)) { + pixfmt->pixelformat = isc->try_config.fourcc = sd_fmt->fourcc; + /* Re-try to validate the new format */ + ret = isc_try_validate_formats(isc); + if (ret) + goto isc_try_fmt_err; + } + + ret = isc_try_configure_rlp_dma(isc, rlp_dma_direct_dump); + if (ret) + goto isc_try_fmt_err; + + ret = isc_try_configure_pipeline(isc); + if (ret) + goto isc_try_fmt_err; v4l2_fill_mbus_format(&format.format, pixfmt, mbus_code); ret = v4l2_subdev_call(isc->current_subdev->sd, pad, set_fmt, &pad_cfg, &format); if (ret < 0) - return ret; + goto isc_try_fmt_err; v4l2_fill_pix_format(pixfmt, &format.format); pixfmt->field = V4L2_FIELD_NONE; - pixfmt->bytesperline = (pixfmt->width * isc_fmt->bpp) >> 3; + pixfmt->bytesperline = (pixfmt->width * isc->try_config.bpp) >> 3; pixfmt->sizeimage = pixfmt->bytesperline * pixfmt->height; - if (current_fmt) - *current_fmt = isc_fmt; - if (code) *code = mbus_code; return 0; + +isc_try_fmt_err: + v4l2_err(&isc->v4l2_dev, "Could not find any possible format for a working pipeline\n"); + memset(&isc->try_config, 0, sizeof(isc->try_config)); + + return ret; } static int isc_set_fmt(struct isc_device *isc, struct v4l2_format *f) @@ -1346,11 +1427,10 @@ static int isc_set_fmt(struct isc_device *isc, struct v4l2_format *f) struct v4l2_subdev_format format = { .which = V4L2_SUBDEV_FORMAT_ACTIVE, }; - struct isc_format *current_fmt; - u32 mbus_code; + u32 mbus_code = 0; int ret; - ret = isc_try_fmt(isc, f, ¤t_fmt, &mbus_code); + ret = isc_try_fmt(isc, f, &mbus_code); if (ret) return ret; @@ -1361,7 +1441,10 @@ static int isc_set_fmt(struct isc_device *isc, struct v4l2_format *f) return ret; isc->fmt = *f; - isc->current_fmt = current_fmt; + /* make the try configuration active */ + isc->config = isc->try_config; + + v4l2_dbg(1, debug, &isc->v4l2_dev, "New ISC configuration in place\n"); return 0; } @@ -1382,7 +1465,7 @@ static int isc_try_fmt_vid_cap(struct file *file, void *priv, { struct isc_device *isc = video_drvdata(file); - return isc_try_fmt(isc, f, NULL, NULL); + return isc_try_fmt(isc, f, NULL); } static int isc_enum_input(struct file *file, void *priv, @@ -1431,27 +1514,31 @@ static int isc_enum_framesizes(struct file *file, void *fh, struct v4l2_frmsizeenum *fsize) { struct isc_device *isc = video_drvdata(file); - const struct isc_format *isc_fmt; struct v4l2_subdev_frame_size_enum fse = { .index = fsize->index, .which = V4L2_SUBDEV_FORMAT_ACTIVE, }; - int ret; + int ret = -EINVAL; + int i; - isc_fmt = find_format_by_fourcc(isc, fsize->pixel_format); - if (!isc_fmt) - return -EINVAL; + for (i = 0; i < isc->num_user_formats; i++) + if (isc->user_formats[i]->fourcc == fsize->pixel_format) + ret = 0; - if (sensor_is_preferred(isc_fmt)) - fse.code = isc_fmt->mbus_code; - else - fse.code = isc->raw_fmt->mbus_code; + for (i = 0; i < ARRAY_SIZE(controller_formats); i++) + if (controller_formats[i].fourcc == fsize->pixel_format) + ret = 0; + + if (ret) + return ret; ret = v4l2_subdev_call(isc->current_subdev->sd, pad, enum_frame_size, NULL, &fse); if (ret) return ret; + fse.code = isc->config.sd_format->mbus_code; + fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; fsize->discrete.width = fse.max_width; fsize->discrete.height = fse.max_height; @@ -1463,29 +1550,32 @@ static int isc_enum_frameintervals(struct file *file, void *fh, struct v4l2_frmivalenum *fival) { struct isc_device *isc = video_drvdata(file); - const struct isc_format *isc_fmt; struct v4l2_subdev_frame_interval_enum fie = { .index = fival->index, .width = fival->width, .height = fival->height, .which = V4L2_SUBDEV_FORMAT_ACTIVE, }; - int ret; + int ret = -EINVAL; + int i; - isc_fmt = find_format_by_fourcc(isc, fival->pixel_format); - if (!isc_fmt) - return -EINVAL; + for (i = 0; i < isc->num_user_formats; i++) + if (isc->user_formats[i]->fourcc == fival->pixel_format) + ret = 0; - if (sensor_is_preferred(isc_fmt)) - fie.code = isc_fmt->mbus_code; - else - fie.code = isc->raw_fmt->mbus_code; + for (i = 0; i < ARRAY_SIZE(controller_formats); i++) + if (controller_formats[i].fourcc == fival->pixel_format) + ret = 0; + + if (ret) + return ret; ret = v4l2_subdev_call(isc->current_subdev->sd, pad, enum_frame_interval, NULL, &fie); if (ret) return ret; + fie.code = isc->config.sd_format->mbus_code; fival->type = V4L2_FRMIVAL_TYPE_DISCRETE; fival->discrete = fie.interval; @@ -1668,7 +1758,6 @@ static void isc_awb_work(struct work_struct *w) struct isc_device *isc = container_of(w, struct isc_device, awb_work); struct regmap *regmap = isc->regmap; - struct fmt_config *config = get_fmt_config(isc->raw_fmt->fourcc); struct isc_ctrls *ctrls = &isc->ctrls; u32 hist_id = ctrls->hist_id; u32 baysel; @@ -1686,7 +1775,7 @@ static void isc_awb_work(struct work_struct *w) } ctrls->hist_id = hist_id; - baysel = config->cfa_baycfg << ISC_HIS_CFG_BAYSEL_SHIFT; + baysel = isc->config.sd_format->cfa_baycfg << ISC_HIS_CFG_BAYSEL_SHIFT; pm_runtime_get_sync(isc->dev); @@ -1754,7 +1843,6 @@ static int isc_ctrl_init(struct isc_device *isc) return 0; } - static int isc_async_bound(struct v4l2_async_notifier *notifier, struct v4l2_subdev *subdev, struct v4l2_async_subdev *asd) @@ -1812,35 +1900,20 @@ static int isc_formats_init(struct isc_device *isc) .which = V4L2_SUBDEV_FORMAT_ACTIVE, }; + num_fmts = 0; while (!v4l2_subdev_call(subdev, pad, enum_mbus_code, NULL, &mbus_code)) { mbus_code.index++; fmt = find_format_by_code(mbus_code.code, &i); - if ((!fmt) || (!(fmt->flags & FMT_FLAG_FROM_SENSOR))) + if (!fmt) { + v4l2_warn(&isc->v4l2_dev, "Mbus code %x not supported\n", + mbus_code.code); continue; + } fmt->sd_support = true; - - if (fmt->flags & FMT_FLAG_RAW_FORMAT) - isc->raw_fmt = fmt; - } - - fmt = &formats_list[0]; - for (i = 0; i < list_size; i++) { - if (fmt->flags & FMT_FLAG_FROM_CONTROLLER) - fmt->isc_support = true; - - fmt++; - } - - fmt = &formats_list[0]; - num_fmts = 0; - for (i = 0; i < list_size; i++) { - if (fmt->isc_support || fmt->sd_support) - num_fmts++; - - fmt++; + num_fmts++; } if (!num_fmts) @@ -1855,9 +1928,8 @@ static int isc_formats_init(struct isc_device *isc) fmt = &formats_list[0]; for (i = 0, j = 0; i < list_size; i++) { - if (fmt->isc_support || fmt->sd_support) + if (fmt->sd_support) isc->user_formats[j++] = fmt; - fmt++; } @@ -1877,13 +1949,11 @@ static int isc_set_default_fmt(struct isc_device *isc) }; int ret; - ret = isc_try_fmt(isc, &f, NULL, NULL); + ret = isc_try_fmt(isc, &f, NULL); if (ret) return ret; - isc->current_fmt = isc->user_formats[0]; isc->fmt = f; - return 0; } @@ -2084,6 +2154,10 @@ static int isc_parse_dt(struct device *dev, struct isc_device *isc) if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING) subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_PPOL_LOW; + if (v4l2_epn.bus_type == V4L2_MBUS_BT656) + subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_CCIR_CRC | + ISC_PFE_CFG0_CCIR656; + subdev_entity->asd->match_type = V4L2_ASYNC_MATCH_FWNODE; subdev_entity->asd->match.fwnode = of_fwnode_handle(rem); diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c index b4f396c2e72c..eaa86737fa04 100644 --- a/drivers/media/platform/coda/coda-bit.c +++ b/drivers/media/platform/coda/coda-bit.c @@ -2010,6 +2010,9 @@ static int coda_prepare_decode(struct coda_ctx *ctx) /* Clear decode success flag */ coda_write(dev, 0, CODA_RET_DEC_PIC_SUCCESS); + /* Clear error return value */ + coda_write(dev, 0, CODA_RET_DEC_PIC_ERR_MB); + trace_coda_dec_pic_run(ctx, meta); coda_command_async(ctx, CODA_COMMAND_PIC_RUN); diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index fa0b22fb7991..3ce58dee4422 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -764,6 +764,7 @@ static int coda_s_fmt_vid_cap(struct file *file, void *priv, { struct coda_ctx *ctx = fh_to_ctx(priv); struct coda_q_data *q_data_src; + const struct coda_codec *codec; struct v4l2_rect r; int ret; @@ -784,6 +785,15 @@ static int coda_s_fmt_vid_cap(struct file *file, void *priv, if (ctx->inst_type != CODA_INST_ENCODER) return 0; + /* Setting the coded format determines the selected codec */ + codec = coda_find_codec(ctx->dev, q_data_src->fourcc, + f->fmt.pix.pixelformat); + if (!codec) { + v4l2_err(&ctx->dev->v4l2_dev, "failed to determine codec\n"); + return -EINVAL; + } + ctx->codec = codec; + ctx->colorspace = f->fmt.pix.colorspace; ctx->xfer_func = f->fmt.pix.xfer_func; ctx->ycbcr_enc = f->fmt.pix.ycbcr_enc; @@ -796,6 +806,7 @@ static int coda_s_fmt_vid_out(struct file *file, void *priv, struct v4l2_format *f) { struct coda_ctx *ctx = fh_to_ctx(priv); + const struct coda_codec *codec; struct v4l2_format f_cap; struct vb2_queue *dst_vq; int ret; @@ -808,14 +819,23 @@ static int coda_s_fmt_vid_out(struct file *file, void *priv, if (ret) return ret; - if (ctx->inst_type != CODA_INST_DECODER) - return 0; - ctx->colorspace = f->fmt.pix.colorspace; ctx->xfer_func = f->fmt.pix.xfer_func; ctx->ycbcr_enc = f->fmt.pix.ycbcr_enc; ctx->quantization = f->fmt.pix.quantization; + if (ctx->inst_type != CODA_INST_DECODER) + return 0; + + /* Setting the coded format determines the selected codec */ + codec = coda_find_codec(ctx->dev, f->fmt.pix.pixelformat, + V4L2_PIX_FMT_YUV420); + if (!codec) { + v4l2_err(&ctx->dev->v4l2_dev, "failed to determine codec\n"); + return -EINVAL; + } + ctx->codec = codec; + dst_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); if (!dst_vq) return -EINVAL; @@ -980,6 +1000,11 @@ static int coda_s_selection(struct file *file, void *fh, static int coda_try_encoder_cmd(struct file *file, void *fh, struct v4l2_encoder_cmd *ec) { + struct coda_ctx *ctx = fh_to_ctx(fh); + + if (ctx->inst_type != CODA_INST_ENCODER) + return -ENOTTY; + if (ec->cmd != V4L2_ENC_CMD_STOP) return -EINVAL; @@ -1000,10 +1025,6 @@ static int coda_encoder_cmd(struct file *file, void *fh, if (ret < 0) return ret; - /* Ignore encoder stop command silently in decoder context */ - if (ctx->inst_type != CODA_INST_ENCODER) - return 0; - /* Set the stream-end flag on this context */ ctx->bit_stream_param |= CODA_BIT_STREAM_END_FLAG; @@ -1021,6 +1042,11 @@ static int coda_encoder_cmd(struct file *file, void *fh, static int coda_try_decoder_cmd(struct file *file, void *fh, struct v4l2_decoder_cmd *dc) { + struct coda_ctx *ctx = fh_to_ctx(fh); + + if (ctx->inst_type != CODA_INST_DECODER) + return -ENOTTY; + if (dc->cmd != V4L2_DEC_CMD_STOP) return -EINVAL; @@ -1043,10 +1069,6 @@ static int coda_decoder_cmd(struct file *file, void *fh, if (ret < 0) return ret; - /* Ignore decoder stop command silently in encoder context */ - if (ctx->inst_type != CODA_INST_DECODER) - return 0; - /* Set the stream-end flag on this context */ coda_bit_stream_end_flag(ctx); ctx->hold = false; @@ -1055,6 +1077,42 @@ static int coda_decoder_cmd(struct file *file, void *fh, return 0; } +static int coda_enum_framesizes(struct file *file, void *fh, + struct v4l2_frmsizeenum *fsize) +{ + struct coda_ctx *ctx = fh_to_ctx(fh); + struct coda_q_data *q_data_dst; + const struct coda_codec *codec; + + if (ctx->inst_type != CODA_INST_ENCODER) + return -ENOTTY; + + if (fsize->index) + return -EINVAL; + + if (coda_format_normalize_yuv(fsize->pixel_format) == + V4L2_PIX_FMT_YUV420) { + q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + codec = coda_find_codec(ctx->dev, fsize->pixel_format, + q_data_dst->fourcc); + } else { + codec = coda_find_codec(ctx->dev, V4L2_PIX_FMT_YUV420, + fsize->pixel_format); + } + if (!codec) + return -EINVAL; + + fsize->type = V4L2_FRMSIZE_TYPE_CONTINUOUS; + fsize->stepwise.min_width = MIN_W; + fsize->stepwise.max_width = codec->max_w; + fsize->stepwise.step_width = 1; + fsize->stepwise.min_height = MIN_H; + fsize->stepwise.max_height = codec->max_h; + fsize->stepwise.step_height = 1; + + return 0; +} + static int coda_enum_frameintervals(struct file *file, void *fh, struct v4l2_frmivalenum *f) { @@ -1233,6 +1291,7 @@ static const struct v4l2_ioctl_ops coda_ioctl_ops = { .vidioc_g_parm = coda_g_parm, .vidioc_s_parm = coda_s_parm, + .vidioc_enum_framesizes = coda_enum_framesizes, .vidioc_enum_frameintervals = coda_enum_frameintervals, .vidioc_subscribe_event = coda_subscribe_event, @@ -1442,6 +1501,9 @@ static int coda_queue_setup(struct vb2_queue *vq, q_data = get_q_data(ctx, vq->type); size = q_data->sizeimage; + if (*nplanes) + return sizes[0] < size ? -EINVAL : 0; + *nplanes = 1; sizes[0] = size; @@ -1680,14 +1742,6 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count) ctx->gopcounter = ctx->params.gop_size - 1; - ctx->codec = coda_find_codec(ctx->dev, q_data_src->fourcc, - q_data_dst->fourcc); - if (!ctx->codec) { - v4l2_err(v4l2_dev, "couldn't tell instance type.\n"); - ret = -EINVAL; - goto err; - } - if (q_data_dst->fourcc == V4L2_PIX_FMT_JPEG) ctx->params.gop_size = 1; ctx->gopcounter = ctx->params.gop_size - 1; @@ -2015,7 +2069,6 @@ static void coda_jpeg_encode_ctrls(struct coda_ctx *ctx) static void coda_decode_ctrls(struct coda_ctx *ctx) { - u64 mask; u8 max; ctx->h264_profile_ctrl = v4l2_ctrl_new_std_menu(&ctx->ctrls, @@ -2029,27 +2082,14 @@ static void coda_decode_ctrls(struct coda_ctx *ctx) ctx->h264_profile_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; if (ctx->dev->devtype->product == CODA_HX4 || - ctx->dev->devtype->product == CODA_7541) { + ctx->dev->devtype->product == CODA_7541) max = V4L2_MPEG_VIDEO_H264_LEVEL_4_0; - mask = ~((1 << V4L2_MPEG_VIDEO_H264_LEVEL_2_0) | - (1 << V4L2_MPEG_VIDEO_H264_LEVEL_3_0) | - (1 << V4L2_MPEG_VIDEO_H264_LEVEL_3_1) | - (1 << V4L2_MPEG_VIDEO_H264_LEVEL_3_2) | - (1 << V4L2_MPEG_VIDEO_H264_LEVEL_4_0)); - } else if (ctx->dev->devtype->product == CODA_960) { + else if (ctx->dev->devtype->product == CODA_960) max = V4L2_MPEG_VIDEO_H264_LEVEL_4_1; - mask = ~((1 << V4L2_MPEG_VIDEO_H264_LEVEL_2_0) | - (1 << V4L2_MPEG_VIDEO_H264_LEVEL_3_0) | - (1 << V4L2_MPEG_VIDEO_H264_LEVEL_3_1) | - (1 << V4L2_MPEG_VIDEO_H264_LEVEL_3_2) | - (1 << V4L2_MPEG_VIDEO_H264_LEVEL_4_0) | - (1 << V4L2_MPEG_VIDEO_H264_LEVEL_4_1)); - } else { + else return; - } ctx->h264_level_ctrl = v4l2_ctrl_new_std_menu(&ctx->ctrls, - &coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_H264_LEVEL, max, mask, - max); + &coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_H264_LEVEL, max, 0, max); if (ctx->h264_level_ctrl) ctx->h264_level_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY; } @@ -2063,11 +2103,17 @@ static int coda_ctrls_setup(struct coda_ctx *ctx) v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, V4L2_CID_VFLIP, 0, 1, 1, 0); if (ctx->inst_type == CODA_INST_ENCODER) { + v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, + V4L2_CID_MIN_BUFFERS_FOR_OUTPUT, + 1, 1, 1, 1); if (ctx->cvd->dst_formats[0] == V4L2_PIX_FMT_JPEG) coda_jpeg_encode_ctrls(ctx); else coda_encode_ctrls(ctx); } else { + v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops, + V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, + 1, 1, 1, 1); if (ctx->cvd->src_formats[0] == V4L2_PIX_FMT_H264) coda_decode_ctrls(ctx); } diff --git a/drivers/media/platform/cros-ec-cec/cros-ec-cec.c b/drivers/media/platform/cros-ec-cec/cros-ec-cec.c index 7bc4d8a9af28..068df9888dbf 100644 --- a/drivers/media/platform/cros-ec-cec/cros-ec-cec.c +++ b/drivers/media/platform/cros-ec-cec/cros-ec-cec.c @@ -236,6 +236,7 @@ static int cros_ec_cec_get_notifier(struct device *dev, return -EPROBE_DEFER; *notify = cec_notifier_get_conn(d, m->conn); + put_device(d); return 0; } } diff --git a/drivers/media/platform/davinci/isif.c b/drivers/media/platform/davinci/isif.c index 47cecd10eb9f..2dee9af6d413 100644 --- a/drivers/media/platform/davinci/isif.c +++ b/drivers/media/platform/davinci/isif.c @@ -884,9 +884,7 @@ static int isif_set_hw_if_params(struct vpfe_hw_if_param *params) static int isif_config_ycbcr(void) { struct isif_ycbcr_config *params = &isif_cfg.ycbcr; - struct vpss_pg_frame_size frame_size; u32 modeset = 0, ccdcfg = 0; - struct vpss_sync_pol sync; dev_dbg(isif_cfg.dev, "\nStarting isif_config_ycbcr..."); @@ -974,13 +972,6 @@ static int isif_config_ycbcr(void) /* two fields are interleaved in memory */ regw(0x00000249, SDOFST); - /* Setup test pattern if enabled */ - if (isif_cfg.bayer.config_params.test_pat_gen) { - sync.ccdpg_hdpol = params->hd_pol; - sync.ccdpg_vdpol = params->vd_pol; - dm365_vpss_set_sync_pol(sync); - dm365_vpss_set_pg_frame_size(frame_size); - } return 0; } diff --git a/drivers/media/platform/davinci/vpfe_capture.c b/drivers/media/platform/davinci/vpfe_capture.c index 26dadbba930f..1e3a13830544 100644 --- a/drivers/media/platform/davinci/vpfe_capture.c +++ b/drivers/media/platform/davinci/vpfe_capture.c @@ -1759,7 +1759,7 @@ static int vpfe_probe(struct platform_device *pdev) mutex_lock(&ccdc_lock); - strncpy(ccdc_cfg->name, vpfe_cfg->ccdc, 32); + strscpy(ccdc_cfg->name, vpfe_cfg->ccdc, sizeof(ccdc_cfg->name)); /* Get VINT0 irq resource */ res1 = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (!res1) { diff --git a/drivers/media/platform/davinci/vpif_capture.c b/drivers/media/platform/davinci/vpif_capture.c index 6216b7ac6875..b5aacb0fb96b 100644 --- a/drivers/media/platform/davinci/vpif_capture.c +++ b/drivers/media/platform/davinci/vpif_capture.c @@ -1254,7 +1254,8 @@ static int vpif_s_dv_timings(struct file *file, void *priv, } else { std_info->l5 = std_info->vsize - (bt->vfrontporch - 1); } - strncpy(std_info->name, "Custom timings BT656/1120", VPIF_MAX_NAME); + strscpy(std_info->name, "Custom timings BT656/1120", + sizeof(std_info->name)); std_info->width = bt->width; std_info->height = bt->height; std_info->frm_fmt = bt->interlaced ? 0 : 1; diff --git a/drivers/media/platform/davinci/vpif_display.c b/drivers/media/platform/davinci/vpif_display.c index f4b4f2a1dfc0..a69897c68a50 100644 --- a/drivers/media/platform/davinci/vpif_display.c +++ b/drivers/media/platform/davinci/vpif_display.c @@ -987,8 +987,8 @@ static int vpif_s_dv_timings(struct file *file, void *priv, } else { std_info->l5 = std_info->vsize - (bt->vfrontporch - 1); } - strncpy(std_info->name, "Custom timings BT656/1120", - VPIF_MAX_NAME); + strscpy(std_info->name, "Custom timings BT656/1120", + sizeof(std_info->name)); std_info->width = bt->width; std_info->height = bt->height; std_info->frm_fmt = bt->interlaced ? 0 : 1; diff --git a/drivers/media/platform/exynos4-is/fimc-capture.c b/drivers/media/platform/exynos4-is/fimc-capture.c index 3e9fcf4f8a13..de4af0357a3c 100644 --- a/drivers/media/platform/exynos4-is/fimc-capture.c +++ b/drivers/media/platform/exynos4-is/fimc-capture.c @@ -742,7 +742,7 @@ static int fimc_cap_enum_fmt_mplane(struct file *file, void *priv, f->index); if (!fmt) return -EINVAL; - strncpy(f->description, fmt->name, sizeof(f->description) - 1); + strscpy(f->description, fmt->name, sizeof(f->description)); f->pixelformat = fmt->fourcc; if (fmt->fourcc == MEDIA_BUS_FMT_JPEG_1X8) f->flags |= V4L2_FMT_FLAG_COMPRESSED; diff --git a/drivers/media/platform/exynos4-is/fimc-m2m.c b/drivers/media/platform/exynos4-is/fimc-m2m.c index 61c8177409cf..1bea1ce4091e 100644 --- a/drivers/media/platform/exynos4-is/fimc-m2m.c +++ b/drivers/media/platform/exynos4-is/fimc-m2m.c @@ -252,7 +252,7 @@ static int fimc_m2m_enum_fmt_mplane(struct file *file, void *priv, if (!fmt) return -EINVAL; - strncpy(f->description, fmt->name, sizeof(f->description) - 1); + strscpy(f->description, fmt->name, sizeof(f->description)); f->pixelformat = fmt->fourcc; return 0; } diff --git a/drivers/media/platform/imx-pxp.c b/drivers/media/platform/imx-pxp.c index 0bcfc5aa8f3d..8e7ef23b9a7e 100644 --- a/drivers/media/platform/imx-pxp.c +++ b/drivers/media/platform/imx-pxp.c @@ -1025,8 +1025,8 @@ static irqreturn_t pxp_irq_handler(int irq, void *dev_id) static int pxp_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - strlcpy(cap->driver, MEM2MEM_NAME, sizeof(cap->driver)); - strlcpy(cap->card, MEM2MEM_NAME, sizeof(cap->card)); + 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; diff --git a/drivers/media/platform/marvell-ccic/Kconfig b/drivers/media/platform/marvell-ccic/Kconfig index cf12e077203a..cd88e2eed749 100644 --- a/drivers/media/platform/marvell-ccic/Kconfig +++ b/drivers/media/platform/marvell-ccic/Kconfig @@ -5,7 +5,7 @@ config VIDEO_CAFE_CCIC select VIDEOBUF2_VMALLOC select VIDEOBUF2_DMA_CONTIG select VIDEOBUF2_DMA_SG - ---help--- + help This is a video4linux2 driver for the Marvell 88ALP01 integrated CMOS camera controller. This is the controller found on first- generation OLPC systems. @@ -19,7 +19,7 @@ config VIDEO_MMP_CAMERA select VIDEOBUF2_VMALLOC select VIDEOBUF2_DMA_CONTIG select VIDEOBUF2_DMA_SG - ---help--- + help This is a Video4Linux2 driver for the integrated camera controller found on Marvell Armada 610 application processors (and likely beyond). This is the controller found diff --git a/drivers/media/platform/meson/Makefile b/drivers/media/platform/meson/Makefile index 597beb8f34d1..f611c23c3718 100644 --- a/drivers/media/platform/meson/Makefile +++ b/drivers/media/platform/meson/Makefile @@ -1 +1,2 @@ obj-$(CONFIG_VIDEO_MESON_AO_CEC) += ao-cec.o +obj-$(CONFIG_VIDEO_MESON_G12A_AO_CEC) += ao-cec-g12a.o diff --git a/drivers/media/platform/meson/ao-cec-g12a.c b/drivers/media/platform/meson/ao-cec-g12a.c new file mode 100644 index 000000000000..3620a1e310f5 --- /dev/null +++ b/drivers/media/platform/meson/ao-cec-g12a.c @@ -0,0 +1,779 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Driver for Amlogic Meson AO CEC G12A Controller + * + * Copyright (C) 2017 Amlogic, Inc. All rights reserved + * Copyright (C) 2019 BayLibre, SAS + * Author: Neil Armstrong <narmstrong@baylibre.com> + */ + +#include <linux/bitfield.h> +#include <linux/clk.h> +#include <linux/device.h> +#include <linux/io.h> +#include <linux/delay.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_platform.h> +#include <linux/platform_device.h> +#include <linux/types.h> +#include <linux/interrupt.h> +#include <linux/reset.h> +#include <linux/slab.h> +#include <linux/regmap.h> +#include <media/cec.h> +#include <media/cec-notifier.h> +#include <linux/clk-provider.h> + +/* CEC Registers */ + +#define CECB_CLK_CNTL_REG0 0x00 + +#define CECB_CLK_CNTL_N1 GENMASK(11, 0) +#define CECB_CLK_CNTL_N2 GENMASK(23, 12) +#define CECB_CLK_CNTL_DUAL_EN BIT(28) +#define CECB_CLK_CNTL_OUTPUT_EN BIT(30) +#define CECB_CLK_CNTL_INPUT_EN BIT(31) + +#define CECB_CLK_CNTL_REG1 0x04 + +#define CECB_CLK_CNTL_M1 GENMASK(11, 0) +#define CECB_CLK_CNTL_M2 GENMASK(23, 12) +#define CECB_CLK_CNTL_BYPASS_EN BIT(24) + +/* + * [14:12] Filter_del. For glitch-filtering CEC line, ignore signal + * change pulse width < filter_del * T(filter_tick) * 3. + * [9:8] Filter_tick_sel: Select which periodical pulse for + * glitch-filtering CEC line signal. + * - 0=Use T(xtal)*3 = 125ns; + * - 1=Use once-per-1us pulse; + * - 2=Use once-per-10us pulse; + * - 3=Use once-per-100us pulse. + * [3] Sysclk_en. 0=Disable system clock; 1=Enable system clock. + * [2:1] cntl_clk + * - 0 = Disable clk (Power-off mode) + * - 1 = Enable gated clock (Normal mode) + * - 2 = Enable free-run clk (Debug mode) + * [0] SW_RESET 1=Apply reset; 0=No reset. + */ +#define CECB_GEN_CNTL_REG 0x08 + +#define CECB_GEN_CNTL_RESET BIT(0) +#define CECB_GEN_CNTL_CLK_DISABLE 0 +#define CECB_GEN_CNTL_CLK_ENABLE 1 +#define CECB_GEN_CNTL_CLK_ENABLE_DBG 2 +#define CECB_GEN_CNTL_CLK_CTRL_MASK GENMASK(2, 1) +#define CECB_GEN_CNTL_SYS_CLK_EN BIT(3) +#define CECB_GEN_CNTL_FILTER_TICK_125NS 0 +#define CECB_GEN_CNTL_FILTER_TICK_1US 1 +#define CECB_GEN_CNTL_FILTER_TICK_10US 2 +#define CECB_GEN_CNTL_FILTER_TICK_100US 3 +#define CECB_GEN_CNTL_FILTER_TICK_SEL GENMASK(9, 8) +#define CECB_GEN_CNTL_FILTER_DEL GENMASK(14, 12) + +/* + * [7:0] cec_reg_addr + * [15:8] cec_reg_wrdata + * [16] cec_reg_wr + * - 0 = Read + * - 1 = Write + * [31:24] cec_reg_rddata + */ +#define CECB_RW_REG 0x0c + +#define CECB_RW_ADDR GENMASK(7, 0) +#define CECB_RW_WR_DATA GENMASK(15, 8) +#define CECB_RW_WRITE_EN BIT(16) +#define CECB_RW_BUS_BUSY BIT(23) +#define CECB_RW_RD_DATA GENMASK(31, 24) + +/* + * [0] DONE Interrupt + * [1] End Of Message Interrupt + * [2] Not Acknowlegde Interrupt + * [3] Arbitration Loss Interrupt + * [4] Initiator Error Interrupt + * [5] Follower Error Interrupt + * [6] Wake-Up Interrupt + */ +#define CECB_INTR_MASKN_REG 0x10 +#define CECB_INTR_CLR_REG 0x14 +#define CECB_INTR_STAT_REG 0x18 + +#define CECB_INTR_DONE BIT(0) +#define CECB_INTR_EOM BIT(1) +#define CECB_INTR_NACK BIT(2) +#define CECB_INTR_ARB_LOSS BIT(3) +#define CECB_INTR_INITIATOR_ERR BIT(4) +#define CECB_INTR_FOLLOWER_ERR BIT(5) +#define CECB_INTR_WAKE_UP BIT(6) + +/* CEC Commands */ + +#define CECB_CTRL 0x00 + +#define CECB_CTRL_SEND BIT(0) +#define CECB_CTRL_TYPE GENMASK(2, 1) +#define CECB_CTRL_TYPE_RETRY 0 +#define CECB_CTRL_TYPE_NEW 1 +#define CECB_CTRL_TYPE_NEXT 2 + +#define CECB_CTRL2 0x01 +#define CECB_INTR_MASK 0x02 +#define CECB_LADD_LOW 0x05 +#define CECB_LADD_HIGH 0x06 +#define CECB_TX_CNT 0x07 +#define CECB_RX_CNT 0x08 +#define CECB_STAT0 0x09 +#define CECB_TX_DATA00 0x10 +#define CECB_TX_DATA01 0x11 +#define CECB_TX_DATA02 0x12 +#define CECB_TX_DATA03 0x13 +#define CECB_TX_DATA04 0x14 +#define CECB_TX_DATA05 0x15 +#define CECB_TX_DATA06 0x16 +#define CECB_TX_DATA07 0x17 +#define CECB_TX_DATA08 0x18 +#define CECB_TX_DATA09 0x19 +#define CECB_TX_DATA10 0x1A +#define CECB_TX_DATA11 0x1B +#define CECB_TX_DATA12 0x1C +#define CECB_TX_DATA13 0x1D +#define CECB_TX_DATA14 0x1E +#define CECB_TX_DATA15 0x1F +#define CECB_RX_DATA00 0x20 +#define CECB_RX_DATA01 0x21 +#define CECB_RX_DATA02 0x22 +#define CECB_RX_DATA03 0x23 +#define CECB_RX_DATA04 0x24 +#define CECB_RX_DATA05 0x25 +#define CECB_RX_DATA06 0x26 +#define CECB_RX_DATA07 0x27 +#define CECB_RX_DATA08 0x28 +#define CECB_RX_DATA09 0x29 +#define CECB_RX_DATA10 0x2A +#define CECB_RX_DATA11 0x2B +#define CECB_RX_DATA12 0x2C +#define CECB_RX_DATA13 0x2D +#define CECB_RX_DATA14 0x2E +#define CECB_RX_DATA15 0x2F +#define CECB_LOCK_BUF 0x30 + +#define CECB_LOCK_BUF_EN BIT(0) + +#define CECB_WAKEUPCTRL 0x31 + +struct meson_ao_cec_g12a_device { + struct platform_device *pdev; + struct regmap *regmap; + struct regmap *regmap_cec; + spinlock_t cec_reg_lock; + struct cec_notifier *notify; + struct cec_adapter *adap; + struct cec_msg rx_msg; + struct clk *oscin; + struct clk *core; +}; + +static const struct regmap_config meson_ao_cec_g12a_regmap_conf = { + .reg_bits = 8, + .val_bits = 32, + .reg_stride = 4, + .max_register = CECB_INTR_STAT_REG, +}; + +/* + * The AO-CECB embeds a dual/divider to generate a more precise + * 32,768KHz clock for CEC core clock. + * ______ ______ + * | | | | + * ______ | Div1 |-| Cnt1 | ______ + * | | /|______| |______|\ | | + * Xtal-->| Gate |---| ______ ______ X-X--| Gate |--> + * |______| | \| | | |/ | |______| + * | | Div2 |-| Cnt2 | | + * | |______| |______| | + * |_______________________| + * + * The dividing can be switched to single or dual, with a counter + * for each divider to set when the switching is done. + * The entire dividing mechanism can be also bypassed. + */ + +struct meson_ao_cec_g12a_dualdiv_clk { + struct clk_hw hw; + struct regmap *regmap; +}; + +#define hw_to_meson_ao_cec_g12a_dualdiv_clk(_hw) \ + container_of(_hw, struct meson_ao_cec_g12a_dualdiv_clk, hw) \ + +static unsigned long +meson_ao_cec_g12a_dualdiv_clk_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct meson_ao_cec_g12a_dualdiv_clk *dualdiv_clk = + hw_to_meson_ao_cec_g12a_dualdiv_clk(hw); + unsigned long n1; + u32 reg0, reg1; + + regmap_read(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0, ®0); + regmap_read(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0, ®1); + + if (reg1 & CECB_CLK_CNTL_BYPASS_EN) + return parent_rate; + + if (reg0 & CECB_CLK_CNTL_DUAL_EN) { + unsigned long n2, m1, m2, f1, f2, p1, p2; + + n1 = FIELD_GET(CECB_CLK_CNTL_N1, reg0) + 1; + n2 = FIELD_GET(CECB_CLK_CNTL_N2, reg0) + 1; + + m1 = FIELD_GET(CECB_CLK_CNTL_M1, reg1) + 1; + m2 = FIELD_GET(CECB_CLK_CNTL_M1, reg1) + 1; + + f1 = DIV_ROUND_CLOSEST(parent_rate, n1); + f2 = DIV_ROUND_CLOSEST(parent_rate, n2); + + p1 = DIV_ROUND_CLOSEST(100000000 * m1, f1 * (m1 + m2)); + p2 = DIV_ROUND_CLOSEST(100000000 * m2, f2 * (m1 + m2)); + + return DIV_ROUND_UP(100000000, p1 + p2); + } + + n1 = FIELD_GET(CECB_CLK_CNTL_N1, reg0) + 1; + + return DIV_ROUND_CLOSEST(parent_rate, n1); +} + +static int meson_ao_cec_g12a_dualdiv_clk_enable(struct clk_hw *hw) +{ + struct meson_ao_cec_g12a_dualdiv_clk *dualdiv_clk = + hw_to_meson_ao_cec_g12a_dualdiv_clk(hw); + + + /* Disable Input & Output */ + regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0, + CECB_CLK_CNTL_INPUT_EN | CECB_CLK_CNTL_OUTPUT_EN, + 0); + + /* Set N1 & N2 */ + regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0, + CECB_CLK_CNTL_N1, + FIELD_PREP(CECB_CLK_CNTL_N1, 733 - 1)); + + regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0, + CECB_CLK_CNTL_N2, + FIELD_PREP(CECB_CLK_CNTL_N2, 732 - 1)); + + /* Set M1 & M2 */ + regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG1, + CECB_CLK_CNTL_M1, + FIELD_PREP(CECB_CLK_CNTL_M1, 8 - 1)); + + regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG1, + CECB_CLK_CNTL_M2, + FIELD_PREP(CECB_CLK_CNTL_M2, 11 - 1)); + + /* Enable Dual divisor */ + regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0, + CECB_CLK_CNTL_DUAL_EN, CECB_CLK_CNTL_DUAL_EN); + + /* Disable divisor bypass */ + regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG1, + CECB_CLK_CNTL_BYPASS_EN, 0); + + /* Enable Input & Output */ + regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0, + CECB_CLK_CNTL_INPUT_EN | CECB_CLK_CNTL_OUTPUT_EN, + CECB_CLK_CNTL_INPUT_EN | CECB_CLK_CNTL_OUTPUT_EN); + + return 0; +} + +static void meson_ao_cec_g12a_dualdiv_clk_disable(struct clk_hw *hw) +{ + struct meson_ao_cec_g12a_dualdiv_clk *dualdiv_clk = + hw_to_meson_ao_cec_g12a_dualdiv_clk(hw); + + regmap_update_bits(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0, + CECB_CLK_CNTL_INPUT_EN | CECB_CLK_CNTL_OUTPUT_EN, + 0); +} + +static int meson_ao_cec_g12a_dualdiv_clk_is_enabled(struct clk_hw *hw) +{ + struct meson_ao_cec_g12a_dualdiv_clk *dualdiv_clk = + hw_to_meson_ao_cec_g12a_dualdiv_clk(hw); + int val; + + regmap_read(dualdiv_clk->regmap, CECB_CLK_CNTL_REG0, &val); + + return !!(val & (CECB_CLK_CNTL_INPUT_EN | CECB_CLK_CNTL_OUTPUT_EN)); +} + +static const struct clk_ops meson_ao_cec_g12a_dualdiv_clk_ops = { + .recalc_rate = meson_ao_cec_g12a_dualdiv_clk_recalc_rate, + .is_enabled = meson_ao_cec_g12a_dualdiv_clk_is_enabled, + .enable = meson_ao_cec_g12a_dualdiv_clk_enable, + .disable = meson_ao_cec_g12a_dualdiv_clk_disable, +}; + +static int meson_ao_cec_g12a_setup_clk(struct meson_ao_cec_g12a_device *ao_cec) +{ + struct meson_ao_cec_g12a_dualdiv_clk *dualdiv_clk; + struct device *dev = &ao_cec->pdev->dev; + struct clk_init_data init; + const char *parent_name; + struct clk *clk; + char *name; + + dualdiv_clk = devm_kzalloc(dev, sizeof(*dualdiv_clk), GFP_KERNEL); + if (!dualdiv_clk) + return -ENOMEM; + + name = kasprintf(GFP_KERNEL, "%s#dualdiv_clk", dev_name(dev)); + if (!name) + return -ENOMEM; + + parent_name = __clk_get_name(ao_cec->oscin); + + init.name = name; + init.ops = &meson_ao_cec_g12a_dualdiv_clk_ops; + init.flags = 0; + init.parent_names = &parent_name; + init.num_parents = 1; + dualdiv_clk->regmap = ao_cec->regmap; + dualdiv_clk->hw.init = &init; + + clk = devm_clk_register(dev, &dualdiv_clk->hw); + kfree(name); + if (IS_ERR(clk)) { + dev_err(dev, "failed to register clock\n"); + return PTR_ERR(clk); + } + + ao_cec->core = clk; + + return 0; +} + +static int meson_ao_cec_g12a_read(void *context, unsigned int addr, + unsigned int *data) +{ + struct meson_ao_cec_g12a_device *ao_cec = context; + u32 reg = FIELD_PREP(CECB_RW_ADDR, addr); + unsigned long flags; + int ret = 0; + + spin_lock_irqsave(&ao_cec->cec_reg_lock, flags); + + ret = regmap_write(ao_cec->regmap, CECB_RW_REG, reg); + if (ret) + goto read_out; + + ret = regmap_read_poll_timeout(ao_cec->regmap, CECB_RW_REG, reg, + !(reg & CECB_RW_BUS_BUSY), + 5, 1000); + if (ret) + goto read_out; + + ret = regmap_read(ao_cec->regmap, CECB_RW_REG, ®); + + *data = FIELD_GET(CECB_RW_RD_DATA, reg); + +read_out: + spin_unlock_irqrestore(&ao_cec->cec_reg_lock, flags); + + return ret; +} + +static int meson_ao_cec_g12a_write(void *context, unsigned int addr, + unsigned int data) +{ + struct meson_ao_cec_g12a_device *ao_cec = context; + unsigned long flags; + u32 reg = FIELD_PREP(CECB_RW_ADDR, addr) | + FIELD_PREP(CECB_RW_WR_DATA, data) | + CECB_RW_WRITE_EN; + int ret = 0; + + spin_lock_irqsave(&ao_cec->cec_reg_lock, flags); + + ret = regmap_write(ao_cec->regmap, CECB_RW_REG, reg); + + spin_unlock_irqrestore(&ao_cec->cec_reg_lock, flags); + + return ret; +} + +static const struct regmap_config meson_ao_cec_g12a_cec_regmap_conf = { + .reg_bits = 8, + .val_bits = 8, + .reg_read = meson_ao_cec_g12a_read, + .reg_write = meson_ao_cec_g12a_write, + .max_register = 0xffff, + .fast_io = true, +}; + +static inline void +meson_ao_cec_g12a_irq_setup(struct meson_ao_cec_g12a_device *ao_cec, + bool enable) +{ + u32 cfg = CECB_INTR_DONE | CECB_INTR_EOM | CECB_INTR_NACK | + CECB_INTR_ARB_LOSS | CECB_INTR_INITIATOR_ERR | + CECB_INTR_FOLLOWER_ERR; + + regmap_write(ao_cec->regmap, CECB_INTR_MASKN_REG, + enable ? cfg : 0); +} + +static void meson_ao_cec_g12a_irq_rx(struct meson_ao_cec_g12a_device *ao_cec) +{ + int i, ret = 0; + u32 val; + + ret = regmap_read(ao_cec->regmap_cec, CECB_RX_CNT, &val); + + ao_cec->rx_msg.len = val; + if (ao_cec->rx_msg.len > CEC_MAX_MSG_SIZE) + ao_cec->rx_msg.len = CEC_MAX_MSG_SIZE; + + for (i = 0; i < ao_cec->rx_msg.len; i++) { + ret |= regmap_read(ao_cec->regmap_cec, + CECB_RX_DATA00 + i, &val); + + ao_cec->rx_msg.msg[i] = val & 0xff; + } + + ret |= regmap_write(ao_cec->regmap_cec, CECB_LOCK_BUF, 0); + if (ret) + return; + + cec_received_msg(ao_cec->adap, &ao_cec->rx_msg); +} + +static irqreturn_t meson_ao_cec_g12a_irq(int irq, void *data) +{ + struct meson_ao_cec_g12a_device *ao_cec = data; + u32 stat; + + regmap_read(ao_cec->regmap, CECB_INTR_STAT_REG, &stat); + if (stat) + return IRQ_WAKE_THREAD; + + return IRQ_NONE; +} + +static irqreturn_t meson_ao_cec_g12a_irq_thread(int irq, void *data) +{ + struct meson_ao_cec_g12a_device *ao_cec = data; + u32 stat; + + regmap_read(ao_cec->regmap, CECB_INTR_STAT_REG, &stat); + regmap_write(ao_cec->regmap, CECB_INTR_CLR_REG, stat); + + if (stat & CECB_INTR_DONE) + cec_transmit_attempt_done(ao_cec->adap, CEC_TX_STATUS_OK); + + if (stat & CECB_INTR_EOM) + meson_ao_cec_g12a_irq_rx(ao_cec); + + if (stat & CECB_INTR_NACK) + cec_transmit_attempt_done(ao_cec->adap, CEC_TX_STATUS_NACK); + + if (stat & CECB_INTR_ARB_LOSS) { + regmap_write(ao_cec->regmap_cec, CECB_TX_CNT, 0); + regmap_update_bits(ao_cec->regmap_cec, CECB_CTRL, + CECB_CTRL_SEND | CECB_CTRL_TYPE, 0); + cec_transmit_attempt_done(ao_cec->adap, CEC_TX_STATUS_ARB_LOST); + } + + /* Initiator reports an error on the CEC bus */ + if (stat & CECB_INTR_INITIATOR_ERR) + cec_transmit_attempt_done(ao_cec->adap, CEC_TX_STATUS_ERROR); + + /* Follower reports a receive error, just reset RX buffer */ + if (stat & CECB_INTR_FOLLOWER_ERR) + regmap_write(ao_cec->regmap_cec, CECB_LOCK_BUF, 0); + + return IRQ_HANDLED; +} + +static int +meson_ao_cec_g12a_set_log_addr(struct cec_adapter *adap, u8 logical_addr) +{ + struct meson_ao_cec_g12a_device *ao_cec = adap->priv; + int ret = 0; + + if (logical_addr == CEC_LOG_ADDR_INVALID) { + /* Assume this will allways succeed */ + regmap_write(ao_cec->regmap_cec, CECB_LADD_LOW, 0); + regmap_write(ao_cec->regmap_cec, CECB_LADD_HIGH, 0); + + return 0; + } else if (logical_addr < 8) { + ret = regmap_update_bits(ao_cec->regmap_cec, CECB_LADD_LOW, + BIT(logical_addr), + BIT(logical_addr)); + } else { + ret = regmap_update_bits(ao_cec->regmap_cec, CECB_LADD_HIGH, + BIT(logical_addr - 8), + BIT(logical_addr - 8)); + } + + /* Always set Broadcast/Unregistered 15 address */ + ret |= regmap_update_bits(ao_cec->regmap_cec, CECB_LADD_HIGH, + BIT(CEC_LOG_ADDR_UNREGISTERED - 8), + BIT(CEC_LOG_ADDR_UNREGISTERED - 8)); + + return ret ? -EIO : 0; +} + +static int meson_ao_cec_g12a_transmit(struct cec_adapter *adap, u8 attempts, + u32 signal_free_time, struct cec_msg *msg) +{ + struct meson_ao_cec_g12a_device *ao_cec = adap->priv; + unsigned int type; + int ret = 0; + u32 val; + int i; + + /* Check if RX is in progress */ + ret = regmap_read(ao_cec->regmap_cec, CECB_LOCK_BUF, &val); + if (ret) + return ret; + if (val & CECB_LOCK_BUF_EN) + return -EBUSY; + + /* Check if TX Busy */ + ret = regmap_read(ao_cec->regmap_cec, CECB_CTRL, &val); + if (ret) + return ret; + if (val & CECB_CTRL_SEND) + return -EBUSY; + + switch (signal_free_time) { + case CEC_SIGNAL_FREE_TIME_RETRY: + type = CECB_CTRL_TYPE_RETRY; + break; + case CEC_SIGNAL_FREE_TIME_NEXT_XFER: + type = CECB_CTRL_TYPE_NEXT; + break; + case CEC_SIGNAL_FREE_TIME_NEW_INITIATOR: + default: + type = CECB_CTRL_TYPE_NEW; + break; + } + + for (i = 0; i < msg->len; i++) + ret |= regmap_write(ao_cec->regmap_cec, CECB_TX_DATA00 + i, + msg->msg[i]); + + ret |= regmap_write(ao_cec->regmap_cec, CECB_TX_CNT, msg->len); + if (ret) + return -EIO; + + ret = regmap_update_bits(ao_cec->regmap_cec, CECB_CTRL, + CECB_CTRL_SEND | + CECB_CTRL_TYPE, + CECB_CTRL_SEND | + FIELD_PREP(CECB_CTRL_TYPE, type)); + + return ret; +} + +static int meson_ao_cec_g12a_adap_enable(struct cec_adapter *adap, bool enable) +{ + struct meson_ao_cec_g12a_device *ao_cec = adap->priv; + + meson_ao_cec_g12a_irq_setup(ao_cec, false); + + regmap_update_bits(ao_cec->regmap, CECB_GEN_CNTL_REG, + CECB_GEN_CNTL_RESET, CECB_GEN_CNTL_RESET); + + if (!enable) + return 0; + + /* Setup Filter */ + regmap_update_bits(ao_cec->regmap, CECB_GEN_CNTL_REG, + CECB_GEN_CNTL_FILTER_TICK_SEL | + CECB_GEN_CNTL_FILTER_DEL, + FIELD_PREP(CECB_GEN_CNTL_FILTER_TICK_SEL, + CECB_GEN_CNTL_FILTER_TICK_1US) | + FIELD_PREP(CECB_GEN_CNTL_FILTER_DEL, 7)); + + /* Enable System Clock */ + regmap_update_bits(ao_cec->regmap, CECB_GEN_CNTL_REG, + CECB_GEN_CNTL_SYS_CLK_EN, + CECB_GEN_CNTL_SYS_CLK_EN); + + /* Enable gated clock (Normal mode). */ + regmap_update_bits(ao_cec->regmap, CECB_GEN_CNTL_REG, + CECB_GEN_CNTL_CLK_CTRL_MASK, + FIELD_PREP(CECB_GEN_CNTL_CLK_CTRL_MASK, + CECB_GEN_CNTL_CLK_ENABLE)); + + /* Release Reset */ + regmap_update_bits(ao_cec->regmap, CECB_GEN_CNTL_REG, + CECB_GEN_CNTL_RESET, 0); + + meson_ao_cec_g12a_irq_setup(ao_cec, true); + + return 0; +} + +static const struct cec_adap_ops meson_ao_cec_g12a_ops = { + .adap_enable = meson_ao_cec_g12a_adap_enable, + .adap_log_addr = meson_ao_cec_g12a_set_log_addr, + .adap_transmit = meson_ao_cec_g12a_transmit, +}; + +static int meson_ao_cec_g12a_probe(struct platform_device *pdev) +{ + struct meson_ao_cec_g12a_device *ao_cec; + struct device *hdmi_dev; + struct resource *res; + void __iomem *base; + int ret, irq; + + hdmi_dev = cec_notifier_parse_hdmi_phandle(&pdev->dev); + if (IS_ERR(hdmi_dev)) + return PTR_ERR(hdmi_dev); + + ao_cec = devm_kzalloc(&pdev->dev, sizeof(*ao_cec), GFP_KERNEL); + if (!ao_cec) + return -ENOMEM; + + spin_lock_init(&ao_cec->cec_reg_lock); + ao_cec->pdev = pdev; + + ao_cec->notify = cec_notifier_get(hdmi_dev); + if (!ao_cec->notify) + return -ENOMEM; + + ao_cec->adap = cec_allocate_adapter(&meson_ao_cec_g12a_ops, ao_cec, + "meson_g12a_ao_cec", + CEC_CAP_DEFAULTS, + CEC_MAX_LOG_ADDRS); + if (IS_ERR(ao_cec->adap)) { + ret = PTR_ERR(ao_cec->adap); + goto out_probe_notify; + } + + ao_cec->adap->owner = THIS_MODULE; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(base)) { + ret = PTR_ERR(base); + goto out_probe_adapter; + } + + ao_cec->regmap = devm_regmap_init_mmio(&pdev->dev, base, + &meson_ao_cec_g12a_regmap_conf); + if (IS_ERR(ao_cec->regmap)) { + ret = PTR_ERR(ao_cec->regmap); + goto out_probe_adapter; + } + + ao_cec->regmap_cec = devm_regmap_init(&pdev->dev, NULL, ao_cec, + &meson_ao_cec_g12a_cec_regmap_conf); + if (IS_ERR(ao_cec->regmap_cec)) { + ret = PTR_ERR(ao_cec->regmap_cec); + goto out_probe_adapter; + } + + irq = platform_get_irq(pdev, 0); + ret = devm_request_threaded_irq(&pdev->dev, irq, + meson_ao_cec_g12a_irq, + meson_ao_cec_g12a_irq_thread, + 0, NULL, ao_cec); + if (ret) { + dev_err(&pdev->dev, "irq request failed\n"); + goto out_probe_adapter; + } + + ao_cec->oscin = devm_clk_get(&pdev->dev, "oscin"); + if (IS_ERR(ao_cec->oscin)) { + dev_err(&pdev->dev, "oscin clock request failed\n"); + ret = PTR_ERR(ao_cec->oscin); + goto out_probe_adapter; + } + + ret = meson_ao_cec_g12a_setup_clk(ao_cec); + if (ret) + goto out_probe_adapter; + + ret = clk_prepare_enable(ao_cec->core); + if (ret) { + dev_err(&pdev->dev, "core clock enable failed\n"); + goto out_probe_adapter; + } + + device_reset_optional(&pdev->dev); + + platform_set_drvdata(pdev, ao_cec); + + ret = cec_register_adapter(ao_cec->adap, &pdev->dev); + if (ret < 0) { + cec_notifier_put(ao_cec->notify); + goto out_probe_core_clk; + } + + /* Setup Hardware */ + regmap_write(ao_cec->regmap, CECB_GEN_CNTL_REG, CECB_GEN_CNTL_RESET); + + cec_register_cec_notifier(ao_cec->adap, ao_cec->notify); + + return 0; + +out_probe_core_clk: + clk_disable_unprepare(ao_cec->core); + +out_probe_adapter: + cec_delete_adapter(ao_cec->adap); + +out_probe_notify: + cec_notifier_put(ao_cec->notify); + + dev_err(&pdev->dev, "CEC controller registration failed\n"); + + return ret; +} + +static int meson_ao_cec_g12a_remove(struct platform_device *pdev) +{ + struct meson_ao_cec_g12a_device *ao_cec = platform_get_drvdata(pdev); + + clk_disable_unprepare(ao_cec->core); + + cec_unregister_adapter(ao_cec->adap); + + cec_notifier_put(ao_cec->notify); + + return 0; +} + +static const struct of_device_id meson_ao_cec_g12a_of_match[] = { + { .compatible = "amlogic,meson-g12a-ao-cec", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, meson_ao_cec_g12a_of_match); + +static struct platform_driver meson_ao_cec_g12a_driver = { + .probe = meson_ao_cec_g12a_probe, + .remove = meson_ao_cec_g12a_remove, + .driver = { + .name = "meson-ao-cec-g12a", + .of_match_table = of_match_ptr(meson_ao_cec_g12a_of_match), + }, +}; + +module_platform_driver(meson_ao_cec_g12a_driver); + +MODULE_DESCRIPTION("Meson AO CEC G12A Controller driver"); +MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/platform/meson/ao-cec.c b/drivers/media/platform/meson/ao-cec.c index cd4be38ab5ac..facf9b029e79 100644 --- a/drivers/media/platform/meson/ao-cec.c +++ b/drivers/media/platform/meson/ao-cec.c @@ -601,20 +601,14 @@ static const struct cec_adap_ops meson_ao_cec_ops = { static int meson_ao_cec_probe(struct platform_device *pdev) { struct meson_ao_cec_device *ao_cec; - struct platform_device *hdmi_dev; - struct device_node *np; + struct device *hdmi_dev; struct resource *res; int ret, irq; - np = of_parse_phandle(pdev->dev.of_node, "hdmi-phandle", 0); - if (!np) { - dev_err(&pdev->dev, "Failed to find hdmi node\n"); - return -ENODEV; - } + hdmi_dev = cec_notifier_parse_hdmi_phandle(&pdev->dev); - hdmi_dev = of_find_device_by_node(np); - if (hdmi_dev == NULL) - return -EPROBE_DEFER; + if (IS_ERR(hdmi_dev)) + return PTR_ERR(hdmi_dev); ao_cec = devm_kzalloc(&pdev->dev, sizeof(*ao_cec), GFP_KERNEL); if (!ao_cec) @@ -622,7 +616,7 @@ static int meson_ao_cec_probe(struct platform_device *pdev) spin_lock_init(&ao_cec->cec_reg_lock); - ao_cec->notify = cec_notifier_get(&hdmi_dev->dev); + ao_cec->notify = cec_notifier_get(hdmi_dev); if (!ao_cec->notify) return -ENOMEM; diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c index d022c65bb34c..851903867bc9 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c @@ -129,11 +129,9 @@ static struct vb2_buffer *get_display_buffer(struct mtk_vcodec_ctx *ctx) mutex_lock(&ctx->lock); if (dstbuf->used) { vb2_set_plane_payload(&dstbuf->vb.vb2_buf, 0, - ctx->picinfo.y_bs_sz); + ctx->picinfo.fb_sz[0]); vb2_set_plane_payload(&dstbuf->vb.vb2_buf, 1, - ctx->picinfo.c_bs_sz); - - dstbuf->ready_to_display = true; + ctx->picinfo.fb_sz[1]); mtk_v4l2_debug(2, "[%d]status=%x queue id=%d to done_list %d", @@ -278,6 +276,27 @@ static void mtk_vdec_flush_decoder(struct mtk_vcodec_ctx *ctx) clean_free_buffer(ctx); } +static void mtk_vdec_update_fmt(struct mtk_vcodec_ctx *ctx, + unsigned int pixelformat) +{ + struct mtk_video_fmt *fmt; + struct mtk_q_data *dst_q_data; + unsigned int k; + + dst_q_data = &ctx->q_data[MTK_Q_DATA_DST]; + for (k = 0; k < NUM_FORMATS; k++) { + fmt = &mtk_video_formats[k]; + if (fmt->fourcc == pixelformat) { + mtk_v4l2_debug(1, "Update cap fourcc(%d -> %d)", + dst_q_data->fmt.fourcc, pixelformat); + dst_q_data->fmt = fmt; + return; + } + } + + mtk_v4l2_err("Cannot get fourcc(%d), using init value", pixelformat); +} + static int mtk_vdec_pic_info_update(struct mtk_vcodec_ctx *ctx) { unsigned int dpbsize = 0; @@ -299,6 +318,10 @@ static int mtk_vdec_pic_info_update(struct mtk_vcodec_ctx *ctx) return -EINVAL; } + if (ctx->last_decoded_picinfo.cap_fourcc != ctx->picinfo.cap_fourcc && + ctx->picinfo.cap_fourcc != 0) + mtk_vdec_update_fmt(ctx, ctx->picinfo.cap_fourcc); + if ((ctx->last_decoded_picinfo.pic_w == ctx->picinfo.pic_w) || (ctx->last_decoded_picinfo.pic_h == ctx->picinfo.pic_h)) return 0; @@ -352,11 +375,11 @@ static void mtk_vdec_worker(struct work_struct *work) pfb = &dst_buf_info->frame_buffer; pfb->base_y.va = vb2_plane_vaddr(&dst_buf->vb2_buf, 0); pfb->base_y.dma_addr = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0); - pfb->base_y.size = ctx->picinfo.y_bs_sz + ctx->picinfo.y_len_sz; + pfb->base_y.size = ctx->picinfo.fb_sz[0]; pfb->base_c.va = vb2_plane_vaddr(&dst_buf->vb2_buf, 1); pfb->base_c.dma_addr = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 1); - pfb->base_c.size = ctx->picinfo.c_bs_sz + ctx->picinfo.c_len_sz; + pfb->base_c.size = ctx->picinfo.fb_sz[1]; pfb->status = 0; mtk_v4l2_debug(3, "===>[%d] vdec_if_decode() ===>", ctx->id); @@ -388,7 +411,7 @@ static void mtk_vdec_worker(struct work_struct *work) } buf.va = vb2_plane_vaddr(&src_buf->vb2_buf, 0); buf.dma_addr = vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0); - buf.size = (size_t)src_buf->planes[0].bytesused; + buf.size = (size_t)src_buf->vb2_buf.planes[0].bytesused; if (!buf.va) { v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx); mtk_v4l2_err("[%d] id=%d src_addr is NULL!!", @@ -976,14 +999,13 @@ static int vidioc_vdec_g_fmt(struct file *file, void *priv, * So we just return picinfo yet, and update picinfo in * stop_streaming hook function */ - q_data->sizeimage[0] = ctx->picinfo.y_bs_sz + - ctx->picinfo.y_len_sz; - q_data->sizeimage[1] = ctx->picinfo.c_bs_sz + - ctx->picinfo.c_len_sz; + q_data->sizeimage[0] = ctx->picinfo.fb_sz[0]; + q_data->sizeimage[1] = ctx->picinfo.fb_sz[1]; q_data->bytesperline[0] = ctx->last_decoded_picinfo.buf_w; q_data->bytesperline[1] = ctx->last_decoded_picinfo.buf_w; q_data->coded_width = ctx->picinfo.buf_w; q_data->coded_height = ctx->picinfo.buf_h; + ctx->last_decoded_picinfo.cap_fourcc = q_data->fmt->fourcc; /* * Width and height are set to the dimensions @@ -1103,10 +1125,11 @@ static void vb2ops_vdec_buf_queue(struct vb2_buffer *vb) struct mtk_vcodec_mem src_mem; bool res_chg = false; int ret = 0; - unsigned int dpbsize = 1; + unsigned int dpbsize = 1, i = 0; struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); struct vb2_v4l2_buffer *vb2_v4l2 = NULL; struct mtk_video_dec_buf *buf = NULL; + struct mtk_q_data *dst_q_data; mtk_v4l2_debug(3, "[%d] (%d) id=%d, vb=%p", ctx->id, vb->vb2_queue->type, @@ -1122,11 +1145,9 @@ static void vb2ops_vdec_buf_queue(struct vb2_buffer *vb) v4l2_m2m_buf_queue(ctx->m2m_ctx, vb2_v4l2); buf->queued_in_vb2 = true; buf->queued_in_v4l2 = true; - buf->ready_to_display = false; } else { buf->queued_in_vb2 = false; buf->queued_in_v4l2 = true; - buf->ready_to_display = false; } mutex_unlock(&ctx->lock); return; @@ -1155,10 +1176,10 @@ static void vb2ops_vdec_buf_queue(struct vb2_buffer *vb) src_mem.va = vb2_plane_vaddr(&src_buf->vb2_buf, 0); src_mem.dma_addr = vb2_dma_contig_plane_dma_addr(&src_buf->vb2_buf, 0); - src_mem.size = (size_t)src_buf->planes[0].bytesused; + src_mem.size = (size_t)src_buf->vb2_buf.planes[0].bytesused; mtk_v4l2_debug(2, "[%d] buf id=%d va=%p dma=%pad size=%zx", - ctx->id, src_buf->index, + ctx->id, src_buf->vb2_buf.index, src_mem.va, &src_mem.dma_addr, src_mem.size); @@ -1182,7 +1203,7 @@ static void vb2ops_vdec_buf_queue(struct vb2_buffer *vb) } mtk_v4l2_debug(ret ? 0 : 1, "[%d] vdec_if_decode() src_buf=%d, size=%zu, fail=%d, res_chg=%d", - ctx->id, src_buf->index, + ctx->id, src_buf->vb2_buf.index, src_mem.size, ret, res_chg); return; } @@ -1194,21 +1215,18 @@ static void vb2ops_vdec_buf_queue(struct vb2_buffer *vb) } ctx->last_decoded_picinfo = ctx->picinfo; - ctx->q_data[MTK_Q_DATA_DST].sizeimage[0] = - ctx->picinfo.y_bs_sz + - ctx->picinfo.y_len_sz; - ctx->q_data[MTK_Q_DATA_DST].bytesperline[0] = - ctx->picinfo.buf_w; - ctx->q_data[MTK_Q_DATA_DST].sizeimage[1] = - ctx->picinfo.c_bs_sz + - ctx->picinfo.c_len_sz; - ctx->q_data[MTK_Q_DATA_DST].bytesperline[1] = ctx->picinfo.buf_w; + dst_q_data = &ctx->q_data[MTK_Q_DATA_DST]; + for (i = 0; i < dst_q_data->fmt->num_planes; i++) { + dst_q_data->sizeimage[i] = ctx->picinfo.fb_sz[i]; + dst_q_data->bytesperline[i] = ctx->picinfo.buf_w; + } + mtk_v4l2_debug(2, "[%d] vdec_if_init() OK wxh=%dx%d pic wxh=%dx%d sz[0]=0x%x sz[1]=0x%x", ctx->id, ctx->picinfo.buf_w, ctx->picinfo.buf_h, ctx->picinfo.pic_w, ctx->picinfo.pic_h, - ctx->q_data[MTK_Q_DATA_DST].sizeimage[0], - ctx->q_data[MTK_Q_DATA_DST].sizeimage[1]); + dst_q_data->sizeimage[0], + dst_q_data->sizeimage[1]); ret = vdec_if_get_param(ctx, GET_PARAM_DPB_SIZE, &dpbsize); if (dpbsize == 0) @@ -1253,7 +1271,6 @@ static int vb2ops_vdec_buf_init(struct vb2_buffer *vb) if (vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { buf->used = false; - buf->ready_to_display = false; buf->queued_in_v4l2 = false; } else { buf->lastframe = false; diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h index dc4fc1df63c5..e4984edec4f8 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h @@ -45,7 +45,6 @@ struct vdec_fb { * @list: link list * @used: Capture buffer contain decoded frame data and keep in * codec data structure - * @ready_to_display: Capture buffer not display yet * @queued_in_vb2: Capture buffer is queue in vb2 * @queued_in_v4l2: Capture buffer is in v4l2 driver, but not in vb2 * queue yet @@ -60,7 +59,6 @@ struct mtk_video_dec_buf { struct list_head list; bool used; - bool ready_to_display; bool queued_in_vb2; bool queued_in_v4l2; bool lastframe; diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h index e7e2a108def9..662a84b822af 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h @@ -211,24 +211,20 @@ struct mtk_vcodec_pm { * @pic_h: picture height * @buf_w: picture buffer width (64 aligned up from pic_w) * @buf_h: picture buffer heiht (64 aligned up from pic_h) - * @y_bs_sz: Y bitstream size - * @c_bs_sz: CbCr bitstream size - * @y_len_sz: additional size required to store decompress information for y - * plane - * @c_len_sz: additional size required to store decompress information for cbcr - * plane + * @fb_sz: bitstream size of each plane * E.g. suppose picture size is 176x144, * buffer size will be aligned to 176x160. + * @cap_fourcc: fourcc number(may changed when resolution change) + * @reserved: align struct to 64-bit in order to adjust 32-bit and 64-bit os. */ struct vdec_pic_info { unsigned int pic_w; unsigned int pic_h; unsigned int buf_w; unsigned int buf_h; - unsigned int y_bs_sz; - unsigned int c_bs_sz; - unsigned int y_len_sz; - unsigned int c_len_sz; + unsigned int fb_sz[VIDEO_MAX_PLANES]; + unsigned int cap_fourcc; + unsigned int reserved; }; /** diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c index c6b48b5925fb..50351adafc47 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c @@ -894,7 +894,7 @@ static void vb2ops_venc_stop_streaming(struct vb2_queue *q) if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { while ((dst_buf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx))) { - dst_buf->planes[0].bytesused = 0; + dst_buf->vb2_buf.planes[0].bytesused = 0; v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_ERROR); } } else { @@ -947,7 +947,7 @@ static int mtk_venc_encode_header(void *priv) bs_buf.va = vb2_plane_vaddr(&dst_buf->vb2_buf, 0); bs_buf.dma_addr = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0); - bs_buf.size = (size_t)dst_buf->planes[0].length; + bs_buf.size = (size_t)dst_buf->vb2_buf.planes[0].length; mtk_v4l2_debug(1, "[%d] buf id=%d va=0x%p dma_addr=0x%llx size=%zu", @@ -976,7 +976,7 @@ static int mtk_venc_encode_header(void *priv) } ctx->state = MTK_STATE_HEADER; - dst_buf->planes[0].bytesused = enc_result.bs_size; + dst_buf->vb2_buf.planes[0].bytesused = enc_result.bs_size; v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE); return 0; @@ -1107,12 +1107,12 @@ static void mtk_venc_worker(struct work_struct *work) if (ret) { v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR); - dst_buf->planes[0].bytesused = 0; + dst_buf->vb2_buf.planes[0].bytesused = 0; v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_ERROR); mtk_v4l2_err("venc_if_encode failed=%d", ret); } else { v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); - dst_buf->planes[0].bytesused = enc_result.bs_size; + dst_buf->vb2_buf.planes[0].bytesused = enc_result.bs_size; v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE); mtk_v4l2_debug(2, "venc_if_encode bs size=%d", enc_result.bs_size); diff --git a/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_if.c b/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_if.c index 02c960c63ac0..cdbcd6909728 100644 --- a/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_if.c +++ b/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_if.c @@ -253,8 +253,8 @@ static void get_pic_info(struct vdec_h264_inst *inst, *pic = inst->vsi->pic; mtk_vcodec_debug(inst, "pic(%d, %d), buf(%d, %d)", pic->pic_w, pic->pic_h, pic->buf_w, pic->buf_h); - mtk_vcodec_debug(inst, "Y(%d, %d), C(%d, %d)", pic->y_bs_sz, - pic->y_len_sz, pic->c_bs_sz, pic->c_len_sz); + mtk_vcodec_debug(inst, "fb size: Y(%d), C(%d)", + pic->fb_sz[0], pic->fb_sz[1]); } static void get_crop_info(struct vdec_h264_inst *inst, struct v4l2_rect *cr) diff --git a/drivers/media/platform/mtk-vcodec/vdec/vdec_vp8_if.c b/drivers/media/platform/mtk-vcodec/vdec/vdec_vp8_if.c index bac3723038de..ba79136421ef 100644 --- a/drivers/media/platform/mtk-vcodec/vdec/vdec_vp8_if.c +++ b/drivers/media/platform/mtk-vcodec/vdec/vdec_vp8_if.c @@ -294,8 +294,8 @@ static void get_pic_info(struct vdec_vp8_inst *inst, struct vdec_pic_info *pic) mtk_vcodec_debug(inst, "pic(%d, %d), buf(%d, %d)", pic->pic_w, pic->pic_h, pic->buf_w, pic->buf_h); - mtk_vcodec_debug(inst, "Y(%d, %d), C(%d, %d)", pic->y_bs_sz, - pic->y_len_sz, pic->c_bs_sz, pic->c_len_sz); + mtk_vcodec_debug(inst, "fb size: Y(%d), C(%d)", + pic->fb_sz[0], pic->fb_sz[1]); } static void vp8_dec_finish(struct vdec_vp8_inst *inst) diff --git a/drivers/media/platform/mtk-vcodec/vdec/vdec_vp9_if.c b/drivers/media/platform/mtk-vcodec/vdec/vdec_vp9_if.c index bc8349bc2e80..939ea14bf6c5 100644 --- a/drivers/media/platform/mtk-vcodec/vdec/vdec_vp9_if.c +++ b/drivers/media/platform/mtk-vcodec/vdec/vdec_vp9_if.c @@ -481,15 +481,15 @@ static void vp9_swap_frm_bufs(struct vdec_vp9_inst *inst) */ if ((frm_to_show->fb != NULL) && (inst->cur_fb->base_y.size >= - frm_to_show->fb->base_y.size)) { + frm_to_show->fb->base_y.size) && + (inst->cur_fb->base_c.size >= + frm_to_show->fb->base_c.size)) { memcpy((void *)inst->cur_fb->base_y.va, (void *)frm_to_show->fb->base_y.va, - vsi->buf_w * - vsi->buf_h); + frm_to_show->fb->base_y.size); memcpy((void *)inst->cur_fb->base_c.va, (void *)frm_to_show->fb->base_c.va, - vsi->buf_w * - vsi->buf_h / 2); + frm_to_show->fb->base_c.size); } else { /* After resolution change case, current CAPTURE buffer * may have less buffer size than frm_to_show buffer @@ -702,10 +702,8 @@ static void init_all_fb_lists(struct vdec_vp9_inst *inst) static void get_pic_info(struct vdec_vp9_inst *inst, struct vdec_pic_info *pic) { - pic->y_bs_sz = inst->vsi->buf_sz_y_bs; - pic->c_bs_sz = inst->vsi->buf_sz_c_bs; - pic->y_len_sz = inst->vsi->buf_len_sz_y; - pic->c_len_sz = inst->vsi->buf_len_sz_c; + pic->fb_sz[0] = inst->vsi->buf_sz_y_bs + inst->vsi->buf_len_sz_y; + pic->fb_sz[1] = inst->vsi->buf_sz_c_bs + inst->vsi->buf_len_sz_c; pic->pic_w = inst->vsi->pic_w; pic->pic_h = inst->vsi->pic_h; @@ -714,8 +712,9 @@ static void get_pic_info(struct vdec_vp9_inst *inst, struct vdec_pic_info *pic) mtk_vcodec_debug(inst, "pic(%d, %d), buf(%d, %d)", pic->pic_w, pic->pic_h, pic->buf_w, pic->buf_h); - mtk_vcodec_debug(inst, "Y(%d, %d), C(%d, %d)", pic->y_bs_sz, - pic->y_len_sz, pic->c_bs_sz, pic->c_len_sz); + mtk_vcodec_debug(inst, "fb size: Y(%d), C(%d)", + pic->fb_sz[0], + pic->fb_sz[1]); } static void get_disp_fb(struct vdec_vp9_inst *inst, struct vdec_fb **out_fb) @@ -895,7 +894,7 @@ static int vdec_vp9_decode(unsigned long h_vdec, struct mtk_vcodec_mem *bs, if (vsi->resolution_changed) { if (!vp9_alloc_work_buf(inst)) { - ret = -EINVAL; + ret = -EIO; goto DECODE_ERROR; } } @@ -924,14 +923,12 @@ static int vdec_vp9_decode(unsigned long h_vdec, struct mtk_vcodec_mem *bs, if (vsi->show_existing_frame && (vsi->frm_to_show_idx < VP9_MAX_FRM_BUF_NUM)) { - mtk_vcodec_err(inst, + mtk_vcodec_debug(inst, "Skip Decode drv->new_fb_idx=%d, drv->frm_to_show_idx=%d", vsi->new_fb_idx, vsi->frm_to_show_idx); vp9_ref_cnt_fb(inst, &vsi->new_fb_idx, vsi->frm_to_show_idx); - ret = -EINVAL; - goto DECODE_ERROR; } /* VPU assign the buffer pointer in its address space, diff --git a/drivers/media/platform/mtk-vpu/mtk_vpu.c b/drivers/media/platform/mtk-vpu/mtk_vpu.c index b6602490a247..46c45f93c977 100644 --- a/drivers/media/platform/mtk-vpu/mtk_vpu.c +++ b/drivers/media/platform/mtk-vpu/mtk_vpu.c @@ -614,7 +614,7 @@ static void vpu_init_ipi_handler(void *data, unsigned int len, void *priv) struct vpu_run *run = (struct vpu_run *)data; vpu->run.signaled = run->signaled; - strncpy(vpu->run.fw_ver, run->fw_ver, VPU_FW_VER_LEN); + strscpy(vpu->run.fw_ver, run->fw_ver, sizeof(vpu->run.fw_ver)); vpu->run.dec_capability = run->dec_capability; vpu->run.enc_capability = run->enc_capability; wake_up_interruptible(&vpu->run.wq); diff --git a/drivers/media/platform/mx2_emmaprp.c b/drivers/media/platform/mx2_emmaprp.c index f60f499c596b..e100b30bb6f5 100644 --- a/drivers/media/platform/mx2_emmaprp.c +++ b/drivers/media/platform/mx2_emmaprp.c @@ -385,8 +385,8 @@ static irqreturn_t emmaprp_irq(int irq_emma, void *data) static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - strncpy(cap->driver, MEM2MEM_NAME, sizeof(cap->driver) - 1); - strncpy(cap->card, MEM2MEM_NAME, sizeof(cap->card) - 1); + strscpy(cap->driver, MEM2MEM_NAME, sizeof(cap->driver)); + strscpy(cap->card, MEM2MEM_NAME, sizeof(cap->card)); cap->device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING; cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; return 0; diff --git a/drivers/media/platform/omap/Kconfig b/drivers/media/platform/omap/Kconfig index 4b5e55d41ad4..30ce2ba120a1 100644 --- a/drivers/media/platform/omap/Kconfig +++ b/drivers/media/platform/omap/Kconfig @@ -14,5 +14,5 @@ config VIDEO_OMAP2_VOUT select OMAP2_VRFB if ARCH_OMAP2 || ARCH_OMAP3 select FRAME_VECTOR default n - ---help--- + help V4L2 Display driver support for OMAP2/3 based boards. diff --git a/drivers/media/platform/pxa_camera.c b/drivers/media/platform/pxa_camera.c index 4fe228752a43..a632f06d9fff 100644 --- a/drivers/media/platform/pxa_camera.c +++ b/drivers/media/platform/pxa_camera.c @@ -2350,7 +2350,7 @@ static int pxa_camera_pdata_from_dt(struct device *dev, pcdev->platform_flags |= PXA_CAMERA_PCLK_EN; asd->match_type = V4L2_ASYNC_MATCH_FWNODE; - remote = of_graph_get_remote_port(np); + remote = of_graph_get_remote_port_parent(np); if (remote) asd->match.fwnode = of_fwnode_handle(remote); else diff --git a/drivers/media/platform/qcom/venus/hfi_helper.h b/drivers/media/platform/qcom/venus/hfi_helper.h index 15804ad7e65d..34ea503a9842 100644 --- a/drivers/media/platform/qcom/venus/hfi_helper.h +++ b/drivers/media/platform/qcom/venus/hfi_helper.h @@ -569,7 +569,7 @@ struct hfi_capability { struct hfi_capabilities { u32 num_capabilities; - struct hfi_capability data[1]; + struct hfi_capability *data; }; #define HFI_DEBUG_MSG_LOW 0x01 @@ -726,7 +726,7 @@ struct hfi_profile_level { struct hfi_profile_level_supported { u32 profile_count; - struct hfi_profile_level profile_level[1]; + struct hfi_profile_level *profile_level; }; struct hfi_quality_vs_speed { diff --git a/drivers/media/platform/rcar-vin/Kconfig b/drivers/media/platform/rcar-vin/Kconfig index e3eb8fee2536..240ac3f3c941 100644 --- a/drivers/media/platform/rcar-vin/Kconfig +++ b/drivers/media/platform/rcar-vin/Kconfig @@ -3,6 +3,7 @@ config VIDEO_RCAR_CSI2 tristate "R-Car MIPI CSI-2 Receiver" depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && OF depends on ARCH_RENESAS || COMPILE_TEST + select RESET_CONTROLLER select V4L2_FWNODE help Support for Renesas R-Car MIPI CSI-2 receiver. @@ -17,7 +18,7 @@ config VIDEO_RCAR_VIN depends on ARCH_RENESAS || COMPILE_TEST select VIDEOBUF2_DMA_CONTIG select V4L2_FWNODE - ---help--- + help Support for Renesas R-Car Video Input (VIN) driver. Supports R-Car Gen2 and Gen3 SoCs. diff --git a/drivers/media/platform/rcar-vin/rcar-core.c b/drivers/media/platform/rcar-vin/rcar-core.c index 594d80434004..64f9cf790445 100644 --- a/drivers/media/platform/rcar-vin/rcar-core.c +++ b/drivers/media/platform/rcar-vin/rcar-core.c @@ -546,7 +546,9 @@ static void rvin_parallel_notify_unbind(struct v4l2_async_notifier *notifier, vin_dbg(vin, "unbind parallel subdev %s\n", subdev->name); + mutex_lock(&vin->lock); rvin_parallel_subdevice_detach(vin); + mutex_unlock(&vin->lock); } static int rvin_parallel_notify_bound(struct v4l2_async_notifier *notifier, @@ -556,7 +558,9 @@ static int rvin_parallel_notify_bound(struct v4l2_async_notifier *notifier, struct rvin_dev *vin = v4l2_dev_to_vin(notifier->v4l2_dev); int ret; + mutex_lock(&vin->lock); ret = rvin_parallel_subdevice_attach(vin, subdev); + mutex_unlock(&vin->lock); if (ret) return ret; @@ -664,6 +668,7 @@ static int rvin_group_notify_complete(struct v4l2_async_notifier *notifier) } /* Create all media device links between VINs and CSI-2's. */ + mutex_lock(&vin->group->lock); for (route = vin->info->routes; route->mask; route++) { struct media_pad *source_pad, *sink_pad; struct media_entity *source, *sink; @@ -699,6 +704,7 @@ static int rvin_group_notify_complete(struct v4l2_async_notifier *notifier) break; } } + mutex_unlock(&vin->group->lock); return ret; } @@ -714,6 +720,8 @@ static void rvin_group_notify_unbind(struct v4l2_async_notifier *notifier, if (vin->group->vin[i]) rvin_v4l2_unregister(vin->group->vin[i]); + mutex_lock(&vin->group->lock); + for (i = 0; i < RVIN_CSI_MAX; i++) { if (vin->group->csi[i].fwnode != asd->match.fwnode) continue; @@ -721,6 +729,8 @@ static void rvin_group_notify_unbind(struct v4l2_async_notifier *notifier, vin_dbg(vin, "Unbind CSI-2 %s from slot %u\n", subdev->name, i); break; } + + mutex_unlock(&vin->group->lock); } static int rvin_group_notify_bound(struct v4l2_async_notifier *notifier, @@ -730,6 +740,8 @@ static int rvin_group_notify_bound(struct v4l2_async_notifier *notifier, struct rvin_dev *vin = v4l2_dev_to_vin(notifier->v4l2_dev); unsigned int i; + mutex_lock(&vin->group->lock); + for (i = 0; i < RVIN_CSI_MAX; i++) { if (vin->group->csi[i].fwnode != asd->match.fwnode) continue; @@ -738,6 +750,8 @@ static int rvin_group_notify_bound(struct v4l2_async_notifier *notifier, break; } + mutex_unlock(&vin->group->lock); + return 0; } @@ -752,6 +766,7 @@ static int rvin_mc_parse_of_endpoint(struct device *dev, struct v4l2_async_subdev *asd) { struct rvin_dev *vin = dev_get_drvdata(dev); + int ret = 0; if (vep->base.port != 1 || vep->base.id >= RVIN_CSI_MAX) return -EINVAL; @@ -762,38 +777,48 @@ static int rvin_mc_parse_of_endpoint(struct device *dev, return -ENOTCONN; } + mutex_lock(&vin->group->lock); + if (vin->group->csi[vep->base.id].fwnode) { vin_dbg(vin, "OF device %pOF already handled\n", to_of_node(asd->match.fwnode)); - return -ENOTCONN; + ret = -ENOTCONN; + goto out; } vin->group->csi[vep->base.id].fwnode = asd->match.fwnode; vin_dbg(vin, "Add group OF device %pOF to slot %u\n", to_of_node(asd->match.fwnode), vep->base.id); +out: + mutex_unlock(&vin->group->lock); - return 0; + return ret; } static int rvin_mc_parse_of_graph(struct rvin_dev *vin) { - unsigned int count = 0; + unsigned int count = 0, vin_mask = 0; unsigned int i; int ret; mutex_lock(&vin->group->lock); /* If not all VIN's are registered don't register the notifier. */ - for (i = 0; i < RCAR_VIN_NUM; i++) - if (vin->group->vin[i]) + for (i = 0; i < RCAR_VIN_NUM; i++) { + if (vin->group->vin[i]) { count++; + vin_mask |= BIT(i); + } + } if (vin->group->count != count) { mutex_unlock(&vin->group->lock); return 0; } + mutex_unlock(&vin->group->lock); + v4l2_async_notifier_init(&vin->group->notifier); /* @@ -802,21 +827,17 @@ static int rvin_mc_parse_of_graph(struct rvin_dev *vin) * will only be registered once with the group notifier. */ for (i = 0; i < RCAR_VIN_NUM; i++) { - if (!vin->group->vin[i]) + if (!(vin_mask & BIT(i))) continue; ret = v4l2_async_notifier_parse_fwnode_endpoints_by_port( vin->group->vin[i]->dev, &vin->group->notifier, sizeof(struct v4l2_async_subdev), 1, rvin_mc_parse_of_endpoint); - if (ret) { - mutex_unlock(&vin->group->lock); + if (ret) return ret; - } } - mutex_unlock(&vin->group->lock); - if (list_empty(&vin->group->notifier.asd_list)) return 0; @@ -1136,6 +1157,10 @@ static const struct rvin_info rcar_info_r8a77995 = { static const struct of_device_id rvin_of_id_table[] = { { + .compatible = "renesas,vin-r8a774a1", + .data = &rcar_info_r8a7796, + }, + { .compatible = "renesas,vin-r8a774c0", .data = &rcar_info_r8a77990, }, diff --git a/drivers/media/platform/rcar-vin/rcar-csi2.c b/drivers/media/platform/rcar-vin/rcar-csi2.c index f64528d2be3c..799e526fd3df 100644 --- a/drivers/media/platform/rcar-vin/rcar-csi2.c +++ b/drivers/media/platform/rcar-vin/rcar-csi2.c @@ -14,6 +14,7 @@ #include <linux/of_graph.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> +#include <linux/reset.h> #include <linux/sys_soc.h> #include <media/v4l2-ctrls.h> @@ -350,6 +351,7 @@ struct rcar_csi2 { struct device *dev; void __iomem *base; const struct rcar_csi2_info *info; + struct reset_control *rstc; struct v4l2_subdev subdev; struct media_pad pads[NR_OF_RCAR_CSI2_PAD]; @@ -387,11 +389,19 @@ static void rcsi2_write(struct rcar_csi2 *priv, unsigned int reg, u32 data) iowrite32(data, priv->base + reg); } -static void rcsi2_reset(struct rcar_csi2 *priv) +static void rcsi2_enter_standby(struct rcar_csi2 *priv) { - rcsi2_write(priv, SRST_REG, SRST_SRST); + rcsi2_write(priv, PHYCNT_REG, 0); + rcsi2_write(priv, PHTC_REG, PHTC_TESTCLR); + reset_control_assert(priv->rstc); usleep_range(100, 150); - rcsi2_write(priv, SRST_REG, 0); + pm_runtime_put(priv->dev); +} + +static void rcsi2_exit_standby(struct rcar_csi2 *priv) +{ + pm_runtime_get_sync(priv->dev); + reset_control_deassert(priv->rstc); } static int rcsi2_wait_phy_start(struct rcar_csi2 *priv) @@ -462,7 +472,7 @@ static int rcsi2_calc_mbps(struct rcar_csi2 *priv, unsigned int bpp) return mbps; } -static int rcsi2_start(struct rcar_csi2 *priv) +static int rcsi2_start_receiver(struct rcar_csi2 *priv) { const struct rcar_csi2_format *format; u32 phycnt, vcdt = 0, vcdt2 = 0; @@ -506,12 +516,9 @@ static int rcsi2_start(struct rcar_csi2 *priv) /* Init */ rcsi2_write(priv, TREF_REG, TREF_TREF); - rcsi2_reset(priv); rcsi2_write(priv, PHTC_REG, 0); /* Configure */ - rcsi2_write(priv, FLD_REG, FLD_FLD_NUM(2) | FLD_FLD_EN4 | - FLD_FLD_EN3 | FLD_FLD_EN2 | FLD_FLD_EN); rcsi2_write(priv, VCDT_REG, vcdt); if (vcdt2) rcsi2_write(priv, VCDT2_REG, vcdt2); @@ -542,6 +549,8 @@ static int rcsi2_start(struct rcar_csi2 *priv) rcsi2_write(priv, PHYCNT_REG, phycnt); rcsi2_write(priv, LINKCNT_REG, LINKCNT_MONITOR_EN | LINKCNT_REG_MONI_PACT_EN | LINKCNT_ICLK_NONSTOP); + rcsi2_write(priv, FLD_REG, FLD_FLD_NUM(2) | FLD_FLD_EN4 | + FLD_FLD_EN3 | FLD_FLD_EN2 | FLD_FLD_EN); rcsi2_write(priv, PHYCNT_REG, phycnt | PHYCNT_SHUTDOWNZ); rcsi2_write(priv, PHYCNT_REG, phycnt | PHYCNT_SHUTDOWNZ | PHYCNT_RSTZ); @@ -564,19 +573,36 @@ static int rcsi2_start(struct rcar_csi2 *priv) return 0; } -static void rcsi2_stop(struct rcar_csi2 *priv) +static int rcsi2_start(struct rcar_csi2 *priv) { - rcsi2_write(priv, PHYCNT_REG, 0); + int ret; - rcsi2_reset(priv); + rcsi2_exit_standby(priv); - rcsi2_write(priv, PHTC_REG, PHTC_TESTCLR); + ret = rcsi2_start_receiver(priv); + if (ret) { + rcsi2_enter_standby(priv); + return ret; + } + + ret = v4l2_subdev_call(priv->remote, video, s_stream, 1); + if (ret) { + rcsi2_enter_standby(priv); + return ret; + } + + return 0; +} + +static void rcsi2_stop(struct rcar_csi2 *priv) +{ + rcsi2_enter_standby(priv); + v4l2_subdev_call(priv->remote, video, s_stream, 0); } static int rcsi2_s_stream(struct v4l2_subdev *sd, int enable) { struct rcar_csi2 *priv = sd_to_csi2(sd); - struct v4l2_subdev *nextsd; int ret = 0; mutex_lock(&priv->lock); @@ -586,27 +612,12 @@ static int rcsi2_s_stream(struct v4l2_subdev *sd, int enable) goto out; } - nextsd = priv->remote; - if (enable && priv->stream_count == 0) { - pm_runtime_get_sync(priv->dev); - ret = rcsi2_start(priv); - if (ret) { - pm_runtime_put(priv->dev); - goto out; - } - - ret = v4l2_subdev_call(nextsd, video, s_stream, 1); - if (ret) { - rcsi2_stop(priv); - pm_runtime_put(priv->dev); + if (ret) goto out; - } } else if (!enable && priv->stream_count == 1) { rcsi2_stop(priv); - v4l2_subdev_call(nextsd, video, s_stream, 0); - pm_runtime_put(priv->dev); } priv->stream_count += enable ? 1 : -1; @@ -854,7 +865,8 @@ static int rcsi2_phtw_write_mbps(struct rcar_csi2 *priv, unsigned int mbps, return rcsi2_phtw_write(priv, value->reg, code); } -static int rcsi2_init_phtw_h3_v3h_m3n(struct rcar_csi2 *priv, unsigned int mbps) +static int __rcsi2_init_phtw_h3_v3h_m3n(struct rcar_csi2 *priv, + unsigned int mbps) { static const struct phtw_value step1[] = { { .data = 0xcc, .code = 0xe2 }, @@ -880,7 +892,7 @@ static int rcsi2_init_phtw_h3_v3h_m3n(struct rcar_csi2 *priv, unsigned int mbps) if (ret) return ret; - if (mbps <= 250) { + if (mbps != 0 && mbps <= 250) { ret = rcsi2_phtw_write(priv, 0x39, 0x05); if (ret) return ret; @@ -894,6 +906,16 @@ static int rcsi2_init_phtw_h3_v3h_m3n(struct rcar_csi2 *priv, unsigned int mbps) return rcsi2_phtw_write_array(priv, step2); } +static int rcsi2_init_phtw_h3_v3h_m3n(struct rcar_csi2 *priv, unsigned int mbps) +{ + return __rcsi2_init_phtw_h3_v3h_m3n(priv, mbps); +} + +static int rcsi2_init_phtw_h3es2(struct rcar_csi2 *priv, unsigned int mbps) +{ + return __rcsi2_init_phtw_h3_v3h_m3n(priv, 0); +} + static int rcsi2_init_phtw_v3m_e3(struct rcar_csi2 *priv, unsigned int mbps) { return rcsi2_phtw_write_mbps(priv, mbps, phtw_mbps_v3m_e3, 0x44); @@ -902,11 +924,11 @@ static int rcsi2_init_phtw_v3m_e3(struct rcar_csi2 *priv, unsigned int mbps) static int rcsi2_confirm_start_v3m_e3(struct rcar_csi2 *priv) { static const struct phtw_value step1[] = { - { .data = 0xed, .code = 0x34 }, - { .data = 0xed, .code = 0x44 }, - { .data = 0xed, .code = 0x54 }, - { .data = 0xed, .code = 0x84 }, - { .data = 0xed, .code = 0x94 }, + { .data = 0xee, .code = 0x34 }, + { .data = 0xee, .code = 0x44 }, + { .data = 0xee, .code = 0x54 }, + { .data = 0xee, .code = 0x84 }, + { .data = 0xee, .code = 0x94 }, { /* sentinel */ }, }; @@ -936,6 +958,10 @@ static int rcsi2_probe_resources(struct rcar_csi2 *priv, if (irq < 0) return irq; + priv->rstc = devm_reset_control_get(&pdev->dev, NULL); + if (IS_ERR(priv->rstc)) + return PTR_ERR(priv->rstc); + return 0; } @@ -952,6 +978,14 @@ static const struct rcar_csi2_info rcar_csi2_info_r8a7795es1 = { .num_channels = 4, }; +static const struct rcar_csi2_info rcar_csi2_info_r8a7795es2 = { + .init_phtw = rcsi2_init_phtw_h3es2, + .hsfreqrange = hsfreqrange_h3_v3h_m3n, + .csi0clkfreqrange = 0x20, + .num_channels = 4, + .clear_ulps = true, +}; + static const struct rcar_csi2_info rcar_csi2_info_r8a7796 = { .hsfreqrange = hsfreqrange_m3w_h3es1, .num_channels = 4, @@ -986,6 +1020,10 @@ static const struct rcar_csi2_info rcar_csi2_info_r8a77990 = { static const struct of_device_id rcar_csi2_of_table[] = { { + .compatible = "renesas,r8a774a1-csi2", + .data = &rcar_csi2_info_r8a7796, + }, + { .compatible = "renesas,r8a774c0-csi2", .data = &rcar_csi2_info_r8a77990, }, @@ -1017,11 +1055,15 @@ static const struct of_device_id rcar_csi2_of_table[] = { }; MODULE_DEVICE_TABLE(of, rcar_csi2_of_table); -static const struct soc_device_attribute r8a7795es1[] = { +static const struct soc_device_attribute r8a7795[] = { { .soc_id = "r8a7795", .revision = "ES1.*", .data = &rcar_csi2_info_r8a7795es1, }, + { + .soc_id = "r8a7795", .revision = "ES2.*", + .data = &rcar_csi2_info_r8a7795es2, + }, { /* sentinel */ }, }; @@ -1039,10 +1081,10 @@ static int rcsi2_probe(struct platform_device *pdev) priv->info = of_device_get_match_data(&pdev->dev); /* - * r8a7795 ES1.x behaves differently than the ES2.0+ but doesn't - * have it's own compatible string. + * The different ES versions of r8a7795 (H3) behave differently but + * share the same compatible string. */ - attr = soc_device_match(r8a7795es1); + attr = soc_device_match(r8a7795); if (attr) priv->info = attr->data; diff --git a/drivers/media/platform/rcar-vin/rcar-dma.c b/drivers/media/platform/rcar-vin/rcar-dma.c index 2207a31d355e..91ab064404a1 100644 --- a/drivers/media/platform/rcar-vin/rcar-dma.c +++ b/drivers/media/platform/rcar-vin/rcar-dma.c @@ -486,7 +486,7 @@ static void rvin_set_coeff(struct rvin_dev *vin, unsigned short xs) } /* Use previous value if its XS value is closer */ - if (p_prev_set && p_set && + if (p_prev_set && xs - p_prev_set->xs_value < p_set->xs_value - xs) p_set = p_prev_set; diff --git a/drivers/media/platform/rcar_drif.c b/drivers/media/platform/rcar_drif.c index c417ff8f6fe5..608e5217ccd5 100644 --- a/drivers/media/platform/rcar_drif.c +++ b/drivers/media/platform/rcar_drif.c @@ -1405,11 +1405,9 @@ static int rcar_drif_probe(struct platform_device *pdev) /* Register map */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); ch->base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(ch->base)) { - ret = PTR_ERR(ch->base); - dev_err(&pdev->dev, "ioremap failed (%d)\n", ret); - return ret; - } + if (IS_ERR(ch->base)) + return PTR_ERR(ch->base); + ch->start = res->start; platform_set_drvdata(pdev, ch); diff --git a/drivers/media/platform/rcar_fdp1.c b/drivers/media/platform/rcar_fdp1.c index 6bda1eee9170..6a90bc4c476e 100644 --- a/drivers/media/platform/rcar_fdp1.c +++ b/drivers/media/platform/rcar_fdp1.c @@ -945,7 +945,7 @@ static void fdp1_configure_wpf(struct fdp1_ctx *ctx, u32 rndctl; pstride = q_data->format.plane_fmt[0].bytesperline - << FD1_WPF_PSTRIDE_Y_SHIFT; + << FD1_WPF_PSTRIDE_Y_SHIFT; if (q_data->format.num_planes > 1) pstride |= q_data->format.plane_fmt[1].bytesperline @@ -1139,8 +1139,8 @@ static int fdp1_m2m_job_ready(void *priv) int dstbufs = 1; dprintk(ctx->fdp1, "+ Src: %d : Dst: %d\n", - v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx), - v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx)); + v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx), + v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx)); /* One output buffer is required for each field */ if (V4L2_FIELD_HAS_BOTH(src_q_data->format.field)) @@ -1278,7 +1278,7 @@ static void fdp1_m2m_device_run(void *priv) fdp1_queue_field(ctx, fbuf); dprintk(fdp1, "Queued Buffer [%d] last_field:%d\n", - i, fbuf->last_field); + i, fbuf->last_field); } /* Queue as many jobs as our data provides for */ @@ -1337,7 +1337,7 @@ static void device_frame_end(struct fdp1_dev *fdp1, fdp1_job_free(fdp1, job); dprintk(fdp1, "curr_ctx->num_processed %d curr_ctx->translen %d\n", - ctx->num_processed, ctx->translen); + ctx->num_processed, ctx->translen); if (ctx->num_processed == ctx->translen || ctx->aborting) { @@ -1362,7 +1362,7 @@ static int fdp1_vidioc_querycap(struct file *file, void *priv, strscpy(cap->driver, DRIVER_NAME, sizeof(cap->driver)); strscpy(cap->card, DRIVER_NAME, sizeof(cap->card)); snprintf(cap->bus_info, sizeof(cap->bus_info), - "platform:%s", DRIVER_NAME); + "platform:%s", DRIVER_NAME); return 0; } @@ -1993,13 +1993,13 @@ static void fdp1_stop_streaming(struct vb2_queue *q) /* Free smsk_data */ if (ctx->smsk_cpu) { dma_free_coherent(ctx->fdp1->dev, ctx->smsk_size, - ctx->smsk_cpu, ctx->smsk_addr[0]); + ctx->smsk_cpu, ctx->smsk_addr[0]); ctx->smsk_addr[0] = ctx->smsk_addr[1] = 0; ctx->smsk_cpu = NULL; } WARN(!list_empty(&ctx->fields_queue), - "Buffer queue not empty"); + "Buffer queue not empty"); } else { /* Empty Capture queues (Jobs) */ struct fdp1_job *job; @@ -2021,10 +2021,10 @@ static void fdp1_stop_streaming(struct vb2_queue *q) fdp1_field_complete(ctx, ctx->previous); WARN(!list_empty(&ctx->fdp1->queued_job_list), - "Queued Job List not empty"); + "Queued Job List not empty"); WARN(!list_empty(&ctx->fdp1->hw_job_list), - "HW Job list not empty"); + "HW Job list not empty"); } } @@ -2110,7 +2110,7 @@ static int fdp1_open(struct file *file) fdp1_ctrl_deint_menu); ctrl = v4l2_ctrl_new_std(&ctx->hdl, &fdp1_ctrl_ops, - V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, 1, 2, 1, 1); + V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, 1, 2, 1, 1); if (ctrl) ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE; @@ -2347,8 +2347,8 @@ static int fdp1_probe(struct platform_device *pdev) goto release_m2m; } - v4l2_info(&fdp1->v4l2_dev, - "Device registered as /dev/video%d\n", vfd->num); + v4l2_info(&fdp1->v4l2_dev, "Device registered as /dev/video%d\n", + vfd->num); /* Power up the cells to read HW */ pm_runtime_enable(&pdev->dev); @@ -2367,7 +2367,7 @@ static int fdp1_probe(struct platform_device *pdev) break; default: dev_err(fdp1->dev, "FDP1 Unidentifiable (0x%08x)\n", - hw_version); + hw_version); } /* Allow the hw to sleep until an open call puts it to use */ diff --git a/drivers/media/platform/s5p-cec/s5p_cec.c b/drivers/media/platform/s5p-cec/s5p_cec.c index 8837e2678bde..7f62f5ef0086 100644 --- a/drivers/media/platform/s5p-cec/s5p_cec.c +++ b/drivers/media/platform/s5p-cec/s5p_cec.c @@ -178,22 +178,16 @@ static const struct cec_adap_ops s5p_cec_adap_ops = { static int s5p_cec_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct device_node *np; - struct platform_device *hdmi_dev; + struct device *hdmi_dev; struct resource *res; struct s5p_cec_dev *cec; bool needs_hpd = of_property_read_bool(pdev->dev.of_node, "needs-hpd"); int ret; - np = of_parse_phandle(pdev->dev.of_node, "hdmi-phandle", 0); + hdmi_dev = cec_notifier_parse_hdmi_phandle(dev); - if (!np) { - dev_err(&pdev->dev, "Failed to find hdmi node in device tree\n"); - return -ENODEV; - } - hdmi_dev = of_find_device_by_node(np); - if (hdmi_dev == NULL) - return -EPROBE_DEFER; + if (IS_ERR(hdmi_dev)) + return PTR_ERR(hdmi_dev); cec = devm_kzalloc(&pdev->dev, sizeof(*cec), GFP_KERNEL); if (!cec) @@ -224,7 +218,7 @@ static int s5p_cec_probe(struct platform_device *pdev) if (IS_ERR(cec->reg)) return PTR_ERR(cec->reg); - cec->notifier = cec_notifier_get(&hdmi_dev->dev); + cec->notifier = cec_notifier_get(hdmi_dev); if (cec->notifier == NULL) return -ENOMEM; diff --git a/drivers/media/platform/s5p-g2d/g2d.c b/drivers/media/platform/s5p-g2d/g2d.c index 971c47165010..c8f394e1aff4 100644 --- a/drivers/media/platform/s5p-g2d/g2d.c +++ b/drivers/media/platform/s5p-g2d/g2d.c @@ -297,8 +297,8 @@ static int g2d_release(struct file *file) static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - strncpy(cap->driver, G2D_NAME, sizeof(cap->driver) - 1); - strncpy(cap->card, G2D_NAME, sizeof(cap->card) - 1); + strscpy(cap->driver, G2D_NAME, sizeof(cap->driver)); + strscpy(cap->card, G2D_NAME, sizeof(cap->card)); cap->bus_info[0] = 0; cap->device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING; cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; @@ -312,7 +312,7 @@ static int vidioc_enum_fmt(struct file *file, void *prv, struct v4l2_fmtdesc *f) return -EINVAL; fmt = &formats[f->index]; f->pixelformat = fmt->fourcc; - strncpy(f->description, fmt->name, sizeof(f->description) - 1); + strscpy(f->description, fmt->name, sizeof(f->description)); return 0; } diff --git a/drivers/media/platform/seco-cec/seco-cec.c b/drivers/media/platform/seco-cec/seco-cec.c index a425a10540c1..e5080d6f5b2d 100644 --- a/drivers/media/platform/seco-cec/seco-cec.c +++ b/drivers/media/platform/seco-cec/seco-cec.c @@ -536,6 +536,7 @@ static int secocec_cec_get_notifier(struct cec_notifier **notify) return -EPROBE_DEFER; *notify = cec_notifier_get_conn(d, m->conn); + put_device(d); return 0; } diff --git a/drivers/media/platform/sh_veu.c b/drivers/media/platform/sh_veu.c index d277cc674349..5a9ba05c996e 100644 --- a/drivers/media/platform/sh_veu.c +++ b/drivers/media/platform/sh_veu.c @@ -493,9 +493,6 @@ static int sh_veu_try_fmt_vid_cap(struct file *file, void *priv, const struct sh_veu_format *fmt; fmt = sh_veu_find_fmt(f); - if (!fmt) - /* wrong buffer type */ - return -EINVAL; return sh_veu_try_fmt(f, fmt); } @@ -506,9 +503,6 @@ static int sh_veu_try_fmt_vid_out(struct file *file, void *priv, const struct sh_veu_format *fmt; fmt = sh_veu_find_fmt(f); - if (!fmt) - /* wrong buffer type */ - return -EINVAL; return sh_veu_try_fmt(f, fmt); } diff --git a/drivers/media/platform/sti/c8sectpfe/Kconfig b/drivers/media/platform/sti/c8sectpfe/Kconfig index 7420a50572d3..93eaabfd5437 100644 --- a/drivers/media/platform/sti/c8sectpfe/Kconfig +++ b/drivers/media/platform/sti/c8sectpfe/Kconfig @@ -12,7 +12,7 @@ config DVB_C8SECTPFE select DVB_STV0367 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_TDA18212 if MEDIA_SUBDRV_AUTOSELECT - ---help--- + help This adds support for DVB front-end cards connected to TS inputs of STiH407/410 SoC. diff --git a/drivers/media/platform/sti/cec/stih-cec.c b/drivers/media/platform/sti/cec/stih-cec.c index d34099f75990..fc37efe1d554 100644 --- a/drivers/media/platform/sti/cec/stih-cec.c +++ b/drivers/media/platform/sti/cec/stih-cec.c @@ -301,26 +301,19 @@ static int stih_cec_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct resource *res; struct stih_cec *cec; - struct device_node *np; - struct platform_device *hdmi_dev; + struct device *hdmi_dev; int ret; + hdmi_dev = cec_notifier_parse_hdmi_phandle(dev); + + if (IS_ERR(hdmi_dev)) + return PTR_ERR(hdmi_dev); + cec = devm_kzalloc(dev, sizeof(*cec), GFP_KERNEL); if (!cec) return -ENOMEM; - np = of_parse_phandle(pdev->dev.of_node, "hdmi-phandle", 0); - - if (!np) { - dev_err(&pdev->dev, "Failed to find hdmi node in device tree\n"); - return -ENODEV; - } - - hdmi_dev = of_find_device_by_node(np); - if (!hdmi_dev) - return -EPROBE_DEFER; - - cec->notifier = cec_notifier_get(&hdmi_dev->dev); + cec->notifier = cec_notifier_get(hdmi_dev); if (!cec->notifier) return -ENOMEM; diff --git a/drivers/media/platform/sti/delta/delta-ipc.c b/drivers/media/platform/sti/delta/delta-ipc.c index a4603d573c34..186d88f02ecd 100644 --- a/drivers/media/platform/sti/delta/delta-ipc.c +++ b/drivers/media/platform/sti/delta/delta-ipc.c @@ -220,10 +220,8 @@ int delta_ipc_open(struct delta_ctx *pctx, const char *name, err: pctx->sys_errors++; - if (ctx->ipc_buf) { - hw_free(pctx, ctx->ipc_buf); - ctx->ipc_buf = NULL; - } + hw_free(pctx, ctx->ipc_buf); + ctx->ipc_buf = NULL; return ret; }; diff --git a/drivers/media/platform/stm32/stm32-cec.c b/drivers/media/platform/stm32/stm32-cec.c index 7c496bc1cf38..8a86b2cc22fa 100644 --- a/drivers/media/platform/stm32/stm32-cec.c +++ b/drivers/media/platform/stm32/stm32-cec.c @@ -56,6 +56,13 @@ #define ALL_TX_IT (TXEND | TXBR | TXACKE | TXERR | TXUDR | ARBLST) #define ALL_RX_IT (RXEND | RXBR | RXACKE | RXOVR) +/* + * 400 ms is the time it takes for one 16 byte message to be + * transferred and 5 is the maximum number of retries. Add + * another 100 ms as a margin. + */ +#define CEC_XFER_TIMEOUT_MS (5 * 400 + 100) + struct stm32_cec { struct cec_adapter *adap; struct device *dev; @@ -188,7 +195,11 @@ static int stm32_cec_adap_log_addr(struct cec_adapter *adap, u8 logical_addr) { struct stm32_cec *cec = adap->priv; u32 oar = (1 << logical_addr) << 16; + u32 val; + /* Poll every 100µs the register CEC_CR to wait end of transmission */ + regmap_read_poll_timeout(cec->regmap, CEC_CR, val, !(val & TXSOM), + 100, CEC_XFER_TIMEOUT_MS * 1000); regmap_update_bits(cec->regmap, CEC_CR, CECEN, 0); if (logical_addr == CEC_LOG_ADDR_INVALID) diff --git a/drivers/media/platform/stm32/stm32-dcmi.c b/drivers/media/platform/stm32/stm32-dcmi.c index 5fe5b38fa901..b9dad0accd1b 100644 --- a/drivers/media/platform/stm32/stm32-dcmi.c +++ b/drivers/media/platform/stm32/stm32-dcmi.c @@ -97,6 +97,8 @@ enum state { #define TIMEOUT_MS 1000 +#define OVERRUN_ERROR_THRESHOLD 3 + struct dcmi_graph_entity { struct device_node *node; @@ -164,6 +166,9 @@ struct stm32_dcmi { int errors_count; int overrun_count; int buffers_count; + + /* Ensure DMA operations atomicity */ + struct mutex dma_lock; }; static inline struct stm32_dcmi *notifier_to_dcmi(struct v4l2_async_notifier *n) @@ -314,6 +319,13 @@ static int dcmi_start_dma(struct stm32_dcmi *dcmi, return ret; } + /* + * Avoid call of dmaengine_terminate_all() between + * dmaengine_prep_slave_single() and dmaengine_submit() + * by locking the whole DMA submission sequence + */ + mutex_lock(&dcmi->dma_lock); + /* Prepare a DMA transaction */ desc = dmaengine_prep_slave_single(dcmi->dma_chan, buf->paddr, buf->size, @@ -322,6 +334,7 @@ static int dcmi_start_dma(struct stm32_dcmi *dcmi, if (!desc) { dev_err(dcmi->dev, "%s: DMA dmaengine_prep_slave_single failed for buffer phy=%pad size=%zu\n", __func__, &buf->paddr, buf->size); + mutex_unlock(&dcmi->dma_lock); return -EINVAL; } @@ -333,9 +346,12 @@ static int dcmi_start_dma(struct stm32_dcmi *dcmi, dcmi->dma_cookie = dmaengine_submit(desc); if (dma_submit_error(dcmi->dma_cookie)) { dev_err(dcmi->dev, "%s: DMA submission failed\n", __func__); + mutex_unlock(&dcmi->dma_lock); return -ENXIO; } + mutex_unlock(&dcmi->dma_lock); + dma_async_issue_pending(dcmi->dma_chan); return 0; @@ -432,11 +448,13 @@ static irqreturn_t dcmi_irq_thread(int irq, void *arg) spin_lock_irq(&dcmi->irqlock); - if ((dcmi->misr & IT_OVR) || (dcmi->misr & IT_ERR)) { - dcmi->errors_count++; - if (dcmi->misr & IT_OVR) - dcmi->overrun_count++; + if (dcmi->misr & IT_OVR) { + dcmi->overrun_count++; + if (dcmi->overrun_count > OVERRUN_ERROR_THRESHOLD) + dcmi->errors_count++; } + if (dcmi->misr & IT_ERR) + dcmi->errors_count++; if (dcmi->sd_format->fourcc == V4L2_PIX_FMT_JPEG && dcmi->misr & IT_FRAME) { @@ -570,9 +588,9 @@ static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count) int ret; ret = pm_runtime_get_sync(dcmi->dev); - if (ret) { - dev_err(dcmi->dev, "%s: Failed to start streaming, cannot get sync\n", - __func__); + if (ret < 0) { + dev_err(dcmi->dev, "%s: Failed to start streaming, cannot get sync (%d)\n", + __func__, ret); goto err_release_buffers; } @@ -720,7 +738,9 @@ static void dcmi_stop_streaming(struct vb2_queue *vq) spin_unlock_irq(&dcmi->irqlock); /* Stop all pending DMA operations */ + mutex_lock(&dcmi->dma_lock); dmaengine_terminate_all(dcmi->dma_chan); + mutex_unlock(&dcmi->dma_lock); pm_runtime_put(dcmi->dev); @@ -811,6 +831,9 @@ static int dcmi_try_fmt(struct stm32_dcmi *dcmi, struct v4l2_format *f, sd_fmt = find_format_by_fourcc(dcmi, pix->pixelformat); if (!sd_fmt) { + if (!dcmi->num_of_sd_formats) + return -ENODATA; + sd_fmt = dcmi->sd_formats[dcmi->num_of_sd_formats - 1]; pix->pixelformat = sd_fmt->fourcc; } @@ -989,6 +1012,9 @@ static int dcmi_set_sensor_format(struct stm32_dcmi *dcmi, sd_fmt = find_format_by_fourcc(dcmi, pix->pixelformat); if (!sd_fmt) { + if (!dcmi->num_of_sd_formats) + return -ENODATA; + sd_fmt = dcmi->sd_formats[dcmi->num_of_sd_formats - 1]; pix->pixelformat = sd_fmt->fourcc; } @@ -1595,7 +1621,7 @@ static int dcmi_graph_init(struct stm32_dcmi *dcmi) /* Parse the graph to extract a list of subdevice DT nodes. */ ret = dcmi_graph_parse(dcmi, dcmi->dev->of_node); if (ret < 0) { - dev_err(dcmi->dev, "Graph parsing failed\n"); + dev_err(dcmi->dev, "Failed to parse graph\n"); return ret; } @@ -1604,6 +1630,7 @@ static int dcmi_graph_init(struct stm32_dcmi *dcmi) ret = v4l2_async_notifier_add_subdev(&dcmi->notifier, &dcmi->entity.asd); if (ret) { + dev_err(dcmi->dev, "Failed to add subdev notifier\n"); of_node_put(dcmi->entity.node); return ret; } @@ -1612,7 +1639,7 @@ static int dcmi_graph_init(struct stm32_dcmi *dcmi) ret = v4l2_async_notifier_register(&dcmi->v4l2_dev, &dcmi->notifier); if (ret < 0) { - dev_err(dcmi->dev, "Notifier registration failed\n"); + dev_err(dcmi->dev, "Failed to register notifier\n"); v4l2_async_notifier_cleanup(&dcmi->notifier); return ret; } @@ -1645,7 +1672,7 @@ static int dcmi_probe(struct platform_device *pdev) dcmi->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL); if (IS_ERR(dcmi->rstc)) { dev_err(&pdev->dev, "Could not get reset control\n"); - return -ENODEV; + return PTR_ERR(dcmi->rstc); } /* Get bus characteristics from devicetree */ @@ -1660,7 +1687,7 @@ static int dcmi_probe(struct platform_device *pdev) of_node_put(np); if (ret) { dev_err(&pdev->dev, "Could not parse the endpoint\n"); - return -ENODEV; + return ret; } if (ep.bus_type == V4L2_MBUS_CSI2_DPHY) { @@ -1673,8 +1700,9 @@ static int dcmi_probe(struct platform_device *pdev) irq = platform_get_irq(pdev, 0); if (irq <= 0) { - dev_err(&pdev->dev, "Could not get irq\n"); - return -ENODEV; + if (irq != -EPROBE_DEFER) + dev_err(&pdev->dev, "Could not get irq\n"); + return irq; } dcmi->res = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -1694,12 +1722,13 @@ static int dcmi_probe(struct platform_device *pdev) dev_name(&pdev->dev), dcmi); if (ret) { dev_err(&pdev->dev, "Unable to request irq %d\n", irq); - return -ENODEV; + return ret; } mclk = devm_clk_get(&pdev->dev, "mclk"); if (IS_ERR(mclk)) { - dev_err(&pdev->dev, "Unable to get mclk\n"); + if (PTR_ERR(mclk) != -EPROBE_DEFER) + dev_err(&pdev->dev, "Unable to get mclk\n"); return PTR_ERR(mclk); } @@ -1711,6 +1740,7 @@ static int dcmi_probe(struct platform_device *pdev) spin_lock_init(&dcmi->irqlock); mutex_init(&dcmi->lock); + mutex_init(&dcmi->dma_lock); init_completion(&dcmi->complete); INIT_LIST_HEAD(&dcmi->buffers); diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c index 1fd16861f111..f0dfe68486d1 100644 --- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c +++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c @@ -412,7 +412,7 @@ static int vidioc_enum_input(struct file *file, void *fh, if (inp->index != 0) return -EINVAL; - strlcpy(inp->name, "camera", sizeof(inp->name)); + strscpy(inp->name, "camera", sizeof(inp->name)); inp->type = V4L2_INPUT_TYPE_CAMERA; return 0; @@ -644,7 +644,7 @@ int sun6i_video_init(struct sun6i_video *video, struct sun6i_csi *csi, } /* Register video device */ - strlcpy(vdev->name, name, sizeof(vdev->name)); + strscpy(vdev->name, name, sizeof(vdev->name)); vdev->release = video_device_release_empty; vdev->fops = &sun6i_video_fops; vdev->ioctl_ops = &sun6i_video_ioctl_ops; diff --git a/drivers/media/platform/tegra-cec/tegra_cec.c b/drivers/media/platform/tegra-cec/tegra_cec.c index aba488cd0e64..7fb3a4fa07c1 100644 --- a/drivers/media/platform/tegra-cec/tegra_cec.c +++ b/drivers/media/platform/tegra-cec/tegra_cec.c @@ -327,21 +327,15 @@ static const struct cec_adap_ops tegra_cec_ops = { static int tegra_cec_probe(struct platform_device *pdev) { - struct platform_device *hdmi_dev; - struct device_node *np; + struct device *hdmi_dev; struct tegra_cec *cec; struct resource *res; int ret = 0; - np = of_parse_phandle(pdev->dev.of_node, "hdmi-phandle", 0); + hdmi_dev = cec_notifier_parse_hdmi_phandle(&pdev->dev); - if (!np) { - dev_err(&pdev->dev, "Failed to find hdmi node in device tree\n"); + if (!hdmi_dev) return -ENODEV; - } - hdmi_dev = of_find_device_by_node(np); - if (hdmi_dev == NULL) - return -EPROBE_DEFER; cec = devm_kzalloc(&pdev->dev, sizeof(struct tegra_cec), GFP_KERNEL); @@ -400,7 +394,7 @@ static int tegra_cec_probe(struct platform_device *pdev) goto clk_error; } - cec->notifier = cec_notifier_get(&hdmi_dev->dev); + cec->notifier = cec_notifier_get(hdmi_dev); if (!cec->notifier) { ret = -ENOMEM; goto clk_error; diff --git a/drivers/media/platform/ti-vpe/cal.c b/drivers/media/platform/ti-vpe/cal.c index fc3c212b96e1..8d075683e448 100644 --- a/drivers/media/platform/ti-vpe/cal.c +++ b/drivers/media/platform/ti-vpe/cal.c @@ -1643,8 +1643,7 @@ of_get_next_endpoint(const struct device_node *parent, static int of_cal_create_instance(struct cal_ctx *ctx, int inst) { struct platform_device *pdev = ctx->dev->pdev; - struct device_node *ep_node, *port, *remote_ep, - *sensor_node, *parent; + struct device_node *ep_node, *port, *sensor_node, *parent; struct v4l2_fwnode_endpoint *endpoint; struct v4l2_async_subdev *asd; u32 regval = 0; @@ -1657,7 +1656,6 @@ static int of_cal_create_instance(struct cal_ctx *ctx, int inst) ep_node = NULL; port = NULL; - remote_ep = NULL; sensor_node = NULL; ret = -EINVAL; @@ -1703,12 +1701,7 @@ static int of_cal_create_instance(struct cal_ctx *ctx, int inst) asd->match_type = V4L2_ASYNC_MATCH_FWNODE; asd->match.fwnode = of_fwnode_handle(sensor_node); - remote_ep = of_graph_get_remote_endpoint(ep_node); - if (!remote_ep) { - ctx_dbg(3, ctx, "can't get remote-endpoint\n"); - goto cleanup_exit; - } - v4l2_fwnode_endpoint_parse(of_fwnode_handle(remote_ep), endpoint); + v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep_node), endpoint); if (endpoint->bus_type != V4L2_MBUS_CSI2_DPHY) { ctx_err(ctx, "Port:%d sub-device %pOFn is not a CSI2 device\n", @@ -1759,7 +1752,6 @@ static int of_cal_create_instance(struct cal_ctx *ctx, int inst) sensor_node = NULL; cleanup_exit: - of_node_put(remote_ep); of_node_put(sensor_node); of_node_put(ep_node); of_node_put(port); diff --git a/drivers/media/platform/ti-vpe/vpe.c b/drivers/media/platform/ti-vpe/vpe.c index 207e7e76c048..1e40eafec284 100644 --- a/drivers/media/platform/ti-vpe/vpe.c +++ b/drivers/media/platform/ti-vpe/vpe.c @@ -1491,8 +1491,8 @@ handled: static int vpe_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - strncpy(cap->driver, VPE_MODULE_NAME, sizeof(cap->driver) - 1); - strncpy(cap->card, VPE_MODULE_NAME, sizeof(cap->card) - 1); + strscpy(cap->driver, VPE_MODULE_NAME, sizeof(cap->driver)); + strscpy(cap->card, VPE_MODULE_NAME, sizeof(cap->card)); snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", VPE_MODULE_NAME); cap->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING; @@ -1519,7 +1519,7 @@ static int __enum_fmt(struct v4l2_fmtdesc *f, u32 type) if (!fmt) return -EINVAL; - strncpy(f->description, fmt->name, sizeof(f->description) - 1); + strscpy(f->description, fmt->name, sizeof(f->description)); f->pixelformat = fmt->fourcc; return 0; } diff --git a/drivers/media/platform/vicodec/codec-fwht.c b/drivers/media/platform/vicodec/codec-fwht.c index d1d6085da9f1..31faf319e508 100644 --- a/drivers/media/platform/vicodec/codec-fwht.c +++ b/drivers/media/platform/vicodec/codec-fwht.c @@ -46,8 +46,12 @@ static const uint8_t zigzag[64] = { 63, }; - -static int rlc(const s16 *in, __be16 *output, int blocktype) +/* + * 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; @@ -106,8 +110,8 @@ static int rlc(const s16 *in, __be16 *output, int blocktype) * 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 u16 derlc(const __be16 **rlc_in, s16 *dwht_out, - const __be16 *end_of_input) +static noinline_for_stack u16 +derlc(const __be16 **rlc_in, s16 *dwht_out, const __be16 *end_of_input) { /* header */ const __be16 *input = *rlc_in; @@ -240,8 +244,9 @@ static void dequantize_inter(s16 *coeff) *coeff <<= *quant; } -static void fwht(const u8 *block, s16 *output_block, unsigned int stride, - unsigned int input_step, bool intra) +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]; @@ -373,7 +378,8 @@ static void fwht(const u8 *block, s16 *output_block, unsigned int stride, * Furthermore values can be negative... This is just a version that * works with 16 signed data */ -static void fwht16(const s16 *block, s16 *output_block, int stride, int intra) +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]; @@ -456,7 +462,8 @@ static void fwht16(const s16 *block, s16 *output_block, int stride, int intra) } } -static void ifwht(const s16 *block, s16 *output_block, int intra) +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 @@ -604,9 +611,9 @@ static int var_inter(const s16 *old, const s16 *new) return ret; } -static int decide_blocktype(const u8 *cur, const u8 *reference, - s16 *deltablock, unsigned int stride, - unsigned int input_step) +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]; @@ -632,12 +639,13 @@ static int decide_blocktype(const u8 *cur, const u8 *reference, return vari <= vard ? IBLOCK : PBLOCK; } -static void fill_decoder_block(u8 *dst, const s16 *input, int stride) +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++) { + for (j = 0; j < 8; j++, input++, dst += dst_step) { if (*input < 0) *dst = 0; else if (*input > 255) @@ -645,17 +653,19 @@ static void fill_decoder_block(u8 *dst, const s16 *input, int stride) else *dst = *input; } - dst += stride - 8; + dst += stride - (8 * dst_step); } } -static void add_deltas(s16 *deltas, const u8 *ref, int stride) +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++; + *deltas += *ref; + ref += ref_step; /* * Due to quantizing, it might possible that the * decoded coefficients are slightly out of range @@ -666,7 +676,7 @@ static void add_deltas(s16 *deltas, const u8 *ref, int stride) *deltas = 255; deltas++; } - ref += stride - 8; + ref += stride - (8 * ref_step); } } @@ -711,8 +721,8 @@ static u32 encode_plane(u8 *input, u8 *refp, __be16 **rlco, __be16 *rlco_max, ifwht(cf->de_coeffs, cf->de_fwht, blocktype); if (blocktype == PBLOCK) - add_deltas(cf->de_fwht, refp, 8); - fill_decoder_block(refp, cf->de_fwht, 8); + add_deltas(cf->de_fwht, refp, 8, 1); + fill_decoder_block(refp, cf->de_fwht, 8, 1); } input += 8 * input_step; @@ -821,23 +831,31 @@ u32 fwht_encode_frame(struct fwht_raw_frame *frm, return encoding; } -static bool decode_plane(struct fwht_cframe *cf, const __be16 **rlco, u8 *ref, - u32 height, u32 width, u32 coded_width, +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; - memcpy(ref, *rlco, width * height); - *rlco += width * height / 2; + for (i = 0; i < height; i++) { + memcpy(dst, *rlco, width); + dst += dst_stride; + *rlco += width / 2; + } return true; } @@ -849,15 +867,17 @@ static bool decode_plane(struct fwht_cframe *cf, const __be16 **rlco, u8 *ref, */ for (j = 0; j < height / 8; j++) { for (i = 0; i < width / 8; i++) { - u8 *refp = ref + j * 8 * coded_width + i * 8; + 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) + if ((stat & PFRAME_BIT) && !is_intra) add_deltas(cf->de_fwht, refp, - coded_width); - fill_decoder_block(refp, cf->de_fwht, - coded_width); + ref_stride, ref_step); + fill_decoder_block(dstp, cf->de_fwht, + dst_stride, dst_step); copies--; continue; } @@ -865,35 +885,41 @@ static bool decode_plane(struct fwht_cframe *cf, const __be16 **rlco, u8 *ref, stat = derlc(rlco, cf->coeffs, end_of_rlco_buf); if (stat & OVERFLOW_BIT) return false; - if (stat & PFRAME_BIT) + if ((stat & PFRAME_BIT) && !is_intra) dequantize_inter(cf->coeffs); else dequantize_intra(cf->coeffs); ifwht(cf->coeffs, cf->de_fwht, - (stat & PFRAME_BIT) ? 0 : 1); + ((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) - add_deltas(cf->de_fwht, refp, coded_width); - fill_decoder_block(refp, cf->de_fwht, coded_width); + 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, struct fwht_raw_frame *ref, - u32 hdr_flags, unsigned int components_num, - unsigned int width, unsigned int height, - unsigned int coded_width) +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, ref->luma, height, width, coded_width, + 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; @@ -901,27 +927,30 @@ bool fwht_decode_frame(struct fwht_cframe *cf, struct fwht_raw_frame *ref, if (components_num >= 3) { u32 h = height; u32 w = width; - u32 c = coded_width; if (!(hdr_flags & FWHT_FL_CHROMA_FULL_HEIGHT)) h /= 2; - if (!(hdr_flags & FWHT_FL_CHROMA_FULL_WIDTH)) { + if (!(hdr_flags & FWHT_FL_CHROMA_FULL_WIDTH)) w /= 2; - c /= 2; - } - if (!decode_plane(cf, &rlco, ref->cb, h, w, c, + + 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, ref->cr, h, w, c, + 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, ref->alpha, height, width, - coded_width, + 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; diff --git a/drivers/media/platform/vicodec/codec-fwht.h b/drivers/media/platform/vicodec/codec-fwht.h index c410512d47c5..b6fec2b1cbca 100644 --- a/drivers/media/platform/vicodec/codec-fwht.h +++ b/drivers/media/platform/vicodec/codec-fwht.h @@ -124,6 +124,7 @@ struct fwht_raw_frame { unsigned int luma_alpha_step; unsigned int chroma_step; unsigned int components_num; + u8 *buf; u8 *luma, *cb, *cr, *alpha; }; @@ -140,9 +141,10 @@ u32 fwht_encode_frame(struct fwht_raw_frame *frm, 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, struct fwht_raw_frame *ref, - u32 hdr_flags, unsigned int components_num, - unsigned int width, unsigned int height, - unsigned int coded_width); - +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 index 6573a471c5ca..01e7f09efc4e 100644 --- a/drivers/media/platform/vicodec/codec-v4l2-fwht.c +++ b/drivers/media/platform/vicodec/codec-v4l2-fwht.c @@ -37,7 +37,19 @@ static const struct v4l2_fwht_pixfmt_info v4l2_fwht_pixfmts[] = { { V4L2_PIX_FMT_GREY, 1, 1, 1, 1, 0, 1, 1, 1, 1, FWHT_FL_PIXENC_RGB}, }; -const struct v4l2_fwht_pixfmt_info *v4l2_fwht_default_fmt(u32 width_div, +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, @@ -46,10 +58,10 @@ const struct v4l2_fwht_pixfmt_info *v4l2_fwht_default_fmt(u32 width_div, unsigned int i; for (i = 0; i < ARRAY_SIZE(v4l2_fwht_pixfmts); i++) { - if (v4l2_fwht_pixfmts[i].width_div == width_div && - v4l2_fwht_pixfmts[i].height_div == height_div && - (!pixenc || v4l2_fwht_pixfmts[i].pixenc == pixenc) && - v4l2_fwht_pixfmts[i].components_num == components_num) { + 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--; @@ -75,117 +87,141 @@ const struct v4l2_fwht_pixfmt_info *v4l2_fwht_get_pixfmt(u32 idx) return v4l2_fwht_pixfmts + idx; } -int v4l2_fwht_encode(struct v4l2_fwht_state *state, u8 *p_in, u8 *p_out) +static int prepare_raw_frame(struct fwht_raw_frame *rf, + const struct v4l2_fwht_pixfmt_info *info, u8 *buf, + unsigned int size) { - 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; - - rf.luma = p_in; - 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; + 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; + rf->cb = NULL; + rf->cr = NULL; break; case V4L2_PIX_FMT_YUV420: - rf.cb = rf.luma + size; - rf.cr = rf.cb + size / 4; - chroma_stride /= 2; + 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; - chroma_stride /= 2; + 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; - chroma_stride /= 2; + 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; + 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; + 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; + 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; + 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++; + 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++; + 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++; + 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++; + 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: - rf.cr = rf.luma + 1; - rf.cb = rf.cr + 2; - rf.luma += 2; + rf->cr = rf->luma + 1; + rf->cb = rf->cr + 2; + rf->luma += 2; break; case V4L2_PIX_FMT_BGR32: case V4L2_PIX_FMT_XBGR32: - rf.cb = rf.luma; - rf.cr = rf.cb + 2; - rf.luma++; + rf->cb = rf->luma; + rf->cr = rf->cb + 2; + rf->luma++; break; case V4L2_PIX_FMT_ARGB32: - rf.alpha = rf.luma; - rf.cr = rf.luma + 1; - rf.cb = rf.cr + 2; - rf.luma += 2; + rf->alpha = rf->luma; + rf->cr = rf->luma + 1; + rf->cb = rf->cr + 2; + rf->luma += 2; break; case V4L2_PIX_FMT_ABGR32: - rf.cb = rf.luma; - rf.cr = rf.cb + 2; - rf.luma++; - rf.alpha = rf.cr + 1; + rf->cb = rf->luma; + rf->cr = rf->cb + 2; + rf->luma++; + rf->alpha = rf->cr + 1; 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; @@ -235,14 +271,17 @@ 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) { - unsigned int i, j, k; u32 flags; struct fwht_cframe cf; - u8 *p, *ref_p; 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; @@ -290,241 +329,29 @@ int v4l2_fwht_decode(struct v4l2_fwht_state *state, u8 *p_in, u8 *p_out) hdr_height_div != info->height_div) return -EINVAL; - if (!fwht_decode_frame(&cf, &state->ref_frame, flags, components_num, - state->visible_width, state->visible_height, - state->coded_width)) + 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; + } - /* - * TODO - handle the case where the compressed stream encodes a - * different format than the requested decoded format. - */ - switch (state->info->id) { - case V4L2_PIX_FMT_GREY: - ref_p = state->ref_frame.luma; - for (i = 0; i < state->coded_height; i++) { - memcpy(p_out, ref_p, state->visible_width); - p_out += state->stride; - ref_p += state->coded_width; - } - break; - case V4L2_PIX_FMT_YUV420: - case V4L2_PIX_FMT_YUV422P: - ref_p = state->ref_frame.luma; - for (i = 0; i < state->coded_height; i++) { - memcpy(p_out, ref_p, state->visible_width); - p_out += state->stride; - ref_p += state->coded_width; - } - ref_p = state->ref_frame.cb; - for (i = 0; i < state->coded_height / 2; i++) { - memcpy(p_out, ref_p, state->visible_width / 2); - p_out += state->stride / 2; - ref_p += state->coded_width / 2; - } - ref_p = state->ref_frame.cr; - for (i = 0; i < state->coded_height / 2; i++) { - memcpy(p_out, ref_p, state->visible_width / 2); - p_out += state->stride / 2; - ref_p += state->coded_width / 2; - } - break; - case V4L2_PIX_FMT_YVU420: - ref_p = state->ref_frame.luma; - for (i = 0; i < state->coded_height; i++) { - memcpy(p_out, ref_p, state->visible_width); - p_out += state->stride; - ref_p += state->coded_width; - } - - ref_p = state->ref_frame.cr; - for (i = 0; i < state->coded_height / 2; i++) { - memcpy(p_out, ref_p, state->visible_width / 2); - p_out += state->stride / 2; - ref_p += state->coded_width / 2; - } - ref_p = state->ref_frame.cb; - for (i = 0; i < state->coded_height / 2; i++) { - memcpy(p_out, ref_p, state->visible_width / 2); - p_out += state->stride / 2; - ref_p += state->coded_width / 2; - } - break; - case V4L2_PIX_FMT_NV12: - case V4L2_PIX_FMT_NV16: - case V4L2_PIX_FMT_NV24: - ref_p = state->ref_frame.luma; - for (i = 0; i < state->coded_height; i++) { - memcpy(p_out, ref_p, state->visible_width); - p_out += state->stride; - ref_p += state->coded_width; - } + ref_size = state->ref_stride * state->coded_height; - k = 0; - for (i = 0; i < state->coded_height / 2; i++) { - for (j = 0, p = p_out; j < state->coded_width / 2; j++) { - *p++ = state->ref_frame.cb[k]; - *p++ = state->ref_frame.cr[k]; - k++; - } - p_out += state->stride; - } - break; - case V4L2_PIX_FMT_NV21: - case V4L2_PIX_FMT_NV61: - case V4L2_PIX_FMT_NV42: - ref_p = state->ref_frame.luma; - for (i = 0; i < state->coded_height; i++) { - memcpy(p_out, ref_p, state->visible_width); - p_out += state->stride; - ref_p += state->coded_width; - } + if (prepare_raw_frame(&state->ref_frame, info, state->ref_frame.buf, + ref_size)) + return -EINVAL; - k = 0; - for (i = 0; i < state->coded_height / 2; i++) { - for (j = 0, p = p_out; j < state->coded_width / 2; j++) { - *p++ = state->ref_frame.cr[k]; - *p++ = state->ref_frame.cb[k]; - k++; - } - p_out += state->stride; - } - break; - case V4L2_PIX_FMT_YUYV: - k = 0; - for (i = 0; i < state->coded_height; i++) { - for (j = 0, p = p_out; j < state->coded_width / 2; j++) { - *p++ = state->ref_frame.luma[k]; - *p++ = state->ref_frame.cb[k / 2]; - *p++ = state->ref_frame.luma[k + 1]; - *p++ = state->ref_frame.cr[k / 2]; - k += 2; - } - p_out += state->stride; - } - break; - case V4L2_PIX_FMT_YVYU: - k = 0; - for (i = 0; i < state->coded_height; i++) { - for (j = 0, p = p_out; j < state->coded_width / 2; j++) { - *p++ = state->ref_frame.luma[k]; - *p++ = state->ref_frame.cr[k / 2]; - *p++ = state->ref_frame.luma[k + 1]; - *p++ = state->ref_frame.cb[k / 2]; - k += 2; - } - p_out += state->stride; - } - break; - case V4L2_PIX_FMT_UYVY: - k = 0; - for (i = 0; i < state->coded_height; i++) { - for (j = 0, p = p_out; j < state->coded_width / 2; j++) { - *p++ = state->ref_frame.cb[k / 2]; - *p++ = state->ref_frame.luma[k]; - *p++ = state->ref_frame.cr[k / 2]; - *p++ = state->ref_frame.luma[k + 1]; - k += 2; - } - p_out += state->stride; - } - break; - case V4L2_PIX_FMT_VYUY: - k = 0; - for (i = 0; i < state->coded_height; i++) { - for (j = 0, p = p_out; j < state->coded_width / 2; j++) { - *p++ = state->ref_frame.cr[k / 2]; - *p++ = state->ref_frame.luma[k]; - *p++ = state->ref_frame.cb[k / 2]; - *p++ = state->ref_frame.luma[k + 1]; - k += 2; - } - p_out += state->stride; - } - break; - case V4L2_PIX_FMT_RGB24: - case V4L2_PIX_FMT_HSV24: - k = 0; - for (i = 0; i < state->coded_height; i++) { - for (j = 0, p = p_out; j < state->coded_width; j++) { - *p++ = state->ref_frame.cr[k]; - *p++ = state->ref_frame.luma[k]; - *p++ = state->ref_frame.cb[k]; - k++; - } - p_out += state->stride; - } - break; - case V4L2_PIX_FMT_BGR24: - k = 0; - for (i = 0; i < state->coded_height; i++) { - for (j = 0, p = p_out; j < state->coded_width; j++) { - *p++ = state->ref_frame.cb[k]; - *p++ = state->ref_frame.luma[k]; - *p++ = state->ref_frame.cr[k]; - k++; - } - p_out += state->stride; - } - break; - case V4L2_PIX_FMT_RGB32: - case V4L2_PIX_FMT_XRGB32: - case V4L2_PIX_FMT_HSV32: - k = 0; - for (i = 0; i < state->coded_height; i++) { - for (j = 0, p = p_out; j < state->coded_width; j++) { - *p++ = 0; - *p++ = state->ref_frame.cr[k]; - *p++ = state->ref_frame.luma[k]; - *p++ = state->ref_frame.cb[k]; - k++; - } - p_out += state->stride; - } - break; - case V4L2_PIX_FMT_BGR32: - case V4L2_PIX_FMT_XBGR32: - k = 0; - for (i = 0; i < state->coded_height; i++) { - for (j = 0, p = p_out; j < state->coded_width; j++) { - *p++ = state->ref_frame.cb[k]; - *p++ = state->ref_frame.luma[k]; - *p++ = state->ref_frame.cr[k]; - *p++ = 0; - k++; - } - p_out += state->stride; - } - break; - case V4L2_PIX_FMT_ARGB32: - k = 0; - for (i = 0; i < state->coded_height; i++) { - for (j = 0, p = p_out; j < state->coded_width; j++) { - *p++ = state->ref_frame.alpha[k]; - *p++ = state->ref_frame.cr[k]; - *p++ = state->ref_frame.luma[k]; - *p++ = state->ref_frame.cb[k]; - k++; - } - p_out += state->stride; - } - break; - case V4L2_PIX_FMT_ABGR32: - k = 0; - for (i = 0; i < state->coded_height; i++) { - for (j = 0, p = p_out; j < state->coded_width; j++) { - *p++ = state->ref_frame.cb[k]; - *p++ = state->ref_frame.luma[k]; - *p++ = state->ref_frame.cr[k]; - *p++ = state->ref_frame.alpha[k]; - k++; - } - p_out += state->stride; - } - break; - default: + 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 index aa6fa90a48be..1a0d2a9f931a 100644 --- a/drivers/media/platform/vicodec/codec-v4l2-fwht.h +++ b/drivers/media/platform/vicodec/codec-v4l2-fwht.h @@ -30,6 +30,7 @@ struct v4l2_fwht_state { 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; @@ -43,11 +44,15 @@ struct v4l2_fwht_state { 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); -const struct v4l2_fwht_pixfmt_info *v4l2_fwht_default_fmt(u32 width_div, +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, diff --git a/drivers/media/platform/vicodec/vicodec-core.c b/drivers/media/platform/vicodec/vicodec-core.c index d7636fe9e174..bd01a9206aa6 100644 --- a/drivers/media/platform/vicodec/vicodec-core.c +++ b/drivers/media/platform/vicodec/vicodec-core.c @@ -64,6 +64,10 @@ 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) { } @@ -89,27 +93,29 @@ enum { 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 video_device enc_vfd; - struct video_device dec_vfd; + 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 mutex enc_mutex; - struct mutex dec_mutex; - spinlock_t enc_lock; - spinlock_t dec_lock; - - struct v4l2_m2m_dev *enc_dev; - struct v4l2_m2m_dev *dec_dev; }; 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; @@ -148,27 +154,149 @@ static struct vicodec_q_data *get_q_data(struct vicodec_ctx *ctx, case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: return &ctx->q_data[V4L2_M2M_DST]; default: - WARN_ON(1); 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 vicodec_q_data *q_dst; struct v4l2_fwht_state *state = &ctx->state; u8 *p_src, *p_dst; - int ret; + int ret = 0; - q_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); - if (ctx->is_enc) + 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, @@ -178,30 +306,31 @@ static int device_process(struct vicodec_ctx *ctx, 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; - ret = v4l2_fwht_encode(state, p_src, p_dst); - if (ret < 0) - return ret; - vb2_set_plane_payload(&dst_vb->vb2_buf, 0, ret); + 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); } - - dst_vb->sequence = q_dst->sequence++; - dst_vb->flags &= ~V4L2_BUF_FLAG_LAST; - v4l2_m2m_buf_copy_metadata(src_vb, dst_vb, !ctx->is_enc); - - return 0; + return ret; } /* @@ -274,16 +403,26 @@ 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; + 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, !ctx->is_enc); + ctx->last_dst_buf = dst_buf; spin_lock(ctx->lock); @@ -291,7 +430,7 @@ static void device_run(void *priv) dst_buf->flags |= V4L2_BUF_FLAG_LAST; v4l2_event_queue_fh(&ctx->fh, &eos_event); } - if (ctx->is_enc) { + 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); @@ -303,6 +442,9 @@ static void device_run(void *priv) ctx->comp_has_next_frame = false; } v4l2_m2m_buf_done(dst_buf, state); + if (ctx->is_stateless && src_req) + v4l2_ctrl_request_complete(src_req, &ctx->hdl); + ctx->comp_size = 0; ctx->header_size = 0; ctx->comp_magic_cnt = 0; @@ -310,9 +452,12 @@ static void device_run(void *priv) spin_unlock(ctx->lock); if (ctx->is_enc) - v4l2_m2m_job_finish(dev->enc_dev, ctx->fh.m2m_ctx); + 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->dec_dev, ctx->fh.m2m_ctx); + 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) @@ -344,7 +489,7 @@ info_from_header(const struct fwht_cframe_hdr *p_hdr) FWHT_FL_COMPONENTS_NUM_OFFSET); pixenc = (flags & FWHT_FL_PIXENC_MSK); } - return v4l2_fwht_default_fmt(width_div, height_div, + return v4l2_fwht_find_nth_fmt(width_div, height_div, components_num, pixenc, 0); } @@ -356,21 +501,11 @@ static bool is_header_valid(const struct fwht_cframe_hdr *p_hdr) unsigned int version = ntohl(p_hdr->version); unsigned int flags = ntohl(p_hdr->flags); - if (!version || version > FWHT_VERSION) - return false; - if (w < MIN_WIDTH || w > MAX_WIDTH || h < MIN_HEIGHT || h > MAX_HEIGHT) 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; - } + if (!validate_by_version(flags, version)) + return false; info = info_from_header(p_hdr); if (!info) @@ -388,6 +523,12 @@ static void update_capture_data_from_header(struct vicodec_ctx *ctx) 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); @@ -440,7 +581,7 @@ static int job_ready(void *priv) if (ctx->source_changed) return 0; - if (ctx->is_enc || ctx->comp_has_frame) + if (ctx->is_stateless || ctx->is_enc || ctx->comp_has_frame) return 1; restart: @@ -551,8 +692,8 @@ static const struct v4l2_fwht_pixfmt_info *find_fmt(u32 fmt) static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - strncpy(cap->driver, VICODEC_NAME, sizeof(cap->driver) - 1); - strncpy(cap->card, VICODEC_NAME, sizeof(cap->card) - 1); + 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; @@ -575,7 +716,7 @@ static int enum_fmt(struct v4l2_fmtdesc *f, struct vicodec_ctx *ctx, if (!info || ctx->is_enc) info = v4l2_fwht_get_pixfmt(f->index); else - info = v4l2_fwht_default_fmt(info->width_div, + info = v4l2_fwht_find_nth_fmt(info->width_div, info->height_div, info->components_num, info->pixenc, @@ -586,7 +727,8 @@ static int enum_fmt(struct v4l2_fmtdesc *f, struct vicodec_ctx *ctx, } else { if (f->index) return -EINVAL; - f->pixelformat = V4L2_PIX_FMT_FWHT; + f->pixelformat = ctx->is_stateless ? + V4L2_PIX_FMT_FWHT_STATELESS : V4L2_PIX_FMT_FWHT; } return 0; } @@ -688,13 +830,15 @@ 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 = &pixfmt_fwht; + 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) + 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); @@ -715,7 +859,8 @@ static int vidioc_try_fmt(struct vicodec_ctx *ctx, struct v4l2_format *f) 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) + 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; @@ -792,8 +937,12 @@ static int vidioc_try_fmt_vid_out(struct file *file, void *priv, if (multiplanar) return -EINVAL; pix = &f->fmt.pix; - pix->pixelformat = !ctx->is_enc ? V4L2_PIX_FMT_FWHT : - find_fmt(pix->pixelformat)->id; + 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; @@ -801,8 +950,12 @@ static int vidioc_try_fmt_vid_out(struct file *file, void *priv, 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; + 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; @@ -845,6 +998,8 @@ static int vidioc_s_fmt(struct vicodec_ctx *ctx, struct v4l2_format *f) 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; @@ -866,6 +1021,8 @@ static int vidioc_s_fmt(struct vicodec_ctx *ctx, struct v4l2_format *f) 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; @@ -945,16 +1102,6 @@ static int vidioc_g_selection(struct file *file, void *priv, { struct vicodec_ctx *ctx = file2ctx(file); struct vicodec_q_data *q_data; - enum v4l2_buf_type valid_cap_type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - enum v4l2_buf_type valid_out_type = V4L2_BUF_TYPE_VIDEO_OUTPUT; - - if (multiplanar) { - valid_cap_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; - valid_out_type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; - } - - if (s->type != valid_cap_type && s->type != valid_out_type) - return -EINVAL; q_data = get_q_data(ctx, s->type); if (!q_data) @@ -963,18 +1110,14 @@ static int vidioc_g_selection(struct file *file, void *priv, * encoder supports only cropping on the OUTPUT buffer * decoder supports only composing on the CAPTURE buffer */ - if ((ctx->is_enc && s->type == valid_out_type) || - (!ctx->is_enc && s->type == valid_cap_type)) { + if (ctx->is_enc && s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { switch (s->target) { - case V4L2_SEL_TGT_COMPOSE: 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_COMPOSE_DEFAULT: - case V4L2_SEL_TGT_COMPOSE_BOUNDS: case V4L2_SEL_TGT_CROP_DEFAULT: case V4L2_SEL_TGT_CROP_BOUNDS: s->r.left = 0; @@ -983,6 +1126,22 @@ static int vidioc_g_selection(struct file *file, void *priv, 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; } @@ -992,12 +1151,8 @@ static int vidioc_s_selection(struct file *file, void *priv, { struct vicodec_ctx *ctx = file2ctx(file); struct vicodec_q_data *q_data; - enum v4l2_buf_type out_type = V4L2_BUF_TYPE_VIDEO_OUTPUT; - - if (multiplanar) - out_type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; - if (s->type != out_type) + if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) return -EINVAL; q_data = get_q_data(ctx, s->type); @@ -1092,6 +1247,8 @@ 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: @@ -1200,6 +1357,14 @@ static int vicodec_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, 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); @@ -1263,10 +1428,11 @@ static void vicodec_buf_queue(struct vb2_buffer *vb) } /* - * source change event is relevant only for the decoder + * source change event is relevant only for the stateful decoder * in the compressed stream */ - if (ctx->is_enc || !V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) { + 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; } @@ -1314,12 +1480,33 @@ static void vicodec_return_bufs(struct vb2_queue *q, u32 state) 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) { @@ -1330,7 +1517,7 @@ static int vicodec_start_streaming(struct vb2_queue *q, unsigned int size = q_data->coded_width * q_data->coded_height; unsigned int chroma_div; unsigned int total_planes_size; - u8 *new_comp_frame; + u8 *new_comp_frame = NULL; if (!info) return -EINVAL; @@ -1338,24 +1525,24 @@ static int vicodec_start_streaming(struct vb2_queue *q, chroma_div = info->width_div * info->height_div; q_data->sequence = 0; - ctx->last_src_buf = NULL; - ctx->last_dst_buf = NULL; + if (V4L2_TYPE_IS_OUTPUT(q->type)) + ctx->last_src_buf = NULL; + else + ctx->last_dst_buf = NULL; + 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) { + if (info->id == V4L2_PIX_FMT_FWHT || + info->id == V4L2_PIX_FMT_FWHT_STATELESS) { vicodec_return_bufs(q, VB2_BUF_STATE_QUEUED); return -EINVAL; } - if (info->components_num == 4) - total_planes_size = 2 * size + 2 * (size / chroma_div); - else if (info->components_num == 3) - total_planes_size = size + 2 * (size / chroma_div); - else - total_planes_size = size; + 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; @@ -1364,8 +1551,14 @@ static int vicodec_start_streaming(struct vb2_queue *q, state->stride = q_data->coded_width * info->bytesperline_mult; - state->ref_frame.luma = kvmalloc(total_planes_size, GFP_KERNEL); - ctx->comp_max_size = total_planes_size; + 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) { @@ -1413,7 +1606,10 @@ static void vicodec_stop_streaming(struct vb2_queue *q) if ((!V4L2_TYPE_IS_OUTPUT(q->type) && !ctx->is_enc) || (V4L2_TYPE_IS_OUTPUT(q->type) && ctx->is_enc)) { - kvfree(ctx->state.ref_frame.luma); + 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; } @@ -1427,14 +1623,24 @@ static void vicodec_stop_streaming(struct vb2_queue *q) } } +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_prepare = vicodec_buf_prepare, - .buf_queue = vicodec_buf_queue, - .start_streaming = vicodec_start_streaming, - .stop_streaming = vicodec_stop_streaming, - .wait_prepare = vb2_ops_wait_prepare, - .wait_finish = vb2_ops_wait_finish, + .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, @@ -1452,9 +1658,14 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, src_vq->ops = &vicodec_qops; src_vq->mem_ops = &vb2_vmalloc_memops; src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; - src_vq->lock = ctx->is_enc ? &ctx->dev->enc_mutex : - &ctx->dev->dec_mutex; - + 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; @@ -1473,53 +1684,86 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, return vb2_queue_init(dst_vq); } -#define VICODEC_CID_CUSTOM_BASE (V4L2_CID_MPEG_BASE | 0xf000) -#define VICODEC_CID_I_FRAME_QP (VICODEC_CID_CUSTOM_BASE + 0) -#define VICODEC_CID_P_FRAME_QP (VICODEC_CID_CUSTOM_BASE + 1) +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 VICODEC_CID_I_FRAME_QP: + case V4L2_CID_FWHT_I_FRAME_QP: ctx->state.i_frame_qp = ctrl->val; return 0; - case VICODEC_CID_P_FRAME_QP: + 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_i_frame = { - .ops = &vicodec_ctrl_ops, - .id = VICODEC_CID_I_FRAME_QP, - .name = "FWHT I-Frame QP Value", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = 1, - .max = 31, - .def = 20, - .step = 1, -}; - -static const struct v4l2_ctrl_config vicodec_ctrl_p_frame = { - .ops = &vicodec_ctrl_ops, - .id = VICODEC_CID_P_FRAME_QP, - .name = "FWHT P-Frame QP Value", - .type = V4L2_CTRL_TYPE_INTEGER, - .min = 1, - .max = 31, - .def = 20, - .step = 1, +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), }; /* @@ -1542,8 +1786,10 @@ static int vicodec_open(struct file *file) goto open_unlock; } - if (vfd == &dev->enc_vfd) + 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; @@ -1552,8 +1798,12 @@ static int vicodec_open(struct file *file) v4l2_ctrl_handler_init(hdl, 4); v4l2_ctrl_new_std(hdl, &vicodec_ctrl_ops, V4L2_CID_MPEG_VIDEO_GOP_SIZE, 1, 16, 1, 10); - v4l2_ctrl_new_custom(hdl, &vicodec_ctrl_i_frame, NULL); - v4l2_ctrl_new_custom(hdl, &vicodec_ctrl_p_frame, NULL); + 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_stateless) + v4l2_ctrl_new_custom(hdl, &vicodec_ctrl_stateless_state, NULL); if (hdl->error) { rc = hdl->error; v4l2_ctrl_handler_free(hdl); @@ -1563,15 +1813,19 @@ static int vicodec_open(struct file *file) ctx->fh.ctrl_handler = hdl; v4l2_ctrl_handler_setup(hdl); - ctx->q_data[V4L2_M2M_SRC].info = - ctx->is_enc ? v4l2_fwht_get_pixfmt(0) : &pixfmt_fwht; + if (ctx->is_enc) + ctx->q_data[V4L2_M2M_SRC].info = v4l2_fwht_get_pixfmt(0); + 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; size = 1280 * 720 * ctx->q_data[V4L2_M2M_SRC].info->sizeimage_mult / ctx->q_data[V4L2_M2M_SRC].info->sizeimage_div; - if (ctx->is_enc) + if (ctx->is_enc || ctx->is_stateless) ctx->q_data[V4L2_M2M_SRC].sizeimage = size; else ctx->q_data[V4L2_M2M_SRC].sizeimage = @@ -1590,13 +1844,17 @@ static int vicodec_open(struct file *file) ctx->state.colorspace = V4L2_COLORSPACE_REC709; if (ctx->is_enc) { - ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->enc_dev, ctx, - &queue_init); - ctx->lock = &dev->enc_lock; + 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->dec_dev, ctx, - &queue_init); - ctx->lock = &dev->dec_lock; + 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)) { @@ -1620,17 +1878,71 @@ static int vicodec_release(struct file *file) struct video_device *vfd = video_devdata(file); struct vicodec_ctx *ctx = file2ctx(file); - v4l2_fh_del(&ctx->fh); - v4l2_fh_exit(&ctx->fh); - v4l2_ctrl_handler_free(&ctx->hdl); 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, @@ -1649,24 +1961,67 @@ static const struct video_device vicodec_videodev = { .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_GRABBER, 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 int vicodec_probe(struct platform_device *pdev) { struct vicodec_dev *dev; - struct video_device *vfd; int ret; dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); if (!dev) return -ENOMEM; - spin_lock_init(&dev->enc_lock); - spin_lock_init(&dev->dec_lock); - ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); if (ret) return ret; @@ -1677,103 +2032,74 @@ static int vicodec_probe(struct platform_device *pdev) 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 - mutex_init(&dev->enc_mutex); - mutex_init(&dev->dec_mutex); - platform_set_drvdata(pdev, dev); - dev->enc_dev = v4l2_m2m_init(&m2m_ops); - if (IS_ERR(dev->enc_dev)) { - v4l2_err(&dev->v4l2_dev, "Failed to init vicodec device\n"); - ret = PTR_ERR(dev->enc_dev); + if (register_instance(dev, &dev->stateful_enc, + "stateful-encoder", true)) goto unreg_dev; - } - dev->dec_dev = v4l2_m2m_init(&m2m_ops); - if (IS_ERR(dev->dec_dev)) { - v4l2_err(&dev->v4l2_dev, "Failed to init vicodec device\n"); - ret = PTR_ERR(dev->dec_dev); - goto err_enc_m2m; - } + if (register_instance(dev, &dev->stateful_dec, + "stateful-decoder", false)) + goto unreg_sf_enc; - dev->enc_vfd = vicodec_videodev; - vfd = &dev->enc_vfd; - vfd->lock = &dev->enc_mutex; - vfd->v4l2_dev = &dev->v4l2_dev; - strscpy(vfd->name, "vicodec-enc", sizeof(vfd->name)); - vfd->device_caps = V4L2_CAP_STREAMING | - (multiplanar ? V4L2_CAP_VIDEO_M2M_MPLANE : V4L2_CAP_VIDEO_M2M); - v4l2_disable_ioctl(vfd, VIDIOC_DECODER_CMD); - v4l2_disable_ioctl(vfd, VIDIOC_TRY_DECODER_CMD); - video_set_drvdata(vfd, dev); - - ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0); - if (ret) { - v4l2_err(&dev->v4l2_dev, "Failed to register video device\n"); - goto err_dec_m2m; - } - v4l2_info(&dev->v4l2_dev, - "Device registered as /dev/video%d\n", vfd->num); + if (register_instance(dev, &dev->stateless_dec, + "stateless-decoder", false)) + goto unreg_sf_dec; - dev->dec_vfd = vicodec_videodev; - vfd = &dev->dec_vfd; - vfd->lock = &dev->dec_mutex; - vfd->v4l2_dev = &dev->v4l2_dev; - vfd->device_caps = V4L2_CAP_STREAMING | - (multiplanar ? V4L2_CAP_VIDEO_M2M_MPLANE : V4L2_CAP_VIDEO_M2M); - strscpy(vfd->name, "vicodec-dec", sizeof(vfd->name)); - 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_GRABBER, 0); +#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 register video device\n"); - goto unreg_enc; + v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem media controller for enc\n"); + goto unreg_m2m; } - v4l2_info(&dev->v4l2_dev, - "Device registered as /dev/video%d\n", vfd->num); -#ifdef CONFIG_MEDIA_CONTROLLER - ret = v4l2_m2m_register_media_controller(dev->enc_dev, - &dev->enc_vfd, MEDIA_ENT_F_PROC_VIDEO_ENCODER); + 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\n"); - goto unreg_m2m; + 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->dec_dev, - &dev->dec_vfd, MEDIA_ENT_F_PROC_VIDEO_DECODER); + 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\n"); - goto unreg_m2m_enc_mc; + 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_dec_mc; + goto unreg_m2m_sl_dec_mc; } #endif return 0; #ifdef CONFIG_MEDIA_CONTROLLER -unreg_m2m_dec_mc: - v4l2_m2m_unregister_media_controller(dev->dec_dev); -unreg_m2m_enc_mc: - v4l2_m2m_unregister_media_controller(dev->enc_dev); +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->dec_vfd); + video_unregister_device(&dev->stateless_dec.vfd); + v4l2_m2m_release(dev->stateless_dec.m2m_dev); #endif -unreg_enc: - video_unregister_device(&dev->enc_vfd); -err_dec_m2m: - v4l2_m2m_release(dev->dec_dev); -err_enc_m2m: - v4l2_m2m_release(dev->enc_dev); +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); @@ -1788,15 +2114,17 @@ static int vicodec_remove(struct platform_device *pdev) #ifdef CONFIG_MEDIA_CONTROLLER media_device_unregister(&dev->mdev); - v4l2_m2m_unregister_media_controller(dev->enc_dev); - v4l2_m2m_unregister_media_controller(dev->dec_dev); + 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); media_device_cleanup(&dev->mdev); #endif - v4l2_m2m_release(dev->enc_dev); - v4l2_m2m_release(dev->dec_dev); - video_unregister_device(&dev->enc_vfd); - video_unregister_device(&dev->dec_vfd); + v4l2_m2m_release(dev->stateful_enc.m2m_dev); + v4l2_m2m_release(dev->stateful_dec.m2m_dev); + video_unregister_device(&dev->stateful_enc.vfd); + video_unregister_device(&dev->stateful_dec.vfd); + video_unregister_device(&dev->stateless_dec.vfd); v4l2_device_unregister(&dev->v4l2_dev); return 0; diff --git a/drivers/media/platform/video-mux.c b/drivers/media/platform/video-mux.c index 0ba30756e1e4..d8cd5f5cb10d 100644 --- a/drivers/media/platform/video-mux.c +++ b/drivers/media/platform/video-mux.c @@ -419,9 +419,14 @@ static int video_mux_probe(struct platform_device *pdev) vmux->active = -1; vmux->pads = devm_kcalloc(dev, num_pads, sizeof(*vmux->pads), GFP_KERNEL); + if (!vmux->pads) + return -ENOMEM; + vmux->format_mbus = devm_kcalloc(dev, num_pads, sizeof(*vmux->format_mbus), GFP_KERNEL); + if (!vmux->format_mbus) + return -ENOMEM; for (i = 0; i < num_pads; i++) { vmux->pads[i].flags = (i < num_pads - 1) ? MEDIA_PAD_FL_SINK diff --git a/drivers/media/platform/vim2m.c b/drivers/media/platform/vim2m.c index 34dcaca45d8b..243c82b5d537 100644 --- a/drivers/media/platform/vim2m.c +++ b/drivers/media/platform/vim2m.c @@ -302,7 +302,7 @@ static void copy_two_pixels(struct vim2m_q_data *q_data_in, switch (in->fourcc) { case V4L2_PIX_FMT_RGB565: /* rrrrrggg gggbbbbb */ for (i = 0; i < 2; i++) { - u16 pix = *(u16 *)(src[i]); + u16 pix = le16_to_cpu(*(__le16 *)(src[i])); *r++ = (u8)(((pix & 0xf800) >> 11) << 3) | 0x07; *g++ = (u8)((((pix & 0x07e0) >> 5)) << 2) | 0x03; @@ -311,12 +311,11 @@ static void copy_two_pixels(struct vim2m_q_data *q_data_in, break; case V4L2_PIX_FMT_RGB565X: /* gggbbbbb rrrrrggg */ for (i = 0; i < 2; i++) { - u16 pix = *(u16 *)(src[i]); + u16 pix = be16_to_cpu(*(__be16 *)(src[i])); - *r++ = (u8)(((0x00f8 & pix) >> 3) << 3) | 0x07; - *g++ = (u8)(((pix & 0x7) << 2) | - ((pix & 0xe000) >> 5)) | 0x03; - *b++ = (u8)(((pix & 0x1f00) >> 8) << 3) | 0x07; + *r++ = (u8)(((pix & 0xf800) >> 11) << 3) | 0x07; + *g++ = (u8)((((pix & 0x07e0) >> 5)) << 2) | 0x03; + *b++ = (u8)((pix & 0x1f) << 3) | 0x07; } break; default: @@ -345,21 +344,26 @@ static void copy_two_pixels(struct vim2m_q_data *q_data_in, switch (out->fourcc) { case V4L2_PIX_FMT_RGB565: /* rrrrrggg gggbbbbb */ for (i = 0; i < 2; i++) { - u16 *pix = (u16 *)*dst; + u16 pix; + __le16 *dst_pix = (__le16 *)*dst; + + pix = ((*r << 8) & 0xf800) | ((*g << 3) & 0x07e0) | + (*b >> 3); - *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 = (u16 *)*dst; - u8 green = *g++ >> 2; + u16 pix; + __be16 *dst_pix = (__be16 *)*dst; - *pix = ((green << 8) & 0xe000) | (green & 0x07) | - ((*b++ << 5) & 0x1f00) | ((*r++ & 0xf8)); + pix = ((*r << 8) & 0xf800) | ((*g << 3) & 0x07e0) | + (*b >> 3); + + *dst_pix = cpu_to_be16(pix); *dst += 2; } @@ -655,8 +659,8 @@ static void device_work(struct work_struct *w) static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { - strncpy(cap->driver, MEM2MEM_NAME, sizeof(cap->driver) - 1); - strncpy(cap->card, MEM2MEM_NAME, sizeof(cap->card) - 1); + 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; @@ -1262,6 +1266,15 @@ static int vim2m_release(struct file *file) 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); + kfree(dev); +} + static const struct v4l2_file_operations vim2m_fops = { .owner = THIS_MODULE, .open = vim2m_open, @@ -1277,7 +1290,7 @@ static const struct video_device vim2m_videodev = { .fops = &vim2m_fops, .ioctl_ops = &vim2m_ioctl_ops, .minor = -1, - .release = video_device_release_empty, + .release = vim2m_device_release, .device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING, }; @@ -1298,13 +1311,13 @@ static int vim2m_probe(struct platform_device *pdev) struct video_device *vfd; int ret; - dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); + dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (!dev) return -ENOMEM; ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); if (ret) - return ret; + goto error_free; atomic_set(&dev->num_inst, 0); mutex_init(&dev->dev_mutex); @@ -1317,7 +1330,7 @@ static int vim2m_probe(struct platform_device *pdev) ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0); if (ret) { v4l2_err(&dev->v4l2_dev, "Failed to register video device\n"); - goto unreg_v4l2; + goto error_v4l2; } video_set_drvdata(vfd, dev); @@ -1330,7 +1343,7 @@ static int vim2m_probe(struct platform_device *pdev) if (IS_ERR(dev->m2m_dev)) { v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem device\n"); ret = PTR_ERR(dev->m2m_dev); - goto unreg_dev; + goto error_dev; } #ifdef CONFIG_MEDIA_CONTROLLER @@ -1346,27 +1359,29 @@ static int vim2m_probe(struct platform_device *pdev) MEDIA_ENT_F_PROC_VIDEO_SCALER); if (ret) { v4l2_err(&dev->v4l2_dev, "Failed to init mem2mem media controller\n"); - goto unreg_m2m; + goto error_m2m; } ret = media_device_register(&dev->mdev); if (ret) { v4l2_err(&dev->v4l2_dev, "Failed to register mem2mem media device\n"); - goto unreg_m2m_mc; + goto error_m2m_mc; } #endif return 0; #ifdef CONFIG_MEDIA_CONTROLLER -unreg_m2m_mc: +error_m2m_mc: v4l2_m2m_unregister_media_controller(dev->m2m_dev); -unreg_m2m: +error_m2m: v4l2_m2m_release(dev->m2m_dev); #endif -unreg_dev: +error_dev: video_unregister_device(&dev->vfd); -unreg_v4l2: +error_v4l2: v4l2_device_unregister(&dev->v4l2_dev); +error_free: + kfree(dev); return ret; } @@ -1382,9 +1397,7 @@ static int vim2m_remove(struct platform_device *pdev) v4l2_m2m_unregister_media_controller(dev->m2m_dev); media_device_cleanup(&dev->mdev); #endif - v4l2_m2m_release(dev->m2m_dev); video_unregister_device(&dev->vfd); - v4l2_device_unregister(&dev->v4l2_dev); return 0; } diff --git a/drivers/media/platform/vimc/Kconfig b/drivers/media/platform/vimc/Kconfig index 71c9fe7d3370..1de9bc9aa49b 100644 --- a/drivers/media/platform/vimc/Kconfig +++ b/drivers/media/platform/vimc/Kconfig @@ -4,7 +4,7 @@ config VIDEO_VIMC select VIDEOBUF2_VMALLOC select VIDEO_V4L2_TPG default n - ---help--- + help Skeleton driver for Virtual Media Controller This driver can be compared to the vivid driver for emulating diff --git a/drivers/media/platform/vimc/vimc-capture.c b/drivers/media/platform/vimc/vimc-capture.c index ea869631a3f6..e7d0fc2228a6 100644 --- a/drivers/media/platform/vimc/vimc-capture.c +++ b/drivers/media/platform/vimc/vimc-capture.c @@ -28,6 +28,32 @@ #define VIMC_CAP_DRV_NAME "vimc-capture" +static const u32 vimc_cap_supported_pixfmt[] = { + V4L2_PIX_FMT_BGR24, + V4L2_PIX_FMT_RGB24, + V4L2_PIX_FMT_ARGB32, + V4L2_PIX_FMT_SBGGR8, + V4L2_PIX_FMT_SGBRG8, + V4L2_PIX_FMT_SGRBG8, + V4L2_PIX_FMT_SRGGB8, + V4L2_PIX_FMT_SBGGR10, + V4L2_PIX_FMT_SGBRG10, + V4L2_PIX_FMT_SGRBG10, + V4L2_PIX_FMT_SRGGB10, + V4L2_PIX_FMT_SBGGR10ALAW8, + V4L2_PIX_FMT_SGBRG10ALAW8, + V4L2_PIX_FMT_SGRBG10ALAW8, + V4L2_PIX_FMT_SRGGB10ALAW8, + V4L2_PIX_FMT_SBGGR10DPCM8, + V4L2_PIX_FMT_SGBRG10DPCM8, + V4L2_PIX_FMT_SGRBG10DPCM8, + V4L2_PIX_FMT_SRGGB10DPCM8, + V4L2_PIX_FMT_SBGGR12, + V4L2_PIX_FMT_SGBRG12, + V4L2_PIX_FMT_SGRBG12, + V4L2_PIX_FMT_SRGGB12, +}; + struct vimc_cap_device { struct vimc_ent_device ved; struct video_device vdev; @@ -101,29 +127,25 @@ 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; + vimc_colorimetry_clamp(format); if (format->field == V4L2_FIELD_ANY) format->field = fmt_default.field; - vimc_colorimetry_clamp(format); + /* TODO: Add support for custom bytesperline values */ - return 0; + /* Don't accept a pixelformat that is not on the table */ + if (!v4l2_format_info(format->pixelformat)) + format->pixelformat = fmt_default.pixelformat; + + return v4l2_fill_pixfmt(format, format->pixelformat, + format->width, format->height); } static int vimc_cap_s_fmt_vid_cap(struct file *file, void *priv, @@ -159,27 +181,31 @@ static int vimc_cap_s_fmt_vid_cap(struct file *file, void *priv, 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) + if (f->index >= ARRAY_SIZE(vimc_cap_supported_pixfmt)) return -EINVAL; - f->pixelformat = vpix->pixelformat; + f->pixelformat = vimc_cap_supported_pixfmt[f->index]; return 0; } +static bool vimc_cap_is_pixfmt_supported(u32 pixelformat) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(vimc_cap_supported_pixfmt); i++) + if (vimc_cap_supported_pixfmt[i] == pixelformat) + return true; + return false; +} + 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) + if (!vimc_cap_is_pixfmt_supported(fsize->pixel_format)) return -EINVAL; fsize->type = V4L2_FRMSIZE_TYPE_CONTINUOUS; @@ -187,8 +213,8 @@ static int vimc_cap_enum_framesizes(struct file *file, void *fh, 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 = 2; - fsize->stepwise.step_height = 2; + fsize->stepwise.step_width = 1; + fsize->stepwise.step_height = 1; return 0; } @@ -253,6 +279,7 @@ static int vimc_cap_start_streaming(struct vb2_queue *vq, unsigned int count) return ret; } + vcap->stream.producer_pixfmt = vcap->format.pixelformat; ret = vimc_streamer_s_stream(&vcap->stream, &vcap->ved, 1); if (ret) { media_pipeline_stop(entity); @@ -338,6 +365,15 @@ static const struct media_entity_operations vimc_cap_mops = { .link_validate = vimc_link_validate, }; +static void vimc_cap_release(struct video_device *vdev) +{ + struct vimc_cap_device *vcap = + container_of(vdev, struct vimc_cap_device, vdev); + + vimc_pads_cleanup(vcap->ved.pads); + kfree(vcap); +} + static void vimc_cap_comp_unbind(struct device *comp, struct device *master, void *master_data) { @@ -348,8 +384,6 @@ static void vimc_cap_comp_unbind(struct device *comp, struct device *master, vb2_queue_release(&vcap->queue); media_entity_cleanup(ved->ent); video_unregister_device(&vcap->vdev); - vimc_pads_cleanup(vcap->ved.pads); - kfree(vcap); } static void *vimc_cap_process_frame(struct vimc_ent_device *ved, @@ -396,7 +430,6 @@ static int vimc_cap_comp_bind(struct device *comp, struct device *master, { struct v4l2_device *v4l2_dev = master_data; struct vimc_platform_data *pdata = comp->platform_data; - const struct vimc_pix_map *vpix; struct vimc_cap_device *vcap; struct video_device *vdev; struct vb2_queue *q; @@ -451,10 +484,8 @@ static int vimc_cap_comp_bind(struct device *comp, struct device *master, /* 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; + v4l2_fill_pixfmt(&vcap->format, vcap->format.pixelformat, + vcap->format.width, vcap->format.height); /* Fill the vimc_ent_device struct */ vcap->ved.ent = &vcap->vdev.entity; @@ -467,7 +498,7 @@ static int vimc_cap_comp_bind(struct device *comp, struct device *master, 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->release = vimc_cap_release; vdev->fops = &vimc_cap_fops; vdev->ioctl_ops = &vimc_cap_ioctl_ops; vdev->lock = &vcap->lock; diff --git a/drivers/media/platform/vimc/vimc-common.c b/drivers/media/platform/vimc/vimc-common.c index c1a74bb2df58..fad7c7c6de93 100644 --- a/drivers/media/platform/vimc/vimc-common.c +++ b/drivers/media/platform/vimc/vimc-common.c @@ -20,192 +20,139 @@ #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, - }, +static const __u32 vimc_mbus_list[] = { + MEDIA_BUS_FMT_FIXED, + MEDIA_BUS_FMT_RGB444_1X12, + MEDIA_BUS_FMT_RGB444_2X8_PADHI_BE, + MEDIA_BUS_FMT_RGB444_2X8_PADHI_LE, + MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE, + MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE, + MEDIA_BUS_FMT_RGB565_1X16, + MEDIA_BUS_FMT_BGR565_2X8_BE, + MEDIA_BUS_FMT_BGR565_2X8_LE, + MEDIA_BUS_FMT_RGB565_2X8_BE, + MEDIA_BUS_FMT_RGB565_2X8_LE, + MEDIA_BUS_FMT_RGB666_1X18, + MEDIA_BUS_FMT_RBG888_1X24, + MEDIA_BUS_FMT_RGB666_1X24_CPADHI, + MEDIA_BUS_FMT_RGB666_1X7X3_SPWG, + MEDIA_BUS_FMT_BGR888_1X24, + MEDIA_BUS_FMT_GBR888_1X24, + MEDIA_BUS_FMT_RGB888_1X24, + MEDIA_BUS_FMT_RGB888_2X12_BE, + MEDIA_BUS_FMT_RGB888_2X12_LE, + MEDIA_BUS_FMT_RGB888_1X7X4_SPWG, + MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA, + MEDIA_BUS_FMT_ARGB8888_1X32, + MEDIA_BUS_FMT_RGB888_1X32_PADHI, + MEDIA_BUS_FMT_RGB101010_1X30, + MEDIA_BUS_FMT_RGB121212_1X36, + MEDIA_BUS_FMT_RGB161616_1X48, + MEDIA_BUS_FMT_Y8_1X8, + MEDIA_BUS_FMT_UV8_1X8, + MEDIA_BUS_FMT_UYVY8_1_5X8, + MEDIA_BUS_FMT_VYUY8_1_5X8, + MEDIA_BUS_FMT_YUYV8_1_5X8, + MEDIA_BUS_FMT_YVYU8_1_5X8, + MEDIA_BUS_FMT_UYVY8_2X8, + MEDIA_BUS_FMT_VYUY8_2X8, + MEDIA_BUS_FMT_YUYV8_2X8, + MEDIA_BUS_FMT_YVYU8_2X8, + MEDIA_BUS_FMT_Y10_1X10, + MEDIA_BUS_FMT_Y10_2X8_PADHI_LE, + MEDIA_BUS_FMT_UYVY10_2X10, + MEDIA_BUS_FMT_VYUY10_2X10, + MEDIA_BUS_FMT_YUYV10_2X10, + MEDIA_BUS_FMT_YVYU10_2X10, + MEDIA_BUS_FMT_Y12_1X12, + MEDIA_BUS_FMT_UYVY12_2X12, + MEDIA_BUS_FMT_VYUY12_2X12, + MEDIA_BUS_FMT_YUYV12_2X12, + MEDIA_BUS_FMT_YVYU12_2X12, + MEDIA_BUS_FMT_UYVY8_1X16, + MEDIA_BUS_FMT_VYUY8_1X16, + MEDIA_BUS_FMT_YUYV8_1X16, + MEDIA_BUS_FMT_YVYU8_1X16, + MEDIA_BUS_FMT_YDYUYDYV8_1X16, + MEDIA_BUS_FMT_UYVY10_1X20, + MEDIA_BUS_FMT_VYUY10_1X20, + MEDIA_BUS_FMT_YUYV10_1X20, + MEDIA_BUS_FMT_YVYU10_1X20, + MEDIA_BUS_FMT_VUY8_1X24, + MEDIA_BUS_FMT_YUV8_1X24, + MEDIA_BUS_FMT_UYYVYY8_0_5X24, + MEDIA_BUS_FMT_UYVY12_1X24, + MEDIA_BUS_FMT_VYUY12_1X24, + MEDIA_BUS_FMT_YUYV12_1X24, + MEDIA_BUS_FMT_YVYU12_1X24, + MEDIA_BUS_FMT_YUV10_1X30, + MEDIA_BUS_FMT_UYYVYY10_0_5X30, + MEDIA_BUS_FMT_AYUV8_1X32, + MEDIA_BUS_FMT_UYYVYY12_0_5X36, + MEDIA_BUS_FMT_YUV12_1X36, + MEDIA_BUS_FMT_YUV16_1X48, + MEDIA_BUS_FMT_UYYVYY16_0_5X48, + MEDIA_BUS_FMT_SBGGR8_1X8, + MEDIA_BUS_FMT_SGBRG8_1X8, + MEDIA_BUS_FMT_SGRBG8_1X8, + MEDIA_BUS_FMT_SRGGB8_1X8, + MEDIA_BUS_FMT_SBGGR10_ALAW8_1X8, + MEDIA_BUS_FMT_SGBRG10_ALAW8_1X8, + MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8, + MEDIA_BUS_FMT_SRGGB10_ALAW8_1X8, + MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8, + MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8, + MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8, + MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8, + MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_BE, + MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE, + MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_BE, + MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_LE, + MEDIA_BUS_FMT_SBGGR10_1X10, + MEDIA_BUS_FMT_SGBRG10_1X10, + MEDIA_BUS_FMT_SGRBG10_1X10, + MEDIA_BUS_FMT_SRGGB10_1X10, + MEDIA_BUS_FMT_SBGGR12_1X12, + MEDIA_BUS_FMT_SGBRG12_1X12, + MEDIA_BUS_FMT_SGRBG12_1X12, + MEDIA_BUS_FMT_SRGGB12_1X12, + MEDIA_BUS_FMT_SBGGR14_1X14, + MEDIA_BUS_FMT_SGBRG14_1X14, + MEDIA_BUS_FMT_SGRBG14_1X14, + MEDIA_BUS_FMT_SRGGB14_1X14, + MEDIA_BUS_FMT_SBGGR16_1X16, + MEDIA_BUS_FMT_SGBRG16_1X16, + MEDIA_BUS_FMT_SGRBG16_1X16, + MEDIA_BUS_FMT_SRGGB16_1X16, + MEDIA_BUS_FMT_JPEG_1X8, + MEDIA_BUS_FMT_S5C_UYVY_JPEG_1X8, + MEDIA_BUS_FMT_AHSV8888_1X32, }; -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]; -} -EXPORT_SYMBOL_GPL(vimc_pix_map_by_index); - -const struct vimc_pix_map *vimc_pix_map_by_code(u32 code) +/* Helper function to check mbus codes */ +bool vimc_mbus_code_supported(__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; + for (i = 0; i < ARRAY_SIZE(vimc_mbus_list); i++) + if (code == vimc_mbus_list[i]) + return true; + return false; } -EXPORT_SYMBOL_GPL(vimc_pix_map_by_code); +EXPORT_SYMBOL_GPL(vimc_mbus_code_supported); -const struct vimc_pix_map *vimc_pix_map_by_pixelformat(u32 pixelformat) +/* Helper function to enumerate mbus codes */ +int vimc_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code) { - unsigned int i; + if (code->index >= ARRAY_SIZE(vimc_mbus_list)) + return -EINVAL; - 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; + code->code = vimc_mbus_list[code->index]; + return 0; } -EXPORT_SYMBOL_GPL(vimc_pix_map_by_pixelformat); +EXPORT_SYMBOL_GPL(vimc_enum_mbus_code); /* Helper function to allocate and initialize pads */ struct media_pad *vimc_pads_init(u16 num_pads, const unsigned long *pads_flag) @@ -277,15 +224,13 @@ static int vimc_get_mbus_format(struct media_pad *pad, struct video_device, entity); struct vimc_ent_device *ved = video_get_drvdata(vdev); - const struct vimc_pix_map *vpix; struct v4l2_pix_format vdev_fmt; if (!ved->vdev_get_format) return -ENOIOCTLCMD; ved->vdev_get_format(ved, &vdev_fmt); - vpix = vimc_pix_map_by_pixelformat(vdev_fmt.pixelformat); - v4l2_fill_mbus_format(&fmt->format, &vdev_fmt, vpix->code); + v4l2_fill_mbus_format(&fmt->format, &vdev_fmt, 0); } else { return -EINVAL; } @@ -325,8 +270,12 @@ int vimc_link_validate(struct media_link *link) /* The width, height and code must match. */ if (source_fmt.format.width != sink_fmt.format.width || source_fmt.format.height != sink_fmt.format.height - || source_fmt.format.code != sink_fmt.format.code) + || (source_fmt.format.code && sink_fmt.format.code && + source_fmt.format.code != sink_fmt.format.code)) { + pr_err("vimc: format doesn't match in link %s->%s\n", + link->source->entity->name, link->sink->entity->name); return -EPIPE; + } /* * The field order must match, or the sink field order must be NONE @@ -380,6 +329,7 @@ int vimc_ent_sd_register(struct vimc_ent_device *ved, u32 function, u16 num_pads, const unsigned long *pads_flag, + const struct v4l2_subdev_internal_ops *sd_int_ops, const struct v4l2_subdev_ops *sd_ops) { int ret; @@ -394,6 +344,7 @@ int vimc_ent_sd_register(struct vimc_ent_device *ved, /* Initialize the subdev */ v4l2_subdev_init(sd, sd_ops); + sd->internal_ops = sd_int_ops; sd->entity.function = function; sd->entity.ops = &vimc_ent_sd_mops; sd->owner = THIS_MODULE; @@ -431,9 +382,9 @@ EXPORT_SYMBOL_GPL(vimc_ent_sd_register); void vimc_ent_sd_unregister(struct vimc_ent_device *ved, struct v4l2_subdev *sd) { - v4l2_device_unregister_subdev(sd); media_entity_cleanup(ved->ent); vimc_pads_cleanup(ved->pads); + v4l2_device_unregister_subdev(sd); } EXPORT_SYMBOL_GPL(vimc_ent_sd_unregister); diff --git a/drivers/media/platform/vimc/vimc-common.h b/drivers/media/platform/vimc/vimc-common.h index 84539430b5e7..142ddfa69b3d 100644 --- a/drivers/media/platform/vimc/vimc-common.h +++ b/drivers/media/platform/vimc/vimc-common.h @@ -22,6 +22,8 @@ #include <media/media-device.h> #include <media/v4l2-device.h> +#include "vimc-streamer.h" + #define VIMC_PDEV_NAME "vimc" /* VIMC-specific controls */ @@ -78,23 +80,6 @@ struct vimc_platform_data { }; /** - * 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 a node in the topology * * @ent: the pointer to struct media_entity for the node @@ -115,6 +100,7 @@ struct vimc_pix_map { struct vimc_ent_device { struct media_entity *ent; struct media_pad *pads; + struct vimc_stream *stream; void * (*process_frame)(struct vimc_ent_device *ved, const void *frame); void (*vdev_get_format)(struct vimc_ent_device *ved, @@ -122,6 +108,23 @@ struct vimc_ent_device { }; /** + * vimc_mbus_code_supported - helper to check supported mbus codes + * + * Helper function to check if mbus code is enumerated by vimc_enum_mbus_code() + */ +bool vimc_mbus_code_supported(__u32 code); + +/** + * vimc_enum_mbus_code - enumerate mbus codes + * + * Helper function to be pluged in .enum_mbus_code from + * struct v4l2_subdev_pad_ops. + */ +int vimc_enum_mbus_code(struct v4l2_subdev *sd, + struct v4l2_subdev_pad_config *cfg, + struct v4l2_subdev_mbus_code_enum *code); + +/** * vimc_pads_init - initialize pads * * @num_pads: number of pads to initialize @@ -156,27 +159,6 @@ static inline void vimc_pads_cleanup(struct media_pad *pads) int vimc_pipeline_s_stream(struct media_entity *ent, int enable); /** - * 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 @@ -187,6 +169,7 @@ const struct vimc_pix_map *vimc_pix_map_by_pixelformat(u32 pixelformat); * @function: media entity function defined by MEDIA_ENT_F_* macros * @num_pads: number of pads to initialize * @pads_flag: flags to use in each pad + * @sd_int_ops: pointer to &struct v4l2_subdev_internal_ops * @sd_ops: pointer to &struct v4l2_subdev_ops. * * Helper function initialize and register the struct vimc_ent_device and struct @@ -199,6 +182,7 @@ int vimc_ent_sd_register(struct vimc_ent_device *ved, u32 function, u16 num_pads, const unsigned long *pads_flag, + const struct v4l2_subdev_internal_ops *sd_int_ops, const struct v4l2_subdev_ops *sd_ops); /** diff --git a/drivers/media/platform/vimc/vimc-core.c b/drivers/media/platform/vimc/vimc-core.c index 0fbb7914098f..3aa62d7e3d0e 100644 --- a/drivers/media/platform/vimc/vimc-core.c +++ b/drivers/media/platform/vimc/vimc-core.c @@ -304,6 +304,8 @@ static int vimc_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "probe"); + memset(&vimc->mdev, 0, sizeof(vimc->mdev)); + /* Create platform_device for each entity in the topology*/ vimc->subdevs = devm_kcalloc(&vimc->pdev.dev, vimc->pipe_cfg->num_ents, sizeof(*vimc->subdevs), GFP_KERNEL); diff --git a/drivers/media/platform/vimc/vimc-debayer.c b/drivers/media/platform/vimc/vimc-debayer.c index 7d77c63b99d2..281f9c1a7249 100644 --- a/drivers/media/platform/vimc/vimc-debayer.c +++ b/drivers/media/platform/vimc/vimc-debayer.c @@ -26,6 +26,9 @@ #include "vimc-common.h" #define VIMC_DEB_DRV_NAME "vimc-debayer" +/* This module only supports tranforming a bayer format to V4L2_PIX_FMT_RGB24 */ +#define VIMC_DEB_SRC_PIXFMT V4L2_PIX_FMT_RGB24 +#define VIMC_DEB_SRC_MBUS_FMT_DEFAULT MEDIA_BUS_FMT_RGB888_1X24 static unsigned int deb_mean_win_size = 3; module_param(deb_mean_win_size, uint, 0000); @@ -44,6 +47,7 @@ enum vimc_deb_rgb_colors { }; struct vimc_deb_pix_map { + u32 pixelformat; u32 code; enum vimc_deb_rgb_colors order[2][2]; }; @@ -66,68 +70,80 @@ struct vimc_deb_device { static const struct v4l2_mbus_framefmt sink_fmt_default = { .width = 640, .height = 480, - .code = MEDIA_BUS_FMT_RGB888_1X24, + .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[] = { { + .pixelformat = V4L2_PIX_FMT_SBGGR8, .code = MEDIA_BUS_FMT_SBGGR8_1X8, .order = { { VIMC_DEB_BLUE, VIMC_DEB_GREEN }, { VIMC_DEB_GREEN, VIMC_DEB_RED } } }, { + .pixelformat = V4L2_PIX_FMT_SGBRG8, .code = MEDIA_BUS_FMT_SGBRG8_1X8, .order = { { VIMC_DEB_GREEN, VIMC_DEB_BLUE }, { VIMC_DEB_RED, VIMC_DEB_GREEN } } }, { + .pixelformat = V4L2_PIX_FMT_SGRBG8, .code = MEDIA_BUS_FMT_SGRBG8_1X8, .order = { { VIMC_DEB_GREEN, VIMC_DEB_RED }, { VIMC_DEB_BLUE, VIMC_DEB_GREEN } } }, { + .pixelformat = V4L2_PIX_FMT_SRGGB8, .code = MEDIA_BUS_FMT_SRGGB8_1X8, .order = { { VIMC_DEB_RED, VIMC_DEB_GREEN }, { VIMC_DEB_GREEN, VIMC_DEB_BLUE } } }, { + .pixelformat = V4L2_PIX_FMT_SBGGR10, .code = MEDIA_BUS_FMT_SBGGR10_1X10, .order = { { VIMC_DEB_BLUE, VIMC_DEB_GREEN }, { VIMC_DEB_GREEN, VIMC_DEB_RED } } }, { + .pixelformat = V4L2_PIX_FMT_SGBRG10, .code = MEDIA_BUS_FMT_SGBRG10_1X10, .order = { { VIMC_DEB_GREEN, VIMC_DEB_BLUE }, { VIMC_DEB_RED, VIMC_DEB_GREEN } } }, { + .pixelformat = V4L2_PIX_FMT_SGRBG10, .code = MEDIA_BUS_FMT_SGRBG10_1X10, .order = { { VIMC_DEB_GREEN, VIMC_DEB_RED }, { VIMC_DEB_BLUE, VIMC_DEB_GREEN } } }, { + .pixelformat = V4L2_PIX_FMT_SRGGB10, .code = MEDIA_BUS_FMT_SRGGB10_1X10, .order = { { VIMC_DEB_RED, VIMC_DEB_GREEN }, { VIMC_DEB_GREEN, VIMC_DEB_BLUE } } }, { + .pixelformat = V4L2_PIX_FMT_SBGGR12, .code = MEDIA_BUS_FMT_SBGGR12_1X12, .order = { { VIMC_DEB_BLUE, VIMC_DEB_GREEN }, { VIMC_DEB_GREEN, VIMC_DEB_RED } } }, { + .pixelformat = V4L2_PIX_FMT_SGBRG12, .code = MEDIA_BUS_FMT_SGBRG12_1X12, .order = { { VIMC_DEB_GREEN, VIMC_DEB_BLUE }, { VIMC_DEB_RED, VIMC_DEB_GREEN } } }, { + .pixelformat = V4L2_PIX_FMT_SGRBG12, .code = MEDIA_BUS_FMT_SGRBG12_1X12, .order = { { VIMC_DEB_GREEN, VIMC_DEB_RED }, { VIMC_DEB_BLUE, VIMC_DEB_GREEN } } }, { + .pixelformat = V4L2_PIX_FMT_SRGGB12, .code = MEDIA_BUS_FMT_SRGGB12_1X12, .order = { { VIMC_DEB_RED, VIMC_DEB_GREEN }, { VIMC_DEB_GREEN, VIMC_DEB_BLUE } } @@ -168,41 +184,32 @@ 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 (IS_SRC(code->pad)) { - struct vimc_deb_device *vdeb = v4l2_get_subdevdata(sd); - - if (code->index) - return -EINVAL; - - code->code = vdeb->src_code; - } else { + /* For the sink pad we only support codes in the map_list */ + if (IS_SINK(code->pad)) { if (code->index >= ARRAY_SIZE(vimc_deb_pix_map_list)) return -EINVAL; code->code = vimc_deb_pix_map_list[code->index].code; + return 0; } - return 0; + return vimc_enum_mbus_code(sd, cfg, code); } 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; + /* For the sink pad we only support codes in the map_list */ if (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; @@ -258,6 +265,9 @@ static int vimc_deb_set_fmt(struct v4l2_subdev *sd, struct vimc_deb_device *vdeb = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *sink_fmt; + if (!vimc_mbus_code_supported(fmt->format.code)) + fmt->format.code = sink_fmt_default.code; + if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { /* Do not change the format while stream is on */ if (vdeb->src_frame) @@ -270,11 +280,11 @@ static int vimc_deb_set_fmt(struct v4l2_subdev *sd, /* * Do not change the format of the source pad, - * it is propagated from the sink + * it is propagated from the sink (except for the code) */ if (IS_SRC(fmt->pad)) { + vdeb->src_code = fmt->format.code; 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 */ @@ -306,7 +316,7 @@ static const struct v4l2_subdev_pad_ops vimc_deb_pad_ops = { .set_fmt = vimc_deb_set_fmt, }; -static void vimc_deb_set_rgb_mbus_fmt_rgb888_1x24(struct vimc_deb_device *vdeb, +static void vimc_deb_set_rgb_pix_rgb24(struct vimc_deb_device *vdeb, unsigned int lin, unsigned int col, unsigned int rgb[3]) @@ -323,25 +333,38 @@ 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; + u32 src_pixelformat = vdeb->ved.stream->producer_pixfmt; + const struct v4l2_format_info *pix_info; 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; + /* We only support translating bayer to RGB24 */ + if (src_pixelformat != V4L2_PIX_FMT_RGB24) { + dev_err(vdeb->dev, + "translating to pixfmt (0x%08x) is not supported\n", + src_pixelformat); + return -EINVAL; + } /* Get the corresponding pixel map from the table */ vdeb->sink_pix_map = vimc_deb_pix_map_by_code(vdeb->sink_fmt.code); + /* Request bayer format from the pipeline for the sink pad */ + vdeb->ved.stream->producer_pixfmt = + vdeb->sink_pix_map->pixelformat; + + /* Calculate frame_size of the source */ + pix_info = v4l2_format_info(src_pixelformat); + frame_size = vdeb->sink_fmt.width * vdeb->sink_fmt.height * + pix_info->bpp[0]; + + /* Get bpp from the sink */ + pix_info = v4l2_format_info(vdeb->sink_pix_map->pixelformat); + vdeb->sink_bpp = pix_info->bpp[0]; + /* * Allocate the frame buffer. Use vmalloc to be able to * allocate a large amount of memory @@ -489,6 +512,18 @@ static void *vimc_deb_process_frame(struct vimc_ent_device *ved, } +static void vimc_deb_release(struct v4l2_subdev *sd) +{ + struct vimc_deb_device *vdeb = + container_of(sd, struct vimc_deb_device, sd); + + kfree(vdeb); +} + +static const struct v4l2_subdev_internal_ops vimc_deb_int_ops = { + .release = vimc_deb_release, +}; + static void vimc_deb_comp_unbind(struct device *comp, struct device *master, void *master_data) { @@ -497,7 +532,6 @@ static void vimc_deb_comp_unbind(struct device *comp, struct device *master, ved); vimc_ent_sd_unregister(ved, &vdeb->sd); - kfree(vdeb); } static int vimc_deb_comp_bind(struct device *comp, struct device *master, @@ -519,7 +553,7 @@ static int vimc_deb_comp_bind(struct device *comp, struct device *master, MEDIA_ENT_F_PROC_VIDEO_PIXEL_ENC_CONV, 2, (const unsigned long[2]) {MEDIA_PAD_FL_SINK, MEDIA_PAD_FL_SOURCE}, - &vimc_deb_ops); + &vimc_deb_int_ops, &vimc_deb_ops); if (ret) { kfree(vdeb); return ret; @@ -531,14 +565,14 @@ static int vimc_deb_comp_bind(struct device *comp, struct device *master, /* Initialize the frame format */ vdeb->sink_fmt = sink_fmt_default; + vdeb->src_code = VIMC_DEB_SRC_MBUS_FMT_DEFAULT; /* * TODO: Add support for more output formats, we only support - * RGB888 for now + * RGB24 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; + vdeb->set_rgb_src = vimc_deb_set_rgb_pix_rgb24; return 0; } diff --git a/drivers/media/platform/vimc/vimc-scaler.c b/drivers/media/platform/vimc/vimc-scaler.c index 39b2a73dfcc1..8aecf8e92031 100644 --- a/drivers/media/platform/vimc/vimc-scaler.c +++ b/drivers/media/platform/vimc/vimc-scaler.c @@ -35,6 +35,12 @@ MODULE_PARM_DESC(sca_mult, " the image size multiplier"); #define IS_SRC(pad) (pad) #define MAX_ZOOM 8 +static const u32 vimc_sca_supported_pixfmt[] = { + V4L2_PIX_FMT_BGR24, + V4L2_PIX_FMT_RGB24, + V4L2_PIX_FMT_ARGB32, +}; + struct vimc_sca_device { struct vimc_ent_device ved; struct v4l2_subdev sd; @@ -57,6 +63,16 @@ static const struct v4l2_mbus_framefmt sink_fmt_default = { .colorspace = V4L2_COLORSPACE_DEFAULT, }; +static bool vimc_sca_is_pixfmt_supported(u32 pixelformat) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(vimc_sca_supported_pixfmt); i++) + if (vimc_sca_supported_pixfmt[i] == pixelformat) + return true; + return false; +} + static int vimc_sca_init_cfg(struct v4l2_subdev *sd, struct v4l2_subdev_pad_config *cfg) { @@ -76,35 +92,13 @@ static int vimc_sca_init_cfg(struct v4l2_subdev *sd, 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; @@ -141,13 +135,6 @@ static int vimc_sca_get_fmt(struct v4l2_subdev *sd, 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, @@ -166,6 +153,9 @@ static int vimc_sca_set_fmt(struct v4l2_subdev *sd, struct vimc_sca_device *vsca = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *sink_fmt; + if (!vimc_mbus_code_supported(fmt->format.code)) + fmt->format.code = sink_fmt_default.code; + if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { /* Do not change the format while stream is on */ if (vsca->src_frame) @@ -208,7 +198,7 @@ static int vimc_sca_set_fmt(struct v4l2_subdev *sd, 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_mbus_code = vimc_enum_mbus_code, .enum_frame_size = vimc_sca_enum_frame_size, .get_fmt = vimc_sca_get_fmt, .set_fmt = vimc_sca_set_fmt, @@ -219,15 +209,22 @@ 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; + u32 pixelformat = vsca->ved.stream->producer_pixfmt; + const struct v4l2_format_info *pix_info; unsigned int frame_size; if (vsca->src_frame) return 0; + if (!vimc_sca_is_pixfmt_supported(pixelformat)) { + dev_err(vsca->dev, "pixfmt (0x%08x) is not supported\n", + pixelformat); + return -EINVAL; + } + /* Save the bytes per pixel of the sink */ - vpix = vimc_pix_map_by_code(vsca->sink_fmt.code); - vsca->bpp = vpix->bpp; + pix_info = v4l2_format_info(pixelformat); + vsca->bpp = pix_info->bpp[0]; /* Calculate the width in bytes of the src frame */ vsca->src_line_size = vsca->sink_fmt.width * @@ -348,6 +345,18 @@ static void *vimc_sca_process_frame(struct vimc_ent_device *ved, return vsca->src_frame; }; +static void vimc_sca_release(struct v4l2_subdev *sd) +{ + struct vimc_sca_device *vsca = + container_of(sd, struct vimc_sca_device, sd); + + kfree(vsca); +} + +static const struct v4l2_subdev_internal_ops vimc_sca_int_ops = { + .release = vimc_sca_release, +}; + static void vimc_sca_comp_unbind(struct device *comp, struct device *master, void *master_data) { @@ -356,7 +365,6 @@ static void vimc_sca_comp_unbind(struct device *comp, struct device *master, ved); vimc_ent_sd_unregister(ved, &vsca->sd); - kfree(vsca); } @@ -379,7 +387,7 @@ static int vimc_sca_comp_bind(struct device *comp, struct device *master, MEDIA_ENT_F_PROC_VIDEO_SCALER, 2, (const unsigned long[2]) {MEDIA_PAD_FL_SINK, MEDIA_PAD_FL_SOURCE}, - &vimc_sca_ops); + &vimc_sca_int_ops, &vimc_sca_ops); if (ret) { kfree(vsca); return ret; diff --git a/drivers/media/platform/vimc/vimc-sensor.c b/drivers/media/platform/vimc/vimc-sensor.c index 59195f262623..081e54204c9f 100644 --- a/drivers/media/platform/vimc/vimc-sensor.c +++ b/drivers/media/platform/vimc/vimc-sensor.c @@ -65,34 +65,13 @@ static int vimc_sen_init_cfg(struct v4l2_subdev *sd, 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; @@ -117,14 +96,17 @@ static int vimc_sen_get_fmt(struct v4l2_subdev *sd, 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); + u32 pixelformat = vsen->ved.stream->producer_pixfmt; + const struct v4l2_format_info *pix_info; + + pix_info = v4l2_format_info(pixelformat); 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_bytesperline(&vsen->tpg, 0, + vsen->mbus_format.width * pix_info->bpp[0]); tpg_s_buf_height(&vsen->tpg, vsen->mbus_format.height); - tpg_s_fourcc(&vsen->tpg, vpix->pixelformat); + tpg_s_fourcc(&vsen->tpg, 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); @@ -135,13 +117,6 @@ static void vimc_sen_tpg_s_format(struct vimc_sen_device *vsen) 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, @@ -161,6 +136,9 @@ static int vimc_sen_set_fmt(struct v4l2_subdev *sd, struct vimc_sen_device *vsen = v4l2_get_subdevdata(sd); struct v4l2_mbus_framefmt *mf; + if (!vimc_mbus_code_supported(fmt->format.code)) + fmt->format.code = fmt_default.code; + if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { /* Do not change the format while stream is on */ if (vsen->frame) @@ -193,7 +171,7 @@ static int vimc_sen_set_fmt(struct v4l2_subdev *sd, 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_mbus_code = vimc_enum_mbus_code, .enum_frame_size = vimc_sen_enum_frame_size, .get_fmt = vimc_sen_get_fmt, .set_fmt = vimc_sen_set_fmt, @@ -215,7 +193,8 @@ static int vimc_sen_s_stream(struct v4l2_subdev *sd, int enable) container_of(sd, struct vimc_sen_device, sd); if (enable) { - const struct vimc_pix_map *vpix; + u32 pixelformat = vsen->ved.stream->producer_pixfmt; + const struct v4l2_format_info *pix_info; unsigned int frame_size; if (vsen->kthread_sen) @@ -223,8 +202,8 @@ static int vimc_sen_s_stream(struct v4l2_subdev *sd, int enable) return 0; /* Calculate the frame size */ - vpix = vimc_pix_map_by_code(vsen->mbus_format.code); - frame_size = vsen->mbus_format.width * vpix->bpp * + pix_info = v4l2_format_info(pixelformat); + frame_size = vsen->mbus_format.width * pix_info->bpp[0] * vsen->mbus_format.height; /* @@ -301,6 +280,20 @@ static const struct v4l2_ctrl_ops vimc_sen_ctrl_ops = { .s_ctrl = vimc_sen_s_ctrl, }; +static void vimc_sen_release(struct v4l2_subdev *sd) +{ + struct vimc_sen_device *vsen = + container_of(sd, struct vimc_sen_device, sd); + + v4l2_ctrl_handler_free(&vsen->hdl); + tpg_free(&vsen->tpg); + kfree(vsen); +} + +static const struct v4l2_subdev_internal_ops vimc_sen_int_ops = { + .release = vimc_sen_release, +}; + static void vimc_sen_comp_unbind(struct device *comp, struct device *master, void *master_data) { @@ -309,9 +302,6 @@ static void vimc_sen_comp_unbind(struct device *comp, struct device *master, container_of(ved, struct vimc_sen_device, ved); vimc_ent_sd_unregister(ved, &vsen->sd); - v4l2_ctrl_handler_free(&vsen->hdl); - tpg_free(&vsen->tpg); - kfree(vsen); } /* Image Processing Controls */ @@ -371,7 +361,7 @@ static int vimc_sen_comp_bind(struct device *comp, struct device *master, pdata->entity_name, MEDIA_ENT_F_CAM_SENSOR, 1, (const unsigned long[1]) {MEDIA_PAD_FL_SOURCE}, - &vimc_sen_ops); + &vimc_sen_int_ops, &vimc_sen_ops); if (ret) goto err_free_hdl; diff --git a/drivers/media/platform/vimc/vimc-streamer.c b/drivers/media/platform/vimc/vimc-streamer.c index fcc897fb247b..26b674259489 100644 --- a/drivers/media/platform/vimc/vimc-streamer.c +++ b/drivers/media/platform/vimc/vimc-streamer.c @@ -46,19 +46,19 @@ static struct media_entity *vimc_get_source_entity(struct media_entity *ent) */ static void vimc_streamer_pipeline_terminate(struct vimc_stream *stream) { - struct media_entity *entity; + struct vimc_ent_device *ved; struct v4l2_subdev *sd; while (stream->pipe_size) { stream->pipe_size--; - entity = stream->ved_pipeline[stream->pipe_size]->ent; - entity = vimc_get_source_entity(entity); + ved = stream->ved_pipeline[stream->pipe_size]; + ved->stream = NULL; stream->ved_pipeline[stream->pipe_size] = NULL; - if (!is_media_entity_v4l2_subdev(entity)) + if (!is_media_entity_v4l2_subdev(ved->ent)) continue; - sd = media_entity_to_v4l2_subdev(entity); + sd = media_entity_to_v4l2_subdev(ved->ent); v4l2_subdev_call(sd, video, s_stream, 0); } } @@ -88,19 +88,27 @@ static int vimc_streamer_pipeline_init(struct vimc_stream *stream, return -EINVAL; } stream->ved_pipeline[stream->pipe_size++] = ved; + ved->stream = stream; + + 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) { + pr_err("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) return 0; + /* Get the next device in the pipeline */ if (is_media_entity_v4l2_subdev(entity)) { sd = media_entity_to_v4l2_subdev(entity); - ret = v4l2_subdev_call(sd, video, s_stream, 1); - if (ret && ret != -ENOIOCTLCMD) { - vimc_streamer_pipeline_terminate(stream); - return ret; - } ved = v4l2_get_subdevdata(sd); } else { vdev = container_of(entity, @@ -117,10 +125,10 @@ static int vimc_streamer_pipeline_init(struct vimc_stream *stream, static int vimc_streamer_thread(void *data) { struct vimc_stream *stream = data; + u8 *frame = NULL; int i; set_freezable(); - set_current_state(TASK_UNINTERRUPTIBLE); for (;;) { try_to_freeze(); @@ -128,15 +136,13 @@ static int vimc_streamer_thread(void *data) break; for (i = stream->pipe_size - 1; i >= 0; i--) { - stream->frame = stream->ved_pipeline[i]->process_frame( - stream->ved_pipeline[i], - stream->frame); - if (!stream->frame) - break; - if (IS_ERR(stream->frame)) + 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); } diff --git a/drivers/media/platform/vimc/vimc-streamer.h b/drivers/media/platform/vimc/vimc-streamer.h index 752af2e2d5a2..2b3667408794 100644 --- a/drivers/media/platform/vimc/vimc-streamer.h +++ b/drivers/media/platform/vimc/vimc-streamer.h @@ -15,12 +15,32 @@ #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. + * @producer_pixfmt: the pixel format requested from the pipeline. This must + * be set just before calling vimc_streamer_s_stream(ent, 1). This value is + * propagated up to the source of the base image (usually a sensor node) and + * can be modified by entities during s_stream callback to request a different + * format from rest of the pipeline. + * + * 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; - u8 *frame; struct task_struct *kthread; + u32 producer_pixfmt; }; /** diff --git a/drivers/media/platform/vivid/Kconfig b/drivers/media/platform/vivid/Kconfig index 154de92dd809..4b51d4d6cf93 100644 --- a/drivers/media/platform/vivid/Kconfig +++ b/drivers/media/platform/vivid/Kconfig @@ -11,7 +11,7 @@ config VIDEO_VIVID select VIDEOBUF2_DMA_CONTIG select VIDEO_V4L2_TPG default n - ---help--- + 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, @@ -28,7 +28,7 @@ config VIDEO_VIVID_CEC bool "Enable CEC emulation support" depends on VIDEO_VIVID select CEC_CORE - ---help--- + help When selected the vivid module will emulate the optional HDMI CEC feature. @@ -36,6 +36,6 @@ config VIDEO_VIVID_MAX_DEVS int "Maximum number of devices" depends on VIDEO_VIVID default "64" - ---help--- + help This allows you to specify the maximum number of devices supported by the vivid driver. diff --git a/drivers/media/platform/vivid/vivid-core.c b/drivers/media/platform/vivid/vivid-core.c index 342e0e6c103b..7047df6f0e0e 100644 --- a/drivers/media/platform/vivid/vivid-core.c +++ b/drivers/media/platform/vivid/vivid-core.c @@ -681,7 +681,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) dev->v4l2_dev.mdev = &dev->mdev; /* Initialize media device */ - strlcpy(dev->mdev.model, VIVID_MODULE_NAME, sizeof(dev->mdev.model)); + 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; diff --git a/drivers/media/platform/vivid/vivid-vid-cap.c b/drivers/media/platform/vivid/vivid-vid-cap.c index 52eeda624d7e..530ac8decb25 100644 --- a/drivers/media/platform/vivid/vivid-vid-cap.c +++ b/drivers/media/platform/vivid/vivid-vid-cap.c @@ -1007,7 +1007,7 @@ int vivid_vid_cap_s_selection(struct file *file, void *fh, struct v4l2_selection v4l2_rect_map_inside(&s->r, &dev->fmt_cap_rect); if (dev->bitmap_cap && (compose->width != s->r.width || compose->height != s->r.height)) { - kfree(dev->bitmap_cap); + vfree(dev->bitmap_cap); dev->bitmap_cap = NULL; } *compose = s->r; diff --git a/drivers/media/platform/vivid/vivid-vid-out.c b/drivers/media/platform/vivid/vivid-vid-out.c index e61b91b414f9..9350ca65dd91 100644 --- a/drivers/media/platform/vivid/vivid-vid-out.c +++ b/drivers/media/platform/vivid/vivid-vid-out.c @@ -798,7 +798,7 @@ int vivid_vid_out_s_selection(struct file *file, void *fh, struct v4l2_selection s->r.height *= factor; if (dev->bitmap_out && (compose->width != s->r.width || compose->height != s->r.height)) { - kfree(dev->bitmap_out); + vfree(dev->bitmap_out); dev->bitmap_out = NULL; } *compose = s->r; @@ -941,15 +941,19 @@ int vidioc_s_fmt_vid_out_overlay(struct file *file, void *priv, return ret; if (win->bitmap) { - new_bitmap = memdup_user(win->bitmap, bitmap_size); + new_bitmap = vzalloc(bitmap_size); - if (IS_ERR(new_bitmap)) - return PTR_ERR(new_bitmap); + 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; - kfree(dev->bitmap_out); + vfree(dev->bitmap_out); dev->bitmap_out = new_bitmap; dev->clipcount_out = win->clipcount; if (dev->clipcount_out) diff --git a/drivers/media/platform/vsp1/vsp1_pipe.c b/drivers/media/platform/vsp1/vsp1_pipe.c index 54ff539ffea0..f72ac01c21ea 100644 --- a/drivers/media/platform/vsp1/vsp1_pipe.c +++ b/drivers/media/platform/vsp1/vsp1_pipe.c @@ -42,6 +42,30 @@ static const struct vsp1_format_info vsp1_video_formats[] = { VI6_FMT_XRGB_4444, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | VI6_RPF_DSWAP_P_WDS, 1, { 16, 0, 0 }, false, false, 1, 1, false }, + { V4L2_PIX_FMT_RGBA444, MEDIA_BUS_FMT_ARGB8888_1X32, + VI6_FMT_RGBA_4444, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | + VI6_RPF_DSWAP_P_WDS, + 1, { 16, 0, 0 }, false, false, 1, 1, true }, + { V4L2_PIX_FMT_RGBX444, MEDIA_BUS_FMT_ARGB8888_1X32, + VI6_FMT_RGBX_4444, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | + VI6_RPF_DSWAP_P_WDS, + 1, { 16, 0, 0 }, false, false, 1, 1, false }, + { V4L2_PIX_FMT_ABGR444, MEDIA_BUS_FMT_ARGB8888_1X32, + VI6_FMT_ABGR_4444, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | + VI6_RPF_DSWAP_P_WDS, + 1, { 16, 0, 0 }, false, false, 1, 1, true }, + { V4L2_PIX_FMT_XBGR444, MEDIA_BUS_FMT_ARGB8888_1X32, + VI6_FMT_ABGR_4444, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | + VI6_RPF_DSWAP_P_WDS, + 1, { 16, 0, 0 }, false, false, 1, 1, false }, + { V4L2_PIX_FMT_BGRA444, MEDIA_BUS_FMT_ARGB8888_1X32, + VI6_FMT_BGRA_4444, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | + VI6_RPF_DSWAP_P_WDS, + 1, { 16, 0, 0 }, false, false, 1, 1, true }, + { V4L2_PIX_FMT_BGRX444, MEDIA_BUS_FMT_ARGB8888_1X32, + VI6_FMT_BGRA_4444, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | + VI6_RPF_DSWAP_P_WDS, + 1, { 16, 0, 0 }, false, false, 1, 1, false }, { V4L2_PIX_FMT_ARGB555, MEDIA_BUS_FMT_ARGB8888_1X32, VI6_FMT_ARGB_1555, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | VI6_RPF_DSWAP_P_WDS, @@ -50,6 +74,30 @@ static const struct vsp1_format_info vsp1_video_formats[] = { VI6_FMT_XRGB_1555, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | VI6_RPF_DSWAP_P_WDS, 1, { 16, 0, 0 }, false, false, 1, 1, false }, + { V4L2_PIX_FMT_RGBA555, MEDIA_BUS_FMT_ARGB8888_1X32, + VI6_FMT_RGBA_5551, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | + VI6_RPF_DSWAP_P_WDS, + 1, { 16, 0, 0 }, false, false, 1, 1, true }, + { V4L2_PIX_FMT_RGBX555, MEDIA_BUS_FMT_ARGB8888_1X32, + VI6_FMT_RGBX_5551, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | + VI6_RPF_DSWAP_P_WDS, + 1, { 16, 0, 0 }, false, false, 1, 1, false }, + { V4L2_PIX_FMT_ABGR555, MEDIA_BUS_FMT_ARGB8888_1X32, + VI6_FMT_ABGR_1555, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | + VI6_RPF_DSWAP_P_WDS, + 1, { 16, 0, 0 }, false, false, 1, 1, true }, + { V4L2_PIX_FMT_XBGR555, MEDIA_BUS_FMT_ARGB8888_1X32, + VI6_FMT_ABGR_1555, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | + VI6_RPF_DSWAP_P_WDS, + 1, { 16, 0, 0 }, false, false, 1, 1, false }, + { V4L2_PIX_FMT_BGRA555, MEDIA_BUS_FMT_ARGB8888_1X32, + VI6_FMT_BGRA_5551, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | + VI6_RPF_DSWAP_P_WDS, + 1, { 16, 0, 0 }, false, false, 1, 1, true }, + { V4L2_PIX_FMT_BGRX555, MEDIA_BUS_FMT_ARGB8888_1X32, + VI6_FMT_BGRA_5551, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | + VI6_RPF_DSWAP_P_WDS, + 1, { 16, 0, 0 }, false, false, 1, 1, false }, { V4L2_PIX_FMT_RGB565, MEDIA_BUS_FMT_ARGB8888_1X32, VI6_FMT_RGB_565, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | VI6_RPF_DSWAP_P_WDS, @@ -68,6 +116,20 @@ static const struct vsp1_format_info vsp1_video_formats[] = { { V4L2_PIX_FMT_XBGR32, MEDIA_BUS_FMT_ARGB8888_1X32, VI6_FMT_ARGB_8888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS, 1, { 32, 0, 0 }, false, false, 1, 1, false }, + { V4L2_PIX_FMT_BGRA32, MEDIA_BUS_FMT_ARGB8888_1X32, + VI6_FMT_RGBA_8888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS, + 1, { 32, 0, 0 }, false, false, 1, 1, true }, + { V4L2_PIX_FMT_BGRX32, MEDIA_BUS_FMT_ARGB8888_1X32, + VI6_FMT_RGBA_8888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS, + 1, { 32, 0, 0 }, false, false, 1, 1, false }, + { V4L2_PIX_FMT_RGBA32, MEDIA_BUS_FMT_ARGB8888_1X32, + VI6_FMT_RGBA_8888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | + VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS, + 1, { 32, 0, 0 }, false, false, 1, 1, true }, + { V4L2_PIX_FMT_RGBX32, MEDIA_BUS_FMT_ARGB8888_1X32, + VI6_FMT_RGBA_8888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | + VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS, + 1, { 32, 0, 0 }, false, false, 1, 1, false }, { V4L2_PIX_FMT_ARGB32, MEDIA_BUS_FMT_ARGB8888_1X32, VI6_FMT_ARGB_8888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS, diff --git a/drivers/media/platform/xilinx/Kconfig b/drivers/media/platform/xilinx/Kconfig index 74ec8aaa5ae0..a2773ad7c185 100644 --- a/drivers/media/platform/xilinx/Kconfig +++ b/drivers/media/platform/xilinx/Kconfig @@ -5,7 +5,7 @@ config VIDEO_XILINX depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && OF && HAS_DMA select VIDEOBUF2_DMA_CONTIG select V4L2_FWNODE - ---help--- + help Driver for Xilinx Video IP Pipelines if VIDEO_XILINX @@ -14,13 +14,13 @@ config VIDEO_XILINX_TPG tristate "Xilinx Video Test Pattern Generator" depends on VIDEO_XILINX select VIDEO_XILINX_VTC - ---help--- + help Driver for the Xilinx Video Test Pattern Generator config VIDEO_XILINX_VTC tristate "Xilinx Video Timing Controller" depends on VIDEO_XILINX - ---help--- + help Driver for the Xilinx Video Timing Controller endif #VIDEO_XILINX diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig index 9b99dfb2d0c6..9cd00f64af32 100644 --- a/drivers/media/radio/Kconfig +++ b/drivers/media/radio/Kconfig @@ -7,7 +7,7 @@ menuconfig RADIO_ADAPTERS depends on VIDEO_V4L2 depends on MEDIA_RADIO_SUPPORT default y - ---help--- + help Say Y here to enable selecting AM/FM radio adapters. if RADIO_ADAPTERS && VIDEO_V4L2 @@ -29,7 +29,7 @@ config RADIO_SI476X depends on MFD_SI476X_CORE depends on SND_SOC select SND_SOC_SI476X - ---help--- + help Choose Y here if you have this FM radio chip. In order to control your radio card, you will need to use programs @@ -43,7 +43,7 @@ config RADIO_SI476X config USB_MR800 tristate "AverMedia MR 800 USB FM radio support" depends on USB && VIDEO_V4L2 - ---help--- + help Say Y here if you want to connect this type of radio to your computer's USB port. Note that the audio is not digital, and you must connect the line out connector to a sound card or a @@ -55,7 +55,7 @@ config USB_MR800 config USB_DSBR tristate "D-Link/GemTek USB FM radio support" depends on USB && VIDEO_V4L2 - ---help--- + help Say Y here if you want to connect this type of radio to your computer's USB port. Note that the audio is not digital, and you must connect the line out connector to a sound card or a @@ -68,7 +68,7 @@ config RADIO_MAXIRADIO tristate "Guillemot MAXI Radio FM 2000 radio" depends on VIDEO_V4L2 && PCI select RADIO_TEA575X - ---help--- + help Choose Y here if you have this radio card. This card may also be found as Gemtek PCI FM. @@ -84,7 +84,7 @@ config RADIO_SHARK tristate "Griffin radioSHARK USB radio receiver" depends on USB select RADIO_TEA575X - ---help--- + help Choose Y here if you have this radio receiver. There are 2 versions of this device, this driver is for version 1, @@ -101,7 +101,7 @@ config RADIO_SHARK config RADIO_SHARK2 tristate "Griffin radioSHARK2 USB radio receiver" depends on USB - ---help--- + help Choose Y here if you have this radio receiver. There are 2 versions of this device, this driver is for version 2, @@ -118,7 +118,7 @@ config RADIO_SHARK2 config USB_KEENE tristate "Keene FM Transmitter USB support" depends on USB && VIDEO_V4L2 - ---help--- + help Say Y here if you want to connect this type of FM transmitter to your computer's USB port. @@ -128,7 +128,7 @@ config USB_KEENE config USB_RAREMONO tristate "Thanko's Raremono AM/FM/SW radio support" depends on USB && VIDEO_V4L2 - ---help--- + help The 'Thanko's Raremono' device contains the Si4734 chip from Silicon Labs Inc. It is one of the very few or perhaps the only consumer USB radio device to receive the AM/FM/SW bands. @@ -142,7 +142,7 @@ config USB_RAREMONO config USB_MA901 tristate "Masterkit MA901 USB FM radio support" depends on USB && VIDEO_V4L2 - ---help--- + help Say Y here if you want to connect this type of radio to your computer's USB port. Note that the audio is not digital, and you must connect the line out connector to a sound card or a @@ -154,7 +154,7 @@ config USB_MA901 config RADIO_TEA5764 tristate "TEA5764 I2C FM radio support" depends on I2C && VIDEO_V4L2 - ---help--- + help Say Y here if you want to use the TEA5764 FM chip found in EZX phones. This FM chip is present in EZX phones from Motorola, connected to internal pxa I2C bus. @@ -173,7 +173,7 @@ config RADIO_TEA5764_XTAL config RADIO_SAA7706H tristate "SAA7706H Car Radio DSP" depends on I2C && VIDEO_V4L2 - ---help--- + help Say Y here if you want to use the SAA7706H Car radio Digital Signal Processor, found for instance on the Russellville development board. On the russellville the device is connected to internal @@ -185,7 +185,7 @@ config RADIO_SAA7706H config RADIO_TEF6862 tristate "TEF6862 Car Radio Enhanced Selectivity Tuner" depends on I2C && VIDEO_V4L2 - ---help--- + help Say Y here if you want to use the TEF6862 Car Radio Enhanced Selectivity Tuner, found for instance on the Russellville development board. On the russellville the device is connected to internal @@ -200,7 +200,7 @@ config RADIO_TIMBERDALE depends on I2C # for RADIO_SAA7706H select RADIO_TEF6862 select RADIO_SAA7706H - ---help--- + help This is a kind of umbrella driver for the Radio Tuner and DSP found behind the Timberdale FPGA on the Russellville board. Enabling this driver will automatically select the DSP and tuner. @@ -211,7 +211,7 @@ config RADIO_WL1273 select MFD_CORE select MFD_WL1273_CORE select FW_LOADER - ---help--- + help Choose Y here if you have this FM radio chip. In order to control your radio card, you will need to use programs @@ -233,7 +233,7 @@ menuconfig V4L_RADIO_ISA_DRIVERS bool "ISA radio devices" depends on ISA || COMPILE_TEST default n - ---help--- + help Say Y here to enable support for these ISA drivers. if V4L_RADIO_ISA_DRIVERS @@ -246,7 +246,7 @@ config RADIO_CADET tristate "ADS Cadet AM/FM Tuner" depends on ISA || COMPILE_TEST depends on VIDEO_V4L2 - ---help--- + help Choose Y here if you have one of these AM/FM radio cards, and then fill in the port address below. @@ -258,7 +258,7 @@ config RADIO_RTRACK depends on ISA || COMPILE_TEST depends on VIDEO_V4L2 select RADIO_ISA - ---help--- + help Choose Y here if you have one of these FM radio cards, and then fill in the port address below. @@ -290,7 +290,7 @@ config RADIO_RTRACK2 depends on ISA || COMPILE_TEST depends on VIDEO_V4L2 select RADIO_ISA - ---help--- + help Choose Y here if you have this FM radio card, and then fill in the port address below. @@ -314,7 +314,7 @@ config RADIO_AZTECH depends on ISA || COMPILE_TEST depends on VIDEO_V4L2 select RADIO_ISA - ---help--- + help Choose Y here if you have one of these FM radio cards, and then fill in the port address below. @@ -335,7 +335,7 @@ config RADIO_GEMTEK depends on ISA || COMPILE_TEST depends on VIDEO_V4L2 select RADIO_ISA - ---help--- + help Choose Y here if you have this FM radio card, and then fill in the I/O port address and settings below. The following cards either have GemTek Radio tuner or are rebranded GemTek Radio cards: @@ -377,7 +377,7 @@ config RADIO_MIROPCM20 depends on ISA_DMA_API && VIDEO_V4L2 && SND select SND_ISA select SND_MIRO - ---help--- + help Choose Y here if you have this FM radio card. You also need to enable the ALSA sound system. This choice automatically selects the ALSA sound card driver "Miro miroSOUND PCM1pro/PCM12/PCM20radio" as this @@ -390,7 +390,7 @@ config RADIO_SF16FMI tristate "SF16-FMI/SF16-FMP/SF16-FMD Radio" depends on ISA || COMPILE_TEST depends on VIDEO_V4L2 - ---help--- + help Choose Y here if you have one of these FM radio cards. To compile this driver as a module, choose M here: the @@ -401,7 +401,7 @@ config RADIO_SF16FMR2 depends on ISA || COMPILE_TEST depends on VIDEO_V4L2 select RADIO_TEA575X - ---help--- + help Choose Y here if you have one of these FM radio cards. To compile this driver as a module, choose M here: the @@ -412,7 +412,7 @@ config RADIO_TERRATEC depends on ISA || COMPILE_TEST depends on VIDEO_V4L2 select RADIO_ISA - ---help--- + help Choose Y here if you have this FM radio card. Note: this driver hasn't been tested since a long time due to lack @@ -451,7 +451,7 @@ config RADIO_TYPHOON depends on ISA || COMPILE_TEST depends on VIDEO_V4L2 select RADIO_ISA - ---help--- + help Choose Y here if you have one of these FM radio cards, and then fill in the port address and the frequency used for muting below. @@ -486,7 +486,7 @@ config RADIO_ZOLTRIX depends on ISA || COMPILE_TEST depends on VIDEO_V4L2 select RADIO_ISA - ---help--- + help Choose Y here if you have one of these FM radio cards, and then fill in the port address below. diff --git a/drivers/media/radio/si470x/Kconfig b/drivers/media/radio/si470x/Kconfig index 6dbb158cd2a0..21026488de90 100644 --- a/drivers/media/radio/si470x/Kconfig +++ b/drivers/media/radio/si470x/Kconfig @@ -1,7 +1,7 @@ config RADIO_SI470X tristate "Silicon Labs Si470x FM Radio Receiver support" depends on VIDEO_V4L2 - ---help--- + help This is a driver for devices with the Silicon Labs SI470x chip (either via USB or I2C buses). @@ -15,7 +15,7 @@ config RADIO_SI470X config USB_SI470X tristate "Silicon Labs Si470x FM Radio Receiver support with USB" depends on USB && RADIO_SI470X - ---help--- + help This is a driver for USB devices with the Silicon Labs SI470x chip. Currently these devices are known to work: - 10c4:818a: Silicon Labs USB FM Radio Reference Design @@ -40,7 +40,7 @@ config USB_SI470X config I2C_SI470X tristate "Silicon Labs Si470x FM Radio Receiver support with I2C" depends on I2C && RADIO_SI470X - ---help--- + help This is a driver for I2C devices with the Silicon Labs SI470x chip. diff --git a/drivers/media/radio/si4713/Kconfig b/drivers/media/radio/si4713/Kconfig index 9c8b887cff75..17567c917554 100644 --- a/drivers/media/radio/si4713/Kconfig +++ b/drivers/media/radio/si4713/Kconfig @@ -2,7 +2,7 @@ config USB_SI4713 tristate "Silicon Labs Si4713 FM Radio Transmitter support with USB" depends on USB && I2C && RADIO_SI4713 select I2C_SI4713 - ---help--- + help This is a driver for USB devices with the Silicon Labs SI4713 chip. Currently these devices are known to work. - 10c4:8244: Silicon Labs FM Transmitter USB device. @@ -17,7 +17,7 @@ config PLATFORM_SI4713 tristate "Silicon Labs Si4713 FM Radio Transmitter support with I2C" depends on I2C && RADIO_SI4713 select I2C_SI4713 - ---help--- + help This is a driver for I2C devices with the Silicon Labs SI4713 chip. @@ -30,7 +30,7 @@ config PLATFORM_SI4713 config I2C_SI4713 tristate "Silicon Labs Si4713 FM Radio Transmitter support" depends on I2C && RADIO_SI4713 - ---help--- + help Say Y here if you want support to Si4713 FM Radio Transmitter. This device can transmit audio through FM. It can transmit RDS and RBDS signals as well. This module is the v4l2 radio diff --git a/drivers/media/radio/si4713/si4713.c b/drivers/media/radio/si4713/si4713.c index f4a53f1e856e..a8584371a32d 100644 --- a/drivers/media/radio/si4713/si4713.c +++ b/drivers/media/radio/si4713/si4713.c @@ -1272,7 +1272,7 @@ static int si4713_g_modulator(struct v4l2_subdev *sd, struct v4l2_modulator *vm) if (vm->index > 0) return -EINVAL; - strncpy(vm->name, "FM Modulator", 32); + strscpy(vm->name, "FM Modulator", sizeof(vm->name)); vm->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_RDS | V4L2_TUNER_CAP_RDS_CONTROLS; diff --git a/drivers/media/radio/wl128x/fmdrv_common.c b/drivers/media/radio/wl128x/fmdrv_common.c index 3c8987af3772..053d51a5890a 100644 --- a/drivers/media/radio/wl128x/fmdrv_common.c +++ b/drivers/media/radio/wl128x/fmdrv_common.c @@ -489,7 +489,8 @@ int fmc_send_cmd(struct fmdev *fmdev, u8 fm_op, u16 type, void *payload, return -EIO; } /* Send response data to caller */ - if (response != NULL && response_len != NULL && evt_hdr->dlen) { + if (response != NULL && response_len != NULL && evt_hdr->dlen && + evt_hdr->dlen <= payload_len) { /* Skip header info and copy only response data */ skb_pull(skb, sizeof(struct fm_event_msg_hdr)); memcpy(response, skb->data, evt_hdr->dlen); @@ -583,6 +584,8 @@ static void fm_irq_handle_flag_getcmd_resp(struct fmdev *fmdev) return; fm_evt_hdr = (void *)skb->data; + if (fm_evt_hdr->dlen > sizeof(fmdev->irq_info.flag)) + return; /* Skip header info and copy only response data */ skb_pull(skb, sizeof(struct fm_event_msg_hdr)); @@ -1268,8 +1271,9 @@ static int fm_download_firmware(struct fmdev *fmdev, const u8 *fw_name) switch (action->type) { case ACTION_SEND_COMMAND: /* Send */ - if (fmc_send_cmd(fmdev, 0, 0, action->data, - action->size, NULL, NULL)) + ret = fmc_send_cmd(fmdev, 0, 0, action->data, + action->size, NULL, NULL); + if (ret) goto rel_fw; cmd_cnt++; @@ -1308,7 +1312,7 @@ static int load_default_rx_configuration(struct fmdev *fmdev) static int fm_power_up(struct fmdev *fmdev, u8 mode) { u16 payload; - __be16 asic_id, asic_ver; + __be16 asic_id = 0, asic_ver = 0; int resp_len, ret; u8 fw_name[50]; @@ -1520,7 +1524,7 @@ int fmc_prepare(struct fmdev *fmdev) } ret = 0; - } else if (ret == -1) { + } else if (ret < 0) { fmerr("st_register failed %d\n", ret); return -EAGAIN; } diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig index 96ce3e5524e0..3fc6ac15c66d 100644 --- a/drivers/media/rc/Kconfig +++ b/drivers/media/rc/Kconfig @@ -2,7 +2,7 @@ menuconfig RC_CORE tristate "Remote Controller support" depends on INPUT - ---help--- + help Enable support for Remote Controllers on Linux. This is needed in order to support several video capture adapters, standalone IR receivers/transmitters, and RF receivers. @@ -19,7 +19,7 @@ source "drivers/media/rc/keymaps/Kconfig" config LIRC bool "LIRC user interface" depends on RC_CORE - ---help--- + help Enable this option to enable the Linux Infrared Remote Control user interface (e.g. /dev/lirc*). This interface passes raw IR to and from userspace, which is needed for @@ -48,7 +48,7 @@ config IR_NEC_DECODER depends on RC_CORE select BITREVERSE - ---help--- + help Enable this option if you have IR with NEC protocol, and if the IR is decoded in software @@ -57,7 +57,7 @@ config IR_RC5_DECODER depends on RC_CORE select BITREVERSE - ---help--- + help Enable this option if you have IR with RC-5 protocol, and if the IR is decoded in software @@ -66,7 +66,7 @@ config IR_RC6_DECODER depends on RC_CORE select BITREVERSE - ---help--- + help Enable this option if you have an infrared remote control which uses the RC6 protocol, and you need software decoding support. @@ -75,7 +75,7 @@ config IR_JVC_DECODER depends on RC_CORE select BITREVERSE - ---help--- + help Enable this option if you have an infrared remote control which uses the JVC protocol, and you need software decoding support. @@ -84,7 +84,7 @@ config IR_SONY_DECODER depends on RC_CORE select BITREVERSE - ---help--- + help Enable this option if you have an infrared remote control which uses the Sony protocol, and you need software decoding support. @@ -92,7 +92,7 @@ config IR_SANYO_DECODER tristate "Enable IR raw decoder for the Sanyo protocol" depends on RC_CORE - ---help--- + help Enable this option if you have an infrared remote control which uses the Sanyo protocol (Sanyo, Aiwa, Chinon remotes), and you need software decoding support. @@ -101,7 +101,7 @@ config IR_SHARP_DECODER tristate "Enable IR raw decoder for the Sharp protocol" depends on RC_CORE - ---help--- + help Enable this option if you have an infrared remote control which uses the Sharp protocol (Sharp, Denon), and you need software decoding support. @@ -111,7 +111,7 @@ config IR_MCE_KBD_DECODER depends on RC_CORE select BITREVERSE - ---help--- + help Enable this option if you have a Microsoft Remote Keyboard for Windows Media Center Edition, which you would like to use with a raw IR receiver in your system. @@ -121,14 +121,14 @@ config IR_XMP_DECODER depends on RC_CORE select BITREVERSE - ---help--- + help Enable this option if you have IR with XMP protocol, and if the IR is decoded in software config IR_IMON_DECODER tristate "Enable IR raw decoder for the iMON protocol" depends on RC_CORE - ---help--- + help Enable this option if you have iMON PAD or Antec Veris infrared remote control and you would like to use it with a raw IR receiver, or if you wish to use an encoder to transmit this IR. @@ -177,7 +177,7 @@ config IR_ENE tristate "ENE eHome Receiver/Transceiver (pnp id: ENE0100/ENE02xxx)" depends on PNP || COMPILE_TEST depends on RC_CORE - ---help--- + help Say Y here to enable support for integrated infrared receiver /transceiver made by ENE. @@ -203,7 +203,7 @@ config IR_IMON depends on USB_ARCH_HAS_HCD depends on RC_CORE select USB - ---help--- + help Say Y here if you want to use a SoundGraph iMON (aka Antec Veris) IR Receiver and/or LCD/VFD/VGA display. @@ -215,7 +215,7 @@ config IR_IMON_RAW depends on USB_ARCH_HAS_HCD depends on RC_CORE select USB - ---help--- + help Say Y here if you want to use a SoundGraph iMON IR Receiver, early raw models. @@ -227,7 +227,7 @@ config IR_MCEUSB depends on USB_ARCH_HAS_HCD depends on RC_CORE select USB - ---help--- + help Say Y here if you want to use a Windows Media Center Edition eHome Infrared Transceiver. @@ -238,7 +238,7 @@ config IR_ITE_CIR tristate "ITE Tech Inc. IT8712/IT8512 Consumer Infrared Transceiver" depends on PNP || COMPILE_TEST depends on RC_CORE - ---help--- + help Say Y here to enable support for integrated infrared receivers /transceivers made by ITE Tech Inc. These are found in several ASUS devices, like the ASUS Digimatrix or the ASUS @@ -251,7 +251,7 @@ config IR_FINTEK tristate "Fintek Consumer Infrared Transceiver" depends on PNP || COMPILE_TEST depends on RC_CORE - ---help--- + help Say Y here to enable support for integrated infrared receiver /transceiver made by Fintek. This chip is found on assorted Jetway motherboards (and of course, possibly others). @@ -263,7 +263,7 @@ config IR_MESON tristate "Amlogic Meson IR remote receiver" depends on RC_CORE depends on ARCH_MESON || COMPILE_TEST - ---help--- + help Say Y if you want to use the IR remote receiver available on Amlogic Meson SoCs. @@ -274,7 +274,7 @@ config IR_MTK tristate "Mediatek IR remote receiver" depends on RC_CORE depends on ARCH_MEDIATEK || COMPILE_TEST - ---help--- + help Say Y if you want to use the IR remote receiver available on Mediatek SoCs. @@ -285,7 +285,7 @@ config IR_NUVOTON tristate "Nuvoton w836x7hg Consumer Infrared Transceiver" depends on PNP || COMPILE_TEST depends on RC_CORE - ---help--- + help Say Y here to enable support for integrated infrared receiver /transceiver made by Nuvoton (formerly Winbond). This chip is found in the ASRock ION 330HT, as well as assorted Intel @@ -301,7 +301,7 @@ config IR_REDRAT3 select NEW_LEDS select LEDS_CLASS select USB - ---help--- + help Say Y here if you want to use a RedRat3 Infrared Transceiver. To compile this driver as a module, choose M here: the @@ -311,7 +311,7 @@ config IR_SPI tristate "SPI connected IR LED" depends on SPI && LIRC depends on OF || COMPILE_TEST - ---help--- + help Say Y if you want to use an IR LED connected through SPI bus. To compile this driver as a module, choose M here: the module will be @@ -322,7 +322,7 @@ config IR_STREAMZAP depends on USB_ARCH_HAS_HCD depends on RC_CORE select USB - ---help--- + help Say Y here if you want to use a Streamzap PC Remote Infrared Receiver. @@ -336,7 +336,7 @@ config IR_WINBOND_CIR select NEW_LEDS select LEDS_CLASS select BITREVERSE - ---help--- + help Say Y here if you want to use the IR remote functionality found in some Winbond SuperI/O chips. Currently only the WPCD376I chip is supported (included in some Intel Media series @@ -350,7 +350,7 @@ config IR_IGORPLUGUSB depends on USB_ARCH_HAS_HCD depends on RC_CORE select USB - ---help--- + help Say Y here if you want to use the IgorPlug-USB IR Receiver by Igor Cesko. This device is included on the Fit-PC2. @@ -365,7 +365,7 @@ config IR_IGUANA depends on USB_ARCH_HAS_HCD depends on RC_CORE select USB - ---help--- + help Say Y here if you want to use the IguanaWorks USB IR Transceiver. Both infrared receive and send are supported. If you want to change the ID or the pin config, use the user space driver from @@ -383,7 +383,7 @@ config IR_TTUSBIR select USB select NEW_LEDS select LEDS_CLASS - ---help--- + help Say Y here if you want to use the TechnoTrend USB IR Receiver. The driver can control the led. @@ -393,7 +393,7 @@ config IR_TTUSBIR config IR_RX51 tristate "Nokia N900 IR transmitter diode" depends on (OMAP_DM_TIMER && PWM_OMAP_DMTIMER && ARCH_OMAP2PLUS || COMPILE_TEST) && RC_CORE - ---help--- + help Say Y or M here if you want to enable support for the IR transmitter diode built in the Nokia N900 (RX51) device. @@ -405,7 +405,7 @@ source "drivers/media/rc/img-ir/Kconfig" config RC_LOOPBACK tristate "Remote Control Loopback Driver" depends on RC_CORE - ---help--- + help Say Y here if you want support for the remote control loopback driver which allows TX data to be sent back as RX data. This is mostly useful for debugging purposes. @@ -419,7 +419,7 @@ config IR_GPIO_CIR tristate "GPIO IR remote control" depends on RC_CORE depends on (OF && GPIOLIB) || COMPILE_TEST - ---help--- + help Say Y if you want to use GPIO based IR Receiver. To compile this driver as a module, choose M here: the module will @@ -430,7 +430,7 @@ config IR_GPIO_TX depends on RC_CORE depends on LIRC depends on (OF && GPIOLIB) || COMPILE_TEST - ---help--- + help Say Y if you want to a GPIO based IR transmitter. This is a bit banging driver. @@ -443,7 +443,7 @@ config IR_PWM_TX depends on LIRC depends on PWM depends on OF || COMPILE_TEST - ---help--- + help Say Y if you want to use a PWM based IR transmitter. This is more power efficient than the bit banging gpio driver. @@ -454,7 +454,7 @@ config RC_ST tristate "ST remote control receiver" depends on RC_CORE depends on ARCH_STI || COMPILE_TEST - ---help--- + help Say Y here if you want support for ST remote control driver which allows both IR and UHF RX. The driver passes raw pulse and space information to the LIRC decoder. @@ -465,7 +465,7 @@ config IR_SUNXI tristate "SUNXI IR remote control" depends on RC_CORE depends on ARCH_SUNXI || COMPILE_TEST - ---help--- + help Say Y if you want to use sunXi internal IR Controller To compile this driver as a module, choose M here: the module will @@ -474,7 +474,7 @@ config IR_SUNXI config IR_SERIAL tristate "Homebrew Serial Port Receiver" depends on RC_CORE - ---help--- + help Say Y if you want to use Homebrew Serial Port Receivers and Transceivers. @@ -484,13 +484,13 @@ config IR_SERIAL config IR_SERIAL_TRANSMITTER bool "Serial Port Transmitter" depends on IR_SERIAL - ---help--- + help Serial Port Transmitter support config IR_SIR tristate "Built-in SIR IrDA port" depends on RC_CORE - ---help--- + help Say Y if you want to use a IrDA SIR port Transceivers. To compile this driver as a module, choose M here: the module will @@ -500,7 +500,7 @@ config IR_TANGO tristate "Sigma Designs SMP86xx IR decoder" depends on RC_CORE depends on ARCH_TANGO || COMPILE_TEST - ---help--- + help Adds support for the HW IR decoder embedded on Sigma Designs Tango-based systems (SMP86xx, SMP87xx). The HW decoder supports NEC, RC-5, RC-6 IR protocols. @@ -522,7 +522,7 @@ config IR_ZX tristate "ZTE ZX IR remote control" depends on RC_CORE depends on ARCH_ZX || COMPILE_TEST - ---help--- + help Say Y if you want to use the IR remote control available on ZTE ZX family SoCs. diff --git a/drivers/media/rc/ir-rcmm-decoder.c b/drivers/media/rc/ir-rcmm-decoder.c index f1096ac1e5c5..64fb65a9a19f 100644 --- a/drivers/media/rc/ir-rcmm-decoder.c +++ b/drivers/media/rc/ir-rcmm-decoder.c @@ -5,7 +5,6 @@ #include "rc-core-priv.h" #include <linux/module.h> -#include <linux/version.h> #define RCMM_UNIT 166667 /* nanosecs */ #define RCMM_PREFIX_PULSE 416666 /* 166666.666666666*2.5 */ diff --git a/drivers/media/rc/keymaps/Kconfig b/drivers/media/rc/keymaps/Kconfig index 767423bbbdd0..f459096d8e9c 100644 --- a/drivers/media/rc/keymaps/Kconfig +++ b/drivers/media/rc/keymaps/Kconfig @@ -3,7 +3,7 @@ config RC_MAP depends on RC_CORE default y - ---help--- + help This option enables the compilation of lots of Remote Controller tables. They are short tables, but if you don't use a remote controller, or prefer to load the diff --git a/drivers/media/rc/keymaps/rc-xbox-dvd.c b/drivers/media/rc/keymaps/rc-xbox-dvd.c index af387244636b..42815ab57bff 100644 --- a/drivers/media/rc/keymaps/rc-xbox-dvd.c +++ b/drivers/media/rc/keymaps/rc-xbox-dvd.c @@ -42,7 +42,7 @@ static struct rc_map_list xbox_dvd_map = { .map = { .scan = xbox_dvd, .size = ARRAY_SIZE(xbox_dvd), - .rc_proto = RC_PROTO_UNKNOWN, + .rc_proto = RC_PROTO_XBOX_DVD, .name = RC_MAP_XBOX_DVD, } }; diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index e8fa28e20192..be5fd129d728 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -76,6 +76,7 @@ static const struct { .scancode_bits = 0x00ffffff, .repeat_period = 114 }, [RC_PROTO_RCMM32] = { .name = "rc-mm-32", .scancode_bits = 0xffffffff, .repeat_period = 114 }, + [RC_PROTO_XBOX_DVD] = { .name = "xbox-dvd", .repeat_period = 64 }, }; /* Used to keep track of known keymaps */ @@ -1027,6 +1028,7 @@ static const struct { { RC_PROTO_BIT_RCMM12 | RC_PROTO_BIT_RCMM24 | RC_PROTO_BIT_RCMM32, "rc-mm", "ir-rcmm-decoder" }, + { RC_PROTO_BIT_XBOX_DVD, "xbox-dvd", NULL }, }; /** diff --git a/drivers/media/rc/serial_ir.c b/drivers/media/rc/serial_ir.c index ffe2c672d105..3998ba29beb6 100644 --- a/drivers/media/rc/serial_ir.c +++ b/drivers/media/rc/serial_ir.c @@ -773,8 +773,6 @@ static void serial_ir_exit(void) static int __init serial_ir_init_module(void) { - int result; - switch (type) { case IR_HOMEBREW: case IR_IRDEO: @@ -802,12 +800,7 @@ static int __init serial_ir_init_module(void) if (sense != -1) sense = !!sense; - result = serial_ir_init(); - if (!result) - return 0; - - serial_ir_exit(); - return result; + return serial_ir_init(); } static void __exit serial_ir_exit_module(void) diff --git a/drivers/media/rc/xbox_remote.c b/drivers/media/rc/xbox_remote.c index f959cbb94744..4a3f2cc4ef18 100644 --- a/drivers/media/rc/xbox_remote.c +++ b/drivers/media/rc/xbox_remote.c @@ -107,7 +107,7 @@ static void xbox_remote_input_report(struct urb *urb) return; } - rc_keydown(xbox_remote->rdev, RC_PROTO_UNKNOWN, + rc_keydown(xbox_remote->rdev, RC_PROTO_XBOX_DVD, le16_to_cpup((__le16 *)(data + 2)), 0); } @@ -148,7 +148,7 @@ static void xbox_remote_rc_init(struct xbox_remote *xbox_remote) struct rc_dev *rdev = xbox_remote->rdev; rdev->priv = xbox_remote; - rdev->allowed_protocols = RC_PROTO_BIT_UNKNOWN; + rdev->allowed_protocols = RC_PROTO_BIT_XBOX_DVD; rdev->driver_name = "xbox_remote"; rdev->open = xbox_remote_rc_open; @@ -157,6 +157,8 @@ static void xbox_remote_rc_init(struct xbox_remote *xbox_remote) rdev->device_name = xbox_remote->rc_name; rdev->input_phys = xbox_remote->rc_phys; + rdev->timeout = MS_TO_NS(10); + usb_to_input_id(xbox_remote->udev, &rdev->input_id); rdev->dev.parent = &xbox_remote->interface->dev; } diff --git a/drivers/media/spi/Kconfig b/drivers/media/spi/Kconfig index b07ac86fc53c..df169ecf0c27 100644 --- a/drivers/media/spi/Kconfig +++ b/drivers/media/spi/Kconfig @@ -6,7 +6,7 @@ menu "SPI helper chips" config VIDEO_GS1662 tristate "Gennum Serializers video" depends on SPI && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API - ---help--- + help Enable the GS1662 driver which serializes video streams. endmenu diff --git a/drivers/media/usb/airspy/Kconfig b/drivers/media/usb/airspy/Kconfig index 10b204cf4dbc..67578511bb9a 100644 --- a/drivers/media/usb/airspy/Kconfig +++ b/drivers/media/usb/airspy/Kconfig @@ -2,7 +2,7 @@ config USB_AIRSPY tristate "AirSpy" depends on VIDEO_V4L2 select VIDEOBUF2_VMALLOC - ---help--- + help This is a video4linux2 driver for AirSpy SDR device. To compile this driver as a module, choose M here: the diff --git a/drivers/media/usb/au0828/Kconfig b/drivers/media/usb/au0828/Kconfig index 65fc067eb864..0ad985542c60 100644 --- a/drivers/media/usb/au0828/Kconfig +++ b/drivers/media/usb/au0828/Kconfig @@ -2,6 +2,8 @@ config VIDEO_AU0828 tristate "Auvitek AU0828 support" depends on I2C && INPUT && DVB_CORE && USB && VIDEO_V4L2 + select MEDIA_CONTROLLER + select MEDIA_CONTROLLER_DVB select I2C_ALGOBIT select VIDEO_TVEEPROM select VIDEOBUF2_VMALLOC if VIDEO_V4L2 @@ -9,7 +11,7 @@ config VIDEO_AU0828 select MEDIA_TUNER_XC5000 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_MXL5007T if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_TDA18271 if MEDIA_SUBDRV_AUTOSELECT - ---help--- + help This is a hybrid analog/digital tv capture driver for Auvitek's AU0828 USB device. @@ -23,7 +25,7 @@ config VIDEO_AU0828_V4L2 select DVB_AU8522_V4L if MEDIA_SUBDRV_AUTOSELECT select VIDEO_TUNER default y - ---help--- + help This is a video4linux driver for Auvitek's USB device. Choose Y here to include support for v4l2 analog video @@ -34,5 +36,5 @@ config VIDEO_AU0828_RC depends on RC_CORE depends on !(RC_CORE=m && VIDEO_AU0828=y) depends on VIDEO_AU0828 - ---help--- + help Enables Remote Controller support on au0828 driver. diff --git a/drivers/media/usb/au0828/au0828-core.c b/drivers/media/usb/au0828/au0828-core.c index 3f8c92a70116..925a80437822 100644 --- a/drivers/media/usb/au0828/au0828-core.c +++ b/drivers/media/usb/au0828/au0828-core.c @@ -155,9 +155,7 @@ static void au0828_unregister_media_device(struct au0828_dev *dev) dev->media_dev->disable_source = NULL; mutex_unlock(&mdev->graph_mutex); - media_device_unregister(dev->media_dev); - media_device_cleanup(dev->media_dev); - kfree(dev->media_dev); + media_device_delete(dev->media_dev, KBUILD_MODNAME, THIS_MODULE); dev->media_dev = NULL; #endif } @@ -210,14 +208,10 @@ static int au0828_media_device_init(struct au0828_dev *dev, #ifdef CONFIG_MEDIA_CONTROLLER struct media_device *mdev; - mdev = kzalloc(sizeof(*mdev), GFP_KERNEL); + mdev = media_device_usb_allocate(udev, KBUILD_MODNAME, THIS_MODULE); if (!mdev) return -ENOMEM; - /* check if media device is already initialized */ - if (!mdev->dev) - media_device_usb_init(mdev, udev, udev->product); - dev->media_dev = mdev; #endif return 0; @@ -278,6 +272,28 @@ create_link: } } +static bool au0828_is_link_shareable(struct media_entity *owner, + struct media_entity *entity) +{ + bool shareable = false; + + /* Tuner link can be shared by audio, video, and VBI */ + switch (owner->function) { + case MEDIA_ENT_F_IO_V4L: + case MEDIA_ENT_F_AUDIO_CAPTURE: + case MEDIA_ENT_F_IO_VBI: + if (entity->function == MEDIA_ENT_F_IO_V4L || + entity->function == MEDIA_ENT_F_AUDIO_CAPTURE || + entity->function == MEDIA_ENT_F_IO_VBI) + shareable = true; + break; + case MEDIA_ENT_F_DTV_DEMOD: + default: + break; + } + return shareable; +} + /* Callers should hold graph_mutex */ static int au0828_enable_source(struct media_entity *entity, struct media_pipeline *pipe) @@ -320,18 +336,20 @@ static int au0828_enable_source(struct media_entity *entity, /* * Default input is tuner and default input_type * is AU0828_VMUX_TELEVISION. - * FIXME: + * * There is a problem when s_input is called to * change the default input. s_input will try to * enable_source before attempting to change the * input on the device, and will end up enabling * default source which is tuner. * - * Additional logic is necessary in au0828 - * to detect that the input has changed and - * enable the right source. + * Additional logic is necessary in au0828 to detect + * that the input has changed and enable the right + * source. au0828 handles this case in its s_input. + * It will disable the old source and enable the new + * source. + * */ - if (dev->input_type == AU0828_VMUX_TELEVISION) find_source = dev->tuner; else if (dev->input_type == AU0828_VMUX_SVIDEO || @@ -344,27 +362,33 @@ static int au0828_enable_source(struct media_entity *entity, } } - /* Is an active link between sink and source */ + /* Is there an active link between sink and source */ if (dev->active_link) { - /* - * If DVB is using the tuner and calling entity is - * audio/video, the following check will be false, - * since sink is different. Result is Busy. - */ - if (dev->active_link->sink->entity == sink && - dev->active_link->source->entity == find_source) { - /* - * Either ALSA or Video own tuner. sink is - * the same for both. Prevent Video stepping - * on ALSA when ALSA owns the source. + if (dev->active_link_owner == entity) { + /* This check is necessary to handle multiple + * enable_source calls from v4l_ioctls during + * the course of video/vbi application run-time. */ - if (dev->active_link_owner != entity && - dev->active_link_owner->function == - MEDIA_ENT_F_AUDIO_CAPTURE) { - pr_debug("ALSA has the tuner\n"); - ret = -EBUSY; - goto end; - } + pr_debug("%s already owns the tuner\n", entity->name); + ret = 0; + goto end; + } else if (au0828_is_link_shareable(dev->active_link_owner, + entity)) { + /* Either ALSA or Video own tuner. Sink is the same + * for both. Allow sharing the active link between + * their common source (tuner) and sink (decoder). + * Starting pipeline between sharing entity and sink + * will fail with pipe mismatch, while owner has an + * active pipeline. Switch pipeline ownership from + * user to owner when owner disables the source. + */ + dev->active_link_shared = true; + /* save the user info to use from disable */ + dev->active_link_user = entity; + dev->active_link_user_pipe = pipe; + pr_debug("%s owns the tuner %s can share!\n", + dev->active_link_owner->name, + entity->name); ret = 0; goto end; } else { @@ -391,7 +415,7 @@ static int au0828_enable_source(struct media_entity *entity, source = found_link->source->entity; ret = __media_entity_setup_link(found_link, MEDIA_LNK_FL_ENABLED); if (ret) { - pr_err("Activate tuner link %s->%s. Error %d\n", + pr_err("Activate link from %s->%s. Error %d\n", source->name, sink->name, ret); goto end; } @@ -401,25 +425,26 @@ static int au0828_enable_source(struct media_entity *entity, pr_err("Start Pipeline: %s->%s Error %d\n", source->name, entity->name, ret); ret = __media_entity_setup_link(found_link, 0); - pr_err("Deactivate link Error %d\n", ret); + if (ret) + pr_err("Deactivate link Error %d\n", ret); goto end; } - /* - * save active link and active link owner to avoid audio - * deactivating video owned link from disable_source and - * vice versa + + /* save link state to allow audio and video share the link + * and not disable the link while the other is using it. + * active_link_owner is used to deactivate the link. */ dev->active_link = found_link; dev->active_link_owner = entity; dev->active_source = source; dev->active_sink = sink; - pr_debug("Enabled Source: %s->%s->%s Ret %d\n", + pr_info("Enabled Source: %s->%s->%s Ret %d\n", dev->active_source->name, dev->active_sink->name, dev->active_link_owner->name, ret); end: - pr_debug("au0828_enable_source() end %s %d %d\n", - entity->name, entity->function, ret); + pr_debug("%s end: ent:%s fnc:%d ret %d\n", + __func__, entity->name, entity->function, ret); return ret; } @@ -438,21 +463,95 @@ static void au0828_disable_source(struct media_entity *entity) if (!dev->active_link) return; - /* link is active - stop pipeline from source (tuner) */ + /* link is active - stop pipeline from source + * (tuner/s-video/Composite) to the entity + * When DVB/s-video/Composite owns tuner, it won't be in + * shared state. + */ if (dev->active_link->sink->entity == dev->active_sink && dev->active_link->source->entity == dev->active_source) { /* - * prevent video from deactivating link when audio - * has active pipeline + * Prevent video from deactivating link when audio + * has active pipeline and vice versa. In addition + * handle the case when more than one video/vbi + * application is sharing the link. */ + bool owner_is_audio = false; + + if (dev->active_link_owner->function == + MEDIA_ENT_F_AUDIO_CAPTURE) + owner_is_audio = true; + + if (dev->active_link_shared) { + pr_debug("Shared link owner %s user %s %d\n", + dev->active_link_owner->name, + entity->name, dev->users); + + /* Handle video device users > 1 + * When audio owns the shared link with + * more than one video users, avoid + * disabling the source and/or switching + * the owner until the last disable_source + * call from video _close(). Use dev->users to + * determine when to switch/disable. + */ + if (dev->active_link_owner != entity) { + /* video device has users > 1 */ + if (owner_is_audio && dev->users > 1) + return; + + dev->active_link_user = NULL; + dev->active_link_user_pipe = NULL; + dev->active_link_shared = false; + return; + } + + /* video owns the link and has users > 1 */ + if (!owner_is_audio && dev->users > 1) + return; + + /* stop pipeline */ + __media_pipeline_stop(dev->active_link_owner); + pr_debug("Pipeline stop for %s\n", + dev->active_link_owner->name); + + ret = __media_pipeline_start( + dev->active_link_user, + dev->active_link_user_pipe); + if (ret) { + pr_err("Start Pipeline: %s->%s %d\n", + dev->active_source->name, + dev->active_link_user->name, + ret); + goto deactivate_link; + } + /* link user is now the owner */ + dev->active_link_owner = dev->active_link_user; + dev->active_link_user = NULL; + dev->active_link_user_pipe = NULL; + dev->active_link_shared = false; + + pr_debug("Pipeline started for %s\n", + dev->active_link_owner->name); + return; + } else if (!owner_is_audio && dev->users > 1) + /* video/vbi owns the link and has users > 1 */ + return; + if (dev->active_link_owner != entity) return; - __media_pipeline_stop(entity); + + /* stop pipeline */ + __media_pipeline_stop(dev->active_link_owner); + pr_debug("Pipeline stop for %s\n", + dev->active_link_owner->name); + +deactivate_link: ret = __media_entity_setup_link(dev->active_link, 0); if (ret) pr_err("Deactivate link Error %d\n", ret); - pr_debug("Disabled Source: %s->%s->%s Ret %d\n", + pr_info("Disabled Source: %s->%s->%s Ret %d\n", dev->active_source->name, dev->active_sink->name, dev->active_link_owner->name, ret); @@ -460,6 +559,8 @@ static void au0828_disable_source(struct media_entity *entity) dev->active_link_owner = NULL; dev->active_source = NULL; dev->active_sink = NULL; + dev->active_link_shared = false; + dev->active_link_user = NULL; } } #endif @@ -480,6 +581,9 @@ static int au0828_media_device_register(struct au0828_dev *dev, /* register media device */ ret = media_device_register(dev->media_dev); if (ret) { + media_device_delete(dev->media_dev, KBUILD_MODNAME, + THIS_MODULE); + dev->media_dev = NULL; dev_err(&udev->dev, "Media Device Register Error: %d\n", ret); return ret; diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c index 7876c897cc1d..4bde3db83aa2 100644 --- a/drivers/media/usb/au0828/au0828-video.c +++ b/drivers/media/usb/au0828/au0828-video.c @@ -758,6 +758,9 @@ static int au0828_analog_stream_enable(struct au0828_dev *d) dprintk(1, "au0828_analog_stream_enable called\n"); + if (test_bit(DEV_DISCONNECTED, &d->dev_state)) + return -ENODEV; + iface = usb_ifnum_to_if(d->usbdev, 0); if (iface && iface->cur_altsetting->desc.bAlternateSetting != 5) { dprintk(1, "Changing intf#0 to alt 5\n"); @@ -839,9 +842,9 @@ int au0828_start_analog_streaming(struct vb2_queue *vq, unsigned int count) return rc; } + v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 1); + if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { - v4l2_device_call_all(&dev->v4l2_dev, 0, video, - s_stream, 1); dev->vid_timeout_running = 1; mod_timer(&dev->vid_timeout, jiffies + (HZ / 10)); } else if (vq->type == V4L2_BUF_TYPE_VBI_CAPTURE) { @@ -861,10 +864,11 @@ static void au0828_stop_streaming(struct vb2_queue *vq) dprintk(1, "au0828_stop_streaming called %d\n", dev->streaming_users); - if (dev->streaming_users-- == 1) + if (dev->streaming_users-- == 1) { au0828_uninit_isoc(dev); + v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 0); + } - v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 0); dev->vid_timeout_running = 0; del_timer_sync(&dev->vid_timeout); @@ -893,8 +897,10 @@ void au0828_stop_vbi_streaming(struct vb2_queue *vq) dprintk(1, "au0828_stop_vbi_streaming called %d\n", dev->streaming_users); - if (dev->streaming_users-- == 1) + if (dev->streaming_users-- == 1) { au0828_uninit_isoc(dev); + v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 0); + } spin_lock_irqsave(&dev->slock, flags); if (dev->isoc_ctl.vbi_buf != NULL) { @@ -1065,7 +1071,7 @@ static int au0828_v4l2_close(struct file *filp) * streaming. * * On most USB devices like au0828 the tuner can - * be safely put in sleep stare here if ALSA isn't + * be safely put in sleep state here if ALSA isn't * streaming. Exceptions are some very old USB tuner * models such as em28xx-based WinTV USB2 which have * a separate audio output jack. The devices that have @@ -1074,7 +1080,7 @@ static int au0828_v4l2_close(struct file *filp) * so the s_power callback are silently ignored. * So, the current logic here does the following: * Disable (put tuner to sleep) when - * - ALSA and DVB aren't not streaming; + * - ALSA and DVB aren't streaming. * - the last V4L2 file handler is closed. * * FIXME: diff --git a/drivers/media/usb/au0828/au0828.h b/drivers/media/usb/au0828/au0828.h index 425c35d16057..b47ecc9affd8 100644 --- a/drivers/media/usb/au0828/au0828.h +++ b/drivers/media/usb/au0828/au0828.h @@ -31,6 +31,7 @@ #include <media/v4l2-ctrls.h> #include <media/v4l2-fh.h> #include <media/media-device.h> +#include <media/media-dev-allocator.h> /* DVB */ #include <media/demux.h> @@ -283,9 +284,12 @@ struct au0828_dev { struct media_entity_notify entity_notify; struct media_entity *tuner; struct media_link *active_link; - struct media_entity *active_link_owner; struct media_entity *active_source; struct media_entity *active_sink; + struct media_entity *active_link_owner; + struct media_entity *active_link_user; + struct media_pipeline *active_link_user_pipe; + bool active_link_shared; #endif }; diff --git a/drivers/media/usb/cpia2/Kconfig b/drivers/media/usb/cpia2/Kconfig index 66e9283f5993..7029a04f3ffd 100644 --- a/drivers/media/usb/cpia2/Kconfig +++ b/drivers/media/usb/cpia2/Kconfig @@ -1,7 +1,7 @@ config VIDEO_CPIA2 tristate "CPiA2 Video For Linux" depends on VIDEO_DEV && USB && VIDEO_V4L2 - ---help--- + help This is the video4linux driver for cameras based on Vision's CPiA2 (Colour Processor Interface ASIC), such as the Digital Blue QX5 Microscope. If you have one of these cameras, say Y here diff --git a/drivers/media/usb/cpia2/cpia2_v4l.c b/drivers/media/usb/cpia2/cpia2_v4l.c index 95c0bd4a19dc..45caf78119c4 100644 --- a/drivers/media/usb/cpia2/cpia2_v4l.c +++ b/drivers/media/usb/cpia2/cpia2_v4l.c @@ -1240,8 +1240,7 @@ static int __init cpia2_init(void) LOG("%s v%s\n", ABOUT, CPIA_VERSION); check_parameters(); - cpia2_usb_init(); - return 0; + return cpia2_usb_init(); } diff --git a/drivers/media/usb/cx231xx/Kconfig b/drivers/media/usb/cx231xx/Kconfig index 9e5b3e7c3ef5..9262d0d7439a 100644 --- a/drivers/media/usb/cx231xx/Kconfig +++ b/drivers/media/usb/cx231xx/Kconfig @@ -7,7 +7,7 @@ config VIDEO_CX231XX select VIDEO_CX25840 select VIDEO_CX2341X - ---help--- + help This is a video4linux driver for Conexant 231xx USB based TV cards. To compile this driver as a module, choose M here: the @@ -18,7 +18,7 @@ config VIDEO_CX231XX_RC depends on RC_CORE=y || RC_CORE=VIDEO_CX231XX depends on VIDEO_CX231XX default y - ---help--- + help cx231xx hardware has a builtin RX/TX support. However, a few designs opted to not use it, but, instead, some other hardware. This module enables the usage of those other hardware, like the @@ -31,7 +31,7 @@ config VIDEO_CX231XX_ALSA depends on VIDEO_CX231XX && SND select SND_PCM - ---help--- + help This is an ALSA driver for Cx231xx USB based TV cards. To compile this driver as a module, choose M here: the @@ -52,6 +52,6 @@ config VIDEO_CX231XX_DVB select DVB_MN88473 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_R820T if MEDIA_SUBDRV_AUTOSELECT - ---help--- + help This adds support for DVB cards based on the Conexant cx231xx chips. diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c index 80d3bd3a0f24..1b7f1af399fb 100644 --- a/drivers/media/usb/dvb-usb-v2/af9035.c +++ b/drivers/media/usb/dvb-usb-v2/af9035.c @@ -846,6 +846,7 @@ static int af9035_read_config(struct dvb_usb_device *d) state->af9033_config[1].adc_multiplier = AF9033_ADC_MULTIPLIER_2X; state->af9033_config[0].ts_mode = AF9033_TS_MODE_USB; state->af9033_config[1].ts_mode = AF9033_TS_MODE_SERIAL; + state->it930x_addresses = 0; if (state->chip_type == 0x9135) { /* feed clock for integrated RF tuner */ @@ -872,6 +873,10 @@ static int af9035_read_config(struct dvb_usb_device *d) * IT930x is an USB bridge, only single demod-single tuner * configurations seen so far. */ + if ((le16_to_cpu(d->udev->descriptor.idVendor) == USB_VID_AVERMEDIA) && + (le16_to_cpu(d->udev->descriptor.idProduct) == USB_PID_AVERMEDIA_TD310)) { + state->it930x_addresses = 1; + } return 0; } @@ -1218,6 +1223,48 @@ static int it930x_frontend_attach(struct dvb_usb_adapter *adap) dev_dbg(&intf->dev, "adap->id=%d\n", adap->id); + /* I2C master bus 2 clock speed 300k */ + ret = af9035_wr_reg(d, 0x00f6a7, 0x07); + if (ret < 0) + goto err; + + /* I2C master bus 1,3 clock speed 300k */ + ret = af9035_wr_reg(d, 0x00f103, 0x07); + if (ret < 0) + goto err; + + /* set gpio11 low */ + ret = af9035_wr_reg_mask(d, 0xd8d4, 0x01, 0x01); + if (ret < 0) + goto err; + + ret = af9035_wr_reg_mask(d, 0xd8d5, 0x01, 0x01); + if (ret < 0) + goto err; + + ret = af9035_wr_reg_mask(d, 0xd8d3, 0x01, 0x01); + if (ret < 0) + goto err; + + /* Tuner enable using gpiot2_en, gpiot2_on and gpiot2_o (reset) */ + ret = af9035_wr_reg_mask(d, 0xd8b8, 0x01, 0x01); + if (ret < 0) + goto err; + + ret = af9035_wr_reg_mask(d, 0xd8b9, 0x01, 0x01); + if (ret < 0) + goto err; + + ret = af9035_wr_reg_mask(d, 0xd8b7, 0x00, 0x01); + if (ret < 0) + goto err; + + msleep(200); + + ret = af9035_wr_reg_mask(d, 0xd8b7, 0x01, 0x01); + if (ret < 0) + goto err; + memset(&si2168_config, 0, sizeof(si2168_config)); si2168_config.i2c_adapter = &adapter; si2168_config.fe = &adap->fe[0]; @@ -1225,8 +1272,9 @@ static int it930x_frontend_attach(struct dvb_usb_adapter *adap) state->af9033_config[adap->id].fe = &adap->fe[0]; state->af9033_config[adap->id].ops = &state->ops; - ret = af9035_add_i2c_dev(d, "si2168", 0x67, &si2168_config, - &d->i2c_adap); + ret = af9035_add_i2c_dev(d, "si2168", + it930x_addresses_table[state->it930x_addresses].frontend_i2c_addr, + &si2168_config, &d->i2c_adap); if (ret) goto err; @@ -1575,54 +1623,12 @@ static int it930x_tuner_attach(struct dvb_usb_adapter *adap) dev_dbg(&intf->dev, "adap->id=%d\n", adap->id); - /* I2C master bus 2 clock speed 300k */ - ret = af9035_wr_reg(d, 0x00f6a7, 0x07); - if (ret < 0) - goto err; - - /* I2C master bus 1,3 clock speed 300k */ - ret = af9035_wr_reg(d, 0x00f103, 0x07); - if (ret < 0) - goto err; - - /* set gpio11 low */ - ret = af9035_wr_reg_mask(d, 0xd8d4, 0x01, 0x01); - if (ret < 0) - goto err; - - ret = af9035_wr_reg_mask(d, 0xd8d5, 0x01, 0x01); - if (ret < 0) - goto err; - - ret = af9035_wr_reg_mask(d, 0xd8d3, 0x01, 0x01); - if (ret < 0) - goto err; - - /* Tuner enable using gpiot2_en, gpiot2_on and gpiot2_o (reset) */ - ret = af9035_wr_reg_mask(d, 0xd8b8, 0x01, 0x01); - if (ret < 0) - goto err; - - ret = af9035_wr_reg_mask(d, 0xd8b9, 0x01, 0x01); - if (ret < 0) - goto err; - - ret = af9035_wr_reg_mask(d, 0xd8b7, 0x00, 0x01); - if (ret < 0) - goto err; - - msleep(200); - - ret = af9035_wr_reg_mask(d, 0xd8b7, 0x01, 0x01); - if (ret < 0) - goto err; - memset(&si2157_config, 0, sizeof(si2157_config)); si2157_config.fe = adap->fe[0]; - si2157_config.if_port = 1; - ret = af9035_add_i2c_dev(d, "si2157", 0x63, - &si2157_config, state->i2c_adapter_demod); - + si2157_config.if_port = it930x_addresses_table[state->it930x_addresses].tuner_if_port; + ret = af9035_add_i2c_dev(d, "si2157", + it930x_addresses_table[state->it930x_addresses].tuner_i2c_addr, + &si2157_config, state->i2c_adapter_demod); if (ret) goto err; @@ -2128,6 +2134,8 @@ static const struct usb_device_id af9035_id_table[] = { /* IT930x devices */ { DVB_USB_DEVICE(USB_VID_ITETECH, USB_PID_ITETECH_IT9303, &it930x_props, "ITE 9303 Generic", NULL) }, + { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_TD310, + &it930x_props, "AVerMedia TD310 DVB-T2", NULL) }, { } }; MODULE_DEVICE_TABLE(usb, af9035_id_table); diff --git a/drivers/media/usb/dvb-usb-v2/af9035.h b/drivers/media/usb/dvb-usb-v2/af9035.h index a76e6bf0ab1e..bc41c16f9727 100644 --- a/drivers/media/usb/dvb-usb-v2/af9035.h +++ b/drivers/media/usb/dvb-usb-v2/af9035.h @@ -69,6 +69,7 @@ struct state { u8 dual_mode:1; u8 no_read:1; u8 af9033_i2c_addr[2]; + u8 it930x_addresses; struct af9033_config af9033_config[2]; struct af9033_ops ops; #define AF9035_I2C_CLIENT_MAX 4 @@ -77,6 +78,17 @@ struct state { struct platform_device *platform_device_tuner[2]; }; +struct address_table { + u8 frontend_i2c_addr; + u8 tuner_i2c_addr; + u8 tuner_if_port; +}; + +static const struct address_table it930x_addresses_table[] = { + { 0x67, 0x63, 1 }, + { 0x64, 0x60, 0 }, +}; + static const u32 clock_lut_af9035[] = { 20480000, /* FPGA */ 16384000, /* 16.38 MHz */ diff --git a/drivers/media/usb/dvb-usb-v2/dvbsky.c b/drivers/media/usb/dvb-usb-v2/dvbsky.c index e28bd8836751..ae0814dd202a 100644 --- a/drivers/media/usb/dvb-usb-v2/dvbsky.c +++ b/drivers/media/usb/dvb-usb-v2/dvbsky.c @@ -615,16 +615,18 @@ static int dvbsky_init(struct dvb_usb_device *d) return 0; } -static void dvbsky_exit(struct dvb_usb_device *d) +static int dvbsky_frontend_detach(struct dvb_usb_adapter *adap) { + struct dvb_usb_device *d = adap_to_d(adap); struct dvbsky_state *state = d_to_priv(d); - struct dvb_usb_adapter *adap = &d->adapter[0]; + + dev_dbg(&d->udev->dev, "%s: adap=%d\n", __func__, adap->id); dvb_module_release(state->i2c_client_tuner); dvb_module_release(state->i2c_client_demod); dvb_module_release(state->i2c_client_ci); - adap->fe[0] = NULL; + return 0; } /* DVB USB Driver stuff */ @@ -640,11 +642,11 @@ static struct dvb_usb_device_properties dvbsky_s960_props = { .i2c_algo = &dvbsky_i2c_algo, .frontend_attach = dvbsky_s960_attach, + .frontend_detach = dvbsky_frontend_detach, .init = dvbsky_init, .get_rc_config = dvbsky_get_rc_config, .streaming_ctrl = dvbsky_streaming_ctrl, .identify_state = dvbsky_identify_state, - .exit = dvbsky_exit, .read_mac_address = dvbsky_read_mac_addr, .num_adapters = 1, @@ -667,11 +669,11 @@ static struct dvb_usb_device_properties dvbsky_s960c_props = { .i2c_algo = &dvbsky_i2c_algo, .frontend_attach = dvbsky_s960c_attach, + .frontend_detach = dvbsky_frontend_detach, .init = dvbsky_init, .get_rc_config = dvbsky_get_rc_config, .streaming_ctrl = dvbsky_streaming_ctrl, .identify_state = dvbsky_identify_state, - .exit = dvbsky_exit, .read_mac_address = dvbsky_read_mac_addr, .num_adapters = 1, @@ -694,11 +696,11 @@ static struct dvb_usb_device_properties dvbsky_t680c_props = { .i2c_algo = &dvbsky_i2c_algo, .frontend_attach = dvbsky_t680c_attach, + .frontend_detach = dvbsky_frontend_detach, .init = dvbsky_init, .get_rc_config = dvbsky_get_rc_config, .streaming_ctrl = dvbsky_streaming_ctrl, .identify_state = dvbsky_identify_state, - .exit = dvbsky_exit, .read_mac_address = dvbsky_read_mac_addr, .num_adapters = 1, @@ -721,11 +723,11 @@ static struct dvb_usb_device_properties dvbsky_t330_props = { .i2c_algo = &dvbsky_i2c_algo, .frontend_attach = dvbsky_t330_attach, + .frontend_detach = dvbsky_frontend_detach, .init = dvbsky_init, .get_rc_config = dvbsky_get_rc_config, .streaming_ctrl = dvbsky_streaming_ctrl, .identify_state = dvbsky_identify_state, - .exit = dvbsky_exit, .read_mac_address = dvbsky_read_mac_addr, .num_adapters = 1, @@ -748,11 +750,11 @@ static struct dvb_usb_device_properties mygica_t230c_props = { .i2c_algo = &dvbsky_i2c_algo, .frontend_attach = dvbsky_mygica_t230c_attach, + .frontend_detach = dvbsky_frontend_detach, .init = dvbsky_init, .get_rc_config = dvbsky_get_rc_config, .streaming_ctrl = dvbsky_streaming_ctrl, .identify_state = dvbsky_identify_state, - .exit = dvbsky_exit, .num_adapters = 1, .adapter = { diff --git a/drivers/media/usb/em28xx/Kconfig b/drivers/media/usb/em28xx/Kconfig index 451e076525d3..639da7e24066 100644 --- a/drivers/media/usb/em28xx/Kconfig +++ b/drivers/media/usb/em28xx/Kconfig @@ -13,7 +13,7 @@ config VIDEO_EM28XX_V4L2 select VIDEO_MSP3400 if MEDIA_SUBDRV_AUTOSELECT select VIDEO_MT9V011 if MEDIA_SUBDRV_AUTOSELECT && MEDIA_CAMERA_SUPPORT select VIDEO_OV2640 if MEDIA_SUBDRV_AUTOSELECT && MEDIA_CAMERA_SUPPORT - ---help--- + help This is a video4linux driver for Empia 28xx based TV cards. To compile this driver as a module, choose M here: the @@ -23,7 +23,7 @@ config VIDEO_EM28XX_ALSA depends on VIDEO_EM28XX && SND select SND_PCM tristate "Empia EM28xx ALSA audio module" - ---help--- + help This is an ALSA driver for some Empia 28xx based TV cards. This is not required for em2800/em2820/em2821 boards. However, @@ -66,7 +66,7 @@ config VIDEO_EM28XX_DVB select MEDIA_TUNER_XC2028 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_XC5000 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_MT2060 if MEDIA_SUBDRV_AUTOSELECT - ---help--- + help This adds support for DVB cards based on the Empiatech em28xx chips. @@ -76,5 +76,5 @@ config VIDEO_EM28XX_RC depends on VIDEO_EM28XX depends on !(RC_CORE=m && VIDEO_EM28XX=y) default VIDEO_EM28XX - ---help--- + help Enables Remote Controller support on em28xx driver. diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c index f84a1208d5d3..d85ea1af6aa1 100644 --- a/drivers/media/usb/em28xx/em28xx-input.c +++ b/drivers/media/usb/em28xx/em28xx-input.c @@ -499,7 +499,7 @@ static int em28xx_probe_i2c_ir(struct em28xx *dev) * at address 0x18, so if that address is needed for another board in * the future, please put it after 0x1f. */ - const unsigned short addr_list[] = { + static const unsigned short addr_list[] = { 0x1f, 0x30, 0x47, I2C_CLIENT_END }; diff --git a/drivers/media/usb/go7007/Kconfig b/drivers/media/usb/go7007/Kconfig index af1d02430931..beab257c092f 100644 --- a/drivers/media/usb/go7007/Kconfig +++ b/drivers/media/usb/go7007/Kconfig @@ -13,7 +13,7 @@ config VIDEO_GO7007 select VIDEO_TW9906 if MEDIA_SUBDRV_AUTOSELECT select VIDEO_OV7640 if MEDIA_SUBDRV_AUTOSELECT && MEDIA_CAMERA_SUPPORT select VIDEO_UDA1342 if MEDIA_SUBDRV_AUTOSELECT - ---help--- + help This is a video4linux driver for the WIS GO7007 MPEG encoder chip. @@ -23,7 +23,7 @@ config VIDEO_GO7007 config VIDEO_GO7007_USB tristate "WIS GO7007 USB support" depends on VIDEO_GO7007 && USB - ---help--- + help This is a video4linux driver for the WIS GO7007 MPEG encoder chip over USB. @@ -34,7 +34,7 @@ config VIDEO_GO7007_LOADER tristate "WIS GO7007 Loader support" depends on VIDEO_GO7007 default y - ---help--- + help This is a go7007 firmware loader driver for the WIS GO7007 MPEG encoder chip over USB. @@ -44,7 +44,7 @@ config VIDEO_GO7007_LOADER config VIDEO_GO7007_USB_S2250_BOARD tristate "Sensoray 2250/2251 support" depends on VIDEO_GO7007_USB && USB - ---help--- + help This is a video4linux driver for the Sensoray 2250/2251 device. To compile this driver as a module, choose M here: the diff --git a/drivers/media/usb/go7007/go7007-fw.c b/drivers/media/usb/go7007/go7007-fw.c index 24f5b615dc7a..dfa9f899d0c2 100644 --- a/drivers/media/usb/go7007/go7007-fw.c +++ b/drivers/media/usb/go7007/go7007-fw.c @@ -1499,8 +1499,8 @@ static int modet_to_package(struct go7007 *go, __le16 *code, int space) return cnt; } -static int do_special(struct go7007 *go, u16 type, __le16 *code, int space, - int *framelen) +static noinline_for_stack int do_special(struct go7007 *go, u16 type, + __le16 *code, int space, int *framelen) { switch (type) { case SPECIAL_FRM_HEAD: diff --git a/drivers/media/usb/go7007/go7007-usb.c b/drivers/media/usb/go7007/go7007-usb.c index 19c6a0354ce0..abe98488be23 100644 --- a/drivers/media/usb/go7007/go7007-usb.c +++ b/drivers/media/usb/go7007/go7007-usb.c @@ -1132,7 +1132,7 @@ static int go7007_usb_probe(struct usb_interface *intf, usb->usbdev = usbdev; usb_make_path(usbdev, go->bus_info, sizeof(go->bus_info)); go->board_id = id->driver_info; - strncpy(go->name, name, sizeof(go->name)); + strscpy(go->name, name, sizeof(go->name)); if (board->flags & GO7007_USB_EZUSB) go->hpi_ops = &go7007_usb_ezusb_hpi_ops; else @@ -1198,7 +1198,7 @@ static int go7007_usb_probe(struct usb_interface *intf, go->board_id = GO7007_BOARDID_ENDURA; usb->board = board = &board_endura; go->board_info = &board->main_info; - strncpy(go->name, "Pelco Endura", + strscpy(go->name, "Pelco Endura", sizeof(go->name)); } else { u16 channel; @@ -1232,21 +1232,21 @@ static int go7007_usb_probe(struct usb_interface *intf, case 1: go->tuner_type = TUNER_SONY_BTF_PG472Z; go->std = V4L2_STD_PAL; - strncpy(go->name, "Plextor PX-TV402U-EU", - sizeof(go->name)); + strscpy(go->name, "Plextor PX-TV402U-EU", + sizeof(go->name)); break; case 2: go->tuner_type = TUNER_SONY_BTF_PK467Z; go->std = V4L2_STD_NTSC_M_JP; num_i2c_devs -= 2; - strncpy(go->name, "Plextor PX-TV402U-JP", - sizeof(go->name)); + strscpy(go->name, "Plextor PX-TV402U-JP", + sizeof(go->name)); break; case 3: go->tuner_type = TUNER_SONY_BTF_PB463Z; num_i2c_devs -= 2; - strncpy(go->name, "Plextor PX-TV402U-NA", - sizeof(go->name)); + strscpy(go->name, "Plextor PX-TV402U-NA", + sizeof(go->name)); break; default: pr_debug("unable to detect tuner type!\n"); diff --git a/drivers/media/usb/go7007/go7007-v4l2.c b/drivers/media/usb/go7007/go7007-v4l2.c index 7a2781fa83e7..bebdfcecf600 100644 --- a/drivers/media/usb/go7007/go7007-v4l2.c +++ b/drivers/media/usb/go7007/go7007-v4l2.c @@ -327,7 +327,7 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; fmt->flags = V4L2_FMT_FLAG_COMPRESSED; - strncpy(fmt->description, desc, sizeof(fmt->description)); + strscpy(fmt->description, desc, sizeof(fmt->description)); return 0; } diff --git a/drivers/media/usb/gspca/Kconfig b/drivers/media/usb/gspca/Kconfig index 088566e88467..0e6f36cb46e6 100644 --- a/drivers/media/usb/gspca/Kconfig +++ b/drivers/media/usb/gspca/Kconfig @@ -4,7 +4,7 @@ menuconfig USB_GSPCA depends on INPUT || INPUT=n select VIDEOBUF2_VMALLOC default m - ---help--- + help Say Y here if you want to enable selecting webcams based on the GSPCA framework. diff --git a/drivers/media/usb/gspca/gspca.c b/drivers/media/usb/gspca/gspca.c index ac70b36d67b7..4d7517411cc2 100644 --- a/drivers/media/usb/gspca/gspca.c +++ b/drivers/media/usb/gspca/gspca.c @@ -294,7 +294,7 @@ static void fill_frame(struct gspca_dev *gspca_dev, /* check the packet status and length */ st = urb->iso_frame_desc[i].status; if (st) { - pr_err("ISOC data error: [%d] len=%d, status=%d\n", + gspca_dbg(gspca_dev, D_PACK, "ISOC data error: [%d] len=%d, status=%d\n", i, len, st); gspca_dev->last_packet_type = DISCARD_PACKET; continue; @@ -314,6 +314,8 @@ static void fill_frame(struct gspca_dev *gspca_dev, } resubmit: + if (!gspca_dev->streaming) + return; /* resubmit the URB */ st = usb_submit_urb(urb, GFP_ATOMIC); if (st < 0) @@ -330,7 +332,7 @@ static void isoc_irq(struct urb *urb) struct gspca_dev *gspca_dev = (struct gspca_dev *) urb->context; gspca_dbg(gspca_dev, D_PACK, "isoc irq\n"); - if (!vb2_start_streaming_called(&gspca_dev->queue)) + if (!gspca_dev->streaming) return; fill_frame(gspca_dev, urb); } @@ -344,7 +346,7 @@ static void bulk_irq(struct urb *urb) int st; gspca_dbg(gspca_dev, D_PACK, "bulk irq\n"); - if (!vb2_start_streaming_called(&gspca_dev->queue)) + if (!gspca_dev->streaming) return; switch (urb->status) { case 0: @@ -367,6 +369,8 @@ static void bulk_irq(struct urb *urb) urb->actual_length); resubmit: + if (!gspca_dev->streaming) + return; /* resubmit the URB */ if (gspca_dev->cam.bulk_nurbs != 0) { st = usb_submit_urb(urb, GFP_ATOMIC); @@ -1638,6 +1642,8 @@ void gspca_disconnect(struct usb_interface *intf) mutex_lock(&gspca_dev->usb_lock); gspca_dev->present = false; + destroy_urbs(gspca_dev); + gspca_input_destroy_urb(gspca_dev); vb2_queue_error(&gspca_dev->queue); diff --git a/drivers/media/usb/hackrf/Kconfig b/drivers/media/usb/hackrf/Kconfig index 937e6f5c1e8e..072e186018f5 100644 --- a/drivers/media/usb/hackrf/Kconfig +++ b/drivers/media/usb/hackrf/Kconfig @@ -2,7 +2,7 @@ config USB_HACKRF tristate "HackRF" depends on VIDEO_V4L2 select VIDEOBUF2_VMALLOC - ---help--- + help This is a video4linux2 driver for HackRF SDR device. To compile this driver as a module, choose M here: the diff --git a/drivers/media/usb/hdpvr/Kconfig b/drivers/media/usb/hdpvr/Kconfig index d73d9a1952b4..9e78c0c32651 100644 --- a/drivers/media/usb/hdpvr/Kconfig +++ b/drivers/media/usb/hdpvr/Kconfig @@ -2,7 +2,7 @@ config VIDEO_HDPVR tristate "Hauppauge HD PVR support" depends on VIDEO_DEV && VIDEO_V4L2 - ---help--- + help This is a video4linux driver for Hauppauge's HD PVR USB device. To compile this driver as a module, choose M here: the diff --git a/drivers/media/usb/hdpvr/hdpvr-video.c b/drivers/media/usb/hdpvr/hdpvr-video.c index e082086428a4..3804aa3fb50f 100644 --- a/drivers/media/usb/hdpvr/hdpvr-video.c +++ b/drivers/media/usb/hdpvr/hdpvr-video.c @@ -769,8 +769,7 @@ static int vidioc_enum_input(struct file *file, void *_fh, struct v4l2_input *i) i->type = V4L2_INPUT_TYPE_CAMERA; - strncpy(i->name, iname[n], sizeof(i->name) - 1); - i->name[sizeof(i->name) - 1] = '\0'; + strscpy(i->name, iname[n], sizeof(i->name)); i->audioset = 1<<HDPVR_RCA_FRONT | 1<<HDPVR_RCA_BACK | 1<<HDPVR_SPDIF; @@ -841,8 +840,7 @@ static int vidioc_enumaudio(struct file *file, void *priv, audio->capability = V4L2_AUDCAP_STEREO; - strncpy(audio->name, audio_iname[n], sizeof(audio->name) - 1); - audio->name[sizeof(audio->name) - 1] = '\0'; + strscpy(audio->name, audio_iname[n], sizeof(audio->name)); return 0; } @@ -874,7 +872,6 @@ static int vidioc_g_audio(struct file *file, void *private_data, audio->index = dev->options.audio_input; audio->capability = V4L2_AUDCAP_STEREO; strscpy(audio->name, audio_iname[audio->index], sizeof(audio->name)); - audio->name[sizeof(audio->name) - 1] = '\0'; return 0; } @@ -991,7 +988,8 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *private_data, return -EINVAL; f->flags = V4L2_FMT_FLAG_COMPRESSED; - strncpy(f->description, "MPEG2-TS with AVC/AAC streams", 32); + strscpy(f->description, "MPEG2-TS with AVC/AAC streams", + sizeof(f->description)); f->pixelformat = V4L2_PIX_FMT_MPEG; return 0; diff --git a/drivers/media/usb/pulse8-cec/Kconfig b/drivers/media/usb/pulse8-cec/Kconfig index 18ead44824ba..11f1b75d3efd 100644 --- a/drivers/media/usb/pulse8-cec/Kconfig +++ b/drivers/media/usb/pulse8-cec/Kconfig @@ -4,7 +4,7 @@ config USB_PULSE8_CEC select CEC_CORE select SERIO select SERIO_SERPORT - ---help--- + help This is a cec driver for the Pulse Eight HDMI CEC device. To compile this driver as a module, choose M here: the diff --git a/drivers/media/usb/pulse8-cec/pulse8-cec.c b/drivers/media/usb/pulse8-cec/pulse8-cec.c index b085b14f3f87..ea9ee74fa336 100644 --- a/drivers/media/usb/pulse8-cec/pulse8-cec.c +++ b/drivers/media/usb/pulse8-cec/pulse8-cec.c @@ -435,7 +435,7 @@ static int pulse8_setup(struct pulse8 *pulse8, struct serio *serio, err = pulse8_send_and_wait(pulse8, cmd, 1, cmd[0], 0); if (err) return err; - strncpy(log_addrs->osd_name, data, 13); + strscpy(log_addrs->osd_name, data, sizeof(log_addrs->osd_name)); dev_dbg(pulse8->dev, "OSD name: %s\n", log_addrs->osd_name); return 0; @@ -566,7 +566,7 @@ static int pulse8_cec_adap_log_addr(struct cec_adapter *adap, u8 log_addr) char *osd_str = cmd + 1; cmd[0] = MSGCODE_SET_OSD_NAME; - strncpy(cmd + 1, adap->log_addrs.osd_name, 13); + strscpy(cmd + 1, adap->log_addrs.osd_name, sizeof(cmd) - 1); if (osd_len < 4) { memset(osd_str + osd_len, ' ', 4 - osd_len); osd_len = 4; diff --git a/drivers/media/usb/pvrusb2/Kconfig b/drivers/media/usb/pvrusb2/Kconfig index 1ad913fc30bf..ac6612cf1bec 100644 --- a/drivers/media/usb/pvrusb2/Kconfig +++ b/drivers/media/usb/pvrusb2/Kconfig @@ -9,7 +9,7 @@ config VIDEO_PVRUSB2 select VIDEO_MSP3400 select VIDEO_WM8775 select VIDEO_CS53L32A - ---help--- + help This is a video4linux driver for Conexant 23416 based usb2 personal video recorder devices. @@ -20,7 +20,7 @@ config VIDEO_PVRUSB2_SYSFS bool "pvrusb2 sysfs support" default y depends on VIDEO_PVRUSB2 && SYSFS - ---help--- + help This option enables the operation of a sysfs based interface for query and control of the pvrusb2 driver. @@ -43,7 +43,7 @@ config VIDEO_PVRUSB2_DVB select MEDIA_TUNER_TDA18271 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_SIMPLE if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_TDA8290 if MEDIA_SUBDRV_AUTOSELECT - ---help--- + help This option enables a DVB interface for the pvrusb2 driver. If your device does not support digital television, this feature will have no affect on the driver's operation. @@ -53,7 +53,7 @@ config VIDEO_PVRUSB2_DVB config VIDEO_PVRUSB2_DEBUGIFC bool "pvrusb2 debug interface" depends on VIDEO_PVRUSB2_SYSFS - ---help--- + help This option enables the inclusion of a debug interface in the pvrusb2 driver, hosted through sysfs. diff --git a/drivers/media/usb/pvrusb2/pvrusb2-hdw.c b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c index 446a999dd2ce..816c85786c2a 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c @@ -666,6 +666,8 @@ static int ctrl_get_input(struct pvr2_ctrl *cptr,int *vp) static int ctrl_check_input(struct pvr2_ctrl *cptr,int v) { + if (v < 0 || v > PVR2_CVAL_INPUT_MAX) + return 0; return ((1 << v) & cptr->hdw->input_allowed_mask) != 0; } @@ -2459,9 +2461,8 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf, if (!(qctrl.flags & V4L2_CTRL_FLAG_READ_ONLY)) { ciptr->set_value = ctrl_cx2341x_set; } - strncpy(hdw->mpeg_ctrl_info[idx].desc,qctrl.name, - PVR2_CTLD_INFO_DESC_SIZE); - hdw->mpeg_ctrl_info[idx].desc[PVR2_CTLD_INFO_DESC_SIZE-1] = 0; + strscpy(hdw->mpeg_ctrl_info[idx].desc, qctrl.name, + sizeof(hdw->mpeg_ctrl_info[idx].desc)); ciptr->default_value = qctrl.default_value; switch (qctrl.type) { default: diff --git a/drivers/media/usb/pvrusb2/pvrusb2-hdw.h b/drivers/media/usb/pvrusb2/pvrusb2-hdw.h index 25648add77e5..bd2b7a67b732 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-hdw.h +++ b/drivers/media/usb/pvrusb2/pvrusb2-hdw.h @@ -50,6 +50,7 @@ #define PVR2_CVAL_INPUT_COMPOSITE 2 #define PVR2_CVAL_INPUT_SVIDEO 3 #define PVR2_CVAL_INPUT_RADIO 4 +#define PVR2_CVAL_INPUT_MAX PVR2_CVAL_INPUT_RADIO enum pvr2_config { pvr2_config_empty, /* No configuration */ diff --git a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c index 08d5b7aa3537..cb6668580d77 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c @@ -284,7 +284,7 @@ static int pvr2_enumaudio(struct file *file, void *priv, struct v4l2_audio *vin) if (vin->index > 0) return -EINVAL; - strncpy(vin->name, "PVRUSB2 Audio", 14); + strscpy(vin->name, "PVRUSB2 Audio", sizeof(vin->name)); vin->capability = V4L2_AUDCAP_STEREO; return 0; } @@ -293,7 +293,7 @@ static int pvr2_g_audio(struct file *file, void *priv, struct v4l2_audio *vin) { /* pkt: FIXME: see above comment (VIDIOC_ENUMAUDIO) */ vin->index = 0; - strncpy(vin->name, "PVRUSB2 Audio", 14); + strscpy(vin->name, "PVRUSB2 Audio", sizeof(vin->name)); vin->capability = V4L2_AUDCAP_STEREO; return 0; } diff --git a/drivers/media/usb/pwc/Kconfig b/drivers/media/usb/pwc/Kconfig index d63d0a850035..5f6d91edca41 100644 --- a/drivers/media/usb/pwc/Kconfig +++ b/drivers/media/usb/pwc/Kconfig @@ -2,7 +2,7 @@ config USB_PWC tristate "USB Philips Cameras" depends on VIDEO_V4L2 select VIDEOBUF2_VMALLOC - ---help--- + help Say Y or M here if you want to use one of these Philips & OEM webcams: * Philips PCA645, PCA646 @@ -41,7 +41,7 @@ config USB_PWC_INPUT_EVDEV bool "USB Philips Cameras input events device support" default y depends on USB_PWC && (USB_PWC=INPUT || INPUT=y) - ---help--- + help This option makes USB Philips cameras register the snapshot button as an input device to report button events. diff --git a/drivers/media/usb/pwc/pwc-ctrl.c b/drivers/media/usb/pwc/pwc-ctrl.c index 655cef39eb3d..b681a184ef87 100644 --- a/drivers/media/usb/pwc/pwc-ctrl.c +++ b/drivers/media/usb/pwc/pwc-ctrl.c @@ -242,14 +242,14 @@ static int set_video_mode_Timon(struct pwc_device *pdev, int size, int pixfmt, fps = (frames / 5) - 1; /* Find a supported framerate with progressively higher compression */ - pChoose = NULL; - while (*compression <= 3) { + do { pChoose = &Timon_table[size][fps][*compression]; if (pChoose->alternate != 0) break; (*compression)++; - } - if (pChoose == NULL || pChoose->alternate == 0) + } while (*compression <= 3); + + if (pChoose->alternate == 0) return -ENOENT; /* Not supported. */ if (send_to_cam) @@ -279,7 +279,7 @@ static int set_video_mode_Timon(struct pwc_device *pdev, int size, int pixfmt, static int set_video_mode_Kiara(struct pwc_device *pdev, int size, int pixfmt, int frames, int *compression, int send_to_cam) { - const struct Kiara_table_entry *pChoose = NULL; + const struct Kiara_table_entry *pChoose; int fps, ret = 0; if (size >= PSZ_MAX || *compression < 0 || *compression > 3) @@ -293,13 +293,14 @@ static int set_video_mode_Kiara(struct pwc_device *pdev, int size, int pixfmt, fps = (frames / 5) - 1; /* Find a supported framerate with progressively higher compression */ - while (*compression <= 3) { + do { pChoose = &Kiara_table[size][fps][*compression]; if (pChoose->alternate != 0) break; (*compression)++; - } - if (pChoose == NULL || pChoose->alternate == 0) + } while (*compression <= 3); + + if (pChoose->alternate == 0) return -ENOENT; /* Not supported. */ /* Firmware bug: video endpoint is 5, but commands are sent to endpoint 4 */ diff --git a/drivers/media/usb/rainshadow-cec/Kconfig b/drivers/media/usb/rainshadow-cec/Kconfig index 030ef01b1ff0..6b00be618db8 100644 --- a/drivers/media/usb/rainshadow-cec/Kconfig +++ b/drivers/media/usb/rainshadow-cec/Kconfig @@ -4,7 +4,7 @@ config USB_RAINSHADOW_CEC select CEC_CORE select SERIO select SERIO_SERPORT - ---help--- + help This is a cec driver for the RainShadow Tech HDMI CEC device. To compile this driver as a module, choose M here: the diff --git a/drivers/media/usb/siano/Kconfig b/drivers/media/usb/siano/Kconfig index d37b742d4f7a..cc5e5aa3c93a 100644 --- a/drivers/media/usb/siano/Kconfig +++ b/drivers/media/usb/siano/Kconfig @@ -8,6 +8,6 @@ config SMS_USB_DRV depends on !RC_CORE || RC_CORE select MEDIA_COMMON_OPTIONS select SMS_SIANO_MDTV - ---help--- + help Choose if you would like to have Siano's support for USB interface diff --git a/drivers/media/usb/stk1160/Kconfig b/drivers/media/usb/stk1160/Kconfig index 425ed00e2599..03426e4437ea 100644 --- a/drivers/media/usb/stk1160/Kconfig +++ b/drivers/media/usb/stk1160/Kconfig @@ -2,7 +2,7 @@ config VIDEO_STK1160_COMMON tristate "STK1160 USB video capture support" depends on VIDEO_DEV && I2C - ---help--- + help This is a video4linux driver for STK1160 based video capture devices. To compile this driver as a module, choose M here: the diff --git a/drivers/media/usb/stkwebcam/Kconfig b/drivers/media/usb/stkwebcam/Kconfig index a6a00aa4fce6..ea9e04b3caaf 100644 --- a/drivers/media/usb/stkwebcam/Kconfig +++ b/drivers/media/usb/stkwebcam/Kconfig @@ -1,7 +1,7 @@ config USB_STKWEBCAM tristate "USB Syntek DC1125 Camera support" depends on VIDEO_V4L2 - ---help--- + help Say Y here if you want to use this type of camera. Supported devices are typically found in some Asus laptops, with USB id 174f:a311 and 05e1:0501. Other Syntek cameras diff --git a/drivers/media/usb/tm6000/Kconfig b/drivers/media/usb/tm6000/Kconfig index a43b77abd931..321ae691f4d9 100644 --- a/drivers/media/usb/tm6000/Kconfig +++ b/drivers/media/usb/tm6000/Kconfig @@ -18,7 +18,7 @@ config VIDEO_TM6000_ALSA tristate "TV Master TM5600/6000/6010 audio support" depends on VIDEO_TM6000 && SND select SND_PCM - ---help--- + help This is a video4linux driver for direct (DMA) audio for TM5600/TM6000/TM6010 USB Devices. @@ -29,5 +29,5 @@ config VIDEO_TM6000_DVB tristate "DVB Support for tm6000 based TV cards" depends on VIDEO_TM6000 && DVB_CORE && USB select DVB_ZL10353 - ---help--- + help This adds support for DVB cards based on the tm5600/tm6000 chip. diff --git a/drivers/media/usb/usbtv/Kconfig b/drivers/media/usb/usbtv/Kconfig index 14a0941fa0d0..2b4ac0848469 100644 --- a/drivers/media/usb/usbtv/Kconfig +++ b/drivers/media/usb/usbtv/Kconfig @@ -4,7 +4,7 @@ config VIDEO_USBTV select SND_PCM select VIDEOBUF2_VMALLOC - ---help--- + help This is a video4linux2 driver for USBTV007 based video capture devices. To compile this driver as a module, choose M here: the diff --git a/drivers/media/usb/usbvision/Kconfig b/drivers/media/usb/usbvision/Kconfig index 6b6afc5d8f7e..7aa080cb9884 100644 --- a/drivers/media/usb/usbvision/Kconfig +++ b/drivers/media/usb/usbvision/Kconfig @@ -3,7 +3,7 @@ config VIDEO_USBVISION depends on I2C && VIDEO_V4L2 select VIDEO_TUNER select VIDEO_SAA711X if MEDIA_SUBDRV_AUTOSELECT - ---help--- + help There are more than 50 different USB video devices based on NT1003/1004/1005 USB Bridges. This driver enables using those devices. diff --git a/drivers/media/usb/usbvision/usbvision-core.c b/drivers/media/usb/usbvision/usbvision-core.c index 92d166bf8c12..abc4eed832a3 100644 --- a/drivers/media/usb/usbvision/usbvision-core.c +++ b/drivers/media/usb/usbvision/usbvision-core.c @@ -2302,6 +2302,9 @@ int usbvision_init_isoc(struct usb_usbvision *usbvision) sb_size, GFP_KERNEL, &urb->transfer_dma); + if (!usbvision->sbuf[buf_idx].data) + return -ENOMEM; + urb->dev = dev; urb->context = usbvision; urb->pipe = usb_rcvisocpipe(dev, usbvision->video_endp); diff --git a/drivers/media/usb/uvc/Kconfig b/drivers/media/usb/uvc/Kconfig index 6ed85efabcaa..94937d0cc2e3 100644 --- a/drivers/media/usb/uvc/Kconfig +++ b/drivers/media/usb/uvc/Kconfig @@ -2,7 +2,7 @@ config USB_VIDEO_CLASS tristate "USB Video Class (UVC)" depends on VIDEO_V4L2 select VIDEOBUF2_VMALLOC - ---help--- + help Support for the USB Video Class (UVC). Currently only video input devices, such as webcams, are supported. @@ -13,7 +13,7 @@ config USB_VIDEO_CLASS_INPUT_EVDEV default y depends on USB_VIDEO_CLASS depends on USB_VIDEO_CLASS=INPUT || INPUT=y - ---help--- + help This option makes USB Video Class devices register an input device to report button events. diff --git a/drivers/media/usb/zr364xx/Kconfig b/drivers/media/usb/zr364xx/Kconfig index ac429bca70e8..979b1d4f3f68 100644 --- a/drivers/media/usb/zr364xx/Kconfig +++ b/drivers/media/usb/zr364xx/Kconfig @@ -3,7 +3,7 @@ config USB_ZR364XX depends on VIDEO_V4L2 select VIDEOBUF_GEN select VIDEOBUF_VMALLOC - ---help--- + help Say Y here if you want to connect this type of camera to your computer's USB port. See <file:Documentation/media/v4l-drivers/zr364xx.rst> for more info diff --git a/drivers/media/v4l2-core/Kconfig b/drivers/media/v4l2-core/Kconfig index c0940f5c69b4..8402096f7796 100644 --- a/drivers/media/v4l2-core/Kconfig +++ b/drivers/media/v4l2-core/Kconfig @@ -13,7 +13,7 @@ config VIDEO_V4L2 config VIDEO_ADV_DEBUG bool "Enable advanced debug functionality on V4L2 drivers" default n - ---help--- + help Say Y here to enable advanced debugging functionality on some V4L devices. In doubt, say N. @@ -21,7 +21,7 @@ config VIDEO_ADV_DEBUG config VIDEO_FIXED_MINOR_RANGES bool "Enable old-style fixed minor ranges on drivers/video devices" default n - ---help--- + help Say Y here to enable the old-style fixed-range minor assignments. Only useful if you rely on the old behavior and use mknod instead of udev. @@ -33,7 +33,7 @@ config VIDEO_PCI_SKELETON depends on SAMPLES depends on VIDEO_V4L2 && VIDEOBUF2_CORE depends on VIDEOBUF2_MEMOPS && VIDEOBUF2_DMA_CONTIG - ---help--- + help Enable build of the skeleton PCI driver, used as a reference when developing new drivers. @@ -51,7 +51,7 @@ config V4L2_FLASH_LED_CLASS tristate "V4L2 flash API for LED flash class devices" depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API depends on LEDS_CLASS_FLASH - ---help--- + help Say Y here to enable V4L2 flash API support for LED flash class drivers. diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c index 663730f088cd..b5778b2ffa27 100644 --- a/drivers/media/v4l2-core/v4l2-common.c +++ b/drivers/media/v4l2-core/v4l2-common.c @@ -445,3 +445,189 @@ int v4l2_s_parm_cap(struct video_device *vdev, return ret; } EXPORT_SYMBOL_GPL(v4l2_s_parm_cap); + +const struct v4l2_format_info *v4l2_format_info(u32 format) +{ + static const struct v4l2_format_info formats[] = { + /* RGB formats */ + { .format = V4L2_PIX_FMT_BGR24, .mem_planes = 1, .comp_planes = 1, .bpp = { 3, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_RGB24, .mem_planes = 1, .comp_planes = 1, .bpp = { 3, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_HSV24, .mem_planes = 1, .comp_planes = 1, .bpp = { 3, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_BGR32, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_XBGR32, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_RGB32, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_XRGB32, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_HSV32, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_ARGB32, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_ABGR32, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_GREY, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + + /* YUV packed formats */ + { .format = V4L2_PIX_FMT_YUYV, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 2, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_YVYU, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 2, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_UYVY, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 2, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_VYUY, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 2, .vdiv = 1 }, + + /* YUV planar formats */ + { .format = V4L2_PIX_FMT_NV12, .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 2, .vdiv = 2 }, + { .format = V4L2_PIX_FMT_NV21, .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 2, .vdiv = 2 }, + { .format = V4L2_PIX_FMT_NV16, .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 2, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_NV61, .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 2, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_NV24, .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_NV42, .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + + { .format = V4L2_PIX_FMT_YUV410, .mem_planes = 1, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 4, .vdiv = 4 }, + { .format = V4L2_PIX_FMT_YVU410, .mem_planes = 1, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 4, .vdiv = 4 }, + { .format = V4L2_PIX_FMT_YUV411P, .mem_planes = 1, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 4, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_YUV420, .mem_planes = 1, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 2, .vdiv = 2 }, + { .format = V4L2_PIX_FMT_YVU420, .mem_planes = 1, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 2, .vdiv = 2 }, + { .format = V4L2_PIX_FMT_YUV422P, .mem_planes = 1, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 2, .vdiv = 1 }, + + /* YUV planar formats, non contiguous variant */ + { .format = V4L2_PIX_FMT_YUV420M, .mem_planes = 3, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 2, .vdiv = 2 }, + { .format = V4L2_PIX_FMT_YVU420M, .mem_planes = 3, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 2, .vdiv = 2 }, + { .format = V4L2_PIX_FMT_YUV422M, .mem_planes = 3, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 2, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_YVU422M, .mem_planes = 3, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 2, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_YUV444M, .mem_planes = 3, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_YVU444M, .mem_planes = 3, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, .hdiv = 1, .vdiv = 1 }, + + { .format = V4L2_PIX_FMT_NV12M, .mem_planes = 2, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 2, .vdiv = 2 }, + { .format = V4L2_PIX_FMT_NV21M, .mem_planes = 2, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 2, .vdiv = 2 }, + { .format = V4L2_PIX_FMT_NV16M, .mem_planes = 2, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 2, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_NV61M, .mem_planes = 2, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, .hdiv = 2, .vdiv = 1 }, + + /* Bayer RGB formats */ + { .format = V4L2_PIX_FMT_SBGGR8, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_SGBRG8, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_SGRBG8, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_SRGGB8, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_SBGGR10, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_SGBRG10, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_SGRBG10, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_SRGGB10, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_SBGGR10ALAW8, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_SGBRG10ALAW8, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_SGRBG10ALAW8, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_SRGGB10ALAW8, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_SBGGR10DPCM8, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_SGBRG10DPCM8, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_SGRBG10DPCM8, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_SRGGB10DPCM8, .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_SBGGR12, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_SGBRG12, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_SGRBG12, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + { .format = V4L2_PIX_FMT_SRGGB12, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .hdiv = 1, .vdiv = 1 }, + }; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(formats); ++i) + if (formats[i].format == format) + return &formats[i]; + return NULL; +} +EXPORT_SYMBOL(v4l2_format_info); + +static inline unsigned int v4l2_format_block_width(const struct v4l2_format_info *info, int plane) +{ + if (!info->block_w[plane]) + return 1; + return info->block_w[plane]; +} + +static inline unsigned int v4l2_format_block_height(const struct v4l2_format_info *info, int plane) +{ + if (!info->block_h[plane]) + return 1; + return info->block_h[plane]; +} + +int v4l2_fill_pixfmt_mp(struct v4l2_pix_format_mplane *pixfmt, + int pixelformat, int width, int height) +{ + const struct v4l2_format_info *info; + struct v4l2_plane_pix_format *plane; + int i; + + info = v4l2_format_info(pixelformat); + if (!info) + return -EINVAL; + + pixfmt->width = width; + pixfmt->height = height; + pixfmt->pixelformat = pixelformat; + pixfmt->num_planes = info->mem_planes; + + if (info->mem_planes == 1) { + plane = &pixfmt->plane_fmt[0]; + plane->bytesperline = ALIGN(width, v4l2_format_block_width(info, 0)) * info->bpp[0]; + plane->sizeimage = 0; + + for (i = 0; i < info->comp_planes; i++) { + unsigned int hdiv = (i == 0) ? 1 : info->hdiv; + unsigned int vdiv = (i == 0) ? 1 : info->vdiv; + unsigned int aligned_width; + unsigned int aligned_height; + + aligned_width = ALIGN(width, v4l2_format_block_width(info, i)); + aligned_height = ALIGN(height, v4l2_format_block_height(info, i)); + + plane->sizeimage += info->bpp[i] * + DIV_ROUND_UP(aligned_width, hdiv) * + DIV_ROUND_UP(aligned_height, vdiv); + } + } else { + for (i = 0; i < info->comp_planes; i++) { + unsigned int hdiv = (i == 0) ? 1 : info->hdiv; + unsigned int vdiv = (i == 0) ? 1 : info->vdiv; + unsigned int aligned_width; + unsigned int aligned_height; + + aligned_width = ALIGN(width, v4l2_format_block_width(info, i)); + aligned_height = ALIGN(height, v4l2_format_block_height(info, i)); + + plane = &pixfmt->plane_fmt[i]; + plane->bytesperline = + info->bpp[i] * DIV_ROUND_UP(aligned_width, hdiv); + plane->sizeimage = + plane->bytesperline * DIV_ROUND_UP(aligned_height, vdiv); + } + } + return 0; +} +EXPORT_SYMBOL_GPL(v4l2_fill_pixfmt_mp); + +int v4l2_fill_pixfmt(struct v4l2_pix_format *pixfmt, int pixelformat, int width, int height) +{ + const struct v4l2_format_info *info; + int i; + + info = v4l2_format_info(pixelformat); + if (!info) + return -EINVAL; + + /* Single planar API cannot be used for multi plane formats. */ + if (info->mem_planes > 1) + return -EINVAL; + + pixfmt->width = width; + pixfmt->height = height; + pixfmt->pixelformat = pixelformat; + pixfmt->bytesperline = ALIGN(width, v4l2_format_block_width(info, 0)) * info->bpp[0]; + pixfmt->sizeimage = 0; + + for (i = 0; i < info->comp_planes; i++) { + unsigned int hdiv = (i == 0) ? 1 : info->hdiv; + unsigned int vdiv = (i == 0) ? 1 : info->vdiv; + unsigned int aligned_width; + unsigned int aligned_height; + + aligned_width = ALIGN(width, v4l2_format_block_width(info, i)); + aligned_height = ALIGN(height, v4l2_format_block_height(info, i)); + + pixfmt->sizeimage += info->bpp[i] * + DIV_ROUND_UP(aligned_width, hdiv) * + DIV_ROUND_UP(aligned_height, vdiv); + } + return 0; +} +EXPORT_SYMBOL_GPL(v4l2_fill_pixfmt); diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index b79d3bbd8350..89a1fe564675 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c @@ -828,6 +828,10 @@ const char *v4l2_ctrl_get_name(u32 id) case V4L2_CID_MPEG_VIDEO_H264_CONSTRAINED_INTRA_PREDICTION: return "H264 Constrained Intra Pred"; case V4L2_CID_MPEG_VIDEO_H264_CHROMA_QP_INDEX_OFFSET: return "H264 Chroma QP Index Offset"; + case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_MIN_QP: return "H264 I-Frame Minimum QP Value"; + case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_MAX_QP: return "H264 I-Frame Maximum QP Value"; + case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_MIN_QP: return "H264 P-Frame Minimum QP Value"; + case V4L2_CID_MPEG_VIDEO_H264_P_FRAME_MAX_QP: return "H264 P-Frame Maximum QP Value"; case V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP: return "MPEG4 I-Frame QP Value"; case V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP: return "MPEG4 P-Frame QP Value"; case V4L2_CID_MPEG_VIDEO_MPEG4_B_FRAME_QP: return "MPEG4 B-Frame QP Value"; @@ -849,6 +853,9 @@ const char *v4l2_ctrl_get_name(u32 id) case V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME: return "Force Key Frame"; case V4L2_CID_MPEG_VIDEO_MPEG2_SLICE_PARAMS: return "MPEG-2 Slice Parameters"; case V4L2_CID_MPEG_VIDEO_MPEG2_QUANTIZATION: return "MPEG-2 Quantization Matrices"; + case V4L2_CID_MPEG_VIDEO_FWHT_PARAMS: return "FWHT Stateless Parameters"; + case V4L2_CID_FWHT_I_FRAME_QP: return "FWHT I-Frame QP Value"; + case V4L2_CID_FWHT_P_FRAME_QP: return "FWHT P-Frame QP Value"; /* VPX controls */ case V4L2_CID_MPEG_VIDEO_VPX_NUM_PARTITIONS: return "VPX Number of Partitions"; @@ -1303,6 +1310,9 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, case V4L2_CID_MPEG_VIDEO_MPEG2_QUANTIZATION: *type = V4L2_CTRL_TYPE_MPEG2_QUANTIZATION; break; + case V4L2_CID_MPEG_VIDEO_FWHT_PARAMS: + *type = V4L2_CTRL_TYPE_FWHT_PARAMS; + break; default: *type = V4L2_CTRL_TYPE_INTEGER; break; @@ -1599,7 +1609,7 @@ static int std_validate(const struct v4l2_ctrl *ctrl, u32 idx, case V4L2_CTRL_TYPE_INTEGER_MENU: if (ptr.p_s32[idx] < ctrl->minimum || ptr.p_s32[idx] > ctrl->maximum) return -ERANGE; - if (ctrl->menu_skip_mask & (1 << ptr.p_s32[idx])) + if (ctrl->menu_skip_mask & (1ULL << ptr.p_s32[idx])) return -EINVAL; if (ctrl->type == V4L2_CTRL_TYPE_MENU && ctrl->qmenu[ptr.p_s32[idx]][0] == '\0') @@ -1669,6 +1679,9 @@ static int std_validate(const struct v4l2_ctrl *ctrl, u32 idx, case V4L2_CTRL_TYPE_MPEG2_QUANTIZATION: return 0; + case V4L2_CTRL_TYPE_FWHT_PARAMS: + return 0; + default: return -EINVAL; } @@ -2249,6 +2262,9 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl, case V4L2_CTRL_TYPE_MPEG2_QUANTIZATION: elem_size = sizeof(struct v4l2_ctrl_mpeg2_quantization); break; + case V4L2_CTRL_TYPE_FWHT_PARAMS: + elem_size = sizeof(struct v4l2_ctrl_fwht_params); + break; default: if (type < V4L2_CTRL_COMPOUND_TYPES) elem_size = sizeof(s32); @@ -2918,7 +2934,7 @@ int v4l2_querymenu(struct v4l2_ctrl_handler *hdl, struct v4l2_querymenu *qm) return -EINVAL; /* Use mask to see if this menu item should be skipped */ - if (ctrl->menu_skip_mask & (1 << i)) + if (ctrl->menu_skip_mask & (1ULL << i)) return -EINVAL; /* Empty menu items should also be skipped */ if (ctrl->type == V4L2_CTRL_TYPE_MENU) { @@ -3899,18 +3915,19 @@ void v4l2_ctrl_request_complete(struct media_request *req, } EXPORT_SYMBOL(v4l2_ctrl_request_complete); -void v4l2_ctrl_request_setup(struct media_request *req, +int v4l2_ctrl_request_setup(struct media_request *req, struct v4l2_ctrl_handler *main_hdl) { struct media_request_object *obj; struct v4l2_ctrl_handler *hdl; struct v4l2_ctrl_ref *ref; + int ret = 0; if (!req || !main_hdl) - return; + return 0; if (WARN_ON(req->state != MEDIA_REQUEST_STATE_QUEUED)) - return; + return -EBUSY; /* * Note that it is valid if nothing was found. It means @@ -3919,10 +3936,10 @@ void v4l2_ctrl_request_setup(struct media_request *req, */ obj = media_request_object_find(req, &req_ops, main_hdl); if (!obj) - return; + return 0; if (obj->completed) { media_request_object_put(obj); - return; + return -EBUSY; } hdl = container_of(obj, struct v4l2_ctrl_handler, req_obj); @@ -3990,12 +4007,15 @@ void v4l2_ctrl_request_setup(struct media_request *req, update_from_auto_cluster(master); } - try_or_set_cluster(NULL, master, true, 0); - + ret = try_or_set_cluster(NULL, master, true, 0); v4l2_ctrl_unlock(master); + + if (ret) + break; } media_request_object_put(obj); + return ret; } EXPORT_SYMBOL(v4l2_ctrl_request_setup); diff --git a/drivers/media/v4l2-core/v4l2-device.c b/drivers/media/v4l2-core/v4l2-device.c index e0ddb9a52bd1..7cca0de1b730 100644 --- a/drivers/media/v4l2-core/v4l2-device.c +++ b/drivers/media/v4l2-core/v4l2-device.c @@ -216,10 +216,18 @@ error_module: } EXPORT_SYMBOL_GPL(v4l2_device_register_subdev); +static void v4l2_subdev_release(struct v4l2_subdev *sd) +{ + struct module *owner = !sd->owner_v4l2_dev ? sd->owner : NULL; + + if (sd->internal_ops && sd->internal_ops->release) + sd->internal_ops->release(sd); + module_put(owner); +} + static void v4l2_device_release_subdev_node(struct video_device *vdev) { - struct v4l2_subdev *sd = video_get_drvdata(vdev); - sd->devnode = NULL; + v4l2_subdev_release(video_get_drvdata(vdev)); kfree(vdev); } @@ -318,8 +326,9 @@ void v4l2_device_unregister_subdev(struct v4l2_subdev *sd) media_device_unregister_entity(&sd->entity); } #endif - video_unregister_device(sd->devnode); - if (!sd->owner_v4l2_dev) - module_put(sd->owner); + if (sd->devnode) + video_unregister_device(sd->devnode); + else + v4l2_subdev_release(sd); } EXPORT_SYMBOL_GPL(v4l2_device_unregister_subdev); diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c index 20571846e636..ea1ed88f9dc8 100644 --- a/drivers/media/v4l2-core/v4l2-fwnode.c +++ b/drivers/media/v4l2-core/v4l2-fwnode.c @@ -163,7 +163,7 @@ static int v4l2_fwnode_endpoint_parse_csi2_bus(struct fwnode_handle *fwnode, } if (use_default_lane_mapping) - pr_debug("using default lane mapping\n"); + pr_debug("no lane mapping given, using defaults\n"); } rval = fwnode_property_read_u32_array(fwnode, "data-lanes", NULL, 0); @@ -175,6 +175,10 @@ static int v4l2_fwnode_endpoint_parse_csi2_bus(struct fwnode_handle *fwnode, num_data_lanes); have_data_lanes = true; + if (use_default_lane_mapping) { + pr_debug("data-lanes property exists; disabling default mapping\n"); + use_default_lane_mapping = false; + } } for (i = 0; i < num_data_lanes; i++) { @@ -225,6 +229,10 @@ static int v4l2_fwnode_endpoint_parse_csi2_bus(struct fwnode_handle *fwnode, if (bus_type == V4L2_MBUS_CSI2_DPHY || bus_type == V4L2_MBUS_CSI2_CPHY || lanes_used || have_clk_lane || (flags & ~V4L2_MBUS_CSI2_CONTINUOUS_CLOCK)) { + /* Only D-PHY has a clock lane. */ + unsigned int dfl_data_lane_index = + bus_type == V4L2_MBUS_CSI2_DPHY; + bus->flags = flags; if (bus_type == V4L2_MBUS_UNKNOWN) vep->bus_type = V4L2_MBUS_CSI2_DPHY; @@ -233,7 +241,7 @@ static int v4l2_fwnode_endpoint_parse_csi2_bus(struct fwnode_handle *fwnode, if (use_default_lane_mapping) { bus->clock_lane = 0; for (i = 0; i < num_data_lanes; i++) - bus->data_lanes[i] = 1 + i; + bus->data_lanes[i] = dfl_data_lane_index + i; } else { bus->clock_lane = clock_lane; for (i = 0; i < num_data_lanes; i++) @@ -820,7 +828,10 @@ error: * underneath the fwnode identified by the previous tuple, etc. until you * reached the fwnode you need. * - * An example with a graph, as defined in Documentation/acpi/dsd/graph.txt: + * THIS EXAMPLE EXISTS MERELY TO DOCUMENT THIS FUNCTION. DO NOT USE IT AS A + * REFERENCE IN HOW ACPI TABLES SHOULD BE WRITTEN!! See documentation under + * Documentation/acpi/dsd instead and especially graph.txt, + * data-node-references.txt and leds.txt . * * Scope (\_SB.PCI0.I2C2) * { diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index f6d663934648..ac87c3e37280 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -1337,6 +1337,7 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) case V4L2_PIX_FMT_VP9: descr = "VP9"; break; case V4L2_PIX_FMT_HEVC: descr = "HEVC"; break; /* aka H.265 */ case V4L2_PIX_FMT_FWHT: descr = "FWHT"; break; /* used in vicodec */ + case V4L2_PIX_FMT_FWHT_STATELESS: descr = "FWHT Stateless"; break; /* used in vicodec */ case V4L2_PIX_FMT_CPIA1: descr = "GSPCA CPiA YUV"; break; case V4L2_PIX_FMT_WNVA: descr = "WNVA"; break; case V4L2_PIX_FMT_SN9C10X: descr = "GSPCA SN9C10X"; break; @@ -1373,7 +1374,7 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) } if (descr) - WARN_ON(strscpy(fmt->description, descr, sz) >= sz); + WARN_ON(strscpy(fmt->description, descr, sz) < 0); fmt->flags = flags; } diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c index f5f0d71ec745..d75815ab0d7b 100644 --- a/drivers/media/v4l2-core/v4l2-subdev.c +++ b/drivers/media/v4l2-core/v4l2-subdev.c @@ -18,6 +18,7 @@ #include <linux/ioctl.h> #include <linux/mm.h> +#include <linux/module.h> #include <linux/slab.h> #include <linux/types.h> #include <linux/videodev2.h> @@ -54,9 +55,6 @@ static int subdev_open(struct file *file) struct video_device *vdev = video_devdata(file); struct v4l2_subdev *sd = vdev_to_v4l2_subdev(vdev); struct v4l2_subdev_fh *subdev_fh; -#if defined(CONFIG_MEDIA_CONTROLLER) - struct media_entity *entity = NULL; -#endif int ret; subdev_fh = kzalloc(sizeof(*subdev_fh), GFP_KERNEL); @@ -73,12 +71,15 @@ static int subdev_open(struct file *file) v4l2_fh_add(&subdev_fh->vfh); file->private_data = &subdev_fh->vfh; #if defined(CONFIG_MEDIA_CONTROLLER) - if (sd->v4l2_dev->mdev) { - entity = media_entity_get(&sd->entity); - if (!entity) { + if (sd->v4l2_dev->mdev && sd->entity.graph_obj.mdev->dev) { + struct module *owner; + + owner = sd->entity.graph_obj.mdev->dev->driver->owner; + if (!try_module_get(owner)) { ret = -EBUSY; goto err; } + subdev_fh->owner = owner; } #endif @@ -91,9 +92,7 @@ static int subdev_open(struct file *file) return 0; err: -#if defined(CONFIG_MEDIA_CONTROLLER) - media_entity_put(entity); -#endif + module_put(subdev_fh->owner); v4l2_fh_del(&subdev_fh->vfh); v4l2_fh_exit(&subdev_fh->vfh); subdev_fh_free(subdev_fh); @@ -111,10 +110,7 @@ static int subdev_close(struct file *file) if (sd->internal_ops && sd->internal_ops->close) sd->internal_ops->close(sd, subdev_fh); -#if defined(CONFIG_MEDIA_CONTROLLER) - if (sd->v4l2_dev->mdev) - media_entity_put(&sd->entity); -#endif + module_put(subdev_fh->owner); v4l2_fh_del(vfh); v4l2_fh_exit(vfh); subdev_fh_free(subdev_fh); diff --git a/drivers/staging/media/Kconfig b/drivers/staging/media/Kconfig index 44280b6c021a..f77f5eee7fc2 100644 --- a/drivers/staging/media/Kconfig +++ b/drivers/staging/media/Kconfig @@ -2,7 +2,7 @@ menuconfig STAGING_MEDIA bool "Media staging drivers" default n - ---help--- + help This option allows you to select a number of media drivers that don't have the "normal" Linux kernel quality level. Most of them don't follow properly the V4L, DVB and/or RC API's, @@ -34,8 +34,6 @@ source "drivers/staging/media/sunxi/Kconfig" source "drivers/staging/media/tegra-vde/Kconfig" -source "drivers/staging/media/zoran/Kconfig" - source "drivers/staging/media/ipu3/Kconfig" source "drivers/staging/media/soc_camera/Kconfig" diff --git a/drivers/staging/media/Makefile b/drivers/staging/media/Makefile index 0355e3030504..99218bfc997f 100644 --- a/drivers/staging/media/Makefile +++ b/drivers/staging/media/Makefile @@ -5,7 +5,6 @@ obj-$(CONFIG_VIDEO_DM365_VPFE) += davinci_vpfe/ obj-$(CONFIG_VIDEO_OMAP4) += omap4iss/ obj-$(CONFIG_VIDEO_SUNXI) += sunxi/ obj-$(CONFIG_TEGRA_VDE) += tegra-vde/ -obj-$(CONFIG_VIDEO_ZORAN) += zoran/ obj-$(CONFIG_VIDEO_ROCKCHIP_VPU) += rockchip/vpu/ obj-$(CONFIG_VIDEO_IPU3_IMGU) += ipu3/ obj-$(CONFIG_SOC_CAMERA) += soc_camera/ diff --git a/drivers/staging/media/bcm2048/Kconfig b/drivers/staging/media/bcm2048/Kconfig index c93a0a848c90..ab2d50cac140 100644 --- a/drivers/staging/media/bcm2048/Kconfig +++ b/drivers/staging/media/bcm2048/Kconfig @@ -6,7 +6,7 @@ config I2C_BCM2048 tristate "Broadcom BCM2048 FM Radio Receiver support" depends on I2C && VIDEO_V4L2 && RADIO_ADAPTERS - ---help--- + help Say Y here if you want support to BCM2048 FM Radio Receiver. This device driver supports only i2c bus. diff --git a/drivers/staging/media/bcm2048/radio-bcm2048.c b/drivers/staging/media/bcm2048/radio-bcm2048.c index d9b02ff66259..09903ffb13ba 100644 --- a/drivers/staging/media/bcm2048/radio-bcm2048.c +++ b/drivers/staging/media/bcm2048/radio-bcm2048.c @@ -2404,7 +2404,7 @@ static int bcm2048_vidioc_g_audio(struct file *file, void *priv, if (audio->index > 1) return -EINVAL; - strncpy(audio->name, "Radio", 32); + strscpy(audio->name, "Radio", sizeof(audio->name)); audio->capability = V4L2_AUDCAP_STEREO; return 0; @@ -2432,7 +2432,7 @@ static int bcm2048_vidioc_g_tuner(struct file *file, void *priv, if (tuner->index > 0) return -EINVAL; - strncpy(tuner->name, "FM Receiver", 32); + strscpy(tuner->name, "FM Receiver", sizeof(tuner->name)); tuner->type = V4L2_TUNER_RADIO; tuner->rangelow = dev_to_v4l2(bcm2048_get_region_bottom_frequency(bdev)); diff --git a/drivers/staging/media/davinci_vpfe/Kconfig b/drivers/staging/media/davinci_vpfe/Kconfig index eb61141b29e8..94bf6746c03f 100644 --- a/drivers/staging/media/davinci_vpfe/Kconfig +++ b/drivers/staging/media/davinci_vpfe/Kconfig @@ -2,7 +2,7 @@ config VIDEO_DM365_VPFE tristate "DM365 VPFE Media Controller Capture Driver" depends on VIDEO_V4L2 - depends on (ARCH_DAVINCI_DM365 && !VIDEO_DM365_ISIF) || COMPILE_TEST + depends on (ARCH_DAVINCI_DM365 && !VIDEO_DM365_ISIF) || (COMPILE_TEST && !ARCH_OMAP1) depends on VIDEO_V4L2_SUBDEV_API depends on VIDEO_DAVINCI_VPBE_DISPLAY select VIDEOBUF2_DMA_CONTIG diff --git a/drivers/staging/media/davinci_vpfe/dm365_isif.c b/drivers/staging/media/davinci_vpfe/dm365_isif.c index 0a6d038fcec9..46fd8184fc77 100644 --- a/drivers/staging/media/davinci_vpfe/dm365_isif.c +++ b/drivers/staging/media/davinci_vpfe/dm365_isif.c @@ -433,9 +433,9 @@ static int isif_get_params(struct v4l2_subdev *sd, void *params) return 0; } -static int isif_validate_df_csc_params(struct vpfe_isif_df_csc *df_csc) +static int isif_validate_df_csc_params(const struct vpfe_isif_df_csc *df_csc) { - struct vpfe_isif_color_space_conv *csc; + const struct vpfe_isif_color_space_conv *csc; int err = -EINVAL; int i; @@ -481,7 +481,7 @@ static int isif_validate_df_csc_params(struct vpfe_isif_df_csc *df_csc) #define DM365_ISIF_MAX_DFCMEM0 0x1fff #define DM365_ISIF_MAX_DFCMEM1 0x1fff -static int isif_validate_dfc_params(struct vpfe_isif_dfc *dfc) +static int isif_validate_dfc_params(const struct vpfe_isif_dfc *dfc) { int err = -EINVAL; int i; @@ -532,7 +532,7 @@ static int isif_validate_dfc_params(struct vpfe_isif_dfc *dfc) #define DM365_ISIF_MAX_CLVSV 0x1fff #define DM365_ISIF_MAX_HEIGHT_BLACK_REGION 0x1fff -static int isif_validate_bclamp_params(struct vpfe_isif_black_clamp *bclamp) +static int isif_validate_bclamp_params(const struct vpfe_isif_black_clamp *bclamp) { int err = -EINVAL; @@ -580,7 +580,7 @@ static int isif_validate_bclamp_params(struct vpfe_isif_black_clamp *bclamp) } static int -isif_validate_raw_params(struct vpfe_isif_raw_config *params) +isif_validate_raw_params(const struct vpfe_isif_raw_config *params) { int ret; @@ -593,20 +593,18 @@ isif_validate_raw_params(struct vpfe_isif_raw_config *params) return isif_validate_bclamp_params(¶ms->bclamp); } -static int isif_set_params(struct v4l2_subdev *sd, void *params) +static int isif_set_params(struct v4l2_subdev *sd, const struct vpfe_isif_raw_config *params) { struct vpfe_isif_device *isif = v4l2_get_subdevdata(sd); - struct vpfe_isif_raw_config isif_raw_params; int ret = -EINVAL; /* only raw module parameters can be set through the IOCTL */ if (isif->formats[ISIF_PAD_SINK].code != MEDIA_BUS_FMT_SGRBG12_1X12) return ret; - memcpy(&isif_raw_params, params, sizeof(isif_raw_params)); - if (!isif_validate_raw_params(&isif_raw_params)) { - memcpy(&isif->isif_cfg.bayer.config_params, &isif_raw_params, - sizeof(isif_raw_params)); + if (!isif_validate_raw_params(params)) { + memcpy(&isif->isif_cfg.bayer.config_params, params, + sizeof(*params)); ret = 0; } return ret; diff --git a/drivers/staging/media/davinci_vpfe/dm365_resizer.c b/drivers/staging/media/davinci_vpfe/dm365_resizer.c index d460963106fa..7adf1fae43f6 100644 --- a/drivers/staging/media/davinci_vpfe/dm365_resizer.c +++ b/drivers/staging/media/davinci_vpfe/dm365_resizer.c @@ -1881,7 +1881,7 @@ int vpfe_resizer_init(struct vpfe_resizer_device *vpfe_rsz, struct v4l2_subdev *sd = &vpfe_rsz->crop_resizer.subdev; struct media_pad *pads = &vpfe_rsz->crop_resizer.pads[0]; struct media_entity *me = &sd->entity; - static resource_size_t res_len; + resource_size_t res_len; struct resource *res; int ret; diff --git a/drivers/staging/media/imx/Kconfig b/drivers/staging/media/imx/Kconfig index 6c8b69491ef0..4c726345dc25 100644 --- a/drivers/staging/media/imx/Kconfig +++ b/drivers/staging/media/imx/Kconfig @@ -7,7 +7,7 @@ config VIDEO_IMX_MEDIA depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG select V4L2_FWNODE - ---help--- + help Say yes here to enable support for video4linux media controller driver for the i.MX5/6 SOC. @@ -18,7 +18,7 @@ config VIDEO_IMX_CSI tristate "i.MX5/6 Camera Sensor Interface driver" depends on VIDEO_IMX_MEDIA && VIDEO_DEV && I2C default y - ---help--- + help A video4linux camera sensor interface driver for i.MX5/6. config VIDEO_IMX7_CSI diff --git a/drivers/staging/media/imx/imx-ic-common.c b/drivers/staging/media/imx/imx-ic-common.c index 7e2455097315..18cd4cb92431 100644 --- a/drivers/staging/media/imx/imx-ic-common.c +++ b/drivers/staging/media/imx/imx-ic-common.c @@ -22,7 +22,7 @@ static struct imx_ic_ops *ic_ops[IC_NUM_OPS] = { static int imx_ic_probe(struct platform_device *pdev) { - struct imx_media_internal_sd_platformdata *pdata; + struct imx_media_ipu_internal_sd_pdata *pdata; struct imx_ic_priv *priv; int ret; @@ -59,7 +59,7 @@ static int imx_ic_probe(struct platform_device *pdev) priv->sd.owner = THIS_MODULE; priv->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; priv->sd.grp_id = pdata->grp_id; - strncpy(priv->sd.name, pdata->sd_name, sizeof(priv->sd.name)); + strscpy(priv->sd.name, pdata->sd_name, sizeof(priv->sd.name)); ret = ic_ops[priv->task_id]->init(priv); if (ret) diff --git a/drivers/staging/media/imx/imx-media-csi.c b/drivers/staging/media/imx/imx-media-csi.c index edc0e9a2a90d..28fe66052cc7 100644 --- a/drivers/staging/media/imx/imx-media-csi.c +++ b/drivers/staging/media/imx/imx-media-csi.c @@ -150,9 +150,10 @@ static inline bool requires_passthrough(struct v4l2_fwnode_endpoint *ep, /* * Parses the fwnode endpoint from the source pad of the entity * connected to this CSI. This will either be the entity directly - * upstream from the CSI-2 receiver, or directly upstream from the - * video mux. The endpoint is needed to determine the bus type and - * bus config coming into the CSI. + * upstream from the CSI-2 receiver, directly upstream from the + * video mux, or directly upstream from the CSI itself. The endpoint + * is needed to determine the bus type and bus config coming into + * the CSI. */ static int csi_get_upstream_endpoint(struct csi_priv *priv, struct v4l2_fwnode_endpoint *ep) @@ -168,7 +169,8 @@ static int csi_get_upstream_endpoint(struct csi_priv *priv, if (!priv->src_sd) return -EPIPE; - src = &priv->src_sd->entity; + sd = priv->src_sd; + src = &sd->entity; if (src->function == MEDIA_ENT_F_VID_MUX) { /* @@ -182,6 +184,14 @@ static int csi_get_upstream_endpoint(struct csi_priv *priv, src = &sd->entity; } + /* + * If the source is neither the video mux nor the CSI-2 receiver, + * get the source pad directly upstream from CSI itself. + */ + if (src->function != MEDIA_ENT_F_VID_MUX && + sd->grp_id != IMX_MEDIA_GRP_ID_CSI2) + src = &priv->sd.entity; + /* get source pad of entity directly upstream from src */ pad = imx_media_find_upstream_pad(priv->md, src, 0); if (IS_ERR(pad)) diff --git a/drivers/staging/media/imx/imx-media-dev-common.c b/drivers/staging/media/imx/imx-media-dev-common.c index 910594125889..6cd93419b81d 100644 --- a/drivers/staging/media/imx/imx-media-dev-common.c +++ b/drivers/staging/media/imx/imx-media-dev-common.c @@ -30,7 +30,7 @@ struct imx_media_dev *imx_media_dev_init(struct device *dev) dev_set_drvdata(dev, imxmd); - strlcpy(imxmd->md.model, "imx-media", sizeof(imxmd->md.model)); + strscpy(imxmd->md.model, "imx-media", sizeof(imxmd->md.model)); imxmd->md.ops = &imx_media_md_ops; imxmd->md.dev = dev; @@ -38,7 +38,7 @@ struct imx_media_dev *imx_media_dev_init(struct device *dev) imxmd->v4l2_dev.mdev = &imxmd->md; imxmd->v4l2_dev.notify = imx_media_notify; - strlcpy(imxmd->v4l2_dev.name, "imx-media", + strscpy(imxmd->v4l2_dev.name, "imx-media", sizeof(imxmd->v4l2_dev.name)); media_device_init(&imxmd->md); diff --git a/drivers/staging/media/imx/imx-media-dev.c b/drivers/staging/media/imx/imx-media-dev.c index bd4ddea488f1..6be95584006d 100644 --- a/drivers/staging/media/imx/imx-media-dev.c +++ b/drivers/staging/media/imx/imx-media-dev.c @@ -46,12 +46,14 @@ int imx_media_add_async_subdev(struct imx_media_dev *imxmd, int ret; if (fwnode) { - asd = v4l2_async_notifier_add_fwnode_subdev( - &imxmd->notifier, fwnode, sizeof(*imxasd)); + asd = v4l2_async_notifier_add_fwnode_subdev(&imxmd->notifier, + fwnode, + sizeof(*imxasd)); } else { devname = dev_name(&pdev->dev); - asd = v4l2_async_notifier_add_devname_subdev( - &imxmd->notifier, devname, sizeof(*imxasd)); + asd = v4l2_async_notifier_add_devname_subdev(&imxmd->notifier, + devname, + sizeof(*imxasd)); } if (IS_ERR(asd)) { @@ -262,10 +264,9 @@ static int imx_media_alloc_pad_vdev_lists(struct imx_media_dev *imxmd) list_for_each_entry(sd, &imxmd->v4l2_dev.subdevs, list) { entity = &sd->entity; - vdev_lists = devm_kcalloc( - imxmd->md.dev, - entity->num_pads, sizeof(*vdev_lists), - GFP_KERNEL); + vdev_lists = devm_kcalloc(imxmd->md.dev, + entity->num_pads, sizeof(*vdev_lists), + GFP_KERNEL); if (!vdev_lists) return -ENOMEM; @@ -473,13 +474,6 @@ static int imx_media_probe(struct platform_device *pdev) goto cleanup; } - ret = imx_media_add_internal_subdevs(imxmd); - if (ret) { - v4l2_err(&imxmd->v4l2_dev, - "add_internal_subdevs failed with %d\n", ret); - goto cleanup; - } - ret = imx_media_dev_notifier_register(imxmd); if (ret) goto del_int; @@ -487,7 +481,7 @@ static int imx_media_probe(struct platform_device *pdev) return 0; del_int: - imx_media_remove_internal_subdevs(imxmd); + imx_media_remove_ipu_internal_subdevs(imxmd); cleanup: v4l2_async_notifier_cleanup(&imxmd->notifier); v4l2_device_unregister(&imxmd->v4l2_dev); @@ -504,7 +498,7 @@ static int imx_media_remove(struct platform_device *pdev) v4l2_info(&imxmd->v4l2_dev, "Removing imx-media\n"); v4l2_async_notifier_unregister(&imxmd->notifier); - imx_media_remove_internal_subdevs(imxmd); + imx_media_remove_ipu_internal_subdevs(imxmd); v4l2_async_notifier_cleanup(&imxmd->notifier); media_device_unregister(&imxmd->md); v4l2_device_unregister(&imxmd->v4l2_dev); diff --git a/drivers/staging/media/imx/imx-media-internal-sd.c b/drivers/staging/media/imx/imx-media-internal-sd.c index c547280a309e..df49ebfbe98a 100644 --- a/drivers/staging/media/imx/imx-media-internal-sd.c +++ b/drivers/staging/media/imx/imx-media-internal-sd.c @@ -2,7 +2,7 @@ /* * Media driver for Freescale i.MX5/6 SOC * - * Adds the internal subdevices and the media links between them. + * Adds the IPU internal subdevices and the media links between them. * * Copyright (c) 2016 Mentor Graphics Inc. */ @@ -188,7 +188,7 @@ static struct v4l2_subdev *find_sink(struct imx_media_dev *imxmd, /* * retrieve IPU id from subdev name, note: can't get this from - * struct imx_media_internal_sd_platformdata because if src is + * struct imx_media_ipu_internal_sd_pdata because if src is * a CSI, it has different struct ipu_client_platformdata which * does not contain IPU id. */ @@ -266,7 +266,7 @@ static int add_internal_subdev(struct imx_media_dev *imxmd, const struct internal_subdev *isd, int ipu_id) { - struct imx_media_internal_sd_platformdata pdata; + struct imx_media_ipu_internal_sd_pdata pdata; struct platform_device_info pdevinfo = {}; struct platform_device *pdev; @@ -294,13 +294,14 @@ static int add_internal_subdev(struct imx_media_dev *imxmd, } /* adds the internal subdevs in one ipu */ -static int add_ipu_internal_subdevs(struct imx_media_dev *imxmd, int ipu_id) +int imx_media_add_ipu_internal_subdevs(struct imx_media_dev *imxmd, + int ipu_id) { enum isd_enum i; + int ret; for (i = 0; i < num_isd; i++) { const struct internal_subdev *isd = &int_subdev[i]; - int ret; /* * the CSIs are represented in the device-tree, so those @@ -318,32 +319,17 @@ static int add_ipu_internal_subdevs(struct imx_media_dev *imxmd, int ipu_id) } if (ret) - return ret; + goto remove; } return 0; -} - -int imx_media_add_internal_subdevs(struct imx_media_dev *imxmd) -{ - int ret; - - ret = add_ipu_internal_subdevs(imxmd, 0); - if (ret) - goto remove; - - ret = add_ipu_internal_subdevs(imxmd, 1); - if (ret) - goto remove; - - return 0; remove: - imx_media_remove_internal_subdevs(imxmd); + imx_media_remove_ipu_internal_subdevs(imxmd); return ret; } -void imx_media_remove_internal_subdevs(struct imx_media_dev *imxmd) +void imx_media_remove_ipu_internal_subdevs(struct imx_media_dev *imxmd) { struct imx_media_async_subdev *imxasd; struct v4l2_async_subdev *asd; diff --git a/drivers/staging/media/imx/imx-media-of.c b/drivers/staging/media/imx/imx-media-of.c index 09580d83c685..990e82aa8e42 100644 --- a/drivers/staging/media/imx/imx-media-of.c +++ b/drivers/staging/media/imx/imx-media-of.c @@ -19,36 +19,25 @@ int imx_media_of_add_csi(struct imx_media_dev *imxmd, struct device_node *csi_np) { - int ret; - if (!of_device_is_available(csi_np)) { dev_dbg(imxmd->md.dev, "%s: %pOFn not enabled\n", __func__, csi_np); - /* unavailable is not an error */ - return 0; + return -ENODEV; } /* add CSI fwnode to async notifier */ - ret = imx_media_add_async_subdev(imxmd, of_fwnode_handle(csi_np), NULL); - if (ret) { - if (ret == -EEXIST) { - /* already added, everything is fine */ - return 0; - } - - /* other error, can't continue */ - return ret; - } - - return 0; + return imx_media_add_async_subdev(imxmd, of_fwnode_handle(csi_np), + NULL); } EXPORT_SYMBOL_GPL(imx_media_of_add_csi); int imx_media_add_of_subdevs(struct imx_media_dev *imxmd, struct device_node *np) { + bool ipu_found[2] = {false, false}; struct device_node *csi_np; int i, ret; + u32 ipu_id; for (i = 0; ; i++) { csi_np = of_parse_phandle(np, "ports", i); @@ -56,12 +45,43 @@ int imx_media_add_of_subdevs(struct imx_media_dev *imxmd, break; ret = imx_media_of_add_csi(imxmd, csi_np); - of_node_put(csi_np); - if (ret) - return ret; + if (ret) { + /* unavailable or already added is not an error */ + if (ret == -ENODEV || ret == -EEXIST) { + of_node_put(csi_np); + continue; + } + + /* other error, can't continue */ + goto err_out; + } + + ret = of_alias_get_id(csi_np->parent, "ipu"); + if (ret < 0) + goto err_out; + if (ret > 1) { + ret = -EINVAL; + goto err_out; + } + + ipu_id = ret; + + if (!ipu_found[ipu_id]) { + ret = imx_media_add_ipu_internal_subdevs(imxmd, + ipu_id); + if (ret) + goto err_out; + } + + ipu_found[ipu_id] = true; } return 0; + +err_out: + imx_media_remove_ipu_internal_subdevs(imxmd); + of_node_put(csi_np); + return ret; } /* @@ -141,15 +161,18 @@ int imx_media_create_csi_of_links(struct imx_media_dev *imxmd, struct v4l2_subdev *csi) { struct device_node *csi_np = csi->dev->of_node; - struct fwnode_handle *fwnode, *csi_ep; - struct v4l2_fwnode_link link; struct device_node *ep; - int ret; - - link.local_node = of_fwnode_handle(csi_np); - link.local_port = CSI_SINK_PAD; for_each_child_of_node(csi_np, ep) { + struct fwnode_handle *fwnode, *csi_ep; + struct v4l2_fwnode_link link; + int ret; + + memset(&link, 0, sizeof(link)); + + link.local_node = of_fwnode_handle(csi_np); + link.local_port = CSI_SINK_PAD; + csi_ep = of_fwnode_handle(ep); fwnode = fwnode_graph_get_remote_endpoint(csi_ep); diff --git a/drivers/staging/media/imx/imx-media-vdic.c b/drivers/staging/media/imx/imx-media-vdic.c index 3f4b5e9080d4..4487374c9435 100644 --- a/drivers/staging/media/imx/imx-media-vdic.c +++ b/drivers/staging/media/imx/imx-media-vdic.c @@ -227,6 +227,12 @@ static void __maybe_unused prepare_vdi_in_buffers(struct vdic_priv *priv, curr_phys = vb2_dma_contig_plane_dma_addr(curr_vb, 0); next_phys = vb2_dma_contig_plane_dma_addr(curr_vb, 0) + is; break; + default: + /* + * can't get here, priv->fieldtype can only be one of + * the above. This is to quiet smatch errors. + */ + return; } ipu_cpmem_set_buffer(priv->vdi_in_ch_p, 0, prev_phys); @@ -740,7 +746,7 @@ static int vdic_link_setup(struct media_entity *entity, remote_sd = media_entity_to_v4l2_subdev(remote->entity); /* direct pad must connect to a CSI */ - if (!(remote_sd->grp_id & IMX_MEDIA_GRP_ID_CSI) || + if (!(remote_sd->grp_id & IMX_MEDIA_GRP_ID_IPU_CSI) || remote->index != CSI_SRC_PAD_DIRECT) { ret = -EINVAL; goto out; @@ -930,7 +936,7 @@ static const struct v4l2_subdev_internal_ops vdic_internal_ops = { static int imx_vdic_probe(struct platform_device *pdev) { - struct imx_media_internal_sd_platformdata *pdata; + struct imx_media_ipu_internal_sd_pdata *pdata; struct vdic_priv *priv; int ret; @@ -954,7 +960,7 @@ static int imx_vdic_probe(struct platform_device *pdev) priv->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE; /* get our group id */ priv->sd.grp_id = pdata->grp_id; - strncpy(priv->sd.name, pdata->sd_name, sizeof(priv->sd.name)); + strscpy(priv->sd.name, pdata->sd_name, sizeof(priv->sd.name)); mutex_init(&priv->lock); diff --git a/drivers/staging/media/imx/imx-media.h b/drivers/staging/media/imx/imx-media.h index 1f7501d527fb..eb59ba0c3b62 100644 --- a/drivers/staging/media/imx/imx-media.h +++ b/drivers/staging/media/imx/imx-media.h @@ -111,7 +111,7 @@ struct imx_media_pad_vdev { struct list_head list; }; -struct imx_media_internal_sd_platformdata { +struct imx_media_ipu_internal_sd_pdata { char sd_name[V4L2_SUBDEV_NAME_SIZE]; u32 grp_id; int ipu_id; @@ -248,10 +248,11 @@ struct imx_media_fim *imx_media_fim_init(struct v4l2_subdev *sd); void imx_media_fim_free(struct imx_media_fim *fim); /* imx-media-internal-sd.c */ -int imx_media_add_internal_subdevs(struct imx_media_dev *imxmd); +int imx_media_add_ipu_internal_subdevs(struct imx_media_dev *imxmd, + int ipu_id); int imx_media_create_ipu_internal_links(struct imx_media_dev *imxmd, struct v4l2_subdev *sd); -void imx_media_remove_internal_subdevs(struct imx_media_dev *imxmd); +void imx_media_remove_ipu_internal_subdevs(struct imx_media_dev *imxmd); /* imx-media-of.c */ int imx_media_add_of_subdevs(struct imx_media_dev *dev, diff --git a/drivers/staging/media/imx/imx7-media-csi.c b/drivers/staging/media/imx/imx7-media-csi.c index 3fba7c27c0ec..18eb5d3ecf10 100644 --- a/drivers/staging/media/imx/imx7-media-csi.c +++ b/drivers/staging/media/imx/imx7-media-csi.c @@ -1051,7 +1051,9 @@ static int imx7_csi_set_fmt(struct v4l2_subdev *sd, goto out_unlock; } - imx7_csi_try_fmt(csi, cfg, sdformat, &cc); + ret = imx7_csi_try_fmt(csi, cfg, sdformat, &cc); + if (ret < 0) + goto out_unlock; fmt = imx7_csi_get_format(csi, cfg, sdformat->pad, sdformat->which); if (!fmt) { @@ -1271,7 +1273,7 @@ static int imx7_csi_probe(struct platform_device *pdev) platform_set_drvdata(pdev, &csi->sd); ret = imx_media_of_add_csi(imxmd, node); - if (ret < 0) + if (ret < 0 && ret != -ENODEV && ret != -EEXIST) goto cleanup; ret = imx_media_dev_notifier_register(imxmd); diff --git a/drivers/staging/media/imx/imx7-mipi-csis.c b/drivers/staging/media/imx/imx7-mipi-csis.c index 2ddcc42ab8ff..19455f425416 100644 --- a/drivers/staging/media/imx/imx7-mipi-csis.c +++ b/drivers/staging/media/imx/imx7-mipi-csis.c @@ -9,6 +9,7 @@ */ #include <linux/clk.h> +#include <linux/debugfs.h> #include <linux/delay.h> #include <linux/errno.h> #include <linux/interrupt.h> @@ -491,7 +492,7 @@ static int mipi_csis_clk_get(struct csi_state *state) state->wrap_clk = devm_clk_get(dev, "wrap"); if (IS_ERR(state->wrap_clk)) - return IS_ERR(state->wrap_clk); + return PTR_ERR(state->wrap_clk); /* Set clock rate */ ret = clk_set_rate(state->wrap_clk, state->clk_frequency); @@ -706,7 +707,7 @@ static int mipi_csis_set_fmt(struct v4l2_subdev *mipi_sd, fmt = mipi_csis_get_format(state, cfg, sdformat->which, sdformat->pad); mutex_lock(&state->lock); - if (fmt && sdformat->pad == CSIS_PAD_SOURCE) { + if (sdformat->pad == CSIS_PAD_SOURCE) { sdformat->format = *fmt; goto unlock; } @@ -889,8 +890,6 @@ static int mipi_csis_subdev_init(struct v4l2_subdev *mipi_sd, return ret; } -#ifdef CONFIG_DEBUG_FS -#include <linux/debugfs.h> static int mipi_csis_dump_regs_show(struct seq_file *m, void *private) { @@ -900,7 +899,7 @@ static int mipi_csis_dump_regs_show(struct seq_file *m, void *private) } DEFINE_SHOW_ATTRIBUTE(mipi_csis_dump_regs); -static int __init_or_module mipi_csis_debugfs_init(struct csi_state *state) +static int mipi_csis_debugfs_init(struct csi_state *state) { struct dentry *d; @@ -934,17 +933,6 @@ static void mipi_csis_debugfs_exit(struct csi_state *state) debugfs_remove_recursive(state->debugfs_root); } -#else -static int mipi_csis_debugfs_init(struct csi_state *state __maybe_unused) -{ - return 0; -} - -static void mipi_csis_debugfs_exit(struct csi_state *state __maybe_unused) -{ -} -#endif - static int mipi_csis_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -1039,8 +1027,7 @@ disable_clock: static int mipi_csis_pm_suspend(struct device *dev, bool runtime) { - struct platform_device *pdev = to_platform_device(dev); - struct v4l2_subdev *mipi_sd = platform_get_drvdata(pdev); + struct v4l2_subdev *mipi_sd = dev_get_drvdata(dev); struct csi_state *state = mipi_sd_to_csis_state(mipi_sd); int ret = 0; @@ -1064,8 +1051,7 @@ unlock: static int mipi_csis_pm_resume(struct device *dev, bool runtime) { - struct platform_device *pdev = to_platform_device(dev); - struct v4l2_subdev *mipi_sd = platform_get_drvdata(pdev); + struct v4l2_subdev *mipi_sd = dev_get_drvdata(dev); struct csi_state *state = mipi_sd_to_csis_state(mipi_sd); int ret = 0; diff --git a/drivers/staging/media/ipu3/Kconfig b/drivers/staging/media/ipu3/Kconfig index f80f3e35f431..4b51c67eac88 100644 --- a/drivers/staging/media/ipu3/Kconfig +++ b/drivers/staging/media/ipu3/Kconfig @@ -6,7 +6,7 @@ config VIDEO_IPU3_IMGU depends on X86 select IOMMU_IOVA select VIDEOBUF2_DMA_SG - ---help--- + help This is the Video4Linux2 driver for Intel IPU3 image processing unit, found in Intel Skylake and Kaby Lake SoCs and used for processing images and video. diff --git a/drivers/staging/media/ipu3/ipu3-css.c b/drivers/staging/media/ipu3/ipu3-css.c index 15ab77e4b766..23cf5b2cfe8b 100644 --- a/drivers/staging/media/ipu3/ipu3-css.c +++ b/drivers/staging/media/ipu3/ipu3-css.c @@ -3,6 +3,7 @@ #include <linux/device.h> #include <linux/iopoll.h> +#include <linux/slab.h> #include "ipu3-css.h" #include "ipu3-css-fw.h" @@ -1744,15 +1745,18 @@ int imgu_css_fmt_try(struct imgu_css *css, struct v4l2_rect *const bds = &r[IPU3_CSS_RECT_BDS]; struct v4l2_rect *const env = &r[IPU3_CSS_RECT_ENVELOPE]; struct v4l2_rect *const gdc = &r[IPU3_CSS_RECT_GDC]; - struct imgu_css_queue q[IPU3_CSS_QUEUES]; - struct v4l2_pix_format_mplane *const in = - &q[IPU3_CSS_QUEUE_IN].fmt.mpix; - struct v4l2_pix_format_mplane *const out = - &q[IPU3_CSS_QUEUE_OUT].fmt.mpix; - struct v4l2_pix_format_mplane *const vf = - &q[IPU3_CSS_QUEUE_VF].fmt.mpix; + struct imgu_css_queue *q; + struct v4l2_pix_format_mplane *in, *out, *vf; int i, s, ret; + q = kcalloc(IPU3_CSS_QUEUES, sizeof(struct imgu_css_queue), GFP_KERNEL); + if (!q) + return -ENOMEM; + + in = &q[IPU3_CSS_QUEUE_IN].fmt.mpix; + out = &q[IPU3_CSS_QUEUE_OUT].fmt.mpix; + vf = &q[IPU3_CSS_QUEUE_VF].fmt.mpix; + /* Adjust all formats, get statistics buffer sizes and formats */ for (i = 0; i < IPU3_CSS_QUEUES; i++) { if (fmts[i]) @@ -1766,7 +1770,8 @@ int imgu_css_fmt_try(struct imgu_css *css, IPU3_CSS_QUEUE_TO_FLAGS(i))) { dev_notice(css->dev, "can not initialize queue %s\n", qnames[i]); - return -EINVAL; + ret = -EINVAL; + goto out; } } for (i = 0; i < IPU3_CSS_RECTS; i++) { @@ -1788,7 +1793,8 @@ int imgu_css_fmt_try(struct imgu_css *css, if (!imgu_css_queue_enabled(&q[IPU3_CSS_QUEUE_IN]) || !imgu_css_queue_enabled(&q[IPU3_CSS_QUEUE_OUT])) { dev_warn(css->dev, "required queues are disabled\n"); - return -EINVAL; + ret = -EINVAL; + goto out; } if (!imgu_css_queue_enabled(&q[IPU3_CSS_QUEUE_OUT])) { @@ -1829,7 +1835,8 @@ int imgu_css_fmt_try(struct imgu_css *css, ret = imgu_css_find_binary(css, pipe, q, r); if (ret < 0) { dev_err(css->dev, "failed to find suitable binary\n"); - return -EINVAL; + ret = -EINVAL; + goto out; } css->pipes[pipe].bindex = ret; @@ -1843,7 +1850,8 @@ int imgu_css_fmt_try(struct imgu_css *css, IPU3_CSS_QUEUE_TO_FLAGS(i))) { dev_err(css->dev, "final resolution adjustment failed\n"); - return -EINVAL; + ret = -EINVAL; + goto out; } *fmts[i] = q[i].fmt.mpix; } @@ -1859,7 +1867,10 @@ int imgu_css_fmt_try(struct imgu_css *css, bds->width, bds->height, gdc->width, gdc->height, out->width, out->height, vf->width, vf->height); - return 0; + ret = 0; +out: + kfree(q); + return ret; } int imgu_css_fmt_set(struct imgu_css *css, @@ -2160,11 +2171,6 @@ int imgu_css_set_parameters(struct imgu_css *css, unsigned int pipe, obgrid_size = imgu_css_fw_obgrid_size(bi); stripes = bi->info.isp.sp.iterator.num_stripes ? : 1; - /* - * TODO(b/118782861): If userspace queues more than 4 buffers, the - * parameters from previous buffers will be overwritten. Fix the driver - * not to allow this. - */ imgu_css_pool_get(&css_pipe->pool.parameter_set_info); param_set = imgu_css_pool_last(&css_pipe->pool.parameter_set_info, 0)->vaddr; diff --git a/drivers/staging/media/ipu3/ipu3-v4l2.c b/drivers/staging/media/ipu3/ipu3-v4l2.c index 9c0352b193a7..a7bc22040ed8 100644 --- a/drivers/staging/media/ipu3/ipu3-v4l2.c +++ b/drivers/staging/media/ipu3/ipu3-v4l2.c @@ -66,7 +66,7 @@ static int imgu_subdev_s_stream(struct v4l2_subdev *sd, int enable) struct imgu_css_pipe *css_pipe = &imgu->css.pipes[pipe]; struct imgu_media_pipe *imgu_pipe = &imgu->imgu_pipe[pipe]; - dev_dbg(dev, "%s %d for pipe %d", __func__, enable, pipe); + dev_dbg(dev, "%s %d for pipe %u", __func__, enable, pipe); /* grab ctrl after streamon and return after off */ v4l2_ctrl_grab(imgu_sd->ctrl, enable); @@ -101,7 +101,7 @@ static int imgu_subdev_s_stream(struct v4l2_subdev *sd, int enable) else css_pipe->pipe_id = IPU3_CSS_PIPE_ID_CAPTURE; - dev_dbg(dev, "IPU3 pipe %d pipe_id %d", pipe, css_pipe->pipe_id); + dev_dbg(dev, "IPU3 pipe %u pipe_id %u", pipe, css_pipe->pipe_id); rects[IPU3_CSS_RECT_EFFECTIVE] = &imgu_sd->rect.eff; rects[IPU3_CSS_RECT_BDS] = &imgu_sd->rect.bds; @@ -109,7 +109,7 @@ static int imgu_subdev_s_stream(struct v4l2_subdev *sd, int enable) r = imgu_css_fmt_set(&imgu->css, fmts, rects, pipe); if (r) { - dev_err(dev, "failed to set initial formats pipe %d with (%d)", + dev_err(dev, "failed to set initial formats pipe %u with (%d)", pipe, r); return r; } @@ -157,7 +157,7 @@ static int imgu_subdev_set_fmt(struct v4l2_subdev *sd, u32 pad = fmt->pad; unsigned int pipe = imgu_sd->pipe; - dev_dbg(&imgu->pci_dev->dev, "set subdev %d pad %d fmt to [%dx%d]", + dev_dbg(&imgu->pci_dev->dev, "set subdev %u pad %u fmt to [%ux%u]", pipe, pad, fmt->format.width, fmt->format.height); imgu_pipe = &imgu->imgu_pipe[pipe]; @@ -233,7 +233,7 @@ static int imgu_subdev_set_selection(struct v4l2_subdev *sd, struct v4l2_rect *rect, *try_sel; dev_dbg(&imgu->pci_dev->dev, - "set subdev %d sel which %d target 0x%4x rect [%dx%d]", + "set subdev %u sel which %u target 0x%4x rect [%ux%u]", imgu_sd->pipe, sel->which, sel->target, sel->r.width, sel->r.height); @@ -279,7 +279,7 @@ static int imgu_link_setup(struct media_entity *entity, WARN_ON(pad >= IMGU_NODE_NUM); - dev_dbg(&imgu->pci_dev->dev, "pipe %d pad %d is %s", pipe, pad, + dev_dbg(&imgu->pci_dev->dev, "pipe %u pad %u is %s", pipe, pad, flags & MEDIA_LNK_FL_ENABLED ? "enabled" : "disabled"); imgu_pipe = &imgu->imgu_pipe[pipe]; @@ -294,7 +294,7 @@ static int imgu_link_setup(struct media_entity *entity, else __clear_bit(pipe, imgu->css.enabled_pipes); - dev_dbg(&imgu->pci_dev->dev, "pipe %d is %s", pipe, + dev_dbg(&imgu->pci_dev->dev, "pipe %u is %s", pipe, flags & MEDIA_LNK_FL_ENABLED ? "enabled" : "disabled"); return 0; @@ -341,8 +341,10 @@ static void imgu_vb2_buf_queue(struct vb2_buffer *vb) struct imgu_video_device *node = container_of(vb->vb2_queue, struct imgu_video_device, vbq); unsigned int queue = imgu_node_to_queue(node->id); + struct imgu_buffer *buf = container_of(vb, struct imgu_buffer, + vid_buf.vbb.vb2_buf); unsigned long need_bytes; - unsigned int pipe = node->pipe; + unsigned long payload = vb2_get_plane_payload(vb, 0); if (vb->vb2_queue->type == V4L2_BUF_TYPE_META_CAPTURE || vb->vb2_queue->type == V4L2_BUF_TYPE_META_OUTPUT) @@ -350,42 +352,26 @@ static void imgu_vb2_buf_queue(struct vb2_buffer *vb) else need_bytes = node->vdev_fmt.fmt.pix_mp.plane_fmt[0].sizeimage; - if (queue == IPU3_CSS_QUEUE_PARAMS) { - unsigned long payload = vb2_get_plane_payload(vb, 0); - struct vb2_v4l2_buffer *buf = - container_of(vb, struct vb2_v4l2_buffer, vb2_buf); - int r = -EINVAL; - - if (payload == 0) { - payload = need_bytes; - vb2_set_plane_payload(vb, 0, payload); - } - if (payload >= need_bytes) - r = imgu_css_set_parameters(&imgu->css, pipe, - vb2_plane_vaddr(vb, 0)); - buf->flags = V4L2_BUF_FLAG_DONE; - vb2_buffer_done(vb, r == 0 ? VB2_BUF_STATE_DONE - : VB2_BUF_STATE_ERROR); - - } else { - struct imgu_buffer *buf = container_of(vb, struct imgu_buffer, - vid_buf.vbb.vb2_buf); + if (queue == IPU3_CSS_QUEUE_PARAMS && payload && payload < need_bytes) { + dev_err(&imgu->pci_dev->dev, "invalid data size for params."); + vb2_buffer_done(vb, VB2_BUF_STATE_ERROR); + return; + } - mutex_lock(&imgu->lock); + mutex_lock(&imgu->lock); + if (queue != IPU3_CSS_QUEUE_PARAMS) imgu_css_buf_init(&buf->css_buf, queue, buf->map.daddr); - list_add_tail(&buf->vid_buf.list, - &node->buffers); - mutex_unlock(&imgu->lock); - vb2_set_plane_payload(&buf->vid_buf.vbb.vb2_buf, 0, need_bytes); + list_add_tail(&buf->vid_buf.list, &node->buffers); + mutex_unlock(&imgu->lock); - if (imgu->streaming) - imgu_queue_buffers(imgu, false, pipe); - } + vb2_set_plane_payload(vb, 0, need_bytes); - dev_dbg(&imgu->pci_dev->dev, "%s for pipe %d node %d", __func__, - node->pipe, node->id); + if (imgu->streaming) + imgu_queue_buffers(imgu, false, node->pipe); + dev_dbg(&imgu->pci_dev->dev, "%s for pipe %u node %u", __func__, + node->pipe, node->id); } static int imgu_vb2_queue_setup(struct vb2_queue *vq, @@ -435,7 +421,7 @@ static bool imgu_all_nodes_streaming(struct imgu_device *imgu, pipe = except->pipe; if (!test_bit(pipe, imgu->css.enabled_pipes)) { dev_warn(&imgu->pci_dev->dev, - "pipe %d link is not ready yet", pipe); + "pipe %u link is not ready yet", pipe); return false; } @@ -479,7 +465,7 @@ static int imgu_vb2_start_streaming(struct vb2_queue *vq, unsigned int count) int r; unsigned int pipe; - dev_dbg(dev, "%s node name %s pipe %d id %u", __func__, + dev_dbg(dev, "%s node name %s pipe %u id %u", __func__, node->name, node->pipe, node->id); if (imgu->streaming) { @@ -539,7 +525,7 @@ static void imgu_vb2_stop_streaming(struct vb2_queue *vq) WARN_ON(!node->enabled); pipe = node->pipe; - dev_dbg(dev, "Try to stream off node [%d][%d]", pipe, node->id); + dev_dbg(dev, "Try to stream off node [%u][%u]", pipe, node->id); imgu_pipe = &imgu->imgu_pipe[pipe]; r = v4l2_subdev_call(&imgu_pipe->imgu_sd.subdev, video, s_stream, 0); if (r) @@ -664,20 +650,19 @@ static int imgu_fmt(struct imgu_device *imgu, unsigned int pipe, int node, struct v4l2_format *f, bool try) { struct device *dev = &imgu->pci_dev->dev; - struct v4l2_pix_format_mplane try_fmts[IPU3_CSS_QUEUES]; struct v4l2_pix_format_mplane *fmts[IPU3_CSS_QUEUES] = { NULL }; struct v4l2_rect *rects[IPU3_CSS_RECTS] = { NULL }; struct v4l2_mbus_framefmt pad_fmt; unsigned int i, css_q; - int r; + int ret; struct imgu_css_pipe *css_pipe = &imgu->css.pipes[pipe]; struct imgu_media_pipe *imgu_pipe = &imgu->imgu_pipe[pipe]; struct imgu_v4l2_subdev *imgu_sd = &imgu_pipe->imgu_sd; - dev_dbg(dev, "set fmt node [%u][%u](try = %d)", pipe, node, try); + dev_dbg(dev, "set fmt node [%u][%u](try = %u)", pipe, node, try); for (i = 0; i < IMGU_NODE_NUM; i++) - dev_dbg(dev, "IMGU pipe %d node %d enabled = %d", + dev_dbg(dev, "IMGU pipe %u node %u enabled = %u", pipe, i, imgu_pipe->nodes[i].enabled); if (imgu_pipe->nodes[IMGU_NODE_VF].enabled) @@ -688,7 +673,7 @@ static int imgu_fmt(struct imgu_device *imgu, unsigned int pipe, int node, else css_pipe->pipe_id = IPU3_CSS_PIPE_ID_CAPTURE; - dev_dbg(dev, "IPU3 pipe %d pipe_id = %d", pipe, css_pipe->pipe_id); + dev_dbg(dev, "IPU3 pipe %u pipe_id = %u", pipe, css_pipe->pipe_id); for (i = 0; i < IPU3_CSS_QUEUES; i++) { unsigned int inode = imgu_map_node(imgu, i); @@ -698,9 +683,13 @@ static int imgu_fmt(struct imgu_device *imgu, unsigned int pipe, int node, continue; if (try) { - try_fmts[i] = - imgu_pipe->nodes[inode].vdev_fmt.fmt.pix_mp; - fmts[i] = &try_fmts[i]; + fmts[i] = kmemdup(&imgu_pipe->nodes[inode].vdev_fmt.fmt.pix_mp, + sizeof(struct v4l2_pix_format_mplane), + GFP_KERNEL); + if (!fmts[i]) { + ret = -ENOMEM; + goto out; + } } else { fmts[i] = &imgu_pipe->nodes[inode].vdev_fmt.fmt.pix_mp; } @@ -730,26 +719,33 @@ static int imgu_fmt(struct imgu_device *imgu, unsigned int pipe, int node, * before we return success from this function, so set it here. */ css_q = imgu_node_to_queue(node); - if (fmts[css_q]) - *fmts[css_q] = f->fmt.pix_mp; - else - return -EINVAL; + if (!fmts[css_q]) { + ret = -EINVAL; + goto out; + } + *fmts[css_q] = f->fmt.pix_mp; if (try) - r = imgu_css_fmt_try(&imgu->css, fmts, rects, pipe); + ret = imgu_css_fmt_try(&imgu->css, fmts, rects, pipe); else - r = imgu_css_fmt_set(&imgu->css, fmts, rects, pipe); + ret = imgu_css_fmt_set(&imgu->css, fmts, rects, pipe); - /* r is the binary number in the firmware blob */ - if (r < 0) - return r; + /* ret is the binary number in the firmware blob */ + if (ret < 0) + goto out; if (try) f->fmt.pix_mp = *fmts[css_q]; else f->fmt = imgu_pipe->nodes[node].vdev_fmt.fmt; - return 0; +out: + if (try) { + for (i = 0; i < IPU3_CSS_QUEUES; i++) + kfree(fmts[i]); + } + + return ret; } static int imgu_try_fmt(struct file *file, void *fh, struct v4l2_format *f) @@ -781,7 +777,7 @@ static int imgu_vidioc_try_fmt(struct file *file, void *fh, struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; int r; - dev_dbg(dev, "%s [%ux%u] for node %d\n", __func__, + dev_dbg(dev, "%s [%ux%u] for node %u\n", __func__, pix_mp->width, pix_mp->height, node->id); r = imgu_try_fmt(file, fh, f); @@ -799,7 +795,7 @@ static int imgu_vidioc_s_fmt(struct file *file, void *fh, struct v4l2_format *f) struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; int r; - dev_dbg(dev, "%s [%ux%u] for node %d\n", __func__, + dev_dbg(dev, "%s [%ux%u] for node %u\n", __func__, pix_mp->width, pix_mp->height, node->id); r = imgu_try_fmt(file, fh, f); @@ -1022,7 +1018,7 @@ static int imgu_sd_s_ctrl(struct v4l2_ctrl *ctrl) struct imgu_device *imgu = v4l2_get_subdevdata(&imgu_sd->subdev); struct device *dev = &imgu->pci_dev->dev; - dev_dbg(dev, "set val %d to ctrl 0x%8x for subdev %d", + dev_dbg(dev, "set val %d to ctrl 0x%8x for subdev %u", ctrl->val, ctrl->id, imgu_sd->pipe); switch (ctrl->id) { @@ -1122,7 +1118,7 @@ static int imgu_v4l2_subdev_register(struct imgu_device *imgu, imgu_sd->subdev.flags = V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; snprintf(imgu_sd->subdev.name, sizeof(imgu_sd->subdev.name), - "%s %d", IMGU_NAME, pipe); + "%s %u", IMGU_NAME, pipe); v4l2_set_subdevdata(&imgu_sd->subdev, imgu); atomic_set(&imgu_sd->running_mode, IPU3_RUNNING_MODE_VIDEO); v4l2_ctrl_handler_init(hdl, 1); @@ -1240,7 +1236,7 @@ static int imgu_v4l2_node_setup(struct imgu_device *imgu, unsigned int pipe, } /* Initialize vdev */ - snprintf(vdev->name, sizeof(vdev->name), "%s %d %s", + snprintf(vdev->name, sizeof(vdev->name), "%s %u %s", IMGU_NAME, pipe, node->name); vdev->release = video_device_release_empty; vdev->fops = &imgu_v4l2_fops; @@ -1335,7 +1331,7 @@ static int imgu_v4l2_register_pipes(struct imgu_device *imgu) r = imgu_v4l2_subdev_register(imgu, &imgu_pipe->imgu_sd, i); if (r) { dev_err(&imgu->pci_dev->dev, - "failed to register subdev%d ret (%d)\n", i, r); + "failed to register subdev%u ret (%d)\n", i, r); goto pipes_cleanup; } r = imgu_v4l2_nodes_setup_pipe(imgu, i); diff --git a/drivers/staging/media/ipu3/ipu3.c b/drivers/staging/media/ipu3/ipu3.c index e0bbdad7cf5b..a7372395a101 100644 --- a/drivers/staging/media/ipu3/ipu3.c +++ b/drivers/staging/media/ipu3/ipu3.c @@ -236,6 +236,11 @@ int imgu_queue_buffers(struct imgu_device *imgu, bool initial, unsigned int pipe dev_dbg(&imgu->pci_dev->dev, "Queue buffers to pipe %d", pipe); mutex_lock(&imgu->lock); + if (!imgu_css_pipe_queue_empty(&imgu->css, pipe)) { + mutex_unlock(&imgu->lock); + return 0; + } + /* Buffer set is queued to FW only when input buffer is ready */ for (node = IMGU_NODE_NUM - 1; imgu_queue_getbuf(imgu, IMGU_NODE_IN, pipe); @@ -245,6 +250,31 @@ int imgu_queue_buffers(struct imgu_device *imgu, bool initial, unsigned int pipe dev_warn(&imgu->pci_dev->dev, "Vf not enabled, ignore queue"); continue; + } else if (node == IMGU_NODE_PARAMS && + imgu_pipe->nodes[node].enabled) { + struct vb2_buffer *vb; + struct imgu_vb2_buffer *ivb; + + /* No parameters for this frame */ + if (list_empty(&imgu_pipe->nodes[node].buffers)) + continue; + + ivb = list_first_entry(&imgu_pipe->nodes[node].buffers, + struct imgu_vb2_buffer, list); + vb = &ivb->vbb.vb2_buf; + r = imgu_css_set_parameters(&imgu->css, pipe, + vb2_plane_vaddr(vb, 0)); + if (r) { + vb2_buffer_done(vb, VB2_BUF_STATE_ERROR); + dev_warn(&imgu->pci_dev->dev, + "set parameters failed."); + continue; + } + + vb2_buffer_done(vb, VB2_BUF_STATE_DONE); + dev_dbg(&imgu->pci_dev->dev, + "queue user parameters %d to css.", vb->index); + list_del(&ivb->list); } else if (imgu_pipe->queue_enabled[node]) { struct imgu_css_buffer *buf = imgu_queue_getbuf(imgu, node, pipe); @@ -790,7 +820,7 @@ out: * PCI rpm framework checks the existence of driver rpm callbacks. * Place a dummy callback here to avoid rpm going into error state. */ -static int imgu_rpm_dummy_cb(struct device *dev) +static __maybe_unused int imgu_rpm_dummy_cb(struct device *dev) { return 0; } diff --git a/drivers/staging/media/mt9t031/Kconfig b/drivers/staging/media/mt9t031/Kconfig deleted file mode 100644 index 232f0cdca68b..000000000000 --- a/drivers/staging/media/mt9t031/Kconfig +++ /dev/null @@ -1,6 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -config SOC_CAMERA_MT9T031 - tristate "mt9t031 support (DEPRECATED)" - depends on SOC_CAMERA && I2C - help - This driver supports MT9T031 cameras from Micron. diff --git a/drivers/staging/media/mt9t031/Makefile b/drivers/staging/media/mt9t031/Makefile deleted file mode 100644 index f663f73a5474..000000000000 --- a/drivers/staging/media/mt9t031/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -obj-$(CONFIG_SOC_CAMERA_MT9T031) += mt9t031.o diff --git a/drivers/staging/media/mt9t031/TODO b/drivers/staging/media/mt9t031/TODO deleted file mode 100644 index 15580a4f950c..000000000000 --- a/drivers/staging/media/mt9t031/TODO +++ /dev/null @@ -1,5 +0,0 @@ -This sensor driver needs to be converted to a regular -v4l2 subdev driver. The soc_camera framework is deprecated and -will be removed in the future. Unless someone does this work this -sensor driver will be deleted when the soc_camera framework is -deleted. diff --git a/drivers/staging/media/omap4iss/Kconfig b/drivers/staging/media/omap4iss/Kconfig index 841cc0b3ce13..4dcbc5065821 100644 --- a/drivers/staging/media/omap4iss/Kconfig +++ b/drivers/staging/media/omap4iss/Kconfig @@ -6,5 +6,5 @@ config VIDEO_OMAP4 depends on ARCH_OMAP4 || COMPILE_TEST select MFD_SYSCON select VIDEOBUF2_DMA_CONTIG - ---help--- + help Driver for an OMAP 4 ISS controller. diff --git a/drivers/staging/media/rockchip/vpu/rockchip_vpu_drv.c b/drivers/staging/media/rockchip/vpu/rockchip_vpu_drv.c index 962412c79b91..58721c46fba4 100644 --- a/drivers/staging/media/rockchip/vpu/rockchip_vpu_drv.c +++ b/drivers/staging/media/rockchip/vpu/rockchip_vpu_drv.c @@ -22,7 +22,6 @@ #include <media/v4l2-event.h> #include <media/v4l2-mem2mem.h> #include <media/videobuf2-core.h> -#include <media/videobuf2-core.h> #include <media/videobuf2-vmalloc.h> #include "rockchip_vpu_common.h" @@ -463,7 +462,7 @@ static int rockchip_vpu_probe(struct platform_device *pdev) } vpu->mdev.dev = vpu->dev; - strlcpy(vpu->mdev.model, DRIVER_NAME, sizeof(vpu->mdev.model)); + strscpy(vpu->mdev.model, DRIVER_NAME, sizeof(vpu->mdev.model)); media_device_init(&vpu->mdev); vpu->v4l2_dev.mdev = &vpu->mdev; diff --git a/drivers/staging/media/rockchip/vpu/rockchip_vpu_enc.c b/drivers/staging/media/rockchip/vpu/rockchip_vpu_enc.c index ab0fb2053620..fb5e36aedd8c 100644 --- a/drivers/staging/media/rockchip/vpu/rockchip_vpu_enc.c +++ b/drivers/staging/media/rockchip/vpu/rockchip_vpu_enc.c @@ -41,7 +41,7 @@ * @is_compressed: Is it a compressed format? * @multiplanar: Is it a multiplanar variant format? (e.g. NV12M) */ -struct v4l2_format_info { +struct rockchip_vpu_v4l2_format_info { u32 format; u32 header_size; u8 num_planes; @@ -52,10 +52,10 @@ struct v4l2_format_info { u8 multiplanar; }; -static const struct v4l2_format_info * -v4l2_format_info(u32 format) +static const struct rockchip_vpu_v4l2_format_info * +rockchip_vpu_v4l2_format_info(u32 format) { - static const struct v4l2_format_info formats[] = { + static const struct rockchip_vpu_v4l2_format_info formats[] = { { .format = V4L2_PIX_FMT_YUV420M, .num_planes = 3, .cpp = { 1, 1, 1 }, .hsub = 2, .vsub = 2, .multiplanar = 1 }, { .format = V4L2_PIX_FMT_NV12M, .num_planes = 2, .cpp = { 1, 2, 0 }, .hsub = 2, .vsub = 2, .multiplanar = 1 }, { .format = V4L2_PIX_FMT_YUYV, .num_planes = 1, .cpp = { 2, 0, 0 }, .hsub = 2, .vsub = 1 }, @@ -76,11 +76,11 @@ static void fill_pixfmt_mp(struct v4l2_pix_format_mplane *pixfmt, int pixelformat, int width, int height) { - const struct v4l2_format_info *info; + const struct rockchip_vpu_v4l2_format_info *info; struct v4l2_plane_pix_format *plane; int i; - info = v4l2_format_info(pixelformat); + info = rockchip_vpu_v4l2_format_info(pixelformat); if (!info) return; diff --git a/drivers/staging/media/soc_camera/TODO b/drivers/staging/media/soc_camera/TODO new file mode 100644 index 000000000000..932af6443b67 --- /dev/null +++ b/drivers/staging/media/soc_camera/TODO @@ -0,0 +1,4 @@ +The SoC camera framework is obsolete and scheduled for removal in the near +future. Developers are encouraged to convert the drivers to use the +regular V4L2 API if these drivers are still needed (and if someone has the +hardware). diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.c b/drivers/staging/media/sunxi/cedrus/cedrus.c index ff11cbeba205..d0429c0e6b6b 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus.c @@ -300,7 +300,7 @@ static int cedrus_probe(struct platform_device *pdev) "Failed to initialize V4L2 M2M device\n"); ret = PTR_ERR(dev->m2m_dev); - goto err_video; + goto err_v4l2; } dev->mdev.dev = &pdev->dev; @@ -310,23 +310,23 @@ static int cedrus_probe(struct platform_device *pdev) dev->mdev.ops = &cedrus_m2m_media_ops; dev->v4l2_dev.mdev = &dev->mdev; - ret = v4l2_m2m_register_media_controller(dev->m2m_dev, vfd, - MEDIA_ENT_F_PROC_VIDEO_DECODER); - if (ret) { - v4l2_err(&dev->v4l2_dev, - "Failed to initialize V4L2 M2M media controller\n"); - goto err_m2m; - } - ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0); if (ret) { v4l2_err(&dev->v4l2_dev, "Failed to register video device\n"); - goto err_v4l2; + goto err_m2m; } v4l2_info(&dev->v4l2_dev, "Device registered as /dev/video%d\n", vfd->num); + ret = v4l2_m2m_register_media_controller(dev->m2m_dev, vfd, + MEDIA_ENT_F_PROC_VIDEO_DECODER); + if (ret) { + v4l2_err(&dev->v4l2_dev, + "Failed to initialize V4L2 M2M media controller\n"); + goto err_video; + } + ret = media_device_register(&dev->mdev); if (ret) { v4l2_err(&dev->v4l2_dev, "Failed to register media device\n"); @@ -339,10 +339,10 @@ static int cedrus_probe(struct platform_device *pdev) err_m2m_mc: v4l2_m2m_unregister_media_controller(dev->m2m_dev); -err_m2m: - v4l2_m2m_release(dev->m2m_dev); err_video: video_unregister_device(&dev->vfd); +err_m2m: + v4l2_m2m_release(dev->m2m_dev); err_v4l2: v4l2_device_unregister(&dev->v4l2_dev); @@ -396,6 +396,11 @@ static const struct cedrus_variant sun50i_h5_cedrus_variant = { .capabilities = CEDRUS_CAPABILITY_UNTILED, }; +static const struct cedrus_variant sun50i_h6_cedrus_variant = { + .capabilities = CEDRUS_CAPABILITY_UNTILED, + .quirks = CEDRUS_QUIRK_NO_DMA_OFFSET, +}; + static const struct of_device_id cedrus_dt_match[] = { { .compatible = "allwinner,sun4i-a10-video-engine", @@ -425,6 +430,10 @@ static const struct of_device_id cedrus_dt_match[] = { .compatible = "allwinner,sun50i-h5-video-engine", .data = &sun50i_h5_cedrus_variant, }, + { + .compatible = "allwinner,sun50i-h6-video-engine", + .data = &sun50i_h6_cedrus_variant, + }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, cedrus_dt_match); diff --git a/drivers/staging/media/sunxi/cedrus/cedrus.h b/drivers/staging/media/sunxi/cedrus/cedrus.h index 4aedd24a9848..c57c04b41d2e 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus.h +++ b/drivers/staging/media/sunxi/cedrus/cedrus.h @@ -28,6 +28,8 @@ #define CEDRUS_CAPABILITY_UNTILED BIT(0) +#define CEDRUS_QUIRK_NO_DMA_OFFSET BIT(0) + enum cedrus_codec { CEDRUS_CODEC_MPEG2, @@ -91,6 +93,7 @@ struct cedrus_dec_ops { struct cedrus_variant { unsigned int capabilities; + unsigned int quirks; }; struct cedrus_dev { diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_hw.c b/drivers/staging/media/sunxi/cedrus/cedrus_hw.c index 0acf219a8c91..fbfff7c1c771 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_hw.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_hw.c @@ -177,7 +177,8 @@ int cedrus_hw_probe(struct cedrus_dev *dev) */ #ifdef PHYS_PFN_OFFSET - dev->dev->dma_pfn_offset = PHYS_PFN_OFFSET; + if (!(variant->quirks & CEDRUS_QUIRK_NO_DMA_OFFSET)) + dev->dev->dma_pfn_offset = PHYS_PFN_OFFSET; #endif ret = of_reserved_mem_device_init(dev->dev); diff --git a/drivers/staging/media/sunxi/cedrus/cedrus_video.c b/drivers/staging/media/sunxi/cedrus/cedrus_video.c index b47854b3bce4..9673874ece10 100644 --- a/drivers/staging/media/sunxi/cedrus/cedrus_video.c +++ b/drivers/staging/media/sunxi/cedrus/cedrus_video.c @@ -536,6 +536,7 @@ int cedrus_queue_init(void *priv, struct vb2_queue *src_vq, src_vq->lock = &ctx->dev->dev_mutex; src_vq->dev = ctx->dev->dev; src_vq->supports_requests = true; + src_vq->requires_requests = true; ret = vb2_queue_init(src_vq); if (ret) diff --git a/drivers/staging/media/zoran/Kconfig b/drivers/staging/media/zoran/Kconfig deleted file mode 100644 index 84502b0fe48a..000000000000 --- a/drivers/staging/media/zoran/Kconfig +++ /dev/null @@ -1,76 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -config VIDEO_ZORAN - tristate "Zoran ZR36057/36067 Video For Linux (Deprecated)" - depends on PCI && I2C_ALGOBIT && VIDEO_V4L2 && VIRT_TO_BUS - depends on !ALPHA - help - Say Y for support for MJPEG capture cards based on the Zoran - 36057/36067 PCI controller chipset. This includes the Iomega - Buz, Pinnacle DC10+ and the Linux Media Labs LML33. There is - a driver homepage at <http://mjpeg.sf.net/driver-zoran/>. For - more information, check <file:Documentation/media/v4l-drivers/zoran.rst>. - - To compile this driver as a module, choose M here: the - module will be called zr36067. - -config VIDEO_ZORAN_DC30 - tristate "Pinnacle/Miro DC30(+) support" - depends on VIDEO_ZORAN - select VIDEO_ADV7175 if MEDIA_SUBDRV_AUTOSELECT - select VIDEO_VPX3220 if MEDIA_SUBDRV_AUTOSELECT - help - Support for the Pinnacle/Miro DC30(+) MJPEG capture/playback - card. This also supports really old DC10 cards based on the - zr36050 MJPEG codec and zr36016 VFE. - -config VIDEO_ZORAN_ZR36060 - tristate "Zoran ZR36060" - depends on VIDEO_ZORAN - help - Say Y to support Zoran boards based on 36060 chips. - This includes Iomega Buz, Pinnacle DC10, Linux media Labs 33 - and 33 R10 and AverMedia 6 boards. - -config VIDEO_ZORAN_BUZ - tristate "Iomega Buz support" - depends on VIDEO_ZORAN_ZR36060 - select VIDEO_SAA711X if MEDIA_SUBDRV_AUTOSELECT - select VIDEO_SAA7185 if MEDIA_SUBDRV_AUTOSELECT - help - Support for the Iomega Buz MJPEG capture/playback card. - -config VIDEO_ZORAN_DC10 - tristate "Pinnacle/Miro DC10(+) support" - depends on VIDEO_ZORAN_ZR36060 - select VIDEO_SAA7110 if MEDIA_SUBDRV_AUTOSELECT - select VIDEO_ADV7175 if MEDIA_SUBDRV_AUTOSELECT - help - Support for the Pinnacle/Miro DC10(+) MJPEG capture/playback - card. - -config VIDEO_ZORAN_LML33 - tristate "Linux Media Labs LML33 support" - depends on VIDEO_ZORAN_ZR36060 - select VIDEO_BT819 if MEDIA_SUBDRV_AUTOSELECT - select VIDEO_BT856 if MEDIA_SUBDRV_AUTOSELECT - help - Support for the Linux Media Labs LML33 MJPEG capture/playback - card. - -config VIDEO_ZORAN_LML33R10 - tristate "Linux Media Labs LML33R10 support" - depends on VIDEO_ZORAN_ZR36060 - select VIDEO_SAA711X if MEDIA_SUBDRV_AUTOSELECT - select VIDEO_ADV7170 if MEDIA_SUBDRV_AUTOSELECT - help - support for the Linux Media Labs LML33R10 MJPEG capture/playback - card. - -config VIDEO_ZORAN_AVS6EYES - tristate "AverMedia 6 Eyes support" - depends on VIDEO_ZORAN_ZR36060 - select VIDEO_BT856 if MEDIA_SUBDRV_AUTOSELECT - select VIDEO_BT866 if MEDIA_SUBDRV_AUTOSELECT - select VIDEO_KS0127 if MEDIA_SUBDRV_AUTOSELECT - help - Support for the AverMedia 6 Eyes video surveillance card. diff --git a/drivers/staging/media/zoran/Makefile b/drivers/staging/media/zoran/Makefile deleted file mode 100644 index 21ac29a71458..000000000000 --- a/drivers/staging/media/zoran/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 -zr36067-objs := zoran_procfs.o zoran_device.o \ - zoran_driver.o zoran_card.o - -obj-$(CONFIG_VIDEO_ZORAN) += zr36067.o videocodec.o -obj-$(CONFIG_VIDEO_ZORAN_DC30) += zr36050.o zr36016.o -obj-$(CONFIG_VIDEO_ZORAN_ZR36060) += zr36060.o diff --git a/drivers/staging/media/zoran/TODO b/drivers/staging/media/zoran/TODO deleted file mode 100644 index 54464095d0d7..000000000000 --- a/drivers/staging/media/zoran/TODO +++ /dev/null @@ -1,4 +0,0 @@ -The zoran driver is marked deprecated. It will be removed -around May 2019 unless someone is willing to update this -driver to the latest V4L2 frameworks (especially the vb2 -framework). diff --git a/drivers/staging/media/zoran/videocodec.c b/drivers/staging/media/zoran/videocodec.c deleted file mode 100644 index c1ee5cb7e66b..000000000000 --- a/drivers/staging/media/zoran/videocodec.c +++ /dev/null @@ -1,379 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * VIDEO MOTION CODECs internal API for video devices - * - * Interface for MJPEG (and maybe later MPEG/WAVELETS) codec's - * bound to a master device. - * - * (c) 2002 Wolfgang Scherr <scherr@net4you.at> - * - * $Id: videocodec.c,v 1.1.2.8 2003/03/29 07:16:04 rbultje Exp $ - * ------------------------------------------------------------------------ - */ - -#define VIDEOCODEC_VERSION "v0.2" - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/init.h> -#include <linux/types.h> -#include <linux/slab.h> - -// kernel config is here (procfs flag) - -#ifdef CONFIG_PROC_FS -#include <linux/proc_fs.h> -#include <linux/seq_file.h> -#include <linux/uaccess.h> -#endif - -#include "videocodec.h" - -static int debug; -module_param(debug, int, 0); -MODULE_PARM_DESC(debug, "Debug level (0-4)"); - -#define dprintk(num, format, args...) \ - do { \ - if (debug >= num) \ - printk(format, ##args); \ - } while (0) - -struct attached_list { - struct videocodec *codec; - struct attached_list *next; -}; - -struct codec_list { - const struct videocodec *codec; - int attached; - struct attached_list *list; - struct codec_list *next; -}; - -static struct codec_list *codeclist_top = NULL; - -/* ================================================= */ -/* function prototypes of the master/slave interface */ -/* ================================================= */ - -struct videocodec * -videocodec_attach (struct videocodec_master *master) -{ - struct codec_list *h = codeclist_top; - struct attached_list *a, *ptr; - struct videocodec *codec; - int res; - - if (!master) { - dprintk(1, KERN_ERR "videocodec_attach: no data\n"); - return NULL; - } - - dprintk(2, - "videocodec_attach: '%s', flags %lx, magic %lx\n", - master->name, master->flags, master->magic); - - if (!h) { - dprintk(1, - KERN_ERR - "videocodec_attach: no device available\n"); - return NULL; - } - - while (h) { - // attach only if the slave has at least the flags - // expected by the master - if ((master->flags & h->codec->flags) == master->flags) { - dprintk(4, "videocodec_attach: try '%s'\n", - h->codec->name); - - if (!try_module_get(h->codec->owner)) - return NULL; - - codec = kmemdup(h->codec, sizeof(struct videocodec), - GFP_KERNEL); - if (!codec) { - dprintk(1, - KERN_ERR - "videocodec_attach: no mem\n"); - goto out_module_put; - } - - res = strlen(codec->name); - snprintf(codec->name + res, sizeof(codec->name) - res, - "[%d]", h->attached); - codec->master_data = master; - res = codec->setup(codec); - if (res == 0) { - dprintk(3, "videocodec_attach '%s'\n", - codec->name); - ptr = kzalloc(sizeof(struct attached_list), GFP_KERNEL); - if (!ptr) { - dprintk(1, - KERN_ERR - "videocodec_attach: no memory\n"); - goto out_kfree; - } - ptr->codec = codec; - - a = h->list; - if (!a) { - h->list = ptr; - dprintk(4, - "videocodec: first element\n"); - } else { - while (a->next) - a = a->next; // find end - a->next = ptr; - dprintk(4, - "videocodec: in after '%s'\n", - h->codec->name); - } - - h->attached += 1; - return codec; - } else { - kfree(codec); - } - } - h = h->next; - } - - dprintk(1, KERN_ERR "videocodec_attach: no codec found!\n"); - return NULL; - - out_module_put: - module_put(h->codec->owner); - out_kfree: - kfree(codec); - return NULL; -} - -int -videocodec_detach (struct videocodec *codec) -{ - struct codec_list *h = codeclist_top; - struct attached_list *a, *prev; - int res; - - if (!codec) { - dprintk(1, KERN_ERR "videocodec_detach: no data\n"); - return -EINVAL; - } - - dprintk(2, - "videocodec_detach: '%s', type: %x, flags %lx, magic %lx\n", - codec->name, codec->type, codec->flags, codec->magic); - - if (!h) { - dprintk(1, - KERN_ERR "videocodec_detach: no device left...\n"); - return -ENXIO; - } - - while (h) { - a = h->list; - prev = NULL; - while (a) { - if (codec == a->codec) { - res = a->codec->unset(a->codec); - if (res >= 0) { - dprintk(3, - "videocodec_detach: '%s'\n", - a->codec->name); - a->codec->master_data = NULL; - } else { - dprintk(1, - KERN_ERR - "videocodec_detach: '%s'\n", - a->codec->name); - a->codec->master_data = NULL; - } - if (prev == NULL) { - h->list = a->next; - dprintk(4, - "videocodec: delete first\n"); - } else { - prev->next = a->next; - dprintk(4, - "videocodec: delete middle\n"); - } - module_put(a->codec->owner); - kfree(a->codec); - kfree(a); - h->attached -= 1; - return 0; - } - prev = a; - a = a->next; - } - h = h->next; - } - - dprintk(1, KERN_ERR "videocodec_detach: given codec not found!\n"); - return -EINVAL; -} - -int -videocodec_register (const struct videocodec *codec) -{ - struct codec_list *ptr, *h = codeclist_top; - - if (!codec) { - dprintk(1, KERN_ERR "videocodec_register: no data!\n"); - return -EINVAL; - } - - dprintk(2, - "videocodec: register '%s', type: %x, flags %lx, magic %lx\n", - codec->name, codec->type, codec->flags, codec->magic); - - ptr = kzalloc(sizeof(struct codec_list), GFP_KERNEL); - if (!ptr) { - dprintk(1, KERN_ERR "videocodec_register: no memory\n"); - return -ENOMEM; - } - ptr->codec = codec; - - if (!h) { - codeclist_top = ptr; - dprintk(4, "videocodec: hooked in as first element\n"); - } else { - while (h->next) - h = h->next; // find the end - h->next = ptr; - dprintk(4, "videocodec: hooked in after '%s'\n", - h->codec->name); - } - - return 0; -} - -int -videocodec_unregister (const struct videocodec *codec) -{ - struct codec_list *prev = NULL, *h = codeclist_top; - - if (!codec) { - dprintk(1, KERN_ERR "videocodec_unregister: no data!\n"); - return -EINVAL; - } - - dprintk(2, - "videocodec: unregister '%s', type: %x, flags %lx, magic %lx\n", - codec->name, codec->type, codec->flags, codec->magic); - - if (!h) { - dprintk(1, - KERN_ERR - "videocodec_unregister: no device left...\n"); - return -ENXIO; - } - - while (h) { - if (codec == h->codec) { - if (h->attached) { - dprintk(1, - KERN_ERR - "videocodec: '%s' is used\n", - h->codec->name); - return -EBUSY; - } - dprintk(3, "videocodec: unregister '%s' is ok.\n", - h->codec->name); - if (prev == NULL) { - codeclist_top = h->next; - dprintk(4, - "videocodec: delete first element\n"); - } else { - prev->next = h->next; - dprintk(4, - "videocodec: delete middle element\n"); - } - kfree(h); - return 0; - } - prev = h; - h = h->next; - } - - dprintk(1, - KERN_ERR - "videocodec_unregister: given codec not found!\n"); - return -EINVAL; -} - -#ifdef CONFIG_PROC_FS -static int proc_videocodecs_show(struct seq_file *m, void *v) -{ - struct codec_list *h = codeclist_top; - struct attached_list *a; - - seq_printf(m, "<S>lave or attached <M>aster name type flags magic "); - seq_printf(m, "(connected as)\n"); - - while (h) { - seq_printf(m, "S %32s %04x %08lx %08lx (TEMPLATE)\n", - h->codec->name, h->codec->type, - h->codec->flags, h->codec->magic); - a = h->list; - while (a) { - seq_printf(m, "M %32s %04x %08lx %08lx (%s)\n", - a->codec->master_data->name, - a->codec->master_data->type, - a->codec->master_data->flags, - a->codec->master_data->magic, - a->codec->name); - a = a->next; - } - h = h->next; - } - - return 0; -} -#endif - -/* ===================== */ -/* hook in driver module */ -/* ===================== */ -static int __init -videocodec_init (void) -{ -#ifdef CONFIG_PROC_FS - static struct proc_dir_entry *videocodec_proc_entry; -#endif - - printk(KERN_INFO "Linux video codec intermediate layer: %s\n", - VIDEOCODEC_VERSION); - -#ifdef CONFIG_PROC_FS - videocodec_proc_entry = proc_create_single("videocodecs", 0, NULL, - proc_videocodecs_show); - if (!videocodec_proc_entry) { - dprintk(1, KERN_ERR "videocodec: can't init procfs.\n"); - } -#endif - return 0; -} - -static void __exit -videocodec_exit (void) -{ -#ifdef CONFIG_PROC_FS - remove_proc_entry("videocodecs", NULL); -#endif -} - -EXPORT_SYMBOL(videocodec_attach); -EXPORT_SYMBOL(videocodec_detach); -EXPORT_SYMBOL(videocodec_register); -EXPORT_SYMBOL(videocodec_unregister); - -module_init(videocodec_init); -module_exit(videocodec_exit); - -MODULE_AUTHOR("Wolfgang Scherr <scherr@net4you.at>"); -MODULE_DESCRIPTION("Intermediate API module for video codecs " - VIDEOCODEC_VERSION); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/media/zoran/videocodec.h b/drivers/staging/media/zoran/videocodec.h deleted file mode 100644 index 4946791fce0d..000000000000 --- a/drivers/staging/media/zoran/videocodec.h +++ /dev/null @@ -1,334 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * VIDEO MOTION CODECs internal API for video devices - * - * Interface for MJPEG (and maybe later MPEG/WAVELETS) codec's - * bound to a master device. - * - * (c) 2002 Wolfgang Scherr <scherr@net4you.at> - */ - -/* =================== */ -/* general description */ -/* =================== */ - -/* Should ease the (re-)usage of drivers supporting cards with (different) - video codecs. The codecs register to this module their functionality, - and the processors (masters) can attach to them if they fit. - - The codecs are typically have a "strong" binding to their master - so I - don't think it makes sense to have a full blown interfacing as with e.g. - i2c. If you have an other opinion, let's discuss & implement it :-))) - - Usage: - - The slave has just to setup the videocodec structure and use two functions: - videocodec_register(codecdata); - videocodec_unregister(codecdata); - The best is just calling them at module (de-)initialisation. - - The master sets up the structure videocodec_master and calls: - codecdata=videocodec_attach(master_codecdata); - videocodec_detach(codecdata); - - The slave is called during attach/detach via functions setup previously - during register. At that time, the master_data pointer is set up - and the slave can access any io registers of the master device (in the case - the slave is bound to it). Otherwise it doesn't need this functions and - therfor they may not be initialized. - - The other functions are just for convenience, as they are for sure used by - most/all of the codecs. The last ones may be omitted, too. - - See the structure declaration below for more information and which data has - to be set up for the master and the slave. - - ---------------------------------------------------------------------------- - The master should have "knowledge" of the slave and vice versa. So the data - structures sent to/from slave via set_data/get_data set_image/get_image are - device dependent and vary between MJPEG/MPEG/WAVELET/... devices. (!!!!) - ---------------------------------------------------------------------------- -*/ - - -/* ========================================== */ -/* description of the videocodec_io structure */ -/* ========================================== */ - -/* - ==== master setup ==== - name -> name of the device structure for reference and debugging - master_data -> data ref. for the master (e.g. the zr36055,57,67) - readreg -> ref. to read-fn from register (setup by master, used by slave) - writereg -> ref. to write-fn to register (setup by master, used by slave) - this two functions do the lowlevel I/O job - - ==== slave functionality setup ==== - slave_data -> data ref. for the slave (e.g. the zr36050,60) - check -> fn-ref. checks availability of an device, returns -EIO on failure or - the type on success - this makes espcecially sense if a driver module supports more than - one codec which may be quite similar to access, nevertheless it - is good for a first functionality check - - -- main functions you always need for compression/decompression -- - - set_mode -> this fn-ref. resets the entire codec, and sets up the mode - with the last defined norm/size (or device default if not - available) - it returns 0 if the mode is possible - set_size -> this fn-ref. sets the norm and image size for - compression/decompression (returns 0 on success) - the norm param is defined in videodev2.h (V4L2_STD_*) - - additional setup may be available, too - but the codec should work with - some default values even without this - - set_data -> sets device-specific data (tables, quality etc.) - get_data -> query device-specific data (tables, quality etc.) - - if the device delivers interrupts, they may be setup/handled here - setup_interrupt -> codec irq setup (not needed for 36050/60) - handle_interrupt -> codec irq handling (not needed for 36050/60) - - if the device delivers pictures, they may be handled here - put_image -> puts image data to the codec (not needed for 36050/60) - get_image -> gets image data from the codec (not needed for 36050/60) - the calls include frame numbers and flags (even/odd/...) - if needed and a flag which allows blocking until its ready -*/ - -/* ============== */ -/* user interface */ -/* ============== */ - -/* - Currently there is only a information display planned, as the layer - is not visible for the user space at all. - - Information is available via procfs. The current entry is "/proc/videocodecs" - but it makes sense to "hide" it in the /proc/video tree of v4l(2) --TODO--. - -A example for such an output is: - -<S>lave or attached <M>aster name type flags magic (connected as) -S zr36050 0002 0000d001 00000000 (TEMPLATE) -M zr36055[0] 0001 0000c001 00000000 (zr36050[0]) -M zr36055[1] 0001 0000c001 00000000 (zr36050[1]) - -*/ - - -/* =============================================== */ -/* special defines for the videocodec_io structure */ -/* =============================================== */ - -#ifndef __LINUX_VIDEOCODEC_H -#define __LINUX_VIDEOCODEC_H - -#include <linux/videodev2.h> - -#define CODEC_DO_COMPRESSION 0 -#define CODEC_DO_EXPANSION 1 - -/* this are the current codec flags I think they are needed */ -/* -> type value in structure */ -#define CODEC_FLAG_JPEG 0x00000001L // JPEG codec -#define CODEC_FLAG_MPEG 0x00000002L // MPEG1/2/4 codec -#define CODEC_FLAG_DIVX 0x00000004L // DIVX codec -#define CODEC_FLAG_WAVELET 0x00000008L // WAVELET codec - // room for other types - -#define CODEC_FLAG_MAGIC 0x00000800L // magic key must match -#define CODEC_FLAG_HARDWARE 0x00001000L // is a hardware codec -#define CODEC_FLAG_VFE 0x00002000L // has direct video frontend -#define CODEC_FLAG_ENCODER 0x00004000L // compression capability -#define CODEC_FLAG_DECODER 0x00008000L // decompression capability -#define CODEC_FLAG_NEEDIRQ 0x00010000L // needs irq handling -#define CODEC_FLAG_RDWRPIC 0x00020000L // handles picture I/O - -/* a list of modes, some are just examples (is there any HW?) */ -#define CODEC_MODE_BJPG 0x0001 // Baseline JPEG -#define CODEC_MODE_LJPG 0x0002 // Lossless JPEG -#define CODEC_MODE_MPEG1 0x0003 // MPEG 1 -#define CODEC_MODE_MPEG2 0x0004 // MPEG 2 -#define CODEC_MODE_MPEG4 0x0005 // MPEG 4 -#define CODEC_MODE_MSDIVX 0x0006 // MS DivX -#define CODEC_MODE_ODIVX 0x0007 // Open DivX -#define CODEC_MODE_WAVELET 0x0008 // Wavelet - -/* this are the current codec types I want to implement */ -/* -> type value in structure */ -#define CODEC_TYPE_NONE 0 -#define CODEC_TYPE_L64702 1 -#define CODEC_TYPE_ZR36050 2 -#define CODEC_TYPE_ZR36016 3 -#define CODEC_TYPE_ZR36060 4 - -/* the type of data may be enhanced by future implementations (data-fn.'s) */ -/* -> used in command */ -#define CODEC_G_STATUS 0x0000 /* codec status (query only) */ -#define CODEC_S_CODEC_MODE 0x0001 /* codec mode (baseline JPEG, MPEG1,... */ -#define CODEC_G_CODEC_MODE 0x8001 -#define CODEC_S_VFE 0x0002 /* additional video frontend setup */ -#define CODEC_G_VFE 0x8002 -#define CODEC_S_MMAP 0x0003 /* MMAP setup (if available) */ - -#define CODEC_S_JPEG_TDS_BYTE 0x0010 /* target data size in bytes */ -#define CODEC_G_JPEG_TDS_BYTE 0x8010 -#define CODEC_S_JPEG_SCALE 0x0011 /* scaling factor for quant. tables */ -#define CODEC_G_JPEG_SCALE 0x8011 -#define CODEC_S_JPEG_HDT_DATA 0x0018 /* huffman-tables */ -#define CODEC_G_JPEG_HDT_DATA 0x8018 -#define CODEC_S_JPEG_QDT_DATA 0x0019 /* quantizing-tables */ -#define CODEC_G_JPEG_QDT_DATA 0x8019 -#define CODEC_S_JPEG_APP_DATA 0x001A /* APP marker */ -#define CODEC_G_JPEG_APP_DATA 0x801A -#define CODEC_S_JPEG_COM_DATA 0x001B /* COM marker */ -#define CODEC_G_JPEG_COM_DATA 0x801B - -#define CODEC_S_PRIVATE 0x1000 /* "private" commands start here */ -#define CODEC_G_PRIVATE 0x9000 - -#define CODEC_G_FLAG 0x8000 /* this is how 'get' is detected */ - -/* types of transfer, directly user space or a kernel buffer (image-fn.'s) */ -/* -> used in get_image, put_image */ -#define CODEC_TRANSFER_KERNEL 0 /* use "memcopy" */ -#define CODEC_TRANSFER_USER 1 /* use "to/from_user" */ - - -/* ========================= */ -/* the structures itself ... */ -/* ========================= */ - -struct vfe_polarity { - unsigned int vsync_pol:1; - unsigned int hsync_pol:1; - unsigned int field_pol:1; - unsigned int blank_pol:1; - unsigned int subimg_pol:1; - unsigned int poe_pol:1; - unsigned int pvalid_pol:1; - unsigned int vclk_pol:1; -}; - -struct vfe_settings { - __u32 x, y; /* Offsets into image */ - __u32 width, height; /* Area to capture */ - __u16 decimation; /* Decimation divider */ - __u16 flags; /* Flags for capture */ - __u16 quality; /* quality of the video */ -}; - -struct tvnorm { - u16 Wt, Wa, HStart, HSyncStart, Ht, Ha, VStart; -}; - -struct jpeg_com_marker { - int len; /* number of usable bytes in data */ - char data[60]; -}; - -struct jpeg_app_marker { - int appn; /* number app segment */ - int len; /* number of usable bytes in data */ - char data[60]; -}; - -struct videocodec { - struct module *owner; - /* -- filled in by slave device during register -- */ - char name[32]; - unsigned long magic; /* may be used for client<->master attaching */ - unsigned long flags; /* functionality flags */ - unsigned int type; /* codec type */ - - /* -- these is filled in later during master device attach -- */ - - struct videocodec_master *master_data; - - /* -- these are filled in by the slave device during register -- */ - - void *data; /* private slave data */ - - /* attach/detach client functions (indirect call) */ - int (*setup) (struct videocodec * codec); - int (*unset) (struct videocodec * codec); - - /* main functions, every client needs them for sure! */ - // set compression or decompression (or freeze, stop, standby, etc) - int (*set_mode) (struct videocodec * codec, - int mode); - // setup picture size and norm (for the codec's video frontend) - int (*set_video) (struct videocodec * codec, - struct tvnorm * norm, - struct vfe_settings * cap, - struct vfe_polarity * pol); - // other control commands, also mmap setup etc. - int (*control) (struct videocodec * codec, - int type, - int size, - void *data); - - /* additional setup/query/processing (may be NULL pointer) */ - // interrupt setup / handling (for irq's delivered by master) - int (*setup_interrupt) (struct videocodec * codec, - long mode); - int (*handle_interrupt) (struct videocodec * codec, - int source, - long flag); - // picture interface (if any) - long (*put_image) (struct videocodec * codec, - int tr_type, - int block, - long *fr_num, - long *flag, - long size, - void *buf); - long (*get_image) (struct videocodec * codec, - int tr_type, - int block, - long *fr_num, - long *flag, - long size, - void *buf); -}; - -struct videocodec_master { - /* -- filled in by master device for registration -- */ - char name[32]; - unsigned long magic; /* may be used for client<->master attaching */ - unsigned long flags; /* functionality flags */ - unsigned int type; /* master type */ - - void *data; /* private master data */ - - __u32(*readreg) (struct videocodec * codec, - __u16 reg); - void (*writereg) (struct videocodec * codec, - __u16 reg, - __u32 value); -}; - - -/* ================================================= */ -/* function prototypes of the master/slave interface */ -/* ================================================= */ - -/* attach and detach commands for the master */ -// * master structure needs to be kmalloc'ed before calling attach -// and free'd after calling detach -// * returns pointer on success, NULL on failure -extern struct videocodec *videocodec_attach(struct videocodec_master *); -// * 0 on success, <0 (errno) on failure -extern int videocodec_detach(struct videocodec *); - -/* register and unregister commands for the slaves */ -// * 0 on success, <0 (errno) on failure -extern int videocodec_register(const struct videocodec *); -// * 0 on success, <0 (errno) on failure -extern int videocodec_unregister(const struct videocodec *); - -/* the other calls are directly done via the videocodec structure! */ - -#endif /*ifndef __LINUX_VIDEOCODEC_H */ diff --git a/drivers/staging/media/zoran/zoran.h b/drivers/staging/media/zoran/zoran.h deleted file mode 100644 index 1b2e1fb3555f..000000000000 --- a/drivers/staging/media/zoran/zoran.h +++ /dev/null @@ -1,392 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * zoran - Iomega Buz driver - * - * Copyright (C) 1999 Rainer Johanni <Rainer@Johanni.de> - * - * based on - * - * zoran.0.0.3 Copyright (C) 1998 Dave Perks <dperks@ibm.net> - * - * and - * - * bttv - Bt848 frame grabber driver - * Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de) - * & Marcus Metzler (mocm@thp.uni-koeln.de) - */ -#ifndef _BUZ_H_ -#define _BUZ_H_ - -#include <media/v4l2-device.h> -#include <media/v4l2-ctrls.h> -#include <media/v4l2-fh.h> - -struct zoran_sync { - unsigned long frame; /* number of buffer that has been free'd */ - unsigned long length; /* number of code bytes in buffer (capture only) */ - unsigned long seq; /* frame sequence number */ - u64 ts; /* timestamp */ -}; - - -#define ZORAN_NAME "ZORAN" /* name of the device */ - -#define ZR_DEVNAME(zr) ((zr)->name) - -#define BUZ_MAX_WIDTH (zr->timing->Wa) -#define BUZ_MAX_HEIGHT (zr->timing->Ha) -#define BUZ_MIN_WIDTH 32 /* never display less than 32 pixels */ -#define BUZ_MIN_HEIGHT 24 /* never display less than 24 rows */ - -#define BUZ_NUM_STAT_COM 4 -#define BUZ_MASK_STAT_COM 3 - -#define BUZ_MAX_FRAME 256 /* Must be a power of 2 */ -#define BUZ_MASK_FRAME 255 /* Must be BUZ_MAX_FRAME-1 */ - -#define BUZ_MAX_INPUT 16 - -#if VIDEO_MAX_FRAME <= 32 -# define V4L_MAX_FRAME 32 -#elif VIDEO_MAX_FRAME <= 64 -# define V4L_MAX_FRAME 64 -#else -# error "Too many video frame buffers to handle" -#endif -#define V4L_MASK_FRAME (V4L_MAX_FRAME - 1) - -#define MAX_FRAME (BUZ_MAX_FRAME > VIDEO_MAX_FRAME ? BUZ_MAX_FRAME : VIDEO_MAX_FRAME) - -#include "zr36057.h" - -enum card_type { - UNKNOWN = -1, - - /* Pinnacle/Miro */ - DC10_old, /* DC30 like */ - DC10_new, /* DC10plus like */ - DC10plus, - DC30, - DC30plus, - - /* Linux Media Labs */ - LML33, - LML33R10, - - /* Iomega */ - BUZ, - - /* AverMedia */ - AVS6EYES, - - /* total number of cards */ - NUM_CARDS -}; - -enum zoran_codec_mode { - BUZ_MODE_IDLE, /* nothing going on */ - BUZ_MODE_MOTION_COMPRESS, /* grabbing frames */ - BUZ_MODE_MOTION_DECOMPRESS, /* playing frames */ - BUZ_MODE_STILL_COMPRESS, /* still frame conversion */ - BUZ_MODE_STILL_DECOMPRESS /* still frame conversion */ -}; - -enum zoran_buffer_state { - BUZ_STATE_USER, /* buffer is owned by application */ - BUZ_STATE_PEND, /* buffer is queued in pend[] ready to feed to I/O */ - BUZ_STATE_DMA, /* buffer is queued in dma[] for I/O */ - BUZ_STATE_DONE /* buffer is ready to return to application */ -}; - -enum zoran_map_mode { - ZORAN_MAP_MODE_RAW, - ZORAN_MAP_MODE_JPG_REC, -#define ZORAN_MAP_MODE_JPG ZORAN_MAP_MODE_JPG_REC - ZORAN_MAP_MODE_JPG_PLAY, -}; - -enum gpio_type { - ZR_GPIO_JPEG_SLEEP = 0, - ZR_GPIO_JPEG_RESET, - ZR_GPIO_JPEG_FRAME, - ZR_GPIO_VID_DIR, - ZR_GPIO_VID_EN, - ZR_GPIO_VID_RESET, - ZR_GPIO_CLK_SEL1, - ZR_GPIO_CLK_SEL2, - ZR_GPIO_MAX, -}; - -enum gpcs_type { - GPCS_JPEG_RESET = 0, - GPCS_JPEG_START, - GPCS_MAX, -}; - -struct zoran_format { - char *name; - __u32 fourcc; - int colorspace; - int depth; - __u32 flags; - __u32 vfespfr; -}; -/* flags */ -#define ZORAN_FORMAT_COMPRESSED 1<<0 -#define ZORAN_FORMAT_OVERLAY 1<<1 -#define ZORAN_FORMAT_CAPTURE 1<<2 -#define ZORAN_FORMAT_PLAYBACK 1<<3 - -/* overlay-settings */ -struct zoran_overlay_settings { - int is_set; - int x, y, width, height; /* position */ - int clipcount; /* position and number of clips */ - const struct zoran_format *format; /* overlay format */ -}; - -/* v4l-capture settings */ -struct zoran_v4l_settings { - int width, height, bytesperline; /* capture size */ - const struct zoran_format *format; /* capture format */ -}; - -/* jpg-capture/-playback settings */ -struct zoran_jpg_settings { - int decimation; /* this bit is used to set everything to default */ - int HorDcm, VerDcm, TmpDcm; /* capture decimation settings (TmpDcm=1 means both fields) */ - int field_per_buff, odd_even; /* field-settings (odd_even=1 (+TmpDcm=1) means top-field-first) */ - int img_x, img_y, img_width, img_height; /* crop settings (subframe capture) */ - struct v4l2_jpegcompression jpg_comp; /* JPEG-specific capture settings */ -}; - -struct zoran_fh; - -struct zoran_mapping { - struct zoran_fh *fh; - atomic_t count; -}; - -struct zoran_buffer { - struct zoran_mapping *map; - enum zoran_buffer_state state; /* state: unused/pending/dma/done */ - struct zoran_sync bs; /* DONE: info to return to application */ - union { - struct { - __le32 *frag_tab; /* addresses of frag table */ - u32 frag_tab_bus; /* same value cached to save time in ISR */ - } jpg; - struct { - char *fbuffer; /* virtual address of frame buffer */ - unsigned long fbuffer_phys;/* physical address of frame buffer */ - unsigned long fbuffer_bus;/* bus address of frame buffer */ - } v4l; - }; -}; - -enum zoran_lock_activity { - ZORAN_FREE, /* free for use */ - ZORAN_ACTIVE, /* active but unlocked */ - ZORAN_LOCKED, /* locked */ -}; - -/* buffer collections */ -struct zoran_buffer_col { - enum zoran_lock_activity active; /* feature currently in use? */ - unsigned int num_buffers, buffer_size; - struct zoran_buffer buffer[MAX_FRAME]; /* buffers */ - u8 allocated; /* Flag if buffers are allocated */ - u8 need_contiguous; /* Flag if contiguous buffers are needed */ - /* only applies to jpg buffers, raw buffers are always contiguous */ -}; - -struct zoran; - -/* zoran_fh contains per-open() settings */ -struct zoran_fh { - struct v4l2_fh fh; - struct zoran *zr; - - enum zoran_map_mode map_mode; /* Flag which bufferset will map by next mmap() */ - - struct zoran_overlay_settings overlay_settings; - u32 *overlay_mask; /* overlay mask */ - enum zoran_lock_activity overlay_active;/* feature currently in use? */ - - struct zoran_buffer_col buffers; /* buffers' info */ - - struct zoran_v4l_settings v4l_settings; /* structure with a lot of things to play with */ - struct zoran_jpg_settings jpg_settings; /* structure with a lot of things to play with */ -}; - -struct card_info { - enum card_type type; - char name[32]; - const char *i2c_decoder; /* i2c decoder device */ - const unsigned short *addrs_decoder; - const char *i2c_encoder; /* i2c encoder device */ - const unsigned short *addrs_encoder; - u16 video_vfe, video_codec; /* videocodec types */ - u16 audio_chip; /* audio type */ - - int inputs; /* number of video inputs */ - struct input { - int muxsel; - char name[32]; - } input[BUZ_MAX_INPUT]; - - v4l2_std_id norms; - struct tvnorm *tvn[3]; /* supported TV norms */ - - u32 jpeg_int; /* JPEG interrupt */ - u32 vsync_int; /* VSYNC interrupt */ - s8 gpio[ZR_GPIO_MAX]; - u8 gpcs[GPCS_MAX]; - - struct vfe_polarity vfe_pol; - u8 gpio_pol[ZR_GPIO_MAX]; - - /* is the /GWS line connected? */ - u8 gws_not_connected; - - /* avs6eyes mux setting */ - u8 input_mux; - - void (*init) (struct zoran * zr); -}; - -struct zoran { - struct v4l2_device v4l2_dev; - struct v4l2_ctrl_handler hdl; - struct video_device *video_dev; - - struct i2c_adapter i2c_adapter; /* */ - struct i2c_algo_bit_data i2c_algo; /* */ - u32 i2cbr; - - struct v4l2_subdev *decoder; /* video decoder sub-device */ - struct v4l2_subdev *encoder; /* video encoder sub-device */ - - struct videocodec *codec; /* video codec */ - struct videocodec *vfe; /* video front end */ - - struct mutex lock; /* file ops serialize lock */ - - u8 initialized; /* flag if zoran has been correctly initialized */ - int user; /* number of current users */ - struct card_info card; - struct tvnorm *timing; - - unsigned short id; /* number of this device */ - char name[32]; /* name of this device */ - struct pci_dev *pci_dev; /* PCI device */ - unsigned char revision; /* revision of zr36057 */ - unsigned char __iomem *zr36057_mem;/* pointer to mapped IO memory */ - - spinlock_t spinlock; /* Spinlock */ - - /* Video for Linux parameters */ - int input; /* card's norm and input */ - v4l2_std_id norm; - - /* Current buffer params */ - void *vbuf_base; - int vbuf_height, vbuf_width; - int vbuf_depth; - int vbuf_bytesperline; - - struct zoran_overlay_settings overlay_settings; - u32 *overlay_mask; /* overlay mask */ - enum zoran_lock_activity overlay_active; /* feature currently in use? */ - - wait_queue_head_t v4l_capq; - - int v4l_overlay_active; /* Overlay grab is activated */ - int v4l_memgrab_active; /* Memory grab is activated */ - - int v4l_grab_frame; /* Frame number being currently grabbed */ -#define NO_GRAB_ACTIVE (-1) - unsigned long v4l_grab_seq; /* Number of frames grabbed */ - struct zoran_v4l_settings v4l_settings; /* structure with a lot of things to play with */ - - /* V4L grab queue of frames pending */ - unsigned long v4l_pend_head; - unsigned long v4l_pend_tail; - unsigned long v4l_sync_tail; - int v4l_pend[V4L_MAX_FRAME]; - struct zoran_buffer_col v4l_buffers; /* V4L buffers' info */ - - /* Buz MJPEG parameters */ - enum zoran_codec_mode codec_mode; /* status of codec */ - struct zoran_jpg_settings jpg_settings; /* structure with a lot of things to play with */ - - wait_queue_head_t jpg_capq; /* wait here for grab to finish */ - - /* grab queue counts/indices, mask with BUZ_MASK_STAT_COM before using as index */ - /* (dma_head - dma_tail) is number active in DMA, must be <= BUZ_NUM_STAT_COM */ - /* (value & BUZ_MASK_STAT_COM) corresponds to index in stat_com table */ - unsigned long jpg_que_head; /* Index where to put next buffer which is queued */ - unsigned long jpg_dma_head; /* Index of next buffer which goes into stat_com */ - unsigned long jpg_dma_tail; /* Index of last buffer in stat_com */ - unsigned long jpg_que_tail; /* Index of last buffer in queue */ - unsigned long jpg_seq_num; /* count of frames since grab/play started */ - unsigned long jpg_err_seq; /* last seq_num before error */ - unsigned long jpg_err_shift; - unsigned long jpg_queued_num; /* count of frames queued since grab/play started */ - - /* zr36057's code buffer table */ - __le32 *stat_com; /* stat_com[i] is indexed by dma_head/tail & BUZ_MASK_STAT_COM */ - - /* (value & BUZ_MASK_FRAME) corresponds to index in pend[] queue */ - int jpg_pend[BUZ_MAX_FRAME]; - - /* array indexed by frame number */ - struct zoran_buffer_col jpg_buffers; /* MJPEG buffers' info */ - - /* Additional stuff for testing */ -#ifdef CONFIG_PROC_FS - struct proc_dir_entry *zoran_proc; -#else - void *zoran_proc; -#endif - int testing; - int jpeg_error; - int intr_counter_GIRQ1; - int intr_counter_GIRQ0; - int intr_counter_CodRepIRQ; - int intr_counter_JPEGRepIRQ; - int field_counter; - int IRQ1_in; - int IRQ1_out; - int JPEG_in; - int JPEG_out; - int JPEG_0; - int JPEG_1; - int END_event_missed; - int JPEG_missed; - int JPEG_error; - int num_errors; - int JPEG_max_missed; - int JPEG_min_missed; - - u32 last_isr; - unsigned long frame_num; - - wait_queue_head_t test_q; -}; - -static inline struct zoran *to_zoran(struct v4l2_device *v4l2_dev) -{ - return container_of(v4l2_dev, struct zoran, v4l2_dev); -} - -/* There was something called _ALPHA_BUZ that used the PCI address instead of - * the kernel iomapped address for btread/btwrite. */ -#define btwrite(dat,adr) writel((dat), zr->zr36057_mem+(adr)) -#define btread(adr) readl(zr->zr36057_mem+(adr)) - -#define btand(dat,adr) btwrite((dat) & btread(adr), adr) -#define btor(dat,adr) btwrite((dat) | btread(adr), adr) -#define btaor(dat,mask,adr) btwrite((dat) | ((mask) & btread(adr)), adr) - -#endif diff --git a/drivers/staging/media/zoran/zoran_card.c b/drivers/staging/media/zoran/zoran_card.c deleted file mode 100644 index 1d8cd7946bd8..000000000000 --- a/drivers/staging/media/zoran/zoran_card.c +++ /dev/null @@ -1,1511 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Zoran zr36057/zr36067 PCI controller driver, for the - * Pinnacle/Miro DC10/DC10+/DC30/DC30+, Iomega Buz, Linux - * Media Labs LML33/LML33R10. - * - * This part handles card-specific data and detection - * - * Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx> - * - * Currently maintained by: - * Ronald Bultje <rbultje@ronald.bitfreak.net> - * Laurent Pinchart <laurent.pinchart@skynet.be> - * Mailinglist <mjpeg-users@lists.sf.net> - */ -#include <linux/delay.h> - -#include <linux/types.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/init.h> -#include <linux/vmalloc.h> -#include <linux/slab.h> - -#include <linux/proc_fs.h> -#include <linux/i2c.h> -#include <linux/i2c-algo-bit.h> -#include <linux/videodev2.h> -#include <linux/spinlock.h> -#include <linux/sem.h> -#include <linux/kmod.h> -#include <linux/wait.h> - -#include <linux/pci.h> -#include <linux/interrupt.h> -#include <linux/mutex.h> -#include <linux/io.h> -#include <media/v4l2-common.h> -#include <media/i2c/bt819.h> - -#include "videocodec.h" -#include "zoran.h" -#include "zoran_card.h" -#include "zoran_device.h" -#include "zoran_procfs.h" - -extern const struct zoran_format zoran_formats[]; - -static int card[BUZ_MAX] = { [0 ... (BUZ_MAX-1)] = -1 }; -module_param_array(card, int, NULL, 0444); -MODULE_PARM_DESC(card, "Card type"); - -/* - The video mem address of the video card. - The driver has a little database for some videocards - to determine it from there. If your video card is not in there - you have either to give it to the driver as a parameter - or set in in a VIDIOCSFBUF ioctl - */ - -static unsigned long vidmem; /* default = 0 - Video memory base address */ -module_param_hw(vidmem, ulong, iomem, 0444); -MODULE_PARM_DESC(vidmem, "Default video memory base address"); - -/* - Default input and video norm at startup of the driver. -*/ - -static unsigned int default_input; /* default 0 = Composite, 1 = S-Video */ -module_param(default_input, uint, 0444); -MODULE_PARM_DESC(default_input, - "Default input (0=Composite, 1=S-Video, 2=Internal)"); - -static int default_mux = 1; /* 6 Eyes input selection */ -module_param(default_mux, int, 0644); -MODULE_PARM_DESC(default_mux, - "Default 6 Eyes mux setting (Input selection)"); - -static int default_norm; /* default 0 = PAL, 1 = NTSC 2 = SECAM */ -module_param(default_norm, int, 0444); -MODULE_PARM_DESC(default_norm, "Default norm (0=PAL, 1=NTSC, 2=SECAM)"); - -/* /dev/videoN, -1 for autodetect */ -static int video_nr[BUZ_MAX] = { [0 ... (BUZ_MAX-1)] = -1 }; -module_param_array(video_nr, int, NULL, 0444); -MODULE_PARM_DESC(video_nr, "Video device number (-1=Auto)"); - -int v4l_nbufs = 4; -int v4l_bufsize = 864; /* Everybody should be able to work with this setting */ -module_param(v4l_nbufs, int, 0644); -MODULE_PARM_DESC(v4l_nbufs, "Maximum number of V4L buffers to use"); -module_param(v4l_bufsize, int, 0644); -MODULE_PARM_DESC(v4l_bufsize, "Maximum size per V4L buffer (in kB)"); - -int jpg_nbufs = 32; -int jpg_bufsize = 512; /* max size for 100% quality full-PAL frame */ -module_param(jpg_nbufs, int, 0644); -MODULE_PARM_DESC(jpg_nbufs, "Maximum number of JPG buffers to use"); -module_param(jpg_bufsize, int, 0644); -MODULE_PARM_DESC(jpg_bufsize, "Maximum size per JPG buffer (in kB)"); - -int pass_through = 0; /* 1=Pass through TV signal when device is not used */ - /* 0=Show color bar when device is not used (LML33: only if lml33dpath=1) */ -module_param(pass_through, int, 0644); -MODULE_PARM_DESC(pass_through, - "Pass TV signal through to TV-out when idling"); - -int zr36067_debug = 1; -module_param_named(debug, zr36067_debug, int, 0644); -MODULE_PARM_DESC(debug, "Debug level (0-5)"); - -#define ZORAN_VERSION "0.10.1" - -MODULE_DESCRIPTION("Zoran-36057/36067 JPEG codec driver"); -MODULE_AUTHOR("Serguei Miridonov"); -MODULE_LICENSE("GPL"); -MODULE_VERSION(ZORAN_VERSION); - -#define ZR_DEVICE(subven, subdev, data) { \ - .vendor = PCI_VENDOR_ID_ZORAN, .device = PCI_DEVICE_ID_ZORAN_36057, \ - .subvendor = (subven), .subdevice = (subdev), .driver_data = (data) } - -static const struct pci_device_id zr36067_pci_tbl[] = { - ZR_DEVICE(PCI_VENDOR_ID_MIRO, PCI_DEVICE_ID_MIRO_DC10PLUS, DC10plus), - ZR_DEVICE(PCI_VENDOR_ID_MIRO, PCI_DEVICE_ID_MIRO_DC30PLUS, DC30plus), - ZR_DEVICE(PCI_VENDOR_ID_ELECTRONICDESIGNGMBH, PCI_DEVICE_ID_LML_33R10, LML33R10), - ZR_DEVICE(PCI_VENDOR_ID_IOMEGA, PCI_DEVICE_ID_IOMEGA_BUZ, BUZ), - ZR_DEVICE(PCI_ANY_ID, PCI_ANY_ID, NUM_CARDS), - {0} -}; -MODULE_DEVICE_TABLE(pci, zr36067_pci_tbl); - -static unsigned int zoran_num; /* number of cards found */ - -/* videocodec bus functions ZR36060 */ -static u32 -zr36060_read (struct videocodec *codec, - u16 reg) -{ - struct zoran *zr = (struct zoran *) codec->master_data->data; - __u32 data; - - if (post_office_wait(zr) - || post_office_write(zr, 0, 1, reg >> 8) - || post_office_write(zr, 0, 2, reg & 0xff)) { - return -1; - } - - data = post_office_read(zr, 0, 3) & 0xff; - return data; -} - -static void -zr36060_write (struct videocodec *codec, - u16 reg, - u32 val) -{ - struct zoran *zr = (struct zoran *) codec->master_data->data; - - if (post_office_wait(zr) - || post_office_write(zr, 0, 1, reg >> 8) - || post_office_write(zr, 0, 2, reg & 0xff)) { - return; - } - - post_office_write(zr, 0, 3, val & 0xff); -} - -/* videocodec bus functions ZR36050 */ -static u32 -zr36050_read (struct videocodec *codec, - u16 reg) -{ - struct zoran *zr = (struct zoran *) codec->master_data->data; - __u32 data; - - if (post_office_wait(zr) - || post_office_write(zr, 1, 0, reg >> 2)) { // reg. HIGHBYTES - return -1; - } - - data = post_office_read(zr, 0, reg & 0x03) & 0xff; // reg. LOWBYTES + read - return data; -} - -static void -zr36050_write (struct videocodec *codec, - u16 reg, - u32 val) -{ - struct zoran *zr = (struct zoran *) codec->master_data->data; - - if (post_office_wait(zr) - || post_office_write(zr, 1, 0, reg >> 2)) { // reg. HIGHBYTES - return; - } - - post_office_write(zr, 0, reg & 0x03, val & 0xff); // reg. LOWBYTES + wr. data -} - -/* videocodec bus functions ZR36016 */ -static u32 -zr36016_read (struct videocodec *codec, - u16 reg) -{ - struct zoran *zr = (struct zoran *) codec->master_data->data; - __u32 data; - - if (post_office_wait(zr)) { - return -1; - } - - data = post_office_read(zr, 2, reg & 0x03) & 0xff; // read - return data; -} - -/* hack for in zoran_device.c */ -void -zr36016_write (struct videocodec *codec, - u16 reg, - u32 val) -{ - struct zoran *zr = (struct zoran *) codec->master_data->data; - - if (post_office_wait(zr)) { - return; - } - - post_office_write(zr, 2, reg & 0x03, val & 0x0ff); // wr. data -} - -/* - * Board specific information - */ - -static void -dc10_init (struct zoran *zr) -{ - dprintk(3, KERN_DEBUG "%s: %s\n", ZR_DEVNAME(zr), __func__); - - /* Pixel clock selection */ - GPIO(zr, 4, 0); - GPIO(zr, 5, 1); - /* Enable the video bus sync signals */ - GPIO(zr, 7, 0); -} - -static void -dc10plus_init (struct zoran *zr) -{ - dprintk(3, KERN_DEBUG "%s: %s\n", ZR_DEVNAME(zr), __func__); -} - -static void -buz_init (struct zoran *zr) -{ - dprintk(3, KERN_DEBUG "%s: %s\n", ZR_DEVNAME(zr), __func__); - - /* some stuff from Iomega */ - pci_write_config_dword(zr->pci_dev, 0xfc, 0x90680f15); - pci_write_config_dword(zr->pci_dev, 0x0c, 0x00012020); - pci_write_config_dword(zr->pci_dev, 0xe8, 0xc0200000); -} - -static void -lml33_init (struct zoran *zr) -{ - dprintk(3, KERN_DEBUG "%s: %s\n", ZR_DEVNAME(zr), __func__); - - GPIO(zr, 2, 1); // Set Composite input/output -} - -static void -avs6eyes_init (struct zoran *zr) -{ - // AverMedia 6-Eyes original driver by Christer Weinigel - - // Lifted straight from Christer's old driver and - // modified slightly by Martin Samuelsson. - - int mux = default_mux; /* 1 = BT866, 7 = VID1 */ - - GPIO(zr, 4, 1); /* Bt866 SLEEP on */ - udelay(2); - - GPIO(zr, 0, 1); /* ZR36060 /RESET on */ - GPIO(zr, 1, 0); /* ZR36060 /SLEEP on */ - GPIO(zr, 2, mux & 1); /* MUX S0 */ - GPIO(zr, 3, 0); /* /FRAME on */ - GPIO(zr, 4, 0); /* Bt866 SLEEP off */ - GPIO(zr, 5, mux & 2); /* MUX S1 */ - GPIO(zr, 6, 0); /* ? */ - GPIO(zr, 7, mux & 4); /* MUX S2 */ - -} - -static char * -codecid_to_modulename (u16 codecid) -{ - char *name = NULL; - - switch (codecid) { - case CODEC_TYPE_ZR36060: - name = "zr36060"; - break; - case CODEC_TYPE_ZR36050: - name = "zr36050"; - break; - case CODEC_TYPE_ZR36016: - name = "zr36016"; - break; - } - - return name; -} - -// struct tvnorm { -// u16 Wt, Wa, HStart, HSyncStart, Ht, Ha, VStart; -// }; - -static struct tvnorm f50sqpixel = { 944, 768, 83, 880, 625, 576, 16 }; -static struct tvnorm f60sqpixel = { 780, 640, 51, 716, 525, 480, 12 }; -static struct tvnorm f50ccir601 = { 864, 720, 75, 804, 625, 576, 18 }; -static struct tvnorm f60ccir601 = { 858, 720, 57, 788, 525, 480, 16 }; - -static struct tvnorm f50ccir601_lml33 = { 864, 720, 75+34, 804, 625, 576, 18 }; -static struct tvnorm f60ccir601_lml33 = { 858, 720, 57+34, 788, 525, 480, 16 }; - -/* The DC10 (57/16/50) uses VActive as HSync, so HStart must be 0 */ -static struct tvnorm f50sqpixel_dc10 = { 944, 768, 0, 880, 625, 576, 0 }; -static struct tvnorm f60sqpixel_dc10 = { 780, 640, 0, 716, 525, 480, 12 }; - -/* FIXME: I cannot swap U and V in saa7114, so i do one - * pixel left shift in zoran (75 -> 74) - * (Maxim Yevtyushkin <max@linuxmedialabs.com>) */ -static struct tvnorm f50ccir601_lm33r10 = { 864, 720, 74+54, 804, 625, 576, 18 }; -static struct tvnorm f60ccir601_lm33r10 = { 858, 720, 56+54, 788, 525, 480, 16 }; - -/* FIXME: The ks0127 seem incapable of swapping U and V, too, which is why I - * copy Maxim's left shift hack for the 6 Eyes. - * - * Christer's driver used the unshifted norms, though... - * /Sam */ -static struct tvnorm f50ccir601_avs6eyes = { 864, 720, 74, 804, 625, 576, 18 }; -static struct tvnorm f60ccir601_avs6eyes = { 858, 720, 56, 788, 525, 480, 16 }; - -static const unsigned short vpx3220_addrs[] = { 0x43, 0x47, I2C_CLIENT_END }; -static const unsigned short saa7110_addrs[] = { 0x4e, 0x4f, I2C_CLIENT_END }; -static const unsigned short saa7111_addrs[] = { 0x25, 0x24, I2C_CLIENT_END }; -static const unsigned short saa7114_addrs[] = { 0x21, 0x20, I2C_CLIENT_END }; -static const unsigned short adv717x_addrs[] = { 0x6a, 0x6b, 0x2a, 0x2b, I2C_CLIENT_END }; -static const unsigned short ks0127_addrs[] = { 0x6c, 0x6d, I2C_CLIENT_END }; -static const unsigned short saa7185_addrs[] = { 0x44, I2C_CLIENT_END }; -static const unsigned short bt819_addrs[] = { 0x45, I2C_CLIENT_END }; -static const unsigned short bt856_addrs[] = { 0x44, I2C_CLIENT_END }; -static const unsigned short bt866_addrs[] = { 0x44, I2C_CLIENT_END }; - -static struct card_info zoran_cards[NUM_CARDS] = { - { - .type = DC10_old, - .name = "DC10(old)", - .i2c_decoder = "vpx3220a", - .addrs_decoder = vpx3220_addrs, - .video_codec = CODEC_TYPE_ZR36050, - .video_vfe = CODEC_TYPE_ZR36016, - - .inputs = 3, - .input = { - { 1, "Composite" }, - { 2, "S-Video" }, - { 0, "Internal/comp" } - }, - .norms = V4L2_STD_NTSC|V4L2_STD_PAL|V4L2_STD_SECAM, - .tvn = { - &f50sqpixel_dc10, - &f60sqpixel_dc10, - &f50sqpixel_dc10 - }, - .jpeg_int = 0, - .vsync_int = ZR36057_ISR_GIRQ1, - .gpio = { 2, 1, -1, 3, 7, 0, 4, 5 }, - .gpio_pol = { 0, 0, 0, 1, 0, 0, 0, 0 }, - .gpcs = { -1, 0 }, - .vfe_pol = { 0, 0, 0, 0, 0, 0, 0, 0 }, - .gws_not_connected = 0, - .input_mux = 0, - .init = &dc10_init, - }, { - .type = DC10_new, - .name = "DC10(new)", - .i2c_decoder = "saa7110", - .addrs_decoder = saa7110_addrs, - .i2c_encoder = "adv7175", - .addrs_encoder = adv717x_addrs, - .video_codec = CODEC_TYPE_ZR36060, - - .inputs = 3, - .input = { - { 0, "Composite" }, - { 7, "S-Video" }, - { 5, "Internal/comp" } - }, - .norms = V4L2_STD_NTSC|V4L2_STD_PAL|V4L2_STD_SECAM, - .tvn = { - &f50sqpixel, - &f60sqpixel, - &f50sqpixel}, - .jpeg_int = ZR36057_ISR_GIRQ0, - .vsync_int = ZR36057_ISR_GIRQ1, - .gpio = { 3, 0, 6, 1, 2, -1, 4, 5 }, - .gpio_pol = { 0, 0, 0, 0, 0, 0, 0, 0 }, - .gpcs = { -1, 1}, - .vfe_pol = { 1, 1, 1, 1, 0, 0, 0, 0 }, - .gws_not_connected = 0, - .input_mux = 0, - .init = &dc10plus_init, - }, { - .type = DC10plus, - .name = "DC10plus", - .i2c_decoder = "saa7110", - .addrs_decoder = saa7110_addrs, - .i2c_encoder = "adv7175", - .addrs_encoder = adv717x_addrs, - .video_codec = CODEC_TYPE_ZR36060, - - .inputs = 3, - .input = { - { 0, "Composite" }, - { 7, "S-Video" }, - { 5, "Internal/comp" } - }, - .norms = V4L2_STD_NTSC|V4L2_STD_PAL|V4L2_STD_SECAM, - .tvn = { - &f50sqpixel, - &f60sqpixel, - &f50sqpixel - }, - .jpeg_int = ZR36057_ISR_GIRQ0, - .vsync_int = ZR36057_ISR_GIRQ1, - .gpio = { 3, 0, 6, 1, 2, -1, 4, 5 }, - .gpio_pol = { 0, 0, 0, 0, 0, 0, 0, 0 }, - .gpcs = { -1, 1 }, - .vfe_pol = { 1, 1, 1, 1, 0, 0, 0, 0 }, - .gws_not_connected = 0, - .input_mux = 0, - .init = &dc10plus_init, - }, { - .type = DC30, - .name = "DC30", - .i2c_decoder = "vpx3220a", - .addrs_decoder = vpx3220_addrs, - .i2c_encoder = "adv7175", - .addrs_encoder = adv717x_addrs, - .video_codec = CODEC_TYPE_ZR36050, - .video_vfe = CODEC_TYPE_ZR36016, - - .inputs = 3, - .input = { - { 1, "Composite" }, - { 2, "S-Video" }, - { 0, "Internal/comp" } - }, - .norms = V4L2_STD_NTSC|V4L2_STD_PAL|V4L2_STD_SECAM, - .tvn = { - &f50sqpixel_dc10, - &f60sqpixel_dc10, - &f50sqpixel_dc10 - }, - .jpeg_int = 0, - .vsync_int = ZR36057_ISR_GIRQ1, - .gpio = { 2, 1, -1, 3, 7, 0, 4, 5 }, - .gpio_pol = { 0, 0, 0, 1, 0, 0, 0, 0 }, - .gpcs = { -1, 0 }, - .vfe_pol = { 0, 0, 0, 0, 0, 0, 0, 0 }, - .gws_not_connected = 0, - .input_mux = 0, - .init = &dc10_init, - }, { - .type = DC30plus, - .name = "DC30plus", - .i2c_decoder = "vpx3220a", - .addrs_decoder = vpx3220_addrs, - .i2c_encoder = "adv7175", - .addrs_encoder = adv717x_addrs, - .video_codec = CODEC_TYPE_ZR36050, - .video_vfe = CODEC_TYPE_ZR36016, - - .inputs = 3, - .input = { - { 1, "Composite" }, - { 2, "S-Video" }, - { 0, "Internal/comp" } - }, - .norms = V4L2_STD_NTSC|V4L2_STD_PAL|V4L2_STD_SECAM, - .tvn = { - &f50sqpixel_dc10, - &f60sqpixel_dc10, - &f50sqpixel_dc10 - }, - .jpeg_int = 0, - .vsync_int = ZR36057_ISR_GIRQ1, - .gpio = { 2, 1, -1, 3, 7, 0, 4, 5 }, - .gpio_pol = { 0, 0, 0, 1, 0, 0, 0, 0 }, - .gpcs = { -1, 0 }, - .vfe_pol = { 0, 0, 0, 0, 0, 0, 0, 0 }, - .gws_not_connected = 0, - .input_mux = 0, - .init = &dc10_init, - }, { - .type = LML33, - .name = "LML33", - .i2c_decoder = "bt819a", - .addrs_decoder = bt819_addrs, - .i2c_encoder = "bt856", - .addrs_encoder = bt856_addrs, - .video_codec = CODEC_TYPE_ZR36060, - - .inputs = 2, - .input = { - { 0, "Composite" }, - { 7, "S-Video" } - }, - .norms = V4L2_STD_NTSC|V4L2_STD_PAL, - .tvn = { - &f50ccir601_lml33, - &f60ccir601_lml33, - NULL - }, - .jpeg_int = ZR36057_ISR_GIRQ1, - .vsync_int = ZR36057_ISR_GIRQ0, - .gpio = { 1, -1, 3, 5, 7, -1, -1, -1 }, - .gpio_pol = { 0, 0, 0, 0, 1, 0, 0, 0 }, - .gpcs = { 3, 1 }, - .vfe_pol = { 1, 1, 0, 0, 0, 1, 0, 0 }, - .gws_not_connected = 1, - .input_mux = 0, - .init = &lml33_init, - }, { - .type = LML33R10, - .name = "LML33R10", - .i2c_decoder = "saa7114", - .addrs_decoder = saa7114_addrs, - .i2c_encoder = "adv7170", - .addrs_encoder = adv717x_addrs, - .video_codec = CODEC_TYPE_ZR36060, - - .inputs = 2, - .input = { - { 0, "Composite" }, - { 7, "S-Video" } - }, - .norms = V4L2_STD_NTSC|V4L2_STD_PAL, - .tvn = { - &f50ccir601_lm33r10, - &f60ccir601_lm33r10, - NULL - }, - .jpeg_int = ZR36057_ISR_GIRQ1, - .vsync_int = ZR36057_ISR_GIRQ0, - .gpio = { 1, -1, 3, 5, 7, -1, -1, -1 }, - .gpio_pol = { 0, 0, 0, 0, 1, 0, 0, 0 }, - .gpcs = { 3, 1 }, - .vfe_pol = { 1, 1, 0, 0, 0, 1, 0, 0 }, - .gws_not_connected = 1, - .input_mux = 0, - .init = &lml33_init, - }, { - .type = BUZ, - .name = "Buz", - .i2c_decoder = "saa7111", - .addrs_decoder = saa7111_addrs, - .i2c_encoder = "saa7185", - .addrs_encoder = saa7185_addrs, - .video_codec = CODEC_TYPE_ZR36060, - - .inputs = 2, - .input = { - { 3, "Composite" }, - { 7, "S-Video" } - }, - .norms = V4L2_STD_NTSC|V4L2_STD_PAL|V4L2_STD_SECAM, - .tvn = { - &f50ccir601, - &f60ccir601, - &f50ccir601 - }, - .jpeg_int = ZR36057_ISR_GIRQ1, - .vsync_int = ZR36057_ISR_GIRQ0, - .gpio = { 1, -1, 3, -1, -1, -1, -1, -1 }, - .gpio_pol = { 0, 0, 0, 0, 0, 0, 0, 0 }, - .gpcs = { 3, 1 }, - .vfe_pol = { 1, 1, 0, 0, 0, 1, 0, 0 }, - .gws_not_connected = 1, - .input_mux = 0, - .init = &buz_init, - }, { - .type = AVS6EYES, - .name = "6-Eyes", - /* AverMedia chose not to brand the 6-Eyes. Thus it - can't be autodetected, and requires card=x. */ - .i2c_decoder = "ks0127", - .addrs_decoder = ks0127_addrs, - .i2c_encoder = "bt866", - .addrs_encoder = bt866_addrs, - .video_codec = CODEC_TYPE_ZR36060, - - .inputs = 10, - .input = { - { 0, "Composite 1" }, - { 1, "Composite 2" }, - { 2, "Composite 3" }, - { 4, "Composite 4" }, - { 5, "Composite 5" }, - { 6, "Composite 6" }, - { 8, "S-Video 1" }, - { 9, "S-Video 2" }, - {10, "S-Video 3" }, - {15, "YCbCr" } - }, - .norms = V4L2_STD_NTSC|V4L2_STD_PAL, - .tvn = { - &f50ccir601_avs6eyes, - &f60ccir601_avs6eyes, - NULL - }, - .jpeg_int = ZR36057_ISR_GIRQ1, - .vsync_int = ZR36057_ISR_GIRQ0, - .gpio = { 1, 0, 3, -1, -1, -1, -1, -1 },// Validity unknown /Sam - .gpio_pol = { 0, 0, 0, 0, 0, 0, 0, 0 }, // Validity unknown /Sam - .gpcs = { 3, 1 }, // Validity unknown /Sam - .vfe_pol = { 1, 0, 0, 0, 0, 1, 0, 0 }, // Validity unknown /Sam - .gws_not_connected = 1, - .input_mux = 1, - .init = &avs6eyes_init, - } - -}; - -/* - * I2C functions - */ -/* software I2C functions */ -static int -zoran_i2c_getsda (void *data) -{ - struct zoran *zr = (struct zoran *) data; - - return (btread(ZR36057_I2CBR) >> 1) & 1; -} - -static int -zoran_i2c_getscl (void *data) -{ - struct zoran *zr = (struct zoran *) data; - - return btread(ZR36057_I2CBR) & 1; -} - -static void -zoran_i2c_setsda (void *data, - int state) -{ - struct zoran *zr = (struct zoran *) data; - - if (state) - zr->i2cbr |= 2; - else - zr->i2cbr &= ~2; - btwrite(zr->i2cbr, ZR36057_I2CBR); -} - -static void -zoran_i2c_setscl (void *data, - int state) -{ - struct zoran *zr = (struct zoran *) data; - - if (state) - zr->i2cbr |= 1; - else - zr->i2cbr &= ~1; - btwrite(zr->i2cbr, ZR36057_I2CBR); -} - -static const struct i2c_algo_bit_data zoran_i2c_bit_data_template = { - .setsda = zoran_i2c_setsda, - .setscl = zoran_i2c_setscl, - .getsda = zoran_i2c_getsda, - .getscl = zoran_i2c_getscl, - .udelay = 10, - .timeout = 100, -}; - -static int -zoran_register_i2c (struct zoran *zr) -{ - zr->i2c_algo = zoran_i2c_bit_data_template; - zr->i2c_algo.data = zr; - strscpy(zr->i2c_adapter.name, ZR_DEVNAME(zr), - sizeof(zr->i2c_adapter.name)); - i2c_set_adapdata(&zr->i2c_adapter, &zr->v4l2_dev); - zr->i2c_adapter.algo_data = &zr->i2c_algo; - zr->i2c_adapter.dev.parent = &zr->pci_dev->dev; - return i2c_bit_add_bus(&zr->i2c_adapter); -} - -static void -zoran_unregister_i2c (struct zoran *zr) -{ - i2c_del_adapter(&zr->i2c_adapter); -} - -/* Check a zoran_params struct for correctness, insert default params */ - -int -zoran_check_jpg_settings (struct zoran *zr, - struct zoran_jpg_settings *settings, - int try) -{ - int err = 0, err0 = 0; - - dprintk(4, - KERN_DEBUG - "%s: %s - dec: %d, Hdcm: %d, Vdcm: %d, Tdcm: %d\n", - ZR_DEVNAME(zr), __func__, settings->decimation, settings->HorDcm, - settings->VerDcm, settings->TmpDcm); - dprintk(4, - KERN_DEBUG - "%s: %s - x: %d, y: %d, w: %d, y: %d\n", - ZR_DEVNAME(zr), __func__, settings->img_x, settings->img_y, - settings->img_width, settings->img_height); - /* Check decimation, set default values for decimation = 1, 2, 4 */ - switch (settings->decimation) { - case 1: - - settings->HorDcm = 1; - settings->VerDcm = 1; - settings->TmpDcm = 1; - settings->field_per_buff = 2; - settings->img_x = 0; - settings->img_y = 0; - settings->img_width = BUZ_MAX_WIDTH; - settings->img_height = BUZ_MAX_HEIGHT / 2; - break; - case 2: - - settings->HorDcm = 2; - settings->VerDcm = 1; - settings->TmpDcm = 2; - settings->field_per_buff = 1; - settings->img_x = (BUZ_MAX_WIDTH == 720) ? 8 : 0; - settings->img_y = 0; - settings->img_width = - (BUZ_MAX_WIDTH == 720) ? 704 : BUZ_MAX_WIDTH; - settings->img_height = BUZ_MAX_HEIGHT / 2; - break; - case 4: - - if (zr->card.type == DC10_new) { - dprintk(1, - KERN_DEBUG - "%s: %s - HDec by 4 is not supported on the DC10\n", - ZR_DEVNAME(zr), __func__); - err0++; - break; - } - - settings->HorDcm = 4; - settings->VerDcm = 2; - settings->TmpDcm = 2; - settings->field_per_buff = 1; - settings->img_x = (BUZ_MAX_WIDTH == 720) ? 8 : 0; - settings->img_y = 0; - settings->img_width = - (BUZ_MAX_WIDTH == 720) ? 704 : BUZ_MAX_WIDTH; - settings->img_height = BUZ_MAX_HEIGHT / 2; - break; - case 0: - - /* We have to check the data the user has set */ - - if (settings->HorDcm != 1 && settings->HorDcm != 2 && - (zr->card.type == DC10_new || settings->HorDcm != 4)) { - settings->HorDcm = clamp(settings->HorDcm, 1, 2); - err0++; - } - if (settings->VerDcm != 1 && settings->VerDcm != 2) { - settings->VerDcm = clamp(settings->VerDcm, 1, 2); - err0++; - } - if (settings->TmpDcm != 1 && settings->TmpDcm != 2) { - settings->TmpDcm = clamp(settings->TmpDcm, 1, 2); - err0++; - } - if (settings->field_per_buff != 1 && - settings->field_per_buff != 2) { - settings->field_per_buff = clamp(settings->field_per_buff, 1, 2); - err0++; - } - if (settings->img_x < 0) { - settings->img_x = 0; - err0++; - } - if (settings->img_y < 0) { - settings->img_y = 0; - err0++; - } - if (settings->img_width < 0 || settings->img_width > BUZ_MAX_WIDTH) { - settings->img_width = clamp(settings->img_width, 0, (int)BUZ_MAX_WIDTH); - err0++; - } - if (settings->img_height < 0 || settings->img_height > BUZ_MAX_HEIGHT / 2) { - settings->img_height = clamp(settings->img_height, 0, BUZ_MAX_HEIGHT / 2); - err0++; - } - if (settings->img_x + settings->img_width > BUZ_MAX_WIDTH) { - settings->img_x = BUZ_MAX_WIDTH - settings->img_width; - err0++; - } - if (settings->img_y + settings->img_height > BUZ_MAX_HEIGHT / 2) { - settings->img_y = BUZ_MAX_HEIGHT / 2 - settings->img_height; - err0++; - } - if (settings->img_width % (16 * settings->HorDcm) != 0) { - settings->img_width -= settings->img_width % (16 * settings->HorDcm); - if (settings->img_width == 0) - settings->img_width = 16 * settings->HorDcm; - err0++; - } - if (settings->img_height % (8 * settings->VerDcm) != 0) { - settings->img_height -= settings->img_height % (8 * settings->VerDcm); - if (settings->img_height == 0) - settings->img_height = 8 * settings->VerDcm; - err0++; - } - - if (!try && err0) { - dprintk(1, - KERN_ERR - "%s: %s - error in params for decimation = 0\n", - ZR_DEVNAME(zr), __func__); - err++; - } - break; - default: - dprintk(1, - KERN_ERR - "%s: %s - decimation = %d, must be 0, 1, 2 or 4\n", - ZR_DEVNAME(zr), __func__, settings->decimation); - err++; - break; - } - - if (settings->jpg_comp.quality > 100) - settings->jpg_comp.quality = 100; - if (settings->jpg_comp.quality < 5) - settings->jpg_comp.quality = 5; - if (settings->jpg_comp.APPn < 0) - settings->jpg_comp.APPn = 0; - if (settings->jpg_comp.APPn > 15) - settings->jpg_comp.APPn = 15; - if (settings->jpg_comp.APP_len < 0) - settings->jpg_comp.APP_len = 0; - if (settings->jpg_comp.APP_len > 60) - settings->jpg_comp.APP_len = 60; - if (settings->jpg_comp.COM_len < 0) - settings->jpg_comp.COM_len = 0; - if (settings->jpg_comp.COM_len > 60) - settings->jpg_comp.COM_len = 60; - if (err) - return -EINVAL; - return 0; -} - -void -zoran_open_init_params (struct zoran *zr) -{ - int i; - - /* User must explicitly set a window */ - zr->overlay_settings.is_set = 0; - zr->overlay_mask = NULL; - zr->overlay_active = ZORAN_FREE; - - zr->v4l_memgrab_active = 0; - zr->v4l_overlay_active = 0; - zr->v4l_grab_frame = NO_GRAB_ACTIVE; - zr->v4l_grab_seq = 0; - zr->v4l_settings.width = 192; - zr->v4l_settings.height = 144; - zr->v4l_settings.format = &zoran_formats[7]; /* YUY2 - YUV-4:2:2 packed */ - zr->v4l_settings.bytesperline = - zr->v4l_settings.width * - ((zr->v4l_settings.format->depth + 7) / 8); - - /* DMA ring stuff for V4L */ - zr->v4l_pend_tail = 0; - zr->v4l_pend_head = 0; - zr->v4l_sync_tail = 0; - zr->v4l_buffers.active = ZORAN_FREE; - for (i = 0; i < VIDEO_MAX_FRAME; i++) { - zr->v4l_buffers.buffer[i].state = BUZ_STATE_USER; /* nothing going on */ - } - zr->v4l_buffers.allocated = 0; - - for (i = 0; i < BUZ_MAX_FRAME; i++) { - zr->jpg_buffers.buffer[i].state = BUZ_STATE_USER; /* nothing going on */ - } - zr->jpg_buffers.active = ZORAN_FREE; - zr->jpg_buffers.allocated = 0; - /* Set necessary params and call zoran_check_jpg_settings to set the defaults */ - zr->jpg_settings.decimation = 1; - zr->jpg_settings.jpg_comp.quality = 50; /* default compression factor 8 */ - if (zr->card.type != BUZ) - zr->jpg_settings.odd_even = 1; - else - zr->jpg_settings.odd_even = 0; - zr->jpg_settings.jpg_comp.APPn = 0; - zr->jpg_settings.jpg_comp.APP_len = 0; /* No APPn marker */ - memset(zr->jpg_settings.jpg_comp.APP_data, 0, - sizeof(zr->jpg_settings.jpg_comp.APP_data)); - zr->jpg_settings.jpg_comp.COM_len = 0; /* No COM marker */ - memset(zr->jpg_settings.jpg_comp.COM_data, 0, - sizeof(zr->jpg_settings.jpg_comp.COM_data)); - zr->jpg_settings.jpg_comp.jpeg_markers = - V4L2_JPEG_MARKER_DHT | V4L2_JPEG_MARKER_DQT; - i = zoran_check_jpg_settings(zr, &zr->jpg_settings, 0); - if (i) - dprintk(1, KERN_ERR "%s: %s internal error\n", - ZR_DEVNAME(zr), __func__); - - clear_interrupt_counters(zr); - zr->testing = 0; -} - -static void test_interrupts (struct zoran *zr) -{ - DEFINE_WAIT(wait); - int timeout, icr; - - clear_interrupt_counters(zr); - - zr->testing = 1; - icr = btread(ZR36057_ICR); - btwrite(0x78000000 | ZR36057_ICR_IntPinEn, ZR36057_ICR); - prepare_to_wait(&zr->test_q, &wait, TASK_INTERRUPTIBLE); - timeout = schedule_timeout(HZ); - finish_wait(&zr->test_q, &wait); - btwrite(0, ZR36057_ICR); - btwrite(0x78000000, ZR36057_ISR); - zr->testing = 0; - dprintk(5, KERN_INFO "%s: Testing interrupts...\n", ZR_DEVNAME(zr)); - if (timeout) { - dprintk(1, ": time spent: %d\n", 1 * HZ - timeout); - } - if (zr36067_debug > 1) - print_interrupts(zr); - btwrite(icr, ZR36057_ICR); -} - -static int zr36057_init (struct zoran *zr) -{ - int j, err; - - dprintk(1, - KERN_INFO - "%s: %s - initializing card[%d], zr=%p\n", - ZR_DEVNAME(zr), __func__, zr->id, zr); - - /* default setup of all parameters which will persist between opens */ - zr->user = 0; - - init_waitqueue_head(&zr->v4l_capq); - init_waitqueue_head(&zr->jpg_capq); - init_waitqueue_head(&zr->test_q); - zr->jpg_buffers.allocated = 0; - zr->v4l_buffers.allocated = 0; - - zr->vbuf_base = (void *) vidmem; - zr->vbuf_width = 0; - zr->vbuf_height = 0; - zr->vbuf_depth = 0; - zr->vbuf_bytesperline = 0; - - /* Avoid nonsense settings from user for default input/norm */ - if (default_norm < 0 || default_norm > 2) - default_norm = 0; - if (default_norm == 0) { - zr->norm = V4L2_STD_PAL; - zr->timing = zr->card.tvn[0]; - } else if (default_norm == 1) { - zr->norm = V4L2_STD_NTSC; - zr->timing = zr->card.tvn[1]; - } else { - zr->norm = V4L2_STD_SECAM; - zr->timing = zr->card.tvn[2]; - } - if (zr->timing == NULL) { - dprintk(1, - KERN_WARNING - "%s: %s - default TV standard not supported by hardware. PAL will be used.\n", - ZR_DEVNAME(zr), __func__); - zr->norm = V4L2_STD_PAL; - zr->timing = zr->card.tvn[0]; - } - - if (default_input > zr->card.inputs-1) { - dprintk(1, - KERN_WARNING - "%s: default_input value %d out of range (0-%d)\n", - ZR_DEVNAME(zr), default_input, zr->card.inputs-1); - default_input = 0; - } - zr->input = default_input; - - /* default setup (will be repeated at every open) */ - zoran_open_init_params(zr); - - /* allocate memory *before* doing anything to the hardware - * in case allocation fails */ - zr->stat_com = kzalloc(BUZ_NUM_STAT_COM * 4, GFP_KERNEL); - zr->video_dev = video_device_alloc(); - if (!zr->stat_com || !zr->video_dev) { - dprintk(1, - KERN_ERR - "%s: %s - kmalloc (STAT_COM) failed\n", - ZR_DEVNAME(zr), __func__); - err = -ENOMEM; - goto exit_free; - } - for (j = 0; j < BUZ_NUM_STAT_COM; j++) { - zr->stat_com[j] = cpu_to_le32(1); /* mark as unavailable to zr36057 */ - } - - /* - * Now add the template and register the device unit. - */ - *zr->video_dev = zoran_template; - zr->video_dev->v4l2_dev = &zr->v4l2_dev; - zr->video_dev->lock = &zr->lock; - strscpy(zr->video_dev->name, ZR_DEVNAME(zr), sizeof(zr->video_dev->name)); - /* It's not a mem2mem device, but you can both capture and output from - one and the same device. This should really be split up into two - device nodes, but that's a job for another day. */ - zr->video_dev->vfl_dir = VFL_DIR_M2M; - err = video_register_device(zr->video_dev, VFL_TYPE_GRABBER, video_nr[zr->id]); - if (err < 0) - goto exit_free; - video_set_drvdata(zr->video_dev, zr); - - zoran_init_hardware(zr); - if (zr36067_debug > 2) - detect_guest_activity(zr); - test_interrupts(zr); - if (!pass_through) { - decoder_call(zr, video, s_stream, 0); - encoder_call(zr, video, s_routing, 2, 0, 0); - } - - zr->zoran_proc = NULL; - zr->initialized = 1; - return 0; - -exit_free: - kfree(zr->stat_com); - kfree(zr->video_dev); - return err; -} - -static void zoran_remove(struct pci_dev *pdev) -{ - struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev); - struct zoran *zr = to_zoran(v4l2_dev); - - if (!zr->initialized) - goto exit_free; - - /* unregister videocodec bus */ - if (zr->codec) { - struct videocodec_master *master = zr->codec->master_data; - - videocodec_detach(zr->codec); - kfree(master); - } - if (zr->vfe) { - struct videocodec_master *master = zr->vfe->master_data; - - videocodec_detach(zr->vfe); - kfree(master); - } - - /* unregister i2c bus */ - zoran_unregister_i2c(zr); - /* disable PCI bus-mastering */ - zoran_set_pci_master(zr, 0); - /* put chip into reset */ - btwrite(0, ZR36057_SPGPPCR); - free_irq(zr->pci_dev->irq, zr); - /* unmap and free memory */ - kfree(zr->stat_com); - zoran_proc_cleanup(zr); - iounmap(zr->zr36057_mem); - pci_disable_device(zr->pci_dev); - video_unregister_device(zr->video_dev); -exit_free: - v4l2_ctrl_handler_free(&zr->hdl); - v4l2_device_unregister(&zr->v4l2_dev); - kfree(zr); -} - -void -zoran_vdev_release (struct video_device *vdev) -{ - kfree(vdev); -} - -static struct videocodec_master *zoran_setup_videocodec(struct zoran *zr, - int type) -{ - struct videocodec_master *m = NULL; - - m = kmalloc(sizeof(struct videocodec_master), GFP_KERNEL); - if (!m) { - return m; - } - - /* magic and type are unused for master struct. Makes sense only at - codec structs. - In the past, .type were initialized to the old V4L1 .hardware - value, as VID_HARDWARE_ZR36067 - */ - m->magic = 0L; - m->type = 0; - - m->flags = CODEC_FLAG_ENCODER | CODEC_FLAG_DECODER; - strscpy(m->name, ZR_DEVNAME(zr), sizeof(m->name)); - m->data = zr; - - switch (type) { - case CODEC_TYPE_ZR36060: - m->readreg = zr36060_read; - m->writereg = zr36060_write; - m->flags |= CODEC_FLAG_JPEG | CODEC_FLAG_VFE; - break; - case CODEC_TYPE_ZR36050: - m->readreg = zr36050_read; - m->writereg = zr36050_write; - m->flags |= CODEC_FLAG_JPEG; - break; - case CODEC_TYPE_ZR36016: - m->readreg = zr36016_read; - m->writereg = zr36016_write; - m->flags |= CODEC_FLAG_VFE; - break; - } - - return m; -} - -static void zoran_subdev_notify(struct v4l2_subdev *sd, unsigned int cmd, void *arg) -{ - struct zoran *zr = to_zoran(sd->v4l2_dev); - - /* Bt819 needs to reset its FIFO buffer using #FRST pin and - LML33 card uses GPIO(7) for that. */ - if (cmd == BT819_FIFO_RESET_LOW) - GPIO(zr, 7, 0); - else if (cmd == BT819_FIFO_RESET_HIGH) - GPIO(zr, 7, 1); -} - -/* - * Scan for a Buz card (actually for the PCI controller ZR36057), - * request the irq and map the io memory - */ -static int zoran_probe(struct pci_dev *pdev, const struct pci_device_id *ent) -{ - unsigned char latency, need_latency; - struct zoran *zr; - int result; - struct videocodec_master *master_vfe = NULL; - struct videocodec_master *master_codec = NULL; - int card_num; - char *codec_name, *vfe_name; - unsigned int nr; - - - nr = zoran_num++; - if (nr >= BUZ_MAX) { - dprintk(1, KERN_ERR "%s: driver limited to %d card(s) maximum\n", - ZORAN_NAME, BUZ_MAX); - return -ENOENT; - } - - zr = kzalloc(sizeof(struct zoran), GFP_KERNEL); - if (!zr) { - dprintk(1, KERN_ERR "%s: %s - kzalloc failed\n", - ZORAN_NAME, __func__); - return -ENOMEM; - } - zr->v4l2_dev.notify = zoran_subdev_notify; - if (v4l2_device_register(&pdev->dev, &zr->v4l2_dev)) - goto zr_free_mem; - zr->pci_dev = pdev; - zr->id = nr; - snprintf(ZR_DEVNAME(zr), sizeof(ZR_DEVNAME(zr)), "MJPEG[%u]", zr->id); - if (v4l2_ctrl_handler_init(&zr->hdl, 10)) - goto zr_unreg; - zr->v4l2_dev.ctrl_handler = &zr->hdl; - spin_lock_init(&zr->spinlock); - mutex_init(&zr->lock); - if (pci_enable_device(pdev)) - goto zr_unreg; - zr->revision = zr->pci_dev->revision; - - dprintk(1, - KERN_INFO - "%s: Zoran ZR360%c7 (rev %d), irq: %d, memory: 0x%08llx\n", - ZR_DEVNAME(zr), zr->revision < 2 ? '5' : '6', zr->revision, - zr->pci_dev->irq, (uint64_t)pci_resource_start(zr->pci_dev, 0)); - if (zr->revision >= 2) { - dprintk(1, - KERN_INFO - "%s: Subsystem vendor=0x%04x id=0x%04x\n", - ZR_DEVNAME(zr), zr->pci_dev->subsystem_vendor, - zr->pci_dev->subsystem_device); - } - - /* Use auto-detected card type? */ - if (card[nr] == -1) { - if (zr->revision < 2) { - dprintk(1, - KERN_ERR - "%s: No card type specified, please use the card=X module parameter\n", - ZR_DEVNAME(zr)); - dprintk(1, - KERN_ERR - "%s: It is not possible to auto-detect ZR36057 based cards\n", - ZR_DEVNAME(zr)); - goto zr_unreg; - } - - card_num = ent->driver_data; - if (card_num >= NUM_CARDS) { - dprintk(1, - KERN_ERR - "%s: Unknown card, try specifying card=X module parameter\n", - ZR_DEVNAME(zr)); - goto zr_unreg; - } - dprintk(3, - KERN_DEBUG - "%s: %s() - card %s detected\n", - ZR_DEVNAME(zr), __func__, zoran_cards[card_num].name); - } else { - card_num = card[nr]; - if (card_num >= NUM_CARDS || card_num < 0) { - dprintk(1, - KERN_ERR - "%s: User specified card type %d out of range (0 .. %d)\n", - ZR_DEVNAME(zr), card_num, NUM_CARDS - 1); - goto zr_unreg; - } - } - - /* even though we make this a non pointer and thus - * theoretically allow for making changes to this struct - * on a per-individual card basis at runtime, this is - * strongly discouraged. This structure is intended to - * keep general card information, no settings or anything */ - zr->card = zoran_cards[card_num]; - snprintf(ZR_DEVNAME(zr), sizeof(ZR_DEVNAME(zr)), - "%s[%u]", zr->card.name, zr->id); - - zr->zr36057_mem = pci_ioremap_bar(zr->pci_dev, 0); - if (!zr->zr36057_mem) { - dprintk(1, KERN_ERR "%s: %s() - ioremap failed\n", - ZR_DEVNAME(zr), __func__); - goto zr_unreg; - } - - result = request_irq(zr->pci_dev->irq, zoran_irq, - IRQF_SHARED, ZR_DEVNAME(zr), zr); - if (result < 0) { - if (result == -EINVAL) { - dprintk(1, - KERN_ERR - "%s: %s - bad irq number or handler\n", - ZR_DEVNAME(zr), __func__); - } else if (result == -EBUSY) { - dprintk(1, - KERN_ERR - "%s: %s - IRQ %d busy, change your PnP config in BIOS\n", - ZR_DEVNAME(zr), __func__, zr->pci_dev->irq); - } else { - dprintk(1, - KERN_ERR - "%s: %s - can't assign irq, error code %d\n", - ZR_DEVNAME(zr), __func__, result); - } - goto zr_unmap; - } - - /* set PCI latency timer */ - pci_read_config_byte(zr->pci_dev, PCI_LATENCY_TIMER, - &latency); - need_latency = zr->revision > 1 ? 32 : 48; - if (latency != need_latency) { - dprintk(2, KERN_INFO "%s: Changing PCI latency from %d to %d\n", - ZR_DEVNAME(zr), latency, need_latency); - pci_write_config_byte(zr->pci_dev, PCI_LATENCY_TIMER, - need_latency); - } - - zr36057_restart(zr); - /* i2c */ - dprintk(2, KERN_INFO "%s: Initializing i2c bus...\n", - ZR_DEVNAME(zr)); - - if (zoran_register_i2c(zr) < 0) { - dprintk(1, KERN_ERR "%s: %s - can't initialize i2c bus\n", - ZR_DEVNAME(zr), __func__); - goto zr_free_irq; - } - - zr->decoder = v4l2_i2c_new_subdev(&zr->v4l2_dev, - &zr->i2c_adapter, zr->card.i2c_decoder, - 0, zr->card.addrs_decoder); - - if (zr->card.i2c_encoder) - zr->encoder = v4l2_i2c_new_subdev(&zr->v4l2_dev, - &zr->i2c_adapter, zr->card.i2c_encoder, - 0, zr->card.addrs_encoder); - - dprintk(2, - KERN_INFO "%s: Initializing videocodec bus...\n", - ZR_DEVNAME(zr)); - - if (zr->card.video_codec) { - codec_name = codecid_to_modulename(zr->card.video_codec); - if (codec_name) { - result = request_module(codec_name); - if (result) { - dprintk(1, - KERN_ERR - "%s: failed to load modules %s: %d\n", - ZR_DEVNAME(zr), codec_name, result); - } - } - } - if (zr->card.video_vfe) { - vfe_name = codecid_to_modulename(zr->card.video_vfe); - if (vfe_name) { - result = request_module(vfe_name); - if (result < 0) { - dprintk(1, - KERN_ERR - "%s: failed to load modules %s: %d\n", - ZR_DEVNAME(zr), vfe_name, result); - } - } - } - - /* reset JPEG codec */ - jpeg_codec_sleep(zr, 1); - jpeg_codec_reset(zr); - /* video bus enabled */ - /* display codec revision */ - if (zr->card.video_codec != 0) { - master_codec = zoran_setup_videocodec(zr, zr->card.video_codec); - if (!master_codec) - goto zr_unreg_i2c; - zr->codec = videocodec_attach(master_codec); - if (!zr->codec) { - dprintk(1, KERN_ERR "%s: %s - no codec found\n", - ZR_DEVNAME(zr), __func__); - goto zr_free_codec; - } - if (zr->codec->type != zr->card.video_codec) { - dprintk(1, KERN_ERR "%s: %s - wrong codec\n", - ZR_DEVNAME(zr), __func__); - goto zr_detach_codec; - } - } - if (zr->card.video_vfe != 0) { - master_vfe = zoran_setup_videocodec(zr, zr->card.video_vfe); - if (!master_vfe) - goto zr_detach_codec; - zr->vfe = videocodec_attach(master_vfe); - if (!zr->vfe) { - dprintk(1, KERN_ERR "%s: %s - no VFE found\n", - ZR_DEVNAME(zr), __func__); - goto zr_free_vfe; - } - if (zr->vfe->type != zr->card.video_vfe) { - dprintk(1, KERN_ERR "%s: %s = wrong VFE\n", - ZR_DEVNAME(zr), __func__); - goto zr_detach_vfe; - } - } - - /* take care of Natoma chipset and a revision 1 zr36057 */ - if ((pci_pci_problems & PCIPCI_NATOMA) && zr->revision <= 1) { - zr->jpg_buffers.need_contiguous = 1; - dprintk(1, KERN_INFO - "%s: ZR36057/Natoma bug, max. buffer size is 128K\n", - ZR_DEVNAME(zr)); - } - - if (zr36057_init(zr) < 0) - goto zr_detach_vfe; - - zoran_proc_init(zr); - - return 0; - -zr_detach_vfe: - videocodec_detach(zr->vfe); -zr_free_vfe: - kfree(master_vfe); -zr_detach_codec: - videocodec_detach(zr->codec); -zr_free_codec: - kfree(master_codec); -zr_unreg_i2c: - zoran_unregister_i2c(zr); -zr_free_irq: - btwrite(0, ZR36057_SPGPPCR); - free_irq(zr->pci_dev->irq, zr); -zr_unmap: - iounmap(zr->zr36057_mem); -zr_unreg: - v4l2_ctrl_handler_free(&zr->hdl); - v4l2_device_unregister(&zr->v4l2_dev); -zr_free_mem: - kfree(zr); - - return -ENODEV; -} - -static struct pci_driver zoran_driver = { - .name = "zr36067", - .id_table = zr36067_pci_tbl, - .probe = zoran_probe, - .remove = zoran_remove, -}; - -static int __init zoran_init(void) -{ - int res; - - printk(KERN_INFO "Zoran MJPEG board driver version %s\n", - ZORAN_VERSION); - - /* check the parameters we have been given, adjust if necessary */ - if (v4l_nbufs < 2) - v4l_nbufs = 2; - if (v4l_nbufs > VIDEO_MAX_FRAME) - v4l_nbufs = VIDEO_MAX_FRAME; - /* The user specifies the in KB, we want them in byte - * (and page aligned) */ - v4l_bufsize = PAGE_ALIGN(v4l_bufsize * 1024); - if (v4l_bufsize < 32768) - v4l_bufsize = 32768; - /* 2 MB is arbitrary but sufficient for the maximum possible images */ - if (v4l_bufsize > 2048 * 1024) - v4l_bufsize = 2048 * 1024; - if (jpg_nbufs < 4) - jpg_nbufs = 4; - if (jpg_nbufs > BUZ_MAX_FRAME) - jpg_nbufs = BUZ_MAX_FRAME; - jpg_bufsize = PAGE_ALIGN(jpg_bufsize * 1024); - if (jpg_bufsize < 8192) - jpg_bufsize = 8192; - if (jpg_bufsize > (512 * 1024)) - jpg_bufsize = 512 * 1024; - /* Use parameter for vidmem or try to find a video card */ - if (vidmem) { - dprintk(1, - KERN_INFO - "%s: Using supplied video memory base address @ 0x%lx\n", - ZORAN_NAME, vidmem); - } - - /* some mainboards might not do PCI-PCI data transfer well */ - if (pci_pci_problems & (PCIPCI_FAIL|PCIAGP_FAIL|PCIPCI_ALIMAGIK)) { - dprintk(1, - KERN_WARNING - "%s: chipset does not support reliable PCI-PCI DMA\n", - ZORAN_NAME); - } - - res = pci_register_driver(&zoran_driver); - if (res) { - dprintk(1, - KERN_ERR - "%s: Unable to register ZR36057 driver\n", - ZORAN_NAME); - return res; - } - - return 0; -} - -static void __exit zoran_exit(void) -{ - pci_unregister_driver(&zoran_driver); -} - -module_init(zoran_init); -module_exit(zoran_exit); diff --git a/drivers/staging/media/zoran/zoran_card.h b/drivers/staging/media/zoran/zoran_card.h deleted file mode 100644 index 600b9a3f320c..000000000000 --- a/drivers/staging/media/zoran/zoran_card.h +++ /dev/null @@ -1,40 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Zoran zr36057/zr36067 PCI controller driver, for the - * Pinnacle/Miro DC10/DC10+/DC30/DC30+, Iomega Buz, Linux - * Media Labs LML33/LML33R10. - * - * This part handles card-specific data and detection - * - * Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx> - * - * Currently maintained by: - * Ronald Bultje <rbultje@ronald.bitfreak.net> - * Laurent Pinchart <laurent.pinchart@skynet.be> - * Mailinglist <mjpeg-users@lists.sf.net> - */ -#ifndef __ZORAN_CARD_H__ -#define __ZORAN_CARD_H__ - -extern int zr36067_debug; - -#define dprintk(num, format, args...) \ - do { \ - if (zr36067_debug >= num) \ - printk(format, ##args); \ - } while (0) - -/* Anybody who uses more than four? */ -#define BUZ_MAX 4 - -extern const struct video_device zoran_template; - -extern int zoran_check_jpg_settings(struct zoran *zr, - struct zoran_jpg_settings *settings, - int try); -extern void zoran_open_init_params(struct zoran *zr); -extern void zoran_vdev_release(struct video_device *vdev); - -void zr36016_write(struct videocodec *codec, u16 reg, u32 val); - -#endif /* __ZORAN_CARD_H__ */ diff --git a/drivers/staging/media/zoran/zoran_device.c b/drivers/staging/media/zoran/zoran_device.c deleted file mode 100644 index 2191fe69b0f9..000000000000 --- a/drivers/staging/media/zoran/zoran_device.c +++ /dev/null @@ -1,1609 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Zoran zr36057/zr36067 PCI controller driver, for the - * Pinnacle/Miro DC10/DC10+/DC30/DC30+, Iomega Buz, Linux - * Media Labs LML33/LML33R10. - * - * This part handles device access (PCI/I2C/codec/...) - * - * Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx> - * - * Currently maintained by: - * Ronald Bultje <rbultje@ronald.bitfreak.net> - * Laurent Pinchart <laurent.pinchart@skynet.be> - * Mailinglist <mjpeg-users@lists.sf.net> - */ -#include <linux/types.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/vmalloc.h> -#include <linux/ktime.h> -#include <linux/sched/signal.h> - -#include <linux/interrupt.h> -#include <linux/proc_fs.h> -#include <linux/i2c.h> -#include <linux/i2c-algo-bit.h> -#include <linux/videodev2.h> -#include <media/v4l2-common.h> -#include <linux/spinlock.h> -#include <linux/sem.h> - -#include <linux/pci.h> -#include <linux/delay.h> -#include <linux/wait.h> - -#include <asm/byteorder.h> -#include <asm/io.h> - -#include "videocodec.h" -#include "zoran.h" -#include "zoran_device.h" -#include "zoran_card.h" - -#define IRQ_MASK ( ZR36057_ISR_GIRQ0 | \ - ZR36057_ISR_GIRQ1 | \ - ZR36057_ISR_JPEGRepIRQ ) - -static bool lml33dpath; /* default = 0 - * 1 will use digital path in capture - * mode instead of analog. It can be - * used for picture adjustments using - * tool like xawtv while watching image - * on TV monitor connected to the output. - * However, due to absence of 75 Ohm - * load on Bt819 input, there will be - * some image imperfections */ - -module_param(lml33dpath, bool, 0644); -MODULE_PARM_DESC(lml33dpath, - "Use digital path capture mode (on LML33 cards)"); - -static void -zr36057_init_vfe (struct zoran *zr); - -/* - * General Purpose I/O and Guest bus access - */ - -/* - * This is a bit tricky. When a board lacks a GPIO function, the corresponding - * GPIO bit number in the card_info structure is set to 0. - */ - -void -GPIO (struct zoran *zr, - int bit, - unsigned int value) -{ - u32 reg; - u32 mask; - - /* Make sure the bit number is legal - * A bit number of -1 (lacking) gives a mask of 0, - * making it harmless */ - mask = (1 << (24 + bit)) & 0xff000000; - reg = btread(ZR36057_GPPGCR1) & ~mask; - if (value) { - reg |= mask; - } - btwrite(reg, ZR36057_GPPGCR1); - udelay(1); -} - -/* - * Wait til post office is no longer busy - */ - -int -post_office_wait (struct zoran *zr) -{ - u32 por; - -// while (((por = btread(ZR36057_POR)) & (ZR36057_POR_POPen | ZR36057_POR_POTime)) == ZR36057_POR_POPen) { - while ((por = btread(ZR36057_POR)) & ZR36057_POR_POPen) { - /* wait for something to happen */ - } - if ((por & ZR36057_POR_POTime) && !zr->card.gws_not_connected) { - /* In LML33/BUZ \GWS line is not connected, so it has always timeout set */ - dprintk(1, KERN_INFO "%s: pop timeout %08x\n", ZR_DEVNAME(zr), - por); - return -1; - } - - return 0; -} - -int -post_office_write (struct zoran *zr, - unsigned int guest, - unsigned int reg, - unsigned int value) -{ - u32 por; - - por = - ZR36057_POR_PODir | ZR36057_POR_POTime | ((guest & 7) << 20) | - ((reg & 7) << 16) | (value & 0xFF); - btwrite(por, ZR36057_POR); - - return post_office_wait(zr); -} - -int -post_office_read (struct zoran *zr, - unsigned int guest, - unsigned int reg) -{ - u32 por; - - por = ZR36057_POR_POTime | ((guest & 7) << 20) | ((reg & 7) << 16); - btwrite(por, ZR36057_POR); - if (post_office_wait(zr) < 0) { - return -1; - } - - return btread(ZR36057_POR) & 0xFF; -} - -/* - * detect guests - */ - -static void -dump_guests (struct zoran *zr) -{ - if (zr36067_debug > 2) { - int i, guest[8]; - - for (i = 1; i < 8; i++) { // Don't read jpeg codec here - guest[i] = post_office_read(zr, i, 0); - } - - printk(KERN_INFO "%s: Guests: %*ph\n", - ZR_DEVNAME(zr), 8, guest); - } -} - -void -detect_guest_activity (struct zoran *zr) -{ - int timeout, i, j, res, guest[8], guest0[8], change[8][3]; - ktime_t t0, t1; - - dump_guests(zr); - printk(KERN_INFO "%s: Detecting guests activity, please wait...\n", - ZR_DEVNAME(zr)); - for (i = 1; i < 8; i++) { // Don't read jpeg codec here - guest0[i] = guest[i] = post_office_read(zr, i, 0); - } - - timeout = 0; - j = 0; - t0 = ktime_get(); - while (timeout < 10000) { - udelay(10); - timeout++; - for (i = 1; (i < 8) && (j < 8); i++) { - res = post_office_read(zr, i, 0); - if (res != guest[i]) { - t1 = ktime_get(); - change[j][0] = ktime_to_us(ktime_sub(t1, t0)); - t0 = t1; - change[j][1] = i; - change[j][2] = res; - j++; - guest[i] = res; - } - } - if (j >= 8) - break; - } - - printk(KERN_INFO "%s: Guests: %*ph\n", ZR_DEVNAME(zr), 8, guest0); - - if (j == 0) { - printk(KERN_INFO "%s: No activity detected.\n", ZR_DEVNAME(zr)); - return; - } - for (i = 0; i < j; i++) { - printk(KERN_INFO "%s: %6d: %d => 0x%02x\n", ZR_DEVNAME(zr), - change[i][0], change[i][1], change[i][2]); - } -} - -/* - * JPEG Codec access - */ - -void -jpeg_codec_sleep (struct zoran *zr, - int sleep) -{ - GPIO(zr, zr->card.gpio[ZR_GPIO_JPEG_SLEEP], !sleep); - if (!sleep) { - dprintk(3, - KERN_DEBUG - "%s: jpeg_codec_sleep() - wake GPIO=0x%08x\n", - ZR_DEVNAME(zr), btread(ZR36057_GPPGCR1)); - udelay(500); - } else { - dprintk(3, - KERN_DEBUG - "%s: jpeg_codec_sleep() - sleep GPIO=0x%08x\n", - ZR_DEVNAME(zr), btread(ZR36057_GPPGCR1)); - udelay(2); - } -} - -int -jpeg_codec_reset (struct zoran *zr) -{ - /* Take the codec out of sleep */ - jpeg_codec_sleep(zr, 0); - - if (zr->card.gpcs[GPCS_JPEG_RESET] != 0xff) { - post_office_write(zr, zr->card.gpcs[GPCS_JPEG_RESET], 0, - 0); - udelay(2); - } else { - GPIO(zr, zr->card.gpio[ZR_GPIO_JPEG_RESET], 0); - udelay(2); - GPIO(zr, zr->card.gpio[ZR_GPIO_JPEG_RESET], 1); - udelay(2); - } - - return 0; -} - -/* - * Set the registers for the size we have specified. Don't bother - * trying to understand this without the ZR36057 manual in front of - * you [AC]. - * - * PS: The manual is free for download in .pdf format from - * www.zoran.com - nicely done those folks. - */ - -static void -zr36057_adjust_vfe (struct zoran *zr, - enum zoran_codec_mode mode) -{ - u32 reg; - - switch (mode) { - case BUZ_MODE_MOTION_DECOMPRESS: - btand(~ZR36057_VFESPFR_ExtFl, ZR36057_VFESPFR); - reg = btread(ZR36057_VFEHCR); - if ((reg & (1 << 10)) && zr->card.type != LML33R10) { - reg += ((1 << 10) | 1); - } - btwrite(reg, ZR36057_VFEHCR); - break; - case BUZ_MODE_MOTION_COMPRESS: - case BUZ_MODE_IDLE: - default: - if ((zr->norm & V4L2_STD_NTSC) || - (zr->card.type == LML33R10 && - (zr->norm & V4L2_STD_PAL))) - btand(~ZR36057_VFESPFR_ExtFl, ZR36057_VFESPFR); - else - btor(ZR36057_VFESPFR_ExtFl, ZR36057_VFESPFR); - reg = btread(ZR36057_VFEHCR); - if (!(reg & (1 << 10)) && zr->card.type != LML33R10) { - reg -= ((1 << 10) | 1); - } - btwrite(reg, ZR36057_VFEHCR); - break; - } -} - -/* - * set geometry - */ - -static void -zr36057_set_vfe (struct zoran *zr, - int video_width, - int video_height, - const struct zoran_format *format) -{ - struct tvnorm *tvn; - unsigned HStart, HEnd, VStart, VEnd; - unsigned DispMode; - unsigned VidWinWid, VidWinHt; - unsigned hcrop1, hcrop2, vcrop1, vcrop2; - unsigned Wa, We, Ha, He; - unsigned X, Y, HorDcm, VerDcm; - u32 reg; - unsigned mask_line_size; - - tvn = zr->timing; - - Wa = tvn->Wa; - Ha = tvn->Ha; - - dprintk(2, KERN_INFO "%s: set_vfe() - width = %d, height = %d\n", - ZR_DEVNAME(zr), video_width, video_height); - - if (video_width < BUZ_MIN_WIDTH || - video_height < BUZ_MIN_HEIGHT || - video_width > Wa || video_height > Ha) { - dprintk(1, KERN_ERR "%s: set_vfe: w=%d h=%d not valid\n", - ZR_DEVNAME(zr), video_width, video_height); - return; - } - - /**** zr36057 ****/ - - /* horizontal */ - VidWinWid = video_width; - X = DIV_ROUND_UP(VidWinWid * 64, tvn->Wa); - We = (VidWinWid * 64) / X; - HorDcm = 64 - X; - hcrop1 = 2 * ((tvn->Wa - We) / 4); - hcrop2 = tvn->Wa - We - hcrop1; - HStart = tvn->HStart ? tvn->HStart : 1; - /* (Ronald) Original comment: - * "| 1 Doesn't have any effect, tested on both a DC10 and a DC10+" - * this is false. It inverses chroma values on the LML33R10 (so Cr - * suddenly is shown as Cb and reverse, really cool effect if you - * want to see blue faces, not useful otherwise). So don't use |1. - * However, the DC10 has '0' as HStart, but does need |1, so we - * use a dirty check... - */ - HEnd = HStart + tvn->Wa - 1; - HStart += hcrop1; - HEnd -= hcrop2; - reg = ((HStart & ZR36057_VFEHCR_Hmask) << ZR36057_VFEHCR_HStart) - | ((HEnd & ZR36057_VFEHCR_Hmask) << ZR36057_VFEHCR_HEnd); - if (zr->card.vfe_pol.hsync_pol) - reg |= ZR36057_VFEHCR_HSPol; - btwrite(reg, ZR36057_VFEHCR); - - /* Vertical */ - DispMode = !(video_height > BUZ_MAX_HEIGHT / 2); - VidWinHt = DispMode ? video_height : video_height / 2; - Y = DIV_ROUND_UP(VidWinHt * 64 * 2, tvn->Ha); - He = (VidWinHt * 64) / Y; - VerDcm = 64 - Y; - vcrop1 = (tvn->Ha / 2 - He) / 2; - vcrop2 = tvn->Ha / 2 - He - vcrop1; - VStart = tvn->VStart; - VEnd = VStart + tvn->Ha / 2; // - 1; FIXME SnapShot times out with -1 in 768*576 on the DC10 - LP - VStart += vcrop1; - VEnd -= vcrop2; - reg = ((VStart & ZR36057_VFEVCR_Vmask) << ZR36057_VFEVCR_VStart) - | ((VEnd & ZR36057_VFEVCR_Vmask) << ZR36057_VFEVCR_VEnd); - if (zr->card.vfe_pol.vsync_pol) - reg |= ZR36057_VFEVCR_VSPol; - btwrite(reg, ZR36057_VFEVCR); - - /* scaler and pixel format */ - reg = 0; - reg |= (HorDcm << ZR36057_VFESPFR_HorDcm); - reg |= (VerDcm << ZR36057_VFESPFR_VerDcm); - reg |= (DispMode << ZR36057_VFESPFR_DispMode); - /* RJ: I don't know, why the following has to be the opposite - * of the corresponding ZR36060 setting, but only this way - * we get the correct colors when uncompressing to the screen */ - //reg |= ZR36057_VFESPFR_VCLKPol; /**/ - /* RJ: Don't know if that is needed for NTSC also */ - if (!(zr->norm & V4L2_STD_NTSC)) - reg |= ZR36057_VFESPFR_ExtFl; // NEEDED!!!!!!! Wolfgang - reg |= ZR36057_VFESPFR_TopField; - if (HorDcm >= 48) { - reg |= 3 << ZR36057_VFESPFR_HFilter; /* 5 tap filter */ - } else if (HorDcm >= 32) { - reg |= 2 << ZR36057_VFESPFR_HFilter; /* 4 tap filter */ - } else if (HorDcm >= 16) { - reg |= 1 << ZR36057_VFESPFR_HFilter; /* 3 tap filter */ - } - reg |= format->vfespfr; - btwrite(reg, ZR36057_VFESPFR); - - /* display configuration */ - reg = (16 << ZR36057_VDCR_MinPix) - | (VidWinHt << ZR36057_VDCR_VidWinHt) - | (VidWinWid << ZR36057_VDCR_VidWinWid); - if (pci_pci_problems & PCIPCI_TRITON) - // || zr->revision < 1) // Revision 1 has also Triton support - reg &= ~ZR36057_VDCR_Triton; - else - reg |= ZR36057_VDCR_Triton; - btwrite(reg, ZR36057_VDCR); - - /* (Ronald) don't write this if overlay_mask = NULL */ - if (zr->overlay_mask) { - /* Write overlay clipping mask data, but don't enable overlay clipping */ - /* RJ: since this makes only sense on the screen, we use - * zr->overlay_settings.width instead of video_width */ - - mask_line_size = (BUZ_MAX_WIDTH + 31) / 32; - reg = virt_to_bus(zr->overlay_mask); - btwrite(reg, ZR36057_MMTR); - reg = virt_to_bus(zr->overlay_mask + mask_line_size); - btwrite(reg, ZR36057_MMBR); - reg = - mask_line_size - (zr->overlay_settings.width + - 31) / 32; - if (DispMode == 0) - reg += mask_line_size; - reg <<= ZR36057_OCR_MaskStride; - btwrite(reg, ZR36057_OCR); - } - - zr36057_adjust_vfe(zr, zr->codec_mode); -} - -/* - * Switch overlay on or off - */ - -void -zr36057_overlay (struct zoran *zr, - int on) -{ - u32 reg; - - if (on) { - /* do the necessary settings ... */ - btand(~ZR36057_VDCR_VidEn, ZR36057_VDCR); /* switch it off first */ - - zr36057_set_vfe(zr, - zr->overlay_settings.width, - zr->overlay_settings.height, - zr->overlay_settings.format); - - /* Start and length of each line MUST be 4-byte aligned. - * This should be already checked before the call to this routine. - * All error messages are internal driver checking only! */ - - /* video display top and bottom registers */ - reg = (long) zr->vbuf_base + - zr->overlay_settings.x * - ((zr->overlay_settings.format->depth + 7) / 8) + - zr->overlay_settings.y * - zr->vbuf_bytesperline; - btwrite(reg, ZR36057_VDTR); - if (reg & 3) - dprintk(1, - KERN_ERR - "%s: zr36057_overlay() - video_address not aligned\n", - ZR_DEVNAME(zr)); - if (zr->overlay_settings.height > BUZ_MAX_HEIGHT / 2) - reg += zr->vbuf_bytesperline; - btwrite(reg, ZR36057_VDBR); - - /* video stride, status, and frame grab register */ - reg = zr->vbuf_bytesperline - - zr->overlay_settings.width * - ((zr->overlay_settings.format->depth + 7) / 8); - if (zr->overlay_settings.height > BUZ_MAX_HEIGHT / 2) - reg += zr->vbuf_bytesperline; - if (reg & 3) - dprintk(1, - KERN_ERR - "%s: zr36057_overlay() - video_stride not aligned\n", - ZR_DEVNAME(zr)); - reg = reg << ZR36057_VSSFGR_DispStride; - reg |= ZR36057_VSSFGR_VidOvf; /* clear overflow status */ - btwrite(reg, ZR36057_VSSFGR); - - /* Set overlay clipping */ - if (zr->overlay_settings.clipcount > 0) - btor(ZR36057_OCR_OvlEnable, ZR36057_OCR); - - /* ... and switch it on */ - btor(ZR36057_VDCR_VidEn, ZR36057_VDCR); - } else { - /* Switch it off */ - btand(~ZR36057_VDCR_VidEn, ZR36057_VDCR); - } -} - -/* - * The overlay mask has one bit for each pixel on a scan line, - * and the maximum window size is BUZ_MAX_WIDTH * BUZ_MAX_HEIGHT pixels. - */ - -void write_overlay_mask(struct zoran_fh *fh, struct v4l2_clip *vp, int count) -{ - struct zoran *zr = fh->zr; - unsigned mask_line_size = (BUZ_MAX_WIDTH + 31) / 32; - u32 *mask; - int x, y, width, height; - unsigned i, j, k; - - /* fill mask with one bits */ - memset(fh->overlay_mask, ~0, mask_line_size * 4 * BUZ_MAX_HEIGHT); - - for (i = 0; i < count; ++i) { - /* pick up local copy of clip */ - x = vp[i].c.left; - y = vp[i].c.top; - width = vp[i].c.width; - height = vp[i].c.height; - - /* trim clips that extend beyond the window */ - if (x < 0) { - width += x; - x = 0; - } - if (y < 0) { - height += y; - y = 0; - } - if (x + width > fh->overlay_settings.width) { - width = fh->overlay_settings.width - x; - } - if (y + height > fh->overlay_settings.height) { - height = fh->overlay_settings.height - y; - } - - /* ignore degenerate clips */ - if (height <= 0) { - continue; - } - if (width <= 0) { - continue; - } - - /* apply clip for each scan line */ - for (j = 0; j < height; ++j) { - /* reset bit for each pixel */ - /* this can be optimized later if need be */ - mask = fh->overlay_mask + (y + j) * mask_line_size; - for (k = 0; k < width; ++k) { - mask[(x + k) / 32] &= - ~((u32) 1 << (x + k) % 32); - } - } - } -} - -/* Enable/Disable uncompressed memory grabbing of the 36057 */ - -void -zr36057_set_memgrab (struct zoran *zr, - int mode) -{ - if (mode) { - /* We only check SnapShot and not FrameGrab here. SnapShot==1 - * means a capture is already in progress, but FrameGrab==1 - * doesn't necessary mean that. It's more correct to say a 1 - * to 0 transition indicates a capture completed. If a - * capture is pending when capturing is tuned off, FrameGrab - * will be stuck at 1 until capturing is turned back on. - */ - if (btread(ZR36057_VSSFGR) & ZR36057_VSSFGR_SnapShot) - dprintk(1, - KERN_WARNING - "%s: zr36057_set_memgrab(1) with SnapShot on!?\n", - ZR_DEVNAME(zr)); - - /* switch on VSync interrupts */ - btwrite(IRQ_MASK, ZR36057_ISR); // Clear Interrupts - btor(zr->card.vsync_int, ZR36057_ICR); // SW - - /* enable SnapShot */ - btor(ZR36057_VSSFGR_SnapShot, ZR36057_VSSFGR); - - /* Set zr36057 video front end and enable video */ - zr36057_set_vfe(zr, zr->v4l_settings.width, - zr->v4l_settings.height, - zr->v4l_settings.format); - - zr->v4l_memgrab_active = 1; - } else { - /* switch off VSync interrupts */ - btand(~zr->card.vsync_int, ZR36057_ICR); // SW - - zr->v4l_memgrab_active = 0; - zr->v4l_grab_frame = NO_GRAB_ACTIVE; - - /* re-enable grabbing to screen if it was running */ - if (zr->v4l_overlay_active) { - zr36057_overlay(zr, 1); - } else { - btand(~ZR36057_VDCR_VidEn, ZR36057_VDCR); - btand(~ZR36057_VSSFGR_SnapShot, ZR36057_VSSFGR); - } - } -} - -int -wait_grab_pending (struct zoran *zr) -{ - unsigned long flags; - - /* wait until all pending grabs are finished */ - - if (!zr->v4l_memgrab_active) - return 0; - - wait_event_interruptible(zr->v4l_capq, - (zr->v4l_pend_tail == zr->v4l_pend_head)); - if (signal_pending(current)) - return -ERESTARTSYS; - - spin_lock_irqsave(&zr->spinlock, flags); - zr36057_set_memgrab(zr, 0); - spin_unlock_irqrestore(&zr->spinlock, flags); - - return 0; -} - -/***************************************************************************** - * * - * Set up the Buz-specific MJPEG part * - * * - *****************************************************************************/ - -static inline void -set_frame (struct zoran *zr, - int val) -{ - GPIO(zr, zr->card.gpio[ZR_GPIO_JPEG_FRAME], val); -} - -static void -set_videobus_dir (struct zoran *zr, - int val) -{ - switch (zr->card.type) { - case LML33: - case LML33R10: - if (!lml33dpath) - GPIO(zr, 5, val); - else - GPIO(zr, 5, 1); - break; - default: - GPIO(zr, zr->card.gpio[ZR_GPIO_VID_DIR], - zr->card.gpio_pol[ZR_GPIO_VID_DIR] ? !val : val); - break; - } -} - -static void -init_jpeg_queue (struct zoran *zr) -{ - int i; - - /* re-initialize DMA ring stuff */ - zr->jpg_que_head = 0; - zr->jpg_dma_head = 0; - zr->jpg_dma_tail = 0; - zr->jpg_que_tail = 0; - zr->jpg_seq_num = 0; - zr->JPEG_error = 0; - zr->num_errors = 0; - zr->jpg_err_seq = 0; - zr->jpg_err_shift = 0; - zr->jpg_queued_num = 0; - for (i = 0; i < zr->jpg_buffers.num_buffers; i++) { - zr->jpg_buffers.buffer[i].state = BUZ_STATE_USER; /* nothing going on */ - } - for (i = 0; i < BUZ_NUM_STAT_COM; i++) { - zr->stat_com[i] = cpu_to_le32(1); /* mark as unavailable to zr36057 */ - } -} - -static void -zr36057_set_jpg (struct zoran *zr, - enum zoran_codec_mode mode) -{ - struct tvnorm *tvn; - u32 reg; - - tvn = zr->timing; - - /* assert P_Reset, disable code transfer, deassert Active */ - btwrite(0, ZR36057_JPC); - - /* MJPEG compression mode */ - switch (mode) { - - case BUZ_MODE_MOTION_COMPRESS: - default: - reg = ZR36057_JMC_MJPGCmpMode; - break; - - case BUZ_MODE_MOTION_DECOMPRESS: - reg = ZR36057_JMC_MJPGExpMode; - reg |= ZR36057_JMC_SyncMstr; - /* RJ: The following is experimental - improves the output to screen */ - //if(zr->jpg_settings.VFIFO_FB) reg |= ZR36057_JMC_VFIFO_FB; // No, it doesn't. SM - break; - - case BUZ_MODE_STILL_COMPRESS: - reg = ZR36057_JMC_JPGCmpMode; - break; - - case BUZ_MODE_STILL_DECOMPRESS: - reg = ZR36057_JMC_JPGExpMode; - break; - - } - reg |= ZR36057_JMC_JPG; - if (zr->jpg_settings.field_per_buff == 1) - reg |= ZR36057_JMC_Fld_per_buff; - btwrite(reg, ZR36057_JMC); - - /* vertical */ - btor(ZR36057_VFEVCR_VSPol, ZR36057_VFEVCR); - reg = (6 << ZR36057_VSP_VsyncSize) | - (tvn->Ht << ZR36057_VSP_FrmTot); - btwrite(reg, ZR36057_VSP); - reg = ((zr->jpg_settings.img_y + tvn->VStart) << ZR36057_FVAP_NAY) | - (zr->jpg_settings.img_height << ZR36057_FVAP_PAY); - btwrite(reg, ZR36057_FVAP); - - /* horizontal */ - if (zr->card.vfe_pol.hsync_pol) - btor(ZR36057_VFEHCR_HSPol, ZR36057_VFEHCR); - else - btand(~ZR36057_VFEHCR_HSPol, ZR36057_VFEHCR); - reg = ((tvn->HSyncStart) << ZR36057_HSP_HsyncStart) | - (tvn->Wt << ZR36057_HSP_LineTot); - btwrite(reg, ZR36057_HSP); - reg = ((zr->jpg_settings.img_x + - tvn->HStart + 4) << ZR36057_FHAP_NAX) | - (zr->jpg_settings.img_width << ZR36057_FHAP_PAX); - btwrite(reg, ZR36057_FHAP); - - /* field process parameters */ - if (zr->jpg_settings.odd_even) - reg = ZR36057_FPP_Odd_Even; - else - reg = 0; - - btwrite(reg, ZR36057_FPP); - - /* Set proper VCLK Polarity, else colors will be wrong during playback */ - //btor(ZR36057_VFESPFR_VCLKPol, ZR36057_VFESPFR); - - /* code base address */ - reg = virt_to_bus(zr->stat_com); - btwrite(reg, ZR36057_JCBA); - - /* FIFO threshold (FIFO is 160. double words) */ - /* NOTE: decimal values here */ - switch (mode) { - - case BUZ_MODE_STILL_COMPRESS: - case BUZ_MODE_MOTION_COMPRESS: - if (zr->card.type != BUZ) - reg = 140; - else - reg = 60; - break; - - case BUZ_MODE_STILL_DECOMPRESS: - case BUZ_MODE_MOTION_DECOMPRESS: - reg = 20; - break; - - default: - reg = 80; - break; - - } - btwrite(reg, ZR36057_JCFT); - zr36057_adjust_vfe(zr, mode); - -} - -void -print_interrupts (struct zoran *zr) -{ - int res, noerr = 0; - - printk(KERN_INFO "%s: interrupts received:", ZR_DEVNAME(zr)); - if ((res = zr->field_counter) < -1 || res > 1) { - printk(KERN_CONT " FD:%d", res); - } - if ((res = zr->intr_counter_GIRQ1) != 0) { - printk(KERN_CONT " GIRQ1:%d", res); - noerr++; - } - if ((res = zr->intr_counter_GIRQ0) != 0) { - printk(KERN_CONT " GIRQ0:%d", res); - noerr++; - } - if ((res = zr->intr_counter_CodRepIRQ) != 0) { - printk(KERN_CONT " CodRepIRQ:%d", res); - noerr++; - } - if ((res = zr->intr_counter_JPEGRepIRQ) != 0) { - printk(KERN_CONT " JPEGRepIRQ:%d", res); - noerr++; - } - if (zr->JPEG_max_missed) { - printk(KERN_CONT " JPEG delays: max=%d min=%d", zr->JPEG_max_missed, - zr->JPEG_min_missed); - } - if (zr->END_event_missed) { - printk(KERN_CONT " ENDs missed: %d", zr->END_event_missed); - } - //if (zr->jpg_queued_num) { - printk(KERN_CONT " queue_state=%ld/%ld/%ld/%ld", zr->jpg_que_tail, - zr->jpg_dma_tail, zr->jpg_dma_head, zr->jpg_que_head); - //} - if (!noerr) { - printk(KERN_CONT ": no interrupts detected."); - } - printk(KERN_CONT "\n"); -} - -void -clear_interrupt_counters (struct zoran *zr) -{ - zr->intr_counter_GIRQ1 = 0; - zr->intr_counter_GIRQ0 = 0; - zr->intr_counter_CodRepIRQ = 0; - zr->intr_counter_JPEGRepIRQ = 0; - zr->field_counter = 0; - zr->IRQ1_in = 0; - zr->IRQ1_out = 0; - zr->JPEG_in = 0; - zr->JPEG_out = 0; - zr->JPEG_0 = 0; - zr->JPEG_1 = 0; - zr->END_event_missed = 0; - zr->JPEG_missed = 0; - zr->JPEG_max_missed = 0; - zr->JPEG_min_missed = 0x7fffffff; -} - -static u32 -count_reset_interrupt (struct zoran *zr) -{ - u32 isr; - - if ((isr = btread(ZR36057_ISR) & 0x78000000)) { - if (isr & ZR36057_ISR_GIRQ1) { - btwrite(ZR36057_ISR_GIRQ1, ZR36057_ISR); - zr->intr_counter_GIRQ1++; - } - if (isr & ZR36057_ISR_GIRQ0) { - btwrite(ZR36057_ISR_GIRQ0, ZR36057_ISR); - zr->intr_counter_GIRQ0++; - } - if (isr & ZR36057_ISR_CodRepIRQ) { - btwrite(ZR36057_ISR_CodRepIRQ, ZR36057_ISR); - zr->intr_counter_CodRepIRQ++; - } - if (isr & ZR36057_ISR_JPEGRepIRQ) { - btwrite(ZR36057_ISR_JPEGRepIRQ, ZR36057_ISR); - zr->intr_counter_JPEGRepIRQ++; - } - } - return isr; -} - -void -jpeg_start (struct zoran *zr) -{ - int reg; - - zr->frame_num = 0; - - /* deassert P_reset, disable code transfer, deassert Active */ - btwrite(ZR36057_JPC_P_Reset, ZR36057_JPC); - /* stop flushing the internal code buffer */ - btand(~ZR36057_MCTCR_CFlush, ZR36057_MCTCR); - /* enable code transfer */ - btor(ZR36057_JPC_CodTrnsEn, ZR36057_JPC); - - /* clear IRQs */ - btwrite(IRQ_MASK, ZR36057_ISR); - /* enable the JPEG IRQs */ - btwrite(zr->card.jpeg_int | - ZR36057_ICR_JPEGRepIRQ | - ZR36057_ICR_IntPinEn, - ZR36057_ICR); - - set_frame(zr, 0); // \FRAME - - /* set the JPEG codec guest ID */ - reg = (zr->card.gpcs[1] << ZR36057_JCGI_JPEGuestID) | - (0 << ZR36057_JCGI_JPEGuestReg); - btwrite(reg, ZR36057_JCGI); - - if (zr->card.video_vfe == CODEC_TYPE_ZR36016 && - zr->card.video_codec == CODEC_TYPE_ZR36050) { - /* Enable processing on the ZR36016 */ - if (zr->vfe) - zr36016_write(zr->vfe, 0, 1); - - /* load the address of the GO register in the ZR36050 latch */ - post_office_write(zr, 0, 0, 0); - } - - /* assert Active */ - btor(ZR36057_JPC_Active, ZR36057_JPC); - - /* enable the Go generation */ - btor(ZR36057_JMC_Go_en, ZR36057_JMC); - udelay(30); - - set_frame(zr, 1); // /FRAME - - dprintk(3, KERN_DEBUG "%s: jpeg_start\n", ZR_DEVNAME(zr)); -} - -void -zr36057_enable_jpg (struct zoran *zr, - enum zoran_codec_mode mode) -{ - struct vfe_settings cap; - int field_size = - zr->jpg_buffers.buffer_size / zr->jpg_settings.field_per_buff; - - zr->codec_mode = mode; - - cap.x = zr->jpg_settings.img_x; - cap.y = zr->jpg_settings.img_y; - cap.width = zr->jpg_settings.img_width; - cap.height = zr->jpg_settings.img_height; - cap.decimation = - zr->jpg_settings.HorDcm | (zr->jpg_settings.VerDcm << 8); - cap.quality = zr->jpg_settings.jpg_comp.quality; - - switch (mode) { - - case BUZ_MODE_MOTION_COMPRESS: { - struct jpeg_app_marker app; - struct jpeg_com_marker com; - - /* In motion compress mode, the decoder output must be enabled, and - * the video bus direction set to input. - */ - set_videobus_dir(zr, 0); - decoder_call(zr, video, s_stream, 1); - encoder_call(zr, video, s_routing, 0, 0, 0); - - /* Take the JPEG codec and the VFE out of sleep */ - jpeg_codec_sleep(zr, 0); - - /* set JPEG app/com marker */ - app.appn = zr->jpg_settings.jpg_comp.APPn; - app.len = zr->jpg_settings.jpg_comp.APP_len; - memcpy(app.data, zr->jpg_settings.jpg_comp.APP_data, 60); - zr->codec->control(zr->codec, CODEC_S_JPEG_APP_DATA, - sizeof(struct jpeg_app_marker), &app); - - com.len = zr->jpg_settings.jpg_comp.COM_len; - memcpy(com.data, zr->jpg_settings.jpg_comp.COM_data, 60); - zr->codec->control(zr->codec, CODEC_S_JPEG_COM_DATA, - sizeof(struct jpeg_com_marker), &com); - - /* Setup the JPEG codec */ - zr->codec->control(zr->codec, CODEC_S_JPEG_TDS_BYTE, - sizeof(int), &field_size); - zr->codec->set_video(zr->codec, zr->timing, &cap, - &zr->card.vfe_pol); - zr->codec->set_mode(zr->codec, CODEC_DO_COMPRESSION); - - /* Setup the VFE */ - if (zr->vfe) { - zr->vfe->control(zr->vfe, CODEC_S_JPEG_TDS_BYTE, - sizeof(int), &field_size); - zr->vfe->set_video(zr->vfe, zr->timing, &cap, - &zr->card.vfe_pol); - zr->vfe->set_mode(zr->vfe, CODEC_DO_COMPRESSION); - } - - init_jpeg_queue(zr); - zr36057_set_jpg(zr, mode); // \P_Reset, ... Video param, FIFO - - clear_interrupt_counters(zr); - dprintk(2, KERN_INFO "%s: enable_jpg(MOTION_COMPRESS)\n", - ZR_DEVNAME(zr)); - break; - } - - case BUZ_MODE_MOTION_DECOMPRESS: - /* In motion decompression mode, the decoder output must be disabled, and - * the video bus direction set to output. - */ - decoder_call(zr, video, s_stream, 0); - set_videobus_dir(zr, 1); - encoder_call(zr, video, s_routing, 1, 0, 0); - - /* Take the JPEG codec and the VFE out of sleep */ - jpeg_codec_sleep(zr, 0); - /* Setup the VFE */ - if (zr->vfe) { - zr->vfe->set_video(zr->vfe, zr->timing, &cap, - &zr->card.vfe_pol); - zr->vfe->set_mode(zr->vfe, CODEC_DO_EXPANSION); - } - /* Setup the JPEG codec */ - zr->codec->set_video(zr->codec, zr->timing, &cap, - &zr->card.vfe_pol); - zr->codec->set_mode(zr->codec, CODEC_DO_EXPANSION); - - init_jpeg_queue(zr); - zr36057_set_jpg(zr, mode); // \P_Reset, ... Video param, FIFO - - clear_interrupt_counters(zr); - dprintk(2, KERN_INFO "%s: enable_jpg(MOTION_DECOMPRESS)\n", - ZR_DEVNAME(zr)); - break; - - case BUZ_MODE_IDLE: - default: - /* shut down processing */ - btand(~(zr->card.jpeg_int | ZR36057_ICR_JPEGRepIRQ), - ZR36057_ICR); - btwrite(zr->card.jpeg_int | ZR36057_ICR_JPEGRepIRQ, - ZR36057_ISR); - btand(~ZR36057_JMC_Go_en, ZR36057_JMC); // \Go_en - - msleep(50); - - set_videobus_dir(zr, 0); - set_frame(zr, 1); // /FRAME - btor(ZR36057_MCTCR_CFlush, ZR36057_MCTCR); // /CFlush - btwrite(0, ZR36057_JPC); // \P_Reset,\CodTrnsEn,\Active - btand(~ZR36057_JMC_VFIFO_FB, ZR36057_JMC); - btand(~ZR36057_JMC_SyncMstr, ZR36057_JMC); - jpeg_codec_reset(zr); - jpeg_codec_sleep(zr, 1); - zr36057_adjust_vfe(zr, mode); - - decoder_call(zr, video, s_stream, 1); - encoder_call(zr, video, s_routing, 0, 0, 0); - - dprintk(2, KERN_INFO "%s: enable_jpg(IDLE)\n", ZR_DEVNAME(zr)); - break; - - } -} - -/* when this is called the spinlock must be held */ -void -zoran_feed_stat_com (struct zoran *zr) -{ - /* move frames from pending queue to DMA */ - - int frame, i, max_stat_com; - - max_stat_com = - (zr->jpg_settings.TmpDcm == - 1) ? BUZ_NUM_STAT_COM : (BUZ_NUM_STAT_COM >> 1); - - while ((zr->jpg_dma_head - zr->jpg_dma_tail) < max_stat_com && - zr->jpg_dma_head < zr->jpg_que_head) { - - frame = zr->jpg_pend[zr->jpg_dma_head & BUZ_MASK_FRAME]; - if (zr->jpg_settings.TmpDcm == 1) { - /* fill 1 stat_com entry */ - i = (zr->jpg_dma_head - - zr->jpg_err_shift) & BUZ_MASK_STAT_COM; - if (!(zr->stat_com[i] & cpu_to_le32(1))) - break; - zr->stat_com[i] = - cpu_to_le32(zr->jpg_buffers.buffer[frame].jpg.frag_tab_bus); - } else { - /* fill 2 stat_com entries */ - i = ((zr->jpg_dma_head - - zr->jpg_err_shift) & 1) * 2; - if (!(zr->stat_com[i] & cpu_to_le32(1))) - break; - zr->stat_com[i] = - cpu_to_le32(zr->jpg_buffers.buffer[frame].jpg.frag_tab_bus); - zr->stat_com[i + 1] = - cpu_to_le32(zr->jpg_buffers.buffer[frame].jpg.frag_tab_bus); - } - zr->jpg_buffers.buffer[frame].state = BUZ_STATE_DMA; - zr->jpg_dma_head++; - - } - if (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS) - zr->jpg_queued_num++; -} - -/* when this is called the spinlock must be held */ -static void -zoran_reap_stat_com (struct zoran *zr) -{ - /* move frames from DMA queue to done queue */ - - int i; - u32 stat_com; - unsigned int seq; - unsigned int dif; - struct zoran_buffer *buffer; - int frame; - - /* In motion decompress we don't have a hardware frame counter, - * we just count the interrupts here */ - - if (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS) { - zr->jpg_seq_num++; - } - while (zr->jpg_dma_tail < zr->jpg_dma_head) { - if (zr->jpg_settings.TmpDcm == 1) - i = (zr->jpg_dma_tail - - zr->jpg_err_shift) & BUZ_MASK_STAT_COM; - else - i = ((zr->jpg_dma_tail - - zr->jpg_err_shift) & 1) * 2 + 1; - - stat_com = le32_to_cpu(zr->stat_com[i]); - - if ((stat_com & 1) == 0) { - return; - } - frame = zr->jpg_pend[zr->jpg_dma_tail & BUZ_MASK_FRAME]; - buffer = &zr->jpg_buffers.buffer[frame]; - buffer->bs.ts = ktime_get_ns(); - - if (zr->codec_mode == BUZ_MODE_MOTION_COMPRESS) { - buffer->bs.length = (stat_com & 0x7fffff) >> 1; - - /* update sequence number with the help of the counter in stat_com */ - - seq = ((stat_com >> 24) + zr->jpg_err_seq) & 0xff; - dif = (seq - zr->jpg_seq_num) & 0xff; - zr->jpg_seq_num += dif; - } else { - buffer->bs.length = 0; - } - buffer->bs.seq = - zr->jpg_settings.TmpDcm == - 2 ? (zr->jpg_seq_num >> 1) : zr->jpg_seq_num; - buffer->state = BUZ_STATE_DONE; - - zr->jpg_dma_tail++; - } -} - -static void zoran_restart(struct zoran *zr) -{ - /* Now the stat_comm buffer is ready for restart */ - unsigned int status = 0; - int mode; - - if (zr->codec_mode == BUZ_MODE_MOTION_COMPRESS) { - decoder_call(zr, video, g_input_status, &status); - mode = CODEC_DO_COMPRESSION; - } else { - status = V4L2_IN_ST_NO_SIGNAL; - mode = CODEC_DO_EXPANSION; - } - if (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS || - !(status & V4L2_IN_ST_NO_SIGNAL)) { - /********** RESTART code *************/ - jpeg_codec_reset(zr); - zr->codec->set_mode(zr->codec, mode); - zr36057_set_jpg(zr, zr->codec_mode); - jpeg_start(zr); - - if (zr->num_errors <= 8) - dprintk(2, KERN_INFO "%s: Restart\n", - ZR_DEVNAME(zr)); - - zr->JPEG_missed = 0; - zr->JPEG_error = 2; - /********** End RESTART code ***********/ - } -} - -static void -error_handler (struct zoran *zr, - u32 astat, - u32 stat) -{ - int i; - - /* This is JPEG error handling part */ - if (zr->codec_mode != BUZ_MODE_MOTION_COMPRESS && - zr->codec_mode != BUZ_MODE_MOTION_DECOMPRESS) { - return; - } - - if ((stat & 1) == 0 && - zr->codec_mode == BUZ_MODE_MOTION_COMPRESS && - zr->jpg_dma_tail - zr->jpg_que_tail >= zr->jpg_buffers.num_buffers) { - /* No free buffers... */ - zoran_reap_stat_com(zr); - zoran_feed_stat_com(zr); - wake_up_interruptible(&zr->jpg_capq); - zr->JPEG_missed = 0; - return; - } - - if (zr->JPEG_error == 1) { - zoran_restart(zr); - return; - } - - /* - * First entry: error just happened during normal operation - * - * In BUZ_MODE_MOTION_COMPRESS: - * - * Possible glitch in TV signal. In this case we should - * stop the codec and wait for good quality signal before - * restarting it to avoid further problems - * - * In BUZ_MODE_MOTION_DECOMPRESS: - * - * Bad JPEG frame: we have to mark it as processed (codec crashed - * and was not able to do it itself), and to remove it from queue. - */ - btand(~ZR36057_JMC_Go_en, ZR36057_JMC); - udelay(1); - stat = stat | (post_office_read(zr, 7, 0) & 3) << 8; - btwrite(0, ZR36057_JPC); - btor(ZR36057_MCTCR_CFlush, ZR36057_MCTCR); - jpeg_codec_reset(zr); - jpeg_codec_sleep(zr, 1); - zr->JPEG_error = 1; - zr->num_errors++; - - /* Report error */ - if (zr36067_debug > 1 && zr->num_errors <= 8) { - long frame; - int j; - - frame = zr->jpg_pend[zr->jpg_dma_tail & BUZ_MASK_FRAME]; - printk(KERN_ERR - "%s: JPEG error stat=0x%08x(0x%08x) queue_state=%ld/%ld/%ld/%ld seq=%ld frame=%ld. Codec stopped. ", - ZR_DEVNAME(zr), stat, zr->last_isr, - zr->jpg_que_tail, zr->jpg_dma_tail, - zr->jpg_dma_head, zr->jpg_que_head, - zr->jpg_seq_num, frame); - printk(KERN_INFO "stat_com frames:"); - for (j = 0; j < BUZ_NUM_STAT_COM; j++) { - for (i = 0; i < zr->jpg_buffers.num_buffers; i++) { - if (le32_to_cpu(zr->stat_com[j]) == zr->jpg_buffers.buffer[i].jpg.frag_tab_bus) - printk(KERN_CONT "% d->%d", j, i); - } - } - printk(KERN_CONT "\n"); - } - /* Find an entry in stat_com and rotate contents */ - if (zr->jpg_settings.TmpDcm == 1) - i = (zr->jpg_dma_tail - zr->jpg_err_shift) & BUZ_MASK_STAT_COM; - else - i = ((zr->jpg_dma_tail - zr->jpg_err_shift) & 1) * 2; - if (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS) { - /* Mimic zr36067 operation */ - zr->stat_com[i] |= cpu_to_le32(1); - if (zr->jpg_settings.TmpDcm != 1) - zr->stat_com[i + 1] |= cpu_to_le32(1); - /* Refill */ - zoran_reap_stat_com(zr); - zoran_feed_stat_com(zr); - wake_up_interruptible(&zr->jpg_capq); - /* Find an entry in stat_com again after refill */ - if (zr->jpg_settings.TmpDcm == 1) - i = (zr->jpg_dma_tail - zr->jpg_err_shift) & BUZ_MASK_STAT_COM; - else - i = ((zr->jpg_dma_tail - zr->jpg_err_shift) & 1) * 2; - } - if (i) { - /* Rotate stat_comm entries to make current entry first */ - int j; - __le32 bus_addr[BUZ_NUM_STAT_COM]; - - /* Here we are copying the stat_com array, which - * is already in little endian format, so - * no endian conversions here - */ - memcpy(bus_addr, zr->stat_com, sizeof(bus_addr)); - - for (j = 0; j < BUZ_NUM_STAT_COM; j++) - zr->stat_com[j] = bus_addr[(i + j) & BUZ_MASK_STAT_COM]; - - zr->jpg_err_shift += i; - zr->jpg_err_shift &= BUZ_MASK_STAT_COM; - } - if (zr->codec_mode == BUZ_MODE_MOTION_COMPRESS) - zr->jpg_err_seq = zr->jpg_seq_num; /* + 1; */ - zoran_restart(zr); -} - -irqreturn_t -zoran_irq (int irq, - void *dev_id) -{ - u32 stat, astat; - int count; - struct zoran *zr; - unsigned long flags; - - zr = dev_id; - count = 0; - - if (zr->testing) { - /* Testing interrupts */ - spin_lock_irqsave(&zr->spinlock, flags); - while ((stat = count_reset_interrupt(zr))) { - if (count++ > 100) { - btand(~ZR36057_ICR_IntPinEn, ZR36057_ICR); - dprintk(1, - KERN_ERR - "%s: IRQ lockup while testing, isr=0x%08x, cleared int mask\n", - ZR_DEVNAME(zr), stat); - wake_up_interruptible(&zr->test_q); - } - } - zr->last_isr = stat; - spin_unlock_irqrestore(&zr->spinlock, flags); - return IRQ_HANDLED; - } - - spin_lock_irqsave(&zr->spinlock, flags); - while (1) { - /* get/clear interrupt status bits */ - stat = count_reset_interrupt(zr); - astat = stat & IRQ_MASK; - if (!astat) { - break; - } - dprintk(4, - KERN_DEBUG - "zoran_irq: astat: 0x%08x, mask: 0x%08x\n", - astat, btread(ZR36057_ICR)); - if (astat & zr->card.vsync_int) { // SW - - if (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS || - zr->codec_mode == BUZ_MODE_MOTION_COMPRESS) { - /* count missed interrupts */ - zr->JPEG_missed++; - } - //post_office_read(zr,1,0); - /* Interrupts may still happen when - * zr->v4l_memgrab_active is switched off. - * We simply ignore them */ - - if (zr->v4l_memgrab_active) { - /* A lot more checks should be here ... */ - if ((btread(ZR36057_VSSFGR) & ZR36057_VSSFGR_SnapShot) == 0) - dprintk(1, - KERN_WARNING - "%s: BuzIRQ with SnapShot off ???\n", - ZR_DEVNAME(zr)); - - if (zr->v4l_grab_frame != NO_GRAB_ACTIVE) { - /* There is a grab on a frame going on, check if it has finished */ - if ((btread(ZR36057_VSSFGR) & ZR36057_VSSFGR_FrameGrab) == 0) { - /* it is finished, notify the user */ - - zr->v4l_buffers.buffer[zr->v4l_grab_frame].state = BUZ_STATE_DONE; - zr->v4l_buffers.buffer[zr->v4l_grab_frame].bs.seq = zr->v4l_grab_seq; - zr->v4l_buffers.buffer[zr->v4l_grab_frame].bs.ts = ktime_get_ns(); - zr->v4l_grab_frame = NO_GRAB_ACTIVE; - zr->v4l_pend_tail++; - } - } - - if (zr->v4l_grab_frame == NO_GRAB_ACTIVE) - wake_up_interruptible(&zr->v4l_capq); - - /* Check if there is another grab queued */ - - if (zr->v4l_grab_frame == NO_GRAB_ACTIVE && - zr->v4l_pend_tail != zr->v4l_pend_head) { - int frame = zr->v4l_pend[zr->v4l_pend_tail & V4L_MASK_FRAME]; - u32 reg; - - zr->v4l_grab_frame = frame; - - /* Set zr36057 video front end and enable video */ - - /* Buffer address */ - - reg = zr->v4l_buffers.buffer[frame].v4l.fbuffer_bus; - btwrite(reg, ZR36057_VDTR); - if (zr->v4l_settings.height > BUZ_MAX_HEIGHT / 2) - reg += zr->v4l_settings.bytesperline; - btwrite(reg, ZR36057_VDBR); - - /* video stride, status, and frame grab register */ - reg = 0; - if (zr->v4l_settings.height > BUZ_MAX_HEIGHT / 2) - reg += zr->v4l_settings.bytesperline; - reg = reg << ZR36057_VSSFGR_DispStride; - reg |= ZR36057_VSSFGR_VidOvf; - reg |= ZR36057_VSSFGR_SnapShot; - reg |= ZR36057_VSSFGR_FrameGrab; - btwrite(reg, ZR36057_VSSFGR); - - btor(ZR36057_VDCR_VidEn, - ZR36057_VDCR); - } - } - - /* even if we don't grab, we do want to increment - * the sequence counter to see lost frames */ - zr->v4l_grab_seq++; - } -#if (IRQ_MASK & ZR36057_ISR_CodRepIRQ) - if (astat & ZR36057_ISR_CodRepIRQ) { - zr->intr_counter_CodRepIRQ++; - IDEBUG(printk(KERN_DEBUG "%s: ZR36057_ISR_CodRepIRQ\n", - ZR_DEVNAME(zr))); - btand(~ZR36057_ICR_CodRepIRQ, ZR36057_ICR); - } -#endif /* (IRQ_MASK & ZR36057_ISR_CodRepIRQ) */ - -#if (IRQ_MASK & ZR36057_ISR_JPEGRepIRQ) - if ((astat & ZR36057_ISR_JPEGRepIRQ) && - (zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS || - zr->codec_mode == BUZ_MODE_MOTION_COMPRESS)) { - if (zr36067_debug > 1 && (!zr->frame_num || zr->JPEG_error)) { - char sv[BUZ_NUM_STAT_COM + 1]; - int i; - - printk(KERN_INFO - "%s: first frame ready: state=0x%08x odd_even=%d field_per_buff=%d delay=%d\n", - ZR_DEVNAME(zr), stat, - zr->jpg_settings.odd_even, - zr->jpg_settings.field_per_buff, - zr->JPEG_missed); - - for (i = 0; i < BUZ_NUM_STAT_COM; i++) - sv[i] = le32_to_cpu(zr->stat_com[i]) & 1 ? '1' : '0'; - sv[BUZ_NUM_STAT_COM] = 0; - printk(KERN_INFO - "%s: stat_com=%s queue_state=%ld/%ld/%ld/%ld\n", - ZR_DEVNAME(zr), sv, - zr->jpg_que_tail, - zr->jpg_dma_tail, - zr->jpg_dma_head, - zr->jpg_que_head); - } else { - /* Get statistics */ - if (zr->JPEG_missed > zr->JPEG_max_missed) - zr->JPEG_max_missed = zr->JPEG_missed; - if (zr->JPEG_missed < zr->JPEG_min_missed) - zr->JPEG_min_missed = zr->JPEG_missed; - } - - if (zr36067_debug > 2 && zr->frame_num < 6) { - int i; - - printk(KERN_INFO "%s: seq=%ld stat_com:", - ZR_DEVNAME(zr), zr->jpg_seq_num); - for (i = 0; i < 4; i++) { - printk(KERN_CONT " %08x", - le32_to_cpu(zr->stat_com[i])); - } - printk(KERN_CONT "\n"); - } - zr->frame_num++; - zr->JPEG_missed = 0; - zr->JPEG_error = 0; - zoran_reap_stat_com(zr); - zoran_feed_stat_com(zr); - wake_up_interruptible(&zr->jpg_capq); - } -#endif /* (IRQ_MASK & ZR36057_ISR_JPEGRepIRQ) */ - - /* DATERR, too many fields missed, error processing */ - if ((astat & zr->card.jpeg_int) || - zr->JPEG_missed > 25 || - zr->JPEG_error == 1 || - ((zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS) && - (zr->frame_num && (zr->JPEG_missed > zr->jpg_settings.field_per_buff)))) { - error_handler(zr, astat, stat); - } - - count++; - if (count > 10) { - dprintk(2, KERN_WARNING "%s: irq loop %d\n", - ZR_DEVNAME(zr), count); - if (count > 20) { - btand(~ZR36057_ICR_IntPinEn, ZR36057_ICR); - dprintk(2, - KERN_ERR - "%s: IRQ lockup, cleared int mask\n", - ZR_DEVNAME(zr)); - break; - } - } - zr->last_isr = stat; - } - spin_unlock_irqrestore(&zr->spinlock, flags); - - return IRQ_HANDLED; -} - -void -zoran_set_pci_master (struct zoran *zr, - int set_master) -{ - if (set_master) { - pci_set_master(zr->pci_dev); - } else { - u16 command; - - pci_read_config_word(zr->pci_dev, PCI_COMMAND, &command); - command &= ~PCI_COMMAND_MASTER; - pci_write_config_word(zr->pci_dev, PCI_COMMAND, command); - } -} - -void -zoran_init_hardware (struct zoran *zr) -{ - /* Enable bus-mastering */ - zoran_set_pci_master(zr, 1); - - /* Initialize the board */ - if (zr->card.init) { - zr->card.init(zr); - } - - decoder_call(zr, core, init, 0); - decoder_call(zr, video, s_std, zr->norm); - decoder_call(zr, video, s_routing, - zr->card.input[zr->input].muxsel, 0, 0); - - encoder_call(zr, core, init, 0); - encoder_call(zr, video, s_std_output, zr->norm); - encoder_call(zr, video, s_routing, 0, 0, 0); - - /* toggle JPEG codec sleep to sync PLL */ - jpeg_codec_sleep(zr, 1); - jpeg_codec_sleep(zr, 0); - - /* - * set individual interrupt enables (without GIRQ1) - * but don't global enable until zoran_open() - */ - zr36057_init_vfe(zr); - - zr36057_enable_jpg(zr, BUZ_MODE_IDLE); - - btwrite(IRQ_MASK, ZR36057_ISR); // Clears interrupts -} - -void -zr36057_restart (struct zoran *zr) -{ - btwrite(0, ZR36057_SPGPPCR); - mdelay(1); - btor(ZR36057_SPGPPCR_SoftReset, ZR36057_SPGPPCR); - mdelay(1); - - /* assert P_Reset */ - btwrite(0, ZR36057_JPC); - /* set up GPIO direction - all output */ - btwrite(ZR36057_SPGPPCR_SoftReset | 0, ZR36057_SPGPPCR); - - /* set up GPIO pins and guest bus timing */ - btwrite((0x81 << 24) | 0x8888, ZR36057_GPPGCR1); -} - -/* - * initialize video front end - */ - -static void -zr36057_init_vfe (struct zoran *zr) -{ - u32 reg; - - reg = btread(ZR36057_VFESPFR); - reg |= ZR36057_VFESPFR_LittleEndian; - reg &= ~ZR36057_VFESPFR_VCLKPol; - reg |= ZR36057_VFESPFR_ExtFl; - reg |= ZR36057_VFESPFR_TopField; - btwrite(reg, ZR36057_VFESPFR); - reg = btread(ZR36057_VDCR); - if (pci_pci_problems & PCIPCI_TRITON) - // || zr->revision < 1) // Revision 1 has also Triton support - reg &= ~ZR36057_VDCR_Triton; - else - reg |= ZR36057_VDCR_Triton; - btwrite(reg, ZR36057_VDCR); -} diff --git a/drivers/staging/media/zoran/zoran_device.h b/drivers/staging/media/zoran/zoran_device.h deleted file mode 100644 index b3b8a03f2004..000000000000 --- a/drivers/staging/media/zoran/zoran_device.h +++ /dev/null @@ -1,81 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Zoran zr36057/zr36067 PCI controller driver, for the - * Pinnacle/Miro DC10/DC10+/DC30/DC30+, Iomega Buz, Linux - * Media Labs LML33/LML33R10. - * - * This part handles card-specific data and detection - * - * Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx> - * - * Currently maintained by: - * Ronald Bultje <rbultje@ronald.bitfreak.net> - * Laurent Pinchart <laurent.pinchart@skynet.be> - * Mailinglist <mjpeg-users@lists.sf.net> - */ -#ifndef __ZORAN_DEVICE_H__ -#define __ZORAN_DEVICE_H__ - -/* general purpose I/O */ -extern void GPIO(struct zoran *zr, - int bit, - unsigned int value); - -/* codec (or actually: guest bus) access */ -extern int post_office_wait(struct zoran *zr); -extern int post_office_write(struct zoran *zr, - unsigned int guest, - unsigned int reg, - unsigned int value); -extern int post_office_read(struct zoran *zr, - unsigned int guest, - unsigned int reg); - -extern void detect_guest_activity(struct zoran *zr); - -extern void jpeg_codec_sleep(struct zoran *zr, - int sleep); -extern int jpeg_codec_reset(struct zoran *zr); - -/* zr360x7 access to raw capture */ -extern void zr36057_overlay(struct zoran *zr, - int on); -extern void write_overlay_mask(struct zoran_fh *fh, - struct v4l2_clip *vp, - int count); -extern void zr36057_set_memgrab(struct zoran *zr, - int mode); -extern int wait_grab_pending(struct zoran *zr); - -/* interrupts */ -extern void print_interrupts(struct zoran *zr); -extern void clear_interrupt_counters(struct zoran *zr); -extern irqreturn_t zoran_irq(int irq, void *dev_id); - -/* JPEG codec access */ -extern void jpeg_start(struct zoran *zr); -extern void zr36057_enable_jpg(struct zoran *zr, - enum zoran_codec_mode mode); -extern void zoran_feed_stat_com(struct zoran *zr); - -/* general */ -extern void zoran_set_pci_master(struct zoran *zr, - int set_master); -extern void zoran_init_hardware(struct zoran *zr); -extern void zr36057_restart(struct zoran *zr); - -extern const struct zoran_format zoran_formats[]; - -extern int v4l_nbufs; -extern int v4l_bufsize; -extern int jpg_nbufs; -extern int jpg_bufsize; -extern int pass_through; - -/* i2c */ -#define decoder_call(zr, o, f, args...) \ - v4l2_subdev_call(zr->decoder, o, f, ##args) -#define encoder_call(zr, o, f, args...) \ - v4l2_subdev_call(zr->encoder, o, f, ##args) - -#endif /* __ZORAN_DEVICE_H__ */ diff --git a/drivers/staging/media/zoran/zoran_driver.c b/drivers/staging/media/zoran/zoran_driver.c deleted file mode 100644 index 03bbfb723b43..000000000000 --- a/drivers/staging/media/zoran/zoran_driver.c +++ /dev/null @@ -1,2800 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Zoran zr36057/zr36067 PCI controller driver, for the - * Pinnacle/Miro DC10/DC10+/DC30/DC30+, Iomega Buz, Linux - * Media Labs LML33/LML33R10. - * - * Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx> - * - * Changes for BUZ by Wolfgang Scherr <scherr@net4you.net> - * - * Changes for DC10/DC30 by Laurent Pinchart <laurent.pinchart@skynet.be> - * - * Changes for LML33R10 by Maxim Yevtyushkin <max@linuxmedialabs.com> - * - * Changes for videodev2/v4l2 by Ronald Bultje <rbultje@ronald.bitfreak.net> - * - * Based on - * - * Miro DC10 driver - * Copyright (C) 1999 Wolfgang Scherr <scherr@net4you.net> - * - * Iomega Buz driver version 1.0 - * Copyright (C) 1999 Rainer Johanni <Rainer@Johanni.de> - * - * buz.0.0.3 - * Copyright (C) 1998 Dave Perks <dperks@ibm.net> - * - * bttv - Bt848 frame grabber driver - * Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de) - * & Marcus Metzler (mocm@thp.uni-koeln.de) - */ -#include <linux/init.h> -#include <linux/module.h> -#include <linux/delay.h> -#include <linux/slab.h> -#include <linux/pci.h> -#include <linux/vmalloc.h> -#include <linux/wait.h> - -#include <linux/interrupt.h> -#include <linux/i2c.h> -#include <linux/i2c-algo-bit.h> - -#include <linux/spinlock.h> - -#include <linux/videodev2.h> -#include <media/v4l2-common.h> -#include <media/v4l2-ioctl.h> -#include <media/v4l2-event.h> -#include "videocodec.h" - -#include <asm/byteorder.h> -#include <asm/io.h> -#include <linux/uaccess.h> -#include <linux/proc_fs.h> - -#include <linux/mutex.h> -#include "zoran.h" -#include "zoran_device.h" -#include "zoran_card.h" - - -const struct zoran_format zoran_formats[] = { - { - .name = "15-bit RGB LE", - .fourcc = V4L2_PIX_FMT_RGB555, - .colorspace = V4L2_COLORSPACE_SRGB, - .depth = 15, - .flags = ZORAN_FORMAT_CAPTURE | - ZORAN_FORMAT_OVERLAY, - .vfespfr = ZR36057_VFESPFR_RGB555|ZR36057_VFESPFR_ErrDif| - ZR36057_VFESPFR_LittleEndian, - }, { - .name = "15-bit RGB BE", - .fourcc = V4L2_PIX_FMT_RGB555X, - .colorspace = V4L2_COLORSPACE_SRGB, - .depth = 15, - .flags = ZORAN_FORMAT_CAPTURE | - ZORAN_FORMAT_OVERLAY, - .vfespfr = ZR36057_VFESPFR_RGB555|ZR36057_VFESPFR_ErrDif, - }, { - .name = "16-bit RGB LE", - .fourcc = V4L2_PIX_FMT_RGB565, - .colorspace = V4L2_COLORSPACE_SRGB, - .depth = 16, - .flags = ZORAN_FORMAT_CAPTURE | - ZORAN_FORMAT_OVERLAY, - .vfespfr = ZR36057_VFESPFR_RGB565|ZR36057_VFESPFR_ErrDif| - ZR36057_VFESPFR_LittleEndian, - }, { - .name = "16-bit RGB BE", - .fourcc = V4L2_PIX_FMT_RGB565X, - .colorspace = V4L2_COLORSPACE_SRGB, - .depth = 16, - .flags = ZORAN_FORMAT_CAPTURE | - ZORAN_FORMAT_OVERLAY, - .vfespfr = ZR36057_VFESPFR_RGB565|ZR36057_VFESPFR_ErrDif, - }, { - .name = "24-bit RGB", - .fourcc = V4L2_PIX_FMT_BGR24, - .colorspace = V4L2_COLORSPACE_SRGB, - .depth = 24, - .flags = ZORAN_FORMAT_CAPTURE | - ZORAN_FORMAT_OVERLAY, - .vfespfr = ZR36057_VFESPFR_RGB888|ZR36057_VFESPFR_Pack24, - }, { - .name = "32-bit RGB LE", - .fourcc = V4L2_PIX_FMT_BGR32, - .colorspace = V4L2_COLORSPACE_SRGB, - .depth = 32, - .flags = ZORAN_FORMAT_CAPTURE | - ZORAN_FORMAT_OVERLAY, - .vfespfr = ZR36057_VFESPFR_RGB888|ZR36057_VFESPFR_LittleEndian, - }, { - .name = "32-bit RGB BE", - .fourcc = V4L2_PIX_FMT_RGB32, - .colorspace = V4L2_COLORSPACE_SRGB, - .depth = 32, - .flags = ZORAN_FORMAT_CAPTURE | - ZORAN_FORMAT_OVERLAY, - .vfespfr = ZR36057_VFESPFR_RGB888, - }, { - .name = "4:2:2, packed, YUYV", - .fourcc = V4L2_PIX_FMT_YUYV, - .colorspace = V4L2_COLORSPACE_SMPTE170M, - .depth = 16, - .flags = ZORAN_FORMAT_CAPTURE | - ZORAN_FORMAT_OVERLAY, - .vfespfr = ZR36057_VFESPFR_YUV422, - }, { - .name = "4:2:2, packed, UYVY", - .fourcc = V4L2_PIX_FMT_UYVY, - .colorspace = V4L2_COLORSPACE_SMPTE170M, - .depth = 16, - .flags = ZORAN_FORMAT_CAPTURE | - ZORAN_FORMAT_OVERLAY, - .vfespfr = ZR36057_VFESPFR_YUV422|ZR36057_VFESPFR_LittleEndian, - }, { - .name = "Hardware-encoded Motion-JPEG", - .fourcc = V4L2_PIX_FMT_MJPEG, - .colorspace = V4L2_COLORSPACE_SMPTE170M, - .depth = 0, - .flags = ZORAN_FORMAT_CAPTURE | - ZORAN_FORMAT_PLAYBACK | - ZORAN_FORMAT_COMPRESSED, - } -}; -#define NUM_FORMATS ARRAY_SIZE(zoran_formats) - - /* small helper function for calculating buffersizes for v4l2 - * we calculate the nearest higher power-of-two, which - * will be the recommended buffersize */ -static __u32 -zoran_v4l2_calc_bufsize (struct zoran_jpg_settings *settings) -{ - __u8 div = settings->VerDcm * settings->HorDcm * settings->TmpDcm; - __u32 num = (1024 * 512) / (div); - __u32 result = 2; - - num--; - while (num) { - num >>= 1; - result <<= 1; - } - - if (result > jpg_bufsize) - return jpg_bufsize; - if (result < 8192) - return 8192; - return result; -} - -/* forward references */ -static void v4l_fbuffer_free(struct zoran_fh *fh); -static void jpg_fbuffer_free(struct zoran_fh *fh); - -/* Set mapping mode */ -static void map_mode_raw(struct zoran_fh *fh) -{ - fh->map_mode = ZORAN_MAP_MODE_RAW; - fh->buffers.buffer_size = v4l_bufsize; - fh->buffers.num_buffers = v4l_nbufs; -} -static void map_mode_jpg(struct zoran_fh *fh, int play) -{ - fh->map_mode = play ? ZORAN_MAP_MODE_JPG_PLAY : ZORAN_MAP_MODE_JPG_REC; - fh->buffers.buffer_size = jpg_bufsize; - fh->buffers.num_buffers = jpg_nbufs; -} -static inline const char *mode_name(enum zoran_map_mode mode) -{ - return mode == ZORAN_MAP_MODE_RAW ? "V4L" : "JPG"; -} - -/* - * Allocate the V4L grab buffers - * - * These have to be pysically contiguous. - */ - -static int v4l_fbuffer_alloc(struct zoran_fh *fh) -{ - struct zoran *zr = fh->zr; - int i, off; - unsigned char *mem; - - for (i = 0; i < fh->buffers.num_buffers; i++) { - if (fh->buffers.buffer[i].v4l.fbuffer) - dprintk(2, - KERN_WARNING - "%s: %s - buffer %d already allocated!?\n", - ZR_DEVNAME(zr), __func__, i); - - //udelay(20); - mem = kmalloc(fh->buffers.buffer_size, - GFP_KERNEL | __GFP_NOWARN); - if (!mem) { - v4l_fbuffer_free(fh); - return -ENOBUFS; - } - fh->buffers.buffer[i].v4l.fbuffer = mem; - fh->buffers.buffer[i].v4l.fbuffer_phys = virt_to_phys(mem); - fh->buffers.buffer[i].v4l.fbuffer_bus = virt_to_bus(mem); - for (off = 0; off < fh->buffers.buffer_size; - off += PAGE_SIZE) - SetPageReserved(virt_to_page(mem + off)); - dprintk(4, - KERN_INFO - "%s: %s - V4L frame %d mem %p (bus: 0x%llx)\n", - ZR_DEVNAME(zr), __func__, i, mem, - (unsigned long long)virt_to_bus(mem)); - } - - fh->buffers.allocated = 1; - - return 0; -} - -/* free the V4L grab buffers */ -static void v4l_fbuffer_free(struct zoran_fh *fh) -{ - struct zoran *zr = fh->zr; - int i, off; - unsigned char *mem; - - dprintk(4, KERN_INFO "%s: %s\n", ZR_DEVNAME(zr), __func__); - - for (i = 0; i < fh->buffers.num_buffers; i++) { - if (!fh->buffers.buffer[i].v4l.fbuffer) - continue; - - mem = fh->buffers.buffer[i].v4l.fbuffer; - for (off = 0; off < fh->buffers.buffer_size; - off += PAGE_SIZE) - ClearPageReserved(virt_to_page(mem + off)); - kfree(fh->buffers.buffer[i].v4l.fbuffer); - fh->buffers.buffer[i].v4l.fbuffer = NULL; - } - - fh->buffers.allocated = 0; -} - -/* - * Allocate the MJPEG grab buffers. - * - * If a Natoma chipset is present and this is a revision 1 zr36057, - * each MJPEG buffer needs to be physically contiguous. - * (RJ: This statement is from Dave Perks' original driver, - * I could never check it because I have a zr36067) - * - * RJ: The contents grab buffers needs never be accessed in the driver. - * Therefore there is no need to allocate them with vmalloc in order - * to get a contiguous virtual memory space. - * I don't understand why many other drivers first allocate them with - * vmalloc (which uses internally also get_zeroed_page, but delivers you - * virtual addresses) and then again have to make a lot of efforts - * to get the physical address. - * - * Ben Capper: - * On big-endian architectures (such as ppc) some extra steps - * are needed. When reading and writing to the stat_com array - * and fragment buffers, the device expects to see little- - * endian values. The use of cpu_to_le32() and le32_to_cpu() - * in this function (and one or two others in zoran_device.c) - * ensure that these values are always stored in little-endian - * form, regardless of architecture. The zr36057 does Very Bad - * Things on big endian architectures if the stat_com array - * and fragment buffers are not little-endian. - */ - -static int jpg_fbuffer_alloc(struct zoran_fh *fh) -{ - struct zoran *zr = fh->zr; - int i, j, off; - u8 *mem; - - for (i = 0; i < fh->buffers.num_buffers; i++) { - if (fh->buffers.buffer[i].jpg.frag_tab) - dprintk(2, - KERN_WARNING - "%s: %s - buffer %d already allocated!?\n", - ZR_DEVNAME(zr), __func__, i); - - /* Allocate fragment table for this buffer */ - - mem = (void *)get_zeroed_page(GFP_KERNEL); - if (!mem) { - dprintk(1, - KERN_ERR - "%s: %s - get_zeroed_page (frag_tab) failed for buffer %d\n", - ZR_DEVNAME(zr), __func__, i); - jpg_fbuffer_free(fh); - return -ENOBUFS; - } - fh->buffers.buffer[i].jpg.frag_tab = (__le32 *)mem; - fh->buffers.buffer[i].jpg.frag_tab_bus = virt_to_bus(mem); - - if (fh->buffers.need_contiguous) { - mem = kmalloc(fh->buffers.buffer_size, GFP_KERNEL); - if (!mem) { - dprintk(1, - KERN_ERR - "%s: %s - kmalloc failed for buffer %d\n", - ZR_DEVNAME(zr), __func__, i); - jpg_fbuffer_free(fh); - return -ENOBUFS; - } - fh->buffers.buffer[i].jpg.frag_tab[0] = - cpu_to_le32(virt_to_bus(mem)); - fh->buffers.buffer[i].jpg.frag_tab[1] = - cpu_to_le32((fh->buffers.buffer_size >> 1) | 1); - for (off = 0; off < fh->buffers.buffer_size; off += PAGE_SIZE) - SetPageReserved(virt_to_page(mem + off)); - } else { - /* jpg_bufsize is already page aligned */ - for (j = 0; j < fh->buffers.buffer_size / PAGE_SIZE; j++) { - mem = (void *)get_zeroed_page(GFP_KERNEL); - if (mem == NULL) { - dprintk(1, - KERN_ERR - "%s: %s - get_zeroed_page failed for buffer %d\n", - ZR_DEVNAME(zr), __func__, i); - jpg_fbuffer_free(fh); - return -ENOBUFS; - } - - fh->buffers.buffer[i].jpg.frag_tab[2 * j] = - cpu_to_le32(virt_to_bus(mem)); - fh->buffers.buffer[i].jpg.frag_tab[2 * j + 1] = - cpu_to_le32((PAGE_SIZE >> 2) << 1); - SetPageReserved(virt_to_page(mem)); - } - - fh->buffers.buffer[i].jpg.frag_tab[2 * j - 1] |= cpu_to_le32(1); - } - } - - dprintk(4, - KERN_DEBUG "%s: %s - %d KB allocated\n", - ZR_DEVNAME(zr), __func__, - (fh->buffers.num_buffers * fh->buffers.buffer_size) >> 10); - - fh->buffers.allocated = 1; - - return 0; -} - -/* free the MJPEG grab buffers */ -static void jpg_fbuffer_free(struct zoran_fh *fh) -{ - struct zoran *zr = fh->zr; - int i, j, off; - unsigned char *mem; - __le32 frag_tab; - struct zoran_buffer *buffer; - - dprintk(4, KERN_DEBUG "%s: %s\n", ZR_DEVNAME(zr), __func__); - - for (i = 0, buffer = &fh->buffers.buffer[0]; - i < fh->buffers.num_buffers; i++, buffer++) { - if (!buffer->jpg.frag_tab) - continue; - - if (fh->buffers.need_contiguous) { - frag_tab = buffer->jpg.frag_tab[0]; - - if (frag_tab) { - mem = bus_to_virt(le32_to_cpu(frag_tab)); - for (off = 0; off < fh->buffers.buffer_size; off += PAGE_SIZE) - ClearPageReserved(virt_to_page(mem + off)); - kfree(mem); - buffer->jpg.frag_tab[0] = 0; - buffer->jpg.frag_tab[1] = 0; - } - } else { - for (j = 0; j < fh->buffers.buffer_size / PAGE_SIZE; j++) { - frag_tab = buffer->jpg.frag_tab[2 * j]; - - if (!frag_tab) - break; - ClearPageReserved(virt_to_page(bus_to_virt(le32_to_cpu(frag_tab)))); - free_page((unsigned long)bus_to_virt(le32_to_cpu(frag_tab))); - buffer->jpg.frag_tab[2 * j] = 0; - buffer->jpg.frag_tab[2 * j + 1] = 0; - } - } - - free_page((unsigned long)buffer->jpg.frag_tab); - buffer->jpg.frag_tab = NULL; - } - - fh->buffers.allocated = 0; -} - -/* - * V4L Buffer grabbing - */ - -static int -zoran_v4l_set_format (struct zoran_fh *fh, - int width, - int height, - const struct zoran_format *format) -{ - struct zoran *zr = fh->zr; - int bpp; - - /* Check size and format of the grab wanted */ - - if (height < BUZ_MIN_HEIGHT || width < BUZ_MIN_WIDTH || - height > BUZ_MAX_HEIGHT || width > BUZ_MAX_WIDTH) { - dprintk(1, - KERN_ERR - "%s: %s - wrong frame size (%dx%d)\n", - ZR_DEVNAME(zr), __func__, width, height); - return -EINVAL; - } - - bpp = (format->depth + 7) / 8; - - /* Check against available buffer size */ - if (height * width * bpp > fh->buffers.buffer_size) { - dprintk(1, - KERN_ERR - "%s: %s - video buffer size (%d kB) is too small\n", - ZR_DEVNAME(zr), __func__, fh->buffers.buffer_size >> 10); - return -EINVAL; - } - - /* The video front end needs 4-byte alinged line sizes */ - - if ((bpp == 2 && (width & 1)) || (bpp == 3 && (width & 3))) { - dprintk(1, - KERN_ERR - "%s: %s - wrong frame alignment\n", - ZR_DEVNAME(zr), __func__); - return -EINVAL; - } - - fh->v4l_settings.width = width; - fh->v4l_settings.height = height; - fh->v4l_settings.format = format; - fh->v4l_settings.bytesperline = bpp * fh->v4l_settings.width; - - return 0; -} - -static int zoran_v4l_queue_frame(struct zoran_fh *fh, int num) -{ - struct zoran *zr = fh->zr; - unsigned long flags; - int res = 0; - - if (!fh->buffers.allocated) { - dprintk(1, - KERN_ERR - "%s: %s - buffers not yet allocated\n", - ZR_DEVNAME(zr), __func__); - res = -ENOMEM; - } - - /* No grabbing outside the buffer range! */ - if (num >= fh->buffers.num_buffers || num < 0) { - dprintk(1, - KERN_ERR - "%s: %s - buffer %d is out of range\n", - ZR_DEVNAME(zr), __func__, num); - res = -EINVAL; - } - - spin_lock_irqsave(&zr->spinlock, flags); - - if (fh->buffers.active == ZORAN_FREE) { - if (zr->v4l_buffers.active == ZORAN_FREE) { - zr->v4l_buffers = fh->buffers; - fh->buffers.active = ZORAN_ACTIVE; - } else { - dprintk(1, - KERN_ERR - "%s: %s - another session is already capturing\n", - ZR_DEVNAME(zr), __func__); - res = -EBUSY; - } - } - - /* make sure a grab isn't going on currently with this buffer */ - if (!res) { - switch (zr->v4l_buffers.buffer[num].state) { - default: - case BUZ_STATE_PEND: - if (zr->v4l_buffers.active == ZORAN_FREE) { - fh->buffers.active = ZORAN_FREE; - zr->v4l_buffers.allocated = 0; - } - res = -EBUSY; /* what are you doing? */ - break; - case BUZ_STATE_DONE: - dprintk(2, - KERN_WARNING - "%s: %s - queueing buffer %d in state DONE!?\n", - ZR_DEVNAME(zr), __func__, num); - /* fall through */ - case BUZ_STATE_USER: - /* since there is at least one unused buffer there's room for at least - * one more pend[] entry */ - zr->v4l_pend[zr->v4l_pend_head++ & V4L_MASK_FRAME] = num; - zr->v4l_buffers.buffer[num].state = BUZ_STATE_PEND; - zr->v4l_buffers.buffer[num].bs.length = - fh->v4l_settings.bytesperline * - zr->v4l_settings.height; - fh->buffers.buffer[num] = zr->v4l_buffers.buffer[num]; - break; - } - } - - spin_unlock_irqrestore(&zr->spinlock, flags); - - if (!res && zr->v4l_buffers.active == ZORAN_FREE) - zr->v4l_buffers.active = fh->buffers.active; - - return res; -} - -/* - * Sync on a V4L buffer - */ - -static int v4l_sync(struct zoran_fh *fh, int frame) -{ - struct zoran *zr = fh->zr; - unsigned long flags; - - if (fh->buffers.active == ZORAN_FREE) { - dprintk(1, - KERN_ERR - "%s: %s - no grab active for this session\n", - ZR_DEVNAME(zr), __func__); - return -EINVAL; - } - - /* check passed-in frame number */ - if (frame >= fh->buffers.num_buffers || frame < 0) { - dprintk(1, - KERN_ERR "%s: %s - frame %d is invalid\n", - ZR_DEVNAME(zr), __func__, frame); - return -EINVAL; - } - - /* Check if is buffer was queued at all */ - if (zr->v4l_buffers.buffer[frame].state == BUZ_STATE_USER) { - dprintk(1, - KERN_ERR - "%s: %s - attempt to sync on a buffer which was not queued?\n", - ZR_DEVNAME(zr), __func__); - return -EPROTO; - } - - mutex_unlock(&zr->lock); - /* wait on this buffer to get ready */ - if (!wait_event_interruptible_timeout(zr->v4l_capq, - (zr->v4l_buffers.buffer[frame].state != BUZ_STATE_PEND), 10*HZ)) { - mutex_lock(&zr->lock); - return -ETIME; - } - mutex_lock(&zr->lock); - if (signal_pending(current)) - return -ERESTARTSYS; - - /* buffer should now be in BUZ_STATE_DONE */ - if (zr->v4l_buffers.buffer[frame].state != BUZ_STATE_DONE) - dprintk(2, - KERN_ERR "%s: %s - internal state error\n", - ZR_DEVNAME(zr), __func__); - - zr->v4l_buffers.buffer[frame].state = BUZ_STATE_USER; - fh->buffers.buffer[frame] = zr->v4l_buffers.buffer[frame]; - - spin_lock_irqsave(&zr->spinlock, flags); - - /* Check if streaming capture has finished */ - if (zr->v4l_pend_tail == zr->v4l_pend_head) { - zr36057_set_memgrab(zr, 0); - if (zr->v4l_buffers.active == ZORAN_ACTIVE) { - fh->buffers.active = zr->v4l_buffers.active = ZORAN_FREE; - zr->v4l_buffers.allocated = 0; - } - } - - spin_unlock_irqrestore(&zr->spinlock, flags); - - return 0; -} - -/* - * Queue a MJPEG buffer for capture/playback - */ - -static int zoran_jpg_queue_frame(struct zoran_fh *fh, int num, - enum zoran_codec_mode mode) -{ - struct zoran *zr = fh->zr; - unsigned long flags; - int res = 0; - - /* Check if buffers are allocated */ - if (!fh->buffers.allocated) { - dprintk(1, - KERN_ERR - "%s: %s - buffers not yet allocated\n", - ZR_DEVNAME(zr), __func__); - return -ENOMEM; - } - - /* No grabbing outside the buffer range! */ - if (num >= fh->buffers.num_buffers || num < 0) { - dprintk(1, - KERN_ERR - "%s: %s - buffer %d out of range\n", - ZR_DEVNAME(zr), __func__, num); - return -EINVAL; - } - - /* what is the codec mode right now? */ - if (zr->codec_mode == BUZ_MODE_IDLE) { - zr->jpg_settings = fh->jpg_settings; - } else if (zr->codec_mode != mode) { - /* wrong codec mode active - invalid */ - dprintk(1, - KERN_ERR - "%s: %s - codec in wrong mode\n", - ZR_DEVNAME(zr), __func__); - return -EINVAL; - } - - if (fh->buffers.active == ZORAN_FREE) { - if (zr->jpg_buffers.active == ZORAN_FREE) { - zr->jpg_buffers = fh->buffers; - fh->buffers.active = ZORAN_ACTIVE; - } else { - dprintk(1, - KERN_ERR - "%s: %s - another session is already capturing\n", - ZR_DEVNAME(zr), __func__); - res = -EBUSY; - } - } - - if (!res && zr->codec_mode == BUZ_MODE_IDLE) { - /* Ok load up the jpeg codec */ - zr36057_enable_jpg(zr, mode); - } - - spin_lock_irqsave(&zr->spinlock, flags); - - if (!res) { - switch (zr->jpg_buffers.buffer[num].state) { - case BUZ_STATE_DONE: - dprintk(2, - KERN_WARNING - "%s: %s - queuing frame in BUZ_STATE_DONE state!?\n", - ZR_DEVNAME(zr), __func__); - /* fall through */ - case BUZ_STATE_USER: - /* since there is at least one unused buffer there's room for at - *least one more pend[] entry */ - zr->jpg_pend[zr->jpg_que_head++ & BUZ_MASK_FRAME] = num; - zr->jpg_buffers.buffer[num].state = BUZ_STATE_PEND; - fh->buffers.buffer[num] = zr->jpg_buffers.buffer[num]; - zoran_feed_stat_com(zr); - break; - default: - case BUZ_STATE_DMA: - case BUZ_STATE_PEND: - if (zr->jpg_buffers.active == ZORAN_FREE) { - fh->buffers.active = ZORAN_FREE; - zr->jpg_buffers.allocated = 0; - } - res = -EBUSY; /* what are you doing? */ - break; - } - } - - spin_unlock_irqrestore(&zr->spinlock, flags); - - if (!res && zr->jpg_buffers.active == ZORAN_FREE) - zr->jpg_buffers.active = fh->buffers.active; - - return res; -} - -static int jpg_qbuf(struct zoran_fh *fh, int frame, enum zoran_codec_mode mode) -{ - struct zoran *zr = fh->zr; - int res = 0; - - /* Does the user want to stop streaming? */ - if (frame < 0) { - if (zr->codec_mode == mode) { - if (fh->buffers.active == ZORAN_FREE) { - dprintk(1, - KERN_ERR - "%s: %s(-1) - session not active\n", - ZR_DEVNAME(zr), __func__); - return -EINVAL; - } - fh->buffers.active = zr->jpg_buffers.active = ZORAN_FREE; - zr->jpg_buffers.allocated = 0; - zr36057_enable_jpg(zr, BUZ_MODE_IDLE); - return 0; - } else { - dprintk(1, - KERN_ERR - "%s: %s - stop streaming but not in streaming mode\n", - ZR_DEVNAME(zr), __func__); - return -EINVAL; - } - } - - if ((res = zoran_jpg_queue_frame(fh, frame, mode))) - return res; - - /* Start the jpeg codec when the first frame is queued */ - if (!res && zr->jpg_que_head == 1) - jpeg_start(zr); - - return res; -} - -/* - * Sync on a MJPEG buffer - */ - -static int jpg_sync(struct zoran_fh *fh, struct zoran_sync *bs) -{ - struct zoran *zr = fh->zr; - unsigned long flags; - int frame; - - if (fh->buffers.active == ZORAN_FREE) { - dprintk(1, - KERN_ERR - "%s: %s - capture is not currently active\n", - ZR_DEVNAME(zr), __func__); - return -EINVAL; - } - if (zr->codec_mode != BUZ_MODE_MOTION_DECOMPRESS && - zr->codec_mode != BUZ_MODE_MOTION_COMPRESS) { - dprintk(1, - KERN_ERR - "%s: %s - codec not in streaming mode\n", - ZR_DEVNAME(zr), __func__); - return -EINVAL; - } - mutex_unlock(&zr->lock); - if (!wait_event_interruptible_timeout(zr->jpg_capq, - (zr->jpg_que_tail != zr->jpg_dma_tail || - zr->jpg_dma_tail == zr->jpg_dma_head), - 10*HZ)) { - int isr; - - btand(~ZR36057_JMC_Go_en, ZR36057_JMC); - udelay(1); - zr->codec->control(zr->codec, CODEC_G_STATUS, - sizeof(isr), &isr); - mutex_lock(&zr->lock); - dprintk(1, - KERN_ERR - "%s: %s - timeout: codec isr=0x%02x\n", - ZR_DEVNAME(zr), __func__, isr); - - return -ETIME; - - } - mutex_lock(&zr->lock); - if (signal_pending(current)) - return -ERESTARTSYS; - - spin_lock_irqsave(&zr->spinlock, flags); - - if (zr->jpg_dma_tail != zr->jpg_dma_head) - frame = zr->jpg_pend[zr->jpg_que_tail++ & BUZ_MASK_FRAME]; - else - frame = zr->jpg_pend[zr->jpg_que_tail & BUZ_MASK_FRAME]; - - /* buffer should now be in BUZ_STATE_DONE */ - if (zr->jpg_buffers.buffer[frame].state != BUZ_STATE_DONE) - dprintk(2, - KERN_ERR "%s: %s - internal state error\n", - ZR_DEVNAME(zr), __func__); - - *bs = zr->jpg_buffers.buffer[frame].bs; - bs->frame = frame; - zr->jpg_buffers.buffer[frame].state = BUZ_STATE_USER; - fh->buffers.buffer[frame] = zr->jpg_buffers.buffer[frame]; - - spin_unlock_irqrestore(&zr->spinlock, flags); - - return 0; -} - -static void zoran_open_init_session(struct zoran_fh *fh) -{ - int i; - struct zoran *zr = fh->zr; - - /* Per default, map the V4L Buffers */ - map_mode_raw(fh); - - /* take over the card's current settings */ - fh->overlay_settings = zr->overlay_settings; - fh->overlay_settings.is_set = 0; - fh->overlay_settings.format = zr->overlay_settings.format; - fh->overlay_active = ZORAN_FREE; - - /* v4l settings */ - fh->v4l_settings = zr->v4l_settings; - /* jpg settings */ - fh->jpg_settings = zr->jpg_settings; - - /* buffers */ - memset(&fh->buffers, 0, sizeof(fh->buffers)); - for (i = 0; i < MAX_FRAME; i++) { - fh->buffers.buffer[i].state = BUZ_STATE_USER; /* nothing going on */ - fh->buffers.buffer[i].bs.frame = i; - } - fh->buffers.allocated = 0; - fh->buffers.active = ZORAN_FREE; -} - -static void zoran_close_end_session(struct zoran_fh *fh) -{ - struct zoran *zr = fh->zr; - - /* overlay */ - if (fh->overlay_active != ZORAN_FREE) { - fh->overlay_active = zr->overlay_active = ZORAN_FREE; - zr->v4l_overlay_active = 0; - if (!zr->v4l_memgrab_active) - zr36057_overlay(zr, 0); - zr->overlay_mask = NULL; - } - - if (fh->map_mode == ZORAN_MAP_MODE_RAW) { - /* v4l capture */ - if (fh->buffers.active != ZORAN_FREE) { - unsigned long flags; - - spin_lock_irqsave(&zr->spinlock, flags); - zr36057_set_memgrab(zr, 0); - zr->v4l_buffers.allocated = 0; - zr->v4l_buffers.active = fh->buffers.active = ZORAN_FREE; - spin_unlock_irqrestore(&zr->spinlock, flags); - } - - /* v4l buffers */ - if (fh->buffers.allocated) - v4l_fbuffer_free(fh); - } else { - /* jpg capture */ - if (fh->buffers.active != ZORAN_FREE) { - zr36057_enable_jpg(zr, BUZ_MODE_IDLE); - zr->jpg_buffers.allocated = 0; - zr->jpg_buffers.active = fh->buffers.active = ZORAN_FREE; - } - - /* jpg buffers */ - if (fh->buffers.allocated) - jpg_fbuffer_free(fh); - } -} - -/* - * Open a zoran card. Right now the flags stuff is just playing - */ - -static int zoran_open(struct file *file) -{ - struct zoran *zr = video_drvdata(file); - struct zoran_fh *fh; - int res, first_open = 0; - - dprintk(2, KERN_INFO "%s: %s(%s, pid=[%d]), users(-)=%d\n", - ZR_DEVNAME(zr), __func__, current->comm, task_pid_nr(current), zr->user + 1); - - mutex_lock(&zr->lock); - - if (zr->user >= 2048) { - dprintk(1, KERN_ERR "%s: too many users (%d) on device\n", - ZR_DEVNAME(zr), zr->user); - res = -EBUSY; - goto fail_unlock; - } - - /* now, create the open()-specific file_ops struct */ - fh = kzalloc(sizeof(struct zoran_fh), GFP_KERNEL); - if (!fh) { - dprintk(1, - KERN_ERR - "%s: %s - allocation of zoran_fh failed\n", - ZR_DEVNAME(zr), __func__); - res = -ENOMEM; - goto fail_unlock; - } - v4l2_fh_init(&fh->fh, video_devdata(file)); - - /* used to be BUZ_MAX_WIDTH/HEIGHT, but that gives overflows - * on norm-change! */ - fh->overlay_mask = - kmalloc(array3_size((768 + 31) / 32, 576, 4), GFP_KERNEL); - if (!fh->overlay_mask) { - dprintk(1, - KERN_ERR - "%s: %s - allocation of overlay_mask failed\n", - ZR_DEVNAME(zr), __func__); - res = -ENOMEM; - goto fail_fh; - } - - if (zr->user++ == 0) - first_open = 1; - - /* default setup - TODO: look at flags */ - if (first_open) { /* First device open */ - zr36057_restart(zr); - zoran_open_init_params(zr); - zoran_init_hardware(zr); - - btor(ZR36057_ICR_IntPinEn, ZR36057_ICR); - } - - /* set file_ops stuff */ - file->private_data = fh; - fh->zr = zr; - zoran_open_init_session(fh); - v4l2_fh_add(&fh->fh); - mutex_unlock(&zr->lock); - - return 0; - -fail_fh: - v4l2_fh_exit(&fh->fh); - kfree(fh); -fail_unlock: - mutex_unlock(&zr->lock); - - dprintk(2, KERN_INFO "%s: open failed (%d), users(-)=%d\n", - ZR_DEVNAME(zr), res, zr->user); - - return res; -} - -static int -zoran_close(struct file *file) -{ - struct zoran_fh *fh = file->private_data; - struct zoran *zr = fh->zr; - - dprintk(2, KERN_INFO "%s: %s(%s, pid=[%d]), users(+)=%d\n", - ZR_DEVNAME(zr), __func__, current->comm, task_pid_nr(current), zr->user - 1); - - /* kernel locks (fs/device.c), so don't do that ourselves - * (prevents deadlocks) */ - mutex_lock(&zr->lock); - - zoran_close_end_session(fh); - - if (zr->user-- == 1) { /* Last process */ - /* Clean up JPEG process */ - wake_up_interruptible(&zr->jpg_capq); - zr36057_enable_jpg(zr, BUZ_MODE_IDLE); - zr->jpg_buffers.allocated = 0; - zr->jpg_buffers.active = ZORAN_FREE; - - /* disable interrupts */ - btand(~ZR36057_ICR_IntPinEn, ZR36057_ICR); - - if (zr36067_debug > 1) - print_interrupts(zr); - - /* Overlay off */ - zr->v4l_overlay_active = 0; - zr36057_overlay(zr, 0); - zr->overlay_mask = NULL; - - /* capture off */ - wake_up_interruptible(&zr->v4l_capq); - zr36057_set_memgrab(zr, 0); - zr->v4l_buffers.allocated = 0; - zr->v4l_buffers.active = ZORAN_FREE; - zoran_set_pci_master(zr, 0); - - if (!pass_through) { /* Switch to color bar */ - decoder_call(zr, video, s_stream, 0); - encoder_call(zr, video, s_routing, 2, 0, 0); - } - } - mutex_unlock(&zr->lock); - - v4l2_fh_del(&fh->fh); - v4l2_fh_exit(&fh->fh); - kfree(fh->overlay_mask); - kfree(fh); - - dprintk(4, KERN_INFO "%s: %s done\n", ZR_DEVNAME(zr), __func__); - - return 0; -} - -static int setup_fbuffer(struct zoran_fh *fh, - void *base, - const struct zoran_format *fmt, - int width, - int height, - int bytesperline) -{ - struct zoran *zr = fh->zr; - - /* (Ronald) v4l/v4l2 guidelines */ - if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RAWIO)) - return -EPERM; - - /* Don't allow frame buffer overlay if PCI or AGP is buggy, or on - ALi Magik (that needs very low latency while the card needs a - higher value always) */ - - if (pci_pci_problems & (PCIPCI_FAIL | PCIAGP_FAIL | PCIPCI_ALIMAGIK)) - return -ENXIO; - - /* we need a bytesperline value, even if not given */ - if (!bytesperline) - bytesperline = width * ((fmt->depth + 7) & ~7) / 8; - -#if 0 - if (zr->overlay_active) { - /* dzjee... stupid users... don't even bother to turn off - * overlay before changing the memory location... - * normally, we would return errors here. However, one of - * the tools that does this is... xawtv! and since xawtv - * is used by +/- 99% of the users, we'd rather be user- - * friendly and silently do as if nothing went wrong */ - dprintk(3, - KERN_ERR - "%s: %s - forced overlay turnoff because framebuffer changed\n", - ZR_DEVNAME(zr), __func__); - zr36057_overlay(zr, 0); - } -#endif - - if (!(fmt->flags & ZORAN_FORMAT_OVERLAY)) { - dprintk(1, - KERN_ERR - "%s: %s - no valid overlay format given\n", - ZR_DEVNAME(zr), __func__); - return -EINVAL; - } - if (height <= 0 || width <= 0 || bytesperline <= 0) { - dprintk(1, - KERN_ERR - "%s: %s - invalid height/width/bpl value (%d|%d|%d)\n", - ZR_DEVNAME(zr), __func__, width, height, bytesperline); - return -EINVAL; - } - if (bytesperline & 3) { - dprintk(1, - KERN_ERR - "%s: %s - bytesperline (%d) must be 4-byte aligned\n", - ZR_DEVNAME(zr), __func__, bytesperline); - return -EINVAL; - } - - zr->vbuf_base = (void *) ((unsigned long) base & ~3); - zr->vbuf_height = height; - zr->vbuf_width = width; - zr->vbuf_depth = fmt->depth; - zr->overlay_settings.format = fmt; - zr->vbuf_bytesperline = bytesperline; - - /* The user should set new window parameters */ - zr->overlay_settings.is_set = 0; - - return 0; -} - - -static int setup_window(struct zoran_fh *fh, - int x, - int y, - int width, - int height, - struct v4l2_clip __user *clips, - unsigned int clipcount, - void __user *bitmap) -{ - struct zoran *zr = fh->zr; - struct v4l2_clip *vcp = NULL; - int on, end; - - - if (!zr->vbuf_base) { - dprintk(1, - KERN_ERR - "%s: %s - frame buffer has to be set first\n", - ZR_DEVNAME(zr), __func__); - return -EINVAL; - } - - if (!fh->overlay_settings.format) { - dprintk(1, - KERN_ERR - "%s: %s - no overlay format set\n", - ZR_DEVNAME(zr), __func__); - return -EINVAL; - } - - if (clipcount > 2048) { - dprintk(1, - KERN_ERR - "%s: %s - invalid clipcount\n", - ZR_DEVNAME(zr), __func__); - return -EINVAL; - } - - /* - * The video front end needs 4-byte alinged line sizes, we correct that - * silently here if necessary - */ - if (zr->vbuf_depth == 15 || zr->vbuf_depth == 16) { - end = (x + width) & ~1; /* round down */ - x = (x + 1) & ~1; /* round up */ - width = end - x; - } - - if (zr->vbuf_depth == 24) { - end = (x + width) & ~3; /* round down */ - x = (x + 3) & ~3; /* round up */ - width = end - x; - } - - if (width > BUZ_MAX_WIDTH) - width = BUZ_MAX_WIDTH; - if (height > BUZ_MAX_HEIGHT) - height = BUZ_MAX_HEIGHT; - - /* Check for invalid parameters */ - if (width < BUZ_MIN_WIDTH || height < BUZ_MIN_HEIGHT || - width > BUZ_MAX_WIDTH || height > BUZ_MAX_HEIGHT) { - dprintk(1, - KERN_ERR - "%s: %s - width = %d or height = %d invalid\n", - ZR_DEVNAME(zr), __func__, width, height); - return -EINVAL; - } - - fh->overlay_settings.x = x; - fh->overlay_settings.y = y; - fh->overlay_settings.width = width; - fh->overlay_settings.height = height; - fh->overlay_settings.clipcount = clipcount; - - /* - * If an overlay is running, we have to switch it off - * and switch it on again in order to get the new settings in effect. - * - * We also want to avoid that the overlay mask is written - * when an overlay is running. - */ - - on = zr->v4l_overlay_active && !zr->v4l_memgrab_active && - zr->overlay_active != ZORAN_FREE && - fh->overlay_active != ZORAN_FREE; - if (on) - zr36057_overlay(zr, 0); - - /* - * Write the overlay mask if clips are wanted. - * We prefer a bitmap. - */ - if (bitmap) { - /* fake value - it just means we want clips */ - fh->overlay_settings.clipcount = 1; - - if (copy_from_user(fh->overlay_mask, bitmap, - (width * height + 7) / 8)) { - return -EFAULT; - } - } else if (clipcount) { - /* write our own bitmap from the clips */ - vcp = vmalloc(array_size(sizeof(struct v4l2_clip), - clipcount + 4)); - if (vcp == NULL) { - dprintk(1, - KERN_ERR - "%s: %s - Alloc of clip mask failed\n", - ZR_DEVNAME(zr), __func__); - return -ENOMEM; - } - if (copy_from_user - (vcp, clips, sizeof(struct v4l2_clip) * clipcount)) { - vfree(vcp); - return -EFAULT; - } - write_overlay_mask(fh, vcp, clipcount); - vfree(vcp); - } - - fh->overlay_settings.is_set = 1; - if (fh->overlay_active != ZORAN_FREE && - zr->overlay_active != ZORAN_FREE) - zr->overlay_settings = fh->overlay_settings; - - if (on) - zr36057_overlay(zr, 1); - - /* Make sure the changes come into effect */ - return wait_grab_pending(zr); -} - -static int setup_overlay(struct zoran_fh *fh, int on) -{ - struct zoran *zr = fh->zr; - - /* If there is nothing to do, return immediately */ - if ((on && fh->overlay_active != ZORAN_FREE) || - (!on && fh->overlay_active == ZORAN_FREE)) - return 0; - - /* check whether we're touching someone else's overlay */ - if (on && zr->overlay_active != ZORAN_FREE && - fh->overlay_active == ZORAN_FREE) { - dprintk(1, - KERN_ERR - "%s: %s - overlay is already active for another session\n", - ZR_DEVNAME(zr), __func__); - return -EBUSY; - } - if (!on && zr->overlay_active != ZORAN_FREE && - fh->overlay_active == ZORAN_FREE) { - dprintk(1, - KERN_ERR - "%s: %s - you cannot cancel someone else's session\n", - ZR_DEVNAME(zr), __func__); - return -EPERM; - } - - if (on == 0) { - zr->overlay_active = fh->overlay_active = ZORAN_FREE; - zr->v4l_overlay_active = 0; - /* When a grab is running, the video simply - * won't be switched on any more */ - if (!zr->v4l_memgrab_active) - zr36057_overlay(zr, 0); - zr->overlay_mask = NULL; - } else { - if (!zr->vbuf_base || !fh->overlay_settings.is_set) { - dprintk(1, - KERN_ERR - "%s: %s - buffer or window not set\n", - ZR_DEVNAME(zr), __func__); - return -EINVAL; - } - if (!fh->overlay_settings.format) { - dprintk(1, - KERN_ERR - "%s: %s - no overlay format set\n", - ZR_DEVNAME(zr), __func__); - return -EINVAL; - } - zr->overlay_active = fh->overlay_active = ZORAN_LOCKED; - zr->v4l_overlay_active = 1; - zr->overlay_mask = fh->overlay_mask; - zr->overlay_settings = fh->overlay_settings; - if (!zr->v4l_memgrab_active) - zr36057_overlay(zr, 1); - /* When a grab is running, the video will be - * switched on when grab is finished */ - } - - /* Make sure the changes come into effect */ - return wait_grab_pending(zr); -} - -/* get the status of a buffer in the clients buffer queue */ -static int zoran_v4l2_buffer_status(struct zoran_fh *fh, - struct v4l2_buffer *buf, int num) -{ - struct zoran *zr = fh->zr; - unsigned long flags; - - buf->flags = V4L2_BUF_FLAG_MAPPED | V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; - - switch (fh->map_mode) { - case ZORAN_MAP_MODE_RAW: - /* check range */ - if (num < 0 || num >= fh->buffers.num_buffers || - !fh->buffers.allocated) { - dprintk(1, - KERN_ERR - "%s: %s - wrong number or buffers not allocated\n", - ZR_DEVNAME(zr), __func__); - return -EINVAL; - } - - spin_lock_irqsave(&zr->spinlock, flags); - dprintk(3, - KERN_DEBUG - "%s: %s() - raw active=%c, buffer %d: state=%c, map=%c\n", - ZR_DEVNAME(zr), __func__, - "FAL"[fh->buffers.active], num, - "UPMD"[zr->v4l_buffers.buffer[num].state], - fh->buffers.buffer[num].map ? 'Y' : 'N'); - spin_unlock_irqrestore(&zr->spinlock, flags); - - buf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - buf->length = fh->buffers.buffer_size; - - /* get buffer */ - buf->bytesused = fh->buffers.buffer[num].bs.length; - if (fh->buffers.buffer[num].state == BUZ_STATE_DONE || - fh->buffers.buffer[num].state == BUZ_STATE_USER) { - buf->sequence = fh->buffers.buffer[num].bs.seq; - buf->flags |= V4L2_BUF_FLAG_DONE; - buf->timestamp = ns_to_timeval(fh->buffers.buffer[num].bs.ts); - } else { - buf->flags |= V4L2_BUF_FLAG_QUEUED; - } - - if (fh->v4l_settings.height <= BUZ_MAX_HEIGHT / 2) - buf->field = V4L2_FIELD_TOP; - else - buf->field = V4L2_FIELD_INTERLACED; - - break; - - case ZORAN_MAP_MODE_JPG_REC: - case ZORAN_MAP_MODE_JPG_PLAY: - - /* check range */ - if (num < 0 || num >= fh->buffers.num_buffers || - !fh->buffers.allocated) { - dprintk(1, - KERN_ERR - "%s: %s - wrong number or buffers not allocated\n", - ZR_DEVNAME(zr), __func__); - return -EINVAL; - } - - buf->type = (fh->map_mode == ZORAN_MAP_MODE_JPG_REC) ? - V4L2_BUF_TYPE_VIDEO_CAPTURE : - V4L2_BUF_TYPE_VIDEO_OUTPUT; - buf->length = fh->buffers.buffer_size; - - /* these variables are only written after frame has been captured */ - if (fh->buffers.buffer[num].state == BUZ_STATE_DONE || - fh->buffers.buffer[num].state == BUZ_STATE_USER) { - buf->sequence = fh->buffers.buffer[num].bs.seq; - buf->timestamp = ns_to_timeval(fh->buffers.buffer[num].bs.ts); - buf->bytesused = fh->buffers.buffer[num].bs.length; - buf->flags |= V4L2_BUF_FLAG_DONE; - } else { - buf->flags |= V4L2_BUF_FLAG_QUEUED; - } - - /* which fields are these? */ - if (fh->jpg_settings.TmpDcm != 1) - buf->field = fh->jpg_settings.odd_even ? - V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM; - else - buf->field = fh->jpg_settings.odd_even ? - V4L2_FIELD_SEQ_TB : V4L2_FIELD_SEQ_BT; - - break; - - default: - - dprintk(5, - KERN_ERR - "%s: %s - invalid buffer type|map_mode (%d|%d)\n", - ZR_DEVNAME(zr), __func__, buf->type, fh->map_mode); - return -EINVAL; - } - - buf->memory = V4L2_MEMORY_MMAP; - buf->index = num; - buf->m.offset = buf->length * num; - - return 0; -} - -static int -zoran_set_norm (struct zoran *zr, - v4l2_std_id norm) -{ - int on; - - if (zr->v4l_buffers.active != ZORAN_FREE || - zr->jpg_buffers.active != ZORAN_FREE) { - dprintk(1, - KERN_WARNING - "%s: %s called while in playback/capture mode\n", - ZR_DEVNAME(zr), __func__); - return -EBUSY; - } - - if (!(norm & zr->card.norms)) { - dprintk(1, - KERN_ERR "%s: %s - unsupported norm %llx\n", - ZR_DEVNAME(zr), __func__, norm); - return -EINVAL; - } - - if (norm & V4L2_STD_SECAM) - zr->timing = zr->card.tvn[2]; - else if (norm & V4L2_STD_NTSC) - zr->timing = zr->card.tvn[1]; - else - zr->timing = zr->card.tvn[0]; - - /* We switch overlay off and on since a change in the - * norm needs different VFE settings */ - on = zr->overlay_active && !zr->v4l_memgrab_active; - if (on) - zr36057_overlay(zr, 0); - - decoder_call(zr, video, s_std, norm); - encoder_call(zr, video, s_std_output, norm); - - if (on) - zr36057_overlay(zr, 1); - - /* Make sure the changes come into effect */ - zr->norm = norm; - - return 0; -} - -static int -zoran_set_input (struct zoran *zr, - int input) -{ - if (input == zr->input) { - return 0; - } - - if (zr->v4l_buffers.active != ZORAN_FREE || - zr->jpg_buffers.active != ZORAN_FREE) { - dprintk(1, - KERN_WARNING - "%s: %s called while in playback/capture mode\n", - ZR_DEVNAME(zr), __func__); - return -EBUSY; - } - - if (input < 0 || input >= zr->card.inputs) { - dprintk(1, - KERN_ERR - "%s: %s - unsupported input %d\n", - ZR_DEVNAME(zr), __func__, input); - return -EINVAL; - } - - zr->input = input; - - decoder_call(zr, video, s_routing, - zr->card.input[input].muxsel, 0, 0); - - return 0; -} - -/* - * ioctl routine - */ - -static int zoran_querycap(struct file *file, void *__fh, struct v4l2_capability *cap) -{ - struct zoran_fh *fh = __fh; - struct zoran *zr = fh->zr; - - strscpy(cap->card, ZR_DEVNAME(zr), sizeof(cap->card)); - strscpy(cap->driver, "zoran", sizeof(cap->driver)); - snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s", - pci_name(zr->pci_dev)); - cap->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_VIDEO_OVERLAY; - cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; - return 0; -} - -static int zoran_enum_fmt(struct zoran *zr, struct v4l2_fmtdesc *fmt, int flag) -{ - unsigned int num, i; - - for (num = i = 0; i < NUM_FORMATS; i++) { - if (zoran_formats[i].flags & flag && num++ == fmt->index) { - strncpy(fmt->description, zoran_formats[i].name, - sizeof(fmt->description) - 1); - /* fmt struct pre-zeroed, so adding '\0' not needed */ - fmt->pixelformat = zoran_formats[i].fourcc; - if (zoran_formats[i].flags & ZORAN_FORMAT_COMPRESSED) - fmt->flags |= V4L2_FMT_FLAG_COMPRESSED; - return 0; - } - } - return -EINVAL; -} - -static int zoran_enum_fmt_vid_cap(struct file *file, void *__fh, - struct v4l2_fmtdesc *f) -{ - struct zoran_fh *fh = __fh; - struct zoran *zr = fh->zr; - - return zoran_enum_fmt(zr, f, ZORAN_FORMAT_CAPTURE); -} - -static int zoran_enum_fmt_vid_out(struct file *file, void *__fh, - struct v4l2_fmtdesc *f) -{ - struct zoran_fh *fh = __fh; - struct zoran *zr = fh->zr; - - return zoran_enum_fmt(zr, f, ZORAN_FORMAT_PLAYBACK); -} - -static int zoran_enum_fmt_vid_overlay(struct file *file, void *__fh, - struct v4l2_fmtdesc *f) -{ - struct zoran_fh *fh = __fh; - struct zoran *zr = fh->zr; - - return zoran_enum_fmt(zr, f, ZORAN_FORMAT_OVERLAY); -} - -static int zoran_g_fmt_vid_out(struct file *file, void *__fh, - struct v4l2_format *fmt) -{ - struct zoran_fh *fh = __fh; - - fmt->fmt.pix.width = fh->jpg_settings.img_width / fh->jpg_settings.HorDcm; - fmt->fmt.pix.height = fh->jpg_settings.img_height * 2 / - (fh->jpg_settings.VerDcm * fh->jpg_settings.TmpDcm); - fmt->fmt.pix.sizeimage = zoran_v4l2_calc_bufsize(&fh->jpg_settings); - fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG; - if (fh->jpg_settings.TmpDcm == 1) - fmt->fmt.pix.field = (fh->jpg_settings.odd_even ? - V4L2_FIELD_SEQ_TB : V4L2_FIELD_SEQ_BT); - else - fmt->fmt.pix.field = (fh->jpg_settings.odd_even ? - V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM); - fmt->fmt.pix.bytesperline = 0; - fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; - - return 0; -} - -static int zoran_g_fmt_vid_cap(struct file *file, void *__fh, - struct v4l2_format *fmt) -{ - struct zoran_fh *fh = __fh; - struct zoran *zr = fh->zr; - - if (fh->map_mode != ZORAN_MAP_MODE_RAW) - return zoran_g_fmt_vid_out(file, fh, fmt); - - fmt->fmt.pix.width = fh->v4l_settings.width; - fmt->fmt.pix.height = fh->v4l_settings.height; - fmt->fmt.pix.sizeimage = fh->v4l_settings.bytesperline * - fh->v4l_settings.height; - fmt->fmt.pix.pixelformat = fh->v4l_settings.format->fourcc; - fmt->fmt.pix.colorspace = fh->v4l_settings.format->colorspace; - fmt->fmt.pix.bytesperline = fh->v4l_settings.bytesperline; - if (BUZ_MAX_HEIGHT < (fh->v4l_settings.height * 2)) - fmt->fmt.pix.field = V4L2_FIELD_INTERLACED; - else - fmt->fmt.pix.field = V4L2_FIELD_TOP; - return 0; -} - -static int zoran_g_fmt_vid_overlay(struct file *file, void *__fh, - struct v4l2_format *fmt) -{ - struct zoran_fh *fh = __fh; - struct zoran *zr = fh->zr; - - fmt->fmt.win.w.left = fh->overlay_settings.x; - fmt->fmt.win.w.top = fh->overlay_settings.y; - fmt->fmt.win.w.width = fh->overlay_settings.width; - fmt->fmt.win.w.height = fh->overlay_settings.height; - if (fh->overlay_settings.width * 2 > BUZ_MAX_HEIGHT) - fmt->fmt.win.field = V4L2_FIELD_INTERLACED; - else - fmt->fmt.win.field = V4L2_FIELD_TOP; - - return 0; -} - -static int zoran_try_fmt_vid_overlay(struct file *file, void *__fh, - struct v4l2_format *fmt) -{ - struct zoran_fh *fh = __fh; - struct zoran *zr = fh->zr; - - if (fmt->fmt.win.w.width > BUZ_MAX_WIDTH) - fmt->fmt.win.w.width = BUZ_MAX_WIDTH; - if (fmt->fmt.win.w.width < BUZ_MIN_WIDTH) - fmt->fmt.win.w.width = BUZ_MIN_WIDTH; - if (fmt->fmt.win.w.height > BUZ_MAX_HEIGHT) - fmt->fmt.win.w.height = BUZ_MAX_HEIGHT; - if (fmt->fmt.win.w.height < BUZ_MIN_HEIGHT) - fmt->fmt.win.w.height = BUZ_MIN_HEIGHT; - - return 0; -} - -static int zoran_try_fmt_vid_out(struct file *file, void *__fh, - struct v4l2_format *fmt) -{ - struct zoran_fh *fh = __fh; - struct zoran *zr = fh->zr; - struct zoran_jpg_settings settings; - int res = 0; - - if (fmt->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG) - return -EINVAL; - - settings = fh->jpg_settings; - - /* we actually need to set 'real' parameters now */ - if ((fmt->fmt.pix.height * 2) > BUZ_MAX_HEIGHT) - settings.TmpDcm = 1; - else - settings.TmpDcm = 2; - settings.decimation = 0; - if (fmt->fmt.pix.height <= fh->jpg_settings.img_height / 2) - settings.VerDcm = 2; - else - settings.VerDcm = 1; - if (fmt->fmt.pix.width <= fh->jpg_settings.img_width / 4) - settings.HorDcm = 4; - else if (fmt->fmt.pix.width <= fh->jpg_settings.img_width / 2) - settings.HorDcm = 2; - else - settings.HorDcm = 1; - if (settings.TmpDcm == 1) - settings.field_per_buff = 2; - else - settings.field_per_buff = 1; - - if (settings.HorDcm > 1) { - settings.img_x = (BUZ_MAX_WIDTH == 720) ? 8 : 0; - settings.img_width = (BUZ_MAX_WIDTH == 720) ? 704 : BUZ_MAX_WIDTH; - } else { - settings.img_x = 0; - settings.img_width = BUZ_MAX_WIDTH; - } - - /* check */ - res = zoran_check_jpg_settings(zr, &settings, 1); - if (res) - return res; - - /* tell the user what we actually did */ - fmt->fmt.pix.width = settings.img_width / settings.HorDcm; - fmt->fmt.pix.height = settings.img_height * 2 / - (settings.TmpDcm * settings.VerDcm); - if (settings.TmpDcm == 1) - fmt->fmt.pix.field = (fh->jpg_settings.odd_even ? - V4L2_FIELD_SEQ_TB : V4L2_FIELD_SEQ_BT); - else - fmt->fmt.pix.field = (fh->jpg_settings.odd_even ? - V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM); - - fmt->fmt.pix.sizeimage = zoran_v4l2_calc_bufsize(&settings); - fmt->fmt.pix.bytesperline = 0; - fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; - return res; -} - -static int zoran_try_fmt_vid_cap(struct file *file, void *__fh, - struct v4l2_format *fmt) -{ - struct zoran_fh *fh = __fh; - struct zoran *zr = fh->zr; - int bpp; - int i; - - if (fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG) - return zoran_try_fmt_vid_out(file, fh, fmt); - - for (i = 0; i < NUM_FORMATS; i++) - if (zoran_formats[i].fourcc == fmt->fmt.pix.pixelformat) - break; - - if (i == NUM_FORMATS) - return -EINVAL; - - bpp = DIV_ROUND_UP(zoran_formats[i].depth, 8); - v4l_bound_align_image( - &fmt->fmt.pix.width, BUZ_MIN_WIDTH, BUZ_MAX_WIDTH, bpp == 2 ? 1 : 2, - &fmt->fmt.pix.height, BUZ_MIN_HEIGHT, BUZ_MAX_HEIGHT, 0, 0); - return 0; -} - -static int zoran_s_fmt_vid_overlay(struct file *file, void *__fh, - struct v4l2_format *fmt) -{ - struct zoran_fh *fh = __fh; - - dprintk(3, "x=%d, y=%d, w=%d, h=%d, cnt=%d, map=0x%p\n", - fmt->fmt.win.w.left, fmt->fmt.win.w.top, - fmt->fmt.win.w.width, - fmt->fmt.win.w.height, - fmt->fmt.win.clipcount, - fmt->fmt.win.bitmap); - return setup_window(fh, fmt->fmt.win.w.left, fmt->fmt.win.w.top, - fmt->fmt.win.w.width, fmt->fmt.win.w.height, - (struct v4l2_clip __user *)fmt->fmt.win.clips, - fmt->fmt.win.clipcount, fmt->fmt.win.bitmap); -} - -static int zoran_s_fmt_vid_out(struct file *file, void *__fh, - struct v4l2_format *fmt) -{ - struct zoran_fh *fh = __fh; - struct zoran *zr = fh->zr; - __le32 printformat = __cpu_to_le32(fmt->fmt.pix.pixelformat); - struct zoran_jpg_settings settings; - int res = 0; - - dprintk(3, "size=%dx%d, fmt=0x%x (%4.4s)\n", - fmt->fmt.pix.width, fmt->fmt.pix.height, - fmt->fmt.pix.pixelformat, - (char *) &printformat); - if (fmt->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG) - return -EINVAL; - - if (fh->buffers.allocated) { - dprintk(1, KERN_ERR "%s: VIDIOC_S_FMT - cannot change capture mode\n", - ZR_DEVNAME(zr)); - return -EBUSY; - } - - settings = fh->jpg_settings; - - /* we actually need to set 'real' parameters now */ - if (fmt->fmt.pix.height * 2 > BUZ_MAX_HEIGHT) - settings.TmpDcm = 1; - else - settings.TmpDcm = 2; - settings.decimation = 0; - if (fmt->fmt.pix.height <= fh->jpg_settings.img_height / 2) - settings.VerDcm = 2; - else - settings.VerDcm = 1; - if (fmt->fmt.pix.width <= fh->jpg_settings.img_width / 4) - settings.HorDcm = 4; - else if (fmt->fmt.pix.width <= fh->jpg_settings.img_width / 2) - settings.HorDcm = 2; - else - settings.HorDcm = 1; - if (settings.TmpDcm == 1) - settings.field_per_buff = 2; - else - settings.field_per_buff = 1; - - if (settings.HorDcm > 1) { - settings.img_x = (BUZ_MAX_WIDTH == 720) ? 8 : 0; - settings.img_width = (BUZ_MAX_WIDTH == 720) ? 704 : BUZ_MAX_WIDTH; - } else { - settings.img_x = 0; - settings.img_width = BUZ_MAX_WIDTH; - } - - /* check */ - res = zoran_check_jpg_settings(zr, &settings, 0); - if (res) - return res; - - /* it's ok, so set them */ - fh->jpg_settings = settings; - - map_mode_jpg(fh, fmt->type == V4L2_BUF_TYPE_VIDEO_OUTPUT); - fh->buffers.buffer_size = zoran_v4l2_calc_bufsize(&fh->jpg_settings); - - /* tell the user what we actually did */ - fmt->fmt.pix.width = settings.img_width / settings.HorDcm; - fmt->fmt.pix.height = settings.img_height * 2 / - (settings.TmpDcm * settings.VerDcm); - if (settings.TmpDcm == 1) - fmt->fmt.pix.field = (fh->jpg_settings.odd_even ? - V4L2_FIELD_SEQ_TB : V4L2_FIELD_SEQ_BT); - else - fmt->fmt.pix.field = (fh->jpg_settings.odd_even ? - V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM); - fmt->fmt.pix.bytesperline = 0; - fmt->fmt.pix.sizeimage = fh->buffers.buffer_size; - fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; - return res; -} - -static int zoran_s_fmt_vid_cap(struct file *file, void *__fh, - struct v4l2_format *fmt) -{ - struct zoran_fh *fh = __fh; - struct zoran *zr = fh->zr; - int i; - int res = 0; - - if (fmt->fmt.pix.pixelformat == V4L2_PIX_FMT_MJPEG) - return zoran_s_fmt_vid_out(file, fh, fmt); - - for (i = 0; i < NUM_FORMATS; i++) - if (fmt->fmt.pix.pixelformat == zoran_formats[i].fourcc) - break; - if (i == NUM_FORMATS) { - dprintk(1, KERN_ERR "%s: VIDIOC_S_FMT - unknown/unsupported format 0x%x\n", - ZR_DEVNAME(zr), fmt->fmt.pix.pixelformat); - return -EINVAL; - } - - if ((fh->map_mode != ZORAN_MAP_MODE_RAW && fh->buffers.allocated) || - fh->buffers.active != ZORAN_FREE) { - dprintk(1, KERN_ERR "%s: VIDIOC_S_FMT - cannot change capture mode\n", - ZR_DEVNAME(zr)); - return -EBUSY; - } - if (fmt->fmt.pix.height > BUZ_MAX_HEIGHT) - fmt->fmt.pix.height = BUZ_MAX_HEIGHT; - if (fmt->fmt.pix.width > BUZ_MAX_WIDTH) - fmt->fmt.pix.width = BUZ_MAX_WIDTH; - - map_mode_raw(fh); - - res = zoran_v4l_set_format(fh, fmt->fmt.pix.width, fmt->fmt.pix.height, - &zoran_formats[i]); - if (res) - return res; - - /* tell the user the results/missing stuff */ - fmt->fmt.pix.bytesperline = fh->v4l_settings.bytesperline; - fmt->fmt.pix.sizeimage = fh->v4l_settings.height * fh->v4l_settings.bytesperline; - fmt->fmt.pix.colorspace = fh->v4l_settings.format->colorspace; - if (BUZ_MAX_HEIGHT < (fh->v4l_settings.height * 2)) - fmt->fmt.pix.field = V4L2_FIELD_INTERLACED; - else - fmt->fmt.pix.field = V4L2_FIELD_TOP; - return res; -} - -static int zoran_g_fbuf(struct file *file, void *__fh, - struct v4l2_framebuffer *fb) -{ - struct zoran_fh *fh = __fh; - struct zoran *zr = fh->zr; - - memset(fb, 0, sizeof(*fb)); - fb->base = zr->vbuf_base; - fb->fmt.width = zr->vbuf_width; - fb->fmt.height = zr->vbuf_height; - if (zr->overlay_settings.format) - fb->fmt.pixelformat = fh->overlay_settings.format->fourcc; - fb->fmt.bytesperline = zr->vbuf_bytesperline; - fb->fmt.colorspace = V4L2_COLORSPACE_SRGB; - fb->fmt.field = V4L2_FIELD_INTERLACED; - fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING; - - return 0; -} - -static int zoran_s_fbuf(struct file *file, void *__fh, - const struct v4l2_framebuffer *fb) -{ - struct zoran_fh *fh = __fh; - struct zoran *zr = fh->zr; - int i; - __le32 printformat = __cpu_to_le32(fb->fmt.pixelformat); - - for (i = 0; i < NUM_FORMATS; i++) - if (zoran_formats[i].fourcc == fb->fmt.pixelformat) - break; - if (i == NUM_FORMATS) { - dprintk(1, KERN_ERR "%s: VIDIOC_S_FBUF - format=0x%x (%4.4s) not allowed\n", - ZR_DEVNAME(zr), fb->fmt.pixelformat, - (char *)&printformat); - return -EINVAL; - } - - return setup_fbuffer(fh, fb->base, &zoran_formats[i], fb->fmt.width, - fb->fmt.height, fb->fmt.bytesperline); -} - -static int zoran_overlay(struct file *file, void *__fh, unsigned int on) -{ - struct zoran_fh *fh = __fh; - - return setup_overlay(fh, on); -} - -static int zoran_streamoff(struct file *file, void *__fh, enum v4l2_buf_type type); - -static int zoran_reqbufs(struct file *file, void *__fh, struct v4l2_requestbuffers *req) -{ - struct zoran_fh *fh = __fh; - struct zoran *zr = fh->zr; - int res = 0; - - if (req->memory != V4L2_MEMORY_MMAP) { - dprintk(2, - KERN_ERR - "%s: only MEMORY_MMAP capture is supported, not %d\n", - ZR_DEVNAME(zr), req->memory); - return -EINVAL; - } - - if (req->count == 0) - return zoran_streamoff(file, fh, req->type); - - if (fh->buffers.allocated) { - dprintk(2, - KERN_ERR - "%s: VIDIOC_REQBUFS - buffers already allocated\n", - ZR_DEVNAME(zr)); - return -EBUSY; - } - - if (fh->map_mode == ZORAN_MAP_MODE_RAW && - req->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { - /* control user input */ - if (req->count < 2) - req->count = 2; - if (req->count > v4l_nbufs) - req->count = v4l_nbufs; - - /* The next mmap will map the V4L buffers */ - map_mode_raw(fh); - fh->buffers.num_buffers = req->count; - - if (v4l_fbuffer_alloc(fh)) { - return -ENOMEM; - } - } else if (fh->map_mode == ZORAN_MAP_MODE_JPG_REC || - fh->map_mode == ZORAN_MAP_MODE_JPG_PLAY) { - /* we need to calculate size ourselves now */ - if (req->count < 4) - req->count = 4; - if (req->count > jpg_nbufs) - req->count = jpg_nbufs; - - /* The next mmap will map the MJPEG buffers */ - map_mode_jpg(fh, req->type == V4L2_BUF_TYPE_VIDEO_OUTPUT); - fh->buffers.num_buffers = req->count; - fh->buffers.buffer_size = zoran_v4l2_calc_bufsize(&fh->jpg_settings); - - if (jpg_fbuffer_alloc(fh)) { - return -ENOMEM; - } - } else { - dprintk(1, - KERN_ERR - "%s: VIDIOC_REQBUFS - unknown type %d\n", - ZR_DEVNAME(zr), req->type); - return -EINVAL; - } - return res; -} - -static int zoran_querybuf(struct file *file, void *__fh, struct v4l2_buffer *buf) -{ - struct zoran_fh *fh = __fh; - - return zoran_v4l2_buffer_status(fh, buf, buf->index); -} - -static int zoran_qbuf(struct file *file, void *__fh, struct v4l2_buffer *buf) -{ - struct zoran_fh *fh = __fh; - struct zoran *zr = fh->zr; - int res = 0, codec_mode, buf_type; - - switch (fh->map_mode) { - case ZORAN_MAP_MODE_RAW: - if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { - dprintk(1, KERN_ERR - "%s: VIDIOC_QBUF - invalid buf->type=%d for map_mode=%d\n", - ZR_DEVNAME(zr), buf->type, fh->map_mode); - return -EINVAL; - } - - res = zoran_v4l_queue_frame(fh, buf->index); - if (res) - return res; - if (!zr->v4l_memgrab_active && fh->buffers.active == ZORAN_LOCKED) - zr36057_set_memgrab(zr, 1); - break; - - case ZORAN_MAP_MODE_JPG_REC: - case ZORAN_MAP_MODE_JPG_PLAY: - if (fh->map_mode == ZORAN_MAP_MODE_JPG_PLAY) { - buf_type = V4L2_BUF_TYPE_VIDEO_OUTPUT; - codec_mode = BUZ_MODE_MOTION_DECOMPRESS; - } else { - buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - codec_mode = BUZ_MODE_MOTION_COMPRESS; - } - - if (buf->type != buf_type) { - dprintk(1, KERN_ERR - "%s: VIDIOC_QBUF - invalid buf->type=%d for map_mode=%d\n", - ZR_DEVNAME(zr), buf->type, fh->map_mode); - return -EINVAL; - } - - res = zoran_jpg_queue_frame(fh, buf->index, codec_mode); - if (res != 0) - return res; - if (zr->codec_mode == BUZ_MODE_IDLE && - fh->buffers.active == ZORAN_LOCKED) - zr36057_enable_jpg(zr, codec_mode); - - break; - - default: - dprintk(1, KERN_ERR - "%s: VIDIOC_QBUF - unsupported type %d\n", - ZR_DEVNAME(zr), buf->type); - res = -EINVAL; - break; - } - return res; -} - -static int zoran_dqbuf(struct file *file, void *__fh, struct v4l2_buffer *buf) -{ - struct zoran_fh *fh = __fh; - struct zoran *zr = fh->zr; - int res = 0, buf_type, num = -1; /* compiler borks here (?) */ - - switch (fh->map_mode) { - case ZORAN_MAP_MODE_RAW: - if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { - dprintk(1, KERN_ERR - "%s: VIDIOC_QBUF - invalid buf->type=%d for map_mode=%d\n", - ZR_DEVNAME(zr), buf->type, fh->map_mode); - return -EINVAL; - } - - num = zr->v4l_pend[zr->v4l_sync_tail & V4L_MASK_FRAME]; - if (file->f_flags & O_NONBLOCK && - zr->v4l_buffers.buffer[num].state != BUZ_STATE_DONE) { - return -EAGAIN; - } - res = v4l_sync(fh, num); - if (res) - return res; - zr->v4l_sync_tail++; - res = zoran_v4l2_buffer_status(fh, buf, num); - break; - - case ZORAN_MAP_MODE_JPG_REC: - case ZORAN_MAP_MODE_JPG_PLAY: - { - struct zoran_sync bs; - - if (fh->map_mode == ZORAN_MAP_MODE_JPG_PLAY) - buf_type = V4L2_BUF_TYPE_VIDEO_OUTPUT; - else - buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - - if (buf->type != buf_type) { - dprintk(1, KERN_ERR - "%s: VIDIOC_QBUF - invalid buf->type=%d for map_mode=%d\n", - ZR_DEVNAME(zr), buf->type, fh->map_mode); - return -EINVAL; - } - - num = zr->jpg_pend[zr->jpg_que_tail & BUZ_MASK_FRAME]; - - if (file->f_flags & O_NONBLOCK && - zr->jpg_buffers.buffer[num].state != BUZ_STATE_DONE) { - return -EAGAIN; - } - bs.frame = 0; /* suppress compiler warning */ - res = jpg_sync(fh, &bs); - if (res) - return res; - res = zoran_v4l2_buffer_status(fh, buf, bs.frame); - break; - } - - default: - dprintk(1, KERN_ERR - "%s: VIDIOC_DQBUF - unsupported type %d\n", - ZR_DEVNAME(zr), buf->type); - res = -EINVAL; - break; - } - return res; -} - -static int zoran_streamon(struct file *file, void *__fh, enum v4l2_buf_type type) -{ - struct zoran_fh *fh = __fh; - struct zoran *zr = fh->zr; - int res = 0; - - switch (fh->map_mode) { - case ZORAN_MAP_MODE_RAW: /* raw capture */ - if (zr->v4l_buffers.active != ZORAN_ACTIVE || - fh->buffers.active != ZORAN_ACTIVE) { - return -EBUSY; - } - - zr->v4l_buffers.active = fh->buffers.active = ZORAN_LOCKED; - zr->v4l_settings = fh->v4l_settings; - - zr->v4l_sync_tail = zr->v4l_pend_tail; - if (!zr->v4l_memgrab_active && - zr->v4l_pend_head != zr->v4l_pend_tail) { - zr36057_set_memgrab(zr, 1); - } - break; - - case ZORAN_MAP_MODE_JPG_REC: - case ZORAN_MAP_MODE_JPG_PLAY: - /* what is the codec mode right now? */ - if (zr->jpg_buffers.active != ZORAN_ACTIVE || - fh->buffers.active != ZORAN_ACTIVE) { - return -EBUSY; - } - - zr->jpg_buffers.active = fh->buffers.active = ZORAN_LOCKED; - - if (zr->jpg_que_head != zr->jpg_que_tail) { - /* Start the jpeg codec when the first frame is queued */ - jpeg_start(zr); - } - break; - - default: - dprintk(1, - KERN_ERR - "%s: VIDIOC_STREAMON - invalid map mode %d\n", - ZR_DEVNAME(zr), fh->map_mode); - res = -EINVAL; - break; - } - return res; -} - -static int zoran_streamoff(struct file *file, void *__fh, enum v4l2_buf_type type) -{ - struct zoran_fh *fh = __fh; - struct zoran *zr = fh->zr; - int i, res = 0; - unsigned long flags; - - switch (fh->map_mode) { - case ZORAN_MAP_MODE_RAW: /* raw capture */ - if (fh->buffers.active == ZORAN_FREE && - zr->v4l_buffers.active != ZORAN_FREE) { - return -EPERM; /* stay off other's settings! */ - } - if (zr->v4l_buffers.active == ZORAN_FREE) - return res; - - spin_lock_irqsave(&zr->spinlock, flags); - /* unload capture */ - if (zr->v4l_memgrab_active) { - - zr36057_set_memgrab(zr, 0); - } - - for (i = 0; i < fh->buffers.num_buffers; i++) - zr->v4l_buffers.buffer[i].state = BUZ_STATE_USER; - fh->buffers = zr->v4l_buffers; - - zr->v4l_buffers.active = fh->buffers.active = ZORAN_FREE; - - zr->v4l_grab_seq = 0; - zr->v4l_pend_head = zr->v4l_pend_tail = 0; - zr->v4l_sync_tail = 0; - - spin_unlock_irqrestore(&zr->spinlock, flags); - - break; - - case ZORAN_MAP_MODE_JPG_REC: - case ZORAN_MAP_MODE_JPG_PLAY: - if (fh->buffers.active == ZORAN_FREE && - zr->jpg_buffers.active != ZORAN_FREE) { - return -EPERM; /* stay off other's settings! */ - } - if (zr->jpg_buffers.active == ZORAN_FREE) - return res; - - res = jpg_qbuf(fh, -1, - (fh->map_mode == ZORAN_MAP_MODE_JPG_REC) ? - BUZ_MODE_MOTION_COMPRESS : - BUZ_MODE_MOTION_DECOMPRESS); - if (res) - return res; - break; - default: - dprintk(1, KERN_ERR - "%s: VIDIOC_STREAMOFF - invalid map mode %d\n", - ZR_DEVNAME(zr), fh->map_mode); - res = -EINVAL; - break; - } - return res; -} -static int zoran_g_std(struct file *file, void *__fh, v4l2_std_id *std) -{ - struct zoran_fh *fh = __fh; - struct zoran *zr = fh->zr; - - *std = zr->norm; - return 0; -} - -static int zoran_s_std(struct file *file, void *__fh, v4l2_std_id std) -{ - struct zoran_fh *fh = __fh; - struct zoran *zr = fh->zr; - int res = 0; - - res = zoran_set_norm(zr, std); - if (res) - return res; - - return wait_grab_pending(zr); -} - -static int zoran_enum_input(struct file *file, void *__fh, - struct v4l2_input *inp) -{ - struct zoran_fh *fh = __fh; - struct zoran *zr = fh->zr; - - if (inp->index >= zr->card.inputs) - return -EINVAL; - - strncpy(inp->name, zr->card.input[inp->index].name, - sizeof(inp->name) - 1); - inp->type = V4L2_INPUT_TYPE_CAMERA; - inp->std = V4L2_STD_ALL; - - /* Get status of video decoder */ - decoder_call(zr, video, g_input_status, &inp->status); - return 0; -} - -static int zoran_g_input(struct file *file, void *__fh, unsigned int *input) -{ - struct zoran_fh *fh = __fh; - struct zoran *zr = fh->zr; - - *input = zr->input; - - return 0; -} - -static int zoran_s_input(struct file *file, void *__fh, unsigned int input) -{ - struct zoran_fh *fh = __fh; - struct zoran *zr = fh->zr; - int res; - - res = zoran_set_input(zr, input); - if (res) - return res; - - /* Make sure the changes come into effect */ - return wait_grab_pending(zr); -} - -static int zoran_enum_output(struct file *file, void *__fh, - struct v4l2_output *outp) -{ - if (outp->index != 0) - return -EINVAL; - - outp->index = 0; - outp->type = V4L2_OUTPUT_TYPE_ANALOGVGAOVERLAY; - strncpy(outp->name, "Autodetect", sizeof(outp->name)-1); - - return 0; -} - -static int zoran_g_output(struct file *file, void *__fh, unsigned int *output) -{ - *output = 0; - - return 0; -} - -static int zoran_s_output(struct file *file, void *__fh, unsigned int output) -{ - if (output != 0) - return -EINVAL; - - return 0; -} - -/* cropping (sub-frame capture) */ -static int zoran_g_selection(struct file *file, void *__fh, struct v4l2_selection *sel) -{ - struct zoran_fh *fh = __fh; - struct zoran *zr = fh->zr; - - if (sel->type != V4L2_BUF_TYPE_VIDEO_OUTPUT && - sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - if (fh->map_mode == ZORAN_MAP_MODE_RAW) { - dprintk(1, KERN_ERR - "%s: VIDIOC_G_SELECTION - subcapture only supported for compressed capture\n", - ZR_DEVNAME(zr)); - return -EINVAL; - } - - switch (sel->target) { - case V4L2_SEL_TGT_CROP: - sel->r.top = fh->jpg_settings.img_y; - sel->r.left = fh->jpg_settings.img_x; - sel->r.width = fh->jpg_settings.img_width; - sel->r.height = fh->jpg_settings.img_height; - break; - case V4L2_SEL_TGT_CROP_DEFAULT: - sel->r.top = sel->r.left = 0; - sel->r.width = BUZ_MIN_WIDTH; - sel->r.height = BUZ_MIN_HEIGHT; - break; - case V4L2_SEL_TGT_CROP_BOUNDS: - sel->r.top = sel->r.left = 0; - sel->r.width = BUZ_MAX_WIDTH; - sel->r.height = BUZ_MAX_HEIGHT; - break; - default: - return -EINVAL; - } - return 0; -} - -static int zoran_s_selection(struct file *file, void *__fh, struct v4l2_selection *sel) -{ - struct zoran_fh *fh = __fh; - struct zoran *zr = fh->zr; - struct zoran_jpg_settings settings; - int res; - - if (sel->type != V4L2_BUF_TYPE_VIDEO_OUTPUT && - sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - - if (sel->target != V4L2_SEL_TGT_CROP) - return -EINVAL; - - if (fh->map_mode == ZORAN_MAP_MODE_RAW) { - dprintk(1, KERN_ERR - "%s: VIDIOC_S_SELECTION - subcapture only supported for compressed capture\n", - ZR_DEVNAME(zr)); - return -EINVAL; - } - - settings = fh->jpg_settings; - - if (fh->buffers.allocated) { - dprintk(1, KERN_ERR - "%s: VIDIOC_S_SELECTION - cannot change settings while active\n", - ZR_DEVNAME(zr)); - return -EBUSY; - } - - /* move into a form that we understand */ - settings.img_x = sel->r.left; - settings.img_y = sel->r.top; - settings.img_width = sel->r.width; - settings.img_height = sel->r.height; - - /* check validity */ - res = zoran_check_jpg_settings(zr, &settings, 0); - if (res) - return res; - - /* accept */ - fh->jpg_settings = settings; - return res; -} - -static int zoran_g_jpegcomp(struct file *file, void *__fh, - struct v4l2_jpegcompression *params) -{ - struct zoran_fh *fh = __fh; - memset(params, 0, sizeof(*params)); - - params->quality = fh->jpg_settings.jpg_comp.quality; - params->APPn = fh->jpg_settings.jpg_comp.APPn; - memcpy(params->APP_data, - fh->jpg_settings.jpg_comp.APP_data, - fh->jpg_settings.jpg_comp.APP_len); - params->APP_len = fh->jpg_settings.jpg_comp.APP_len; - memcpy(params->COM_data, - fh->jpg_settings.jpg_comp.COM_data, - fh->jpg_settings.jpg_comp.COM_len); - params->COM_len = fh->jpg_settings.jpg_comp.COM_len; - params->jpeg_markers = - fh->jpg_settings.jpg_comp.jpeg_markers; - - return 0; -} - -static int zoran_s_jpegcomp(struct file *file, void *__fh, - const struct v4l2_jpegcompression *params) -{ - struct zoran_fh *fh = __fh; - struct zoran *zr = fh->zr; - int res = 0; - struct zoran_jpg_settings settings; - - settings = fh->jpg_settings; - - settings.jpg_comp = *params; - - if (fh->buffers.active != ZORAN_FREE) { - dprintk(1, KERN_WARNING - "%s: VIDIOC_S_JPEGCOMP called while in playback/capture mode\n", - ZR_DEVNAME(zr)); - return -EBUSY; - } - - res = zoran_check_jpg_settings(zr, &settings, 0); - if (res) - return res; - if (!fh->buffers.allocated) - fh->buffers.buffer_size = - zoran_v4l2_calc_bufsize(&fh->jpg_settings); - fh->jpg_settings.jpg_comp = settings.jpg_comp; - return res; -} - -static __poll_t -zoran_poll (struct file *file, - poll_table *wait) -{ - struct zoran_fh *fh = file->private_data; - struct zoran *zr = fh->zr; - __poll_t res = v4l2_ctrl_poll(file, wait); - int frame; - unsigned long flags; - - /* we should check whether buffers are ready to be synced on - * (w/o waits - O_NONBLOCK) here - * if ready for read (sync), return EPOLLIN|EPOLLRDNORM, - * if ready for write (sync), return EPOLLOUT|EPOLLWRNORM, - * if error, return EPOLLERR, - * if no buffers queued or so, return EPOLLNVAL - */ - - switch (fh->map_mode) { - case ZORAN_MAP_MODE_RAW: - poll_wait(file, &zr->v4l_capq, wait); - frame = zr->v4l_pend[zr->v4l_sync_tail & V4L_MASK_FRAME]; - - spin_lock_irqsave(&zr->spinlock, flags); - dprintk(3, - KERN_DEBUG - "%s: %s() raw - active=%c, sync_tail=%lu/%c, pend_tail=%lu, pend_head=%lu\n", - ZR_DEVNAME(zr), __func__, - "FAL"[fh->buffers.active], zr->v4l_sync_tail, - "UPMD"[zr->v4l_buffers.buffer[frame].state], - zr->v4l_pend_tail, zr->v4l_pend_head); - /* Process is the one capturing? */ - if (fh->buffers.active != ZORAN_FREE && - /* Buffer ready to DQBUF? */ - zr->v4l_buffers.buffer[frame].state == BUZ_STATE_DONE) - res |= EPOLLIN | EPOLLRDNORM; - spin_unlock_irqrestore(&zr->spinlock, flags); - - break; - - case ZORAN_MAP_MODE_JPG_REC: - case ZORAN_MAP_MODE_JPG_PLAY: - poll_wait(file, &zr->jpg_capq, wait); - frame = zr->jpg_pend[zr->jpg_que_tail & BUZ_MASK_FRAME]; - - spin_lock_irqsave(&zr->spinlock, flags); - dprintk(3, - KERN_DEBUG - "%s: %s() jpg - active=%c, que_tail=%lu/%c, que_head=%lu, dma=%lu/%lu\n", - ZR_DEVNAME(zr), __func__, - "FAL"[fh->buffers.active], zr->jpg_que_tail, - "UPMD"[zr->jpg_buffers.buffer[frame].state], - zr->jpg_que_head, zr->jpg_dma_tail, zr->jpg_dma_head); - if (fh->buffers.active != ZORAN_FREE && - zr->jpg_buffers.buffer[frame].state == BUZ_STATE_DONE) { - if (fh->map_mode == ZORAN_MAP_MODE_JPG_REC) - res |= EPOLLIN | EPOLLRDNORM; - else - res |= EPOLLOUT | EPOLLWRNORM; - } - spin_unlock_irqrestore(&zr->spinlock, flags); - - break; - - default: - dprintk(1, - KERN_ERR - "%s: %s - internal error, unknown map_mode=%d\n", - ZR_DEVNAME(zr), __func__, fh->map_mode); - res |= EPOLLERR; - } - - return res; -} - - -/* - * This maps the buffers to user space. - * - * Depending on the state of fh->map_mode - * the V4L or the MJPEG buffers are mapped - * per buffer or all together - * - * Note that we need to connect to some - * unmap signal event to unmap the de-allocate - * the buffer accordingly (zoran_vm_close()) - */ - -static void -zoran_vm_open (struct vm_area_struct *vma) -{ - struct zoran_mapping *map = vma->vm_private_data; - atomic_inc(&map->count); -} - -static void -zoran_vm_close (struct vm_area_struct *vma) -{ - struct zoran_mapping *map = vma->vm_private_data; - struct zoran_fh *fh = map->fh; - struct zoran *zr = fh->zr; - int i; - - dprintk(3, KERN_INFO "%s: %s - munmap(%s)\n", ZR_DEVNAME(zr), - __func__, mode_name(fh->map_mode)); - - for (i = 0; i < fh->buffers.num_buffers; i++) { - if (fh->buffers.buffer[i].map == map) - fh->buffers.buffer[i].map = NULL; - } - kfree(map); - - /* Any buffers still mapped? */ - for (i = 0; i < fh->buffers.num_buffers; i++) { - if (fh->buffers.buffer[i].map) { - return; - } - } - - dprintk(3, KERN_INFO "%s: %s - free %s buffers\n", ZR_DEVNAME(zr), - __func__, mode_name(fh->map_mode)); - - if (fh->map_mode == ZORAN_MAP_MODE_RAW) { - if (fh->buffers.active != ZORAN_FREE) { - unsigned long flags; - - spin_lock_irqsave(&zr->spinlock, flags); - zr36057_set_memgrab(zr, 0); - zr->v4l_buffers.allocated = 0; - zr->v4l_buffers.active = fh->buffers.active = ZORAN_FREE; - spin_unlock_irqrestore(&zr->spinlock, flags); - } - v4l_fbuffer_free(fh); - } else { - if (fh->buffers.active != ZORAN_FREE) { - jpg_qbuf(fh, -1, zr->codec_mode); - zr->jpg_buffers.allocated = 0; - zr->jpg_buffers.active = fh->buffers.active = ZORAN_FREE; - } - jpg_fbuffer_free(fh); - } -} - -static const struct vm_operations_struct zoran_vm_ops = { - .open = zoran_vm_open, - .close = zoran_vm_close, -}; - -static int -zoran_mmap (struct file *file, - struct vm_area_struct *vma) -{ - struct zoran_fh *fh = file->private_data; - struct zoran *zr = fh->zr; - unsigned long size = (vma->vm_end - vma->vm_start); - unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; - int i, j; - unsigned long page, start = vma->vm_start, todo, pos, fraglen; - int first, last; - struct zoran_mapping *map; - int res = 0; - - dprintk(3, - KERN_INFO "%s: %s(%s) of 0x%08lx-0x%08lx (size=%lu)\n", - ZR_DEVNAME(zr), __func__, - mode_name(fh->map_mode), vma->vm_start, vma->vm_end, size); - - if (!(vma->vm_flags & VM_SHARED) || !(vma->vm_flags & VM_READ) || - !(vma->vm_flags & VM_WRITE)) { - dprintk(1, - KERN_ERR - "%s: %s - no MAP_SHARED/PROT_{READ,WRITE} given\n", - ZR_DEVNAME(zr), __func__); - return -EINVAL; - } - - if (!fh->buffers.allocated) { - dprintk(1, - KERN_ERR - "%s: %s(%s) - buffers not yet allocated\n", - ZR_DEVNAME(zr), __func__, mode_name(fh->map_mode)); - return -ENOMEM; - } - - first = offset / fh->buffers.buffer_size; - last = first - 1 + size / fh->buffers.buffer_size; - if (offset % fh->buffers.buffer_size != 0 || - size % fh->buffers.buffer_size != 0 || first < 0 || - last < 0 || first >= fh->buffers.num_buffers || - last >= fh->buffers.buffer_size) { - dprintk(1, - KERN_ERR - "%s: %s(%s) - offset=%lu or size=%lu invalid for bufsize=%d and numbufs=%d\n", - ZR_DEVNAME(zr), __func__, mode_name(fh->map_mode), offset, size, - fh->buffers.buffer_size, - fh->buffers.num_buffers); - return -EINVAL; - } - - /* Check if any buffers are already mapped */ - for (i = first; i <= last; i++) { - if (fh->buffers.buffer[i].map) { - dprintk(1, - KERN_ERR - "%s: %s(%s) - buffer %d already mapped\n", - ZR_DEVNAME(zr), __func__, mode_name(fh->map_mode), i); - return -EBUSY; - } - } - - /* map these buffers */ - map = kmalloc(sizeof(struct zoran_mapping), GFP_KERNEL); - if (!map) { - return -ENOMEM; - } - map->fh = fh; - atomic_set(&map->count, 1); - - vma->vm_ops = &zoran_vm_ops; - vma->vm_flags |= VM_DONTEXPAND; - vma->vm_private_data = map; - - if (fh->map_mode == ZORAN_MAP_MODE_RAW) { - for (i = first; i <= last; i++) { - todo = size; - if (todo > fh->buffers.buffer_size) - todo = fh->buffers.buffer_size; - page = fh->buffers.buffer[i].v4l.fbuffer_phys; - if (remap_pfn_range(vma, start, page >> PAGE_SHIFT, - todo, PAGE_SHARED)) { - dprintk(1, - KERN_ERR - "%s: %s(V4L) - remap_pfn_range failed\n", - ZR_DEVNAME(zr), __func__); - return -EAGAIN; - } - size -= todo; - start += todo; - fh->buffers.buffer[i].map = map; - if (size == 0) - break; - } - } else { - for (i = first; i <= last; i++) { - for (j = 0; - j < fh->buffers.buffer_size / PAGE_SIZE; - j++) { - fraglen = - (le32_to_cpu(fh->buffers.buffer[i].jpg. - frag_tab[2 * j + 1]) & ~1) << 1; - todo = size; - if (todo > fraglen) - todo = fraglen; - pos = - le32_to_cpu(fh->buffers. - buffer[i].jpg.frag_tab[2 * j]); - /* should just be pos on i386 */ - page = virt_to_phys(bus_to_virt(pos)) - >> PAGE_SHIFT; - if (remap_pfn_range(vma, start, page, - todo, PAGE_SHARED)) { - dprintk(1, - KERN_ERR - "%s: %s(V4L) - remap_pfn_range failed\n", - ZR_DEVNAME(zr), __func__); - return -EAGAIN; - } - size -= todo; - start += todo; - if (size == 0) - break; - if (le32_to_cpu(fh->buffers.buffer[i].jpg. - frag_tab[2 * j + 1]) & 1) - break; /* was last fragment */ - } - fh->buffers.buffer[i].map = map; - if (size == 0) - break; - - } - } - return res; -} - -static const struct v4l2_ioctl_ops zoran_ioctl_ops = { - .vidioc_querycap = zoran_querycap, - .vidioc_s_selection = zoran_s_selection, - .vidioc_g_selection = zoran_g_selection, - .vidioc_enum_input = zoran_enum_input, - .vidioc_g_input = zoran_g_input, - .vidioc_s_input = zoran_s_input, - .vidioc_enum_output = zoran_enum_output, - .vidioc_g_output = zoran_g_output, - .vidioc_s_output = zoran_s_output, - .vidioc_g_fbuf = zoran_g_fbuf, - .vidioc_s_fbuf = zoran_s_fbuf, - .vidioc_g_std = zoran_g_std, - .vidioc_s_std = zoran_s_std, - .vidioc_g_jpegcomp = zoran_g_jpegcomp, - .vidioc_s_jpegcomp = zoran_s_jpegcomp, - .vidioc_overlay = zoran_overlay, - .vidioc_reqbufs = zoran_reqbufs, - .vidioc_querybuf = zoran_querybuf, - .vidioc_qbuf = zoran_qbuf, - .vidioc_dqbuf = zoran_dqbuf, - .vidioc_streamon = zoran_streamon, - .vidioc_streamoff = zoran_streamoff, - .vidioc_enum_fmt_vid_cap = zoran_enum_fmt_vid_cap, - .vidioc_enum_fmt_vid_out = zoran_enum_fmt_vid_out, - .vidioc_enum_fmt_vid_overlay = zoran_enum_fmt_vid_overlay, - .vidioc_g_fmt_vid_cap = zoran_g_fmt_vid_cap, - .vidioc_g_fmt_vid_out = zoran_g_fmt_vid_out, - .vidioc_g_fmt_vid_overlay = zoran_g_fmt_vid_overlay, - .vidioc_s_fmt_vid_cap = zoran_s_fmt_vid_cap, - .vidioc_s_fmt_vid_out = zoran_s_fmt_vid_out, - .vidioc_s_fmt_vid_overlay = zoran_s_fmt_vid_overlay, - .vidioc_try_fmt_vid_cap = zoran_try_fmt_vid_cap, - .vidioc_try_fmt_vid_out = zoran_try_fmt_vid_out, - .vidioc_try_fmt_vid_overlay = zoran_try_fmt_vid_overlay, - .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, - .vidioc_unsubscribe_event = v4l2_event_unsubscribe, -}; - -static const struct v4l2_file_operations zoran_fops = { - .owner = THIS_MODULE, - .open = zoran_open, - .release = zoran_close, - .unlocked_ioctl = video_ioctl2, - .mmap = zoran_mmap, - .poll = zoran_poll, -}; - -const struct video_device zoran_template = { - .name = ZORAN_NAME, - .fops = &zoran_fops, - .ioctl_ops = &zoran_ioctl_ops, - .release = &zoran_vdev_release, - .tvnorms = V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM, -}; - diff --git a/drivers/staging/media/zoran/zoran_procfs.c b/drivers/staging/media/zoran/zoran_procfs.c deleted file mode 100644 index 941f73fe323b..000000000000 --- a/drivers/staging/media/zoran/zoran_procfs.c +++ /dev/null @@ -1,211 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Zoran zr36057/zr36067 PCI controller driver, for the - * Pinnacle/Miro DC10/DC10+/DC30/DC30+, Iomega Buz, Linux - * Media Labs LML33/LML33R10. - * - * This part handles the procFS entries (/proc/ZORAN[%d]) - * - * Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx> - * - * Currently maintained by: - * Ronald Bultje <rbultje@ronald.bitfreak.net> - * Laurent Pinchart <laurent.pinchart@skynet.be> - * Mailinglist <mjpeg-users@lists.sf.net> - */ -#include <linux/types.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/vmalloc.h> - -#include <linux/proc_fs.h> -#include <linux/pci.h> -#include <linux/i2c.h> -#include <linux/i2c-algo-bit.h> -#include <linux/videodev2.h> -#include <linux/spinlock.h> -#include <linux/sem.h> -#include <linux/seq_file.h> - -#include <linux/ctype.h> -#include <linux/poll.h> -#include <asm/io.h> - -#include "videocodec.h" -#include "zoran.h" -#include "zoran_procfs.h" -#include "zoran_card.h" - -#ifdef CONFIG_PROC_FS -struct procfs_params_zr36067 { - char *name; - short reg; - u32 mask; - short bit; -}; - -static const struct procfs_params_zr36067 zr67[] = { - {"HSPol", 0x000, 1, 30}, - {"HStart", 0x000, 0x3ff, 10}, - {"HEnd", 0x000, 0x3ff, 0}, - - {"VSPol", 0x004, 1, 30}, - {"VStart", 0x004, 0x3ff, 10}, - {"VEnd", 0x004, 0x3ff, 0}, - - {"ExtFl", 0x008, 1, 26}, - {"TopField", 0x008, 1, 25}, - {"VCLKPol", 0x008, 1, 24}, - {"DupFld", 0x008, 1, 20}, - {"LittleEndian", 0x008, 1, 0}, - - {"HsyncStart", 0x10c, 0xffff, 16}, - {"LineTot", 0x10c, 0xffff, 0}, - - {"NAX", 0x110, 0xffff, 16}, - {"PAX", 0x110, 0xffff, 0}, - - {"NAY", 0x114, 0xffff, 16}, - {"PAY", 0x114, 0xffff, 0}, - - /* {"",,,}, */ - - {NULL, 0, 0, 0}, -}; - -static void -setparam (struct zoran *zr, - char *name, - char *sval) -{ - int i = 0, reg0, reg, val; - - while (zr67[i].name != NULL) { - if (!strncmp(name, zr67[i].name, strlen(zr67[i].name))) { - reg = reg0 = btread(zr67[i].reg); - reg &= ~(zr67[i].mask << zr67[i].bit); - if (!isdigit(sval[0])) - break; - val = simple_strtoul(sval, NULL, 0); - if ((val & ~zr67[i].mask)) - break; - reg |= (val & zr67[i].mask) << zr67[i].bit; - dprintk(4, - KERN_INFO - "%s: setparam: setting ZR36067 register 0x%03x: 0x%08x=>0x%08x %s=%d\n", - ZR_DEVNAME(zr), zr67[i].reg, reg0, reg, - zr67[i].name, val); - btwrite(reg, zr67[i].reg); - break; - } - i++; - } -} - -static int zoran_show(struct seq_file *p, void *v) -{ - struct zoran *zr = p->private; - int i; - - seq_printf(p, "ZR36067 registers:\n"); - for (i = 0; i < 0x130; i += 16) - seq_printf(p, "%03X %08X %08X %08X %08X \n", i, - btread(i), btread(i+4), btread(i+8), btread(i+12)); - return 0; -} - -static int zoran_open(struct inode *inode, struct file *file) -{ - struct zoran *data = PDE_DATA(inode); - return single_open(file, zoran_show, data); -} - -static ssize_t zoran_write(struct file *file, const char __user *buffer, - size_t count, loff_t *ppos) -{ - struct zoran *zr = PDE_DATA(file_inode(file)); - char *string, *sp; - char *line, *ldelim, *varname, *svar, *tdelim; - - if (count > 32768) /* Stupidity filter */ - return -EINVAL; - - string = sp = vmalloc(count + 1); - if (!string) { - dprintk(1, - KERN_ERR - "%s: write_proc: can not allocate memory\n", - ZR_DEVNAME(zr)); - return -ENOMEM; - } - if (copy_from_user(string, buffer, count)) { - vfree (string); - return -EFAULT; - } - string[count] = 0; - dprintk(4, KERN_INFO "%s: write_proc: name=%pD count=%zu zr=%p\n", - ZR_DEVNAME(zr), file, count, zr); - ldelim = " \t\n"; - tdelim = "="; - line = strpbrk(sp, ldelim); - while (line) { - *line = 0; - svar = strpbrk(sp, tdelim); - if (svar) { - *svar = 0; - varname = sp; - svar++; - setparam(zr, varname, svar); - } - sp = line + 1; - line = strpbrk(sp, ldelim); - } - vfree(string); - - return count; -} - -static const struct file_operations zoran_operations = { - .owner = THIS_MODULE, - .open = zoran_open, - .read = seq_read, - .write = zoran_write, - .llseek = seq_lseek, - .release = single_release, -}; -#endif - -int -zoran_proc_init (struct zoran *zr) -{ -#ifdef CONFIG_PROC_FS - char name[8]; - - snprintf(name, 7, "zoran%d", zr->id); - zr->zoran_proc = proc_create_data(name, 0, NULL, &zoran_operations, zr); - if (zr->zoran_proc != NULL) { - dprintk(2, - KERN_INFO - "%s: procfs entry /proc/%s allocated. data=%p\n", - ZR_DEVNAME(zr), name, zr); - } else { - dprintk(1, KERN_ERR "%s: Unable to initialise /proc/%s\n", - ZR_DEVNAME(zr), name); - return 1; - } -#endif - return 0; -} - -void -zoran_proc_cleanup (struct zoran *zr) -{ -#ifdef CONFIG_PROC_FS - char name[8]; - - snprintf(name, 7, "zoran%d", zr->id); - if (zr->zoran_proc) - remove_proc_entry(name, NULL); - zr->zoran_proc = NULL; -#endif -} diff --git a/drivers/staging/media/zoran/zoran_procfs.h b/drivers/staging/media/zoran/zoran_procfs.h deleted file mode 100644 index db9f642c851a..000000000000 --- a/drivers/staging/media/zoran/zoran_procfs.h +++ /dev/null @@ -1,22 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Zoran zr36057/zr36067 PCI controller driver, for the - * Pinnacle/Miro DC10/DC10+/DC30/DC30+, Iomega Buz, Linux - * Media Labs LML33/LML33R10. - * - * This part handles card-specific data and detection - * - * Copyright (C) 2000 Serguei Miridonov <mirsev@cicese.mx> - * - * Currently maintained by: - * Ronald Bultje <rbultje@ronald.bitfreak.net> - * Laurent Pinchart <laurent.pinchart@skynet.be> - * Mailinglist <mjpeg-users@lists.sf.net> - */ -#ifndef __ZORAN_PROCFS_H__ -#define __ZORAN_PROCFS_H__ - -extern int zoran_proc_init(struct zoran *zr); -extern void zoran_proc_cleanup(struct zoran *zr); - -#endif /* __ZORAN_PROCFS_H__ */ diff --git a/drivers/staging/media/zoran/zr36016.c b/drivers/staging/media/zoran/zr36016.c deleted file mode 100644 index b300a0abe95f..000000000000 --- a/drivers/staging/media/zoran/zr36016.c +++ /dev/null @@ -1,500 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Zoran ZR36016 basic configuration functions - * - * Copyright (C) 2001 Wolfgang Scherr <scherr@net4you.at> - */ -#define ZR016_VERSION "v0.7" - -#include <linux/module.h> -#include <linux/init.h> -#include <linux/slab.h> -#include <linux/delay.h> - -#include <linux/types.h> -#include <linux/wait.h> - -/* I/O commands, error codes */ -#include <asm/io.h> - -/* v4l API */ - -/* headerfile of this module */ -#include "zr36016.h" - -/* codec io API */ -#include "videocodec.h" - -/* it doesn't make sense to have more than 20 or so, - just to prevent some unwanted loops */ -#define MAX_CODECS 20 - -/* amount of chips attached via this driver */ -static int zr36016_codecs; - -/* debugging is available via module parameter */ -static int debug; -module_param(debug, int, 0); -MODULE_PARM_DESC(debug, "Debug level (0-4)"); - -#define dprintk(num, format, args...) \ - do { \ - if (debug >= num) \ - printk(format, ##args); \ - } while (0) - -/* ========================================================================= - Local hardware I/O functions: - - read/write via codec layer (registers are located in the master device) - ========================================================================= */ - -/* read and write functions */ -static u8 -zr36016_read (struct zr36016 *ptr, - u16 reg) -{ - u8 value = 0; - - // just in case something is wrong... - if (ptr->codec->master_data->readreg) - value = - (ptr->codec->master_data-> - readreg(ptr->codec, reg)) & 0xFF; - else - dprintk(1, - KERN_ERR "%s: invalid I/O setup, nothing read!\n", - ptr->name); - - dprintk(4, "%s: reading from 0x%04x: %02x\n", ptr->name, reg, - value); - - return value; -} - -static void -zr36016_write (struct zr36016 *ptr, - u16 reg, - u8 value) -{ - dprintk(4, "%s: writing 0x%02x to 0x%04x\n", ptr->name, value, - reg); - - // just in case something is wrong... - if (ptr->codec->master_data->writereg) { - ptr->codec->master_data->writereg(ptr->codec, reg, value); - } else - dprintk(1, - KERN_ERR - "%s: invalid I/O setup, nothing written!\n", - ptr->name); -} - -/* indirect read and write functions */ -/* the 016 supports auto-addr-increment, but - * writing it all time cost not much and is safer... */ -static u8 -zr36016_readi (struct zr36016 *ptr, - u16 reg) -{ - u8 value = 0; - - // just in case something is wrong... - if ((ptr->codec->master_data->writereg) && - (ptr->codec->master_data->readreg)) { - ptr->codec->master_data->writereg(ptr->codec, ZR016_IADDR, reg & 0x0F); // ADDR - value = (ptr->codec->master_data->readreg(ptr->codec, ZR016_IDATA)) & 0xFF; // DATA - } else - dprintk(1, - KERN_ERR - "%s: invalid I/O setup, nothing read (i)!\n", - ptr->name); - - dprintk(4, "%s: reading indirect from 0x%04x: %02x\n", ptr->name, - reg, value); - return value; -} - -static void -zr36016_writei (struct zr36016 *ptr, - u16 reg, - u8 value) -{ - dprintk(4, "%s: writing indirect 0x%02x to 0x%04x\n", ptr->name, - value, reg); - - // just in case something is wrong... - if (ptr->codec->master_data->writereg) { - ptr->codec->master_data->writereg(ptr->codec, ZR016_IADDR, reg & 0x0F); // ADDR - ptr->codec->master_data->writereg(ptr->codec, ZR016_IDATA, value & 0x0FF); // DATA - } else - dprintk(1, - KERN_ERR - "%s: invalid I/O setup, nothing written (i)!\n", - ptr->name); -} - -/* ========================================================================= - Local helper function: - - version read - ========================================================================= */ - -/* version kept in datastructure */ -static u8 -zr36016_read_version (struct zr36016 *ptr) -{ - ptr->version = zr36016_read(ptr, 0) >> 4; - return ptr->version; -} - -/* ========================================================================= - Local helper function: - - basic test of "connectivity", writes/reads to/from PAX-Lo register - ========================================================================= */ - -static int -zr36016_basic_test (struct zr36016 *ptr) -{ - if (debug) { - int i; - zr36016_writei(ptr, ZR016I_PAX_LO, 0x55); - dprintk(1, KERN_INFO "%s: registers: ", ptr->name); - for (i = 0; i <= 0x0b; i++) - dprintk(1, "%02x ", zr36016_readi(ptr, i)); - dprintk(1, "\n"); - } - // for testing just write 0, then the default value to a register and read - // it back in both cases - zr36016_writei(ptr, ZR016I_PAX_LO, 0x00); - if (zr36016_readi(ptr, ZR016I_PAX_LO) != 0x0) { - dprintk(1, - KERN_ERR - "%s: attach failed, can't connect to vfe processor!\n", - ptr->name); - return -ENXIO; - } - zr36016_writei(ptr, ZR016I_PAX_LO, 0x0d0); - if (zr36016_readi(ptr, ZR016I_PAX_LO) != 0x0d0) { - dprintk(1, - KERN_ERR - "%s: attach failed, can't connect to vfe processor!\n", - ptr->name); - return -ENXIO; - } - // we allow version numbers from 0-3, should be enough, though - zr36016_read_version(ptr); - if (ptr->version & 0x0c) { - dprintk(1, - KERN_ERR - "%s: attach failed, suspicious version %d found...\n", - ptr->name, ptr->version); - return -ENXIO; - } - - return 0; /* looks good! */ -} - -/* ========================================================================= - Local helper function: - - simple loop for pushing the init datasets - NO USE -- - ========================================================================= */ - -#if 0 -static int zr36016_pushit (struct zr36016 *ptr, - u16 startreg, - u16 len, - const char *data) -{ - int i=0; - - dprintk(4, "%s: write data block to 0x%04x (len=%d)\n", - ptr->name, startreg,len); - while (i<len) { - zr36016_writei(ptr, startreg++, data[i++]); - } - - return i; -} -#endif - -/* ========================================================================= - Basic datasets & init: - - //TODO// - ========================================================================= */ - -static void -zr36016_init (struct zr36016 *ptr) -{ - // stop any processing - zr36016_write(ptr, ZR016_GOSTOP, 0); - - // mode setup (yuv422 in and out, compression/expansuon due to mode) - zr36016_write(ptr, ZR016_MODE, - ZR016_YUV422 | ZR016_YUV422_YUV422 | - (ptr->mode == CODEC_DO_COMPRESSION ? - ZR016_COMPRESSION : ZR016_EXPANSION)); - - // misc setup - zr36016_writei(ptr, ZR016I_SETUP1, - (ptr->xdec ? (ZR016_HRFL | ZR016_HORZ) : 0) | - (ptr->ydec ? ZR016_VERT : 0) | ZR016_CNTI); - zr36016_writei(ptr, ZR016I_SETUP2, ZR016_CCIR); - - // Window setup - // (no extra offset for now, norm defines offset, default width height) - zr36016_writei(ptr, ZR016I_PAX_HI, ptr->width >> 8); - zr36016_writei(ptr, ZR016I_PAX_LO, ptr->width & 0xFF); - zr36016_writei(ptr, ZR016I_PAY_HI, ptr->height >> 8); - zr36016_writei(ptr, ZR016I_PAY_LO, ptr->height & 0xFF); - zr36016_writei(ptr, ZR016I_NAX_HI, ptr->xoff >> 8); - zr36016_writei(ptr, ZR016I_NAX_LO, ptr->xoff & 0xFF); - zr36016_writei(ptr, ZR016I_NAY_HI, ptr->yoff >> 8); - zr36016_writei(ptr, ZR016I_NAY_LO, ptr->yoff & 0xFF); - - /* shall we continue now, please? */ - zr36016_write(ptr, ZR016_GOSTOP, 1); -} - -/* ========================================================================= - CODEC API FUNCTIONS - - this functions are accessed by the master via the API structure - ========================================================================= */ - -/* set compression/expansion mode and launches codec - - this should be the last call from the master before starting processing */ -static int -zr36016_set_mode (struct videocodec *codec, - int mode) -{ - struct zr36016 *ptr = (struct zr36016 *) codec->data; - - dprintk(2, "%s: set_mode %d call\n", ptr->name, mode); - - if ((mode != CODEC_DO_EXPANSION) && (mode != CODEC_DO_COMPRESSION)) - return -EINVAL; - - ptr->mode = mode; - zr36016_init(ptr); - - return 0; -} - -/* set picture size */ -static int -zr36016_set_video (struct videocodec *codec, - struct tvnorm *norm, - struct vfe_settings *cap, - struct vfe_polarity *pol) -{ - struct zr36016 *ptr = (struct zr36016 *) codec->data; - - dprintk(2, "%s: set_video %d.%d, %d/%d-%dx%d (0x%x) call\n", - ptr->name, norm->HStart, norm->VStart, - cap->x, cap->y, cap->width, cap->height, - cap->decimation); - - /* if () return -EINVAL; - * trust the master driver that it knows what it does - so - * we allow invalid startx/y for now ... */ - ptr->width = cap->width; - ptr->height = cap->height; - /* (Ronald) This is ugly. zoran_device.c, line 387 - * already mentions what happens if HStart is even - * (blue faces, etc., cr/cb inversed). There's probably - * some good reason why HStart is 0 instead of 1, so I'm - * leaving it to this for now, but really... This can be - * done a lot simpler */ - ptr->xoff = (norm->HStart ? norm->HStart : 1) + cap->x; - /* Something to note here (I don't understand it), setting - * VStart too high will cause the codec to 'not work'. I - * really don't get it. values of 16 (VStart) already break - * it here. Just '0' seems to work. More testing needed! */ - ptr->yoff = norm->VStart + cap->y; - /* (Ronald) dzjeeh, can't this thing do hor_decimation = 4? */ - ptr->xdec = ((cap->decimation & 0xff) == 1) ? 0 : 1; - ptr->ydec = (((cap->decimation >> 8) & 0xff) == 1) ? 0 : 1; - - return 0; -} - -/* additional control functions */ -static int -zr36016_control (struct videocodec *codec, - int type, - int size, - void *data) -{ - struct zr36016 *ptr = (struct zr36016 *) codec->data; - int *ival = (int *) data; - - dprintk(2, "%s: control %d call with %d byte\n", ptr->name, type, - size); - - switch (type) { - case CODEC_G_STATUS: /* get last status - we don't know it ... */ - if (size != sizeof(int)) - return -EFAULT; - *ival = 0; - break; - - case CODEC_G_CODEC_MODE: - if (size != sizeof(int)) - return -EFAULT; - *ival = 0; - break; - - case CODEC_S_CODEC_MODE: - if (size != sizeof(int)) - return -EFAULT; - if (*ival != 0) - return -EINVAL; - /* not needed, do nothing */ - return 0; - - case CODEC_G_VFE: - case CODEC_S_VFE: - return 0; - - case CODEC_S_MMAP: - /* not available, give an error */ - return -ENXIO; - - default: - return -EINVAL; - } - - return size; -} - -/* ========================================================================= - Exit and unregister function: - - Deinitializes Zoran's JPEG processor - ========================================================================= */ - -static int -zr36016_unset (struct videocodec *codec) -{ - struct zr36016 *ptr = codec->data; - - if (ptr) { - /* do wee need some codec deinit here, too ???? */ - - dprintk(1, "%s: finished codec #%d\n", ptr->name, - ptr->num); - kfree(ptr); - codec->data = NULL; - - zr36016_codecs--; - return 0; - } - - return -EFAULT; -} - -/* ========================================================================= - Setup and registry function: - - Initializes Zoran's JPEG processor - - Also sets pixel size, average code size, mode (compr./decompr.) - (the given size is determined by the processor with the video interface) - ========================================================================= */ - -static int -zr36016_setup (struct videocodec *codec) -{ - struct zr36016 *ptr; - int res; - - dprintk(2, "zr36016: initializing VFE subsystem #%d.\n", - zr36016_codecs); - - if (zr36016_codecs == MAX_CODECS) { - dprintk(1, - KERN_ERR "zr36016: Can't attach more codecs!\n"); - return -ENOSPC; - } - //mem structure init - codec->data = ptr = kzalloc(sizeof(struct zr36016), GFP_KERNEL); - if (NULL == ptr) { - dprintk(1, KERN_ERR "zr36016: Can't get enough memory!\n"); - return -ENOMEM; - } - - snprintf(ptr->name, sizeof(ptr->name), "zr36016[%d]", - zr36016_codecs); - ptr->num = zr36016_codecs++; - ptr->codec = codec; - - //testing - res = zr36016_basic_test(ptr); - if (res < 0) { - zr36016_unset(codec); - return res; - } - //final setup - ptr->mode = CODEC_DO_COMPRESSION; - ptr->width = 768; - ptr->height = 288; - ptr->xdec = 1; - ptr->ydec = 0; - zr36016_init(ptr); - - dprintk(1, KERN_INFO "%s: codec v%d attached and running\n", - ptr->name, ptr->version); - - return 0; -} - -static const struct videocodec zr36016_codec = { - .owner = THIS_MODULE, - .name = "zr36016", - .magic = 0L, // magic not used - .flags = - CODEC_FLAG_HARDWARE | CODEC_FLAG_VFE | CODEC_FLAG_ENCODER | - CODEC_FLAG_DECODER, - .type = CODEC_TYPE_ZR36016, - .setup = zr36016_setup, // functionality - .unset = zr36016_unset, - .set_mode = zr36016_set_mode, - .set_video = zr36016_set_video, - .control = zr36016_control, - // others are not used -}; - -/* ========================================================================= - HOOK IN DRIVER AS KERNEL MODULE - ========================================================================= */ - -static int __init -zr36016_init_module (void) -{ - //dprintk(1, "ZR36016 driver %s\n",ZR016_VERSION); - zr36016_codecs = 0; - return videocodec_register(&zr36016_codec); -} - -static void __exit -zr36016_cleanup_module (void) -{ - if (zr36016_codecs) { - dprintk(1, - "zr36016: something's wrong - %d codecs left somehow.\n", - zr36016_codecs); - } - videocodec_unregister(&zr36016_codec); -} - -module_init(zr36016_init_module); -module_exit(zr36016_cleanup_module); - -MODULE_AUTHOR("Wolfgang Scherr <scherr@net4you.at>"); -MODULE_DESCRIPTION("Driver module for ZR36016 video frontends " - ZR016_VERSION); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/media/zoran/zr36016.h b/drivers/staging/media/zoran/zr36016.h deleted file mode 100644 index 6e66581c27b2..000000000000 --- a/drivers/staging/media/zoran/zr36016.h +++ /dev/null @@ -1,91 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Zoran ZR36016 basic configuration functions - header file - * - * Copyright (C) 2001 Wolfgang Scherr <scherr@net4you.at> - */ -#ifndef ZR36016_H -#define ZR36016_H - -/* data stored for each zoran jpeg codec chip */ -struct zr36016 { - char name[32]; - int num; - /* io datastructure */ - struct videocodec *codec; - // coder status - __u8 version; - // actual coder setup - int mode; - - __u16 xoff; - __u16 yoff; - __u16 width; - __u16 height; - __u16 xdec; - __u16 ydec; -}; - -/* direct register addresses */ -#define ZR016_GOSTOP 0x00 -#define ZR016_MODE 0x01 -#define ZR016_IADDR 0x02 -#define ZR016_IDATA 0x03 - -/* indirect register addresses */ -#define ZR016I_SETUP1 0x00 -#define ZR016I_SETUP2 0x01 -#define ZR016I_NAX_LO 0x02 -#define ZR016I_NAX_HI 0x03 -#define ZR016I_PAX_LO 0x04 -#define ZR016I_PAX_HI 0x05 -#define ZR016I_NAY_LO 0x06 -#define ZR016I_NAY_HI 0x07 -#define ZR016I_PAY_LO 0x08 -#define ZR016I_PAY_HI 0x09 -#define ZR016I_NOL_LO 0x0a -#define ZR016I_NOL_HI 0x0b - -/* possible values for mode register */ -#define ZR016_RGB444_YUV444 0x00 -#define ZR016_RGB444_YUV422 0x01 -#define ZR016_RGB444_YUV411 0x02 -#define ZR016_RGB444_Y400 0x03 -#define ZR016_RGB444_RGB444 0x04 -#define ZR016_YUV444_YUV444 0x08 -#define ZR016_YUV444_YUV422 0x09 -#define ZR016_YUV444_YUV411 0x0a -#define ZR016_YUV444_Y400 0x0b -#define ZR016_YUV444_RGB444 0x0c -#define ZR016_YUV422_YUV422 0x11 -#define ZR016_YUV422_YUV411 0x12 -#define ZR016_YUV422_Y400 0x13 -#define ZR016_YUV411_YUV411 0x16 -#define ZR016_YUV411_Y400 0x17 -#define ZR016_4444_4444 0x19 -#define ZR016_100_100 0x1b - -#define ZR016_RGB444 0x00 -#define ZR016_YUV444 0x20 -#define ZR016_YUV422 0x40 - -#define ZR016_COMPRESSION 0x80 -#define ZR016_EXPANSION 0x80 - -/* possible values for setup 1 register */ -#define ZR016_CKRT 0x80 -#define ZR016_VERT 0x40 -#define ZR016_HORZ 0x20 -#define ZR016_HRFL 0x10 -#define ZR016_DSFL 0x08 -#define ZR016_SBFL 0x04 -#define ZR016_RSTR 0x02 -#define ZR016_CNTI 0x01 - -/* possible values for setup 2 register */ -#define ZR016_SYEN 0x40 -#define ZR016_CCIR 0x04 -#define ZR016_SIGN 0x02 -#define ZR016_YMCS 0x01 - -#endif /*fndef ZR36016_H */ diff --git a/drivers/staging/media/zoran/zr36050.c b/drivers/staging/media/zoran/zr36050.c deleted file mode 100644 index cd58307af378..000000000000 --- a/drivers/staging/media/zoran/zr36050.c +++ /dev/null @@ -1,880 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Zoran ZR36050 basic configuration functions - * - * Copyright (C) 2001 Wolfgang Scherr <scherr@net4you.at> - */ -#define ZR050_VERSION "v0.7.1" - -#include <linux/module.h> -#include <linux/init.h> -#include <linux/slab.h> -#include <linux/delay.h> - -#include <linux/types.h> -#include <linux/wait.h> - -/* I/O commands, error codes */ -#include <asm/io.h> - -/* headerfile of this module */ -#include "zr36050.h" - -/* codec io API */ -#include "videocodec.h" - -/* it doesn't make sense to have more than 20 or so, - just to prevent some unwanted loops */ -#define MAX_CODECS 20 - -/* amount of chips attached via this driver */ -static int zr36050_codecs; - -/* debugging is available via module parameter */ -static int debug; -module_param(debug, int, 0); -MODULE_PARM_DESC(debug, "Debug level (0-4)"); - -#define dprintk(num, format, args...) \ - do { \ - if (debug >= num) \ - printk(format, ##args); \ - } while (0) - -/* ========================================================================= - Local hardware I/O functions: - - read/write via codec layer (registers are located in the master device) - ========================================================================= */ - -/* read and write functions */ -static u8 -zr36050_read (struct zr36050 *ptr, - u16 reg) -{ - u8 value = 0; - - // just in case something is wrong... - if (ptr->codec->master_data->readreg) - value = (ptr->codec->master_data->readreg(ptr->codec, - reg)) & 0xFF; - else - dprintk(1, - KERN_ERR "%s: invalid I/O setup, nothing read!\n", - ptr->name); - - dprintk(4, "%s: reading from 0x%04x: %02x\n", ptr->name, reg, - value); - - return value; -} - -static void -zr36050_write (struct zr36050 *ptr, - u16 reg, - u8 value) -{ - dprintk(4, "%s: writing 0x%02x to 0x%04x\n", ptr->name, value, - reg); - - // just in case something is wrong... - if (ptr->codec->master_data->writereg) - ptr->codec->master_data->writereg(ptr->codec, reg, value); - else - dprintk(1, - KERN_ERR - "%s: invalid I/O setup, nothing written!\n", - ptr->name); -} - -/* ========================================================================= - Local helper function: - - status read - ========================================================================= */ - -/* status is kept in datastructure */ -static u8 -zr36050_read_status1 (struct zr36050 *ptr) -{ - ptr->status1 = zr36050_read(ptr, ZR050_STATUS_1); - - zr36050_read(ptr, 0); - return ptr->status1; -} - -/* ========================================================================= - Local helper function: - - scale factor read - ========================================================================= */ - -/* scale factor is kept in datastructure */ -static u16 -zr36050_read_scalefactor (struct zr36050 *ptr) -{ - ptr->scalefact = (zr36050_read(ptr, ZR050_SF_HI) << 8) | - (zr36050_read(ptr, ZR050_SF_LO) & 0xFF); - - /* leave 0 selected for an eventually GO from master */ - zr36050_read(ptr, 0); - return ptr->scalefact; -} - -/* ========================================================================= - Local helper function: - - wait if codec is ready to proceed (end of processing) or time is over - ========================================================================= */ - -static void -zr36050_wait_end (struct zr36050 *ptr) -{ - int i = 0; - - while (!(zr36050_read_status1(ptr) & 0x4)) { - udelay(1); - if (i++ > 200000) { // 200ms, there is for sure something wrong!!! - dprintk(1, - "%s: timeout at wait_end (last status: 0x%02x)\n", - ptr->name, ptr->status1); - break; - } - } -} - -/* ========================================================================= - Local helper function: - - basic test of "connectivity", writes/reads to/from memory the SOF marker - ========================================================================= */ - -static int -zr36050_basic_test (struct zr36050 *ptr) -{ - zr36050_write(ptr, ZR050_SOF_IDX, 0x00); - zr36050_write(ptr, ZR050_SOF_IDX + 1, 0x00); - if ((zr36050_read(ptr, ZR050_SOF_IDX) | - zr36050_read(ptr, ZR050_SOF_IDX + 1)) != 0x0000) { - dprintk(1, - KERN_ERR - "%s: attach failed, can't connect to jpeg processor!\n", - ptr->name); - return -ENXIO; - } - zr36050_write(ptr, ZR050_SOF_IDX, 0xff); - zr36050_write(ptr, ZR050_SOF_IDX + 1, 0xc0); - if (((zr36050_read(ptr, ZR050_SOF_IDX) << 8) | - zr36050_read(ptr, ZR050_SOF_IDX + 1)) != 0xffc0) { - dprintk(1, - KERN_ERR - "%s: attach failed, can't connect to jpeg processor!\n", - ptr->name); - return -ENXIO; - } - - zr36050_wait_end(ptr); - if ((ptr->status1 & 0x4) == 0) { - dprintk(1, - KERN_ERR - "%s: attach failed, jpeg processor failed (end flag)!\n", - ptr->name); - return -EBUSY; - } - - return 0; /* looks good! */ -} - -/* ========================================================================= - Local helper function: - - simple loop for pushing the init datasets - ========================================================================= */ - -static int -zr36050_pushit (struct zr36050 *ptr, - u16 startreg, - u16 len, - const char *data) -{ - int i = 0; - - dprintk(4, "%s: write data block to 0x%04x (len=%d)\n", ptr->name, - startreg, len); - while (i < len) { - zr36050_write(ptr, startreg++, data[i++]); - } - - return i; -} - -/* ========================================================================= - Basic datasets: - - jpeg baseline setup data (you find it on lots places in internet, or just - extract it from any regular .jpg image...) - - Could be variable, but until it's not needed it they are just fixed to save - memory. Otherwise expand zr36050 structure with arrays, push the values to - it and initialize from there, as e.g. the linux zr36057/60 driver does it. - ========================================================================= */ - -static const char zr36050_dqt[0x86] = { - 0xff, 0xdb, //Marker: DQT - 0x00, 0x84, //Length: 2*65+2 - 0x00, //Pq,Tq first table - 0x10, 0x0b, 0x0c, 0x0e, 0x0c, 0x0a, 0x10, 0x0e, - 0x0d, 0x0e, 0x12, 0x11, 0x10, 0x13, 0x18, 0x28, - 0x1a, 0x18, 0x16, 0x16, 0x18, 0x31, 0x23, 0x25, - 0x1d, 0x28, 0x3a, 0x33, 0x3d, 0x3c, 0x39, 0x33, - 0x38, 0x37, 0x40, 0x48, 0x5c, 0x4e, 0x40, 0x44, - 0x57, 0x45, 0x37, 0x38, 0x50, 0x6d, 0x51, 0x57, - 0x5f, 0x62, 0x67, 0x68, 0x67, 0x3e, 0x4d, 0x71, - 0x79, 0x70, 0x64, 0x78, 0x5c, 0x65, 0x67, 0x63, - 0x01, //Pq,Tq second table - 0x11, 0x12, 0x12, 0x18, 0x15, 0x18, 0x2f, 0x1a, - 0x1a, 0x2f, 0x63, 0x42, 0x38, 0x42, 0x63, 0x63, - 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, - 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, - 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, - 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, - 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, - 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63 -}; - -static const char zr36050_dht[0x1a4] = { - 0xff, 0xc4, //Marker: DHT - 0x01, 0xa2, //Length: 2*AC, 2*DC - 0x00, //DC first table - 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, - 0x01, //DC second table - 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, - 0x10, //AC first table - 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, - 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, - 0x01, 0x7D, 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, - 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, - 0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xA1, - 0x08, 0x23, 0x42, 0xB1, 0xC1, 0x15, 0x52, 0xD1, 0xF0, 0x24, - 0x33, 0x62, 0x72, 0x82, 0x09, 0x0A, 0x16, 0x17, - 0x18, 0x19, 0x1A, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x34, - 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, - 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, 0x55, 0x56, - 0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, - 0x67, 0x68, 0x69, 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, - 0x79, 0x7A, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, - 0x89, 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, - 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, - 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, - 0xBA, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, - 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, - 0xDA, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, - 0xE8, 0xE9, 0xEA, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, - 0xF8, 0xF9, 0xFA, - 0x11, //AC second table - 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, - 0x07, 0x05, 0x04, 0x04, 0x00, 0x01, - 0x02, 0x77, 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, - 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, - 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, - 0xA1, 0xB1, 0xC1, 0x09, 0x23, 0x33, 0x52, 0xF0, 0x15, 0x62, - 0x72, 0xD1, 0x0A, 0x16, 0x24, 0x34, 0xE1, 0x25, - 0xF1, 0x17, 0x18, 0x19, 0x1A, 0x26, 0x27, 0x28, 0x29, 0x2A, - 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, - 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, 0x55, 0x56, - 0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, - 0x67, 0x68, 0x69, 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, - 0x79, 0x7A, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, - 0x88, 0x89, 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, - 0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, - 0xA8, 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, - 0xB9, 0xBA, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, - 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, - 0xD9, 0xDA, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, - 0xE8, 0xE9, 0xEA, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, - 0xF9, 0xFA -}; - -/* jpeg baseline setup, this is just fixed in this driver (YUV pictures) */ -#define NO_OF_COMPONENTS 0x3 //Y,U,V -#define BASELINE_PRECISION 0x8 //MCU size (?) -static const char zr36050_tq[8] = { 0, 1, 1, 0, 0, 0, 0, 0 }; //table idx's QT -static const char zr36050_td[8] = { 0, 1, 1, 0, 0, 0, 0, 0 }; //table idx's DC -static const char zr36050_ta[8] = { 0, 1, 1, 0, 0, 0, 0, 0 }; //table idx's AC - -/* horizontal 422 decimation setup (maybe we support 411 or so later, too) */ -static const char zr36050_decimation_h[8] = { 2, 1, 1, 0, 0, 0, 0, 0 }; -static const char zr36050_decimation_v[8] = { 1, 1, 1, 0, 0, 0, 0, 0 }; - -/* ========================================================================= - Local helper functions: - - calculation and setup of parameter-dependent JPEG baseline segments - (needed for compression only) - ========================================================================= */ - -/* ------------------------------------------------------------------------- */ - -/* SOF (start of frame) segment depends on width, height and sampling ratio - of each color component */ - -static int -zr36050_set_sof (struct zr36050 *ptr) -{ - char sof_data[34]; // max. size of register set - int i; - - dprintk(3, "%s: write SOF (%dx%d, %d components)\n", ptr->name, - ptr->width, ptr->height, NO_OF_COMPONENTS); - sof_data[0] = 0xff; - sof_data[1] = 0xc0; - sof_data[2] = 0x00; - sof_data[3] = (3 * NO_OF_COMPONENTS) + 8; - sof_data[4] = BASELINE_PRECISION; // only '8' possible with zr36050 - sof_data[5] = (ptr->height) >> 8; - sof_data[6] = (ptr->height) & 0xff; - sof_data[7] = (ptr->width) >> 8; - sof_data[8] = (ptr->width) & 0xff; - sof_data[9] = NO_OF_COMPONENTS; - for (i = 0; i < NO_OF_COMPONENTS; i++) { - sof_data[10 + (i * 3)] = i; // index identifier - sof_data[11 + (i * 3)] = (ptr->h_samp_ratio[i] << 4) | (ptr->v_samp_ratio[i]); // sampling ratios - sof_data[12 + (i * 3)] = zr36050_tq[i]; // Q table selection - } - return zr36050_pushit(ptr, ZR050_SOF_IDX, - (3 * NO_OF_COMPONENTS) + 10, sof_data); -} - -/* ------------------------------------------------------------------------- */ - -/* SOS (start of scan) segment depends on the used scan components - of each color component */ - -static int -zr36050_set_sos (struct zr36050 *ptr) -{ - char sos_data[16]; // max. size of register set - int i; - - dprintk(3, "%s: write SOS\n", ptr->name); - sos_data[0] = 0xff; - sos_data[1] = 0xda; - sos_data[2] = 0x00; - sos_data[3] = 2 + 1 + (2 * NO_OF_COMPONENTS) + 3; - sos_data[4] = NO_OF_COMPONENTS; - for (i = 0; i < NO_OF_COMPONENTS; i++) { - sos_data[5 + (i * 2)] = i; // index - sos_data[6 + (i * 2)] = (zr36050_td[i] << 4) | zr36050_ta[i]; // AC/DC tbl.sel. - } - sos_data[2 + 1 + (2 * NO_OF_COMPONENTS) + 2] = 00; // scan start - sos_data[2 + 1 + (2 * NO_OF_COMPONENTS) + 3] = 0x3F; - sos_data[2 + 1 + (2 * NO_OF_COMPONENTS) + 4] = 00; - return zr36050_pushit(ptr, ZR050_SOS1_IDX, - 4 + 1 + (2 * NO_OF_COMPONENTS) + 3, - sos_data); -} - -/* ------------------------------------------------------------------------- */ - -/* DRI (define restart interval) */ - -static int -zr36050_set_dri (struct zr36050 *ptr) -{ - char dri_data[6]; // max. size of register set - - dprintk(3, "%s: write DRI\n", ptr->name); - dri_data[0] = 0xff; - dri_data[1] = 0xdd; - dri_data[2] = 0x00; - dri_data[3] = 0x04; - dri_data[4] = ptr->dri >> 8; - dri_data[5] = ptr->dri & 0xff; - return zr36050_pushit(ptr, ZR050_DRI_IDX, 6, dri_data); -} - -/* ========================================================================= - Setup function: - - Setup compression/decompression of Zoran's JPEG processor - ( see also zoran 36050 manual ) - - ... sorry for the spaghetti code ... - ========================================================================= */ -static void -zr36050_init (struct zr36050 *ptr) -{ - int sum = 0; - long bitcnt, tmp; - - if (ptr->mode == CODEC_DO_COMPRESSION) { - dprintk(2, "%s: COMPRESSION SETUP\n", ptr->name); - - /* 050 communicates with 057 in master mode */ - zr36050_write(ptr, ZR050_HARDWARE, ZR050_HW_MSTR); - - /* encoding table preload for compression */ - zr36050_write(ptr, ZR050_MODE, - ZR050_MO_COMP | ZR050_MO_TLM); - zr36050_write(ptr, ZR050_OPTIONS, 0); - - /* disable all IRQs */ - zr36050_write(ptr, ZR050_INT_REQ_0, 0); - zr36050_write(ptr, ZR050_INT_REQ_1, 3); // low 2 bits always 1 - - /* volume control settings */ - /*zr36050_write(ptr, ZR050_MBCV, ptr->max_block_vol);*/ - zr36050_write(ptr, ZR050_SF_HI, ptr->scalefact >> 8); - zr36050_write(ptr, ZR050_SF_LO, ptr->scalefact & 0xff); - - zr36050_write(ptr, ZR050_AF_HI, 0xff); - zr36050_write(ptr, ZR050_AF_M, 0xff); - zr36050_write(ptr, ZR050_AF_LO, 0xff); - - /* setup the variable jpeg tables */ - sum += zr36050_set_sof(ptr); - sum += zr36050_set_sos(ptr); - sum += zr36050_set_dri(ptr); - - /* setup the fixed jpeg tables - maybe variable, though - - * (see table init section above) */ - dprintk(3, "%s: write DQT, DHT, APP\n", ptr->name); - sum += zr36050_pushit(ptr, ZR050_DQT_IDX, - sizeof(zr36050_dqt), zr36050_dqt); - sum += zr36050_pushit(ptr, ZR050_DHT_IDX, - sizeof(zr36050_dht), zr36050_dht); - zr36050_write(ptr, ZR050_APP_IDX, 0xff); - zr36050_write(ptr, ZR050_APP_IDX + 1, 0xe0 + ptr->app.appn); - zr36050_write(ptr, ZR050_APP_IDX + 2, 0x00); - zr36050_write(ptr, ZR050_APP_IDX + 3, ptr->app.len + 2); - sum += zr36050_pushit(ptr, ZR050_APP_IDX + 4, 60, - ptr->app.data) + 4; - zr36050_write(ptr, ZR050_COM_IDX, 0xff); - zr36050_write(ptr, ZR050_COM_IDX + 1, 0xfe); - zr36050_write(ptr, ZR050_COM_IDX + 2, 0x00); - zr36050_write(ptr, ZR050_COM_IDX + 3, ptr->com.len + 2); - sum += zr36050_pushit(ptr, ZR050_COM_IDX + 4, 60, - ptr->com.data) + 4; - - /* do the internal huffman table preload */ - zr36050_write(ptr, ZR050_MARKERS_EN, ZR050_ME_DHTI); - - zr36050_write(ptr, ZR050_GO, 1); // launch codec - zr36050_wait_end(ptr); - dprintk(2, "%s: Status after table preload: 0x%02x\n", - ptr->name, ptr->status1); - - if ((ptr->status1 & 0x4) == 0) { - dprintk(1, KERN_ERR "%s: init aborted!\n", - ptr->name); - return; // something is wrong, its timed out!!!! - } - - /* setup misc. data for compression (target code sizes) */ - - /* size of compressed code to reach without header data */ - sum = ptr->real_code_vol - sum; - bitcnt = sum << 3; /* need the size in bits */ - - tmp = bitcnt >> 16; - dprintk(3, - "%s: code: csize=%d, tot=%d, bit=%ld, highbits=%ld\n", - ptr->name, sum, ptr->real_code_vol, bitcnt, tmp); - zr36050_write(ptr, ZR050_TCV_NET_HI, tmp >> 8); - zr36050_write(ptr, ZR050_TCV_NET_MH, tmp & 0xff); - tmp = bitcnt & 0xffff; - zr36050_write(ptr, ZR050_TCV_NET_ML, tmp >> 8); - zr36050_write(ptr, ZR050_TCV_NET_LO, tmp & 0xff); - - bitcnt -= bitcnt >> 7; // bits without stuffing - bitcnt -= ((bitcnt * 5) >> 6); // bits without eob - - tmp = bitcnt >> 16; - dprintk(3, "%s: code: nettobit=%ld, highnettobits=%ld\n", - ptr->name, bitcnt, tmp); - zr36050_write(ptr, ZR050_TCV_DATA_HI, tmp >> 8); - zr36050_write(ptr, ZR050_TCV_DATA_MH, tmp & 0xff); - tmp = bitcnt & 0xffff; - zr36050_write(ptr, ZR050_TCV_DATA_ML, tmp >> 8); - zr36050_write(ptr, ZR050_TCV_DATA_LO, tmp & 0xff); - - /* compression setup with or without bitrate control */ - zr36050_write(ptr, ZR050_MODE, - ZR050_MO_COMP | ZR050_MO_PASS2 | - (ptr->bitrate_ctrl ? ZR050_MO_BRC : 0)); - - /* this headers seem to deliver "valid AVI" jpeg frames */ - zr36050_write(ptr, ZR050_MARKERS_EN, - ZR050_ME_DQT | ZR050_ME_DHT | - ((ptr->app.len > 0) ? ZR050_ME_APP : 0) | - ((ptr->com.len > 0) ? ZR050_ME_COM : 0)); - } else { - dprintk(2, "%s: EXPANSION SETUP\n", ptr->name); - - /* 050 communicates with 055 in master mode */ - zr36050_write(ptr, ZR050_HARDWARE, - ZR050_HW_MSTR | ZR050_HW_CFIS_2_CLK); - - /* encoding table preload */ - zr36050_write(ptr, ZR050_MODE, ZR050_MO_TLM); - - /* disable all IRQs */ - zr36050_write(ptr, ZR050_INT_REQ_0, 0); - zr36050_write(ptr, ZR050_INT_REQ_1, 3); // low 2 bits always 1 - - dprintk(3, "%s: write DHT\n", ptr->name); - zr36050_pushit(ptr, ZR050_DHT_IDX, sizeof(zr36050_dht), - zr36050_dht); - - /* do the internal huffman table preload */ - zr36050_write(ptr, ZR050_MARKERS_EN, ZR050_ME_DHTI); - - zr36050_write(ptr, ZR050_GO, 1); // launch codec - zr36050_wait_end(ptr); - dprintk(2, "%s: Status after table preload: 0x%02x\n", - ptr->name, ptr->status1); - - if ((ptr->status1 & 0x4) == 0) { - dprintk(1, KERN_ERR "%s: init aborted!\n", - ptr->name); - return; // something is wrong, its timed out!!!! - } - - /* setup misc. data for expansion */ - zr36050_write(ptr, ZR050_MODE, 0); - zr36050_write(ptr, ZR050_MARKERS_EN, 0); - } - - /* adr on selected, to allow GO from master */ - zr36050_read(ptr, 0); -} - -/* ========================================================================= - CODEC API FUNCTIONS - - this functions are accessed by the master via the API structure - ========================================================================= */ - -/* set compression/expansion mode and launches codec - - this should be the last call from the master before starting processing */ -static int -zr36050_set_mode (struct videocodec *codec, - int mode) -{ - struct zr36050 *ptr = (struct zr36050 *) codec->data; - - dprintk(2, "%s: set_mode %d call\n", ptr->name, mode); - - if ((mode != CODEC_DO_EXPANSION) && (mode != CODEC_DO_COMPRESSION)) - return -EINVAL; - - ptr->mode = mode; - zr36050_init(ptr); - - return 0; -} - -/* set picture size (norm is ignored as the codec doesn't know about it) */ -static int -zr36050_set_video (struct videocodec *codec, - struct tvnorm *norm, - struct vfe_settings *cap, - struct vfe_polarity *pol) -{ - struct zr36050 *ptr = (struct zr36050 *) codec->data; - int size; - - dprintk(2, "%s: set_video %d.%d, %d/%d-%dx%d (0x%x) q%d call\n", - ptr->name, norm->HStart, norm->VStart, - cap->x, cap->y, cap->width, cap->height, - cap->decimation, cap->quality); - /* if () return -EINVAL; - * trust the master driver that it knows what it does - so - * we allow invalid startx/y and norm for now ... */ - ptr->width = cap->width / (cap->decimation & 0xff); - ptr->height = cap->height / ((cap->decimation >> 8) & 0xff); - - /* (KM) JPEG quality */ - size = ptr->width * ptr->height; - size *= 16; /* size in bits */ - /* apply quality setting */ - size = size * cap->quality / 200; - - /* Minimum: 1kb */ - if (size < 8192) - size = 8192; - /* Maximum: 7/8 of code buffer */ - if (size > ptr->total_code_vol * 7) - size = ptr->total_code_vol * 7; - - ptr->real_code_vol = size >> 3; /* in bytes */ - - /* Set max_block_vol here (previously in zr36050_init, moved - * here for consistency with zr36060 code */ - zr36050_write(ptr, ZR050_MBCV, ptr->max_block_vol); - - return 0; -} - -/* additional control functions */ -static int -zr36050_control (struct videocodec *codec, - int type, - int size, - void *data) -{ - struct zr36050 *ptr = (struct zr36050 *) codec->data; - int *ival = (int *) data; - - dprintk(2, "%s: control %d call with %d byte\n", ptr->name, type, - size); - - switch (type) { - case CODEC_G_STATUS: /* get last status */ - if (size != sizeof(int)) - return -EFAULT; - zr36050_read_status1(ptr); - *ival = ptr->status1; - break; - - case CODEC_G_CODEC_MODE: - if (size != sizeof(int)) - return -EFAULT; - *ival = CODEC_MODE_BJPG; - break; - - case CODEC_S_CODEC_MODE: - if (size != sizeof(int)) - return -EFAULT; - if (*ival != CODEC_MODE_BJPG) - return -EINVAL; - /* not needed, do nothing */ - return 0; - - case CODEC_G_VFE: - case CODEC_S_VFE: - /* not needed, do nothing */ - return 0; - - case CODEC_S_MMAP: - /* not available, give an error */ - return -ENXIO; - - case CODEC_G_JPEG_TDS_BYTE: /* get target volume in byte */ - if (size != sizeof(int)) - return -EFAULT; - *ival = ptr->total_code_vol; - break; - - case CODEC_S_JPEG_TDS_BYTE: /* get target volume in byte */ - if (size != sizeof(int)) - return -EFAULT; - ptr->total_code_vol = *ival; - /* (Kieran Morrissey) - * code copied from zr36060.c to ensure proper bitrate */ - ptr->real_code_vol = (ptr->total_code_vol * 6) >> 3; - break; - - case CODEC_G_JPEG_SCALE: /* get scaling factor */ - if (size != sizeof(int)) - return -EFAULT; - *ival = zr36050_read_scalefactor(ptr); - break; - - case CODEC_S_JPEG_SCALE: /* set scaling factor */ - if (size != sizeof(int)) - return -EFAULT; - ptr->scalefact = *ival; - break; - - case CODEC_G_JPEG_APP_DATA: { /* get appn marker data */ - struct jpeg_app_marker *app = data; - - if (size != sizeof(struct jpeg_app_marker)) - return -EFAULT; - - *app = ptr->app; - break; - } - - case CODEC_S_JPEG_APP_DATA: { /* set appn marker data */ - struct jpeg_app_marker *app = data; - - if (size != sizeof(struct jpeg_app_marker)) - return -EFAULT; - - ptr->app = *app; - break; - } - - case CODEC_G_JPEG_COM_DATA: { /* get comment marker data */ - struct jpeg_com_marker *com = data; - - if (size != sizeof(struct jpeg_com_marker)) - return -EFAULT; - - *com = ptr->com; - break; - } - - case CODEC_S_JPEG_COM_DATA: { /* set comment marker data */ - struct jpeg_com_marker *com = data; - - if (size != sizeof(struct jpeg_com_marker)) - return -EFAULT; - - ptr->com = *com; - break; - } - - default: - return -EINVAL; - } - - return size; -} - -/* ========================================================================= - Exit and unregister function: - - Deinitializes Zoran's JPEG processor - ========================================================================= */ - -static int -zr36050_unset (struct videocodec *codec) -{ - struct zr36050 *ptr = codec->data; - - if (ptr) { - /* do wee need some codec deinit here, too ???? */ - - dprintk(1, "%s: finished codec #%d\n", ptr->name, - ptr->num); - kfree(ptr); - codec->data = NULL; - - zr36050_codecs--; - return 0; - } - - return -EFAULT; -} - -/* ========================================================================= - Setup and registry function: - - Initializes Zoran's JPEG processor - - Also sets pixel size, average code size, mode (compr./decompr.) - (the given size is determined by the processor with the video interface) - ========================================================================= */ - -static int -zr36050_setup (struct videocodec *codec) -{ - struct zr36050 *ptr; - int res; - - dprintk(2, "zr36050: initializing MJPEG subsystem #%d.\n", - zr36050_codecs); - - if (zr36050_codecs == MAX_CODECS) { - dprintk(1, - KERN_ERR "zr36050: Can't attach more codecs!\n"); - return -ENOSPC; - } - //mem structure init - codec->data = ptr = kzalloc(sizeof(struct zr36050), GFP_KERNEL); - if (NULL == ptr) { - dprintk(1, KERN_ERR "zr36050: Can't get enough memory!\n"); - return -ENOMEM; - } - - snprintf(ptr->name, sizeof(ptr->name), "zr36050[%d]", - zr36050_codecs); - ptr->num = zr36050_codecs++; - ptr->codec = codec; - - //testing - res = zr36050_basic_test(ptr); - if (res < 0) { - zr36050_unset(codec); - return res; - } - //final setup - memcpy(ptr->h_samp_ratio, zr36050_decimation_h, 8); - memcpy(ptr->v_samp_ratio, zr36050_decimation_v, 8); - - ptr->bitrate_ctrl = 0; /* 0 or 1 - fixed file size flag - * (what is the difference?) */ - ptr->mode = CODEC_DO_COMPRESSION; - ptr->width = 384; - ptr->height = 288; - ptr->total_code_vol = 16000; - ptr->max_block_vol = 240; - ptr->scalefact = 0x100; - ptr->dri = 1; - - /* no app/com marker by default */ - ptr->app.appn = 0; - ptr->app.len = 0; - ptr->com.len = 0; - - zr36050_init(ptr); - - dprintk(1, KERN_INFO "%s: codec attached and running\n", - ptr->name); - - return 0; -} - -static const struct videocodec zr36050_codec = { - .owner = THIS_MODULE, - .name = "zr36050", - .magic = 0L, // magic not used - .flags = - CODEC_FLAG_JPEG | CODEC_FLAG_HARDWARE | CODEC_FLAG_ENCODER | - CODEC_FLAG_DECODER, - .type = CODEC_TYPE_ZR36050, - .setup = zr36050_setup, // functionality - .unset = zr36050_unset, - .set_mode = zr36050_set_mode, - .set_video = zr36050_set_video, - .control = zr36050_control, - // others are not used -}; - -/* ========================================================================= - HOOK IN DRIVER AS KERNEL MODULE - ========================================================================= */ - -static int __init -zr36050_init_module (void) -{ - //dprintk(1, "ZR36050 driver %s\n",ZR050_VERSION); - zr36050_codecs = 0; - return videocodec_register(&zr36050_codec); -} - -static void __exit -zr36050_cleanup_module (void) -{ - if (zr36050_codecs) { - dprintk(1, - "zr36050: something's wrong - %d codecs left somehow.\n", - zr36050_codecs); - } - videocodec_unregister(&zr36050_codec); -} - -module_init(zr36050_init_module); -module_exit(zr36050_cleanup_module); - -MODULE_AUTHOR("Wolfgang Scherr <scherr@net4you.at>"); -MODULE_DESCRIPTION("Driver module for ZR36050 jpeg processors " - ZR050_VERSION); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/media/zoran/zr36050.h b/drivers/staging/media/zoran/zr36050.h deleted file mode 100644 index c485913dc820..000000000000 --- a/drivers/staging/media/zoran/zr36050.h +++ /dev/null @@ -1,163 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Zoran ZR36050 basic configuration functions - header file - * - * Copyright (C) 2001 Wolfgang Scherr <scherr@net4you.at> - */ -#ifndef ZR36050_H -#define ZR36050_H - -#include "videocodec.h" - -/* data stored for each zoran jpeg codec chip */ -struct zr36050 { - char name[32]; - int num; - /* io datastructure */ - struct videocodec *codec; - // last coder status - __u8 status1; - // actual coder setup - int mode; - - __u16 width; - __u16 height; - - __u16 bitrate_ctrl; - - __u32 total_code_vol; - __u32 real_code_vol; - __u16 max_block_vol; - - __u8 h_samp_ratio[8]; - __u8 v_samp_ratio[8]; - __u16 scalefact; - __u16 dri; - - /* com/app marker */ - struct jpeg_com_marker com; - struct jpeg_app_marker app; -}; - -/* zr36050 register addresses */ -#define ZR050_GO 0x000 -#define ZR050_HARDWARE 0x002 -#define ZR050_MODE 0x003 -#define ZR050_OPTIONS 0x004 -#define ZR050_MBCV 0x005 -#define ZR050_MARKERS_EN 0x006 -#define ZR050_INT_REQ_0 0x007 -#define ZR050_INT_REQ_1 0x008 -#define ZR050_TCV_NET_HI 0x009 -#define ZR050_TCV_NET_MH 0x00a -#define ZR050_TCV_NET_ML 0x00b -#define ZR050_TCV_NET_LO 0x00c -#define ZR050_TCV_DATA_HI 0x00d -#define ZR050_TCV_DATA_MH 0x00e -#define ZR050_TCV_DATA_ML 0x00f -#define ZR050_TCV_DATA_LO 0x010 -#define ZR050_SF_HI 0x011 -#define ZR050_SF_LO 0x012 -#define ZR050_AF_HI 0x013 -#define ZR050_AF_M 0x014 -#define ZR050_AF_LO 0x015 -#define ZR050_ACV_HI 0x016 -#define ZR050_ACV_MH 0x017 -#define ZR050_ACV_ML 0x018 -#define ZR050_ACV_LO 0x019 -#define ZR050_ACT_HI 0x01a -#define ZR050_ACT_MH 0x01b -#define ZR050_ACT_ML 0x01c -#define ZR050_ACT_LO 0x01d -#define ZR050_ACV_TRUN_HI 0x01e -#define ZR050_ACV_TRUN_MH 0x01f -#define ZR050_ACV_TRUN_ML 0x020 -#define ZR050_ACV_TRUN_LO 0x021 -#define ZR050_STATUS_0 0x02e -#define ZR050_STATUS_1 0x02f - -#define ZR050_SOF_IDX 0x040 -#define ZR050_SOS1_IDX 0x07a -#define ZR050_SOS2_IDX 0x08a -#define ZR050_SOS3_IDX 0x09a -#define ZR050_SOS4_IDX 0x0aa -#define ZR050_DRI_IDX 0x0c0 -#define ZR050_DNL_IDX 0x0c6 -#define ZR050_DQT_IDX 0x0cc -#define ZR050_DHT_IDX 0x1d4 -#define ZR050_APP_IDX 0x380 -#define ZR050_COM_IDX 0x3c0 - -/* zr36050 hardware register bits */ - -#define ZR050_HW_BSWD 0x80 -#define ZR050_HW_MSTR 0x40 -#define ZR050_HW_DMA 0x20 -#define ZR050_HW_CFIS_1_CLK 0x00 -#define ZR050_HW_CFIS_2_CLK 0x04 -#define ZR050_HW_CFIS_3_CLK 0x08 -#define ZR050_HW_CFIS_4_CLK 0x0C -#define ZR050_HW_CFIS_5_CLK 0x10 -#define ZR050_HW_CFIS_6_CLK 0x14 -#define ZR050_HW_CFIS_7_CLK 0x18 -#define ZR050_HW_CFIS_8_CLK 0x1C -#define ZR050_HW_BELE 0x01 - -/* zr36050 mode register bits */ - -#define ZR050_MO_COMP 0x80 -#define ZR050_MO_ATP 0x40 -#define ZR050_MO_PASS2 0x20 -#define ZR050_MO_TLM 0x10 -#define ZR050_MO_DCONLY 0x08 -#define ZR050_MO_BRC 0x04 - -#define ZR050_MO_ATP 0x40 -#define ZR050_MO_PASS2 0x20 -#define ZR050_MO_TLM 0x10 -#define ZR050_MO_DCONLY 0x08 - -/* zr36050 option register bits */ - -#define ZR050_OP_NSCN_1 0x00 -#define ZR050_OP_NSCN_2 0x20 -#define ZR050_OP_NSCN_3 0x40 -#define ZR050_OP_NSCN_4 0x60 -#define ZR050_OP_NSCN_5 0x80 -#define ZR050_OP_NSCN_6 0xA0 -#define ZR050_OP_NSCN_7 0xC0 -#define ZR050_OP_NSCN_8 0xE0 -#define ZR050_OP_OVF 0x10 - - -/* zr36050 markers-enable register bits */ - -#define ZR050_ME_APP 0x80 -#define ZR050_ME_COM 0x40 -#define ZR050_ME_DRI 0x20 -#define ZR050_ME_DQT 0x10 -#define ZR050_ME_DHT 0x08 -#define ZR050_ME_DNL 0x04 -#define ZR050_ME_DQTI 0x02 -#define ZR050_ME_DHTI 0x01 - -/* zr36050 status0/1 register bit masks */ - -#define ZR050_ST_RST_MASK 0x20 -#define ZR050_ST_SOF_MASK 0x02 -#define ZR050_ST_SOS_MASK 0x02 -#define ZR050_ST_DATRDY_MASK 0x80 -#define ZR050_ST_MRKDET_MASK 0x40 -#define ZR050_ST_RFM_MASK 0x10 -#define ZR050_ST_RFD_MASK 0x08 -#define ZR050_ST_END_MASK 0x04 -#define ZR050_ST_TCVOVF_MASK 0x02 -#define ZR050_ST_DATOVF_MASK 0x01 - -/* pixel component idx */ - -#define ZR050_Y_COMPONENT 0 -#define ZR050_U_COMPONENT 1 -#define ZR050_V_COMPONENT 2 - -#endif /*fndef ZR36050_H */ diff --git a/drivers/staging/media/zoran/zr36057.h b/drivers/staging/media/zoran/zr36057.h deleted file mode 100644 index c5138cef4ef5..000000000000 --- a/drivers/staging/media/zoran/zr36057.h +++ /dev/null @@ -1,154 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * zr36057.h - zr36057 register offsets - * - * Copyright (C) 1998 Dave Perks <dperks@ibm.net> - */ -#ifndef _ZR36057_H_ -#define _ZR36057_H_ - - -/* Zoran ZR36057 registers */ - -#define ZR36057_VFEHCR 0x000 /* Video Front End, Horizontal Configuration Register */ -#define ZR36057_VFEHCR_HSPol (1<<30) -#define ZR36057_VFEHCR_HStart 10 -#define ZR36057_VFEHCR_HEnd 0 -#define ZR36057_VFEHCR_Hmask 0x3ff - -#define ZR36057_VFEVCR 0x004 /* Video Front End, Vertical Configuration Register */ -#define ZR36057_VFEVCR_VSPol (1<<30) -#define ZR36057_VFEVCR_VStart 10 -#define ZR36057_VFEVCR_VEnd 0 -#define ZR36057_VFEVCR_Vmask 0x3ff - -#define ZR36057_VFESPFR 0x008 /* Video Front End, Scaler and Pixel Format Register */ -#define ZR36057_VFESPFR_ExtFl (1<<26) -#define ZR36057_VFESPFR_TopField (1<<25) -#define ZR36057_VFESPFR_VCLKPol (1<<24) -#define ZR36057_VFESPFR_HFilter 21 -#define ZR36057_VFESPFR_HorDcm 14 -#define ZR36057_VFESPFR_VerDcm 8 -#define ZR36057_VFESPFR_DispMode 6 -#define ZR36057_VFESPFR_YUV422 (0<<3) -#define ZR36057_VFESPFR_RGB888 (1<<3) -#define ZR36057_VFESPFR_RGB565 (2<<3) -#define ZR36057_VFESPFR_RGB555 (3<<3) -#define ZR36057_VFESPFR_ErrDif (1<<2) -#define ZR36057_VFESPFR_Pack24 (1<<1) -#define ZR36057_VFESPFR_LittleEndian (1<<0) - -#define ZR36057_VDTR 0x00c /* Video Display "Top" Register */ - -#define ZR36057_VDBR 0x010 /* Video Display "Bottom" Register */ - -#define ZR36057_VSSFGR 0x014 /* Video Stride, Status, and Frame Grab Register */ -#define ZR36057_VSSFGR_DispStride 16 -#define ZR36057_VSSFGR_VidOvf (1<<8) -#define ZR36057_VSSFGR_SnapShot (1<<1) -#define ZR36057_VSSFGR_FrameGrab (1<<0) - -#define ZR36057_VDCR 0x018 /* Video Display Configuration Register */ -#define ZR36057_VDCR_VidEn (1<<31) -#define ZR36057_VDCR_MinPix 24 -#define ZR36057_VDCR_Triton (1<<24) -#define ZR36057_VDCR_VidWinHt 12 -#define ZR36057_VDCR_VidWinWid 0 - -#define ZR36057_MMTR 0x01c /* Masking Map "Top" Register */ - -#define ZR36057_MMBR 0x020 /* Masking Map "Bottom" Register */ - -#define ZR36057_OCR 0x024 /* Overlay Control Register */ -#define ZR36057_OCR_OvlEnable (1 << 15) -#define ZR36057_OCR_MaskStride 0 - -#define ZR36057_SPGPPCR 0x028 /* System, PCI, and General Purpose Pins Control Register */ -#define ZR36057_SPGPPCR_SoftReset (1<<24) - -#define ZR36057_GPPGCR1 0x02c /* General Purpose Pins and GuestBus Control Register (1) */ - -#define ZR36057_MCSAR 0x030 /* MPEG Code Source Address Register */ - -#define ZR36057_MCTCR 0x034 /* MPEG Code Transfer Control Register */ -#define ZR36057_MCTCR_CodTime (1 << 30) -#define ZR36057_MCTCR_CEmpty (1 << 29) -#define ZR36057_MCTCR_CFlush (1 << 28) -#define ZR36057_MCTCR_CodGuestID 20 -#define ZR36057_MCTCR_CodGuestReg 16 - -#define ZR36057_MCMPR 0x038 /* MPEG Code Memory Pointer Register */ - -#define ZR36057_ISR 0x03c /* Interrupt Status Register */ -#define ZR36057_ISR_GIRQ1 (1<<30) -#define ZR36057_ISR_GIRQ0 (1<<29) -#define ZR36057_ISR_CodRepIRQ (1<<28) -#define ZR36057_ISR_JPEGRepIRQ (1<<27) - -#define ZR36057_ICR 0x040 /* Interrupt Control Register */ -#define ZR36057_ICR_GIRQ1 (1<<30) -#define ZR36057_ICR_GIRQ0 (1<<29) -#define ZR36057_ICR_CodRepIRQ (1<<28) -#define ZR36057_ICR_JPEGRepIRQ (1<<27) -#define ZR36057_ICR_IntPinEn (1<<24) - -#define ZR36057_I2CBR 0x044 /* I2C Bus Register */ -#define ZR36057_I2CBR_SDA (1<<1) -#define ZR36057_I2CBR_SCL (1<<0) - -#define ZR36057_JMC 0x100 /* JPEG Mode and Control */ -#define ZR36057_JMC_JPG (1 << 31) -#define ZR36057_JMC_JPGExpMode (0 << 29) -#define ZR36057_JMC_JPGCmpMode (1 << 29) -#define ZR36057_JMC_MJPGExpMode (2 << 29) -#define ZR36057_JMC_MJPGCmpMode (3 << 29) -#define ZR36057_JMC_RTBUSY_FB (1 << 6) -#define ZR36057_JMC_Go_en (1 << 5) -#define ZR36057_JMC_SyncMstr (1 << 4) -#define ZR36057_JMC_Fld_per_buff (1 << 3) -#define ZR36057_JMC_VFIFO_FB (1 << 2) -#define ZR36057_JMC_CFIFO_FB (1 << 1) -#define ZR36057_JMC_Stll_LitEndian (1 << 0) - -#define ZR36057_JPC 0x104 /* JPEG Process Control */ -#define ZR36057_JPC_P_Reset (1 << 7) -#define ZR36057_JPC_CodTrnsEn (1 << 5) -#define ZR36057_JPC_Active (1 << 0) - -#define ZR36057_VSP 0x108 /* Vertical Sync Parameters */ -#define ZR36057_VSP_VsyncSize 16 -#define ZR36057_VSP_FrmTot 0 - -#define ZR36057_HSP 0x10c /* Horizontal Sync Parameters */ -#define ZR36057_HSP_HsyncStart 16 -#define ZR36057_HSP_LineTot 0 - -#define ZR36057_FHAP 0x110 /* Field Horizontal Active Portion */ -#define ZR36057_FHAP_NAX 16 -#define ZR36057_FHAP_PAX 0 - -#define ZR36057_FVAP 0x114 /* Field Vertical Active Portion */ -#define ZR36057_FVAP_NAY 16 -#define ZR36057_FVAP_PAY 0 - -#define ZR36057_FPP 0x118 /* Field Process Parameters */ -#define ZR36057_FPP_Odd_Even (1 << 0) - -#define ZR36057_JCBA 0x11c /* JPEG Code Base Address */ - -#define ZR36057_JCFT 0x120 /* JPEG Code FIFO Threshold */ - -#define ZR36057_JCGI 0x124 /* JPEG Codec Guest ID */ -#define ZR36057_JCGI_JPEGuestID 4 -#define ZR36057_JCGI_JPEGuestReg 0 - -#define ZR36057_GCR2 0x12c /* GuestBus Control Register (2) */ - -#define ZR36057_POR 0x200 /* Post Office Register */ -#define ZR36057_POR_POPen (1<<25) -#define ZR36057_POR_POTime (1<<24) -#define ZR36057_POR_PODir (1<<23) - -#define ZR36057_STR 0x300 /* "Still" Transfer Register */ - -#endif diff --git a/drivers/staging/media/zoran/zr36060.c b/drivers/staging/media/zoran/zr36060.c deleted file mode 100644 index a3c817fd5c07..000000000000 --- a/drivers/staging/media/zoran/zr36060.c +++ /dev/null @@ -1,994 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0+ -/* - * Zoran ZR36060 basic configuration functions - * - * Copyright (C) 2002 Laurent Pinchart <laurent.pinchart@skynet.be> - */ -#define ZR060_VERSION "v0.7" - -#include <linux/module.h> -#include <linux/init.h> -#include <linux/slab.h> -#include <linux/delay.h> - -#include <linux/types.h> -#include <linux/wait.h> - -/* I/O commands, error codes */ -#include <asm/io.h> - -/* headerfile of this module */ -#include "zr36060.h" - -/* codec io API */ -#include "videocodec.h" - -/* it doesn't make sense to have more than 20 or so, - * just to prevent some unwanted loops - */ -#define MAX_CODECS 20 - -/* amount of chips attached via this driver */ -static int zr36060_codecs; - -static bool low_bitrate; -module_param(low_bitrate, bool, 0); -MODULE_PARM_DESC(low_bitrate, "Buz compatibility option, halves bitrate"); - -/* debugging is available via module parameter */ -static int debug; -module_param(debug, int, 0); -MODULE_PARM_DESC(debug, "Debug level (0-4)"); - -#define dprintk(num, format, args...) \ - do { \ - if (debug >= num) \ - printk(format, ##args); \ - } while (0) - -/* ========================================================================= - Local hardware I/O functions: - - read/write via codec layer (registers are located in the master device) - ========================================================================= */ - -/* read and write functions */ -static u8 -zr36060_read (struct zr36060 *ptr, - u16 reg) -{ - u8 value = 0; - - // just in case something is wrong... - if (ptr->codec->master_data->readreg) - value = (ptr->codec->master_data->readreg(ptr->codec, - reg)) & 0xff; - else - dprintk(1, - KERN_ERR "%s: invalid I/O setup, nothing read!\n", - ptr->name); - - //dprintk(4, "%s: reading from 0x%04x: %02x\n",ptr->name,reg,value); - - return value; -} - -static void -zr36060_write(struct zr36060 *ptr, - u16 reg, - u8 value) -{ - //dprintk(4, "%s: writing 0x%02x to 0x%04x\n",ptr->name,value,reg); - dprintk(4, "0x%02x @0x%04x\n", value, reg); - - // just in case something is wrong... - if (ptr->codec->master_data->writereg) - ptr->codec->master_data->writereg(ptr->codec, reg, value); - else - dprintk(1, - KERN_ERR - "%s: invalid I/O setup, nothing written!\n", - ptr->name); -} - -/* ========================================================================= - Local helper function: - - status read - ========================================================================= */ - -/* status is kept in datastructure */ -static u8 -zr36060_read_status (struct zr36060 *ptr) -{ - ptr->status = zr36060_read(ptr, ZR060_CFSR); - - zr36060_read(ptr, 0); - return ptr->status; -} - -/* ========================================================================= - Local helper function: - - scale factor read - ========================================================================= */ - -/* scale factor is kept in datastructure */ -static u16 -zr36060_read_scalefactor (struct zr36060 *ptr) -{ - ptr->scalefact = (zr36060_read(ptr, ZR060_SF_HI) << 8) | - (zr36060_read(ptr, ZR060_SF_LO) & 0xFF); - - /* leave 0 selected for an eventually GO from master */ - zr36060_read(ptr, 0); - return ptr->scalefact; -} - -/* ========================================================================= - Local helper function: - - wait if codec is ready to proceed (end of processing) or time is over - ========================================================================= */ - -static void -zr36060_wait_end (struct zr36060 *ptr) -{ - int i = 0; - - while (zr36060_read_status(ptr) & ZR060_CFSR_Busy) { - udelay(1); - if (i++ > 200000) { // 200ms, there is for sure something wrong!!! - dprintk(1, - "%s: timeout at wait_end (last status: 0x%02x)\n", - ptr->name, ptr->status); - break; - } - } -} - -/* ========================================================================= - Local helper function: - - basic test of "connectivity", writes/reads to/from memory the SOF marker - ========================================================================= */ - -static int -zr36060_basic_test (struct zr36060 *ptr) -{ - if ((zr36060_read(ptr, ZR060_IDR_DEV) != 0x33) && - (zr36060_read(ptr, ZR060_IDR_REV) != 0x01)) { - dprintk(1, - KERN_ERR - "%s: attach failed, can't connect to jpeg processor!\n", - ptr->name); - return -ENXIO; - } - - zr36060_wait_end(ptr); - if (ptr->status & ZR060_CFSR_Busy) { - dprintk(1, - KERN_ERR - "%s: attach failed, jpeg processor failed (end flag)!\n", - ptr->name); - return -EBUSY; - } - - return 0; /* looks good! */ -} - -/* ========================================================================= - Local helper function: - - simple loop for pushing the init datasets - ========================================================================= */ - -static int -zr36060_pushit (struct zr36060 *ptr, - u16 startreg, - u16 len, - const char *data) -{ - int i = 0; - - dprintk(4, "%s: write data block to 0x%04x (len=%d)\n", ptr->name, - startreg, len); - while (i < len) { - zr36060_write(ptr, startreg++, data[i++]); - } - - return i; -} - -/* ========================================================================= - Basic datasets: - - jpeg baseline setup data (you find it on lots places in internet, or just - extract it from any regular .jpg image...) - - Could be variable, but until it's not needed it they are just fixed to save - memory. Otherwise expand zr36060 structure with arrays, push the values to - it and initialize from there, as e.g. the linux zr36057/60 driver does it. - ========================================================================= */ - -static const char zr36060_dqt[0x86] = { - 0xff, 0xdb, //Marker: DQT - 0x00, 0x84, //Length: 2*65+2 - 0x00, //Pq,Tq first table - 0x10, 0x0b, 0x0c, 0x0e, 0x0c, 0x0a, 0x10, 0x0e, - 0x0d, 0x0e, 0x12, 0x11, 0x10, 0x13, 0x18, 0x28, - 0x1a, 0x18, 0x16, 0x16, 0x18, 0x31, 0x23, 0x25, - 0x1d, 0x28, 0x3a, 0x33, 0x3d, 0x3c, 0x39, 0x33, - 0x38, 0x37, 0x40, 0x48, 0x5c, 0x4e, 0x40, 0x44, - 0x57, 0x45, 0x37, 0x38, 0x50, 0x6d, 0x51, 0x57, - 0x5f, 0x62, 0x67, 0x68, 0x67, 0x3e, 0x4d, 0x71, - 0x79, 0x70, 0x64, 0x78, 0x5c, 0x65, 0x67, 0x63, - 0x01, //Pq,Tq second table - 0x11, 0x12, 0x12, 0x18, 0x15, 0x18, 0x2f, 0x1a, - 0x1a, 0x2f, 0x63, 0x42, 0x38, 0x42, 0x63, 0x63, - 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, - 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, - 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, - 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, - 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, - 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63 -}; - -static const char zr36060_dht[0x1a4] = { - 0xff, 0xc4, //Marker: DHT - 0x01, 0xa2, //Length: 2*AC, 2*DC - 0x00, //DC first table - 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, - 0x01, //DC second table - 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, - 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, - 0x10, //AC first table - 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, - 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, - 0x01, 0x7D, 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, - 0x05, 0x12, 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, - 0x07, 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xA1, - 0x08, 0x23, 0x42, 0xB1, 0xC1, 0x15, 0x52, 0xD1, 0xF0, 0x24, - 0x33, 0x62, 0x72, 0x82, 0x09, 0x0A, 0x16, 0x17, - 0x18, 0x19, 0x1A, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x34, - 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, - 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, 0x55, 0x56, - 0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, - 0x67, 0x68, 0x69, 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, - 0x79, 0x7A, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, - 0x89, 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, - 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, - 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, - 0xBA, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, - 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, - 0xDA, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, - 0xE8, 0xE9, 0xEA, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, - 0xF8, 0xF9, 0xFA, - 0x11, //AC second table - 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, - 0x07, 0x05, 0x04, 0x04, 0x00, 0x01, - 0x02, 0x77, 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, - 0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, - 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91, - 0xA1, 0xB1, 0xC1, 0x09, 0x23, 0x33, 0x52, 0xF0, 0x15, 0x62, - 0x72, 0xD1, 0x0A, 0x16, 0x24, 0x34, 0xE1, 0x25, - 0xF1, 0x17, 0x18, 0x19, 0x1A, 0x26, 0x27, 0x28, 0x29, 0x2A, - 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, - 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, 0x55, 0x56, - 0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, - 0x67, 0x68, 0x69, 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, - 0x79, 0x7A, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, - 0x88, 0x89, 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, - 0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, - 0xA8, 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, - 0xB9, 0xBA, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, - 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, - 0xD9, 0xDA, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, - 0xE8, 0xE9, 0xEA, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, - 0xF9, 0xFA -}; - -/* jpeg baseline setup, this is just fixed in this driver (YUV pictures) */ -#define NO_OF_COMPONENTS 0x3 //Y,U,V -#define BASELINE_PRECISION 0x8 //MCU size (?) -static const char zr36060_tq[8] = { 0, 1, 1, 0, 0, 0, 0, 0 }; //table idx's QT -static const char zr36060_td[8] = { 0, 1, 1, 0, 0, 0, 0, 0 }; //table idx's DC -static const char zr36060_ta[8] = { 0, 1, 1, 0, 0, 0, 0, 0 }; //table idx's AC - -/* horizontal 422 decimation setup (maybe we support 411 or so later, too) */ -static const char zr36060_decimation_h[8] = { 2, 1, 1, 0, 0, 0, 0, 0 }; -static const char zr36060_decimation_v[8] = { 1, 1, 1, 0, 0, 0, 0, 0 }; - -/* ========================================================================= - Local helper functions: - - calculation and setup of parameter-dependent JPEG baseline segments - (needed for compression only) - ========================================================================= */ - -/* ------------------------------------------------------------------------- */ - -/* SOF (start of frame) segment depends on width, height and sampling ratio - of each color component */ - -static int -zr36060_set_sof (struct zr36060 *ptr) -{ - char sof_data[34]; // max. size of register set - int i; - - dprintk(3, "%s: write SOF (%dx%d, %d components)\n", ptr->name, - ptr->width, ptr->height, NO_OF_COMPONENTS); - sof_data[0] = 0xff; - sof_data[1] = 0xc0; - sof_data[2] = 0x00; - sof_data[3] = (3 * NO_OF_COMPONENTS) + 8; - sof_data[4] = BASELINE_PRECISION; // only '8' possible with zr36060 - sof_data[5] = (ptr->height) >> 8; - sof_data[6] = (ptr->height) & 0xff; - sof_data[7] = (ptr->width) >> 8; - sof_data[8] = (ptr->width) & 0xff; - sof_data[9] = NO_OF_COMPONENTS; - for (i = 0; i < NO_OF_COMPONENTS; i++) { - sof_data[10 + (i * 3)] = i; // index identifier - sof_data[11 + (i * 3)] = (ptr->h_samp_ratio[i] << 4) | - (ptr->v_samp_ratio[i]); // sampling ratios - sof_data[12 + (i * 3)] = zr36060_tq[i]; // Q table selection - } - return zr36060_pushit(ptr, ZR060_SOF_IDX, - (3 * NO_OF_COMPONENTS) + 10, sof_data); -} - -/* ------------------------------------------------------------------------- */ - -/* SOS (start of scan) segment depends on the used scan components - of each color component */ - -static int -zr36060_set_sos (struct zr36060 *ptr) -{ - char sos_data[16]; // max. size of register set - int i; - - dprintk(3, "%s: write SOS\n", ptr->name); - sos_data[0] = 0xff; - sos_data[1] = 0xda; - sos_data[2] = 0x00; - sos_data[3] = 2 + 1 + (2 * NO_OF_COMPONENTS) + 3; - sos_data[4] = NO_OF_COMPONENTS; - for (i = 0; i < NO_OF_COMPONENTS; i++) { - sos_data[5 + (i * 2)] = i; // index - sos_data[6 + (i * 2)] = (zr36060_td[i] << 4) | - zr36060_ta[i]; // AC/DC tbl.sel. - } - sos_data[2 + 1 + (2 * NO_OF_COMPONENTS) + 2] = 00; // scan start - sos_data[2 + 1 + (2 * NO_OF_COMPONENTS) + 3] = 0x3f; - sos_data[2 + 1 + (2 * NO_OF_COMPONENTS) + 4] = 00; - return zr36060_pushit(ptr, ZR060_SOS_IDX, - 4 + 1 + (2 * NO_OF_COMPONENTS) + 3, - sos_data); -} - -/* ------------------------------------------------------------------------- */ - -/* DRI (define restart interval) */ - -static int -zr36060_set_dri (struct zr36060 *ptr) -{ - char dri_data[6]; // max. size of register set - - dprintk(3, "%s: write DRI\n", ptr->name); - dri_data[0] = 0xff; - dri_data[1] = 0xdd; - dri_data[2] = 0x00; - dri_data[3] = 0x04; - dri_data[4] = (ptr->dri) >> 8; - dri_data[5] = (ptr->dri) & 0xff; - return zr36060_pushit(ptr, ZR060_DRI_IDX, 6, dri_data); -} - -/* ========================================================================= - Setup function: - - Setup compression/decompression of Zoran's JPEG processor - ( see also zoran 36060 manual ) - - ... sorry for the spaghetti code ... - ========================================================================= */ -static void -zr36060_init (struct zr36060 *ptr) -{ - int sum = 0; - long bitcnt, tmp; - - if (ptr->mode == CODEC_DO_COMPRESSION) { - dprintk(2, "%s: COMPRESSION SETUP\n", ptr->name); - - zr36060_write(ptr, ZR060_LOAD, ZR060_LOAD_SyncRst); - - /* 060 communicates with 067 in master mode */ - zr36060_write(ptr, ZR060_CIR, ZR060_CIR_CodeMstr); - - /* Compression with or without variable scale factor */ - /*FIXME: What about ptr->bitrate_ctrl? */ - zr36060_write(ptr, ZR060_CMR, - ZR060_CMR_Comp | ZR060_CMR_Pass2 | - ZR060_CMR_BRB); - - /* Must be zero */ - zr36060_write(ptr, ZR060_MBZ, 0x00); - zr36060_write(ptr, ZR060_TCR_HI, 0x00); - zr36060_write(ptr, ZR060_TCR_LO, 0x00); - - /* Disable all IRQs - no DataErr means autoreset */ - zr36060_write(ptr, ZR060_IMR, 0); - - /* volume control settings */ - zr36060_write(ptr, ZR060_SF_HI, ptr->scalefact >> 8); - zr36060_write(ptr, ZR060_SF_LO, ptr->scalefact & 0xff); - - zr36060_write(ptr, ZR060_AF_HI, 0xff); - zr36060_write(ptr, ZR060_AF_M, 0xff); - zr36060_write(ptr, ZR060_AF_LO, 0xff); - - /* setup the variable jpeg tables */ - sum += zr36060_set_sof(ptr); - sum += zr36060_set_sos(ptr); - sum += zr36060_set_dri(ptr); - - /* setup the fixed jpeg tables - maybe variable, though - - * (see table init section above) */ - sum += - zr36060_pushit(ptr, ZR060_DQT_IDX, sizeof(zr36060_dqt), - zr36060_dqt); - sum += - zr36060_pushit(ptr, ZR060_DHT_IDX, sizeof(zr36060_dht), - zr36060_dht); - zr36060_write(ptr, ZR060_APP_IDX, 0xff); - zr36060_write(ptr, ZR060_APP_IDX + 1, 0xe0 + ptr->app.appn); - zr36060_write(ptr, ZR060_APP_IDX + 2, 0x00); - zr36060_write(ptr, ZR060_APP_IDX + 3, ptr->app.len + 2); - sum += zr36060_pushit(ptr, ZR060_APP_IDX + 4, 60, - ptr->app.data) + 4; - zr36060_write(ptr, ZR060_COM_IDX, 0xff); - zr36060_write(ptr, ZR060_COM_IDX + 1, 0xfe); - zr36060_write(ptr, ZR060_COM_IDX + 2, 0x00); - zr36060_write(ptr, ZR060_COM_IDX + 3, ptr->com.len + 2); - sum += zr36060_pushit(ptr, ZR060_COM_IDX + 4, 60, - ptr->com.data) + 4; - - /* setup misc. data for compression (target code sizes) */ - - /* size of compressed code to reach without header data */ - sum = ptr->real_code_vol - sum; - bitcnt = sum << 3; /* need the size in bits */ - - tmp = bitcnt >> 16; - dprintk(3, - "%s: code: csize=%d, tot=%d, bit=%ld, highbits=%ld\n", - ptr->name, sum, ptr->real_code_vol, bitcnt, tmp); - zr36060_write(ptr, ZR060_TCV_NET_HI, tmp >> 8); - zr36060_write(ptr, ZR060_TCV_NET_MH, tmp & 0xff); - tmp = bitcnt & 0xffff; - zr36060_write(ptr, ZR060_TCV_NET_ML, tmp >> 8); - zr36060_write(ptr, ZR060_TCV_NET_LO, tmp & 0xff); - - bitcnt -= bitcnt >> 7; // bits without stuffing - bitcnt -= ((bitcnt * 5) >> 6); // bits without eob - - tmp = bitcnt >> 16; - dprintk(3, "%s: code: nettobit=%ld, highnettobits=%ld\n", - ptr->name, bitcnt, tmp); - zr36060_write(ptr, ZR060_TCV_DATA_HI, tmp >> 8); - zr36060_write(ptr, ZR060_TCV_DATA_MH, tmp & 0xff); - tmp = bitcnt & 0xffff; - zr36060_write(ptr, ZR060_TCV_DATA_ML, tmp >> 8); - zr36060_write(ptr, ZR060_TCV_DATA_LO, tmp & 0xff); - - /* JPEG markers to be included in the compressed stream */ - zr36060_write(ptr, ZR060_MER, - ZR060_MER_DQT | ZR060_MER_DHT | - ((ptr->com.len > 0) ? ZR060_MER_Com : 0) | - ((ptr->app.len > 0) ? ZR060_MER_App : 0)); - - /* Setup the Video Frontend */ - /* Limit pixel range to 16..235 as per CCIR-601 */ - zr36060_write(ptr, ZR060_VCR, ZR060_VCR_Range); - - } else { - dprintk(2, "%s: EXPANSION SETUP\n", ptr->name); - - zr36060_write(ptr, ZR060_LOAD, ZR060_LOAD_SyncRst); - - /* 060 communicates with 067 in master mode */ - zr36060_write(ptr, ZR060_CIR, ZR060_CIR_CodeMstr); - - /* Decompression */ - zr36060_write(ptr, ZR060_CMR, 0); - - /* Must be zero */ - zr36060_write(ptr, ZR060_MBZ, 0x00); - zr36060_write(ptr, ZR060_TCR_HI, 0x00); - zr36060_write(ptr, ZR060_TCR_LO, 0x00); - - /* Disable all IRQs - no DataErr means autoreset */ - zr36060_write(ptr, ZR060_IMR, 0); - - /* setup misc. data for expansion */ - zr36060_write(ptr, ZR060_MER, 0); - - /* setup the fixed jpeg tables - maybe variable, though - - * (see table init section above) */ - zr36060_pushit(ptr, ZR060_DHT_IDX, sizeof(zr36060_dht), - zr36060_dht); - - /* Setup the Video Frontend */ - //zr36060_write(ptr, ZR060_VCR, ZR060_VCR_FIExt); - //this doesn't seem right and doesn't work... - zr36060_write(ptr, ZR060_VCR, ZR060_VCR_Range); - } - - /* Load the tables */ - zr36060_write(ptr, ZR060_LOAD, - ZR060_LOAD_SyncRst | ZR060_LOAD_Load); - zr36060_wait_end(ptr); - dprintk(2, "%s: Status after table preload: 0x%02x\n", ptr->name, - ptr->status); - - if (ptr->status & ZR060_CFSR_Busy) { - dprintk(1, KERN_ERR "%s: init aborted!\n", ptr->name); - return; // something is wrong, its timed out!!!! - } -} - -/* ========================================================================= - CODEC API FUNCTIONS - - this functions are accessed by the master via the API structure - ========================================================================= */ - -/* set compression/expansion mode and launches codec - - this should be the last call from the master before starting processing */ -static int -zr36060_set_mode (struct videocodec *codec, - int mode) -{ - struct zr36060 *ptr = (struct zr36060 *) codec->data; - - dprintk(2, "%s: set_mode %d call\n", ptr->name, mode); - - if ((mode != CODEC_DO_EXPANSION) && (mode != CODEC_DO_COMPRESSION)) - return -EINVAL; - - ptr->mode = mode; - zr36060_init(ptr); - - return 0; -} - -/* set picture size (norm is ignored as the codec doesn't know about it) */ -static int -zr36060_set_video (struct videocodec *codec, - struct tvnorm *norm, - struct vfe_settings *cap, - struct vfe_polarity *pol) -{ - struct zr36060 *ptr = (struct zr36060 *) codec->data; - u32 reg; - int size; - - dprintk(2, "%s: set_video %d/%d-%dx%d (%%%d) call\n", ptr->name, - cap->x, cap->y, cap->width, cap->height, cap->decimation); - - /* if () return -EINVAL; - * trust the master driver that it knows what it does - so - * we allow invalid startx/y and norm for now ... */ - ptr->width = cap->width / (cap->decimation & 0xff); - ptr->height = cap->height / (cap->decimation >> 8); - - zr36060_write(ptr, ZR060_LOAD, ZR060_LOAD_SyncRst); - - /* Note that VSPol/HSPol bits in zr36060 have the opposite - * meaning of their zr360x7 counterparts with the same names - * N.b. for VSPol this is only true if FIVEdge = 0 (default, - * left unchanged here - in accordance with datasheet). - */ - reg = (!pol->vsync_pol ? ZR060_VPR_VSPol : 0) - | (!pol->hsync_pol ? ZR060_VPR_HSPol : 0) - | (pol->field_pol ? ZR060_VPR_FIPol : 0) - | (pol->blank_pol ? ZR060_VPR_BLPol : 0) - | (pol->subimg_pol ? ZR060_VPR_SImgPol : 0) - | (pol->poe_pol ? ZR060_VPR_PoePol : 0) - | (pol->pvalid_pol ? ZR060_VPR_PValPol : 0) - | (pol->vclk_pol ? ZR060_VPR_VCLKPol : 0); - zr36060_write(ptr, ZR060_VPR, reg); - - reg = 0; - switch (cap->decimation & 0xff) { - default: - case 1: - break; - - case 2: - reg |= ZR060_SR_HScale2; - break; - - case 4: - reg |= ZR060_SR_HScale4; - break; - } - - switch (cap->decimation >> 8) { - default: - case 1: - break; - - case 2: - reg |= ZR060_SR_VScale; - break; - } - zr36060_write(ptr, ZR060_SR, reg); - - zr36060_write(ptr, ZR060_BCR_Y, 0x00); - zr36060_write(ptr, ZR060_BCR_U, 0x80); - zr36060_write(ptr, ZR060_BCR_V, 0x80); - - /* sync generator */ - - reg = norm->Ht - 1; /* Vtotal */ - zr36060_write(ptr, ZR060_SGR_VTOTAL_HI, (reg >> 8) & 0xff); - zr36060_write(ptr, ZR060_SGR_VTOTAL_LO, (reg >> 0) & 0xff); - - reg = norm->Wt - 1; /* Htotal */ - zr36060_write(ptr, ZR060_SGR_HTOTAL_HI, (reg >> 8) & 0xff); - zr36060_write(ptr, ZR060_SGR_HTOTAL_LO, (reg >> 0) & 0xff); - - reg = 6 - 1; /* VsyncSize */ - zr36060_write(ptr, ZR060_SGR_VSYNC, reg); - - //reg = 30 - 1; /* HsyncSize */ -///*CP*/ reg = (zr->params.norm == 1 ? 57 : 68); - reg = 68; - zr36060_write(ptr, ZR060_SGR_HSYNC, reg); - - reg = norm->VStart - 1; /* BVstart */ - zr36060_write(ptr, ZR060_SGR_BVSTART, reg); - - reg += norm->Ha / 2; /* BVend */ - zr36060_write(ptr, ZR060_SGR_BVEND_HI, (reg >> 8) & 0xff); - zr36060_write(ptr, ZR060_SGR_BVEND_LO, (reg >> 0) & 0xff); - - reg = norm->HStart - 1; /* BHstart */ - zr36060_write(ptr, ZR060_SGR_BHSTART, reg); - - reg += norm->Wa; /* BHend */ - zr36060_write(ptr, ZR060_SGR_BHEND_HI, (reg >> 8) & 0xff); - zr36060_write(ptr, ZR060_SGR_BHEND_LO, (reg >> 0) & 0xff); - - /* active area */ - reg = cap->y + norm->VStart; /* Vstart */ - zr36060_write(ptr, ZR060_AAR_VSTART_HI, (reg >> 8) & 0xff); - zr36060_write(ptr, ZR060_AAR_VSTART_LO, (reg >> 0) & 0xff); - - reg += cap->height; /* Vend */ - zr36060_write(ptr, ZR060_AAR_VEND_HI, (reg >> 8) & 0xff); - zr36060_write(ptr, ZR060_AAR_VEND_LO, (reg >> 0) & 0xff); - - reg = cap->x + norm->HStart; /* Hstart */ - zr36060_write(ptr, ZR060_AAR_HSTART_HI, (reg >> 8) & 0xff); - zr36060_write(ptr, ZR060_AAR_HSTART_LO, (reg >> 0) & 0xff); - - reg += cap->width; /* Hend */ - zr36060_write(ptr, ZR060_AAR_HEND_HI, (reg >> 8) & 0xff); - zr36060_write(ptr, ZR060_AAR_HEND_LO, (reg >> 0) & 0xff); - - /* subimage area */ - reg = norm->VStart - 4; /* SVstart */ - zr36060_write(ptr, ZR060_SWR_VSTART_HI, (reg >> 8) & 0xff); - zr36060_write(ptr, ZR060_SWR_VSTART_LO, (reg >> 0) & 0xff); - - reg += norm->Ha / 2 + 8; /* SVend */ - zr36060_write(ptr, ZR060_SWR_VEND_HI, (reg >> 8) & 0xff); - zr36060_write(ptr, ZR060_SWR_VEND_LO, (reg >> 0) & 0xff); - - reg = norm->HStart /*+ 64 */ - 4; /* SHstart */ - zr36060_write(ptr, ZR060_SWR_HSTART_HI, (reg >> 8) & 0xff); - zr36060_write(ptr, ZR060_SWR_HSTART_LO, (reg >> 0) & 0xff); - - reg += norm->Wa + 8; /* SHend */ - zr36060_write(ptr, ZR060_SWR_HEND_HI, (reg >> 8) & 0xff); - zr36060_write(ptr, ZR060_SWR_HEND_LO, (reg >> 0) & 0xff); - - size = ptr->width * ptr->height; - /* Target compressed field size in bits: */ - size = size * 16; /* uncompressed size in bits */ - /* (Ronald) by default, quality = 100 is a compression - * ratio 1:2. Setting low_bitrate (insmod option) sets - * it to 1:4 (instead of 1:2, zr36060 max) as limit because the - * buz can't handle more at decimation=1... Use low_bitrate if - * you have a Buz, unless you know what you're doing - */ - size = size * cap->quality / (low_bitrate ? 400 : 200); - /* Lower limit (arbitrary, 1 KB) */ - if (size < 8192) - size = 8192; - /* Upper limit: 7/8 of the code buffers */ - if (size > ptr->total_code_vol * 7) - size = ptr->total_code_vol * 7; - - ptr->real_code_vol = size >> 3; /* in bytes */ - - /* the MBCVR is the *maximum* block volume, according to the - * JPEG ISO specs, this shouldn't be used, since that allows - * for the best encoding quality. So set it to it's max value - */ - reg = ptr->max_block_vol; - zr36060_write(ptr, ZR060_MBCVR, reg); - - return 0; -} - -/* additional control functions */ -static int -zr36060_control (struct videocodec *codec, - int type, - int size, - void *data) -{ - struct zr36060 *ptr = (struct zr36060 *) codec->data; - int *ival = (int *) data; - - dprintk(2, "%s: control %d call with %d byte\n", ptr->name, type, - size); - - switch (type) { - case CODEC_G_STATUS: /* get last status */ - if (size != sizeof(int)) - return -EFAULT; - zr36060_read_status(ptr); - *ival = ptr->status; - break; - - case CODEC_G_CODEC_MODE: - if (size != sizeof(int)) - return -EFAULT; - *ival = CODEC_MODE_BJPG; - break; - - case CODEC_S_CODEC_MODE: - if (size != sizeof(int)) - return -EFAULT; - if (*ival != CODEC_MODE_BJPG) - return -EINVAL; - /* not needed, do nothing */ - return 0; - - case CODEC_G_VFE: - case CODEC_S_VFE: - /* not needed, do nothing */ - return 0; - - case CODEC_S_MMAP: - /* not available, give an error */ - return -ENXIO; - - case CODEC_G_JPEG_TDS_BYTE: /* get target volume in byte */ - if (size != sizeof(int)) - return -EFAULT; - *ival = ptr->total_code_vol; - break; - - case CODEC_S_JPEG_TDS_BYTE: /* get target volume in byte */ - if (size != sizeof(int)) - return -EFAULT; - ptr->total_code_vol = *ival; - ptr->real_code_vol = (ptr->total_code_vol * 6) >> 3; - break; - - case CODEC_G_JPEG_SCALE: /* get scaling factor */ - if (size != sizeof(int)) - return -EFAULT; - *ival = zr36060_read_scalefactor(ptr); - break; - - case CODEC_S_JPEG_SCALE: /* set scaling factor */ - if (size != sizeof(int)) - return -EFAULT; - ptr->scalefact = *ival; - break; - - case CODEC_G_JPEG_APP_DATA: { /* get appn marker data */ - struct jpeg_app_marker *app = data; - - if (size != sizeof(struct jpeg_app_marker)) - return -EFAULT; - - *app = ptr->app; - break; - } - - case CODEC_S_JPEG_APP_DATA: { /* set appn marker data */ - struct jpeg_app_marker *app = data; - - if (size != sizeof(struct jpeg_app_marker)) - return -EFAULT; - - ptr->app = *app; - break; - } - - case CODEC_G_JPEG_COM_DATA: { /* get comment marker data */ - struct jpeg_com_marker *com = data; - - if (size != sizeof(struct jpeg_com_marker)) - return -EFAULT; - - *com = ptr->com; - break; - } - - case CODEC_S_JPEG_COM_DATA: { /* set comment marker data */ - struct jpeg_com_marker *com = data; - - if (size != sizeof(struct jpeg_com_marker)) - return -EFAULT; - - ptr->com = *com; - break; - } - - default: - return -EINVAL; - } - - return size; -} - -/* ========================================================================= - Exit and unregister function: - - Deinitializes Zoran's JPEG processor - ========================================================================= */ - -static int -zr36060_unset (struct videocodec *codec) -{ - struct zr36060 *ptr = codec->data; - - if (ptr) { - /* do wee need some codec deinit here, too ???? */ - - dprintk(1, "%s: finished codec #%d\n", ptr->name, - ptr->num); - kfree(ptr); - codec->data = NULL; - - zr36060_codecs--; - return 0; - } - - return -EFAULT; -} - -/* ========================================================================= - Setup and registry function: - - Initializes Zoran's JPEG processor - - Also sets pixel size, average code size, mode (compr./decompr.) - (the given size is determined by the processor with the video interface) - ========================================================================= */ - -static int -zr36060_setup (struct videocodec *codec) -{ - struct zr36060 *ptr; - int res; - - dprintk(2, "zr36060: initializing MJPEG subsystem #%d.\n", - zr36060_codecs); - - if (zr36060_codecs == MAX_CODECS) { - dprintk(1, - KERN_ERR "zr36060: Can't attach more codecs!\n"); - return -ENOSPC; - } - //mem structure init - codec->data = ptr = kzalloc(sizeof(struct zr36060), GFP_KERNEL); - if (NULL == ptr) { - dprintk(1, KERN_ERR "zr36060: Can't get enough memory!\n"); - return -ENOMEM; - } - - snprintf(ptr->name, sizeof(ptr->name), "zr36060[%d]", - zr36060_codecs); - ptr->num = zr36060_codecs++; - ptr->codec = codec; - - //testing - res = zr36060_basic_test(ptr); - if (res < 0) { - zr36060_unset(codec); - return res; - } - //final setup - memcpy(ptr->h_samp_ratio, zr36060_decimation_h, 8); - memcpy(ptr->v_samp_ratio, zr36060_decimation_v, 8); - - ptr->bitrate_ctrl = 0; /* 0 or 1 - fixed file size flag - * (what is the difference?) - */ - ptr->mode = CODEC_DO_COMPRESSION; - ptr->width = 384; - ptr->height = 288; - ptr->total_code_vol = 16000; /* CHECKME */ - ptr->real_code_vol = (ptr->total_code_vol * 6) >> 3; - ptr->max_block_vol = 240; /* CHECKME, was 120 is 240 */ - ptr->scalefact = 0x100; - ptr->dri = 1; /* CHECKME, was 8 is 1 */ - - /* by default, no COM or APP markers - app should set those */ - ptr->com.len = 0; - ptr->app.appn = 0; - ptr->app.len = 0; - - zr36060_init(ptr); - - dprintk(1, KERN_INFO "%s: codec attached and running\n", - ptr->name); - - return 0; -} - -static const struct videocodec zr36060_codec = { - .owner = THIS_MODULE, - .name = "zr36060", - .magic = 0L, // magic not used - .flags = - CODEC_FLAG_JPEG | CODEC_FLAG_HARDWARE | CODEC_FLAG_ENCODER | - CODEC_FLAG_DECODER | CODEC_FLAG_VFE, - .type = CODEC_TYPE_ZR36060, - .setup = zr36060_setup, // functionality - .unset = zr36060_unset, - .set_mode = zr36060_set_mode, - .set_video = zr36060_set_video, - .control = zr36060_control, - // others are not used -}; - -/* ========================================================================= - HOOK IN DRIVER AS KERNEL MODULE - ========================================================================= */ - -static int __init -zr36060_init_module (void) -{ - //dprintk(1, "zr36060 driver %s\n",ZR060_VERSION); - zr36060_codecs = 0; - return videocodec_register(&zr36060_codec); -} - -static void __exit -zr36060_cleanup_module (void) -{ - if (zr36060_codecs) { - dprintk(1, - "zr36060: something's wrong - %d codecs left somehow.\n", - zr36060_codecs); - } - - /* however, we can't just stay alive */ - videocodec_unregister(&zr36060_codec); -} - -module_init(zr36060_init_module); -module_exit(zr36060_cleanup_module); - -MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@skynet.be>"); -MODULE_DESCRIPTION("Driver module for ZR36060 jpeg processors " - ZR060_VERSION); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/media/zoran/zr36060.h b/drivers/staging/media/zoran/zr36060.h deleted file mode 100644 index 9fa553dc475f..000000000000 --- a/drivers/staging/media/zoran/zr36060.h +++ /dev/null @@ -1,200 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Zoran ZR36060 basic configuration functions - header file - * - * Copyright (C) 2002 Laurent Pinchart <laurent.pinchart@skynet.be> - */ -#ifndef ZR36060_H -#define ZR36060_H - -#include "videocodec.h" - -/* data stored for each zoran jpeg codec chip */ -struct zr36060 { - char name[32]; - int num; - /* io datastructure */ - struct videocodec *codec; - // last coder status - __u8 status; - // actual coder setup - int mode; - - __u16 width; - __u16 height; - - __u16 bitrate_ctrl; - - __u32 total_code_vol; - __u32 real_code_vol; - __u16 max_block_vol; - - __u8 h_samp_ratio[8]; - __u8 v_samp_ratio[8]; - __u16 scalefact; - __u16 dri; - - /* app/com marker data */ - struct jpeg_app_marker app; - struct jpeg_com_marker com; -}; - -/* ZR36060 register addresses */ -#define ZR060_LOAD 0x000 -#define ZR060_CFSR 0x001 -#define ZR060_CIR 0x002 -#define ZR060_CMR 0x003 -#define ZR060_MBZ 0x004 -#define ZR060_MBCVR 0x005 -#define ZR060_MER 0x006 -#define ZR060_IMR 0x007 -#define ZR060_ISR 0x008 -#define ZR060_TCV_NET_HI 0x009 -#define ZR060_TCV_NET_MH 0x00a -#define ZR060_TCV_NET_ML 0x00b -#define ZR060_TCV_NET_LO 0x00c -#define ZR060_TCV_DATA_HI 0x00d -#define ZR060_TCV_DATA_MH 0x00e -#define ZR060_TCV_DATA_ML 0x00f -#define ZR060_TCV_DATA_LO 0x010 -#define ZR060_SF_HI 0x011 -#define ZR060_SF_LO 0x012 -#define ZR060_AF_HI 0x013 -#define ZR060_AF_M 0x014 -#define ZR060_AF_LO 0x015 -#define ZR060_ACV_HI 0x016 -#define ZR060_ACV_MH 0x017 -#define ZR060_ACV_ML 0x018 -#define ZR060_ACV_LO 0x019 -#define ZR060_ACT_HI 0x01a -#define ZR060_ACT_MH 0x01b -#define ZR060_ACT_ML 0x01c -#define ZR060_ACT_LO 0x01d -#define ZR060_ACV_TRUN_HI 0x01e -#define ZR060_ACV_TRUN_MH 0x01f -#define ZR060_ACV_TRUN_ML 0x020 -#define ZR060_ACV_TRUN_LO 0x021 -#define ZR060_IDR_DEV 0x022 -#define ZR060_IDR_REV 0x023 -#define ZR060_TCR_HI 0x024 -#define ZR060_TCR_LO 0x025 -#define ZR060_VCR 0x030 -#define ZR060_VPR 0x031 -#define ZR060_SR 0x032 -#define ZR060_BCR_Y 0x033 -#define ZR060_BCR_U 0x034 -#define ZR060_BCR_V 0x035 -#define ZR060_SGR_VTOTAL_HI 0x036 -#define ZR060_SGR_VTOTAL_LO 0x037 -#define ZR060_SGR_HTOTAL_HI 0x038 -#define ZR060_SGR_HTOTAL_LO 0x039 -#define ZR060_SGR_VSYNC 0x03a -#define ZR060_SGR_HSYNC 0x03b -#define ZR060_SGR_BVSTART 0x03c -#define ZR060_SGR_BHSTART 0x03d -#define ZR060_SGR_BVEND_HI 0x03e -#define ZR060_SGR_BVEND_LO 0x03f -#define ZR060_SGR_BHEND_HI 0x040 -#define ZR060_SGR_BHEND_LO 0x041 -#define ZR060_AAR_VSTART_HI 0x042 -#define ZR060_AAR_VSTART_LO 0x043 -#define ZR060_AAR_VEND_HI 0x044 -#define ZR060_AAR_VEND_LO 0x045 -#define ZR060_AAR_HSTART_HI 0x046 -#define ZR060_AAR_HSTART_LO 0x047 -#define ZR060_AAR_HEND_HI 0x048 -#define ZR060_AAR_HEND_LO 0x049 -#define ZR060_SWR_VSTART_HI 0x04a -#define ZR060_SWR_VSTART_LO 0x04b -#define ZR060_SWR_VEND_HI 0x04c -#define ZR060_SWR_VEND_LO 0x04d -#define ZR060_SWR_HSTART_HI 0x04e -#define ZR060_SWR_HSTART_LO 0x04f -#define ZR060_SWR_HEND_HI 0x050 -#define ZR060_SWR_HEND_LO 0x051 - -#define ZR060_SOF_IDX 0x060 -#define ZR060_SOS_IDX 0x07a -#define ZR060_DRI_IDX 0x0c0 -#define ZR060_DQT_IDX 0x0cc -#define ZR060_DHT_IDX 0x1d4 -#define ZR060_APP_IDX 0x380 -#define ZR060_COM_IDX 0x3c0 - -/* ZR36060 LOAD register bits */ - -#define ZR060_LOAD_Load (1 << 7) -#define ZR060_LOAD_SyncRst (1 << 0) - -/* ZR36060 Code FIFO Status register bits */ - -#define ZR060_CFSR_Busy (1 << 7) -#define ZR060_CFSR_CBusy (1 << 2) -#define ZR060_CFSR_CFIFO (3 << 0) - -/* ZR36060 Code Interface register */ - -#define ZR060_CIR_Code16 (1 << 7) -#define ZR060_CIR_Endian (1 << 6) -#define ZR060_CIR_CFIS (1 << 2) -#define ZR060_CIR_CodeMstr (1 << 0) - -/* ZR36060 Codec Mode register */ - -#define ZR060_CMR_Comp (1 << 7) -#define ZR060_CMR_ATP (1 << 6) -#define ZR060_CMR_Pass2 (1 << 5) -#define ZR060_CMR_TLM (1 << 4) -#define ZR060_CMR_BRB (1 << 2) -#define ZR060_CMR_FSF (1 << 1) - -/* ZR36060 Markers Enable register */ - -#define ZR060_MER_App (1 << 7) -#define ZR060_MER_Com (1 << 6) -#define ZR060_MER_DRI (1 << 5) -#define ZR060_MER_DQT (1 << 4) -#define ZR060_MER_DHT (1 << 3) - -/* ZR36060 Interrupt Mask register */ - -#define ZR060_IMR_EOAV (1 << 3) -#define ZR060_IMR_EOI (1 << 2) -#define ZR060_IMR_End (1 << 1) -#define ZR060_IMR_DataErr (1 << 0) - -/* ZR36060 Interrupt Status register */ - -#define ZR060_ISR_ProCnt (3 << 6) -#define ZR060_ISR_EOAV (1 << 3) -#define ZR060_ISR_EOI (1 << 2) -#define ZR060_ISR_End (1 << 1) -#define ZR060_ISR_DataErr (1 << 0) - -/* ZR36060 Video Control register */ - -#define ZR060_VCR_Video8 (1 << 7) -#define ZR060_VCR_Range (1 << 6) -#define ZR060_VCR_FIDet (1 << 3) -#define ZR060_VCR_FIVedge (1 << 2) -#define ZR060_VCR_FIExt (1 << 1) -#define ZR060_VCR_SyncMstr (1 << 0) - -/* ZR36060 Video Polarity register */ - -#define ZR060_VPR_VCLKPol (1 << 7) -#define ZR060_VPR_PValPol (1 << 6) -#define ZR060_VPR_PoePol (1 << 5) -#define ZR060_VPR_SImgPol (1 << 4) -#define ZR060_VPR_BLPol (1 << 3) -#define ZR060_VPR_FIPol (1 << 2) -#define ZR060_VPR_HSPol (1 << 1) -#define ZR060_VPR_VSPol (1 << 0) - -/* ZR36060 Scaling register */ - -#define ZR060_SR_VScale (1 << 2) -#define ZR060_SR_HScale2 (1 << 0) -#define ZR060_SR_HScale4 (2 << 0) - -#endif /*fndef ZR36060_H */ diff --git a/include/media/cec-notifier.h b/include/media/cec-notifier.h index 814eeef35a5c..57b3a9f6ea1d 100644 --- a/include/media/cec-notifier.h +++ b/include/media/cec-notifier.h @@ -9,7 +9,7 @@ #ifndef LINUX_CEC_NOTIFIER_H #define LINUX_CEC_NOTIFIER_H -#include <linux/types.h> +#include <linux/err.h> #include <media/cec.h> struct device; @@ -87,6 +87,17 @@ void cec_notifier_unregister(struct cec_notifier *n); void cec_register_cec_notifier(struct cec_adapter *adap, struct cec_notifier *notifier); +/** + * cec_notifier_parse_hdmi_phandle - find the hdmi device from "hdmi-phandle" + * @dev: the device with the "hdmi-phandle" device tree property + * + * Returns the device pointer referenced by the "hdmi-phandle" property. + * Note that the refcount of the returned device is not incremented. + * This device pointer is only used as a key value in the notifier + * list, but it is never accessed by the CEC driver. + */ +struct device *cec_notifier_parse_hdmi_phandle(struct device *dev); + #else static inline struct cec_notifier *cec_notifier_get_conn(struct device *dev, const char *conn) @@ -122,6 +133,12 @@ static inline void cec_register_cec_notifier(struct cec_adapter *adap, struct cec_notifier *notifier) { } + +static inline struct device *cec_notifier_parse_hdmi_phandle(struct device *dev) +{ + return ERR_PTR(-ENODEV); +} + #endif /** diff --git a/include/media/dvb-usb-ids.h b/include/media/dvb-usb-ids.h index f9e73b4a6e89..52875e3eee71 100644 --- a/include/media/dvb-usb-ids.h +++ b/include/media/dvb-usb-ids.h @@ -258,6 +258,7 @@ #define USB_PID_AVERMEDIA_A867 0xa867 #define USB_PID_AVERMEDIA_H335 0x0335 #define USB_PID_AVERMEDIA_TD110 0xa110 +#define USB_PID_AVERMEDIA_TD310 0x1871 #define USB_PID_AVERMEDIA_TWINSTAR 0x0825 #define USB_PID_TECHNOTREND_CONNECT_S2400 0x3006 #define USB_PID_TECHNOTREND_CONNECT_S2400_8KEEPROM 0x3009 diff --git a/include/media/fwht-ctrls.h b/include/media/fwht-ctrls.h new file mode 100644 index 000000000000..615027410e47 --- /dev/null +++ b/include/media/fwht-ctrls.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * These are the FWHT state controls for use with stateless FWHT + * codec drivers. + * + * It turns out that these structs are not stable yet and will undergo + * more changes. So keep them private until they are stable and ready to + * become part of the official public API. + */ + +#ifndef _FWHT_CTRLS_H_ +#define _FWHT_CTRLS_H_ + +#define V4L2_CTRL_TYPE_FWHT_PARAMS 0x0105 + +#define V4L2_CID_MPEG_VIDEO_FWHT_PARAMS (V4L2_CID_MPEG_BASE + 292) + +struct v4l2_ctrl_fwht_params { + __u64 backward_ref_ts; + __u32 version; + __u32 width; + __u32 height; + __u32 flags; + __u32 colorspace; + __u32 xfer_func; + __u32 ycbcr_enc; + __u32 quantization; +}; + + +#endif diff --git a/include/media/media-dev-allocator.h b/include/media/media-dev-allocator.h new file mode 100644 index 000000000000..b35ea6062596 --- /dev/null +++ b/include/media/media-dev-allocator.h @@ -0,0 +1,63 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * media-dev-allocator.h - Media Controller Device Allocator API + * + * Copyright (c) 2019 Shuah Khan <shuah@kernel.org> + * + * Credits: Suggested by Laurent Pinchart <laurent.pinchart@ideasonboard.com> + */ + +/* + * This file adds a global ref-counted Media Controller Device Instance API. + * A system wide global media device list is managed and each media device + * includes a kref count. The last put on the media device releases the media + * device instance. + */ + +#ifndef _MEDIA_DEV_ALLOCATOR_H +#define _MEDIA_DEV_ALLOCATOR_H + +struct usb_device; + +#if defined(CONFIG_MEDIA_CONTROLLER) && defined(CONFIG_USB) +/** + * media_device_usb_allocate() - Allocate and return struct &media device + * + * @udev: struct &usb_device pointer + * @module_name: should be filled with %KBUILD_MODNAME + * @owner: struct module pointer %THIS_MODULE for the driver. + * %THIS_MODULE is null for a built-in driver. + * It is safe even when %THIS_MODULE is null. + * + * This interface should be called to allocate a Media Device when multiple + * drivers share usb_device and the media device. This interface allocates + * &media_device structure and calls media_device_usb_init() to initialize + * it. + * + */ +struct media_device *media_device_usb_allocate(struct usb_device *udev, + const char *module_name, + struct module *owner); +/** + * media_device_delete() - Release media device. Calls kref_put(). + * + * @mdev: struct &media_device pointer + * @module_name: should be filled with %KBUILD_MODNAME + * @owner: struct module pointer %THIS_MODULE for the driver. + * %THIS_MODULE is null for a built-in driver. + * It is safe even when %THIS_MODULE is null. + * + * This interface should be called to put Media Device Instance kref. + */ +void media_device_delete(struct media_device *mdev, const char *module_name, + struct module *owner); +#else +static inline struct media_device *media_device_usb_allocate( + struct usb_device *udev, const char *module_name, + struct module *owner) + { return NULL; } +static inline void media_device_delete( + struct media_device *mdev, const char *module_name, + struct module *owner) { } +#endif /* CONFIG_MEDIA_CONTROLLER && CONFIG_USB */ +#endif /* _MEDIA_DEV_ALLOCATOR_H */ diff --git a/include/media/media-entity.h b/include/media/media-entity.h index e5f6960d92f6..3cbad42e3693 100644 --- a/include/media/media-entity.h +++ b/include/media/media-entity.h @@ -865,19 +865,6 @@ struct media_link *media_entity_find_link(struct media_pad *source, struct media_pad *media_entity_remote_pad(const struct media_pad *pad); /** - * media_entity_get - Get a reference to the parent module - * - * @entity: The entity - * - * Get a reference to the parent media device module. - * - * The function will return immediately if @entity is %NULL. - * - * Return: returns a pointer to the entity on success or %NULL on failure. - */ -struct media_entity *media_entity_get(struct media_entity *entity); - -/** * media_entity_get_fwnode_pad - Get pad number from fwnode * * @entity: The entity @@ -917,17 +904,6 @@ __must_check int media_graph_walk_init( void media_graph_walk_cleanup(struct media_graph *graph); /** - * media_entity_put - Release the reference to the parent module - * - * @entity: The entity - * - * Release the reference count acquired by media_entity_get(). - * - * The function will return immediately if @entity is %NULL. - */ -void media_entity_put(struct media_entity *entity); - -/** * media_graph_walk_start - Start walking the media graph at a * given entity * diff --git a/include/media/media-request.h b/include/media/media-request.h index bd36d7431698..3cd25a2717ce 100644 --- a/include/media/media-request.h +++ b/include/media/media-request.h @@ -198,7 +198,7 @@ void media_request_put(struct media_request *req); * Get the request represented by @request_fd that is owned * by the media device. * - * Return a -EACCES error pointer if requests are not supported + * Return a -EBADR error pointer if requests are not supported * by this driver. Return -EINVAL if the request was not found. * Return the pointer to the request if found: the caller will * have to call @media_request_put when it finished using the @@ -231,7 +231,7 @@ static inline void media_request_put(struct media_request *req) static inline struct media_request * media_request_get_by_fd(struct media_device *mdev, int request_fd) { - return ERR_PTR(-EACCES); + return ERR_PTR(-EBADR); } #endif diff --git a/include/media/rc-map.h b/include/media/rc-map.h index 5e684bb0d64c..367d983188f7 100644 --- a/include/media/rc-map.h +++ b/include/media/rc-map.h @@ -40,6 +40,7 @@ #define RC_PROTO_BIT_RCMM12 BIT_ULL(RC_PROTO_RCMM12) #define RC_PROTO_BIT_RCMM24 BIT_ULL(RC_PROTO_RCMM24) #define RC_PROTO_BIT_RCMM32 BIT_ULL(RC_PROTO_RCMM32) +#define RC_PROTO_BIT_XBOX_DVD BIT_ULL(RC_PROTO_XBOX_DVD) #define RC_PROTO_BIT_ALL \ (RC_PROTO_BIT_UNKNOWN | RC_PROTO_BIT_OTHER | \ @@ -55,7 +56,8 @@ RC_PROTO_BIT_RC6_MCE | RC_PROTO_BIT_SHARP | \ RC_PROTO_BIT_XMP | RC_PROTO_BIT_CEC | \ RC_PROTO_BIT_IMON | RC_PROTO_BIT_RCMM12 | \ - RC_PROTO_BIT_RCMM24 | RC_PROTO_BIT_RCMM32) + RC_PROTO_BIT_RCMM24 | RC_PROTO_BIT_RCMM32 | \ + RC_PROTO_BIT_XBOX_DVD) /* All rc protocols for which we have decoders */ #define RC_PROTO_BIT_ALL_IR_DECODER \ (RC_PROTO_BIT_RC5 | RC_PROTO_BIT_RC5X_20 | \ diff --git a/include/media/v4l2-common.h b/include/media/v4l2-common.h index 2b93cb281fa5..0a41bbecf3d3 100644 --- a/include/media/v4l2-common.h +++ b/include/media/v4l2-common.h @@ -392,4 +392,37 @@ int v4l2_s_parm_cap(struct video_device *vdev, ((u64)(a).numerator * (b).denominator OP \ (u64)(b).numerator * (a).denominator) +/* ------------------------------------------------------------------------- */ + +/* Pixel format and FourCC helpers */ + +/** + * struct v4l2_format_info - information about a V4L2 format + * @format: 4CC format identifier (V4L2_PIX_FMT_*) + * @mem_planes: Number of memory planes, which includes the alpha plane (1 to 4). + * @comp_planes: Number of component planes, which includes the alpha plane (1 to 4). + * @bpp: Array of per-plane bytes per pixel + * @hdiv: Horizontal chroma subsampling factor + * @vdiv: Vertical chroma subsampling factor + * @block_w: Per-plane macroblock pixel width (optional) + * @block_h: Per-plane macroblock pixel height (optional) + */ +struct v4l2_format_info { + u32 format; + u8 mem_planes; + u8 comp_planes; + u8 bpp[4]; + u8 hdiv; + u8 vdiv; + u8 block_w[4]; + u8 block_h[4]; +}; + +const struct v4l2_format_info *v4l2_format_info(u32 format); + +int v4l2_fill_pixfmt(struct v4l2_pix_format *pixfmt, int pixelformat, + int width, int height); +int v4l2_fill_pixfmt_mp(struct v4l2_pix_format_mplane *pixfmt, int pixelformat, + int width, int height); + #endif /* V4L2_COMMON_H_ */ diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h index e5cae37ced2d..ee026387f513 100644 --- a/include/media/v4l2-ctrls.h +++ b/include/media/v4l2-ctrls.h @@ -23,10 +23,11 @@ #include <media/media-request.h> /* - * Include the mpeg2 stateless codec compound control definitions. + * Include the mpeg2 and fwht stateless codec compound control definitions. * This will move to the public headers once this API is fully stable. */ #include <media/mpeg2-ctrls.h> +#include <media/fwht-ctrls.h> /* forward references */ struct file; @@ -49,6 +50,7 @@ struct poll_table_struct; * @p_char: Pointer to a string. * @p_mpeg2_slice_params: Pointer to a MPEG2 slice parameters structure. * @p_mpeg2_quantization: Pointer to a MPEG2 quantization data structure. + * @p_fwht_params: Pointer to a FWHT stateless parameters structure. * @p: Pointer to a compound value. */ union v4l2_ctrl_ptr { @@ -60,6 +62,7 @@ union v4l2_ctrl_ptr { char *p_char; struct v4l2_ctrl_mpeg2_slice_params *p_mpeg2_slice_params; struct v4l2_ctrl_mpeg2_quantization *p_mpeg2_quantization; + struct v4l2_ctrl_fwht_params *p_fwht_params; void *p; }; @@ -934,7 +937,7 @@ s32 v4l2_ctrl_g_ctrl(struct v4l2_ctrl *ctrl); * __v4l2_ctrl_s_ctrl() - Unlocked variant of v4l2_ctrl_s_ctrl(). * * @ctrl: The control. - * @val: TheControls name new value. + * @val: The new value. * * This sets the control's new value safely by going through the control * framework. This function assumes the control's handler is already locked, @@ -1039,7 +1042,7 @@ int __v4l2_ctrl_s_ctrl_string(struct v4l2_ctrl *ctrl, const char *s); * * @ctrl: The control. * @s: The new string. - *Controls name + * * This sets the control's new string safely by going through the control * framework. This function will lock the control's handler, so it cannot be * used from within the &v4l2_ctrl_ops functions. @@ -1127,7 +1130,7 @@ __poll_t v4l2_ctrl_poll(struct file *file, struct poll_table_struct *wait); * applying control values in a request is only applicable to memory-to-memory * devices. */ -void v4l2_ctrl_request_setup(struct media_request *req, +int v4l2_ctrl_request_setup(struct media_request *req, struct v4l2_ctrl_handler *parent); /** diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h index 349e1c18cf48..a7fa5b80915a 100644 --- a/include/media/v4l2-subdev.h +++ b/include/media/v4l2-subdev.h @@ -755,7 +755,17 @@ struct v4l2_subdev_ops { * * @open: called when the subdev device node is opened by an application. * - * @close: called when the subdev device node is closed. + * @close: called when the subdev device node is closed. Please note that + * it is possible for @close to be called after @unregistered! + * + * @release: called when the last user of the subdev device is gone. This + * happens after the @unregistered callback and when the last open + * filehandle to the v4l-subdevX device node was closed. If no device + * node was created for this sub-device, then the @release callback + * is called right after the @unregistered callback. + * The @release callback is typically used to free the memory containing + * the v4l2_subdev structure. It is almost certainly required for any + * sub-device that sets the V4L2_SUBDEV_FL_HAS_DEVNODE flag. * * .. note:: * Never call this from drivers, only the v4l2 framework can call @@ -766,6 +776,7 @@ struct v4l2_subdev_internal_ops { void (*unregistered)(struct v4l2_subdev *sd); int (*open)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh); int (*close)(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh); + void (*release)(struct v4l2_subdev *sd); }; #define V4L2_SUBDEV_NAME_SIZE 32 @@ -899,9 +910,11 @@ struct v4l2_subdev { * * @vfh: pointer to &struct v4l2_fh * @pad: pointer to &struct v4l2_subdev_pad_config + * @owner: module pointer to the owner of this file handle */ struct v4l2_subdev_fh { struct v4l2_fh vfh; + struct module *owner; #if defined(CONFIG_VIDEO_V4L2_SUBDEV_API) struct v4l2_subdev_pad_config *pad; #endif diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h index 910f3d469005..22f3ff76a8b5 100644 --- a/include/media/videobuf2-core.h +++ b/include/media/videobuf2-core.h @@ -207,7 +207,6 @@ enum vb2_io_modes { * @VB2_BUF_STATE_IN_REQUEST: buffer is queued in media request. * @VB2_BUF_STATE_PREPARING: buffer is being prepared in videobuf. * @VB2_BUF_STATE_QUEUED: buffer queued in videobuf, but not in driver. - * @VB2_BUF_STATE_REQUEUEING: re-queue a buffer to the driver. * @VB2_BUF_STATE_ACTIVE: buffer queued in driver and possibly used * in a hardware operation. * @VB2_BUF_STATE_DONE: buffer returned from driver to videobuf, but @@ -221,7 +220,6 @@ enum vb2_buffer_state { VB2_BUF_STATE_IN_REQUEST, VB2_BUF_STATE_PREPARING, VB2_BUF_STATE_QUEUED, - VB2_BUF_STATE_REQUEUEING, VB2_BUF_STATE_ACTIVE, VB2_BUF_STATE_DONE, VB2_BUF_STATE_ERROR, @@ -384,10 +382,10 @@ struct vb2_buffer { * driver can return an error if hardware fails, in that * case all buffers that have been already given by * the @buf_queue callback are to be returned by the driver - * by calling vb2_buffer_done() with %VB2_BUF_STATE_QUEUED - * or %VB2_BUF_STATE_REQUEUEING. If you need a minimum - * number of buffers before you can start streaming, then - * set &vb2_queue->min_buffers_needed. If that is non-zero + * by calling vb2_buffer_done() with %VB2_BUF_STATE_QUEUED. + * If you need a minimum number of buffers before you can + * start streaming, then set + * &vb2_queue->min_buffers_needed. If that is non-zero * then @start_streaming won't be called until at least * that many buffers have been queued up by userspace. * @stop_streaming: called when 'streaming' state must be disabled; driver @@ -484,6 +482,8 @@ struct vb2_buf_ops { * has not been called. This is a vb1 idiom that has been adopted * also by vb2. * @supports_requests: this queue supports the Request API. + * @requires_requests: this queue requires the Request API. If this is set to 1, + * then supports_requests must be set to 1 as well. * @uses_qbuf: qbuf was used directly for this queue. Set to 1 the first * time this is called. Set to 0 when the queue is canceled. * If this is 1, then you cannot queue buffers from a request. @@ -558,6 +558,7 @@ struct vb2_queue { unsigned allow_zero_bytesused:1; unsigned quirk_poll_must_check_waiting_for_buffers:1; unsigned supports_requests:1; + unsigned requires_requests:1; unsigned uses_qbuf:1; unsigned uses_requests:1; @@ -595,6 +596,7 @@ struct vb2_queue { unsigned int start_streaming_called:1; unsigned int error:1; unsigned int waiting_for_buffers:1; + unsigned int waiting_in_dqbuf:1; unsigned int is_multiplanar:1; unsigned int is_output:1; unsigned int copy_timestamp:1; @@ -648,9 +650,7 @@ void *vb2_plane_cookie(struct vb2_buffer *vb, unsigned int plane_no); * @state: state of the buffer, as defined by &enum vb2_buffer_state. * Either %VB2_BUF_STATE_DONE if the operation finished * successfully, %VB2_BUF_STATE_ERROR if the operation finished - * with an error or any of %VB2_BUF_STATE_QUEUED or - * %VB2_BUF_STATE_REQUEUEING if the driver wants to - * requeue buffers (see below). + * with an error or %VB2_BUF_STATE_QUEUED. * * This function should be called by the driver after a hardware operation on * a buffer is finished and the buffer may be returned to userspace. The driver @@ -661,12 +661,7 @@ void *vb2_plane_cookie(struct vb2_buffer *vb, unsigned int plane_no); * While streaming a buffer can only be returned in state DONE or ERROR. * The &vb2_ops->start_streaming op can also return them in case the DMA engine * cannot be started for some reason. In that case the buffers should be - * returned with state QUEUED or REQUEUEING to put them back into the queue. - * - * %VB2_BUF_STATE_REQUEUEING is like %VB2_BUF_STATE_QUEUED, but it also calls - * &vb2_ops->buf_queue to queue buffers back to the driver. Note that calling - * vb2_buffer_done(..., VB2_BUF_STATE_REQUEUEING) from interrupt context will - * result in &vb2_ops->buf_queue being called in interrupt context as well. + * returned with state QUEUED to put them back into the queue. */ void vb2_buffer_done(struct vb2_buffer *vb, enum vb2_buffer_state state); diff --git a/include/uapi/linux/lirc.h b/include/uapi/linux/lirc.h index 45fcbf99d72e..f99d9dcae667 100644 --- a/include/uapi/linux/lirc.h +++ b/include/uapi/linux/lirc.h @@ -195,6 +195,7 @@ struct lirc_scancode { * @RC_PROTO_RCMM12: RC-MM protocol 12 bits * @RC_PROTO_RCMM24: RC-MM protocol 24 bits * @RC_PROTO_RCMM32: RC-MM protocol 32 bits + * @RC_PROTO_XBOX_DVD: Xbox DVD Movie Playback Kit protocol */ enum rc_proto { RC_PROTO_UNKNOWN = 0, @@ -224,6 +225,7 @@ enum rc_proto { RC_PROTO_RCMM12 = 24, RC_PROTO_RCMM24 = 25, RC_PROTO_RCMM32 = 26, + RC_PROTO_XBOX_DVD = 27, }; #endif diff --git a/include/uapi/linux/media-bus-format.h b/include/uapi/linux/media-bus-format.h index d6a5a3bfe6c4..2a6b253cfb05 100644 --- a/include/uapi/linux/media-bus-format.h +++ b/include/uapi/linux/media-bus-format.h @@ -34,7 +34,7 @@ #define MEDIA_BUS_FMT_FIXED 0x0001 -/* RGB - next is 0x101b */ +/* RGB - next is 0x101c */ #define MEDIA_BUS_FMT_RGB444_1X12 0x1016 #define MEDIA_BUS_FMT_RGB444_2X8_PADHI_BE 0x1001 #define MEDIA_BUS_FMT_RGB444_2X8_PADHI_LE 0x1002 @@ -50,6 +50,7 @@ #define MEDIA_BUS_FMT_RGB666_1X24_CPADHI 0x1015 #define MEDIA_BUS_FMT_RGB666_1X7X3_SPWG 0x1010 #define MEDIA_BUS_FMT_BGR888_1X24 0x1013 +#define MEDIA_BUS_FMT_BGR888_3X8 0x101b #define MEDIA_BUS_FMT_GBR888_1X24 0x1014 #define MEDIA_BUS_FMT_RGB888_1X24 0x100a #define MEDIA_BUS_FMT_RGB888_2X12_BE 0x100b diff --git a/include/uapi/linux/media.h b/include/uapi/linux/media.h index e5d0c5c611b5..9aedb187bc48 100644 --- a/include/uapi/linux/media.h +++ b/include/uapi/linux/media.h @@ -262,6 +262,11 @@ struct media_links_enum { #define MEDIA_INTF_T_V4L_SWRADIO (MEDIA_INTF_T_V4L_BASE + 4) #define MEDIA_INTF_T_V4L_TOUCH (MEDIA_INTF_T_V4L_BASE + 5) +#define MEDIA_INTF_T_ALSA_BASE 0x00000300 +#define MEDIA_INTF_T_ALSA_PCM_CAPTURE (MEDIA_INTF_T_ALSA_BASE) +#define MEDIA_INTF_T_ALSA_PCM_PLAYBACK (MEDIA_INTF_T_ALSA_BASE + 1) +#define MEDIA_INTF_T_ALSA_CONTROL (MEDIA_INTF_T_ALSA_BASE + 2) + #if defined(__KERNEL__) /* @@ -413,19 +418,19 @@ struct media_v2_topology { #define MEDIA_ENT_F_DTV_DECODER MEDIA_ENT_F_DV_DECODER /* - * There is still no ALSA support in the media controller. These + * There is still no full ALSA support in the media controller. These * defines should not have been added and we leave them here only * in case some application tries to use these defines. + * + * The ALSA defines that are in use have been moved into __KERNEL__ + * scope. As support gets added to these interface types, they should + * be moved into __KERNEL__ scope with the code that uses them. */ -#define MEDIA_INTF_T_ALSA_BASE 0x00000300 -#define MEDIA_INTF_T_ALSA_PCM_CAPTURE (MEDIA_INTF_T_ALSA_BASE) -#define MEDIA_INTF_T_ALSA_PCM_PLAYBACK (MEDIA_INTF_T_ALSA_BASE + 1) -#define MEDIA_INTF_T_ALSA_CONTROL (MEDIA_INTF_T_ALSA_BASE + 2) -#define MEDIA_INTF_T_ALSA_COMPRESS (MEDIA_INTF_T_ALSA_BASE + 3) -#define MEDIA_INTF_T_ALSA_RAWMIDI (MEDIA_INTF_T_ALSA_BASE + 4) -#define MEDIA_INTF_T_ALSA_HWDEP (MEDIA_INTF_T_ALSA_BASE + 5) -#define MEDIA_INTF_T_ALSA_SEQUENCER (MEDIA_INTF_T_ALSA_BASE + 6) -#define MEDIA_INTF_T_ALSA_TIMER (MEDIA_INTF_T_ALSA_BASE + 7) +#define MEDIA_INTF_T_ALSA_COMPRESS (MEDIA_INTF_T_ALSA_BASE + 3) +#define MEDIA_INTF_T_ALSA_RAWMIDI (MEDIA_INTF_T_ALSA_BASE + 4) +#define MEDIA_INTF_T_ALSA_HWDEP (MEDIA_INTF_T_ALSA_BASE + 5) +#define MEDIA_INTF_T_ALSA_SEQUENCER (MEDIA_INTF_T_ALSA_BASE + 6) +#define MEDIA_INTF_T_ALSA_TIMER (MEDIA_INTF_T_ALSA_BASE + 7) /* Obsolete symbol for media_version, no longer used in the kernel */ #define MEDIA_API_VERSION ((0 << 16) | (1 << 8) | 0) diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h index 06479f2fb3ae..37807f23231e 100644 --- a/include/uapi/linux/v4l2-controls.h +++ b/include/uapi/linux/v4l2-controls.h @@ -404,6 +404,10 @@ enum v4l2_mpeg_video_multi_slice_mode { #define V4L2_CID_MPEG_VIDEO_MV_V_SEARCH_RANGE (V4L2_CID_MPEG_BASE+228) #define V4L2_CID_MPEG_VIDEO_FORCE_KEY_FRAME (V4L2_CID_MPEG_BASE+229) +/* CIDs for the FWHT codec as used by the vicodec driver. */ +#define V4L2_CID_FWHT_I_FRAME_QP (V4L2_CID_MPEG_BASE + 290) +#define V4L2_CID_FWHT_P_FRAME_QP (V4L2_CID_MPEG_BASE + 291) + #define V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP (V4L2_CID_MPEG_BASE+300) #define V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP (V4L2_CID_MPEG_BASE+301) #define V4L2_CID_MPEG_VIDEO_H263_B_FRAME_QP (V4L2_CID_MPEG_BASE+302) @@ -535,6 +539,10 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type { #define V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER_QP (V4L2_CID_MPEG_BASE+382) #define V4L2_CID_MPEG_VIDEO_H264_CONSTRAINED_INTRA_PREDICTION (V4L2_CID_MPEG_BASE+383) #define V4L2_CID_MPEG_VIDEO_H264_CHROMA_QP_INDEX_OFFSET (V4L2_CID_MPEG_BASE+384) +#define V4L2_CID_MPEG_VIDEO_H264_I_FRAME_MIN_QP (V4L2_CID_MPEG_BASE+385) +#define V4L2_CID_MPEG_VIDEO_H264_I_FRAME_MAX_QP (V4L2_CID_MPEG_BASE+386) +#define V4L2_CID_MPEG_VIDEO_H264_P_FRAME_MIN_QP (V4L2_CID_MPEG_BASE+387) +#define V4L2_CID_MPEG_VIDEO_H264_P_FRAME_MAX_QP (V4L2_CID_MPEG_BASE+388) #define V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP (V4L2_CID_MPEG_BASE+400) #define V4L2_CID_MPEG_VIDEO_MPEG4_P_FRAME_QP (V4L2_CID_MPEG_BASE+401) #define V4L2_CID_MPEG_VIDEO_MPEG4_B_FRAME_QP (V4L2_CID_MPEG_BASE+402) diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index 1db220da3bcc..1050a75fb7ef 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -514,9 +514,21 @@ struct v4l2_pix_format { #define V4L2_PIX_FMT_RGB444 v4l2_fourcc('R', '4', '4', '4') /* 16 xxxxrrrr ggggbbbb */ #define V4L2_PIX_FMT_ARGB444 v4l2_fourcc('A', 'R', '1', '2') /* 16 aaaarrrr ggggbbbb */ #define V4L2_PIX_FMT_XRGB444 v4l2_fourcc('X', 'R', '1', '2') /* 16 xxxxrrrr ggggbbbb */ +#define V4L2_PIX_FMT_RGBA444 v4l2_fourcc('R', 'A', '1', '2') /* 16 rrrrgggg bbbbaaaa */ +#define V4L2_PIX_FMT_RGBX444 v4l2_fourcc('R', 'X', '1', '2') /* 16 rrrrgggg bbbbxxxx */ +#define V4L2_PIX_FMT_ABGR444 v4l2_fourcc('A', 'B', '1', '2') /* 16 aaaabbbb ggggrrrr */ +#define V4L2_PIX_FMT_XBGR444 v4l2_fourcc('X', 'B', '1', '2') /* 16 xxxxbbbb ggggrrrr */ +#define V4L2_PIX_FMT_BGRA444 v4l2_fourcc('B', 'A', '1', '2') /* 16 bbbbgggg rrrraaaa */ +#define V4L2_PIX_FMT_BGRX444 v4l2_fourcc('B', 'X', '1', '2') /* 16 bbbbgggg rrrrxxxx */ #define V4L2_PIX_FMT_RGB555 v4l2_fourcc('R', 'G', 'B', 'O') /* 16 RGB-5-5-5 */ #define V4L2_PIX_FMT_ARGB555 v4l2_fourcc('A', 'R', '1', '5') /* 16 ARGB-1-5-5-5 */ #define V4L2_PIX_FMT_XRGB555 v4l2_fourcc('X', 'R', '1', '5') /* 16 XRGB-1-5-5-5 */ +#define V4L2_PIX_FMT_RGBA555 v4l2_fourcc('R', 'A', '1', '5') /* 16 RGBA-5-5-5-1 */ +#define V4L2_PIX_FMT_RGBX555 v4l2_fourcc('R', 'X', '1', '5') /* 16 RGBX-5-5-5-1 */ +#define V4L2_PIX_FMT_ABGR555 v4l2_fourcc('A', 'B', '1', '5') /* 16 ABGR-1-5-5-5 */ +#define V4L2_PIX_FMT_XBGR555 v4l2_fourcc('X', 'B', '1', '5') /* 16 XBGR-1-5-5-5 */ +#define V4L2_PIX_FMT_BGRA555 v4l2_fourcc('B', 'A', '1', '5') /* 16 BGRA-5-5-5-1 */ +#define V4L2_PIX_FMT_BGRX555 v4l2_fourcc('B', 'X', '1', '5') /* 16 BGRX-5-5-5-1 */ #define V4L2_PIX_FMT_RGB565 v4l2_fourcc('R', 'G', 'B', 'P') /* 16 RGB-5-6-5 */ #define V4L2_PIX_FMT_RGB555X v4l2_fourcc('R', 'G', 'B', 'Q') /* 16 RGB-5-5-5 BE */ #define V4L2_PIX_FMT_ARGB555X v4l2_fourcc_be('A', 'R', '1', '5') /* 16 ARGB-5-5-5 BE */ @@ -528,7 +540,11 @@ struct v4l2_pix_format { #define V4L2_PIX_FMT_BGR32 v4l2_fourcc('B', 'G', 'R', '4') /* 32 BGR-8-8-8-8 */ #define V4L2_PIX_FMT_ABGR32 v4l2_fourcc('A', 'R', '2', '4') /* 32 BGRA-8-8-8-8 */ #define V4L2_PIX_FMT_XBGR32 v4l2_fourcc('X', 'R', '2', '4') /* 32 BGRX-8-8-8-8 */ +#define V4L2_PIX_FMT_BGRA32 v4l2_fourcc('R', 'A', '2', '4') /* 32 ABGR-8-8-8-8 */ +#define V4L2_PIX_FMT_BGRX32 v4l2_fourcc('R', 'X', '2', '4') /* 32 XBGR-8-8-8-8 */ #define V4L2_PIX_FMT_RGB32 v4l2_fourcc('R', 'G', 'B', '4') /* 32 RGB-8-8-8-8 */ +#define V4L2_PIX_FMT_RGBA32 v4l2_fourcc('A', 'B', '2', '4') /* 32 RGBA-8-8-8-8 */ +#define V4L2_PIX_FMT_RGBX32 v4l2_fourcc('X', 'B', '2', '4') /* 32 RGBX-8-8-8-8 */ #define V4L2_PIX_FMT_ARGB32 v4l2_fourcc('B', 'A', '2', '4') /* 32 ARGB-8-8-8-8 */ #define V4L2_PIX_FMT_XRGB32 v4l2_fourcc('B', 'X', '2', '4') /* 32 XRGB-8-8-8-8 */ @@ -669,6 +685,7 @@ struct v4l2_pix_format { #define V4L2_PIX_FMT_VP9 v4l2_fourcc('V', 'P', '9', '0') /* VP9 */ #define V4L2_PIX_FMT_HEVC v4l2_fourcc('H', 'E', 'V', 'C') /* HEVC aka H.265 */ #define V4L2_PIX_FMT_FWHT v4l2_fourcc('F', 'W', 'H', 'T') /* Fast Walsh Hadamard Transform (vicodec) */ +#define V4L2_PIX_FMT_FWHT_STATELESS v4l2_fourcc('S', 'F', 'W', 'H') /* Stateless FWHT (vicodec) */ /* Vendor-specific formats */ #define V4L2_PIX_FMT_CPIA1 v4l2_fourcc('C', 'P', 'I', 'A') /* cpia1 YUV */ diff --git a/sound/usb/Kconfig b/sound/usb/Kconfig index f61b5662bb89..6319b544ba3a 100644 --- a/sound/usb/Kconfig +++ b/sound/usb/Kconfig @@ -15,6 +15,7 @@ config SND_USB_AUDIO select SND_RAWMIDI select SND_PCM select BITREVERSE + select SND_USB_AUDIO_USE_MEDIA_CONTROLLER if MEDIA_CONTROLLER && (MEDIA_SUPPORT=y || MEDIA_SUPPORT=SND_USB_AUDIO) help Say Y here to include support for USB audio and USB MIDI devices. @@ -22,6 +23,9 @@ config SND_USB_AUDIO To compile this driver as a module, choose M here: the module will be called snd-usb-audio. +config SND_USB_AUDIO_USE_MEDIA_CONTROLLER + bool + config SND_USB_UA101 tristate "Edirol UA-101/UA-1000 driver" select SND_PCM diff --git a/sound/usb/Makefile b/sound/usb/Makefile index d330f74c90e6..e1ce257ab705 100644 --- a/sound/usb/Makefile +++ b/sound/usb/Makefile @@ -18,6 +18,8 @@ snd-usb-audio-objs := card.o \ quirks.o \ stream.o +snd-usb-audio-$(CONFIG_SND_USB_AUDIO_USE_MEDIA_CONTROLLER) += media.o + snd-usbmidi-lib-objs := midi.o # Toplevel Module Dependency diff --git a/sound/usb/card.c b/sound/usb/card.c index 719e10034553..04465d581204 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c @@ -68,6 +68,7 @@ #include "format.h" #include "power.h" #include "stream.h" +#include "media.h" MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>"); MODULE_DESCRIPTION("USB Audio"); @@ -673,6 +674,11 @@ static int usb_audio_probe(struct usb_interface *intf, if (err < 0) goto __error; + if (quirk && quirk->shares_media_device) { + /* don't want to fail when snd_media_device_create() fails */ + snd_media_device_create(chip, intf); + } + usb_chip[chip->index] = chip; chip->num_interfaces++; usb_set_intfdata(intf, chip); @@ -732,6 +738,14 @@ static void usb_audio_disconnect(struct usb_interface *intf) list_for_each(p, &chip->midi_list) { snd_usbmidi_disconnect(p); } + /* + * Nice to check quirk && quirk->shares_media_device and + * then call the snd_media_device_delete(). Don't have + * access to the quirk here. snd_media_device_delete() + * accesses mixer_list + */ + snd_media_device_delete(chip); + /* release mixer resources */ list_for_each_entry(mixer, &chip->mixer_list, list) { snd_usb_mixer_disconnect(mixer); diff --git a/sound/usb/card.h b/sound/usb/card.h index 79fa2a19fb7b..2991b9986f66 100644 --- a/sound/usb/card.h +++ b/sound/usb/card.h @@ -109,6 +109,8 @@ struct snd_usb_endpoint { struct list_head list; }; +struct media_ctl; + struct snd_usb_substream { struct snd_usb_stream *stream; struct usb_device *dev; @@ -161,6 +163,7 @@ struct snd_usb_substream { } dsd_dop; bool trigger_tstamp_pending_update; /* trigger timestamp being updated from initial estimate */ + struct media_ctl *media_ctl; }; struct snd_usb_stream { diff --git a/sound/usb/media.c b/sound/usb/media.c new file mode 100644 index 000000000000..812017eacbcf --- /dev/null +++ b/sound/usb/media.c @@ -0,0 +1,327 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * media.c - Media Controller specific ALSA driver code + * + * Copyright (c) 2019 Shuah Khan <shuah@kernel.org> + * + */ + +/* + * This file adds Media Controller support to the ALSA driver + * to use the Media Controller API to share the tuner with DVB + * and V4L2 drivers that control the media device. + * + * The media device is created based on the existing quirks framework. + * Using this approach, the media controller API usage can be added for + * a specific device. + */ + +#include <linux/init.h> +#include <linux/list.h> +#include <linux/mutex.h> +#include <linux/slab.h> +#include <linux/usb.h> + +#include <sound/pcm.h> +#include <sound/core.h> + +#include "usbaudio.h" +#include "card.h" +#include "mixer.h" +#include "media.h" + +int snd_media_stream_init(struct snd_usb_substream *subs, struct snd_pcm *pcm, + int stream) +{ + struct media_device *mdev; + struct media_ctl *mctl; + struct device *pcm_dev = &pcm->streams[stream].dev; + u32 intf_type; + int ret = 0; + u16 mixer_pad; + struct media_entity *entity; + + mdev = subs->stream->chip->media_dev; + if (!mdev) + return 0; + + if (subs->media_ctl) + return 0; + + /* allocate media_ctl */ + mctl = kzalloc(sizeof(*mctl), GFP_KERNEL); + if (!mctl) + return -ENOMEM; + + mctl->media_dev = mdev; + if (stream == SNDRV_PCM_STREAM_PLAYBACK) { + intf_type = MEDIA_INTF_T_ALSA_PCM_PLAYBACK; + mctl->media_entity.function = MEDIA_ENT_F_AUDIO_PLAYBACK; + mctl->media_pad.flags = MEDIA_PAD_FL_SOURCE; + mixer_pad = 1; + } else { + intf_type = MEDIA_INTF_T_ALSA_PCM_CAPTURE; + mctl->media_entity.function = MEDIA_ENT_F_AUDIO_CAPTURE; + mctl->media_pad.flags = MEDIA_PAD_FL_SINK; + mixer_pad = 2; + } + mctl->media_entity.name = pcm->name; + media_entity_pads_init(&mctl->media_entity, 1, &mctl->media_pad); + ret = media_device_register_entity(mctl->media_dev, + &mctl->media_entity); + if (ret) + goto free_mctl; + + mctl->intf_devnode = media_devnode_create(mdev, intf_type, 0, + MAJOR(pcm_dev->devt), + MINOR(pcm_dev->devt)); + if (!mctl->intf_devnode) { + ret = -ENOMEM; + goto unregister_entity; + } + mctl->intf_link = media_create_intf_link(&mctl->media_entity, + &mctl->intf_devnode->intf, + MEDIA_LNK_FL_ENABLED); + if (!mctl->intf_link) { + ret = -ENOMEM; + goto devnode_remove; + } + + /* create link between mixer and audio */ + media_device_for_each_entity(entity, mdev) { + switch (entity->function) { + case MEDIA_ENT_F_AUDIO_MIXER: + ret = media_create_pad_link(entity, mixer_pad, + &mctl->media_entity, 0, + MEDIA_LNK_FL_ENABLED); + if (ret) + goto remove_intf_link; + break; + } + } + + subs->media_ctl = mctl; + return 0; + +remove_intf_link: + media_remove_intf_link(mctl->intf_link); +devnode_remove: + media_devnode_remove(mctl->intf_devnode); +unregister_entity: + media_device_unregister_entity(&mctl->media_entity); +free_mctl: + kfree(mctl); + return ret; +} + +void snd_media_stream_delete(struct snd_usb_substream *subs) +{ + struct media_ctl *mctl = subs->media_ctl; + + if (mctl) { + struct media_device *mdev; + + mdev = mctl->media_dev; + if (mdev && media_devnode_is_registered(mdev->devnode)) { + media_devnode_remove(mctl->intf_devnode); + media_device_unregister_entity(&mctl->media_entity); + media_entity_cleanup(&mctl->media_entity); + } + kfree(mctl); + subs->media_ctl = NULL; + } +} + +int snd_media_start_pipeline(struct snd_usb_substream *subs) +{ + struct media_ctl *mctl = subs->media_ctl; + int ret = 0; + + if (!mctl) + return 0; + + mutex_lock(&mctl->media_dev->graph_mutex); + if (mctl->media_dev->enable_source) + ret = mctl->media_dev->enable_source(&mctl->media_entity, + &mctl->media_pipe); + mutex_unlock(&mctl->media_dev->graph_mutex); + return ret; +} + +void snd_media_stop_pipeline(struct snd_usb_substream *subs) +{ + struct media_ctl *mctl = subs->media_ctl; + + if (!mctl) + return; + + mutex_lock(&mctl->media_dev->graph_mutex); + if (mctl->media_dev->disable_source) + mctl->media_dev->disable_source(&mctl->media_entity); + mutex_unlock(&mctl->media_dev->graph_mutex); +} + +static int snd_media_mixer_init(struct snd_usb_audio *chip) +{ + struct device *ctl_dev = &chip->card->ctl_dev; + struct media_intf_devnode *ctl_intf; + struct usb_mixer_interface *mixer; + struct media_device *mdev = chip->media_dev; + struct media_mixer_ctl *mctl; + u32 intf_type = MEDIA_INTF_T_ALSA_CONTROL; + int ret; + + if (!mdev) + return -ENODEV; + + ctl_intf = chip->ctl_intf_media_devnode; + if (!ctl_intf) { + ctl_intf = media_devnode_create(mdev, intf_type, 0, + MAJOR(ctl_dev->devt), + MINOR(ctl_dev->devt)); + if (!ctl_intf) + return -ENOMEM; + chip->ctl_intf_media_devnode = ctl_intf; + } + + list_for_each_entry(mixer, &chip->mixer_list, list) { + + if (mixer->media_mixer_ctl) + continue; + + /* allocate media_mixer_ctl */ + mctl = kzalloc(sizeof(*mctl), GFP_KERNEL); + if (!mctl) + return -ENOMEM; + + mctl->media_dev = mdev; + mctl->media_entity.function = MEDIA_ENT_F_AUDIO_MIXER; + mctl->media_entity.name = chip->card->mixername; + mctl->media_pad[0].flags = MEDIA_PAD_FL_SINK; + mctl->media_pad[1].flags = MEDIA_PAD_FL_SOURCE; + mctl->media_pad[2].flags = MEDIA_PAD_FL_SOURCE; + media_entity_pads_init(&mctl->media_entity, MEDIA_MIXER_PAD_MAX, + mctl->media_pad); + ret = media_device_register_entity(mctl->media_dev, + &mctl->media_entity); + if (ret) { + kfree(mctl); + return ret; + } + + mctl->intf_link = media_create_intf_link(&mctl->media_entity, + &ctl_intf->intf, + MEDIA_LNK_FL_ENABLED); + if (!mctl->intf_link) { + media_device_unregister_entity(&mctl->media_entity); + media_entity_cleanup(&mctl->media_entity); + kfree(mctl); + return -ENOMEM; + } + mctl->intf_devnode = ctl_intf; + mixer->media_mixer_ctl = mctl; + } + return 0; +} + +static void snd_media_mixer_delete(struct snd_usb_audio *chip) +{ + struct usb_mixer_interface *mixer; + struct media_device *mdev = chip->media_dev; + + if (!mdev) + return; + + list_for_each_entry(mixer, &chip->mixer_list, list) { + struct media_mixer_ctl *mctl; + + mctl = mixer->media_mixer_ctl; + if (!mixer->media_mixer_ctl) + continue; + + if (media_devnode_is_registered(mdev->devnode)) { + media_device_unregister_entity(&mctl->media_entity); + media_entity_cleanup(&mctl->media_entity); + } + kfree(mctl); + mixer->media_mixer_ctl = NULL; + } + if (media_devnode_is_registered(mdev->devnode)) + media_devnode_remove(chip->ctl_intf_media_devnode); + chip->ctl_intf_media_devnode = NULL; +} + +int snd_media_device_create(struct snd_usb_audio *chip, + struct usb_interface *iface) +{ + struct media_device *mdev; + struct usb_device *usbdev = interface_to_usbdev(iface); + int ret = 0; + + /* usb-audio driver is probed for each usb interface, and + * there are multiple interfaces per device. Avoid calling + * media_device_usb_allocate() each time usb_audio_probe() + * is called. Do it only once. + */ + if (chip->media_dev) { + mdev = chip->media_dev; + goto snd_mixer_init; + } + + mdev = media_device_usb_allocate(usbdev, KBUILD_MODNAME, THIS_MODULE); + if (IS_ERR(mdev)) + return -ENOMEM; + + /* save media device - avoid lookups */ + chip->media_dev = mdev; + +snd_mixer_init: + /* Create media entities for mixer and control dev */ + ret = snd_media_mixer_init(chip); + /* media_device might be registered, print error and continue */ + if (ret) + dev_err(&usbdev->dev, + "Couldn't create media mixer entities. Error: %d\n", + ret); + + if (!media_devnode_is_registered(mdev->devnode)) { + /* dont'register if snd_media_mixer_init() failed */ + if (ret) + goto create_fail; + + /* register media_device */ + ret = media_device_register(mdev); +create_fail: + if (ret) { + snd_media_mixer_delete(chip); + media_device_delete(mdev, KBUILD_MODNAME, THIS_MODULE); + /* clear saved media_dev */ + chip->media_dev = NULL; + dev_err(&usbdev->dev, + "Couldn't register media device. Error: %d\n", + ret); + return ret; + } + } + + return ret; +} + +void snd_media_device_delete(struct snd_usb_audio *chip) +{ + struct media_device *mdev = chip->media_dev; + struct snd_usb_stream *stream; + + /* release resources */ + list_for_each_entry(stream, &chip->pcm_list, list) { + snd_media_stream_delete(&stream->substream[0]); + snd_media_stream_delete(&stream->substream[1]); + } + + snd_media_mixer_delete(chip); + + if (mdev) { + media_device_delete(mdev, KBUILD_MODNAME, THIS_MODULE); + chip->media_dev = NULL; + } +} diff --git a/sound/usb/media.h b/sound/usb/media.h new file mode 100644 index 000000000000..f5bdec1d602f --- /dev/null +++ b/sound/usb/media.h @@ -0,0 +1,74 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * media.h - Media Controller specific ALSA driver code + * + * Copyright (c) 2019 Shuah Khan <shuah@kernel.org> + * + */ + +/* + * This file adds Media Controller support to the ALSA driver + * to use the Media Controller API to share the tuner with DVB + * and V4L2 drivers that control the media device. + * + * The media device is created based on the existing quirks framework. + * Using this approach, the media controller API usage can be added for + * a specific device. + */ +#ifndef __MEDIA_H + +#ifdef CONFIG_SND_USB_AUDIO_USE_MEDIA_CONTROLLER + +#include <linux/media.h> +#include <media/media-device.h> +#include <media/media-entity.h> +#include <media/media-dev-allocator.h> +#include <sound/asound.h> + +struct media_ctl { + struct media_device *media_dev; + struct media_entity media_entity; + struct media_intf_devnode *intf_devnode; + struct media_link *intf_link; + struct media_pad media_pad; + struct media_pipeline media_pipe; +}; + +/* + * One source pad each for SNDRV_PCM_STREAM_CAPTURE and + * SNDRV_PCM_STREAM_PLAYBACK. One for sink pad to link + * to AUDIO Source + */ +#define MEDIA_MIXER_PAD_MAX (SNDRV_PCM_STREAM_LAST + 2) + +struct media_mixer_ctl { + struct media_device *media_dev; + struct media_entity media_entity; + struct media_intf_devnode *intf_devnode; + struct media_link *intf_link; + struct media_pad media_pad[MEDIA_MIXER_PAD_MAX]; + struct media_pipeline media_pipe; +}; + +int snd_media_device_create(struct snd_usb_audio *chip, + struct usb_interface *iface); +void snd_media_device_delete(struct snd_usb_audio *chip); +int snd_media_stream_init(struct snd_usb_substream *subs, struct snd_pcm *pcm, + int stream); +void snd_media_stream_delete(struct snd_usb_substream *subs); +int snd_media_start_pipeline(struct snd_usb_substream *subs); +void snd_media_stop_pipeline(struct snd_usb_substream *subs); +#else +static inline int snd_media_device_create(struct snd_usb_audio *chip, + struct usb_interface *iface) + { return 0; } +static inline void snd_media_device_delete(struct snd_usb_audio *chip) { } +static inline int snd_media_stream_init(struct snd_usb_substream *subs, + struct snd_pcm *pcm, int stream) + { return 0; } +static inline void snd_media_stream_delete(struct snd_usb_substream *subs) { } +static inline int snd_media_start_pipeline(struct snd_usb_substream *subs) + { return 0; } +static inline void snd_media_stop_pipeline(struct snd_usb_substream *subs) { } +#endif +#endif /* __MEDIA_H */ diff --git a/sound/usb/mixer.h b/sound/usb/mixer.h index 3d12af8bf191..394cd9107507 100644 --- a/sound/usb/mixer.h +++ b/sound/usb/mixer.h @@ -4,6 +4,8 @@ #include <sound/info.h> +struct media_mixer_ctl; + struct usb_mixer_interface { struct snd_usb_audio *chip; struct usb_host_interface *hostif; @@ -23,6 +25,7 @@ struct usb_mixer_interface { struct urb *rc_urb; struct usb_ctrlrequest *rc_setup_packet; u8 rc_buffer[6]; + struct media_mixer_ctl *media_mixer_ctl; bool disconnected; }; diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index 056af0a57b22..5d8494b2a026 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -35,6 +35,7 @@ #include "pcm.h" #include "clock.h" #include "power.h" +#include "media.h" #define SUBSTREAM_FLAG_DATA_EP_STARTED 0 #define SUBSTREAM_FLAG_SYNC_EP_STARTED 1 @@ -787,6 +788,10 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream, struct audioformat *fmt; int ret; + ret = snd_media_start_pipeline(subs); + if (ret) + return ret; + if (snd_usb_use_vmalloc) ret = snd_pcm_lib_alloc_vmalloc_buffer(substream, params_buffer_bytes(hw_params)); @@ -794,7 +799,7 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream, ret = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); if (ret < 0) - return ret; + goto stop_pipeline; subs->pcm_format = params_format(hw_params); subs->period_bytes = params_period_bytes(hw_params); @@ -808,12 +813,13 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream, dev_dbg(&subs->dev->dev, "cannot set format: format = %#x, rate = %d, channels = %d\n", subs->pcm_format, subs->cur_rate, subs->channels); - return -EINVAL; + ret = -EINVAL; + goto stop_pipeline; } ret = snd_usb_lock_shutdown(subs->stream->chip); if (ret < 0) - return ret; + goto stop_pipeline; ret = snd_usb_pcm_change_state(subs, UAC3_PD_STATE_D0); if (ret < 0) @@ -829,6 +835,12 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream, unlock: snd_usb_unlock_shutdown(subs->stream->chip); + if (ret < 0) + goto stop_pipeline; + return ret; + + stop_pipeline: + snd_media_stop_pipeline(subs); return ret; } @@ -841,6 +853,7 @@ static int snd_usb_hw_free(struct snd_pcm_substream *substream) { struct snd_usb_substream *subs = substream->runtime->private_data; + snd_media_stop_pipeline(subs); subs->cur_audiofmt = NULL; subs->cur_rate = 0; subs->period_bytes = 0; @@ -1313,6 +1326,7 @@ static int snd_usb_pcm_open(struct snd_pcm_substream *substream) struct snd_usb_stream *as = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; struct snd_usb_substream *subs = &as->substream[direction]; + int ret; subs->interface = -1; subs->altset_idx = 0; @@ -1326,7 +1340,13 @@ static int snd_usb_pcm_open(struct snd_pcm_substream *substream) subs->dsd_dop.channel = 0; subs->dsd_dop.marker = 1; - return setup_hw_info(runtime, subs); + ret = setup_hw_info(runtime, subs); + if (ret == 0) { + ret = snd_media_stream_init(subs, as->pcm, direction); + if (ret) + snd_usb_autosuspend(subs->stream->chip); + } + return ret; } static int snd_usb_pcm_close(struct snd_pcm_substream *substream) @@ -1337,6 +1357,7 @@ static int snd_usb_pcm_close(struct snd_pcm_substream *substream) int ret; stop_endpoints(subs, true); + snd_media_stop_pipeline(subs); if (!as->chip->keep_iface && subs->interface >= 0 && diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index 86e80916a029..8cbca137ee6f 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h @@ -2887,6 +2887,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), .product_name = pname, \ .ifnum = QUIRK_ANY_INTERFACE, \ .type = QUIRK_AUDIO_ALIGN_TRANSFER, \ + .shares_media_device = 1, \ } \ } diff --git a/sound/usb/stream.c b/sound/usb/stream.c index d9e3de495c16..9f1623e37fb3 100644 --- a/sound/usb/stream.c +++ b/sound/usb/stream.c @@ -38,6 +38,7 @@ #include "clock.h" #include "stream.h" #include "power.h" +#include "media.h" /* * free a substream @@ -55,6 +56,7 @@ static void free_substream(struct snd_usb_substream *subs) } kfree(subs->rate_list.list); kfree(subs->str_pd); + snd_media_stream_delete(subs); } diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index b9faeca645fd..0968a45c8925 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h @@ -30,6 +30,9 @@ * */ +struct media_device; +struct media_intf_devnode; + struct snd_usb_audio { int index; struct usb_device *dev; @@ -66,6 +69,8 @@ struct snd_usb_audio { */ struct usb_host_interface *ctrl_intf; /* the audio control interface */ + struct media_device *media_dev; + struct media_intf_devnode *ctl_intf_media_devnode; }; #define usb_audio_err(chip, fmt, args...) \ @@ -117,6 +122,7 @@ struct snd_usb_audio_quirk { const char *profile_name; /* override the card->longname */ int16_t ifnum; uint16_t type; + bool shares_media_device; const void *data; }; diff --git a/tools/testing/selftests/media_tests/media_dev_allocator.sh b/tools/testing/selftests/media_tests/media_dev_allocator.sh new file mode 100755 index 000000000000..ffe00c59a483 --- /dev/null +++ b/tools/testing/selftests/media_tests/media_dev_allocator.sh @@ -0,0 +1,85 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 +# Media Device Allocator API test script +# Copyright (c) 2019 Shuah Khan <shuah@kernel.org> + +echo "Media Device Allocator testing: unbind and bind" +echo "media driver $1 audio driver $2" + +MDRIVER=/sys/bus/usb/drivers/$1 +cd $MDRIVER +MDEV=$(ls -d *\-*) + +ADRIVER=/sys/bus/usb/drivers/$2 +cd $ADRIVER +ADEV=$(ls -d *\-*.1) + +echo "==================================" +echo "Test unbind both devices - start" +echo "Running unbind of $MDEV from $MDRIVER" +echo $MDEV > $MDRIVER/unbind; + +echo "Media device should still be present!" +ls -l /dev/media* + +echo "sound driver is at: $ADRIVER" +echo "Device is: $ADEV" + +echo "Running unbind of $ADEV from $ADRIVER" +echo $ADEV > $ADRIVER/unbind; + +echo "Media device should have been deleted!" +ls -l /dev/media* +echo "Test unbind both devices - end" + +echo "==================================" + +echo "Test bind both devices - start" +echo "Running bind of $MDEV from $MDRIVER" +echo $MDEV > $MDRIVER/bind; + +echo "Media device should be present!" +ls -l /dev/media* + +echo "Running bind of $ADEV from $ADRIVER" +echo $ADEV > $ADRIVER/bind; + +echo "Media device should be there!" +ls -l /dev/media* + +echo "Test bind both devices - end" + +echo "==================================" + +echo "Test unbind $MDEV - bind $MDEV - unbind $ADEV - bind $ADEV start" + +echo "Running unbind of $MDEV from $MDRIVER" +echo $MDEV > $MDRIVER/unbind; + +echo "Media device should be there!" +ls -l /dev/media* + +sleep 1 + +echo "Running bind of $MDEV from $MDRIVER" +echo $MDEV > $MDRIVER/bind; + +echo "Media device should be there!" +ls -l /dev/media* + +echo "Running unbind of $ADEV from $ADRIVER" +echo $ADEV > $ADRIVER/unbind; + +echo "Media device should be there!" +ls -l /dev/media* + +sleep 1 + +echo "Running bind of $ADEV from $ADRIVER" +echo $ADEV > $ADRIVER/bind; + +echo "Media device should be there!" +ls -l /dev/media* + +echo "Test unbind $MDEV - bind $MDEV - unbind $ADEV - bind $ADEV end" +echo "==================================" |