media updates for v4.15-rc1
-----BEGIN PGP SIGNATURE----- iQIcBAABAgAGBQJaC/4EAAoJEAhfPr2O5OEVQnsP/2JNpdLuzgwNp0p2gXrvK5pl KOsA6Fld6RNmpuel8eHARbbDTPKF1Y1bvYXVo7lPhXb7KuM2IzG56VxoNech/5pX eflKwnpV/Ns/ZMLYue7Rqdw0iZnjWESBWf5lzg9MvzwhZBaPlRwqu/aOJy360AZr FnjKHtU/6WUIOCB8r0qLBDR/epoh7y2lKfjDTcEBrURrFEsTajdyd59npdMSIQqO iUeeBVEIUKyytYDQNM/VOsBnh0G+2inLuykF8Nd6pYs8O0iUEUpZYwdGuwGUG1HB VmCcRGU62efl5nu8zQMPnwAvjXwZAh8vbS0ha+B1vBJh1RwNVUz0kKIKEgAaOMZ3 zZa3NLfDP4cHgYtr2Xw2vSvJvDwQecmiItJKeZ/Id4cPy03TKEV1KEaHCQJHwbDn RP/o9C+5gagMO/oIvZPQ+esVZXQ4prAzOdX53N7HPn4Wn+k4clkI0+hMvMGf67mo EYOguCqbN2D0e11BLiPP1bRbGZRSI8I9xcKuhcw4ajJHbRRkrjl8EW7V6c8CuMkd 0Wj5oidFleJ0Vy+qQOPqXN1FwR7AbHNtI38JfWNz324AIrFCQERpfXVmKwRPZfl4 YXgGIA9fil3a01YJCtxc0PsXlRkveKJ8hKCLpjXbjNTh1oSbgrDxx5sMx9PO6WqJ VOb6fL17rwTXlKV/GeU/ =d9nT -----END PGP SIGNATURE----- Merge tag 'media/v4.15-1' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media Pull media updates from Mauro Carvalho Chehab: - Documentation for digital TV (both kAPI and uAPI) are now in sync with the implementation (except for legacy/deprecated ioctls). This is a major step, as there were always a gap there - New sensor driver: imx274 - New cec driver: cec-gpio - New platform driver for rockship rga and tegra CEC - New RC driver: tango-ir - Several cleanups at atomisp driver - Core improvements for RC, CEC, V4L2 async probing support and DVB - Lots of drivers cleanup, fixes and improvements. * tag 'media/v4.15-1' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (332 commits) dvb_frontend: don't use-after-free the frontend struct media: dib0700: fix invalid dvb_detach argument media: v4l2-ctrls: Don't validate BITMASK twice media: s5p-mfc: fix lockdep warning media: dvb-core: always call invoke_release() in fe_free() media: usb: dvb-usb-v2: dvb_usb_core: remove redundant code in dvb_usb_fe_sleep media: au0828: make const array addr_list static media: cx88: make const arrays default_addr_list and pvr2000_addr_list static media: drxd: make const array fastIncrDecLUT static media: usb: fix spelling mistake: "synchronuously" -> "synchronously" media: ddbridge: fix build warnings media: av7110: avoid 2038 overflow in debug print media: Don't do DMA on stack for firmware upload in the AS102 driver media: v4l: async: fix unregister for implicitly registered sub-device notifiers media: v4l: async: fix return of unitialized variable ret media: imx274: fix missing return assignment from call to imx274_mode_regs media: camss-vfe: always initialize reg at vfe_set_xbar_cfg() media: atomisp: make function calls cleaner media: atomisp: get rid of storage_class.h media: atomisp: get rid of wrong stddef.h include ...
This commit is contained in:
commit
5d352e69c6
498 changed files with 12071 additions and 22634 deletions
32
Documentation/devicetree/bindings/media/cec-gpio.txt
Normal file
32
Documentation/devicetree/bindings/media/cec-gpio.txt
Normal file
|
@ -0,0 +1,32 @@
|
|||
* HDMI CEC GPIO driver
|
||||
|
||||
The HDMI CEC GPIO module supports CEC implementations where the CEC line
|
||||
is hooked up to a pull-up GPIO line and - optionally - the HPD line is
|
||||
hooked up to another GPIO line.
|
||||
|
||||
Required properties:
|
||||
- compatible: value must be "cec-gpio".
|
||||
- cec-gpios: gpio that the CEC line is connected to. The line should be
|
||||
tagged as open drain.
|
||||
|
||||
If the CEC line is associated with an HDMI receiver/transmitter, then the
|
||||
following property is also required:
|
||||
|
||||
- hdmi-phandle - phandle to the HDMI controller, see also cec.txt.
|
||||
|
||||
If the CEC line is not associated with an HDMI receiver/transmitter, then
|
||||
the following property is optional:
|
||||
|
||||
- hpd-gpios: gpio that the HPD line is connected to.
|
||||
|
||||
Example for the Raspberry Pi 3 where the CEC line is connected to
|
||||
pin 26 aka BCM7 aka CE1 on the GPIO pin header and the HPD line is
|
||||
connected to pin 11 aka BCM17:
|
||||
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
|
||||
cec-gpio {
|
||||
compatible = "cec-gpio";
|
||||
cec-gpios = <&gpio 7 (GPIO_ACTIVE_HIGH|GPIO_OPEN_DRAIN)>;
|
||||
hpd-gpios = <&gpio 17 GPIO_ACTIVE_HIGH>;
|
||||
};
|
|
@ -3,8 +3,11 @@
|
|||
G-Scaler is used for scaling and color space conversion on EXYNOS5 SoCs.
|
||||
|
||||
Required properties:
|
||||
- compatible: should be "samsung,exynos5-gsc" (for Exynos 5250, 5420 and
|
||||
5422 SoCs) or "samsung,exynos5433-gsc" (Exynos 5433)
|
||||
- compatible: should be one of
|
||||
"samsung,exynos5250-gsc"
|
||||
"samsung,exynos5420-gsc"
|
||||
"samsung,exynos5433-gsc"
|
||||
"samsung,exynos5-gsc" (deprecated)
|
||||
- reg: should contain G-Scaler physical address location and length.
|
||||
- interrupts: should contain G-Scaler interrupt number
|
||||
|
||||
|
@ -15,7 +18,7 @@ Optional properties:
|
|||
Example:
|
||||
|
||||
gsc_0: gsc@0x13e00000 {
|
||||
compatible = "samsung,exynos5-gsc";
|
||||
compatible = "samsung,exynos5250-gsc";
|
||||
reg = <0x13e00000 0x1000>;
|
||||
interrupts = <0 85 0>;
|
||||
};
|
||||
|
|
33
Documentation/devicetree/bindings/media/i2c/imx274.txt
Normal file
33
Documentation/devicetree/bindings/media/i2c/imx274.txt
Normal file
|
@ -0,0 +1,33 @@
|
|||
* Sony 1/2.5-Inch 8.51Mp CMOS Digital Image Sensor
|
||||
|
||||
The Sony imx274 is a 1/2.5-inch CMOS active pixel digital image sensor with
|
||||
an active array size of 3864H x 2202V. It is programmable through I2C
|
||||
interface. The I2C address is fixed to 0x1a as per sensor data sheet.
|
||||
Image data is sent through MIPI CSI-2, which is configured as 4 lanes
|
||||
at 1440 Mbps.
|
||||
|
||||
|
||||
Required Properties:
|
||||
- compatible: value should be "sony,imx274" for imx274 sensor
|
||||
- reg: I2C bus address of the device
|
||||
|
||||
Optional Properties:
|
||||
- reset-gpios: Sensor reset GPIO
|
||||
|
||||
The imx274 device node should contain one 'port' child node with
|
||||
an 'endpoint' subnode. For further reading on port node refer to
|
||||
Documentation/devicetree/bindings/media/video-interfaces.txt.
|
||||
|
||||
Example:
|
||||
sensor@1a {
|
||||
compatible = "sony,imx274";
|
||||
reg = <0x1a>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
reset-gpios = <&gpio_sensor 0 0>;
|
||||
port {
|
||||
sensor_out: endpoint {
|
||||
remote-endpoint = <&csiss_in>;
|
||||
};
|
||||
};
|
||||
};
|
|
@ -27,6 +27,8 @@ Optional properties
|
|||
- nokia,nvm-size: The size of the NVM, in bytes. If the size is not given,
|
||||
the NVM contents will not be read.
|
||||
- reset-gpios: XSHUTDOWN GPIO
|
||||
- flash-leds: See ../video-interfaces.txt
|
||||
- lens-focus: See ../video-interfaces.txt
|
||||
|
||||
|
||||
Endpoint node mandatory properties
|
||||
|
|
33
Documentation/devicetree/bindings/media/rockchip-rga.txt
Normal file
33
Documentation/devicetree/bindings/media/rockchip-rga.txt
Normal file
|
@ -0,0 +1,33 @@
|
|||
device-tree bindings for rockchip 2D raster graphic acceleration controller (RGA)
|
||||
|
||||
RGA is a standalone 2D raster graphic acceleration unit. It accelerates 2D
|
||||
graphics operations, such as point/line drawing, image scaling, rotation,
|
||||
BitBLT, alpha blending and image blur/sharpness.
|
||||
|
||||
Required properties:
|
||||
- compatible: value should be one of the following
|
||||
"rockchip,rk3288-rga";
|
||||
"rockchip,rk3399-rga";
|
||||
|
||||
- interrupts: RGA interrupt specifier.
|
||||
|
||||
- clocks: phandle to RGA sclk/hclk/aclk clocks
|
||||
|
||||
- clock-names: should be "aclk", "hclk" and "sclk"
|
||||
|
||||
- resets: Must contain an entry for each entry in reset-names.
|
||||
See ../reset/reset.txt for details.
|
||||
- reset-names: should be "core", "axi" and "ahb"
|
||||
|
||||
Example:
|
||||
SoC-specific DT entry:
|
||||
rga: rga@ff680000 {
|
||||
compatible = "rockchip,rk3399-rga";
|
||||
reg = <0xff680000 0x10000>;
|
||||
interrupts = <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&cru ACLK_RGA>, <&cru HCLK_RGA>, <&cru SCLK_RGA_CORE>;
|
||||
clock-names = "aclk", "hclk", "sclk";
|
||||
|
||||
resets = <&cru SRST_RGA_CORE>, <&cru SRST_A_RGA>, <&cru SRST_H_RGA>;
|
||||
reset-names = "core, "axi", "ahb";
|
||||
};
|
21
Documentation/devicetree/bindings/media/tango-ir.txt
Normal file
21
Documentation/devicetree/bindings/media/tango-ir.txt
Normal file
|
@ -0,0 +1,21 @@
|
|||
Sigma Designs Tango IR NEC/RC-5/RC-6 decoder (SMP86xx and SMP87xx)
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible: "sigma,smp8642-ir"
|
||||
- reg: address/size of NEC+RC5 area, address/size of RC6 area
|
||||
- interrupts: spec for IR IRQ
|
||||
- clocks: spec for IR clock (typically the crystal oscillator)
|
||||
|
||||
Optional properties:
|
||||
|
||||
- linux,rc-map-name: see Documentation/devicetree/bindings/media/rc.txt
|
||||
|
||||
Example:
|
||||
|
||||
ir@10518 {
|
||||
compatible = "sigma,smp8642-ir";
|
||||
reg = <0x10518 0x18>, <0x105e0 0x1c>;
|
||||
interrupts = <21 IRQ_TYPE_EDGE_RISING>;
|
||||
clocks = <&xtal>;
|
||||
};
|
27
Documentation/devicetree/bindings/media/tegra-cec.txt
Normal file
27
Documentation/devicetree/bindings/media/tegra-cec.txt
Normal file
|
@ -0,0 +1,27 @@
|
|||
* Tegra HDMI CEC hardware
|
||||
|
||||
The HDMI CEC module is present in Tegra SoCs and its purpose is to
|
||||
handle communication between HDMI connected devices over the CEC bus.
|
||||
|
||||
Required properties:
|
||||
- compatible : value should be one of the following:
|
||||
"nvidia,tegra114-cec"
|
||||
"nvidia,tegra124-cec"
|
||||
"nvidia,tegra210-cec"
|
||||
- reg : Physical base address of the IP registers and length of memory
|
||||
mapped region.
|
||||
- interrupts : HDMI CEC interrupt number to the CPU.
|
||||
- clocks : from common clock binding: handle to HDMI CEC clock.
|
||||
- clock-names : from common clock binding: must contain "cec",
|
||||
corresponding to the entry in the clocks property.
|
||||
- hdmi-phandle : phandle to the HDMI controller, see also cec.txt.
|
||||
|
||||
Example:
|
||||
|
||||
cec@70015000 {
|
||||
compatible = "nvidia,tegra124-cec";
|
||||
reg = <0x0 0x70015000 0x0 0x00001000>;
|
||||
interrupts = <GIC_SPI 3 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&tegra_car TEGRA124_CLK_CEC>;
|
||||
clock-names = "cec";
|
||||
};
|
|
@ -55,6 +55,15 @@ divided into two separate ITU-R BT.656 8-bit busses. In such case bus-width
|
|||
and data-shift properties can be used to assign physical data lines to each
|
||||
endpoint node (logical bus).
|
||||
|
||||
Documenting bindings for devices
|
||||
--------------------------------
|
||||
|
||||
All required and optional bindings the device supports shall be explicitly
|
||||
documented in device DT binding documentation. This also includes port and
|
||||
endpoint nodes for the device, including unit-addresses and reg properties where
|
||||
relevant.
|
||||
|
||||
Please also see Documentation/devicetree/bindings/graph.txt .
|
||||
|
||||
Required properties
|
||||
-------------------
|
||||
|
@ -67,6 +76,16 @@ are required in a relevant parent node:
|
|||
identifier, should be 1.
|
||||
- #size-cells : should be zero.
|
||||
|
||||
|
||||
Optional properties
|
||||
-------------------
|
||||
|
||||
- flash-leds: An array of phandles, each referring to a flash LED, a sub-node
|
||||
of the LED driver device node.
|
||||
|
||||
- lens-focus: A phandle to the node of the focus lens controller.
|
||||
|
||||
|
||||
Optional endpoint properties
|
||||
----------------------------
|
||||
|
||||
|
@ -99,7 +118,10 @@ Optional endpoint properties
|
|||
determines the logical lane number, while the value of an entry indicates
|
||||
physical lane, e.g. for 2-lane MIPI CSI-2 bus we could have
|
||||
"data-lanes = <1 2>;", assuming the clock lane is on hardware lane 0.
|
||||
This property is valid for serial busses only (e.g. MIPI CSI-2).
|
||||
If the hardware does not support lane reordering, monotonically
|
||||
incremented values shall be used from 0 or 1 onwards, depending on
|
||||
whether or not there is also a clock lane. This property is valid for
|
||||
serial busses only (e.g. MIPI CSI-2).
|
||||
- clock-lanes: an array of physical clock lane indexes. Position of an entry
|
||||
determines the logical lane number, while the value of an entry indicates
|
||||
physical lane, e.g. for a MIPI CSI-2 bus we could have "clock-lanes = <0>;",
|
||||
|
|
|
@ -24,8 +24,6 @@ ignore define CEC_VENDOR_ID_NONE
|
|||
ignore define CEC_MODE_INITIATOR_MSK
|
||||
ignore define CEC_MODE_FOLLOWER_MSK
|
||||
|
||||
ignore define CEC_EVENT_FL_INITIAL_STATE
|
||||
|
||||
# Part of CEC 2.0 spec - shouldn't be documented too?
|
||||
ignore define CEC_LOG_ADDR_TV
|
||||
ignore define CEC_LOG_ADDR_RECORD_1
|
||||
|
|
|
@ -227,8 +227,8 @@ CEC_TX_STATUS_LOW_DRIVE:
|
|||
retransmission.
|
||||
|
||||
CEC_TX_STATUS_ERROR:
|
||||
some unspecified error occurred: this can be one of
|
||||
the previous two if the hardware cannot differentiate or something
|
||||
some unspecified error occurred: this can be one of ARB_LOST
|
||||
or LOW_DRIVE if the hardware cannot differentiate or something
|
||||
else entirely.
|
||||
|
||||
CEC_TX_STATUS_MAX_RETRIES:
|
||||
|
@ -238,6 +238,9 @@ CEC_TX_STATUS_MAX_RETRIES:
|
|||
doesn't have to make another attempt to transmit the message
|
||||
since the hardware did that already.
|
||||
|
||||
The hardware must be able to differentiate between OK, NACK and 'something
|
||||
else'.
|
||||
|
||||
The \*_cnt arguments are the number of error conditions that were seen.
|
||||
This may be 0 if no information is available. Drivers that do not support
|
||||
hardware retry can just set the counter corresponding to the transmit error
|
||||
|
|
4
Documentation/media/kapi/dtv-ca.rst
Normal file
4
Documentation/media/kapi/dtv-ca.rst
Normal file
|
@ -0,0 +1,4 @@
|
|||
Digital TV Conditional Access kABI
|
||||
----------------------------------
|
||||
|
||||
.. kernel-doc:: drivers/media/dvb-core/dvb_ca_en50221.h
|
55
Documentation/media/kapi/dtv-common.rst
Normal file
55
Documentation/media/kapi/dtv-common.rst
Normal file
|
@ -0,0 +1,55 @@
|
|||
Digital TV Common functions
|
||||
---------------------------
|
||||
|
||||
Math functions
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
Provide some commonly-used math functions, usually required in order to
|
||||
estimate signal strength and signal to noise measurements in dB.
|
||||
|
||||
.. kernel-doc:: drivers/media/dvb-core/dvb_math.h
|
||||
|
||||
|
||||
DVB devices
|
||||
~~~~~~~~~~~
|
||||
|
||||
Those functions are responsible for handling the DVB device nodes.
|
||||
|
||||
.. kernel-doc:: drivers/media/dvb-core/dvbdev.h
|
||||
|
||||
Digital TV Ring buffer
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Those routines implement ring buffers used to handle digital TV data and
|
||||
copy it from/to userspace.
|
||||
|
||||
.. note::
|
||||
|
||||
1) For performance reasons read and write routines don't check buffer sizes
|
||||
and/or number of bytes free/available. This has to be done before these
|
||||
routines are called. For example:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
/* write @buflen: bytes */
|
||||
free = dvb_ringbuffer_free(rbuf);
|
||||
if (free >= buflen)
|
||||
count = dvb_ringbuffer_write(rbuf, buffer, buflen);
|
||||
else
|
||||
/* do something */
|
||||
|
||||
/* read min. 1000, max. @bufsize: bytes */
|
||||
avail = dvb_ringbuffer_avail(rbuf);
|
||||
if (avail >= 1000)
|
||||
count = dvb_ringbuffer_read(rbuf, buffer, min(avail, bufsize));
|
||||
else
|
||||
/* do something */
|
||||
|
||||
2) If there is exactly one reader and one writer, there is no need
|
||||
to lock read or write operations.
|
||||
Two or more readers must be locked against each other.
|
||||
Flushing the buffer counts as a read operation.
|
||||
Resetting the buffer counts as a read and write operation.
|
||||
Two or more writers must be locked against each other.
|
||||
|
||||
.. kernel-doc:: drivers/media/dvb-core/dvb_ringbuffer.h
|
|
@ -26,572 +26,12 @@ I2C bus.
|
|||
abandoned standard, not used anymore) and ATSC version 3.0 current
|
||||
proposals. Currently, the DVB subsystem doesn't implement those standards.
|
||||
|
||||
Digital TV Common functions
|
||||
---------------------------
|
||||
|
||||
.. kernel-doc:: drivers/media/dvb-core/dvb_math.h
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
.. kernel-doc:: drivers/media/dvb-core/dvbdev.h
|
||||
|
||||
Digital TV Ring buffer
|
||||
----------------------
|
||||
|
||||
Those routines implement ring buffers used to handle digital TV data and
|
||||
copy it from/to userspace.
|
||||
|
||||
.. note::
|
||||
|
||||
1) For performance reasons read and write routines don't check buffer sizes
|
||||
and/or number of bytes free/available. This has to be done before these
|
||||
routines are called. For example:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
/* write @buflen: bytes */
|
||||
free = dvb_ringbuffer_free(rbuf);
|
||||
if (free >= buflen)
|
||||
count = dvb_ringbuffer_write(rbuf, buffer, buflen);
|
||||
else
|
||||
/* do something */
|
||||
|
||||
/* read min. 1000, max. @bufsize: bytes */
|
||||
avail = dvb_ringbuffer_avail(rbuf);
|
||||
if (avail >= 1000)
|
||||
count = dvb_ringbuffer_read(rbuf, buffer, min(avail, bufsize));
|
||||
else
|
||||
/* do something */
|
||||
|
||||
2) If there is exactly one reader and one writer, there is no need
|
||||
to lock read or write operations.
|
||||
Two or more readers must be locked against each other.
|
||||
Flushing the buffer counts as a read operation.
|
||||
Resetting the buffer counts as a read and write operation.
|
||||
Two or more writers must be locked against each other.
|
||||
|
||||
.. kernel-doc:: drivers/media/dvb-core/dvb_ringbuffer.h
|
||||
|
||||
|
||||
Digital TV Frontend kABI
|
||||
------------------------
|
||||
|
||||
Digital TV Frontend
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The Digital TV Frontend kABI defines a driver-internal interface for
|
||||
registering low-level, hardware specific driver to a hardware independent
|
||||
frontend layer. It is only of interest for Digital TV device driver writers.
|
||||
The header file for this API is named ``dvb_frontend.h`` and located in
|
||||
``drivers/media/dvb-core``.
|
||||
|
||||
Demodulator driver
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The demodulator driver is responsible to talk with the decoding part of the
|
||||
hardware. Such driver should implement :c:type:`dvb_frontend_ops`, with
|
||||
tells what type of digital TV standards are supported, and points to a
|
||||
series of functions that allow the DVB core to command the hardware via
|
||||
the code under ``drivers/media/dvb-core/dvb_frontend.c``.
|
||||
|
||||
A typical example of such struct in a driver ``foo`` is::
|
||||
|
||||
static struct dvb_frontend_ops foo_ops = {
|
||||
.delsys = { SYS_DVBT, SYS_DVBT2, SYS_DVBC_ANNEX_A },
|
||||
.info = {
|
||||
.name = "foo DVB-T/T2/C driver",
|
||||
.caps = FE_CAN_FEC_1_2 |
|
||||
FE_CAN_FEC_2_3 |
|
||||
FE_CAN_FEC_3_4 |
|
||||
FE_CAN_FEC_5_6 |
|
||||
FE_CAN_FEC_7_8 |
|
||||
FE_CAN_FEC_AUTO |
|
||||
FE_CAN_QPSK |
|
||||
FE_CAN_QAM_16 |
|
||||
FE_CAN_QAM_32 |
|
||||
FE_CAN_QAM_64 |
|
||||
FE_CAN_QAM_128 |
|
||||
FE_CAN_QAM_256 |
|
||||
FE_CAN_QAM_AUTO |
|
||||
FE_CAN_TRANSMISSION_MODE_AUTO |
|
||||
FE_CAN_GUARD_INTERVAL_AUTO |
|
||||
FE_CAN_HIERARCHY_AUTO |
|
||||
FE_CAN_MUTE_TS |
|
||||
FE_CAN_2G_MODULATION,
|
||||
.frequency_min = 42000000, /* Hz */
|
||||
.frequency_max = 1002000000, /* Hz */
|
||||
.symbol_rate_min = 870000,
|
||||
.symbol_rate_max = 11700000
|
||||
},
|
||||
.init = foo_init,
|
||||
.sleep = foo_sleep,
|
||||
.release = foo_release,
|
||||
.set_frontend = foo_set_frontend,
|
||||
.get_frontend = foo_get_frontend,
|
||||
.read_status = foo_get_status_and_stats,
|
||||
.tune = foo_tune,
|
||||
.i2c_gate_ctrl = foo_i2c_gate_ctrl,
|
||||
.get_frontend_algo = foo_get_algo,
|
||||
};
|
||||
|
||||
A typical example of such struct in a driver ``bar`` meant to be used on
|
||||
Satellite TV reception is::
|
||||
|
||||
static const struct dvb_frontend_ops bar_ops = {
|
||||
.delsys = { SYS_DVBS, SYS_DVBS2 },
|
||||
.info = {
|
||||
.name = "Bar DVB-S/S2 demodulator",
|
||||
.frequency_min = 500000, /* KHz */
|
||||
.frequency_max = 2500000, /* KHz */
|
||||
.frequency_stepsize = 0,
|
||||
.symbol_rate_min = 1000000,
|
||||
.symbol_rate_max = 45000000,
|
||||
.symbol_rate_tolerance = 500,
|
||||
.caps = FE_CAN_INVERSION_AUTO |
|
||||
FE_CAN_FEC_AUTO |
|
||||
FE_CAN_QPSK,
|
||||
},
|
||||
.init = bar_init,
|
||||
.sleep = bar_sleep,
|
||||
.release = bar_release,
|
||||
.set_frontend = bar_set_frontend,
|
||||
.get_frontend = bar_get_frontend,
|
||||
.read_status = bar_get_status_and_stats,
|
||||
.i2c_gate_ctrl = bar_i2c_gate_ctrl,
|
||||
.get_frontend_algo = bar_get_algo,
|
||||
.tune = bar_tune,
|
||||
|
||||
/* Satellite-specific */
|
||||
.diseqc_send_master_cmd = bar_send_diseqc_msg,
|
||||
.diseqc_send_burst = bar_send_burst,
|
||||
.set_tone = bar_set_tone,
|
||||
.set_voltage = bar_set_voltage,
|
||||
};
|
||||
|
||||
.. note::
|
||||
|
||||
#) For satellite digital TV standards (DVB-S, DVB-S2, ISDB-S), the
|
||||
frequencies are specified in kHz, while, for terrestrial and cable
|
||||
standards, they're specified in Hz. Due to that, if the same frontend
|
||||
supports both types, you'll need to have two separate
|
||||
:c:type:`dvb_frontend_ops` structures, one for each standard.
|
||||
#) The ``.i2c_gate_ctrl`` field is present only when the hardware has
|
||||
allows controlling an I2C gate (either directly of via some GPIO pin),
|
||||
in order to remove the tuner from the I2C bus after a channel is
|
||||
tuned.
|
||||
#) All new drivers should implement the
|
||||
:ref:`DVBv5 statistics <dvbv5_stats>` via ``.read_status``.
|
||||
Yet, there are a number of callbacks meant to get statistics for
|
||||
signal strength, S/N and UCB. Those are there to provide backward
|
||||
compatibility with legacy applications that don't support the DVBv5
|
||||
API. Implementing those callbacks are optional. Those callbacks may be
|
||||
removed in the future, after we have all existing drivers supporting
|
||||
DVBv5 stats.
|
||||
#) Other callbacks are required for satellite TV standards, in order to
|
||||
control LNBf and DiSEqC: ``.diseqc_send_master_cmd``,
|
||||
``.diseqc_send_burst``, ``.set_tone``, ``.set_voltage``.
|
||||
|
||||
.. |delta| unicode:: U+00394
|
||||
|
||||
The ``drivers/media/dvb-core/dvb_frontend.c`` has a kernel thread with is
|
||||
responsible for tuning the device. It supports multiple algoritms to
|
||||
detect a channel, as defined at enum :c:func:`dvbfe_algo`.
|
||||
|
||||
The algorithm to be used is obtained via ``.get_frontend_algo``. If the driver
|
||||
doesn't fill its field at struct :c:type:`dvb_frontend_ops`, it will default to
|
||||
``DVBFE_ALGO_SW``, meaning that the dvb-core will do a zigzag when tuning,
|
||||
e. g. it will try first to use the specified center frequency ``f``,
|
||||
then, it will do ``f`` + |delta|, ``f`` - |delta|, ``f`` + 2 x |delta|,
|
||||
``f`` - 2 x |delta| and so on.
|
||||
|
||||
If the hardware has internally a some sort of zigzag algorithm, you should
|
||||
define a ``.get_frontend_algo`` function that would return ``DVBFE_ALGO_HW``.
|
||||
|
||||
.. note::
|
||||
|
||||
The core frontend support also supports
|
||||
a third type (``DVBFE_ALGO_CUSTOM``), in order to allow the driver to
|
||||
define its own hardware-assisted algorithm. Very few hardware need to
|
||||
use it nowadays. Using ``DVBFE_ALGO_CUSTOM`` require to provide other
|
||||
function callbacks at struct :c:type:`dvb_frontend_ops`.
|
||||
|
||||
Attaching frontend driver to the bridge driver
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Before using the Digital TV frontend core, the bridge driver should attach
|
||||
the frontend demod, tuner and SEC devices and call
|
||||
:c:func:`dvb_register_frontend()`,
|
||||
in order to register the new frontend at the subsystem. At device
|
||||
detach/removal, the bridge driver should call
|
||||
:c:func:`dvb_unregister_frontend()` to
|
||||
remove the frontend from the core and then :c:func:`dvb_frontend_detach()`
|
||||
to free the memory allocated by the frontend drivers.
|
||||
|
||||
The drivers should also call :c:func:`dvb_frontend_suspend()` as part of
|
||||
their handler for the :c:type:`device_driver`.\ ``suspend()``, and
|
||||
:c:func:`dvb_frontend_resume()` as
|
||||
part of their handler for :c:type:`device_driver`.\ ``resume()``.
|
||||
|
||||
A few other optional functions are provided to handle some special cases.
|
||||
|
||||
.. _dvbv5_stats:
|
||||
|
||||
Digital TV Frontend statistics
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Introduction
|
||||
^^^^^^^^^^^^
|
||||
|
||||
Digital TV frontends provide a range of
|
||||
:ref:`statistics <frontend-stat-properties>` meant to help tuning the device
|
||||
and measuring the quality of service.
|
||||
|
||||
For each statistics measurement, the driver should set the type of scale used,
|
||||
or ``FE_SCALE_NOT_AVAILABLE`` if the statistics is not available on a given
|
||||
time. Drivers should also provide the number of statistics for each type.
|
||||
that's usually 1 for most video standards [#f2]_.
|
||||
|
||||
Drivers should initialize each statistic counters with length and
|
||||
scale at its init code. For example, if the frontend provides signal
|
||||
strength, it should have, on its init code::
|
||||
|
||||
struct dtv_frontend_properties *c = &state->fe.dtv_property_cache;
|
||||
|
||||
c->strength.len = 1;
|
||||
c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
|
||||
|
||||
And, when the statistics got updated, set the scale::
|
||||
|
||||
c->strength.stat[0].scale = FE_SCALE_DECIBEL;
|
||||
c->strength.stat[0].uvalue = strength;
|
||||
|
||||
.. [#f2] For ISDB-T, it may provide both a global statistics and a per-layer
|
||||
set of statistics. On such cases, len should be equal to 4. The first
|
||||
value corresponds to the global stat; the other ones to each layer, e. g.:
|
||||
|
||||
- c->cnr.stat[0] for global S/N carrier ratio,
|
||||
- c->cnr.stat[1] for Layer A S/N carrier ratio,
|
||||
- c->cnr.stat[2] for layer B S/N carrier ratio,
|
||||
- c->cnr.stat[3] for layer C S/N carrier ratio.
|
||||
|
||||
.. note:: Please prefer to use ``FE_SCALE_DECIBEL`` instead of
|
||||
``FE_SCALE_RELATIVE`` for signal strength and CNR measurements.
|
||||
|
||||
Groups of statistics
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
There are several groups of statistics currently supported:
|
||||
|
||||
Signal strength (:ref:`DTV-STAT-SIGNAL-STRENGTH`)
|
||||
- Measures the signal strength level at the analog part of the tuner or
|
||||
demod.
|
||||
|
||||
- Typically obtained from the gain applied to the tuner and/or frontend
|
||||
in order to detect the carrier. When no carrier is detected, the gain is
|
||||
at the maximum value (so, strength is on its minimal).
|
||||
|
||||
- As the gain is visible through the set of registers that adjust the gain,
|
||||
typically, this statistics is always available [#f3]_.
|
||||
|
||||
- Drivers should try to make it available all the times, as this statistics
|
||||
can be used when adjusting an antenna position and to check for troubles
|
||||
at the cabling.
|
||||
|
||||
.. [#f3] On a few devices, the gain keeps floating if no carrier.
|
||||
On such devices, strength report should check first if carrier is
|
||||
detected at the tuner (``FE_HAS_CARRIER``, see :c:type:`fe_status`),
|
||||
and otherwise return the lowest possible value.
|
||||
|
||||
Carrier Signal to Noise ratio (:ref:`DTV-STAT-CNR`)
|
||||
- Signal to Noise ratio for the main carrier.
|
||||
|
||||
- Signal to Noise measurement depends on the device. On some hardware, is
|
||||
available when the main carrier is detected. On those hardware, CNR
|
||||
measurement usually comes from the tuner (e. g. after ``FE_HAS_CARRIER``,
|
||||
see :c:type:`fe_status`).
|
||||
|
||||
On other devices, it requires inner FEC decoding,
|
||||
as the frontend measures it indirectly from other parameters (e. g. after
|
||||
``FE_HAS_VITERBI``, see :c:type:`fe_status`).
|
||||
|
||||
Having it available after inner FEC is more common.
|
||||
|
||||
Bit counts post-FEC (:ref:`DTV-STAT-POST-ERROR-BIT-COUNT` and :ref:`DTV-STAT-POST-TOTAL-BIT-COUNT`)
|
||||
- Those counters measure the number of bits and bit errors errors after
|
||||
the forward error correction (FEC) on the inner coding block
|
||||
(after Viterbi, LDPC or other inner code).
|
||||
|
||||
- Due to its nature, those statistics depend on full coding lock
|
||||
(e. g. after ``FE_HAS_SYNC`` or after ``FE_HAS_LOCK``,
|
||||
see :c:type:`fe_status`).
|
||||
|
||||
Bit counts pre-FEC (:ref:`DTV-STAT-PRE-ERROR-BIT-COUNT` and :ref:`DTV-STAT-PRE-TOTAL-BIT-COUNT`)
|
||||
- Those counters measure the number of bits and bit errors errors before
|
||||
the forward error correction (FEC) on the inner coding block
|
||||
(before Viterbi, LDPC or other inner code).
|
||||
|
||||
- Not all frontends provide this kind of statistics.
|
||||
|
||||
- Due to its nature, those statistics depend on inner coding lock (e. g.
|
||||
after ``FE_HAS_VITERBI``, see :c:type:`fe_status`).
|
||||
|
||||
Block counts (:ref:`DTV-STAT-ERROR-BLOCK-COUNT` and :ref:`DTV-STAT-TOTAL-BLOCK-COUNT`)
|
||||
- Those counters measure the number of blocks and block errors errors after
|
||||
the forward error correction (FEC) on the inner coding block
|
||||
(before Viterbi, LDPC or other inner code).
|
||||
|
||||
- Due to its nature, those statistics depend on full coding lock
|
||||
(e. g. after ``FE_HAS_SYNC`` or after
|
||||
``FE_HAS_LOCK``, see :c:type:`fe_status`).
|
||||
|
||||
.. note:: All counters should be monotonically increased as they're
|
||||
collected from the hardware.
|
||||
|
||||
A typical example of the logic that handle status and statistics is::
|
||||
|
||||
static int foo_get_status_and_stats(struct dvb_frontend *fe)
|
||||
{
|
||||
struct foo_state *state = fe->demodulator_priv;
|
||||
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
|
||||
|
||||
int rc;
|
||||
enum fe_status *status;
|
||||
|
||||
/* Both status and strength are always available */
|
||||
rc = foo_read_status(fe, &status);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
rc = foo_read_strength(fe);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
/* Check if CNR is available */
|
||||
if (!(fe->status & FE_HAS_CARRIER))
|
||||
return 0;
|
||||
|
||||
rc = foo_read_cnr(fe);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
/* Check if pre-BER stats are available */
|
||||
if (!(fe->status & FE_HAS_VITERBI))
|
||||
return 0;
|
||||
|
||||
rc = foo_get_pre_ber(fe);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
/* Check if post-BER stats are available */
|
||||
if (!(fe->status & FE_HAS_SYNC))
|
||||
return 0;
|
||||
|
||||
rc = foo_get_post_ber(fe);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
}
|
||||
|
||||
static const struct dvb_frontend_ops ops = {
|
||||
/* ... */
|
||||
.read_status = foo_get_status_and_stats,
|
||||
};
|
||||
|
||||
Statistics collect
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
On almost all frontend hardware, the bit and byte counts are stored by
|
||||
the hardware after a certain amount of time or after the total bit/block
|
||||
counter reaches a certain value (usually programable), for example, on
|
||||
every 1000 ms or after receiving 1,000,000 bits.
|
||||
|
||||
So, if you read the registers too soon, you'll end by reading the same
|
||||
value as in the previous reading, causing the monotonic value to be
|
||||
incremented too often.
|
||||
|
||||
Drivers should take the responsibility to avoid too often reads. That
|
||||
can be done using two approaches:
|
||||
|
||||
if the driver have a bit that indicates when a collected data is ready
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
Driver should check such bit before making the statistics available.
|
||||
|
||||
An example of such behavior can be found at this code snippet (adapted
|
||||
from mb86a20s driver's logic)::
|
||||
|
||||
static int foo_get_pre_ber(struct dvb_frontend *fe)
|
||||
{
|
||||
struct foo_state *state = fe->demodulator_priv;
|
||||
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
|
||||
int rc, bit_error;
|
||||
|
||||
/* Check if the BER measures are already available */
|
||||
rc = foo_read_u8(state, 0x54);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
if (!rc)
|
||||
return 0;
|
||||
|
||||
/* Read Bit Error Count */
|
||||
bit_error = foo_read_u32(state, 0x55);
|
||||
if (bit_error < 0)
|
||||
return bit_error;
|
||||
|
||||
/* Read Total Bit Count */
|
||||
rc = foo_read_u32(state, 0x51);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
c->pre_bit_error.stat[0].scale = FE_SCALE_COUNTER;
|
||||
c->pre_bit_error.stat[0].uvalue += bit_error;
|
||||
c->pre_bit_count.stat[0].scale = FE_SCALE_COUNTER;
|
||||
c->pre_bit_count.stat[0].uvalue += rc;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
If the driver doesn't provide a statistics available check bit
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
A few devices, however, may not provide a way to check if the stats are
|
||||
available (or the way to check it is unknown). They may not even provide
|
||||
a way to directly read the total number of bits or blocks.
|
||||
|
||||
On those devices, the driver need to ensure that it won't be reading from
|
||||
the register too often and/or estimate the total number of bits/blocks.
|
||||
|
||||
On such drivers, a typical routine to get statistics would be like
|
||||
(adapted from dib8000 driver's logic)::
|
||||
|
||||
struct foo_state {
|
||||
/* ... */
|
||||
|
||||
unsigned long per_jiffies_stats;
|
||||
}
|
||||
|
||||
static int foo_get_pre_ber(struct dvb_frontend *fe)
|
||||
{
|
||||
struct foo_state *state = fe->demodulator_priv;
|
||||
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
|
||||
int rc, bit_error;
|
||||
u64 bits;
|
||||
|
||||
/* Check if time for stats was elapsed */
|
||||
if (!time_after(jiffies, state->per_jiffies_stats))
|
||||
return 0;
|
||||
|
||||
/* Next stat should be collected in 1000 ms */
|
||||
state->per_jiffies_stats = jiffies + msecs_to_jiffies(1000);
|
||||
|
||||
/* Read Bit Error Count */
|
||||
bit_error = foo_read_u32(state, 0x55);
|
||||
if (bit_error < 0)
|
||||
return bit_error;
|
||||
|
||||
/*
|
||||
* On this particular frontend, there's no register that
|
||||
* would provide the number of bits per 1000ms sample. So,
|
||||
* some function would calculate it based on DTV properties
|
||||
*/
|
||||
bits = get_number_of_bits_per_1000ms(fe);
|
||||
|
||||
c->pre_bit_error.stat[0].scale = FE_SCALE_COUNTER;
|
||||
c->pre_bit_error.stat[0].uvalue += bit_error;
|
||||
c->pre_bit_count.stat[0].scale = FE_SCALE_COUNTER;
|
||||
c->pre_bit_count.stat[0].uvalue += bits;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Please notice that, on both cases, we're getting the statistics using the
|
||||
:c:type:`dvb_frontend_ops` ``.read_status`` callback. The rationale is that
|
||||
the frontend core will automatically call this function periodically
|
||||
(usually, 3 times per second, when the frontend is locked).
|
||||
|
||||
That warrants that we won't miss to collect a counter and increment the
|
||||
monotonic stats at the right time.
|
||||
|
||||
Digital TV Frontend functions and types
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. kernel-doc:: drivers/media/dvb-core/dvb_frontend.h
|
||||
|
||||
|
||||
Digital TV Demux kABI
|
||||
---------------------
|
||||
|
||||
Digital TV Demux
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
The Kernel Digital TV Demux kABI defines a driver-internal interface for
|
||||
registering low-level, hardware specific driver to a hardware independent
|
||||
demux layer. It is only of interest for Digital TV device driver writers.
|
||||
The header file for this kABI is named demux.h and located in
|
||||
drivers/media/dvb-core.
|
||||
|
||||
The demux kABI should be implemented for each demux in the system. It is
|
||||
used to select the TS source of a demux and to manage the demux resources.
|
||||
When the demux client allocates a resource via the demux kABI, it receives
|
||||
a pointer to the kABI of that resource.
|
||||
|
||||
Each demux receives its TS input from a DVB front-end or from memory, as
|
||||
set via this demux kABI. In a system with more than one front-end, the kABI
|
||||
can be used to select one of the DVB front-ends as a TS source for a demux,
|
||||
unless this is fixed in the HW platform.
|
||||
|
||||
The demux kABI only controls front-ends regarding to their connections with
|
||||
demuxes; the kABI used to set the other front-end parameters, such as
|
||||
tuning, are devined via the Digital TV Frontend kABI.
|
||||
|
||||
The functions that implement the abstract interface demux should be defined
|
||||
static or module private and registered to the Demux core for external
|
||||
access. It is not necessary to implement every function in the struct
|
||||
&dmx_demux. For example, a demux interface might support Section filtering,
|
||||
but not PES filtering. The kABI client is expected to check the value of any
|
||||
function pointer before calling the function: the value of ``NULL`` means
|
||||
that the function is not available.
|
||||
|
||||
Whenever the functions of the demux API modify shared data, the
|
||||
possibilities of lost update and race condition problems should be
|
||||
addressed, e.g. by protecting parts of code with mutexes.
|
||||
|
||||
Note that functions called from a bottom half context must not sleep.
|
||||
Even a simple memory allocation without using ``GFP_ATOMIC`` can result in a
|
||||
kernel thread being put to sleep if swapping is needed. For example, the
|
||||
Linux Kernel calls the functions of a network device interface from a
|
||||
bottom half context. Thus, if a demux kABI function is called from network
|
||||
device code, the function must not sleep.
|
||||
|
||||
|
||||
|
||||
Demux Callback API
|
||||
------------------
|
||||
|
||||
Demux Callback
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
This kernel-space API comprises the callback functions that deliver filtered
|
||||
data to the demux client. Unlike the other DVB kABIs, these functions are
|
||||
provided by the client and called from the demux code.
|
||||
|
||||
The function pointers of this abstract interface are not packed into a
|
||||
structure as in the other demux APIs, because the callback functions are
|
||||
registered and used independent of each other. As an example, it is possible
|
||||
for the API client to provide several callback functions for receiving TS
|
||||
packets and no callbacks for PES packets or sections.
|
||||
|
||||
The functions that implement the callback API need not be re-entrant: when
|
||||
a demux driver calls one of these functions, the driver is not allowed to
|
||||
call the function again before the original call returns. If a callback is
|
||||
triggered by a hardware interrupt, it is recommended to use the Linux
|
||||
bottom half mechanism or start a tasklet instead of making the callback
|
||||
function call directly from a hardware interrupt.
|
||||
|
||||
This mechanism is implemented by :c:func:`dmx_ts_cb()` and :c:func:`dmx_section_cb()`
|
||||
callbacks.
|
||||
|
||||
.. kernel-doc:: drivers/media/dvb-core/demux.h
|
||||
|
||||
Digital TV Conditional Access kABI
|
||||
----------------------------------
|
||||
|
||||
.. kernel-doc:: drivers/media/dvb-core/dvb_ca_en50221.h
|
||||
dtv-common
|
||||
dtv-frontend
|
||||
dtv-demux
|
||||
dtv-ca
|
||||
dtv-net
|
||||
|
|
82
Documentation/media/kapi/dtv-demux.rst
Normal file
82
Documentation/media/kapi/dtv-demux.rst
Normal file
|
@ -0,0 +1,82 @@
|
|||
Digital TV Demux kABI
|
||||
---------------------
|
||||
|
||||
Digital TV Demux
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
The Kernel Digital TV Demux kABI defines a driver-internal interface for
|
||||
registering low-level, hardware specific driver to a hardware independent
|
||||
demux layer. It is only of interest for Digital TV device driver writers.
|
||||
The header file for this kABI is named ``demux.h`` and located in
|
||||
``drivers/media/dvb-core``.
|
||||
|
||||
The demux kABI should be implemented for each demux in the system. It is
|
||||
used to select the TS source of a demux and to manage the demux resources.
|
||||
When the demux client allocates a resource via the demux kABI, it receives
|
||||
a pointer to the kABI of that resource.
|
||||
|
||||
Each demux receives its TS input from a DVB front-end or from memory, as
|
||||
set via this demux kABI. In a system with more than one front-end, the kABI
|
||||
can be used to select one of the DVB front-ends as a TS source for a demux,
|
||||
unless this is fixed in the HW platform.
|
||||
|
||||
The demux kABI only controls front-ends regarding to their connections with
|
||||
demuxes; the kABI used to set the other front-end parameters, such as
|
||||
tuning, are devined via the Digital TV Frontend kABI.
|
||||
|
||||
The functions that implement the abstract interface demux should be defined
|
||||
static or module private and registered to the Demux core for external
|
||||
access. It is not necessary to implement every function in the struct
|
||||
:c:type:`dmx_demux`. For example, a demux interface might support Section filtering,
|
||||
but not PES filtering. The kABI client is expected to check the value of any
|
||||
function pointer before calling the function: the value of ``NULL`` means
|
||||
that the function is not available.
|
||||
|
||||
Whenever the functions of the demux API modify shared data, the
|
||||
possibilities of lost update and race condition problems should be
|
||||
addressed, e.g. by protecting parts of code with mutexes.
|
||||
|
||||
Note that functions called from a bottom half context must not sleep.
|
||||
Even a simple memory allocation without using ``GFP_ATOMIC`` can result in a
|
||||
kernel thread being put to sleep if swapping is needed. For example, the
|
||||
Linux Kernel calls the functions of a network device interface from a
|
||||
bottom half context. Thus, if a demux kABI function is called from network
|
||||
device code, the function must not sleep.
|
||||
|
||||
Demux Callback API
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
This kernel-space API comprises the callback functions that deliver filtered
|
||||
data to the demux client. Unlike the other DVB kABIs, these functions are
|
||||
provided by the client and called from the demux code.
|
||||
|
||||
The function pointers of this abstract interface are not packed into a
|
||||
structure as in the other demux APIs, because the callback functions are
|
||||
registered and used independent of each other. As an example, it is possible
|
||||
for the API client to provide several callback functions for receiving TS
|
||||
packets and no callbacks for PES packets or sections.
|
||||
|
||||
The functions that implement the callback API need not be re-entrant: when
|
||||
a demux driver calls one of these functions, the driver is not allowed to
|
||||
call the function again before the original call returns. If a callback is
|
||||
triggered by a hardware interrupt, it is recommended to use the Linux
|
||||
bottom half mechanism or start a tasklet instead of making the callback
|
||||
function call directly from a hardware interrupt.
|
||||
|
||||
This mechanism is implemented by :c:func:`dmx_ts_cb()` and :c:func:`dmx_section_cb()`
|
||||
callbacks.
|
||||
|
||||
Digital TV Demux device registration functions and data structures
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. kernel-doc:: drivers/media/dvb-core/dmxdev.h
|
||||
|
||||
High-level Digital TV demux interface
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. kernel-doc:: drivers/media/dvb-core/dvb_demux.h
|
||||
|
||||
Driver-internal low-level hardware specific driver demux interface
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. kernel-doc:: drivers/media/dvb-core/demux.h
|
443
Documentation/media/kapi/dtv-frontend.rst
Normal file
443
Documentation/media/kapi/dtv-frontend.rst
Normal file
|
@ -0,0 +1,443 @@
|
|||
Digital TV Frontend kABI
|
||||
------------------------
|
||||
|
||||
Digital TV Frontend
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The Digital TV Frontend kABI defines a driver-internal interface for
|
||||
registering low-level, hardware specific driver to a hardware independent
|
||||
frontend layer. It is only of interest for Digital TV device driver writers.
|
||||
The header file for this API is named ``dvb_frontend.h`` and located in
|
||||
``drivers/media/dvb-core``.
|
||||
|
||||
Demodulator driver
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The demodulator driver is responsible to talk with the decoding part of the
|
||||
hardware. Such driver should implement :c:type:`dvb_frontend_ops`, with
|
||||
tells what type of digital TV standards are supported, and points to a
|
||||
series of functions that allow the DVB core to command the hardware via
|
||||
the code under ``drivers/media/dvb-core/dvb_frontend.c``.
|
||||
|
||||
A typical example of such struct in a driver ``foo`` is::
|
||||
|
||||
static struct dvb_frontend_ops foo_ops = {
|
||||
.delsys = { SYS_DVBT, SYS_DVBT2, SYS_DVBC_ANNEX_A },
|
||||
.info = {
|
||||
.name = "foo DVB-T/T2/C driver",
|
||||
.caps = FE_CAN_FEC_1_2 |
|
||||
FE_CAN_FEC_2_3 |
|
||||
FE_CAN_FEC_3_4 |
|
||||
FE_CAN_FEC_5_6 |
|
||||
FE_CAN_FEC_7_8 |
|
||||
FE_CAN_FEC_AUTO |
|
||||
FE_CAN_QPSK |
|
||||
FE_CAN_QAM_16 |
|
||||
FE_CAN_QAM_32 |
|
||||
FE_CAN_QAM_64 |
|
||||
FE_CAN_QAM_128 |
|
||||
FE_CAN_QAM_256 |
|
||||
FE_CAN_QAM_AUTO |
|
||||
FE_CAN_TRANSMISSION_MODE_AUTO |
|
||||
FE_CAN_GUARD_INTERVAL_AUTO |
|
||||
FE_CAN_HIERARCHY_AUTO |
|
||||
FE_CAN_MUTE_TS |
|
||||
FE_CAN_2G_MODULATION,
|
||||
.frequency_min = 42000000, /* Hz */
|
||||
.frequency_max = 1002000000, /* Hz */
|
||||
.symbol_rate_min = 870000,
|
||||
.symbol_rate_max = 11700000
|
||||
},
|
||||
.init = foo_init,
|
||||
.sleep = foo_sleep,
|
||||
.release = foo_release,
|
||||
.set_frontend = foo_set_frontend,
|
||||
.get_frontend = foo_get_frontend,
|
||||
.read_status = foo_get_status_and_stats,
|
||||
.tune = foo_tune,
|
||||
.i2c_gate_ctrl = foo_i2c_gate_ctrl,
|
||||
.get_frontend_algo = foo_get_algo,
|
||||
};
|
||||
|
||||
A typical example of such struct in a driver ``bar`` meant to be used on
|
||||
Satellite TV reception is::
|
||||
|
||||
static const struct dvb_frontend_ops bar_ops = {
|
||||
.delsys = { SYS_DVBS, SYS_DVBS2 },
|
||||
.info = {
|
||||
.name = "Bar DVB-S/S2 demodulator",
|
||||
.frequency_min = 500000, /* KHz */
|
||||
.frequency_max = 2500000, /* KHz */
|
||||
.frequency_stepsize = 0,
|
||||
.symbol_rate_min = 1000000,
|
||||
.symbol_rate_max = 45000000,
|
||||
.symbol_rate_tolerance = 500,
|
||||
.caps = FE_CAN_INVERSION_AUTO |
|
||||
FE_CAN_FEC_AUTO |
|
||||
FE_CAN_QPSK,
|
||||
},
|
||||
.init = bar_init,
|
||||
.sleep = bar_sleep,
|
||||
.release = bar_release,
|
||||
.set_frontend = bar_set_frontend,
|
||||
.get_frontend = bar_get_frontend,
|
||||
.read_status = bar_get_status_and_stats,
|
||||
.i2c_gate_ctrl = bar_i2c_gate_ctrl,
|
||||
.get_frontend_algo = bar_get_algo,
|
||||
.tune = bar_tune,
|
||||
|
||||
/* Satellite-specific */
|
||||
.diseqc_send_master_cmd = bar_send_diseqc_msg,
|
||||
.diseqc_send_burst = bar_send_burst,
|
||||
.set_tone = bar_set_tone,
|
||||
.set_voltage = bar_set_voltage,
|
||||
};
|
||||
|
||||
.. note::
|
||||
|
||||
#) For satellite digital TV standards (DVB-S, DVB-S2, ISDB-S), the
|
||||
frequencies are specified in kHz, while, for terrestrial and cable
|
||||
standards, they're specified in Hz. Due to that, if the same frontend
|
||||
supports both types, you'll need to have two separate
|
||||
:c:type:`dvb_frontend_ops` structures, one for each standard.
|
||||
#) The ``.i2c_gate_ctrl`` field is present only when the hardware has
|
||||
allows controlling an I2C gate (either directly of via some GPIO pin),
|
||||
in order to remove the tuner from the I2C bus after a channel is
|
||||
tuned.
|
||||
#) All new drivers should implement the
|
||||
:ref:`DVBv5 statistics <dvbv5_stats>` via ``.read_status``.
|
||||
Yet, there are a number of callbacks meant to get statistics for
|
||||
signal strength, S/N and UCB. Those are there to provide backward
|
||||
compatibility with legacy applications that don't support the DVBv5
|
||||
API. Implementing those callbacks are optional. Those callbacks may be
|
||||
removed in the future, after we have all existing drivers supporting
|
||||
DVBv5 stats.
|
||||
#) Other callbacks are required for satellite TV standards, in order to
|
||||
control LNBf and DiSEqC: ``.diseqc_send_master_cmd``,
|
||||
``.diseqc_send_burst``, ``.set_tone``, ``.set_voltage``.
|
||||
|
||||
.. |delta| unicode:: U+00394
|
||||
|
||||
The ``drivers/media/dvb-core/dvb_frontend.c`` has a kernel thread with is
|
||||
responsible for tuning the device. It supports multiple algorithms to
|
||||
detect a channel, as defined at enum :c:func:`dvbfe_algo`.
|
||||
|
||||
The algorithm to be used is obtained via ``.get_frontend_algo``. If the driver
|
||||
doesn't fill its field at struct :c:type:`dvb_frontend_ops`, it will default to
|
||||
``DVBFE_ALGO_SW``, meaning that the dvb-core will do a zigzag when tuning,
|
||||
e. g. it will try first to use the specified center frequency ``f``,
|
||||
then, it will do ``f`` + |delta|, ``f`` - |delta|, ``f`` + 2 x |delta|,
|
||||
``f`` - 2 x |delta| and so on.
|
||||
|
||||
If the hardware has internally a some sort of zigzag algorithm, you should
|
||||
define a ``.get_frontend_algo`` function that would return ``DVBFE_ALGO_HW``.
|
||||
|
||||
.. note::
|
||||
|
||||
The core frontend support also supports
|
||||
a third type (``DVBFE_ALGO_CUSTOM``), in order to allow the driver to
|
||||
define its own hardware-assisted algorithm. Very few hardware need to
|
||||
use it nowadays. Using ``DVBFE_ALGO_CUSTOM`` require to provide other
|
||||
function callbacks at struct :c:type:`dvb_frontend_ops`.
|
||||
|
||||
Attaching frontend driver to the bridge driver
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Before using the Digital TV frontend core, the bridge driver should attach
|
||||
the frontend demod, tuner and SEC devices and call
|
||||
:c:func:`dvb_register_frontend()`,
|
||||
in order to register the new frontend at the subsystem. At device
|
||||
detach/removal, the bridge driver should call
|
||||
:c:func:`dvb_unregister_frontend()` to
|
||||
remove the frontend from the core and then :c:func:`dvb_frontend_detach()`
|
||||
to free the memory allocated by the frontend drivers.
|
||||
|
||||
The drivers should also call :c:func:`dvb_frontend_suspend()` as part of
|
||||
their handler for the :c:type:`device_driver`.\ ``suspend()``, and
|
||||
:c:func:`dvb_frontend_resume()` as
|
||||
part of their handler for :c:type:`device_driver`.\ ``resume()``.
|
||||
|
||||
A few other optional functions are provided to handle some special cases.
|
||||
|
||||
.. _dvbv5_stats:
|
||||
|
||||
Digital TV Frontend statistics
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Introduction
|
||||
^^^^^^^^^^^^
|
||||
|
||||
Digital TV frontends provide a range of
|
||||
:ref:`statistics <frontend-stat-properties>` meant to help tuning the device
|
||||
and measuring the quality of service.
|
||||
|
||||
For each statistics measurement, the driver should set the type of scale used,
|
||||
or ``FE_SCALE_NOT_AVAILABLE`` if the statistics is not available on a given
|
||||
time. Drivers should also provide the number of statistics for each type.
|
||||
that's usually 1 for most video standards [#f2]_.
|
||||
|
||||
Drivers should initialize each statistic counters with length and
|
||||
scale at its init code. For example, if the frontend provides signal
|
||||
strength, it should have, on its init code::
|
||||
|
||||
struct dtv_frontend_properties *c = &state->fe.dtv_property_cache;
|
||||
|
||||
c->strength.len = 1;
|
||||
c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
|
||||
|
||||
And, when the statistics got updated, set the scale::
|
||||
|
||||
c->strength.stat[0].scale = FE_SCALE_DECIBEL;
|
||||
c->strength.stat[0].uvalue = strength;
|
||||
|
||||
.. [#f2] For ISDB-T, it may provide both a global statistics and a per-layer
|
||||
set of statistics. On such cases, len should be equal to 4. The first
|
||||
value corresponds to the global stat; the other ones to each layer, e. g.:
|
||||
|
||||
- c->cnr.stat[0] for global S/N carrier ratio,
|
||||
- c->cnr.stat[1] for Layer A S/N carrier ratio,
|
||||
- c->cnr.stat[2] for layer B S/N carrier ratio,
|
||||
- c->cnr.stat[3] for layer C S/N carrier ratio.
|
||||
|
||||
.. note:: Please prefer to use ``FE_SCALE_DECIBEL`` instead of
|
||||
``FE_SCALE_RELATIVE`` for signal strength and CNR measurements.
|
||||
|
||||
Groups of statistics
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
There are several groups of statistics currently supported:
|
||||
|
||||
Signal strength (:ref:`DTV-STAT-SIGNAL-STRENGTH`)
|
||||
- Measures the signal strength level at the analog part of the tuner or
|
||||
demod.
|
||||
|
||||
- Typically obtained from the gain applied to the tuner and/or frontend
|
||||
in order to detect the carrier. When no carrier is detected, the gain is
|
||||
at the maximum value (so, strength is on its minimal).
|
||||
|
||||
- As the gain is visible through the set of registers that adjust the gain,
|
||||
typically, this statistics is always available [#f3]_.
|
||||
|
||||
- Drivers should try to make it available all the times, as this statistics
|
||||
can be used when adjusting an antenna position and to check for troubles
|
||||
at the cabling.
|
||||
|
||||
.. [#f3] On a few devices, the gain keeps floating if no carrier.
|
||||
On such devices, strength report should check first if carrier is
|
||||
detected at the tuner (``FE_HAS_CARRIER``, see :c:type:`fe_status`),
|
||||
and otherwise return the lowest possible value.
|
||||
|
||||
Carrier Signal to Noise ratio (:ref:`DTV-STAT-CNR`)
|
||||
- Signal to Noise ratio for the main carrier.
|
||||
|
||||
- Signal to Noise measurement depends on the device. On some hardware, is
|
||||
available when the main carrier is detected. On those hardware, CNR
|
||||
measurement usually comes from the tuner (e. g. after ``FE_HAS_CARRIER``,
|
||||
see :c:type:`fe_status`).
|
||||
|
||||
On other devices, it requires inner FEC decoding,
|
||||
as the frontend measures it indirectly from other parameters (e. g. after
|
||||
``FE_HAS_VITERBI``, see :c:type:`fe_status`).
|
||||
|
||||
Having it available after inner FEC is more common.
|
||||
|
||||
Bit counts post-FEC (:ref:`DTV-STAT-POST-ERROR-BIT-COUNT` and :ref:`DTV-STAT-POST-TOTAL-BIT-COUNT`)
|
||||
- Those counters measure the number of bits and bit errors errors after
|
||||
the forward error correction (FEC) on the inner coding block
|
||||
(after Viterbi, LDPC or other inner code).
|
||||
|
||||
- Due to its nature, those statistics depend on full coding lock
|
||||
(e. g. after ``FE_HAS_SYNC`` or after ``FE_HAS_LOCK``,
|
||||
see :c:type:`fe_status`).
|
||||
|
||||
Bit counts pre-FEC (:ref:`DTV-STAT-PRE-ERROR-BIT-COUNT` and :ref:`DTV-STAT-PRE-TOTAL-BIT-COUNT`)
|
||||
- Those counters measure the number of bits and bit errors errors before
|
||||
the forward error correction (FEC) on the inner coding block
|
||||
(before Viterbi, LDPC or other inner code).
|
||||
|
||||
- Not all frontends provide this kind of statistics.
|
||||
|
||||
- Due to its nature, those statistics depend on inner coding lock (e. g.
|
||||
after ``FE_HAS_VITERBI``, see :c:type:`fe_status`).
|
||||
|
||||
Block counts (:ref:`DTV-STAT-ERROR-BLOCK-COUNT` and :ref:`DTV-STAT-TOTAL-BLOCK-COUNT`)
|
||||
- Those counters measure the number of blocks and block errors errors after
|
||||
the forward error correction (FEC) on the inner coding block
|
||||
(before Viterbi, LDPC or other inner code).
|
||||
|
||||
- Due to its nature, those statistics depend on full coding lock
|
||||
(e. g. after ``FE_HAS_SYNC`` or after
|
||||
``FE_HAS_LOCK``, see :c:type:`fe_status`).
|
||||
|
||||
.. note:: All counters should be monotonically increased as they're
|
||||
collected from the hardware.
|
||||
|
||||
A typical example of the logic that handle status and statistics is::
|
||||
|
||||
static int foo_get_status_and_stats(struct dvb_frontend *fe)
|
||||
{
|
||||
struct foo_state *state = fe->demodulator_priv;
|
||||
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
|
||||
|
||||
int rc;
|
||||
enum fe_status *status;
|
||||
|
||||
/* Both status and strength are always available */
|
||||
rc = foo_read_status(fe, &status);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
rc = foo_read_strength(fe);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
/* Check if CNR is available */
|
||||
if (!(fe->status & FE_HAS_CARRIER))
|
||||
return 0;
|
||||
|
||||
rc = foo_read_cnr(fe);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
/* Check if pre-BER stats are available */
|
||||
if (!(fe->status & FE_HAS_VITERBI))
|
||||
return 0;
|
||||
|
||||
rc = foo_get_pre_ber(fe);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
/* Check if post-BER stats are available */
|
||||
if (!(fe->status & FE_HAS_SYNC))
|
||||
return 0;
|
||||
|
||||
rc = foo_get_post_ber(fe);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
}
|
||||
|
||||
static const struct dvb_frontend_ops ops = {
|
||||
/* ... */
|
||||
.read_status = foo_get_status_and_stats,
|
||||
};
|
||||
|
||||
Statistics collect
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
On almost all frontend hardware, the bit and byte counts are stored by
|
||||
the hardware after a certain amount of time or after the total bit/block
|
||||
counter reaches a certain value (usually programable), for example, on
|
||||
every 1000 ms or after receiving 1,000,000 bits.
|
||||
|
||||
So, if you read the registers too soon, you'll end by reading the same
|
||||
value as in the previous reading, causing the monotonic value to be
|
||||
incremented too often.
|
||||
|
||||
Drivers should take the responsibility to avoid too often reads. That
|
||||
can be done using two approaches:
|
||||
|
||||
if the driver have a bit that indicates when a collected data is ready
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
Driver should check such bit before making the statistics available.
|
||||
|
||||
An example of such behavior can be found at this code snippet (adapted
|
||||
from mb86a20s driver's logic)::
|
||||
|
||||
static int foo_get_pre_ber(struct dvb_frontend *fe)
|
||||
{
|
||||
struct foo_state *state = fe->demodulator_priv;
|
||||
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
|
||||
int rc, bit_error;
|
||||
|
||||
/* Check if the BER measures are already available */
|
||||
rc = foo_read_u8(state, 0x54);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
if (!rc)
|
||||
return 0;
|
||||
|
||||
/* Read Bit Error Count */
|
||||
bit_error = foo_read_u32(state, 0x55);
|
||||
if (bit_error < 0)
|
||||
return bit_error;
|
||||
|
||||
/* Read Total Bit Count */
|
||||
rc = foo_read_u32(state, 0x51);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
|
||||
c->pre_bit_error.stat[0].scale = FE_SCALE_COUNTER;
|
||||
c->pre_bit_error.stat[0].uvalue += bit_error;
|
||||
c->pre_bit_count.stat[0].scale = FE_SCALE_COUNTER;
|
||||
c->pre_bit_count.stat[0].uvalue += rc;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
If the driver doesn't provide a statistics available check bit
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
A few devices, however, may not provide a way to check if the stats are
|
||||
available (or the way to check it is unknown). They may not even provide
|
||||
a way to directly read the total number of bits or blocks.
|
||||
|
||||
On those devices, the driver need to ensure that it won't be reading from
|
||||
the register too often and/or estimate the total number of bits/blocks.
|
||||
|
||||
On such drivers, a typical routine to get statistics would be like
|
||||
(adapted from dib8000 driver's logic)::
|
||||
|
||||
struct foo_state {
|
||||
/* ... */
|
||||
|
||||
unsigned long per_jiffies_stats;
|
||||
}
|
||||
|
||||
static int foo_get_pre_ber(struct dvb_frontend *fe)
|
||||
{
|
||||
struct foo_state *state = fe->demodulator_priv;
|
||||
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
|
||||
int rc, bit_error;
|
||||
u64 bits;
|
||||
|
||||
/* Check if time for stats was elapsed */
|
||||
if (!time_after(jiffies, state->per_jiffies_stats))
|
||||
return 0;
|
||||
|
||||
/* Next stat should be collected in 1000 ms */
|
||||
state->per_jiffies_stats = jiffies + msecs_to_jiffies(1000);
|
||||
|
||||
/* Read Bit Error Count */
|
||||
bit_error = foo_read_u32(state, 0x55);
|
||||
if (bit_error < 0)
|
||||
return bit_error;
|
||||
|
||||
/*
|
||||
* On this particular frontend, there's no register that
|
||||
* would provide the number of bits per 1000ms sample. So,
|
||||
* some function would calculate it based on DTV properties
|
||||
*/
|
||||
bits = get_number_of_bits_per_1000ms(fe);
|
||||
|
||||
c->pre_bit_error.stat[0].scale = FE_SCALE_COUNTER;
|
||||
c->pre_bit_error.stat[0].uvalue += bit_error;
|
||||
c->pre_bit_count.stat[0].scale = FE_SCALE_COUNTER;
|
||||
c->pre_bit_count.stat[0].uvalue += bits;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Please notice that, on both cases, we're getting the statistics using the
|
||||
:c:type:`dvb_frontend_ops` ``.read_status`` callback. The rationale is that
|
||||
the frontend core will automatically call this function periodically
|
||||
(usually, 3 times per second, when the frontend is locked).
|
||||
|
||||
That warrants that we won't miss to collect a counter and increment the
|
||||
monotonic stats at the right time.
|
||||
|
||||
Digital TV Frontend functions and types
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. kernel-doc:: drivers/media/dvb-core/dvb_frontend.h
|
4
Documentation/media/kapi/dtv-net.rst
Normal file
4
Documentation/media/kapi/dtv-net.rst
Normal file
|
@ -0,0 +1,4 @@
|
|||
Digital TV Network kABI
|
||||
-----------------------
|
||||
|
||||
.. kernel-doc:: drivers/media/dvb-core/dvb_net.h
|
3
Documentation/media/kapi/v4l2-async.rst
Normal file
3
Documentation/media/kapi/v4l2-async.rst
Normal file
|
@ -0,0 +1,3 @@
|
|||
V4L2 async kAPI
|
||||
^^^^^^^^^^^^^^^
|
||||
.. kernel-doc:: include/media/v4l2-async.h
|
|
@ -19,6 +19,7 @@ Video4Linux devices
|
|||
v4l2-mc
|
||||
v4l2-mediabus
|
||||
v4l2-mem2mem
|
||||
v4l2-async
|
||||
v4l2-fwnode
|
||||
v4l2-rect
|
||||
v4l2-tuner
|
||||
|
|
|
@ -161,6 +161,24 @@ it is guaranteed that the state did change in between the two events.
|
|||
- Generated if the CEC pin goes from a low voltage to a high voltage.
|
||||
Only applies to adapters that have the ``CEC_CAP_MONITOR_PIN``
|
||||
capability set.
|
||||
* .. _`CEC-EVENT-PIN-HPD-LOW`:
|
||||
|
||||
- ``CEC_EVENT_PIN_HPD_LOW``
|
||||
- 5
|
||||
- Generated if the HPD pin goes from a high voltage to a low voltage.
|
||||
Only applies to adapters that have the ``CEC_CAP_MONITOR_PIN``
|
||||
capability set. When open() is called, the HPD pin can be read and
|
||||
if the HPD is low, then an initial event will be generated for that
|
||||
filehandle.
|
||||
* .. _`CEC-EVENT-PIN-HPD-HIGH`:
|
||||
|
||||
- ``CEC_EVENT_PIN_HPD_HIGH``
|
||||
- 6
|
||||
- Generated if the HPD pin goes from a low voltage to a high voltage.
|
||||
Only applies to adapters that have the ``CEC_CAP_MONITOR_PIN``
|
||||
capability set. When open() is called, the HPD pin can be read and
|
||||
if the HPD is high, then an initial event will be generated for that
|
||||
filehandle.
|
||||
|
||||
|
||||
.. tabularcolumns:: |p{6.0cm}|p{0.6cm}|p{10.9cm}|
|
||||
|
@ -172,9 +190,9 @@ it is guaranteed that the state did change in between the two events.
|
|||
:stub-columns: 0
|
||||
:widths: 3 1 8
|
||||
|
||||
* .. _`CEC-EVENT-FL-INITIAL-VALUE`:
|
||||
* .. _`CEC-EVENT-FL-INITIAL-STATE`:
|
||||
|
||||
- ``CEC_EVENT_FL_INITIAL_VALUE``
|
||||
- ``CEC_EVENT_FL_INITIAL_STATE``
|
||||
- 1
|
||||
- Set for the initial events that are generated when the device is
|
||||
opened. See the table above for which events do this. This allows
|
||||
|
|
|
@ -131,7 +131,7 @@ View On' messages from initiator 0xf ('Unregistered') to destination 0 ('TV').
|
|||
- ``tx_status``
|
||||
- The status bits of the transmitted message. See
|
||||
:ref:`cec-tx-status` for the possible status values. It is 0 if
|
||||
this messages was received, not transmitted.
|
||||
this message was received, not transmitted.
|
||||
* - __u8
|
||||
- ``msg[16]``
|
||||
- The message payload. For :ref:`ioctl CEC_TRANSMIT <CEC_TRANSMIT>` this is filled in by the
|
||||
|
@ -168,7 +168,7 @@ View On' messages from initiator 0xf ('Unregistered') to destination 0 ('TV').
|
|||
- ``tx_status``
|
||||
- The status bits of the transmitted message. See
|
||||
:ref:`cec-tx-status` for the possible status values. It is 0 if
|
||||
this messages was received, not transmitted.
|
||||
this message was received, not transmitted.
|
||||
* - __u8
|
||||
- ``tx_arb_lost_cnt``
|
||||
- A counter of the number of transmit attempts that resulted in the
|
||||
|
@ -256,9 +256,9 @@ View On' messages from initiator 0xf ('Unregistered') to destination 0 ('TV').
|
|||
- ``CEC_TX_STATUS_ERROR``
|
||||
- 0x10
|
||||
- Some error occurred. This is used for any errors that do not fit
|
||||
the previous two, either because the hardware could not tell which
|
||||
error occurred, or because the hardware tested for other
|
||||
conditions besides those two.
|
||||
``CEC_TX_STATUS_ARB_LOST`` or ``CEC_TX_STATUS_LOW_DRIVE``, either because
|
||||
the hardware could not tell which error occurred, or because the hardware
|
||||
tested for other conditions besides those two.
|
||||
* .. _`CEC-TX-STATUS-MAX-RETRIES`:
|
||||
|
||||
- ``CEC_TX_STATUS_MAX_RETRIES``
|
||||
|
|
|
@ -6,377 +6,11 @@
|
|||
Examples
|
||||
********
|
||||
|
||||
In this section we would like to present some examples for using the Digital
|
||||
TV API.
|
||||
In the past, we used to have a set of examples here. However, those
|
||||
examples got out of date and doesn't even compile nowadays.
|
||||
|
||||
.. note::
|
||||
Also, nowadays, the best is to use the libdvbv5 DVB API nowadays,
|
||||
with is fully documented.
|
||||
|
||||
This section is out of date, and the code below won't even
|
||||
compile. Please refer to the
|
||||
`libdvbv5 <https://linuxtv.org/docs/libdvbv5/index.html>`__ for
|
||||
updated/recommended examples.
|
||||
|
||||
|
||||
.. _tuning:
|
||||
|
||||
Example: Tuning
|
||||
===============
|
||||
|
||||
We will start with a generic tuning subroutine that uses the frontend
|
||||
and SEC, as well as the demux devices. The example is given for QPSK
|
||||
tuners, but can easily be adjusted for QAM.
|
||||
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <linux/dvb/dmx.h>
|
||||
#include <linux/dvb/frontend.h>
|
||||
#include <linux/dvb/sec.h>
|
||||
#include <sys/poll.h>
|
||||
|
||||
#define DMX "/dev/dvb/adapter0/demux1"
|
||||
#define FRONT "/dev/dvb/adapter0/frontend1"
|
||||
#define SEC "/dev/dvb/adapter0/sec1"
|
||||
|
||||
/* routine for checking if we have a signal and other status information*/
|
||||
int FEReadStatus(int fd, fe_status_t *stat)
|
||||
{
|
||||
int ans;
|
||||
|
||||
if ( (ans = ioctl(fd,FE_READ_STATUS,stat) < 0)){
|
||||
perror("FE READ STATUS: ");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (*stat & FE_HAS_POWER)
|
||||
printf("FE HAS POWER\\n");
|
||||
|
||||
if (*stat & FE_HAS_SIGNAL)
|
||||
printf("FE HAS SIGNAL\\n");
|
||||
|
||||
if (*stat & FE_SPECTRUM_INV)
|
||||
printf("SPEKTRUM INV\\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* tune qpsk */
|
||||
/* freq: frequency of transponder */
|
||||
/* vpid, apid, tpid: PIDs of video, audio and teletext TS packets */
|
||||
/* diseqc: DiSEqC address of the used LNB */
|
||||
/* pol: Polarisation */
|
||||
/* srate: Symbol Rate */
|
||||
/* fec. FEC */
|
||||
/* lnb_lof1: local frequency of lower LNB band */
|
||||
/* lnb_lof2: local frequency of upper LNB band */
|
||||
/* lnb_slof: switch frequency of LNB */
|
||||
|
||||
int set_qpsk_channel(int freq, int vpid, int apid, int tpid,
|
||||
int diseqc, int pol, int srate, int fec, int lnb_lof1,
|
||||
int lnb_lof2, int lnb_slof)
|
||||
{
|
||||
struct secCommand scmd;
|
||||
struct secCmdSequence scmds;
|
||||
struct dmx_pes_filter_params pesFilterParams;
|
||||
FrontendParameters frp;
|
||||
struct pollfd pfd[1];
|
||||
FrontendEvent event;
|
||||
int demux1, demux2, demux3, front;
|
||||
|
||||
frequency = (uint32_t) freq;
|
||||
symbolrate = (uint32_t) srate;
|
||||
|
||||
if((front = open(FRONT,O_RDWR)) < 0){
|
||||
perror("FRONTEND DEVICE: ");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if((sec = open(SEC,O_RDWR)) < 0){
|
||||
perror("SEC DEVICE: ");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (demux1 < 0){
|
||||
if ((demux1=open(DMX, O_RDWR|O_NONBLOCK))
|
||||
< 0){
|
||||
perror("DEMUX DEVICE: ");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (demux2 < 0){
|
||||
if ((demux2=open(DMX, O_RDWR|O_NONBLOCK))
|
||||
< 0){
|
||||
perror("DEMUX DEVICE: ");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (demux3 < 0){
|
||||
if ((demux3=open(DMX, O_RDWR|O_NONBLOCK))
|
||||
< 0){
|
||||
perror("DEMUX DEVICE: ");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (freq < lnb_slof) {
|
||||
frp.Frequency = (freq - lnb_lof1);
|
||||
scmds.continuousTone = SEC_TONE_OFF;
|
||||
} else {
|
||||
frp.Frequency = (freq - lnb_lof2);
|
||||
scmds.continuousTone = SEC_TONE_ON;
|
||||
}
|
||||
frp.Inversion = INVERSION_AUTO;
|
||||
if (pol) scmds.voltage = SEC_VOLTAGE_18;
|
||||
else scmds.voltage = SEC_VOLTAGE_13;
|
||||
|
||||
scmd.type=0;
|
||||
scmd.u.diseqc.addr=0x10;
|
||||
scmd.u.diseqc.cmd=0x38;
|
||||
scmd.u.diseqc.numParams=1;
|
||||
scmd.u.diseqc.params[0] = 0xF0 | ((diseqc * 4) & 0x0F) |
|
||||
(scmds.continuousTone == SEC_TONE_ON ? 1 : 0) |
|
||||
(scmds.voltage==SEC_VOLTAGE_18 ? 2 : 0);
|
||||
|
||||
scmds.miniCommand=SEC_MINI_NONE;
|
||||
scmds.numCommands=1;
|
||||
scmds.commands=&scmd;
|
||||
if (ioctl(sec, SEC_SEND_SEQUENCE, &scmds) < 0){
|
||||
perror("SEC SEND: ");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ioctl(sec, SEC_SEND_SEQUENCE, &scmds) < 0){
|
||||
perror("SEC SEND: ");
|
||||
return -1;
|
||||
}
|
||||
|
||||
frp.u.qpsk.SymbolRate = srate;
|
||||
frp.u.qpsk.FEC_inner = fec;
|
||||
|
||||
if (ioctl(front, FE_SET_FRONTEND, &frp) < 0){
|
||||
perror("QPSK TUNE: ");
|
||||
return -1;
|
||||
}
|
||||
|
||||
pfd[0].fd = front;
|
||||
pfd[0].events = POLLIN;
|
||||
|
||||
if (poll(pfd,1,3000)){
|
||||
if (pfd[0].revents & POLLIN){
|
||||
printf("Getting QPSK event\\n");
|
||||
if ( ioctl(front, FE_GET_EVENT, &event)
|
||||
|
||||
== -EOVERFLOW){
|
||||
perror("qpsk get event");
|
||||
return -1;
|
||||
}
|
||||
printf("Received ");
|
||||
switch(event.type){
|
||||
case FE_UNEXPECTED_EV:
|
||||
printf("unexpected event\\n");
|
||||
return -1;
|
||||
case FE_FAILURE_EV:
|
||||
printf("failure event\\n");
|
||||
return -1;
|
||||
|
||||
case FE_COMPLETION_EV:
|
||||
printf("completion event\\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pesFilterParams.pid = vpid;
|
||||
pesFilterParams.input = DMX_IN_FRONTEND;
|
||||
pesFilterParams.output = DMX_OUT_DECODER;
|
||||
pesFilterParams.pes_type = DMX_PES_VIDEO;
|
||||
pesFilterParams.flags = DMX_IMMEDIATE_START;
|
||||
if (ioctl(demux1, DMX_SET_PES_FILTER, &pesFilterParams) < 0){
|
||||
perror("set_vpid");
|
||||
return -1;
|
||||
}
|
||||
|
||||
pesFilterParams.pid = apid;
|
||||
pesFilterParams.input = DMX_IN_FRONTEND;
|
||||
pesFilterParams.output = DMX_OUT_DECODER;
|
||||
pesFilterParams.pes_type = DMX_PES_AUDIO;
|
||||
pesFilterParams.flags = DMX_IMMEDIATE_START;
|
||||
if (ioctl(demux2, DMX_SET_PES_FILTER, &pesFilterParams) < 0){
|
||||
perror("set_apid");
|
||||
return -1;
|
||||
}
|
||||
|
||||
pesFilterParams.pid = tpid;
|
||||
pesFilterParams.input = DMX_IN_FRONTEND;
|
||||
pesFilterParams.output = DMX_OUT_DECODER;
|
||||
pesFilterParams.pes_type = DMX_PES_TELETEXT;
|
||||
pesFilterParams.flags = DMX_IMMEDIATE_START;
|
||||
if (ioctl(demux3, DMX_SET_PES_FILTER, &pesFilterParams) < 0){
|
||||
perror("set_tpid");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return has_signal(fds);
|
||||
}
|
||||
|
||||
The program assumes that you are using a universal LNB and a standard
|
||||
DiSEqC switch with up to 4 addresses. Of course, you could build in some
|
||||
more checking if tuning was successful and maybe try to repeat the
|
||||
tuning process. Depending on the external hardware, i.e. LNB and DiSEqC
|
||||
switch, and weather conditions this may be necessary.
|
||||
|
||||
|
||||
.. _the_dvr_device:
|
||||
|
||||
Example: The DVR device
|
||||
========================
|
||||
|
||||
The following program code shows how to use the DVR device for
|
||||
recording.
|
||||
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <linux/dvb/dmx.h>
|
||||
#include <linux/dvb/video.h>
|
||||
#include <sys/poll.h>
|
||||
#define DVR "/dev/dvb/adapter0/dvr1"
|
||||
#define AUDIO "/dev/dvb/adapter0/audio1"
|
||||
#define VIDEO "/dev/dvb/adapter0/video1"
|
||||
|
||||
#define BUFFY (188*20)
|
||||
#define MAX_LENGTH (1024*1024*5) /* record 5MB */
|
||||
|
||||
|
||||
/* switch the demuxes to recording, assuming the transponder is tuned */
|
||||
|
||||
/* demux1, demux2: file descriptor of video and audio filters */
|
||||
/* vpid, apid: PIDs of video and audio channels */
|
||||
|
||||
int switch_to_record(int demux1, int demux2, uint16_t vpid, uint16_t apid)
|
||||
{
|
||||
struct dmx_pes_filter_params pesFilterParams;
|
||||
|
||||
if (demux1 < 0){
|
||||
if ((demux1=open(DMX, O_RDWR|O_NONBLOCK))
|
||||
< 0){
|
||||
perror("DEMUX DEVICE: ");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (demux2 < 0){
|
||||
if ((demux2=open(DMX, O_RDWR|O_NONBLOCK))
|
||||
< 0){
|
||||
perror("DEMUX DEVICE: ");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
pesFilterParams.pid = vpid;
|
||||
pesFilterParams.input = DMX_IN_FRONTEND;
|
||||
pesFilterParams.output = DMX_OUT_TS_TAP;
|
||||
pesFilterParams.pes_type = DMX_PES_VIDEO;
|
||||
pesFilterParams.flags = DMX_IMMEDIATE_START;
|
||||
if (ioctl(demux1, DMX_SET_PES_FILTER, &pesFilterParams) < 0){
|
||||
perror("DEMUX DEVICE");
|
||||
return -1;
|
||||
}
|
||||
pesFilterParams.pid = apid;
|
||||
pesFilterParams.input = DMX_IN_FRONTEND;
|
||||
pesFilterParams.output = DMX_OUT_TS_TAP;
|
||||
pesFilterParams.pes_type = DMX_PES_AUDIO;
|
||||
pesFilterParams.flags = DMX_IMMEDIATE_START;
|
||||
if (ioctl(demux2, DMX_SET_PES_FILTER, &pesFilterParams) < 0){
|
||||
perror("DEMUX DEVICE");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* start recording MAX_LENGTH , assuming the transponder is tuned */
|
||||
|
||||
/* demux1, demux2: file descriptor of video and audio filters */
|
||||
/* vpid, apid: PIDs of video and audio channels */
|
||||
int record_dvr(int demux1, int demux2, uint16_t vpid, uint16_t apid)
|
||||
{
|
||||
int i;
|
||||
int len;
|
||||
int written;
|
||||
uint8_t buf[BUFFY];
|
||||
uint64_t length;
|
||||
struct pollfd pfd[1];
|
||||
int dvr, dvr_out;
|
||||
|
||||
/* open dvr device */
|
||||
if ((dvr = open(DVR, O_RDONLY|O_NONBLOCK)) < 0){
|
||||
perror("DVR DEVICE");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* switch video and audio demuxes to dvr */
|
||||
printf ("Switching dvr on\\n");
|
||||
i = switch_to_record(demux1, demux2, vpid, apid);
|
||||
printf("finished: ");
|
||||
|
||||
printf("Recording %2.0f MB of test file in TS format\\n",
|
||||
MAX_LENGTH/(1024.0*1024.0));
|
||||
length = 0;
|
||||
|
||||
/* open output file */
|
||||
if ((dvr_out = open(DVR_FILE,O_WRONLY|O_CREAT
|
||||
|O_TRUNC, S_IRUSR|S_IWUSR
|
||||
|S_IRGRP|S_IWGRP|S_IROTH|
|
||||
S_IWOTH)) < 0){
|
||||
perror("Can't open file for dvr test");
|
||||
return -1;
|
||||
}
|
||||
|
||||
pfd[0].fd = dvr;
|
||||
pfd[0].events = POLLIN;
|
||||
|
||||
/* poll for dvr data and write to file */
|
||||
while (length < MAX_LENGTH ) {
|
||||
if (poll(pfd,1,1)){
|
||||
if (pfd[0].revents & POLLIN){
|
||||
len = read(dvr, buf, BUFFY);
|
||||
if (len < 0){
|
||||
perror("recording");
|
||||
return -1;
|
||||
}
|
||||
if (len > 0){
|
||||
written = 0;
|
||||
while (written < len)
|
||||
written +=
|
||||
write (dvr_out,
|
||||
buf, len);
|
||||
length += len;
|
||||
printf("written %2.0f MB\\r",
|
||||
length/1024./1024.);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
Please refer to the `libdvbv5 <https://linuxtv.org/docs/libdvbv5/index.html>`__
|
||||
for updated/recommended examples.
|
||||
|
|
|
@ -48,8 +48,11 @@ depends on the delivery system and on the device:
|
|||
|
||||
- This call requires read/write access to the device.
|
||||
|
||||
- At return, the values are updated to reflect the actual parameters
|
||||
used.
|
||||
.. note::
|
||||
|
||||
At return, the values aren't updated to reflect the actual
|
||||
parameters used. If the actual parameters are needed, an explicit
|
||||
call to ``FE_GET_PROPERTY`` is needed.
|
||||
|
||||
- ``FE_GET_PROPERTY:``
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
.. -*- coding: utf-8; mode: rst -*-
|
||||
|
||||
.. _dmx_types:
|
||||
.. _net_types:
|
||||
|
||||
**************
|
||||
Net Data Types
|
||||
|
|
31
MAINTAINERS
31
MAINTAINERS
|
@ -1956,6 +1956,14 @@ M: Lennert Buytenhek <kernel@wantstofly.org>
|
|||
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
|
||||
S: Maintained
|
||||
|
||||
ARM/TEGRA HDMI CEC SUBSYSTEM SUPPORT
|
||||
M: Hans Verkuil <hans.verkuil@cisco.com>
|
||||
L: linux-tegra@vger.kernel.org
|
||||
L: linux-media@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/media/platform/tegra-cec/
|
||||
F: Documentation/devicetree/bindings/media/tegra-cec.txt
|
||||
|
||||
ARM/TETON BGA MACHINE SUPPORT
|
||||
M: "Mark F. Brown" <mark.brown314@gmail.com>
|
||||
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
|
||||
|
@ -3264,6 +3272,15 @@ F: include/uapi/linux/cec.h
|
|||
F: include/uapi/linux/cec-funcs.h
|
||||
F: Documentation/devicetree/bindings/media/cec.txt
|
||||
|
||||
CEC GPIO DRIVER
|
||||
M: Hans Verkuil <hans.verkuil@cisco.com>
|
||||
L: linux-media@vger.kernel.org
|
||||
T: git git://linuxtv.org/media_tree.git
|
||||
W: http://linuxtv.org
|
||||
S: Supported
|
||||
F: drivers/media/platform/cec-gpio/
|
||||
F: Documentation/devicetree/bindings/media/cec-gpio.txt
|
||||
|
||||
CELL BROADBAND ENGINE ARCHITECTURE
|
||||
M: Arnd Bergmann <arnd@arndb.de>
|
||||
L: linuxppc-dev@lists.ozlabs.org
|
||||
|
@ -11572,6 +11589,13 @@ F: drivers/hid/hid-roccat*
|
|||
F: include/linux/hid-roccat*
|
||||
F: Documentation/ABI/*/sysfs-driver-hid-roccat*
|
||||
|
||||
ROCKCHIP RASTER 2D GRAPHIC ACCELERATION UNIT DRIVER
|
||||
M: Jacob chen <jacob2.chen@rock-chips.com>
|
||||
L: linux-media@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/media/platform/rockchip/rga/
|
||||
F: Documentation/devicetree/bindings/media/rockchip-rga.txt
|
||||
|
||||
ROCKER DRIVER
|
||||
M: Jiri Pirko <jiri@resnulli.us>
|
||||
L: netdev@vger.kernel.org
|
||||
|
@ -12721,6 +12745,13 @@ L: stable@vger.kernel.org
|
|||
S: Supported
|
||||
F: Documentation/process/stable-kernel-rules.rst
|
||||
|
||||
STAGING - ATOMISP DRIVER
|
||||
M: Alan Cox <alan@linux.intel.com>
|
||||
M: Sakari Ailus <sakari.ailus@linux.intel.com>
|
||||
L: linux-media@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/staging/media/atomisp/
|
||||
|
||||
STAGING - COMEDI
|
||||
M: Ian Abbott <abbotti@mev.co.uk>
|
||||
M: H Hartley Sweeten <hsweeten@visionengravers.com>
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
clocks = <&isp 0>;
|
||||
clock-frequency = <9600000>;
|
||||
nokia,nvm-size = <(16 * 64)>;
|
||||
flash-leds = <&as3645a_flash &as3645a_indicator>;
|
||||
port {
|
||||
smia_1_1: endpoint {
|
||||
link-frequencies = /bits/ 64 <199200000 210000000 499200000>;
|
||||
|
|
|
@ -271,14 +271,14 @@
|
|||
#size-cells = <0>;
|
||||
reg = <0x30>;
|
||||
compatible = "ams,as3645a";
|
||||
flash@0 {
|
||||
as3645a_flash: flash@0 {
|
||||
reg = <0x0>;
|
||||
flash-timeout-us = <150000>;
|
||||
flash-max-microamp = <320000>;
|
||||
led-max-microamp = <60000>;
|
||||
ams,input-max-microamp = <1750000>;
|
||||
};
|
||||
indicator@1 {
|
||||
as3645a_indicator: indicator@1 {
|
||||
reg = <0x1>;
|
||||
led-max-microamp = <10000>;
|
||||
};
|
||||
|
|
|
@ -60,6 +60,7 @@
|
|||
clocks = <&isp 0>;
|
||||
clock-frequency = <9600000>;
|
||||
nokia,nvm-size = <(16 * 64)>;
|
||||
flash-leds = <&as3645a_flash &as3645a_indicator>;
|
||||
port {
|
||||
smia_1_1: endpoint {
|
||||
link-frequencies = /bits/ 64 <210000000 333600000 398400000>;
|
||||
|
|
|
@ -86,7 +86,7 @@ void cec_queue_event_fh(struct cec_fh *fh,
|
|||
const struct cec_event *new_ev, u64 ts)
|
||||
{
|
||||
static const u8 max_events[CEC_NUM_EVENTS] = {
|
||||
1, 1, 64, 64,
|
||||
1, 1, 64, 64, 8, 8,
|
||||
};
|
||||
struct cec_event_entry *entry;
|
||||
unsigned int ev_idx = new_ev->event - 1;
|
||||
|
@ -170,6 +170,22 @@ void cec_queue_pin_cec_event(struct cec_adapter *adap, bool is_high, ktime_t ts)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(cec_queue_pin_cec_event);
|
||||
|
||||
/* Notify userspace that the HPD pin changed state at the given time. */
|
||||
void cec_queue_pin_hpd_event(struct cec_adapter *adap, bool is_high, ktime_t ts)
|
||||
{
|
||||
struct cec_event ev = {
|
||||
.event = is_high ? CEC_EVENT_PIN_HPD_HIGH :
|
||||
CEC_EVENT_PIN_HPD_LOW,
|
||||
};
|
||||
struct cec_fh *fh;
|
||||
|
||||
mutex_lock(&adap->devnode.lock);
|
||||
list_for_each_entry(fh, &adap->devnode.fhs, list)
|
||||
cec_queue_event_fh(fh, &ev, ktime_to_ns(ts));
|
||||
mutex_unlock(&adap->devnode.lock);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cec_queue_pin_hpd_event);
|
||||
|
||||
/*
|
||||
* Queue a new message for this filehandle.
|
||||
*
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
|
||||
#include <media/cec-pin.h>
|
||||
#include "cec-priv.h"
|
||||
#include "cec-pin-priv.h"
|
||||
|
||||
static inline struct cec_devnode *cec_devnode_data(struct file *filp)
|
||||
{
|
||||
|
@ -529,7 +530,7 @@ static int cec_open(struct inode *inode, struct file *filp)
|
|||
* Initial events that are automatically sent when the cec device is
|
||||
* opened.
|
||||
*/
|
||||
struct cec_event ev_state = {
|
||||
struct cec_event ev = {
|
||||
.event = CEC_EVENT_STATE_CHANGE,
|
||||
.flags = CEC_EVENT_FL_INITIAL_STATE,
|
||||
};
|
||||
|
@ -569,9 +570,19 @@ static int cec_open(struct inode *inode, struct file *filp)
|
|||
filp->private_data = fh;
|
||||
|
||||
/* Queue up initial state events */
|
||||
ev_state.state_change.phys_addr = adap->phys_addr;
|
||||
ev_state.state_change.log_addr_mask = adap->log_addrs.log_addr_mask;
|
||||
cec_queue_event_fh(fh, &ev_state, 0);
|
||||
ev.state_change.phys_addr = adap->phys_addr;
|
||||
ev.state_change.log_addr_mask = adap->log_addrs.log_addr_mask;
|
||||
cec_queue_event_fh(fh, &ev, 0);
|
||||
#ifdef CONFIG_CEC_PIN
|
||||
if (adap->pin && adap->pin->ops->read_hpd) {
|
||||
err = adap->pin->ops->read_hpd(adap);
|
||||
if (err >= 0) {
|
||||
ev.event = err ? CEC_EVENT_PIN_HPD_HIGH :
|
||||
CEC_EVENT_PIN_HPD_LOW;
|
||||
cec_queue_event_fh(fh, &ev, 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
list_add(&fh->list, &devnode->fhs);
|
||||
mutex_unlock(&devnode->lock);
|
||||
|
|
|
@ -112,10 +112,6 @@ static int __must_check cec_devnode_register(struct cec_devnode *devnode,
|
|||
int minor;
|
||||
int ret;
|
||||
|
||||
/* Initialization */
|
||||
INIT_LIST_HEAD(&devnode->fhs);
|
||||
mutex_init(&devnode->lock);
|
||||
|
||||
/* Part 1: Find a free minor number */
|
||||
mutex_lock(&cec_devnode_lock);
|
||||
minor = find_next_zero_bit(cec_devnode_nums, CEC_NUM_DEVICES, 0);
|
||||
|
@ -242,6 +238,10 @@ struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops,
|
|||
INIT_LIST_HEAD(&adap->wait_queue);
|
||||
init_waitqueue_head(&adap->kthread_waitq);
|
||||
|
||||
/* adap->devnode initialization */
|
||||
INIT_LIST_HEAD(&adap->devnode.fhs);
|
||||
mutex_init(&adap->devnode.lock);
|
||||
|
||||
adap->kthread = kthread_run(cec_thread_func, adap, "cec-%s", name);
|
||||
if (IS_ERR(adap->kthread)) {
|
||||
pr_err("cec-%s: kernel_thread() failed\n", name);
|
||||
|
@ -277,7 +277,6 @@ struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops,
|
|||
adap->rc->input_id.version = 1;
|
||||
adap->rc->driver_name = CEC_NAME;
|
||||
adap->rc->allowed_protocols = RC_PROTO_BIT_CEC;
|
||||
adap->rc->enabled_protocols = RC_PROTO_BIT_CEC;
|
||||
adap->rc->priv = adap;
|
||||
adap->rc->map_name = RC_MAP_CEC;
|
||||
adap->rc->timeout = MS_TO_NS(100);
|
||||
|
|
133
drivers/media/cec/cec-pin-priv.h
Normal file
133
drivers/media/cec/cec-pin-priv.h
Normal file
|
@ -0,0 +1,133 @@
|
|||
/*
|
||||
* cec-pin-priv.h - internal cec-pin header
|
||||
*
|
||||
* Copyright 2017 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program is free software; you may redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef LINUX_CEC_PIN_PRIV_H
|
||||
#define LINUX_CEC_PIN_PRIV_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/atomic.h>
|
||||
#include <media/cec-pin.h>
|
||||
|
||||
enum cec_pin_state {
|
||||
/* CEC is off */
|
||||
CEC_ST_OFF,
|
||||
/* CEC is idle, waiting for Rx or Tx */
|
||||
CEC_ST_IDLE,
|
||||
|
||||
/* Tx states */
|
||||
|
||||
/* Pending Tx, waiting for Signal Free Time to expire */
|
||||
CEC_ST_TX_WAIT,
|
||||
/* Low-drive was detected, wait for bus to go high */
|
||||
CEC_ST_TX_WAIT_FOR_HIGH,
|
||||
/* Drive CEC low for the start bit */
|
||||
CEC_ST_TX_START_BIT_LOW,
|
||||
/* Drive CEC high for the start bit */
|
||||
CEC_ST_TX_START_BIT_HIGH,
|
||||
/* Drive CEC low for the 0 bit */
|
||||
CEC_ST_TX_DATA_BIT_0_LOW,
|
||||
/* Drive CEC high for the 0 bit */
|
||||
CEC_ST_TX_DATA_BIT_0_HIGH,
|
||||
/* Drive CEC low for the 1 bit */
|
||||
CEC_ST_TX_DATA_BIT_1_LOW,
|
||||
/* Drive CEC high for the 1 bit */
|
||||
CEC_ST_TX_DATA_BIT_1_HIGH,
|
||||
/*
|
||||
* Wait for start of sample time to check for Ack bit or first
|
||||
* four initiator bits to check for Arbitration Lost.
|
||||
*/
|
||||
CEC_ST_TX_DATA_BIT_1_HIGH_PRE_SAMPLE,
|
||||
/* Wait for end of bit period after sampling */
|
||||
CEC_ST_TX_DATA_BIT_1_HIGH_POST_SAMPLE,
|
||||
|
||||
/* Rx states */
|
||||
|
||||
/* Start bit low detected */
|
||||
CEC_ST_RX_START_BIT_LOW,
|
||||
/* Start bit high detected */
|
||||
CEC_ST_RX_START_BIT_HIGH,
|
||||
/* Wait for bit sample time */
|
||||
CEC_ST_RX_DATA_SAMPLE,
|
||||
/* Wait for earliest end of bit period after sampling */
|
||||
CEC_ST_RX_DATA_POST_SAMPLE,
|
||||
/* Wait for CEC to go high (i.e. end of bit period */
|
||||
CEC_ST_RX_DATA_HIGH,
|
||||
/* Drive CEC low to send 0 Ack bit */
|
||||
CEC_ST_RX_ACK_LOW,
|
||||
/* End of 0 Ack time, wait for earliest end of bit period */
|
||||
CEC_ST_RX_ACK_LOW_POST,
|
||||
/* Wait for CEC to go high (i.e. end of bit period */
|
||||
CEC_ST_RX_ACK_HIGH_POST,
|
||||
/* Wait for earliest end of bit period and end of message */
|
||||
CEC_ST_RX_ACK_FINISH,
|
||||
|
||||
/* Start low drive */
|
||||
CEC_ST_LOW_DRIVE,
|
||||
/* Monitor pin using interrupts */
|
||||
CEC_ST_RX_IRQ,
|
||||
|
||||
/* Total number of pin states */
|
||||
CEC_PIN_STATES
|
||||
};
|
||||
|
||||
#define CEC_NUM_PIN_EVENTS 128
|
||||
|
||||
#define CEC_PIN_IRQ_UNCHANGED 0
|
||||
#define CEC_PIN_IRQ_DISABLE 1
|
||||
#define CEC_PIN_IRQ_ENABLE 2
|
||||
|
||||
struct cec_pin {
|
||||
struct cec_adapter *adap;
|
||||
const struct cec_pin_ops *ops;
|
||||
struct task_struct *kthread;
|
||||
wait_queue_head_t kthread_waitq;
|
||||
struct hrtimer timer;
|
||||
ktime_t ts;
|
||||
unsigned int wait_usecs;
|
||||
u16 la_mask;
|
||||
bool enabled;
|
||||
bool monitor_all;
|
||||
bool rx_eom;
|
||||
bool enable_irq_failed;
|
||||
enum cec_pin_state state;
|
||||
struct cec_msg tx_msg;
|
||||
u32 tx_bit;
|
||||
bool tx_nacked;
|
||||
u32 tx_signal_free_time;
|
||||
struct cec_msg rx_msg;
|
||||
u32 rx_bit;
|
||||
|
||||
struct cec_msg work_rx_msg;
|
||||
u8 work_tx_status;
|
||||
ktime_t work_tx_ts;
|
||||
atomic_t work_irq_change;
|
||||
atomic_t work_pin_events;
|
||||
unsigned int work_pin_events_wr;
|
||||
unsigned int work_pin_events_rd;
|
||||
ktime_t work_pin_ts[CEC_NUM_PIN_EVENTS];
|
||||
bool work_pin_is_high[CEC_NUM_PIN_EVENTS];
|
||||
ktime_t timer_ts;
|
||||
u32 timer_cnt;
|
||||
u32 timer_100ms_overruns;
|
||||
u32 timer_300ms_overruns;
|
||||
u32 timer_max_overrun;
|
||||
u32 timer_sum_overrun;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -20,6 +20,7 @@
|
|||
#include <linux/sched/types.h>
|
||||
|
||||
#include <media/cec-pin.h>
|
||||
#include "cec-pin-priv.h"
|
||||
|
||||
/* All timings are in microseconds */
|
||||
|
||||
|
@ -132,7 +133,7 @@ static void cec_pin_to_idle(struct cec_pin *pin)
|
|||
pin->rx_msg.len = 0;
|
||||
memset(pin->rx_msg.msg, 0, sizeof(pin->rx_msg.msg));
|
||||
pin->state = CEC_ST_IDLE;
|
||||
pin->ts = 0;
|
||||
pin->ts = ns_to_ktime(0);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -426,7 +427,7 @@ static void cec_pin_rx_states(struct cec_pin *pin, ktime_t ts)
|
|||
v = cec_pin_read(pin);
|
||||
if (v && pin->rx_eom) {
|
||||
pin->work_rx_msg = pin->rx_msg;
|
||||
pin->work_rx_msg.rx_ts = ts;
|
||||
pin->work_rx_msg.rx_ts = ktime_to_ns(ts);
|
||||
wake_up_interruptible(&pin->kthread_waitq);
|
||||
pin->ts = ts;
|
||||
pin->state = CEC_ST_RX_ACK_FINISH;
|
||||
|
@ -457,7 +458,7 @@ static enum hrtimer_restart cec_pin_timer(struct hrtimer *timer)
|
|||
s32 delta;
|
||||
|
||||
ts = ktime_get();
|
||||
if (pin->timer_ts) {
|
||||
if (ktime_to_ns(pin->timer_ts)) {
|
||||
delta = ktime_us_delta(ts, pin->timer_ts);
|
||||
pin->timer_cnt++;
|
||||
if (delta > 100 && pin->state != CEC_ST_IDLE) {
|
||||
|
@ -481,17 +482,19 @@ static enum hrtimer_restart cec_pin_timer(struct hrtimer *timer)
|
|||
if (pin->wait_usecs > 150) {
|
||||
pin->wait_usecs -= 100;
|
||||
pin->timer_ts = ktime_add_us(ts, 100);
|
||||
hrtimer_forward_now(timer, 100000);
|
||||
hrtimer_forward_now(timer, ns_to_ktime(100000));
|
||||
return HRTIMER_RESTART;
|
||||
}
|
||||
if (pin->wait_usecs > 100) {
|
||||
pin->wait_usecs /= 2;
|
||||
pin->timer_ts = ktime_add_us(ts, pin->wait_usecs);
|
||||
hrtimer_forward_now(timer, pin->wait_usecs * 1000);
|
||||
hrtimer_forward_now(timer,
|
||||
ns_to_ktime(pin->wait_usecs * 1000));
|
||||
return HRTIMER_RESTART;
|
||||
}
|
||||
pin->timer_ts = ktime_add_us(ts, pin->wait_usecs);
|
||||
hrtimer_forward_now(timer, pin->wait_usecs * 1000);
|
||||
hrtimer_forward_now(timer,
|
||||
ns_to_ktime(pin->wait_usecs * 1000));
|
||||
pin->wait_usecs = 0;
|
||||
return HRTIMER_RESTART;
|
||||
}
|
||||
|
@ -531,7 +534,7 @@ static enum hrtimer_restart cec_pin_timer(struct hrtimer *timer)
|
|||
pin->state = CEC_ST_RX_START_BIT_LOW;
|
||||
break;
|
||||
}
|
||||
if (pin->ts == 0)
|
||||
if (ktime_to_ns(pin->ts) == 0)
|
||||
pin->ts = ts;
|
||||
if (pin->tx_msg.len) {
|
||||
/*
|
||||
|
@ -572,12 +575,13 @@ static enum hrtimer_restart cec_pin_timer(struct hrtimer *timer)
|
|||
if (!adap->monitor_pin_cnt || states[pin->state].usecs <= 150) {
|
||||
pin->wait_usecs = 0;
|
||||
pin->timer_ts = ktime_add_us(ts, states[pin->state].usecs);
|
||||
hrtimer_forward_now(timer, states[pin->state].usecs * 1000);
|
||||
hrtimer_forward_now(timer,
|
||||
ns_to_ktime(states[pin->state].usecs * 1000));
|
||||
return HRTIMER_RESTART;
|
||||
}
|
||||
pin->wait_usecs = states[pin->state].usecs - 100;
|
||||
pin->timer_ts = ktime_add_us(ts, 100);
|
||||
hrtimer_forward_now(timer, 100000);
|
||||
hrtimer_forward_now(timer, ns_to_ktime(100000));
|
||||
return HRTIMER_RESTART;
|
||||
}
|
||||
|
||||
|
@ -596,7 +600,7 @@ static int cec_pin_thread_func(void *_adap)
|
|||
|
||||
if (pin->work_rx_msg.len) {
|
||||
cec_received_msg_ts(adap, &pin->work_rx_msg,
|
||||
pin->work_rx_msg.rx_ts);
|
||||
ns_to_ktime(pin->work_rx_msg.rx_ts));
|
||||
pin->work_rx_msg.len = 0;
|
||||
}
|
||||
if (pin->work_tx_status) {
|
||||
|
@ -623,13 +627,15 @@ static int cec_pin_thread_func(void *_adap)
|
|||
pin->ops->disable_irq(adap);
|
||||
cec_pin_high(pin);
|
||||
cec_pin_to_idle(pin);
|
||||
hrtimer_start(&pin->timer, 0, HRTIMER_MODE_REL);
|
||||
hrtimer_start(&pin->timer, ns_to_ktime(0),
|
||||
HRTIMER_MODE_REL);
|
||||
break;
|
||||
case CEC_PIN_IRQ_ENABLE:
|
||||
pin->enable_irq_failed = !pin->ops->enable_irq(adap);
|
||||
if (pin->enable_irq_failed) {
|
||||
cec_pin_to_idle(pin);
|
||||
hrtimer_start(&pin->timer, 0, HRTIMER_MODE_REL);
|
||||
hrtimer_start(&pin->timer, ns_to_ktime(0),
|
||||
HRTIMER_MODE_REL);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
@ -653,7 +659,7 @@ static int cec_pin_adap_enable(struct cec_adapter *adap, bool enable)
|
|||
cec_pin_read(pin);
|
||||
cec_pin_to_idle(pin);
|
||||
pin->tx_msg.len = 0;
|
||||
pin->timer_ts = 0;
|
||||
pin->timer_ts = ns_to_ktime(0);
|
||||
atomic_set(&pin->work_irq_change, CEC_PIN_IRQ_UNCHANGED);
|
||||
pin->kthread = kthread_run(cec_pin_thread_func, adap,
|
||||
"cec-pin");
|
||||
|
@ -661,7 +667,8 @@ static int cec_pin_adap_enable(struct cec_adapter *adap, bool enable)
|
|||
pr_err("cec-pin: kernel_thread() failed\n");
|
||||
return PTR_ERR(pin->kthread);
|
||||
}
|
||||
hrtimer_start(&pin->timer, 0, HRTIMER_MODE_REL);
|
||||
hrtimer_start(&pin->timer, ns_to_ktime(0),
|
||||
HRTIMER_MODE_REL);
|
||||
} else {
|
||||
if (pin->ops->disable_irq)
|
||||
pin->ops->disable_irq(adap);
|
||||
|
@ -699,7 +706,8 @@ static int cec_pin_adap_transmit(struct cec_adapter *adap, u8 attempts,
|
|||
pin->ops->disable_irq(adap);
|
||||
cec_pin_high(pin);
|
||||
cec_pin_to_idle(pin);
|
||||
hrtimer_start(&pin->timer, 0, HRTIMER_MODE_REL);
|
||||
hrtimer_start(&pin->timer, ns_to_ktime(0),
|
||||
HRTIMER_MODE_REL);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -789,7 +797,7 @@ struct cec_adapter *cec_pin_allocate_adapter(const struct cec_pin_ops *pin_ops,
|
|||
caps | CEC_CAP_MONITOR_ALL | CEC_CAP_MONITOR_PIN,
|
||||
CEC_MAX_LOG_ADDRS);
|
||||
|
||||
if (PTR_ERR_OR_ZERO(adap)) {
|
||||
if (IS_ERR(adap)) {
|
||||
kfree(pin);
|
||||
return adap;
|
||||
}
|
||||
|
|
|
@ -74,11 +74,9 @@ int cypress_load_firmware(struct usb_device *udev,
|
|||
struct hexline *hx;
|
||||
int ret, pos = 0;
|
||||
|
||||
hx = kmalloc(sizeof(struct hexline), GFP_KERNEL);
|
||||
if (!hx) {
|
||||
dev_err(&udev->dev, "%s: kmalloc() failed\n", KBUILD_MODNAME);
|
||||
hx = kmalloc(sizeof(*hx), GFP_KERNEL);
|
||||
if (!hx)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* stop the CPU */
|
||||
hx->data[0] = 1;
|
||||
|
|
|
@ -163,9 +163,9 @@ void saa7146_buffer_next(struct saa7146_dev *dev,
|
|||
}
|
||||
}
|
||||
|
||||
void saa7146_buffer_timeout(unsigned long data)
|
||||
void saa7146_buffer_timeout(struct timer_list *t)
|
||||
{
|
||||
struct saa7146_dmaqueue *q = (struct saa7146_dmaqueue*)data;
|
||||
struct saa7146_dmaqueue *q = from_timer(q, t, timeout);
|
||||
struct saa7146_dev *dev = q->dev;
|
||||
unsigned long flags;
|
||||
|
||||
|
@ -559,7 +559,7 @@ int saa7146_vv_init(struct saa7146_dev* dev, struct saa7146_ext_vv *ext_vv)
|
|||
vbi->start[1] = 312;
|
||||
vbi->count[1] = 16;
|
||||
|
||||
init_timer(&vv->vbi_read_timeout);
|
||||
timer_setup(&vv->vbi_read_timeout, NULL, 0);
|
||||
|
||||
vv->ov_fb.capability = V4L2_FBUF_CAP_LIST_CLIPPING;
|
||||
vv->ov_fb.flags = V4L2_FBUF_FLAG_PRIMARY;
|
||||
|
|
|
@ -349,9 +349,10 @@ static void vbi_stop(struct saa7146_fh *fh, struct file *file)
|
|||
spin_unlock_irqrestore(&dev->slock, flags);
|
||||
}
|
||||
|
||||
static void vbi_read_timeout(unsigned long data)
|
||||
static void vbi_read_timeout(struct timer_list *t)
|
||||
{
|
||||
struct file *file = (struct file*)data;
|
||||
struct saa7146_vv *vv = from_timer(vv, t, vbi_read_timeout);
|
||||
struct file *file = vv->vbi_read_timeout_file;
|
||||
struct saa7146_fh *fh = file->private_data;
|
||||
struct saa7146_dev *dev = fh->dev;
|
||||
|
||||
|
@ -366,8 +367,7 @@ static void vbi_init(struct saa7146_dev *dev, struct saa7146_vv *vv)
|
|||
|
||||
INIT_LIST_HEAD(&vv->vbi_dmaq.queue);
|
||||
|
||||
setup_timer(&vv->vbi_dmaq.timeout, saa7146_buffer_timeout,
|
||||
(unsigned long)(&vv->vbi_dmaq));
|
||||
timer_setup(&vv->vbi_dmaq.timeout, saa7146_buffer_timeout, 0);
|
||||
vv->vbi_dmaq.dev = dev;
|
||||
|
||||
init_waitqueue_head(&vv->vbi_wq);
|
||||
|
@ -402,8 +402,8 @@ static int vbi_open(struct saa7146_dev *dev, struct file *file)
|
|||
sizeof(struct saa7146_buf),
|
||||
file, &dev->v4l2_lock);
|
||||
|
||||
vv->vbi_read_timeout.function = vbi_read_timeout;
|
||||
vv->vbi_read_timeout.data = (unsigned long)file;
|
||||
vv->vbi_read_timeout.function = (TIMER_FUNC_TYPE)vbi_read_timeout;
|
||||
vv->vbi_read_timeout_file = file;
|
||||
|
||||
/* initialize the brs */
|
||||
if ( 0 != (SAA7146_USE_PORT_B_FOR_VBI & dev->ext_vv_data->flags)) {
|
||||
|
@ -489,7 +489,7 @@ static ssize_t vbi_read(struct file *file, char __user *data, size_t count, loff
|
|||
return ret;
|
||||
}
|
||||
|
||||
struct saa7146_use_ops saa7146_vbi_uops = {
|
||||
const struct saa7146_use_ops saa7146_vbi_uops = {
|
||||
.init = vbi_init,
|
||||
.open = vbi_open,
|
||||
.release = vbi_close,
|
||||
|
|
|
@ -1201,8 +1201,7 @@ static void video_init(struct saa7146_dev *dev, struct saa7146_vv *vv)
|
|||
{
|
||||
INIT_LIST_HEAD(&vv->video_dmaq.queue);
|
||||
|
||||
setup_timer(&vv->video_dmaq.timeout, saa7146_buffer_timeout,
|
||||
(unsigned long)(&vv->video_dmaq));
|
||||
timer_setup(&vv->video_dmaq.timeout, saa7146_buffer_timeout, 0);
|
||||
vv->video_dmaq.dev = dev;
|
||||
|
||||
/* set some default values */
|
||||
|
@ -1303,7 +1302,7 @@ static ssize_t video_read(struct file *file, char __user *data, size_t count, lo
|
|||
return ret;
|
||||
}
|
||||
|
||||
struct saa7146_use_ops saa7146_video_uops = {
|
||||
const struct saa7146_use_ops saa7146_video_uops = {
|
||||
.init = video_init,
|
||||
.open = video_open,
|
||||
.release = video_close,
|
||||
|
|
|
@ -447,7 +447,7 @@ static struct smscore_registry_entry_t *smscore_find_registry(char *devpath)
|
|||
return entry;
|
||||
}
|
||||
}
|
||||
entry = kmalloc(sizeof(struct smscore_registry_entry_t), GFP_KERNEL);
|
||||
entry = kmalloc(sizeof(*entry), GFP_KERNEL);
|
||||
if (entry) {
|
||||
entry->mode = default_mode;
|
||||
strcpy(entry->devpath, devpath);
|
||||
|
@ -536,9 +536,7 @@ int smscore_register_hotplug(hotplug_t hotplug)
|
|||
int rc = 0;
|
||||
|
||||
kmutex_lock(&g_smscore_deviceslock);
|
||||
|
||||
notifyee = kmalloc(sizeof(struct smscore_device_notifyee_t),
|
||||
GFP_KERNEL);
|
||||
notifyee = kmalloc(sizeof(*notifyee), GFP_KERNEL);
|
||||
if (notifyee) {
|
||||
/* now notify callback about existing devices */
|
||||
first = &g_smscore_devices;
|
||||
|
@ -627,7 +625,7 @@ smscore_buffer_t *smscore_createbuffer(u8 *buffer, void *common_buffer,
|
|||
{
|
||||
struct smscore_buffer_t *cb;
|
||||
|
||||
cb = kzalloc(sizeof(struct smscore_buffer_t), GFP_KERNEL);
|
||||
cb = kzalloc(sizeof(*cb), GFP_KERNEL);
|
||||
if (!cb)
|
||||
return NULL;
|
||||
|
||||
|
@ -655,7 +653,7 @@ int smscore_register_device(struct smsdevice_params_t *params,
|
|||
struct smscore_device_t *dev;
|
||||
u8 *buffer;
|
||||
|
||||
dev = kzalloc(sizeof(struct smscore_device_t), GFP_KERNEL);
|
||||
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
|
||||
if (!dev)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -751,7 +749,7 @@ static int smscore_sendrequest_and_wait(struct smscore_device_t *coredev,
|
|||
void *buffer, size_t size, struct completion *completion) {
|
||||
int rc;
|
||||
|
||||
if (completion == NULL)
|
||||
if (!completion)
|
||||
return -EINVAL;
|
||||
init_completion(completion);
|
||||
|
||||
|
@ -1153,8 +1151,8 @@ static int smscore_load_firmware_from_file(struct smscore_device_t *coredev,
|
|||
}
|
||||
pr_debug("Firmware name: %s\n", fw_filename);
|
||||
|
||||
if (loadfirmware_handler == NULL && !(coredev->device_flags
|
||||
& SMS_DEVICE_FAMILY2))
|
||||
if (!loadfirmware_handler &&
|
||||
!(coredev->device_flags & SMS_DEVICE_FAMILY2))
|
||||
return -EINVAL;
|
||||
|
||||
rc = request_firmware(&fw, fw_filename, coredev->device);
|
||||
|
@ -1301,10 +1299,8 @@ static int smscore_init_device(struct smscore_device_t *coredev, int mode)
|
|||
|
||||
buffer = kmalloc(sizeof(struct sms_msg_data) +
|
||||
SMS_DMA_ALIGNMENT, GFP_KERNEL | GFP_DMA);
|
||||
if (!buffer) {
|
||||
pr_err("Could not allocate buffer for init device message.\n");
|
||||
if (!buffer)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
msg = (struct sms_msg_data *)SMS_ALIGN_ADDRESS(buffer);
|
||||
SMS_INIT_MSG(&msg->x_msg_header, MSG_SMS_INIT_DEVICE_REQ,
|
||||
|
@ -1686,11 +1682,10 @@ static int smscore_validate_client(struct smscore_device_t *coredev,
|
|||
pr_err("The msg ID already registered to another client.\n");
|
||||
return -EEXIST;
|
||||
}
|
||||
listentry = kzalloc(sizeof(struct smscore_idlist_t), GFP_KERNEL);
|
||||
if (!listentry) {
|
||||
pr_err("Can't allocate memory for client id.\n");
|
||||
listentry = kzalloc(sizeof(*listentry), GFP_KERNEL);
|
||||
if (!listentry)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
listentry->id = id;
|
||||
listentry->data_type = data_type;
|
||||
list_add_locked(&listentry->entry, &client->idlist,
|
||||
|
@ -1724,11 +1719,9 @@ int smscore_register_client(struct smscore_device_t *coredev,
|
|||
return -EEXIST;
|
||||
}
|
||||
|
||||
newclient = kzalloc(sizeof(struct smscore_client_t), GFP_KERNEL);
|
||||
if (!newclient) {
|
||||
pr_err("Failed to allocate memory for client.\n");
|
||||
newclient = kzalloc(sizeof(*newclient), GFP_KERNEL);
|
||||
if (!newclient)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&newclient->idlist);
|
||||
newclient->coredev = coredev;
|
||||
|
@ -1796,7 +1789,7 @@ int smsclient_sendrequest(struct smscore_client_t *client,
|
|||
struct sms_msg_hdr *phdr = (struct sms_msg_hdr *) buffer;
|
||||
int rc;
|
||||
|
||||
if (client == NULL) {
|
||||
if (!client) {
|
||||
pr_err("Got NULL client\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -1804,7 +1797,7 @@ int smsclient_sendrequest(struct smscore_client_t *client,
|
|||
coredev = client->coredev;
|
||||
|
||||
/* check that no other channel with same id exists */
|
||||
if (coredev == NULL) {
|
||||
if (!coredev) {
|
||||
pr_err("Got NULL coredev\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -1961,7 +1954,7 @@ int smscore_gpio_configure(struct smscore_device_t *coredev, u8 pin_num,
|
|||
if (pin_num > MAX_GPIO_PIN_NUMBER)
|
||||
return -EINVAL;
|
||||
|
||||
if (p_gpio_config == NULL)
|
||||
if (!p_gpio_config)
|
||||
return -EINVAL;
|
||||
|
||||
total_len = sizeof(struct sms_msg_hdr) + (sizeof(u32) * 6);
|
||||
|
|
|
@ -238,6 +238,8 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc)
|
|||
tpg->color_enc = TGP_COLOR_ENC_RGB;
|
||||
break;
|
||||
case V4L2_PIX_FMT_GREY:
|
||||
case V4L2_PIX_FMT_Y10:
|
||||
case V4L2_PIX_FMT_Y12:
|
||||
case V4L2_PIX_FMT_Y16:
|
||||
case V4L2_PIX_FMT_Y16_BE:
|
||||
tpg->color_enc = TGP_COLOR_ENC_LUMA;
|
||||
|
@ -352,6 +354,8 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc)
|
|||
case V4L2_PIX_FMT_YUV444:
|
||||
case V4L2_PIX_FMT_YUV555:
|
||||
case V4L2_PIX_FMT_YUV565:
|
||||
case V4L2_PIX_FMT_Y10:
|
||||
case V4L2_PIX_FMT_Y12:
|
||||
case V4L2_PIX_FMT_Y16:
|
||||
case V4L2_PIX_FMT_Y16_BE:
|
||||
tpg->twopixelsize[0] = 2 * 2;
|
||||
|
@ -1056,6 +1060,14 @@ static void gen_twopix(struct tpg_data *tpg,
|
|||
case V4L2_PIX_FMT_GREY:
|
||||
buf[0][offset] = r_y_h;
|
||||
break;
|
||||
case V4L2_PIX_FMT_Y10:
|
||||
buf[0][offset] = (r_y_h << 2) & 0xff;
|
||||
buf[0][offset+1] = r_y_h >> 6;
|
||||
break;
|
||||
case V4L2_PIX_FMT_Y12:
|
||||
buf[0][offset] = (r_y_h << 4) & 0xff;
|
||||
buf[0][offset+1] = r_y_h >> 4;
|
||||
break;
|
||||
case V4L2_PIX_FMT_Y16:
|
||||
/*
|
||||
* Ideally both bytes should be set to r_y_h, but then you won't
|
||||
|
|
|
@ -329,9 +329,9 @@ static int dvb_dmxdev_set_buffer_size(struct dmxdev_filter *dmxdevfilter,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void dvb_dmxdev_filter_timeout(unsigned long data)
|
||||
static void dvb_dmxdev_filter_timeout(struct timer_list *t)
|
||||
{
|
||||
struct dmxdev_filter *dmxdevfilter = (struct dmxdev_filter *)data;
|
||||
struct dmxdev_filter *dmxdevfilter = from_timer(dmxdevfilter, t, timer);
|
||||
|
||||
dmxdevfilter->buffer.error = -ETIMEDOUT;
|
||||
spin_lock_irq(&dmxdevfilter->dev->lock);
|
||||
|
@ -346,8 +346,6 @@ static void dvb_dmxdev_filter_timer(struct dmxdev_filter *dmxdevfilter)
|
|||
|
||||
del_timer(&dmxdevfilter->timer);
|
||||
if (para->timeout) {
|
||||
dmxdevfilter->timer.function = dvb_dmxdev_filter_timeout;
|
||||
dmxdevfilter->timer.data = (unsigned long)dmxdevfilter;
|
||||
dmxdevfilter->timer.expires =
|
||||
jiffies + 1 + (HZ / 2 + HZ * para->timeout) / 1000;
|
||||
add_timer(&dmxdevfilter->timer);
|
||||
|
@ -754,7 +752,7 @@ static int dvb_demux_open(struct inode *inode, struct file *file)
|
|||
dvb_ringbuffer_init(&dmxdevfilter->buffer, NULL, 8192);
|
||||
dmxdevfilter->type = DMXDEV_TYPE_NONE;
|
||||
dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED);
|
||||
init_timer(&dmxdevfilter->timer);
|
||||
timer_setup(&dmxdevfilter->timer, dvb_dmxdev_filter_timeout, 0);
|
||||
|
||||
dvbdev->users++;
|
||||
|
||||
|
|
|
@ -36,12 +36,33 @@
|
|||
#include "demux.h"
|
||||
#include "dvb_ringbuffer.h"
|
||||
|
||||
/**
|
||||
* enum dmxdev_type - type of demux filter type.
|
||||
*
|
||||
* @DMXDEV_TYPE_NONE: no filter set.
|
||||
* @DMXDEV_TYPE_SEC: section filter.
|
||||
* @DMXDEV_TYPE_PES: Program Elementary Stream (PES) filter.
|
||||
*/
|
||||
enum dmxdev_type {
|
||||
DMXDEV_TYPE_NONE,
|
||||
DMXDEV_TYPE_SEC,
|
||||
DMXDEV_TYPE_PES,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum dmxdev_state - state machine for the dmxdev.
|
||||
*
|
||||
* @DMXDEV_STATE_FREE: indicates that the filter is freed.
|
||||
* @DMXDEV_STATE_ALLOCATED: indicates that the filter was allocated
|
||||
* to be used.
|
||||
* @DMXDEV_STATE_SET: indicates that the filter parameters are set.
|
||||
* @DMXDEV_STATE_GO: indicates that the filter is running.
|
||||
* @DMXDEV_STATE_DONE: indicates that a packet was already filtered
|
||||
* and the filter is now disabled.
|
||||
* Set only if %DMX_ONESHOT. See
|
||||
* &dmx_sct_filter_params.
|
||||
* @DMXDEV_STATE_TIMEDOUT: Indicates a timeout condition.
|
||||
*/
|
||||
enum dmxdev_state {
|
||||
DMXDEV_STATE_FREE,
|
||||
DMXDEV_STATE_ALLOCATED,
|
||||
|
@ -51,12 +72,49 @@ enum dmxdev_state {
|
|||
DMXDEV_STATE_TIMEDOUT
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dmxdev_feed - digital TV dmxdev feed
|
||||
*
|
||||
* @pid: Program ID to be filtered
|
||||
* @ts: pointer to &struct dmx_ts_feed
|
||||
* @next: &struct list_head pointing to the next feed.
|
||||
*/
|
||||
|
||||
struct dmxdev_feed {
|
||||
u16 pid;
|
||||
struct dmx_ts_feed *ts;
|
||||
struct list_head next;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dmxdev_filter - digital TV dmxdev filter
|
||||
*
|
||||
* @filter: a dmxdev filter. Currently used only for section filter:
|
||||
* if the filter is Section, it contains a
|
||||
* &struct dmx_section_filter @sec pointer.
|
||||
* @feed: a dmxdev feed. Depending on the feed type, it can be:
|
||||
* for TS feed: a &struct list_head @ts list of TS and PES
|
||||
* feeds;
|
||||
* for section feed: a &struct dmx_section_feed @sec pointer.
|
||||
* @params: dmxdev filter parameters. Depending on the feed type, it
|
||||
* can be:
|
||||
* for section filter: a &struct dmx_sct_filter_params @sec
|
||||
* embedded struct;
|
||||
* for a TS filter: a &struct dmx_pes_filter_params @pes
|
||||
* embedded struct.
|
||||
* @type: type of the dmxdev filter, as defined by &enum dmxdev_type.
|
||||
* @state: state of the dmxdev filter, as defined by &enum dmxdev_state.
|
||||
* @dev: pointer to &struct dmxdev.
|
||||
* @buffer: an embedded &struct dvb_ringbuffer buffer.
|
||||
* @mutex: protects the access to &struct dmxdev_filter.
|
||||
* @timer: &struct timer_list embedded timer, used to check for
|
||||
* feed timeouts.
|
||||
* Only for section filter.
|
||||
* @todo: index for the @secheader.
|
||||
* Only for section filter.
|
||||
* @secheader: buffer cache to parse the section header.
|
||||
* Only for section filter.
|
||||
*/
|
||||
struct dmxdev_filter {
|
||||
union {
|
||||
struct dmx_section_filter *sec;
|
||||
|
@ -86,7 +144,23 @@ struct dmxdev_filter {
|
|||
u8 secheader[3];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* struct dmxdev - Describes a digital TV demux device.
|
||||
*
|
||||
* @dvbdev: pointer to &struct dvb_device associated with
|
||||
* the demux device node.
|
||||
* @dvr_dvbdev: pointer to &struct dvb_device associated with
|
||||
* the dvr device node.
|
||||
* @filter: pointer to &struct dmxdev_filter.
|
||||
* @demux: pointer to &struct dmx_demux.
|
||||
* @filternum: number of filters.
|
||||
* @capabilities: demux capabilities as defined by &enum dmx_demux_caps.
|
||||
* @exit: flag to indicate that the demux is being released.
|
||||
* @dvr_orig_fe: pointer to &struct dmx_frontend.
|
||||
* @dvr_buffer: embedded &struct dvb_ringbuffer for DVB output.
|
||||
* @mutex: protects the usage of this structure.
|
||||
* @lock: protects access to &dmxdev->filter->data.
|
||||
*/
|
||||
struct dmxdev {
|
||||
struct dvb_device *dvbdev;
|
||||
struct dvb_device *dvr_dvbdev;
|
||||
|
@ -108,8 +182,20 @@ struct dmxdev {
|
|||
spinlock_t lock;
|
||||
};
|
||||
|
||||
/**
|
||||
* dvb_dmxdev_init - initializes a digital TV demux and registers both demux
|
||||
* and DVR devices.
|
||||
*
|
||||
* @dmxdev: pointer to &struct dmxdev.
|
||||
* @adap: pointer to &struct dvb_adapter.
|
||||
*/
|
||||
int dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *adap);
|
||||
|
||||
int dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *);
|
||||
/**
|
||||
* dvb_dmxdev_release - releases a digital TV demux and unregisters it.
|
||||
*
|
||||
* @dmxdev: pointer to &struct dmxdev.
|
||||
*/
|
||||
void dvb_dmxdev_release(struct dmxdev *dmxdev);
|
||||
|
||||
#endif /* _DMXDEV_H_ */
|
||||
|
|
|
@ -223,10 +223,10 @@ static void dvb_dmx_swfilter_section_new(struct dvb_demux_feed *feed)
|
|||
* when the second packet arrives.
|
||||
*
|
||||
* Fix:
|
||||
* when demux is started, let feed->pusi_seen = 0 to
|
||||
* when demux is started, let feed->pusi_seen = false to
|
||||
* prevent initial feeding of garbage from the end of
|
||||
* previous section. When you for the first time see PUSI=1
|
||||
* then set feed->pusi_seen = 1
|
||||
* then set feed->pusi_seen = true
|
||||
*/
|
||||
static int dvb_dmx_swfilter_section_copy_dump(struct dvb_demux_feed *feed,
|
||||
const u8 *buf, u8 len)
|
||||
|
@ -318,10 +318,10 @@ static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed,
|
|||
*/
|
||||
#endif
|
||||
/*
|
||||
* Discontinuity detected. Reset pusi_seen = 0 to
|
||||
* Discontinuity detected. Reset pusi_seen to
|
||||
* stop feeding of suspicious data until next PUSI=1 arrives
|
||||
*/
|
||||
feed->pusi_seen = 0;
|
||||
feed->pusi_seen = false;
|
||||
dvb_dmx_swfilter_section_new(feed);
|
||||
}
|
||||
|
||||
|
@ -335,8 +335,8 @@ static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed,
|
|||
|
||||
dvb_dmx_swfilter_section_copy_dump(feed, before,
|
||||
before_len);
|
||||
/* before start of new section, set pusi_seen = 1 */
|
||||
feed->pusi_seen = 1;
|
||||
/* before start of new section, set pusi_seen */
|
||||
feed->pusi_seen = true;
|
||||
dvb_dmx_swfilter_section_new(feed);
|
||||
dvb_dmx_swfilter_section_copy_dump(feed, after,
|
||||
after_len);
|
||||
|
@ -367,6 +367,7 @@ static inline void dvb_dmx_swfilter_packet_type(struct dvb_demux_feed *feed,
|
|||
else
|
||||
feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts);
|
||||
}
|
||||
/* Used only on full-featured devices */
|
||||
if (feed->ts_type & TS_DECODER)
|
||||
if (feed->demux->write_to_decoder)
|
||||
feed->demux->write_to_decoder(feed, buf, 188);
|
||||
|
@ -898,14 +899,14 @@ static void prepare_secfilters(struct dvb_demux_feed *dvbdmxfeed)
|
|||
return;
|
||||
do {
|
||||
sf = &f->filter;
|
||||
doneq = 0;
|
||||
doneq = false;
|
||||
for (i = 0; i < DVB_DEMUX_MASK_MAX; i++) {
|
||||
mode = sf->filter_mode[i];
|
||||
mask = sf->filter_mask[i];
|
||||
f->maskandmode[i] = mask & mode;
|
||||
doneq |= f->maskandnotmode[i] = mask & ~mode;
|
||||
}
|
||||
f->doneq = doneq ? 1 : 0;
|
||||
f->doneq = doneq ? true : false;
|
||||
} while ((f = f->next));
|
||||
}
|
||||
|
||||
|
|
|
@ -26,15 +26,33 @@
|
|||
|
||||
#include "demux.h"
|
||||
|
||||
#define DMX_TYPE_TS 0
|
||||
#define DMX_TYPE_SEC 1
|
||||
#define DMX_TYPE_PES 2
|
||||
/**
|
||||
* enum dvb_dmx_filter_type - type of demux feed.
|
||||
*
|
||||
* @DMX_TYPE_TS: feed is in TS mode.
|
||||
* @DMX_TYPE_SEC: feed is in Section mode.
|
||||
*/
|
||||
enum dvb_dmx_filter_type {
|
||||
DMX_TYPE_TS,
|
||||
DMX_TYPE_SEC,
|
||||
};
|
||||
|
||||
#define DMX_STATE_FREE 0
|
||||
#define DMX_STATE_ALLOCATED 1
|
||||
#define DMX_STATE_SET 2
|
||||
#define DMX_STATE_READY 3
|
||||
#define DMX_STATE_GO 4
|
||||
/**
|
||||
* enum dvb_dmx_state - state machine for a demux filter.
|
||||
*
|
||||
* @DMX_STATE_FREE: indicates that the filter is freed.
|
||||
* @DMX_STATE_ALLOCATED: indicates that the filter was allocated
|
||||
* to be used.
|
||||
* @DMX_STATE_READY: indicates that the filter is ready
|
||||
* to be used.
|
||||
* @DMX_STATE_GO: indicates that the filter is running.
|
||||
*/
|
||||
enum dvb_dmx_state {
|
||||
DMX_STATE_FREE,
|
||||
DMX_STATE_ALLOCATED,
|
||||
DMX_STATE_READY,
|
||||
DMX_STATE_GO,
|
||||
};
|
||||
|
||||
#define DVB_DEMUX_MASK_MAX 18
|
||||
|
||||
|
@ -42,24 +60,66 @@
|
|||
|
||||
#define SPEED_PKTS_INTERVAL 50000
|
||||
|
||||
/**
|
||||
* struct dvb_demux_filter - Describes a DVB demux section filter.
|
||||
*
|
||||
* @filter: Section filter as defined by &struct dmx_section_filter.
|
||||
* @maskandmode: logical ``and`` bit mask.
|
||||
* @maskandnotmode: logical ``and not`` bit mask.
|
||||
* @doneq: flag that indicates when a filter is ready.
|
||||
* @next: pointer to the next section filter.
|
||||
* @feed: &struct dvb_demux_feed pointer.
|
||||
* @index: index of the used demux filter.
|
||||
* @state: state of the filter as described by &enum dvb_dmx_state.
|
||||
* @type: type of the filter as described
|
||||
* by &enum dvb_dmx_filter_type.
|
||||
*/
|
||||
|
||||
struct dvb_demux_filter {
|
||||
struct dmx_section_filter filter;
|
||||
u8 maskandmode[DMX_MAX_FILTER_SIZE];
|
||||
u8 maskandnotmode[DMX_MAX_FILTER_SIZE];
|
||||
int doneq;
|
||||
bool doneq;
|
||||
|
||||
struct dvb_demux_filter *next;
|
||||
struct dvb_demux_feed *feed;
|
||||
int index;
|
||||
int state;
|
||||
int type;
|
||||
enum dvb_dmx_state state;
|
||||
enum dvb_dmx_filter_type type;
|
||||
|
||||
/* private: used only by av7110 */
|
||||
u16 hw_handle;
|
||||
struct timer_list timer;
|
||||
};
|
||||
|
||||
#define DMX_FEED_ENTRY(pos) list_entry(pos, struct dvb_demux_feed, list_head)
|
||||
|
||||
/**
|
||||
* struct dvb_demux_feed - describes a DVB field
|
||||
*
|
||||
* @feed: a digital TV feed. It can either be a TS or a section feed:
|
||||
* if the feed is TS, it contains &struct dvb_ts_feed @ts;
|
||||
* if the feed is section, it contains
|
||||
* &struct dmx_section_feed @sec.
|
||||
* @cb: digital TV callbacks. depending on the feed type, it can be:
|
||||
* if the feed is TS, it contains a dmx_ts_cb() @ts callback;
|
||||
* if the feed is section, it contains a dmx_section_cb() @sec
|
||||
* callback.
|
||||
*
|
||||
* @demux: pointer to &struct dvb_demux.
|
||||
* @priv: private data that can optionally be used by a DVB driver.
|
||||
* @type: type of the filter, as defined by &enum dvb_dmx_filter_type.
|
||||
* @state: state of the filter as defined by &enum dvb_dmx_state.
|
||||
* @pid: PID to be filtered.
|
||||
* @timeout: feed timeout.
|
||||
* @filter: pointer to &struct dvb_demux_filter.
|
||||
* @ts_type: type of TS, as defined by &enum ts_filter_type.
|
||||
* @pes_type: type of PES, as defined by &enum dmx_ts_pes.
|
||||
* @cc: MPEG-TS packet continuity counter
|
||||
* @pusi_seen: if true, indicates that a discontinuity was detected.
|
||||
* it is used to prevent feeding of garbage from previous section.
|
||||
* @peslen: length of the PES (Packet Elementary Stream).
|
||||
* @list_head: head for the list of digital TV demux feeds.
|
||||
* @index: a unique index for each feed. Can be used as hardware
|
||||
* pid filter index.
|
||||
*/
|
||||
struct dvb_demux_feed {
|
||||
union {
|
||||
struct dmx_ts_feed ts;
|
||||
|
@ -73,25 +133,63 @@ struct dvb_demux_feed {
|
|||
|
||||
struct dvb_demux *demux;
|
||||
void *priv;
|
||||
int type;
|
||||
int state;
|
||||
enum dvb_dmx_filter_type type;
|
||||
enum dvb_dmx_state state;
|
||||
u16 pid;
|
||||
|
||||
ktime_t timeout;
|
||||
struct dvb_demux_filter *filter;
|
||||
|
||||
int ts_type;
|
||||
enum ts_filter_type ts_type;
|
||||
enum dmx_ts_pes pes_type;
|
||||
|
||||
int cc;
|
||||
int pusi_seen; /* prevents feeding of garbage from previous section */
|
||||
bool pusi_seen;
|
||||
|
||||
u16 peslen;
|
||||
|
||||
struct list_head list_head;
|
||||
unsigned int index; /* a unique index for each feed (can be used as hardware pid filter index) */
|
||||
unsigned int index;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dvb_demux - represents a digital TV demux
|
||||
* @dmx: embedded &struct dmx_demux with demux capabilities
|
||||
* and callbacks.
|
||||
* @priv: private data that can optionally be used by
|
||||
* a DVB driver.
|
||||
* @filternum: maximum amount of DVB filters.
|
||||
* @feednum: maximum amount of DVB feeds.
|
||||
* @start_feed: callback routine to be called in order to start
|
||||
* a DVB feed.
|
||||
* @stop_feed: callback routine to be called in order to stop
|
||||
* a DVB feed.
|
||||
* @write_to_decoder: callback routine to be called if the feed is TS and
|
||||
* it is routed to an A/V decoder, when a new TS packet
|
||||
* is received.
|
||||
* Used only on av7110-av.c.
|
||||
* @check_crc32: callback routine to check CRC. If not initialized,
|
||||
* dvb_demux will use an internal one.
|
||||
* @memcopy: callback routine to memcopy received data.
|
||||
* If not initialized, dvb_demux will default to memcpy().
|
||||
* @users: counter for the number of demux opened file descriptors.
|
||||
* Currently, it is limited to 10 users.
|
||||
* @filter: pointer to &struct dvb_demux_filter.
|
||||
* @feed: pointer to &struct dvb_demux_feed.
|
||||
* @frontend_list: &struct list_head with frontends used by the demux.
|
||||
* @pesfilter: array of &struct dvb_demux_feed with the PES types
|
||||
* that will be filtered.
|
||||
* @pids: list of filtered program IDs.
|
||||
* @feed_list: &struct list_head with feeds.
|
||||
* @tsbuf: temporary buffer used internally to store TS packets.
|
||||
* @tsbufp: temporary buffer index used internally.
|
||||
* @mutex: pointer to &struct mutex used to protect feed set
|
||||
* logic.
|
||||
* @lock: pointer to &spinlock_t, used to protect buffer handling.
|
||||
* @cnt_storage: buffer used for TS/TEI continuity check.
|
||||
* @speed_last_time: &ktime_t used for TS speed check.
|
||||
* @speed_pkts_cnt: packets count used for TS speed check.
|
||||
*/
|
||||
struct dvb_demux {
|
||||
struct dmx_demux dmx;
|
||||
void *priv;
|
||||
|
@ -115,8 +213,6 @@ struct dvb_demux {
|
|||
|
||||
struct dvb_demux_feed *pesfilter[DMX_PES_OTHER];
|
||||
u16 pids[DMX_PES_OTHER];
|
||||
int playing;
|
||||
int recording;
|
||||
|
||||
#define DMX_MAX_PID 0x2000
|
||||
struct list_head feed_list;
|
||||
|
@ -130,15 +226,119 @@ struct dvb_demux {
|
|||
|
||||
ktime_t speed_last_time; /* for TS speed check */
|
||||
uint32_t speed_pkts_cnt; /* for TS speed check */
|
||||
|
||||
/* private: used only on av7110 */
|
||||
int playing;
|
||||
int recording;
|
||||
};
|
||||
|
||||
int dvb_dmx_init(struct dvb_demux *dvbdemux);
|
||||
void dvb_dmx_release(struct dvb_demux *dvbdemux);
|
||||
void dvb_dmx_swfilter_packets(struct dvb_demux *dvbdmx, const u8 *buf,
|
||||
/**
|
||||
* dvb_dmx_init - initialize a digital TV demux struct.
|
||||
*
|
||||
* @demux: &struct dvb_demux to be initialized.
|
||||
*
|
||||
* Before being able to register a digital TV demux struct, drivers
|
||||
* should call this routine. On its typical usage, some fields should
|
||||
* be initialized at the driver before calling it.
|
||||
*
|
||||
* A typical usecase is::
|
||||
*
|
||||
* dvb->demux.dmx.capabilities =
|
||||
* DMX_TS_FILTERING | DMX_SECTION_FILTERING |
|
||||
* DMX_MEMORY_BASED_FILTERING;
|
||||
* dvb->demux.priv = dvb;
|
||||
* dvb->demux.filternum = 256;
|
||||
* dvb->demux.feednum = 256;
|
||||
* dvb->demux.start_feed = driver_start_feed;
|
||||
* dvb->demux.stop_feed = driver_stop_feed;
|
||||
* ret = dvb_dmx_init(&dvb->demux);
|
||||
* if (ret < 0)
|
||||
* return ret;
|
||||
*/
|
||||
int dvb_dmx_init(struct dvb_demux *demux);
|
||||
|
||||
/**
|
||||
* dvb_dmx_release - releases a digital TV demux internal buffers.
|
||||
*
|
||||
* @demux: &struct dvb_demux to be released.
|
||||
*
|
||||
* The DVB core internally allocates data at @demux. This routine
|
||||
* releases those data. Please notice that the struct itelf is not
|
||||
* released, as it can be embedded on other structs.
|
||||
*/
|
||||
void dvb_dmx_release(struct dvb_demux *demux);
|
||||
|
||||
/**
|
||||
* dvb_dmx_swfilter_packets - use dvb software filter for a buffer with
|
||||
* multiple MPEG-TS packets with 188 bytes each.
|
||||
*
|
||||
* @demux: pointer to &struct dvb_demux
|
||||
* @buf: buffer with data to be filtered
|
||||
* @count: number of MPEG-TS packets with size of 188.
|
||||
*
|
||||
* The routine will discard a DVB packet that don't start with 0x47.
|
||||
*
|
||||
* Use this routine if the DVB demux fills MPEG-TS buffers that are
|
||||
* already aligned.
|
||||
*
|
||||
* NOTE: The @buf size should have size equal to ``count * 188``.
|
||||
*/
|
||||
void dvb_dmx_swfilter_packets(struct dvb_demux *demux, const u8 *buf,
|
||||
size_t count);
|
||||
|
||||
/**
|
||||
* dvb_dmx_swfilter - use dvb software filter for a buffer with
|
||||
* multiple MPEG-TS packets with 188 bytes each.
|
||||
*
|
||||
* @demux: pointer to &struct dvb_demux
|
||||
* @buf: buffer with data to be filtered
|
||||
* @count: number of MPEG-TS packets with size of 188.
|
||||
*
|
||||
* If a DVB packet doesn't start with 0x47, it will seek for the first
|
||||
* byte that starts with 0x47.
|
||||
*
|
||||
* Use this routine if the DVB demux fill buffers that may not start with
|
||||
* a packet start mark (0x47).
|
||||
*
|
||||
* NOTE: The @buf size should have size equal to ``count * 188``.
|
||||
*/
|
||||
void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count);
|
||||
|
||||
/**
|
||||
* dvb_dmx_swfilter_204 - use dvb software filter for a buffer with
|
||||
* multiple MPEG-TS packets with 204 bytes each.
|
||||
*
|
||||
* @demux: pointer to &struct dvb_demux
|
||||
* @buf: buffer with data to be filtered
|
||||
* @count: number of MPEG-TS packets with size of 204.
|
||||
*
|
||||
* If a DVB packet doesn't start with 0x47, it will seek for the first
|
||||
* byte that starts with 0x47.
|
||||
*
|
||||
* Use this routine if the DVB demux fill buffers that may not start with
|
||||
* a packet start mark (0x47).
|
||||
*
|
||||
* NOTE: The @buf size should have size equal to ``count * 204``.
|
||||
*/
|
||||
void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf,
|
||||
size_t count);
|
||||
|
||||
/**
|
||||
* dvb_dmx_swfilter_raw - make the raw data available to userspace without
|
||||
* filtering
|
||||
*
|
||||
* @demux: pointer to &struct dvb_demux
|
||||
* @buf: buffer with data
|
||||
* @count: number of packets to be passed. The actual size of each packet
|
||||
* depends on the &dvb_demux->feed->cb.ts logic.
|
||||
*
|
||||
* Use it if the driver needs to deliver the raw payload to userspace without
|
||||
* passing through the kernel demux. That is meant to support some
|
||||
* delivery systems that aren't based on MPEG-TS.
|
||||
*
|
||||
* This function relies on &dvb_demux->feed->cb.ts to actually handle the
|
||||
* buffer.
|
||||
*/
|
||||
void dvb_dmx_swfilter_raw(struct dvb_demux *demux, const u8 *buf,
|
||||
size_t count);
|
||||
|
||||
|
|
|
@ -145,15 +145,13 @@ static void __dvb_frontend_free(struct dvb_frontend *fe)
|
|||
{
|
||||
struct dvb_frontend_private *fepriv = fe->frontend_priv;
|
||||
|
||||
if (!fepriv)
|
||||
return;
|
||||
|
||||
dvb_free_device(fepriv->dvbdev);
|
||||
if (fepriv)
|
||||
dvb_free_device(fepriv->dvbdev);
|
||||
|
||||
dvb_frontend_invoke_release(fe, fe->ops.release);
|
||||
|
||||
kfree(fepriv);
|
||||
fe->frontend_priv = NULL;
|
||||
if (fepriv)
|
||||
kfree(fepriv);
|
||||
}
|
||||
|
||||
static void dvb_frontend_free(struct kref *ref)
|
||||
|
@ -951,8 +949,6 @@ static int dvb_frontend_clear_cache(struct dvb_frontend *fe)
|
|||
memset(c, 0, offsetof(struct dtv_frontend_properties, strength));
|
||||
c->delivery_system = delsys;
|
||||
|
||||
c->state = DTV_CLEAR;
|
||||
|
||||
dev_dbg(fe->dvb->device, "%s: Clearing cache for delivery system %d\n",
|
||||
__func__, c->delivery_system);
|
||||
|
||||
|
@ -1109,39 +1105,6 @@ static struct dtv_cmds_h dtv_cmds[DTV_MAX_COMMAND + 1] = {
|
|||
_DTV_CMD(DTV_STAT_TOTAL_BLOCK_COUNT, 0, 0),
|
||||
};
|
||||
|
||||
static void dtv_property_dump(struct dvb_frontend *fe,
|
||||
bool is_set,
|
||||
struct dtv_property *tvp)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (tvp->cmd <= 0 || tvp->cmd > DTV_MAX_COMMAND) {
|
||||
dev_warn(fe->dvb->device, "%s: %s tvp.cmd = 0x%08x undefined\n",
|
||||
__func__,
|
||||
is_set ? "SET" : "GET",
|
||||
tvp->cmd);
|
||||
return;
|
||||
}
|
||||
|
||||
dev_dbg(fe->dvb->device, "%s: %s tvp.cmd = 0x%08x (%s)\n", __func__,
|
||||
is_set ? "SET" : "GET",
|
||||
tvp->cmd,
|
||||
dtv_cmds[tvp->cmd].name);
|
||||
|
||||
if (dtv_cmds[tvp->cmd].buffer) {
|
||||
dev_dbg(fe->dvb->device, "%s: tvp.u.buffer.len = 0x%02x\n",
|
||||
__func__, tvp->u.buffer.len);
|
||||
|
||||
for(i = 0; i < tvp->u.buffer.len; i++)
|
||||
dev_dbg(fe->dvb->device,
|
||||
"%s: tvp.u.buffer.data[0x%02x] = 0x%02x\n",
|
||||
__func__, i, tvp->u.buffer.data[i]);
|
||||
} else {
|
||||
dev_dbg(fe->dvb->device, "%s: tvp.u.data = 0x%08x\n", __func__,
|
||||
tvp->u.data);
|
||||
}
|
||||
}
|
||||
|
||||
/* Synchronise the legacy tuning parameters into the cache, so that demodulator
|
||||
* drivers can use a single set_frontend tuning function, regardless of whether
|
||||
* it's being used for the legacy or new API, reducing code and complexity.
|
||||
|
@ -1315,17 +1278,15 @@ static int dtv_get_frontend(struct dvb_frontend *fe,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int dvb_frontend_ioctl_legacy(struct file *file,
|
||||
unsigned int cmd, void *parg);
|
||||
static int dvb_frontend_ioctl_properties(struct file *file,
|
||||
unsigned int cmd, void *parg);
|
||||
static int dvb_frontend_handle_ioctl(struct file *file,
|
||||
unsigned int cmd, void *parg);
|
||||
|
||||
static int dtv_property_process_get(struct dvb_frontend *fe,
|
||||
const struct dtv_frontend_properties *c,
|
||||
struct dtv_property *tvp,
|
||||
struct file *file)
|
||||
{
|
||||
int r, ncaps;
|
||||
int ncaps;
|
||||
|
||||
switch(tvp->cmd) {
|
||||
case DTV_ENUM_DELSYS:
|
||||
|
@ -1536,14 +1497,18 @@ static int dtv_property_process_get(struct dvb_frontend *fe,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Allow the frontend to override outgoing properties */
|
||||
if (fe->ops.get_property) {
|
||||
r = fe->ops.get_property(fe, tvp);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
dtv_property_dump(fe, false, tvp);
|
||||
if (!dtv_cmds[tvp->cmd].buffer)
|
||||
dev_dbg(fe->dvb->device,
|
||||
"%s: GET cmd 0x%08x (%s) = 0x%08x\n",
|
||||
__func__, tvp->cmd, dtv_cmds[tvp->cmd].name,
|
||||
tvp->u.data);
|
||||
else
|
||||
dev_dbg(fe->dvb->device,
|
||||
"%s: GET cmd 0x%08x (%s) len %d: %*ph\n",
|
||||
__func__,
|
||||
tvp->cmd, dtv_cmds[tvp->cmd].name,
|
||||
tvp->u.buffer.len,
|
||||
tvp->u.buffer.len, tvp->u.buffer.data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1766,23 +1731,36 @@ static int dvbv3_set_delivery_system(struct dvb_frontend *fe)
|
|||
return emulate_delivery_system(fe, delsys);
|
||||
}
|
||||
|
||||
/**
|
||||
* dtv_property_process_set - Sets a single DTV property
|
||||
* @fe: Pointer to &struct dvb_frontend
|
||||
* @file: Pointer to &struct file
|
||||
* @cmd: Digital TV command
|
||||
* @data: An unsigned 32-bits number
|
||||
*
|
||||
* This routine assigns the property
|
||||
* value to the corresponding member of
|
||||
* &struct dtv_frontend_properties
|
||||
*
|
||||
* Returns:
|
||||
* Zero on success, negative errno on failure.
|
||||
*/
|
||||
static int dtv_property_process_set(struct dvb_frontend *fe,
|
||||
struct dtv_property *tvp,
|
||||
struct file *file)
|
||||
struct file *file,
|
||||
u32 cmd, u32 data)
|
||||
{
|
||||
int r = 0;
|
||||
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
|
||||
|
||||
/* Allow the frontend to validate incoming properties */
|
||||
if (fe->ops.set_property) {
|
||||
r = fe->ops.set_property(fe, tvp);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
dtv_property_dump(fe, true, tvp);
|
||||
|
||||
switch(tvp->cmd) {
|
||||
/** Dump DTV command name and value*/
|
||||
if (!cmd || cmd > DTV_MAX_COMMAND)
|
||||
dev_warn(fe->dvb->device, "%s: SET cmd 0x%08x undefined\n",
|
||||
__func__, cmd);
|
||||
else
|
||||
dev_dbg(fe->dvb->device,
|
||||
"%s: SET cmd 0x%08x (%s) to 0x%08x\n",
|
||||
__func__, cmd, dtv_cmds[cmd].name, data);
|
||||
switch (cmd) {
|
||||
case DTV_CLEAR:
|
||||
/*
|
||||
* Reset a cache of data specific to the frontend here. This does
|
||||
|
@ -1791,144 +1769,144 @@ static int dtv_property_process_set(struct dvb_frontend *fe,
|
|||
dvb_frontend_clear_cache(fe);
|
||||
break;
|
||||
case DTV_TUNE:
|
||||
/* interpret the cache of data, build either a traditional frontend
|
||||
* tunerequest so we can pass validation in the FE_SET_FRONTEND
|
||||
* ioctl.
|
||||
/*
|
||||
* Use the cached Digital TV properties to tune the
|
||||
* frontend
|
||||
*/
|
||||
c->state = tvp->cmd;
|
||||
dev_dbg(fe->dvb->device, "%s: Finalised property cache\n",
|
||||
__func__);
|
||||
dev_dbg(fe->dvb->device,
|
||||
"%s: Setting the frontend from property cache\n",
|
||||
__func__);
|
||||
|
||||
r = dtv_set_frontend(fe);
|
||||
break;
|
||||
case DTV_FREQUENCY:
|
||||
c->frequency = tvp->u.data;
|
||||
c->frequency = data;
|
||||
break;
|
||||
case DTV_MODULATION:
|
||||
c->modulation = tvp->u.data;
|
||||
c->modulation = data;
|
||||
break;
|
||||
case DTV_BANDWIDTH_HZ:
|
||||
c->bandwidth_hz = tvp->u.data;
|
||||
c->bandwidth_hz = data;
|
||||
break;
|
||||
case DTV_INVERSION:
|
||||
c->inversion = tvp->u.data;
|
||||
c->inversion = data;
|
||||
break;
|
||||
case DTV_SYMBOL_RATE:
|
||||
c->symbol_rate = tvp->u.data;
|
||||
c->symbol_rate = data;
|
||||
break;
|
||||
case DTV_INNER_FEC:
|
||||
c->fec_inner = tvp->u.data;
|
||||
c->fec_inner = data;
|
||||
break;
|
||||
case DTV_PILOT:
|
||||
c->pilot = tvp->u.data;
|
||||
c->pilot = data;
|
||||
break;
|
||||
case DTV_ROLLOFF:
|
||||
c->rolloff = tvp->u.data;
|
||||
c->rolloff = data;
|
||||
break;
|
||||
case DTV_DELIVERY_SYSTEM:
|
||||
r = dvbv5_set_delivery_system(fe, tvp->u.data);
|
||||
r = dvbv5_set_delivery_system(fe, data);
|
||||
break;
|
||||
case DTV_VOLTAGE:
|
||||
c->voltage = tvp->u.data;
|
||||
r = dvb_frontend_ioctl_legacy(file, FE_SET_VOLTAGE,
|
||||
c->voltage = data;
|
||||
r = dvb_frontend_handle_ioctl(file, FE_SET_VOLTAGE,
|
||||
(void *)c->voltage);
|
||||
break;
|
||||
case DTV_TONE:
|
||||
c->sectone = tvp->u.data;
|
||||
r = dvb_frontend_ioctl_legacy(file, FE_SET_TONE,
|
||||
c->sectone = data;
|
||||
r = dvb_frontend_handle_ioctl(file, FE_SET_TONE,
|
||||
(void *)c->sectone);
|
||||
break;
|
||||
case DTV_CODE_RATE_HP:
|
||||
c->code_rate_HP = tvp->u.data;
|
||||
c->code_rate_HP = data;
|
||||
break;
|
||||
case DTV_CODE_RATE_LP:
|
||||
c->code_rate_LP = tvp->u.data;
|
||||
c->code_rate_LP = data;
|
||||
break;
|
||||
case DTV_GUARD_INTERVAL:
|
||||
c->guard_interval = tvp->u.data;
|
||||
c->guard_interval = data;
|
||||
break;
|
||||
case DTV_TRANSMISSION_MODE:
|
||||
c->transmission_mode = tvp->u.data;
|
||||
c->transmission_mode = data;
|
||||
break;
|
||||
case DTV_HIERARCHY:
|
||||
c->hierarchy = tvp->u.data;
|
||||
c->hierarchy = data;
|
||||
break;
|
||||
case DTV_INTERLEAVING:
|
||||
c->interleaving = tvp->u.data;
|
||||
c->interleaving = data;
|
||||
break;
|
||||
|
||||
/* ISDB-T Support here */
|
||||
case DTV_ISDBT_PARTIAL_RECEPTION:
|
||||
c->isdbt_partial_reception = tvp->u.data;
|
||||
c->isdbt_partial_reception = data;
|
||||
break;
|
||||
case DTV_ISDBT_SOUND_BROADCASTING:
|
||||
c->isdbt_sb_mode = tvp->u.data;
|
||||
c->isdbt_sb_mode = data;
|
||||
break;
|
||||
case DTV_ISDBT_SB_SUBCHANNEL_ID:
|
||||
c->isdbt_sb_subchannel = tvp->u.data;
|
||||
c->isdbt_sb_subchannel = data;
|
||||
break;
|
||||
case DTV_ISDBT_SB_SEGMENT_IDX:
|
||||
c->isdbt_sb_segment_idx = tvp->u.data;
|
||||
c->isdbt_sb_segment_idx = data;
|
||||
break;
|
||||
case DTV_ISDBT_SB_SEGMENT_COUNT:
|
||||
c->isdbt_sb_segment_count = tvp->u.data;
|
||||
c->isdbt_sb_segment_count = data;
|
||||
break;
|
||||
case DTV_ISDBT_LAYER_ENABLED:
|
||||
c->isdbt_layer_enabled = tvp->u.data;
|
||||
c->isdbt_layer_enabled = data;
|
||||
break;
|
||||
case DTV_ISDBT_LAYERA_FEC:
|
||||
c->layer[0].fec = tvp->u.data;
|
||||
c->layer[0].fec = data;
|
||||
break;
|
||||
case DTV_ISDBT_LAYERA_MODULATION:
|
||||
c->layer[0].modulation = tvp->u.data;
|
||||
c->layer[0].modulation = data;
|
||||
break;
|
||||
case DTV_ISDBT_LAYERA_SEGMENT_COUNT:
|
||||
c->layer[0].segment_count = tvp->u.data;
|
||||
c->layer[0].segment_count = data;
|
||||
break;
|
||||
case DTV_ISDBT_LAYERA_TIME_INTERLEAVING:
|
||||
c->layer[0].interleaving = tvp->u.data;
|
||||
c->layer[0].interleaving = data;
|
||||
break;
|
||||
case DTV_ISDBT_LAYERB_FEC:
|
||||
c->layer[1].fec = tvp->u.data;
|
||||
c->layer[1].fec = data;
|
||||
break;
|
||||
case DTV_ISDBT_LAYERB_MODULATION:
|
||||
c->layer[1].modulation = tvp->u.data;
|
||||
c->layer[1].modulation = data;
|
||||
break;
|
||||
case DTV_ISDBT_LAYERB_SEGMENT_COUNT:
|
||||
c->layer[1].segment_count = tvp->u.data;
|
||||
c->layer[1].segment_count = data;
|
||||
break;
|
||||
case DTV_ISDBT_LAYERB_TIME_INTERLEAVING:
|
||||
c->layer[1].interleaving = tvp->u.data;
|
||||
c->layer[1].interleaving = data;
|
||||
break;
|
||||
case DTV_ISDBT_LAYERC_FEC:
|
||||
c->layer[2].fec = tvp->u.data;
|
||||
c->layer[2].fec = data;
|
||||
break;
|
||||
case DTV_ISDBT_LAYERC_MODULATION:
|
||||
c->layer[2].modulation = tvp->u.data;
|
||||
c->layer[2].modulation = data;
|
||||
break;
|
||||
case DTV_ISDBT_LAYERC_SEGMENT_COUNT:
|
||||
c->layer[2].segment_count = tvp->u.data;
|
||||
c->layer[2].segment_count = data;
|
||||
break;
|
||||
case DTV_ISDBT_LAYERC_TIME_INTERLEAVING:
|
||||
c->layer[2].interleaving = tvp->u.data;
|
||||
c->layer[2].interleaving = data;
|
||||
break;
|
||||
|
||||
/* Multistream support */
|
||||
case DTV_STREAM_ID:
|
||||
case DTV_DVBT2_PLP_ID_LEGACY:
|
||||
c->stream_id = tvp->u.data;
|
||||
c->stream_id = data;
|
||||
break;
|
||||
|
||||
/* ATSC-MH */
|
||||
case DTV_ATSCMH_PARADE_ID:
|
||||
fe->dtv_property_cache.atscmh_parade_id = tvp->u.data;
|
||||
fe->dtv_property_cache.atscmh_parade_id = data;
|
||||
break;
|
||||
case DTV_ATSCMH_RS_FRAME_ENSEMBLE:
|
||||
fe->dtv_property_cache.atscmh_rs_frame_ensemble = tvp->u.data;
|
||||
fe->dtv_property_cache.atscmh_rs_frame_ensemble = data;
|
||||
break;
|
||||
|
||||
case DTV_LNA:
|
||||
c->lna = tvp->u.data;
|
||||
c->lna = data;
|
||||
if (fe->ops.set_lna)
|
||||
r = fe->ops.set_lna(fe);
|
||||
if (r < 0)
|
||||
|
@ -1942,14 +1920,12 @@ static int dtv_property_process_set(struct dvb_frontend *fe,
|
|||
return r;
|
||||
}
|
||||
|
||||
static int dvb_frontend_ioctl(struct file *file,
|
||||
unsigned int cmd, void *parg)
|
||||
static int dvb_frontend_ioctl(struct file *file, unsigned int cmd, void *parg)
|
||||
{
|
||||
struct dvb_device *dvbdev = file->private_data;
|
||||
struct dvb_frontend *fe = dvbdev->priv;
|
||||
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
|
||||
struct dvb_frontend_private *fepriv = fe->frontend_priv;
|
||||
int err = -EOPNOTSUPP;
|
||||
int err;
|
||||
|
||||
dev_dbg(fe->dvb->device, "%s: (%d)\n", __func__, _IOC_NR(cmd));
|
||||
if (down_interruptible(&fepriv->sem))
|
||||
|
@ -1960,109 +1936,33 @@ static int dvb_frontend_ioctl(struct file *file,
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
if ((file->f_flags & O_ACCMODE) == O_RDONLY &&
|
||||
(_IOC_DIR(cmd) != _IOC_READ || cmd == FE_GET_EVENT ||
|
||||
cmd == FE_DISEQC_RECV_SLAVE_REPLY)) {
|
||||
/*
|
||||
* If the frontend is opened in read-only mode, only the ioctls
|
||||
* that don't interfere with the tune logic should be accepted.
|
||||
* That allows an external application to monitor the DVB QoS and
|
||||
* statistics parameters.
|
||||
*
|
||||
* That matches all _IOR() ioctls, except for two special cases:
|
||||
* - FE_GET_EVENT is part of the tuning logic on a DVB application;
|
||||
* - FE_DISEQC_RECV_SLAVE_REPLY is part of DiSEqC 2.0
|
||||
* setup
|
||||
* So, those two ioctls should also return -EPERM, as otherwise
|
||||
* reading from them would interfere with a DVB tune application
|
||||
*/
|
||||
if ((file->f_flags & O_ACCMODE) == O_RDONLY
|
||||
&& (_IOC_DIR(cmd) != _IOC_READ
|
||||
|| cmd == FE_GET_EVENT
|
||||
|| cmd == FE_DISEQC_RECV_SLAVE_REPLY)) {
|
||||
up(&fepriv->sem);
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
if ((cmd == FE_SET_PROPERTY) || (cmd == FE_GET_PROPERTY))
|
||||
err = dvb_frontend_ioctl_properties(file, cmd, parg);
|
||||
else {
|
||||
c->state = DTV_UNDEFINED;
|
||||
err = dvb_frontend_ioctl_legacy(file, cmd, parg);
|
||||
}
|
||||
err = dvb_frontend_handle_ioctl(file, cmd, parg);
|
||||
|
||||
up(&fepriv->sem);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int dvb_frontend_ioctl_properties(struct file *file,
|
||||
unsigned int cmd, void *parg)
|
||||
{
|
||||
struct dvb_device *dvbdev = file->private_data;
|
||||
struct dvb_frontend *fe = dvbdev->priv;
|
||||
struct dvb_frontend_private *fepriv = fe->frontend_priv;
|
||||
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
|
||||
int err = 0;
|
||||
|
||||
struct dtv_properties *tvps = parg;
|
||||
struct dtv_property *tvp = NULL;
|
||||
int i;
|
||||
|
||||
dev_dbg(fe->dvb->device, "%s:\n", __func__);
|
||||
|
||||
if (cmd == FE_SET_PROPERTY) {
|
||||
dev_dbg(fe->dvb->device, "%s: properties.num = %d\n", __func__, tvps->num);
|
||||
dev_dbg(fe->dvb->device, "%s: properties.props = %p\n", __func__, tvps->props);
|
||||
|
||||
/* Put an arbitrary limit on the number of messages that can
|
||||
* be sent at once */
|
||||
if ((tvps->num == 0) || (tvps->num > DTV_IOCTL_MAX_MSGS))
|
||||
return -EINVAL;
|
||||
|
||||
tvp = memdup_user(tvps->props, tvps->num * sizeof(*tvp));
|
||||
if (IS_ERR(tvp))
|
||||
return PTR_ERR(tvp);
|
||||
|
||||
for (i = 0; i < tvps->num; i++) {
|
||||
err = dtv_property_process_set(fe, tvp + i, file);
|
||||
if (err < 0)
|
||||
goto out;
|
||||
(tvp + i)->result = err;
|
||||
}
|
||||
|
||||
if (c->state == DTV_TUNE)
|
||||
dev_dbg(fe->dvb->device, "%s: Property cache is full, tuning\n", __func__);
|
||||
|
||||
} else if (cmd == FE_GET_PROPERTY) {
|
||||
struct dtv_frontend_properties getp = fe->dtv_property_cache;
|
||||
|
||||
dev_dbg(fe->dvb->device, "%s: properties.num = %d\n", __func__, tvps->num);
|
||||
dev_dbg(fe->dvb->device, "%s: properties.props = %p\n", __func__, tvps->props);
|
||||
|
||||
/* Put an arbitrary limit on the number of messages that can
|
||||
* be sent at once */
|
||||
if ((tvps->num == 0) || (tvps->num > DTV_IOCTL_MAX_MSGS))
|
||||
return -EINVAL;
|
||||
|
||||
tvp = memdup_user(tvps->props, tvps->num * sizeof(*tvp));
|
||||
if (IS_ERR(tvp))
|
||||
return PTR_ERR(tvp);
|
||||
|
||||
/*
|
||||
* Let's use our own copy of property cache, in order to
|
||||
* avoid mangling with DTV zigzag logic, as drivers might
|
||||
* return crap, if they don't check if the data is available
|
||||
* before updating the properties cache.
|
||||
*/
|
||||
if (fepriv->state != FESTATE_IDLE) {
|
||||
err = dtv_get_frontend(fe, &getp, NULL);
|
||||
if (err < 0)
|
||||
goto out;
|
||||
}
|
||||
for (i = 0; i < tvps->num; i++) {
|
||||
err = dtv_property_process_get(fe, &getp, tvp + i, file);
|
||||
if (err < 0)
|
||||
goto out;
|
||||
(tvp + i)->result = err;
|
||||
}
|
||||
|
||||
if (copy_to_user((void __user *)tvps->props, tvp,
|
||||
tvps->num * sizeof(struct dtv_property))) {
|
||||
err = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
} else
|
||||
err = -EOPNOTSUPP;
|
||||
|
||||
out:
|
||||
kfree(tvp);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int dtv_set_frontend(struct dvb_frontend *fe)
|
||||
{
|
||||
struct dvb_frontend_private *fepriv = fe->frontend_priv;
|
||||
|
@ -2200,16 +2100,102 @@ static int dtv_set_frontend(struct dvb_frontend *fe)
|
|||
}
|
||||
|
||||
|
||||
static int dvb_frontend_ioctl_legacy(struct file *file,
|
||||
unsigned int cmd, void *parg)
|
||||
static int dvb_frontend_handle_ioctl(struct file *file,
|
||||
unsigned int cmd, void *parg)
|
||||
{
|
||||
struct dvb_device *dvbdev = file->private_data;
|
||||
struct dvb_frontend *fe = dvbdev->priv;
|
||||
struct dvb_frontend_private *fepriv = fe->frontend_priv;
|
||||
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
|
||||
int err = -EOPNOTSUPP;
|
||||
int i, err;
|
||||
|
||||
dev_dbg(fe->dvb->device, "%s:\n", __func__);
|
||||
|
||||
switch (cmd) {
|
||||
case FE_SET_PROPERTY: {
|
||||
struct dtv_properties *tvps = parg;
|
||||
struct dtv_property *tvp = NULL;
|
||||
|
||||
dev_dbg(fe->dvb->device, "%s: properties.num = %d\n",
|
||||
__func__, tvps->num);
|
||||
dev_dbg(fe->dvb->device, "%s: properties.props = %p\n",
|
||||
__func__, tvps->props);
|
||||
|
||||
/*
|
||||
* Put an arbitrary limit on the number of messages that can
|
||||
* be sent at once
|
||||
*/
|
||||
if (!tvps->num || (tvps->num > DTV_IOCTL_MAX_MSGS))
|
||||
return -EINVAL;
|
||||
|
||||
tvp = memdup_user(tvps->props, tvps->num * sizeof(*tvp));
|
||||
if (IS_ERR(tvp))
|
||||
return PTR_ERR(tvp);
|
||||
|
||||
for (i = 0; i < tvps->num; i++) {
|
||||
err = dtv_property_process_set(fe, file,
|
||||
(tvp + i)->cmd,
|
||||
(tvp + i)->u.data);
|
||||
if (err < 0) {
|
||||
kfree(tvp);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
kfree(tvp);
|
||||
break;
|
||||
}
|
||||
case FE_GET_PROPERTY: {
|
||||
struct dtv_properties *tvps = parg;
|
||||
struct dtv_property *tvp = NULL;
|
||||
struct dtv_frontend_properties getp = fe->dtv_property_cache;
|
||||
|
||||
dev_dbg(fe->dvb->device, "%s: properties.num = %d\n",
|
||||
__func__, tvps->num);
|
||||
dev_dbg(fe->dvb->device, "%s: properties.props = %p\n",
|
||||
__func__, tvps->props);
|
||||
|
||||
/*
|
||||
* Put an arbitrary limit on the number of messages that can
|
||||
* be sent at once
|
||||
*/
|
||||
if (!tvps->num || (tvps->num > DTV_IOCTL_MAX_MSGS))
|
||||
return -EINVAL;
|
||||
|
||||
tvp = memdup_user(tvps->props, tvps->num * sizeof(*tvp));
|
||||
if (IS_ERR(tvp))
|
||||
return PTR_ERR(tvp);
|
||||
|
||||
/*
|
||||
* Let's use our own copy of property cache, in order to
|
||||
* avoid mangling with DTV zigzag logic, as drivers might
|
||||
* return crap, if they don't check if the data is available
|
||||
* before updating the properties cache.
|
||||
*/
|
||||
if (fepriv->state != FESTATE_IDLE) {
|
||||
err = dtv_get_frontend(fe, &getp, NULL);
|
||||
if (err < 0) {
|
||||
kfree(tvp);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < tvps->num; i++) {
|
||||
err = dtv_property_process_get(fe, &getp,
|
||||
tvp + i, file);
|
||||
if (err < 0) {
|
||||
kfree(tvp);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
if (copy_to_user((void __user *)tvps->props, tvp,
|
||||
tvps->num * sizeof(struct dtv_property))) {
|
||||
kfree(tvp);
|
||||
return -EFAULT;
|
||||
}
|
||||
kfree(tvp);
|
||||
break;
|
||||
}
|
||||
|
||||
case FE_GET_INFO: {
|
||||
struct dvb_frontend_info* info = parg;
|
||||
|
||||
|
@ -2273,42 +2259,6 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
|
|||
break;
|
||||
}
|
||||
|
||||
case FE_READ_BER:
|
||||
if (fe->ops.read_ber) {
|
||||
if (fepriv->thread)
|
||||
err = fe->ops.read_ber(fe, (__u32 *) parg);
|
||||
else
|
||||
err = -EAGAIN;
|
||||
}
|
||||
break;
|
||||
|
||||
case FE_READ_SIGNAL_STRENGTH:
|
||||
if (fe->ops.read_signal_strength) {
|
||||
if (fepriv->thread)
|
||||
err = fe->ops.read_signal_strength(fe, (__u16 *) parg);
|
||||
else
|
||||
err = -EAGAIN;
|
||||
}
|
||||
break;
|
||||
|
||||
case FE_READ_SNR:
|
||||
if (fe->ops.read_snr) {
|
||||
if (fepriv->thread)
|
||||
err = fe->ops.read_snr(fe, (__u16 *) parg);
|
||||
else
|
||||
err = -EAGAIN;
|
||||
}
|
||||
break;
|
||||
|
||||
case FE_READ_UNCORRECTED_BLOCKS:
|
||||
if (fe->ops.read_ucblocks) {
|
||||
if (fepriv->thread)
|
||||
err = fe->ops.read_ucblocks(fe, (__u32 *) parg);
|
||||
else
|
||||
err = -EAGAIN;
|
||||
}
|
||||
break;
|
||||
|
||||
case FE_DISEQC_RESET_OVERLOAD:
|
||||
if (fe->ops.diseqc_reset_overload) {
|
||||
err = fe->ops.diseqc_reset_overload(fe);
|
||||
|
@ -2360,6 +2310,23 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
|
|||
}
|
||||
break;
|
||||
|
||||
case FE_DISEQC_RECV_SLAVE_REPLY:
|
||||
if (fe->ops.diseqc_recv_slave_reply)
|
||||
err = fe->ops.diseqc_recv_slave_reply(fe, parg);
|
||||
break;
|
||||
|
||||
case FE_ENABLE_HIGH_LNB_VOLTAGE:
|
||||
if (fe->ops.enable_high_lnb_voltage)
|
||||
err = fe->ops.enable_high_lnb_voltage(fe, (long) parg);
|
||||
break;
|
||||
|
||||
case FE_SET_FRONTEND_TUNE_MODE:
|
||||
fepriv->tune_mode_flags = (unsigned long) parg;
|
||||
err = 0;
|
||||
break;
|
||||
|
||||
/* DEPRECATED dish control ioctls */
|
||||
|
||||
case FE_DISHNETWORK_SEND_LEGACY_CMD:
|
||||
if (fe->ops.dishnetwork_send_legacy_command) {
|
||||
err = fe->ops.dishnetwork_send_legacy_command(fe,
|
||||
|
@ -2425,16 +2392,46 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
|
|||
}
|
||||
break;
|
||||
|
||||
case FE_DISEQC_RECV_SLAVE_REPLY:
|
||||
if (fe->ops.diseqc_recv_slave_reply)
|
||||
err = fe->ops.diseqc_recv_slave_reply(fe, (struct dvb_diseqc_slave_reply*) parg);
|
||||
/* DEPRECATED statistics ioctls */
|
||||
|
||||
case FE_READ_BER:
|
||||
if (fe->ops.read_ber) {
|
||||
if (fepriv->thread)
|
||||
err = fe->ops.read_ber(fe, parg);
|
||||
else
|
||||
err = -EAGAIN;
|
||||
}
|
||||
break;
|
||||
|
||||
case FE_ENABLE_HIGH_LNB_VOLTAGE:
|
||||
if (fe->ops.enable_high_lnb_voltage)
|
||||
err = fe->ops.enable_high_lnb_voltage(fe, (long) parg);
|
||||
case FE_READ_SIGNAL_STRENGTH:
|
||||
if (fe->ops.read_signal_strength) {
|
||||
if (fepriv->thread)
|
||||
err = fe->ops.read_signal_strength(fe, parg);
|
||||
else
|
||||
err = -EAGAIN;
|
||||
}
|
||||
break;
|
||||
|
||||
case FE_READ_SNR:
|
||||
if (fe->ops.read_snr) {
|
||||
if (fepriv->thread)
|
||||
err = fe->ops.read_snr(fe, parg);
|
||||
else
|
||||
err = -EAGAIN;
|
||||
}
|
||||
break;
|
||||
|
||||
case FE_READ_UNCORRECTED_BLOCKS:
|
||||
if (fe->ops.read_ucblocks) {
|
||||
if (fepriv->thread)
|
||||
err = fe->ops.read_ucblocks(fe, parg);
|
||||
else
|
||||
err = -EAGAIN;
|
||||
}
|
||||
break;
|
||||
|
||||
/* DEPRECATED DVBv3 ioctls */
|
||||
|
||||
case FE_SET_FRONTEND:
|
||||
err = dvbv3_set_delivery_system(fe);
|
||||
if (err)
|
||||
|
@ -2461,11 +2458,10 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
|
|||
err = dtv_get_frontend(fe, &getp, parg);
|
||||
break;
|
||||
}
|
||||
case FE_SET_FRONTEND_TUNE_MODE:
|
||||
fepriv->tune_mode_flags = (unsigned long) parg;
|
||||
err = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
return -ENOTSUPP;
|
||||
} /* switch */
|
||||
|
||||
return err;
|
||||
}
|
||||
|
|
|
@ -180,8 +180,8 @@ enum dvbfe_search {
|
|||
/**
|
||||
* struct dvb_tuner_ops - Tuner information and callbacks
|
||||
*
|
||||
* @info: embedded struct dvb_tuner_info with tuner properties
|
||||
* @release: callback function called when frontend is dettached.
|
||||
* @info: embedded &struct dvb_tuner_info with tuner properties
|
||||
* @release: callback function called when frontend is detached.
|
||||
* drivers should free any allocated memory.
|
||||
* @init: callback function used to initialize the tuner device.
|
||||
* @sleep: callback function used to put the tuner to sleep.
|
||||
|
@ -191,14 +191,14 @@ enum dvbfe_search {
|
|||
* resuming from suspend.
|
||||
* @set_params: callback function used to inform the tuner to tune
|
||||
* into a digital TV channel. The properties to be used
|
||||
* are stored at @dvb_frontend.dtv_property_cache;. The
|
||||
* tuner demod can change the parameters to reflect the
|
||||
* changes needed for the channel to be tuned, and
|
||||
* are stored at &struct dvb_frontend.dtv_property_cache.
|
||||
* The tuner demod can change the parameters to reflect
|
||||
* the changes needed for the channel to be tuned, and
|
||||
* update statistics. This is the recommended way to set
|
||||
* the tuner parameters and should be used on newer
|
||||
* drivers.
|
||||
* @set_analog_params: callback function used to tune into an analog TV
|
||||
* channel on hybrid tuners. It passes @analog_parameters;
|
||||
* channel on hybrid tuners. It passes @analog_parameters
|
||||
* to the driver.
|
||||
* @set_config: callback function used to send some tuner-specific
|
||||
* parameters.
|
||||
|
@ -207,9 +207,9 @@ enum dvbfe_search {
|
|||
* @get_if_frequency: get the Intermediate Frequency, in Hz. For baseband,
|
||||
* should return 0.
|
||||
* @get_status: returns the frontend lock status
|
||||
* @get_rf_strength: returns the RF signal strengh. Used mostly to support
|
||||
* @get_rf_strength: returns the RF signal strength. Used mostly to support
|
||||
* analog TV and radio. Digital TV should report, instead,
|
||||
* via DVBv5 API (@dvb_frontend.dtv_property_cache;).
|
||||
* via DVBv5 API (&struct dvb_frontend.dtv_property_cache).
|
||||
* @get_afc: Used only by analog TV core. Reports the frequency
|
||||
* drift due to AFC.
|
||||
* @calc_regs: callback function used to pass register data settings
|
||||
|
@ -217,7 +217,7 @@ enum dvbfe_search {
|
|||
* @set_frequency: Set a new frequency. Shouldn't be used on newer drivers.
|
||||
* @set_bandwidth: Set a new frequency. Shouldn't be used on newer drivers.
|
||||
*
|
||||
* NOTE: frequencies used on get_frequency and set_frequency are in Hz for
|
||||
* NOTE: frequencies used on @get_frequency and @set_frequency are in Hz for
|
||||
* terrestrial/cable or kHz for satellite.
|
||||
*
|
||||
*/
|
||||
|
@ -283,14 +283,14 @@ struct analog_demod_info {
|
|||
* @set_params: callback function used to inform the demod to set the
|
||||
* demodulator parameters needed to decode an analog or
|
||||
* radio channel. The properties are passed via
|
||||
* struct @analog_params;.
|
||||
* &struct analog_params.
|
||||
* @has_signal: returns 0xffff if has signal, or 0 if it doesn't.
|
||||
* @get_afc: Used only by analog TV core. Reports the frequency
|
||||
* drift due to AFC.
|
||||
* @tuner_status: callback function that returns tuner status bits, e. g.
|
||||
* TUNER_STATUS_LOCKED and TUNER_STATUS_STEREO.
|
||||
* %TUNER_STATUS_LOCKED and %TUNER_STATUS_STEREO.
|
||||
* @standby: set the tuner to standby mode.
|
||||
* @release: callback function called when frontend is dettached.
|
||||
* @release: callback function called when frontend is detached.
|
||||
* drivers should free any allocated memory.
|
||||
* @i2c_gate_ctrl: controls the I2C gate. Newer drivers should use I2C
|
||||
* mux support instead.
|
||||
|
@ -321,10 +321,10 @@ struct dtv_frontend_properties;
|
|||
* struct dvb_frontend_ops - Demodulation information and callbacks for
|
||||
* ditialt TV
|
||||
*
|
||||
* @info: embedded struct dvb_tuner_info with tuner properties
|
||||
* @info: embedded &struct dvb_tuner_info with tuner properties
|
||||
* @delsys: Delivery systems supported by the frontend
|
||||
* @detach: callback function called when frontend is detached.
|
||||
* drivers should clean up, but not yet free the struct
|
||||
* drivers should clean up, but not yet free the &struct
|
||||
* dvb_frontend allocation.
|
||||
* @release: callback function called when frontend is ready to be
|
||||
* freed.
|
||||
|
@ -338,57 +338,57 @@ struct dtv_frontend_properties;
|
|||
* allow other drivers to write data into their registers.
|
||||
* Should not be used on new drivers.
|
||||
* @tune: callback function used by demod drivers that use
|
||||
* @DVBFE_ALGO_HW; to tune into a frequency.
|
||||
* @DVBFE_ALGO_HW to tune into a frequency.
|
||||
* @get_frontend_algo: returns the desired hardware algorithm.
|
||||
* @set_frontend: callback function used to inform the demod to set the
|
||||
* parameters for demodulating a digital TV channel.
|
||||
* The properties to be used are stored at
|
||||
* @dvb_frontend.dtv_property_cache;. The demod can change
|
||||
* The properties to be used are stored at &struct
|
||||
* dvb_frontend.dtv_property_cache. The demod can change
|
||||
* the parameters to reflect the changes needed for the
|
||||
* channel to be decoded, and update statistics.
|
||||
* @get_tune_settings: callback function
|
||||
* @get_frontend: callback function used to inform the parameters
|
||||
* actuall in use. The properties to be used are stored at
|
||||
* @dvb_frontend.dtv_property_cache; and update
|
||||
* &struct dvb_frontend.dtv_property_cache and update
|
||||
* statistics. Please notice that it should not return
|
||||
* an error code if the statistics are not available
|
||||
* because the demog is not locked.
|
||||
* @read_status: returns the locking status of the frontend.
|
||||
* @read_ber: legacy callback function to return the bit error rate.
|
||||
* Newer drivers should provide such info via DVBv5 API,
|
||||
* e. g. @set_frontend;/@get_frontend;, implementing this
|
||||
* e. g. @set_frontend;/@get_frontend, implementing this
|
||||
* callback only if DVBv3 API compatibility is wanted.
|
||||
* @read_signal_strength: legacy callback function to return the signal
|
||||
* strength. Newer drivers should provide such info via
|
||||
* DVBv5 API, e. g. @set_frontend;/@get_frontend;,
|
||||
* DVBv5 API, e. g. @set_frontend/@get_frontend,
|
||||
* implementing this callback only if DVBv3 API
|
||||
* compatibility is wanted.
|
||||
* @read_snr: legacy callback function to return the Signal/Noise
|
||||
* rate. Newer drivers should provide such info via
|
||||
* DVBv5 API, e. g. @set_frontend;/@get_frontend;,
|
||||
* DVBv5 API, e. g. @set_frontend/@get_frontend,
|
||||
* implementing this callback only if DVBv3 API
|
||||
* compatibility is wanted.
|
||||
* @read_ucblocks: legacy callback function to return the Uncorrected Error
|
||||
* Blocks. Newer drivers should provide such info via
|
||||
* DVBv5 API, e. g. @set_frontend;/@get_frontend;,
|
||||
* DVBv5 API, e. g. @set_frontend/@get_frontend,
|
||||
* implementing this callback only if DVBv3 API
|
||||
* compatibility is wanted.
|
||||
* @diseqc_reset_overload: callback function to implement the
|
||||
* FE_DISEQC_RESET_OVERLOAD ioctl (only Satellite)
|
||||
* FE_DISEQC_RESET_OVERLOAD() ioctl (only Satellite)
|
||||
* @diseqc_send_master_cmd: callback function to implement the
|
||||
* FE_DISEQC_SEND_MASTER_CMD ioctl (only Satellite).
|
||||
* FE_DISEQC_SEND_MASTER_CMD() ioctl (only Satellite).
|
||||
* @diseqc_recv_slave_reply: callback function to implement the
|
||||
* FE_DISEQC_RECV_SLAVE_REPLY ioctl (only Satellite)
|
||||
* FE_DISEQC_RECV_SLAVE_REPLY() ioctl (only Satellite)
|
||||
* @diseqc_send_burst: callback function to implement the
|
||||
* FE_DISEQC_SEND_BURST ioctl (only Satellite).
|
||||
* FE_DISEQC_SEND_BURST() ioctl (only Satellite).
|
||||
* @set_tone: callback function to implement the
|
||||
* FE_SET_TONE ioctl (only Satellite).
|
||||
* FE_SET_TONE() ioctl (only Satellite).
|
||||
* @set_voltage: callback function to implement the
|
||||
* FE_SET_VOLTAGE ioctl (only Satellite).
|
||||
* FE_SET_VOLTAGE() ioctl (only Satellite).
|
||||
* @enable_high_lnb_voltage: callback function to implement the
|
||||
* FE_ENABLE_HIGH_LNB_VOLTAGE ioctl (only Satellite).
|
||||
* FE_ENABLE_HIGH_LNB_VOLTAGE() ioctl (only Satellite).
|
||||
* @dishnetwork_send_legacy_command: callback function to implement the
|
||||
* FE_DISHNETWORK_SEND_LEGACY_CMD ioctl (only Satellite).
|
||||
* FE_DISHNETWORK_SEND_LEGACY_CMD() ioctl (only Satellite).
|
||||
* Drivers should not use this, except when the DVB
|
||||
* core emulation fails to provide proper support (e.g.
|
||||
* if @set_voltage takes more than 8ms to work), and
|
||||
|
@ -399,15 +399,10 @@ struct dtv_frontend_properties;
|
|||
* @ts_bus_ctrl: callback function used to take control of the TS bus.
|
||||
* @set_lna: callback function to power on/off/auto the LNA.
|
||||
* @search: callback function used on some custom algo search algos.
|
||||
* @tuner_ops: pointer to struct dvb_tuner_ops
|
||||
* @analog_ops: pointer to struct analog_demod_ops
|
||||
* @set_property: callback function to allow the frontend to validade
|
||||
* incoming properties. Should not be used on new drivers.
|
||||
* @get_property: callback function to allow the frontend to override
|
||||
* outcoming properties. Should not be used on new drivers.
|
||||
* @tuner_ops: pointer to &struct dvb_tuner_ops
|
||||
* @analog_ops: pointer to &struct analog_demod_ops
|
||||
*/
|
||||
struct dvb_frontend_ops {
|
||||
|
||||
struct dvb_frontend_info info;
|
||||
|
||||
u8 delsys[MAX_DELSYS];
|
||||
|
@ -466,9 +461,6 @@ struct dvb_frontend_ops {
|
|||
|
||||
struct dvb_tuner_ops tuner_ops;
|
||||
struct analog_demod_ops analog_ops;
|
||||
|
||||
int (*set_property)(struct dvb_frontend* fe, struct dtv_property* tvp);
|
||||
int (*get_property)(struct dvb_frontend* fe, struct dtv_property* tvp);
|
||||
};
|
||||
|
||||
#ifdef __DVB_CORE__
|
||||
|
@ -565,15 +557,15 @@ struct dtv_frontend_properties {
|
|||
|
||||
enum fe_sec_voltage voltage;
|
||||
enum fe_sec_tone_mode sectone;
|
||||
enum fe_spectral_inversion inversion;
|
||||
enum fe_code_rate fec_inner;
|
||||
enum fe_spectral_inversion inversion;
|
||||
enum fe_code_rate fec_inner;
|
||||
enum fe_transmit_mode transmission_mode;
|
||||
u32 bandwidth_hz; /* 0 = AUTO */
|
||||
enum fe_guard_interval guard_interval;
|
||||
enum fe_hierarchy hierarchy;
|
||||
enum fe_hierarchy hierarchy;
|
||||
u32 symbol_rate;
|
||||
enum fe_code_rate code_rate_HP;
|
||||
enum fe_code_rate code_rate_LP;
|
||||
enum fe_code_rate code_rate_HP;
|
||||
enum fe_code_rate code_rate_LP;
|
||||
|
||||
enum fe_pilot pilot;
|
||||
enum fe_rolloff rolloff;
|
||||
|
@ -628,11 +620,6 @@ struct dtv_frontend_properties {
|
|||
struct dtv_fe_stats post_bit_count;
|
||||
struct dtv_fe_stats block_error;
|
||||
struct dtv_fe_stats block_count;
|
||||
|
||||
/* private: */
|
||||
/* Cache State */
|
||||
u32 state;
|
||||
|
||||
};
|
||||
|
||||
#define DVB_FE_NO_EXIT 0
|
||||
|
@ -643,16 +630,16 @@ struct dtv_frontend_properties {
|
|||
/**
|
||||
* struct dvb_frontend - Frontend structure to be used on drivers.
|
||||
*
|
||||
* @refcount: refcount to keep track of struct dvb_frontend
|
||||
* @refcount: refcount to keep track of &struct dvb_frontend
|
||||
* references
|
||||
* @ops: embedded struct dvb_frontend_ops
|
||||
* @dvb: pointer to struct dvb_adapter
|
||||
* @ops: embedded &struct dvb_frontend_ops
|
||||
* @dvb: pointer to &struct dvb_adapter
|
||||
* @demodulator_priv: demod private data
|
||||
* @tuner_priv: tuner private data
|
||||
* @frontend_priv: frontend private data
|
||||
* @sec_priv: SEC private data
|
||||
* @analog_demod_priv: Analog demod private data
|
||||
* @dtv_property_cache: embedded struct dtv_frontend_properties
|
||||
* @dtv_property_cache: embedded &struct dtv_frontend_properties
|
||||
* @callback: callback function used on some drivers to call
|
||||
* either the tuner or the demodulator.
|
||||
* @id: Frontend ID
|
||||
|
@ -681,8 +668,8 @@ struct dvb_frontend {
|
|||
/**
|
||||
* dvb_register_frontend() - Registers a DVB frontend at the adapter
|
||||
*
|
||||
* @dvb: pointer to the dvb adapter
|
||||
* @fe: pointer to the frontend struct
|
||||
* @dvb: pointer to &struct dvb_adapter
|
||||
* @fe: pointer to &struct dvb_frontend
|
||||
*
|
||||
* Allocate and initialize the private data needed by the frontend core to
|
||||
* manage the frontend and calls dvb_register_device() to register a new
|
||||
|
@ -695,7 +682,7 @@ int dvb_register_frontend(struct dvb_adapter *dvb,
|
|||
/**
|
||||
* dvb_unregister_frontend() - Unregisters a DVB frontend
|
||||
*
|
||||
* @fe: pointer to the frontend struct
|
||||
* @fe: pointer to &struct dvb_frontend
|
||||
*
|
||||
* Stops the frontend kthread, calls dvb_unregister_device() and frees the
|
||||
* private frontend data allocated by dvb_register_frontend().
|
||||
|
@ -709,14 +696,14 @@ int dvb_unregister_frontend(struct dvb_frontend *fe);
|
|||
/**
|
||||
* dvb_frontend_detach() - Detaches and frees frontend specific data
|
||||
*
|
||||
* @fe: pointer to the frontend struct
|
||||
* @fe: pointer to &struct dvb_frontend
|
||||
*
|
||||
* This function should be called after dvb_unregister_frontend(). It
|
||||
* calls the SEC, tuner and demod release functions:
|
||||
* &dvb_frontend_ops.release_sec, &dvb_frontend_ops.tuner_ops.release,
|
||||
* &dvb_frontend_ops.analog_ops.release and &dvb_frontend_ops.release.
|
||||
*
|
||||
* If the driver is compiled with CONFIG_MEDIA_ATTACH, it also decreases
|
||||
* If the driver is compiled with %CONFIG_MEDIA_ATTACH, it also decreases
|
||||
* the module reference count, needed to allow userspace to remove the
|
||||
* previously used DVB frontend modules.
|
||||
*/
|
||||
|
@ -725,7 +712,7 @@ void dvb_frontend_detach(struct dvb_frontend *fe);
|
|||
/**
|
||||
* dvb_frontend_suspend() - Suspends a Digital TV frontend
|
||||
*
|
||||
* @fe: pointer to the frontend struct
|
||||
* @fe: pointer to &struct dvb_frontend
|
||||
*
|
||||
* This function prepares a Digital TV frontend to suspend.
|
||||
*
|
||||
|
@ -743,7 +730,7 @@ int dvb_frontend_suspend(struct dvb_frontend *fe);
|
|||
/**
|
||||
* dvb_frontend_resume() - Resumes a Digital TV frontend
|
||||
*
|
||||
* @fe: pointer to the frontend struct
|
||||
* @fe: pointer to &struct dvb_frontend
|
||||
*
|
||||
* This function resumes the usual operation of the tuner after resume.
|
||||
*
|
||||
|
@ -764,7 +751,7 @@ int dvb_frontend_resume(struct dvb_frontend *fe);
|
|||
/**
|
||||
* dvb_frontend_reinitialise() - forces a reinitialisation at the frontend
|
||||
*
|
||||
* @fe: pointer to the frontend struct
|
||||
* @fe: pointer to &struct dvb_frontend
|
||||
*
|
||||
* Calls &dvb_frontend_ops.init\(\) and &dvb_frontend_ops.tuner_ops.init\(\),
|
||||
* and resets SEC tone and voltage (for Satellite systems).
|
||||
|
@ -779,16 +766,16 @@ void dvb_frontend_reinitialise(struct dvb_frontend *fe);
|
|||
* dvb_frontend_sleep_until() - Sleep for the amount of time given by
|
||||
* add_usec parameter
|
||||
*
|
||||
* @waketime: pointer to a struct ktime_t
|
||||
* @waketime: pointer to &struct ktime_t
|
||||
* @add_usec: time to sleep, in microseconds
|
||||
*
|
||||
* This function is used to measure the time required for the
|
||||
* %FE_DISHNETWORK_SEND_LEGACY_CMD ioctl to work. It needs to be as precise
|
||||
* FE_DISHNETWORK_SEND_LEGACY_CMD() ioctl to work. It needs to be as precise
|
||||
* as possible, as it affects the detection of the dish tone command at the
|
||||
* satellite subsystem.
|
||||
*
|
||||
* Its used internally by the DVB frontend core, in order to emulate
|
||||
* %FE_DISHNETWORK_SEND_LEGACY_CMD using the &dvb_frontend_ops.set_voltage\(\)
|
||||
* FE_DISHNETWORK_SEND_LEGACY_CMD() using the &dvb_frontend_ops.set_voltage\(\)
|
||||
* callback.
|
||||
*
|
||||
* NOTE: it should not be used at the drivers, as the emulation for the
|
||||
|
|
|
@ -30,6 +30,22 @@
|
|||
|
||||
#ifdef CONFIG_DVB_NET
|
||||
|
||||
/**
|
||||
* struct dvb_net - describes a DVB network interface
|
||||
*
|
||||
* @dvbdev: pointer to &struct dvb_device.
|
||||
* @device: array of pointers to &struct net_device.
|
||||
* @state: array of integers to each net device. A value
|
||||
* different than zero means that the interface is
|
||||
* in usage.
|
||||
* @exit: flag to indicate when the device is being removed.
|
||||
* @demux: pointer to &struct dmx_demux.
|
||||
* @ioctl_mutex: protect access to this struct.
|
||||
*
|
||||
* Currently, the core supports up to %DVB_NET_DEVICES_MAX (10) network
|
||||
* devices.
|
||||
*/
|
||||
|
||||
struct dvb_net {
|
||||
struct dvb_device *dvbdev;
|
||||
struct net_device *device[DVB_NET_DEVICES_MAX];
|
||||
|
@ -39,8 +55,22 @@ struct dvb_net {
|
|||
struct mutex ioctl_mutex;
|
||||
};
|
||||
|
||||
void dvb_net_release(struct dvb_net *);
|
||||
int dvb_net_init(struct dvb_adapter *, struct dvb_net *, struct dmx_demux *);
|
||||
/**
|
||||
* dvb_net_init - nitializes a digital TV network device and registers it.
|
||||
*
|
||||
* @adap: pointer to &struct dvb_adapter.
|
||||
* @dvbnet: pointer to &struct dvb_net.
|
||||
* @dmxdemux: pointer to &struct dmx_demux.
|
||||
*/
|
||||
int dvb_net_init(struct dvb_adapter *adap, struct dvb_net *dvbnet,
|
||||
struct dmx_demux *dmxdemux);
|
||||
|
||||
/**
|
||||
* dvb_net_release - releases a digital TV network device and unregisters it.
|
||||
*
|
||||
* @dvbnet: pointer to &struct dvb_net.
|
||||
*/
|
||||
void dvb_net_release(struct dvb_net *dvbnet);
|
||||
|
||||
#else
|
||||
|
||||
|
|
|
@ -51,8 +51,15 @@ static LIST_HEAD(dvb_adapter_list);
|
|||
static DEFINE_MUTEX(dvbdev_register_lock);
|
||||
|
||||
static const char * const dnames[] = {
|
||||
"video", "audio", "sec", "frontend", "demux", "dvr", "ca",
|
||||
"net", "osd"
|
||||
[DVB_DEVICE_VIDEO] = "video",
|
||||
[DVB_DEVICE_AUDIO] = "audio",
|
||||
[DVB_DEVICE_SEC] = "sec",
|
||||
[DVB_DEVICE_FRONTEND] = "frontend",
|
||||
[DVB_DEVICE_DEMUX] = "demux",
|
||||
[DVB_DEVICE_DVR] = "dvr",
|
||||
[DVB_DEVICE_CA] = "ca",
|
||||
[DVB_DEVICE_NET] = "net",
|
||||
[DVB_DEVICE_OSD] = "osd"
|
||||
};
|
||||
|
||||
#ifdef CONFIG_DVB_DYNAMIC_MINORS
|
||||
|
@ -60,7 +67,22 @@ static const char * const dnames[] = {
|
|||
#define DVB_MAX_IDS MAX_DVB_MINORS
|
||||
#else
|
||||
#define DVB_MAX_IDS 4
|
||||
#define nums2minor(num, type, id) ((num << 6) | (id << 4) | type)
|
||||
|
||||
static const u8 minor_type[] = {
|
||||
[DVB_DEVICE_VIDEO] = 0,
|
||||
[DVB_DEVICE_AUDIO] = 1,
|
||||
[DVB_DEVICE_SEC] = 2,
|
||||
[DVB_DEVICE_FRONTEND] = 3,
|
||||
[DVB_DEVICE_DEMUX] = 4,
|
||||
[DVB_DEVICE_DVR] = 5,
|
||||
[DVB_DEVICE_CA] = 6,
|
||||
[DVB_DEVICE_NET] = 7,
|
||||
[DVB_DEVICE_OSD] = 8,
|
||||
};
|
||||
|
||||
#define nums2minor(num, type, id) \
|
||||
(((num) << 6) | ((id) << 4) | minor_type[type])
|
||||
|
||||
#define MAX_DVB_MINORS (DVB_MAX_ADAPTERS*64)
|
||||
#endif
|
||||
|
||||
|
@ -426,8 +448,8 @@ static int dvb_register_media_device(struct dvb_device *dvbdev,
|
|||
}
|
||||
|
||||
int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
|
||||
const struct dvb_device *template, void *priv, int type,
|
||||
int demux_sink_pads)
|
||||
const struct dvb_device *template, void *priv,
|
||||
enum dvb_device_type type, int demux_sink_pads)
|
||||
{
|
||||
struct dvb_device *dvbdev;
|
||||
struct file_operations *dvbdevfops;
|
||||
|
|
|
@ -35,15 +35,37 @@
|
|||
|
||||
#define DVB_UNSET (-1)
|
||||
|
||||
#define DVB_DEVICE_VIDEO 0
|
||||
#define DVB_DEVICE_AUDIO 1
|
||||
#define DVB_DEVICE_SEC 2
|
||||
#define DVB_DEVICE_FRONTEND 3
|
||||
#define DVB_DEVICE_DEMUX 4
|
||||
#define DVB_DEVICE_DVR 5
|
||||
#define DVB_DEVICE_CA 6
|
||||
#define DVB_DEVICE_NET 7
|
||||
#define DVB_DEVICE_OSD 8
|
||||
/* List of DVB device types */
|
||||
|
||||
/**
|
||||
* enum dvb_device_type - type of the Digital TV device
|
||||
*
|
||||
* @DVB_DEVICE_SEC: Digital TV standalone Common Interface (CI)
|
||||
* @DVB_DEVICE_FRONTEND: Digital TV frontend.
|
||||
* @DVB_DEVICE_DEMUX: Digital TV demux.
|
||||
* @DVB_DEVICE_DVR: Digital TV digital video record (DVR).
|
||||
* @DVB_DEVICE_CA: Digital TV Conditional Access (CA).
|
||||
* @DVB_DEVICE_NET: Digital TV network.
|
||||
*
|
||||
* @DVB_DEVICE_VIDEO: Digital TV video decoder.
|
||||
* Deprecated. Used only on av7110-av.
|
||||
* @DVB_DEVICE_AUDIO: Digital TV audio decoder.
|
||||
* Deprecated. Used only on av7110-av.
|
||||
* @DVB_DEVICE_OSD: Digital TV On Screen Display (OSD).
|
||||
* Deprecated. Used only on av7110.
|
||||
*/
|
||||
enum dvb_device_type {
|
||||
DVB_DEVICE_SEC,
|
||||
DVB_DEVICE_FRONTEND,
|
||||
DVB_DEVICE_DEMUX,
|
||||
DVB_DEVICE_DVR,
|
||||
DVB_DEVICE_CA,
|
||||
DVB_DEVICE_NET,
|
||||
|
||||
DVB_DEVICE_VIDEO,
|
||||
DVB_DEVICE_AUDIO,
|
||||
DVB_DEVICE_OSD,
|
||||
};
|
||||
|
||||
#define DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr) \
|
||||
static short adapter_nr[] = \
|
||||
|
@ -104,8 +126,7 @@ struct dvb_adapter {
|
|||
* @list_head: List head with all DVB devices
|
||||
* @fops: pointer to struct file_operations
|
||||
* @adapter: pointer to the adapter that holds this device node
|
||||
* @type: type of the device: DVB_DEVICE_SEC, DVB_DEVICE_FRONTEND,
|
||||
* DVB_DEVICE_DEMUX, DVB_DEVICE_DVR, DVB_DEVICE_CA, DVB_DEVICE_NET
|
||||
* @type: type of the device, as defined by &enum dvb_device_type.
|
||||
* @minor: devnode minor number. Major number is always DVB_MAJOR.
|
||||
* @id: device ID number, inside the adapter
|
||||
* @readers: Initialized by the caller. Each call to open() in Read Only mode
|
||||
|
@ -135,7 +156,7 @@ struct dvb_device {
|
|||
struct list_head list_head;
|
||||
const struct file_operations *fops;
|
||||
struct dvb_adapter *adapter;
|
||||
int type;
|
||||
enum dvb_device_type type;
|
||||
int minor;
|
||||
u32 id;
|
||||
|
||||
|
@ -194,9 +215,7 @@ int dvb_unregister_adapter(struct dvb_adapter *adap);
|
|||
* stored
|
||||
* @template: Template used to create &pdvbdev;
|
||||
* @priv: private data
|
||||
* @type: type of the device: %DVB_DEVICE_SEC, %DVB_DEVICE_FRONTEND,
|
||||
* %DVB_DEVICE_DEMUX, %DVB_DEVICE_DVR, %DVB_DEVICE_CA,
|
||||
* %DVB_DEVICE_NET
|
||||
* @type: type of the device, as defined by &enum dvb_device_type.
|
||||
* @demux_sink_pads: Number of demux outputs, to be used to create the TS
|
||||
* outputs via the Media Controller.
|
||||
*/
|
||||
|
@ -204,7 +223,7 @@ int dvb_register_device(struct dvb_adapter *adap,
|
|||
struct dvb_device **pdvbdev,
|
||||
const struct dvb_device *template,
|
||||
void *priv,
|
||||
int type,
|
||||
enum dvb_device_type type,
|
||||
int demux_sink_pads);
|
||||
|
||||
/**
|
||||
|
@ -242,7 +261,7 @@ void dvb_unregister_device(struct dvb_device *dvbdev);
|
|||
* dvb_create_media_graph - Creates media graph for the Digital TV part of the
|
||||
* device.
|
||||
*
|
||||
* @adap: pointer to struct dvb_adapter
|
||||
* @adap: pointer to &struct dvb_adapter
|
||||
* @create_rf_connector: if true, it creates the RF connector too
|
||||
*
|
||||
* This function checks all DVB-related functions at the media controller
|
||||
|
@ -255,12 +274,23 @@ void dvb_unregister_device(struct dvb_device *dvbdev);
|
|||
__must_check int dvb_create_media_graph(struct dvb_adapter *adap,
|
||||
bool create_rf_connector);
|
||||
|
||||
/**
|
||||
* dvb_register_media_controller - registers a media controller at DVB adapter
|
||||
*
|
||||
* @adap: pointer to &struct dvb_adapter
|
||||
* @mdev: pointer to &struct media_device
|
||||
*/
|
||||
static inline void dvb_register_media_controller(struct dvb_adapter *adap,
|
||||
struct media_device *mdev)
|
||||
{
|
||||
adap->mdev = mdev;
|
||||
}
|
||||
|
||||
/**
|
||||
* dvb_get_media_controller - gets the associated media controller
|
||||
*
|
||||
* @adap: pointer to &struct dvb_adapter
|
||||
*/
|
||||
static inline struct media_device
|
||||
*dvb_get_media_controller(struct dvb_adapter *adap)
|
||||
{
|
||||
|
@ -277,20 +307,71 @@ int dvb_create_media_graph(struct dvb_adapter *adap,
|
|||
#define dvb_get_media_controller(a) NULL
|
||||
#endif
|
||||
|
||||
int dvb_generic_open (struct inode *inode, struct file *file);
|
||||
int dvb_generic_release (struct inode *inode, struct file *file);
|
||||
long dvb_generic_ioctl (struct file *file,
|
||||
unsigned int cmd, unsigned long arg);
|
||||
/**
|
||||
* dvb_generic_open - Digital TV open function, used by DVB devices
|
||||
*
|
||||
* @inode: pointer to &struct inode.
|
||||
* @file: pointer to &struct file.
|
||||
*
|
||||
* Checks if a DVB devnode is still valid, and if the permissions are
|
||||
* OK and increment negative use count.
|
||||
*/
|
||||
int dvb_generic_open(struct inode *inode, struct file *file);
|
||||
|
||||
/* we don't mess with video_usercopy() any more,
|
||||
we simply define out own dvb_usercopy(), which will hopefully become
|
||||
generic_usercopy() someday... */
|
||||
/**
|
||||
* dvb_generic_close - Digital TV close function, used by DVB devices
|
||||
*
|
||||
* @inode: pointer to &struct inode.
|
||||
* @file: pointer to &struct file.
|
||||
*
|
||||
* Checks if a DVB devnode is still valid, and if the permissions are
|
||||
* OK and decrement negative use count.
|
||||
*/
|
||||
int dvb_generic_release(struct inode *inode, struct file *file);
|
||||
|
||||
/**
|
||||
* dvb_generic_ioctl - Digital TV close function, used by DVB devices
|
||||
*
|
||||
* @file: pointer to &struct file.
|
||||
* @cmd: Ioctl name.
|
||||
* @arg: Ioctl argument.
|
||||
*
|
||||
* Checks if a DVB devnode and struct dvbdev.kernel_ioctl is still valid.
|
||||
* If so, calls dvb_usercopy().
|
||||
*/
|
||||
long dvb_generic_ioctl(struct file *file,
|
||||
unsigned int cmd, unsigned long arg);
|
||||
|
||||
/**
|
||||
* dvb_usercopy - copies data from/to userspace memory when an ioctl is
|
||||
* issued.
|
||||
*
|
||||
* @file: Pointer to struct &file.
|
||||
* @cmd: Ioctl name.
|
||||
* @arg: Ioctl argument.
|
||||
* @func: function that will actually handle the ioctl
|
||||
*
|
||||
* Ancillary function that uses ioctl direction and size to copy from
|
||||
* userspace. Then, it calls @func, and, if needed, data is copied back
|
||||
* to userspace.
|
||||
*/
|
||||
int dvb_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
|
||||
int (*func)(struct file *file, unsigned int cmd, void *arg));
|
||||
|
||||
/** generic DVB attach function. */
|
||||
#ifdef CONFIG_MEDIA_ATTACH
|
||||
|
||||
/**
|
||||
* dvb_attach - attaches a DVB frontend into the DVB core.
|
||||
*
|
||||
* @FUNCTION: function on a frontend module to be called.
|
||||
* @ARGS...: @FUNCTION arguments.
|
||||
*
|
||||
* This ancillary function loads a frontend module in runtime and runs
|
||||
* the @FUNCTION function there, with @ARGS.
|
||||
* As it increments symbol usage cont, at unregister, dvb_detach()
|
||||
* should be called.
|
||||
*/
|
||||
#define dvb_attach(FUNCTION, ARGS...) ({ \
|
||||
void *__r = NULL; \
|
||||
typeof(&FUNCTION) __a = symbol_request(FUNCTION); \
|
||||
|
@ -304,6 +385,14 @@ int dvb_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
|
|||
__r; \
|
||||
})
|
||||
|
||||
/**
|
||||
* dvb_detach - detaches a DVB frontend loaded via dvb_attach()
|
||||
*
|
||||
* @FUNC: attach function
|
||||
*
|
||||
* Decrements usage count for a function previously called via dvb_attach().
|
||||
*/
|
||||
|
||||
#define dvb_detach(FUNC) symbol_put_addr(FUNC)
|
||||
|
||||
#else
|
||||
|
|
|
@ -173,7 +173,7 @@ config DVB_STB6000
|
|||
tristate "ST STB6000 silicon tuner"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
help
|
||||
A DVB-S silicon tuner module. Say Y when you want to support this tuner.
|
||||
|
||||
config DVB_STV0299
|
||||
|
@ -187,7 +187,7 @@ config DVB_STV6110
|
|||
tristate "ST STV6110 silicon tuner"
|
||||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
help
|
||||
A DVB-S silicon tuner module. Say Y when you want to support this tuner.
|
||||
|
||||
config DVB_STV0900
|
||||
|
@ -902,7 +902,7 @@ config DVB_HELENE
|
|||
depends on DVB_CORE && I2C
|
||||
default m if !MEDIA_SUBDRV_AUTOSELECT
|
||||
help
|
||||
Say Y when you want to support this frontend.
|
||||
Say Y when you want to support this frontend.
|
||||
|
||||
comment "Tools to develop new frontends"
|
||||
|
||||
|
|
|
@ -455,11 +455,10 @@ struct dvb_frontend *as102_attach(const char *name,
|
|||
struct as102_state *state;
|
||||
struct dvb_frontend *fe;
|
||||
|
||||
state = kzalloc(sizeof(struct as102_state), GFP_KERNEL);
|
||||
if (state == NULL) {
|
||||
pr_err("%s: unable to allocate memory for state\n", __func__);
|
||||
state = kzalloc(sizeof(*state), GFP_KERNEL);
|
||||
if (!state)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fe = &state->frontend;
|
||||
fe->demodulator_priv = state;
|
||||
state->ops = ops;
|
||||
|
|
|
@ -552,13 +552,11 @@ struct dvb_frontend *cx24113_attach(struct dvb_frontend *fe,
|
|||
const struct cx24113_config *config, struct i2c_adapter *i2c)
|
||||
{
|
||||
/* allocate memory for the internal state */
|
||||
struct cx24113_state *state =
|
||||
kzalloc(sizeof(struct cx24113_state), GFP_KERNEL);
|
||||
struct cx24113_state *state = kzalloc(sizeof(*state), GFP_KERNEL);
|
||||
int rc;
|
||||
if (state == NULL) {
|
||||
cx_err("Unable to kzalloc\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (!state)
|
||||
return NULL;
|
||||
|
||||
/* setup the state */
|
||||
state->config = config;
|
||||
|
|
|
@ -221,16 +221,13 @@ static int cx24116_writereg(struct cx24116_state *state, int reg, int data)
|
|||
static int cx24116_writeregN(struct cx24116_state *state, int reg,
|
||||
const u8 *data, u16 len)
|
||||
{
|
||||
int ret = -EREMOTEIO;
|
||||
int ret;
|
||||
struct i2c_msg msg;
|
||||
u8 *buf;
|
||||
|
||||
buf = kmalloc(len + 1, GFP_KERNEL);
|
||||
if (buf == NULL) {
|
||||
printk("Unable to kmalloc\n");
|
||||
ret = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
*(buf) = reg;
|
||||
memcpy(buf + 1, data, len);
|
||||
|
@ -251,7 +248,6 @@ static int cx24116_writeregN(struct cx24116_state *state, int reg,
|
|||
ret = -EREMOTEIO;
|
||||
}
|
||||
|
||||
error:
|
||||
kfree(buf);
|
||||
|
||||
return ret;
|
||||
|
@ -1121,15 +1117,15 @@ static const struct dvb_frontend_ops cx24116_ops;
|
|||
struct dvb_frontend *cx24116_attach(const struct cx24116_config *config,
|
||||
struct i2c_adapter *i2c)
|
||||
{
|
||||
struct cx24116_state *state = NULL;
|
||||
struct cx24116_state *state;
|
||||
int ret;
|
||||
|
||||
dprintk("%s\n", __func__);
|
||||
|
||||
/* allocate memory for the internal state */
|
||||
state = kzalloc(sizeof(struct cx24116_state), GFP_KERNEL);
|
||||
state = kzalloc(sizeof(*state), GFP_KERNEL);
|
||||
if (state == NULL)
|
||||
goto error1;
|
||||
return NULL;
|
||||
|
||||
state->config = config;
|
||||
state->i2c = i2c;
|
||||
|
@ -1138,8 +1134,9 @@ struct dvb_frontend *cx24116_attach(const struct cx24116_config *config,
|
|||
ret = (cx24116_readreg(state, 0xFF) << 8) |
|
||||
cx24116_readreg(state, 0xFE);
|
||||
if (ret != 0x0501) {
|
||||
kfree(state);
|
||||
printk(KERN_INFO "Invalid probe, probably not a CX24116 device\n");
|
||||
goto error2;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* create dvb_frontend */
|
||||
|
@ -1147,9 +1144,6 @@ struct dvb_frontend *cx24116_attach(const struct cx24116_config *config,
|
|||
sizeof(struct dvb_frontend_ops));
|
||||
state->frontend.demodulator_priv = state;
|
||||
return &state->frontend;
|
||||
|
||||
error2: kfree(state);
|
||||
error1: return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(cx24116_attach);
|
||||
|
||||
|
|
|
@ -328,7 +328,7 @@ static int WriteTable(struct drxd_state *state, u8 * pTable)
|
|||
{
|
||||
int status = 0;
|
||||
|
||||
if (pTable == NULL)
|
||||
if (!pTable)
|
||||
return 0;
|
||||
|
||||
while (!status) {
|
||||
|
@ -640,7 +640,7 @@ static int SetCfgIfAgc(struct drxd_state *state, struct SCfgAgc *cfg)
|
|||
const u16 maxRur = 8;
|
||||
static const u16 slowIncrDecLUT[] = {
|
||||
3, 4, 4, 5, 6 };
|
||||
const u16 fastIncrDecLUT[] = {
|
||||
static const u16 fastIncrDecLUT[] = {
|
||||
14, 15, 15, 16,
|
||||
17, 18, 18, 19,
|
||||
20, 21, 22, 23,
|
||||
|
@ -909,9 +909,8 @@ static int load_firmware(struct drxd_state *state, const char *fw_name)
|
|||
}
|
||||
|
||||
state->microcode = kmemdup(fw->data, fw->size, GFP_KERNEL);
|
||||
if (state->microcode == NULL) {
|
||||
if (!state->microcode) {
|
||||
release_firmware(fw);
|
||||
printk(KERN_ERR "drxd: firmware load failure: no memory\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
|
@ -2630,7 +2629,7 @@ static int DRXD_init(struct drxd_state *state, const u8 *fw, u32 fw_size)
|
|||
break;
|
||||
|
||||
/* Apply I2c address patch to B1 */
|
||||
if (!state->type_A && state->m_HiI2cPatch != NULL) {
|
||||
if (!state->type_A && state->m_HiI2cPatch) {
|
||||
status = WriteTable(state, state->m_HiI2cPatch);
|
||||
if (status < 0)
|
||||
break;
|
||||
|
|
|
@ -277,10 +277,8 @@ static int ds3000_writeFW(struct ds3000_state *state, int reg,
|
|||
u8 *buf;
|
||||
|
||||
buf = kmalloc(33, GFP_KERNEL);
|
||||
if (buf == NULL) {
|
||||
printk(KERN_ERR "Unable to kmalloc\n");
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
*(buf) = reg;
|
||||
|
||||
|
@ -835,17 +833,15 @@ static const struct dvb_frontend_ops ds3000_ops;
|
|||
struct dvb_frontend *ds3000_attach(const struct ds3000_config *config,
|
||||
struct i2c_adapter *i2c)
|
||||
{
|
||||
struct ds3000_state *state = NULL;
|
||||
struct ds3000_state *state;
|
||||
int ret;
|
||||
|
||||
dprintk("%s\n", __func__);
|
||||
|
||||
/* allocate memory for the internal state */
|
||||
state = kzalloc(sizeof(struct ds3000_state), GFP_KERNEL);
|
||||
if (state == NULL) {
|
||||
printk(KERN_ERR "Unable to kmalloc\n");
|
||||
goto error2;
|
||||
}
|
||||
state = kzalloc(sizeof(*state), GFP_KERNEL);
|
||||
if (!state)
|
||||
return NULL;
|
||||
|
||||
state->config = config;
|
||||
state->i2c = i2c;
|
||||
|
@ -854,8 +850,9 @@ struct dvb_frontend *ds3000_attach(const struct ds3000_config *config,
|
|||
/* check if the demod is present */
|
||||
ret = ds3000_readreg(state, 0x00) & 0xfe;
|
||||
if (ret != 0xe0) {
|
||||
kfree(state);
|
||||
printk(KERN_ERR "Invalid probe, probably not a DS3000\n");
|
||||
goto error3;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
printk(KERN_INFO "DS3000 chip version: %d.%d attached.\n",
|
||||
|
@ -873,11 +870,6 @@ struct dvb_frontend *ds3000_attach(const struct ds3000_config *config,
|
|||
*/
|
||||
ds3000_set_voltage(&state->frontend, SEC_VOLTAGE_OFF);
|
||||
return &state->frontend;
|
||||
|
||||
error3:
|
||||
kfree(state);
|
||||
error2:
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(ds3000_attach);
|
||||
|
||||
|
|
|
@ -1048,16 +1048,6 @@ static int lg216x_get_frontend(struct dvb_frontend *fe,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int lg216x_get_property(struct dvb_frontend *fe,
|
||||
struct dtv_property *tvp)
|
||||
{
|
||||
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
|
||||
|
||||
return (DTV_ATSCMH_FIC_VER == tvp->cmd) ?
|
||||
lg216x_get_frontend(fe, c) : 0;
|
||||
}
|
||||
|
||||
|
||||
static int lg2160_set_frontend(struct dvb_frontend *fe)
|
||||
{
|
||||
struct lg216x_state *state = fe->demodulator_priv;
|
||||
|
@ -1368,8 +1358,6 @@ static const struct dvb_frontend_ops lg2160_ops = {
|
|||
.init = lg216x_init,
|
||||
.sleep = lg216x_sleep,
|
||||
#endif
|
||||
.get_property = lg216x_get_property,
|
||||
|
||||
.set_frontend = lg2160_set_frontend,
|
||||
.get_frontend = lg216x_get_frontend,
|
||||
.get_tune_settings = lg216x_get_tune_settings,
|
||||
|
@ -1396,8 +1384,6 @@ static const struct dvb_frontend_ops lg2161_ops = {
|
|||
.init = lg216x_init,
|
||||
.sleep = lg216x_sleep,
|
||||
#endif
|
||||
.get_property = lg216x_get_property,
|
||||
|
||||
.set_frontend = lg2160_set_frontend,
|
||||
.get_frontend = lg216x_get_frontend,
|
||||
.get_tune_settings = lg216x_get_tune_settings,
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <asm/div64.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/dvb/frontend.h>
|
||||
#include "dvb_math.h"
|
||||
#include "lgdt3306a.h"
|
||||
|
@ -2072,7 +2073,7 @@ static const short regtab[] = {
|
|||
0x30aa, /* MPEGLOCK */
|
||||
};
|
||||
|
||||
#define numDumpRegs (sizeof(regtab)/sizeof(regtab[0]))
|
||||
#define numDumpRegs (ARRAY_SIZE(regtab))
|
||||
static u8 regval1[numDumpRegs] = {0, };
|
||||
static u8 regval2[numDumpRegs] = {0, };
|
||||
|
||||
|
|
|
@ -2071,12 +2071,9 @@ struct dvb_frontend *mb86a20s_attach(const struct mb86a20s_config *config,
|
|||
dev_dbg(&i2c->dev, "%s called.\n", __func__);
|
||||
|
||||
/* allocate memory for the internal state */
|
||||
state = kzalloc(sizeof(struct mb86a20s_state), GFP_KERNEL);
|
||||
if (state == NULL) {
|
||||
dev_err(&i2c->dev,
|
||||
"%s: unable to allocate memory for state\n", __func__);
|
||||
goto error;
|
||||
}
|
||||
state = kzalloc(sizeof(*state), GFP_KERNEL);
|
||||
if (!state)
|
||||
return NULL;
|
||||
|
||||
/* setup the state */
|
||||
state->config = config;
|
||||
|
@ -2089,22 +2086,16 @@ struct dvb_frontend *mb86a20s_attach(const struct mb86a20s_config *config,
|
|||
|
||||
/* Check if it is a mb86a20s frontend */
|
||||
rev = mb86a20s_readreg(state, 0);
|
||||
|
||||
if (rev == 0x13) {
|
||||
dev_info(&i2c->dev,
|
||||
"Detected a Fujitsu mb86a20s frontend\n");
|
||||
} else {
|
||||
if (rev != 0x13) {
|
||||
kfree(state);
|
||||
dev_dbg(&i2c->dev,
|
||||
"Frontend revision %d is unknown - aborting.\n",
|
||||
rev);
|
||||
goto error;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dev_info(&i2c->dev, "Detected a Fujitsu mb86a20s frontend\n");
|
||||
return &state->frontend;
|
||||
|
||||
error:
|
||||
kfree(state);
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(mb86a20s_attach);
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@
|
|||
#define BYTE2(v) ((v >> 16) & 0xff)
|
||||
#define BYTE3(v) ((v >> 24) & 0xff)
|
||||
|
||||
LIST_HEAD(mxllist);
|
||||
static LIST_HEAD(mxllist);
|
||||
|
||||
struct mxl_base {
|
||||
struct list_head mxllist;
|
||||
|
|
|
@ -696,7 +696,6 @@ static int si2168_probe(struct i2c_client *client,
|
|||
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
|
||||
if (!dev) {
|
||||
ret = -ENOMEM;
|
||||
dev_err(&client->dev, "kzalloc() failed\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
|
|
|
@ -357,14 +357,14 @@ static int sp2_exit(struct i2c_client *client)
|
|||
|
||||
dev_dbg(&client->dev, "\n");
|
||||
|
||||
if (client == NULL)
|
||||
if (!client)
|
||||
return 0;
|
||||
|
||||
s = i2c_get_clientdata(client);
|
||||
if (s == NULL)
|
||||
if (!s)
|
||||
return 0;
|
||||
|
||||
if (s->ca.data == NULL)
|
||||
if (!s->ca.data)
|
||||
return 0;
|
||||
|
||||
dvb_ca_en50221_release(&s->ca);
|
||||
|
@ -381,10 +381,9 @@ static int sp2_probe(struct i2c_client *client,
|
|||
|
||||
dev_dbg(&client->dev, "\n");
|
||||
|
||||
s = kzalloc(sizeof(struct sp2), GFP_KERNEL);
|
||||
s = kzalloc(sizeof(*s), GFP_KERNEL);
|
||||
if (!s) {
|
||||
ret = -ENOMEM;
|
||||
dev_err(&client->dev, "kzalloc() failed\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
|
|
|
@ -447,12 +447,6 @@ static int stv0288_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int stv0288_set_property(struct dvb_frontend *fe, struct dtv_property *p)
|
||||
{
|
||||
dprintk("%s(..)\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stv0288_set_frontend(struct dvb_frontend *fe)
|
||||
{
|
||||
struct stv0288_state *state = fe->demodulator_priv;
|
||||
|
@ -567,7 +561,6 @@ static const struct dvb_frontend_ops stv0288_ops = {
|
|||
.set_tone = stv0288_set_tone,
|
||||
.set_voltage = stv0288_set_voltage,
|
||||
|
||||
.set_property = stv0288_set_property,
|
||||
.set_frontend = stv0288_set_frontend,
|
||||
};
|
||||
|
||||
|
|
|
@ -258,11 +258,9 @@ static int stv6110_get_frequency(struct dvb_frontend *fe, u32 *frequency)
|
|||
static int stv6110_set_frequency(struct dvb_frontend *fe, u32 frequency)
|
||||
{
|
||||
struct stv6110_priv *priv = fe->tuner_priv;
|
||||
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
|
||||
u8 ret = 0x04;
|
||||
u32 divider, ref, p, presc, i, result_freq, vco_freq;
|
||||
s32 p_calc, p_calc_opt = 1000, r_div, r_div_opt = 0, p_val;
|
||||
s32 srate;
|
||||
|
||||
dprintk("%s, freq=%d kHz, mclk=%d Hz\n", __func__,
|
||||
frequency, priv->mclk);
|
||||
|
@ -273,13 +271,6 @@ static int stv6110_set_frequency(struct dvb_frontend *fe, u32 frequency)
|
|||
((((priv->mclk / 1000000) - 16) & 0x1f) << 3);
|
||||
|
||||
/* BB_GAIN = db/2 */
|
||||
if (fe->ops.set_property && fe->ops.get_property) {
|
||||
srate = c->symbol_rate;
|
||||
dprintk("%s: Get Frontend parameters: srate=%d\n",
|
||||
__func__, srate);
|
||||
} else
|
||||
srate = 15000000;
|
||||
|
||||
priv->regs[RSTV6110_CTRL2] &= ~0x0f;
|
||||
priv->regs[RSTV6110_CTRL2] |= (priv->gain & 0x0f);
|
||||
|
||||
|
|
|
@ -354,6 +354,14 @@ config VIDEO_TC358743
|
|||
To compile this driver as a module, choose M here: the
|
||||
module will be called tc358743.
|
||||
|
||||
config VIDEO_TC358743_CEC
|
||||
bool "Enable Toshiba TC358743 CEC support"
|
||||
depends on VIDEO_TC358743
|
||||
select CEC_CORE
|
||||
---help---
|
||||
When selected the tc358743 will support the optional
|
||||
HDMI CEC feature.
|
||||
|
||||
config VIDEO_TVP514X
|
||||
tristate "Texas Instruments TVP514x video decoder"
|
||||
depends on VIDEO_V4L2 && I2C
|
||||
|
@ -547,6 +555,14 @@ config VIDEO_APTINA_PLL
|
|||
config VIDEO_SMIAPP_PLL
|
||||
tristate
|
||||
|
||||
config VIDEO_IMX274
|
||||
tristate "Sony IMX274 sensor support"
|
||||
depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
|
||||
depends on MEDIA_CAMERA_SUPPORT
|
||||
---help---
|
||||
This is a V4L2 sensor-level driver for the Sony IMX274
|
||||
CMOS image sensor.
|
||||
|
||||
config VIDEO_OV2640
|
||||
tristate "OmniVision OV2640 sensor support"
|
||||
depends on VIDEO_V4L2 && I2C
|
||||
|
|
|
@ -93,5 +93,6 @@ obj-$(CONFIG_VIDEO_IR_I2C) += ir-kbd-i2c.o
|
|||
obj-$(CONFIG_VIDEO_ML86V7667) += ml86v7667.o
|
||||
obj-$(CONFIG_VIDEO_OV2659) += ov2659.o
|
||||
obj-$(CONFIG_VIDEO_TC358743) += tc358743.o
|
||||
obj-$(CONFIG_VIDEO_IMX274) += imx274.o
|
||||
|
||||
obj-$(CONFIG_SDR_MAX2175) += max2175.o
|
||||
|
|
|
@ -1328,7 +1328,7 @@ static int adv7180_probe(struct i2c_client *client,
|
|||
state->input = 0;
|
||||
sd = &state->sd;
|
||||
v4l2_i2c_subdev_init(sd, client, &adv7180_ops);
|
||||
sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS;
|
||||
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS;
|
||||
|
||||
ret = adv7180_init_controls(state);
|
||||
if (ret)
|
||||
|
|
|
@ -217,6 +217,7 @@ static int adv748x_afe_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
|
|||
{
|
||||
struct adv748x_afe *afe = adv748x_sd_to_afe(sd);
|
||||
struct adv748x_state *state = adv748x_afe_to_state(afe);
|
||||
int afe_std;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&state->mutex);
|
||||
|
@ -235,8 +236,12 @@ static int adv748x_afe_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
|
|||
/* Read detected standard */
|
||||
ret = adv748x_afe_status(afe, NULL, std);
|
||||
|
||||
afe_std = adv748x_afe_std(afe->curr_norm);
|
||||
if (afe_std < 0)
|
||||
goto unlock;
|
||||
|
||||
/* Restore original state */
|
||||
adv748x_afe_set_video_standard(state, afe->curr_norm);
|
||||
adv748x_afe_set_video_standard(state, afe_std);
|
||||
|
||||
unlock:
|
||||
mutex_unlock(&state->mutex);
|
||||
|
|
|
@ -1948,7 +1948,7 @@ static int adv76xx_set_format(struct v4l2_subdev *sd,
|
|||
return -EINVAL;
|
||||
|
||||
info = adv76xx_format_info(state, format->format.code);
|
||||
if (info == NULL)
|
||||
if (!info)
|
||||
info = adv76xx_format_info(state, MEDIA_BUS_FMT_YUYV8_2X8);
|
||||
|
||||
adv76xx_fill_format(state, &format->format);
|
||||
|
@ -2256,7 +2256,7 @@ static int adv76xx_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (data == NULL)
|
||||
if (!data)
|
||||
return -ENODATA;
|
||||
|
||||
if (edid->start_block >= state->edid.blocks)
|
||||
|
@ -3316,10 +3316,8 @@ static int adv76xx_probe(struct i2c_client *client,
|
|||
client->addr << 1);
|
||||
|
||||
state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL);
|
||||
if (!state) {
|
||||
v4l_err(client, "Could not allocate adv76xx_state memory!\n");
|
||||
if (!state)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
state->i2c_clients[ADV76XX_PAGE_IO] = client;
|
||||
|
||||
|
@ -3482,7 +3480,7 @@ static int adv76xx_probe(struct i2c_client *client,
|
|||
state->i2c_clients[i] =
|
||||
adv76xx_dummy_client(sd, state->pdata.i2c_addresses[i],
|
||||
0xf2 + i);
|
||||
if (state->i2c_clients[i] == NULL) {
|
||||
if (!state->i2c_clients[i]) {
|
||||
err = -ENOMEM;
|
||||
v4l2_err(sd, "failed to create i2c client %u\n", i);
|
||||
goto err_i2c;
|
||||
|
|
|
@ -3467,11 +3467,9 @@ static int adv7842_probe(struct i2c_client *client,
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
state = devm_kzalloc(&client->dev, sizeof(struct adv7842_state), GFP_KERNEL);
|
||||
if (!state) {
|
||||
v4l_err(client, "Could not allocate adv7842_state memory!\n");
|
||||
state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL);
|
||||
if (!state)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* platform data */
|
||||
state->pdata = *pdata;
|
||||
|
|
|
@ -1745,7 +1745,7 @@ static int cx25840_g_std(struct v4l2_subdev *sd, v4l2_std_id *std)
|
|||
{
|
||||
struct i2c_client *client = v4l2_get_subdevdata(sd);
|
||||
|
||||
v4l2_std_id stds[] = {
|
||||
static const v4l2_std_id stds[] = {
|
||||
/* 0000 */ V4L2_STD_UNKNOWN,
|
||||
|
||||
/* 0001 */ V4L2_STD_NTSC_M,
|
||||
|
|
|
@ -20,6 +20,11 @@
|
|||
|
||||
#define DW9714_NAME "dw9714"
|
||||
#define DW9714_MAX_FOCUS_POS 1023
|
||||
/*
|
||||
* This sets the minimum granularity for the focus positions.
|
||||
* A value of 1 gives maximum accuracy for a desired focus position
|
||||
*/
|
||||
#define DW9714_FOCUS_STEPS 1
|
||||
/*
|
||||
* This acts as the minimum granularity of lens movement.
|
||||
* Keep this value power of 2, so the control steps can be
|
||||
|
@ -137,7 +142,7 @@ static int dw9714_init_controls(struct dw9714_device *dev_vcm)
|
|||
v4l2_ctrl_handler_init(hdl, 1);
|
||||
|
||||
v4l2_ctrl_new_std(hdl, ops, V4L2_CID_FOCUS_ABSOLUTE,
|
||||
0, DW9714_MAX_FOCUS_POS, DW9714_CTRL_STEPS, 0);
|
||||
0, DW9714_MAX_FOCUS_POS, DW9714_FOCUS_STEPS, 0);
|
||||
|
||||
if (hdl->error)
|
||||
dev_err(&client->dev, "%s fail error: 0x%x\n",
|
||||
|
|
|
@ -1453,7 +1453,7 @@ static int et8ek8_probe(struct i2c_client *client,
|
|||
goto err_mutex;
|
||||
}
|
||||
|
||||
ret = v4l2_async_register_subdev(&sensor->subdev);
|
||||
ret = v4l2_async_register_subdev_sensor_common(&sensor->subdev);
|
||||
if (ret < 0)
|
||||
goto err_entity;
|
||||
|
||||
|
|
1811
drivers/media/i2c/imx274.c
Normal file
1811
drivers/media/i2c/imx274.c
Normal file
File diff suppressed because it is too large
Load diff
|
@ -460,7 +460,6 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
|||
*/
|
||||
rc->map_name = ir->ir_codes;
|
||||
rc->allowed_protocols = rc_proto;
|
||||
rc->enabled_protocols = rc_proto;
|
||||
if (!rc->driver_name)
|
||||
rc->driver_name = MODULE_NAME;
|
||||
|
||||
|
|
|
@ -1345,7 +1345,7 @@ static int max2175_probe(struct i2c_client *client,
|
|||
v4l2_i2c_subdev_init(sd, client, &max2175_ops);
|
||||
ctx->client = client;
|
||||
|
||||
sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
|
||||
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
|
||||
|
||||
/* Controls */
|
||||
hdl = &ctx->ctrl_hdl;
|
||||
|
|
|
@ -945,7 +945,7 @@ static int mt9m111_probe(struct i2c_client *client,
|
|||
|
||||
mt9m111->clk = v4l2_clk_get(&client->dev, "mclk");
|
||||
if (IS_ERR(mt9m111->clk))
|
||||
return -EPROBE_DEFER;
|
||||
return PTR_ERR(mt9m111->clk);
|
||||
|
||||
/* Default HIGHPOWER context */
|
||||
mt9m111->ctx = &context_b;
|
||||
|
|
|
@ -104,7 +104,6 @@ struct ov13858_reg_list {
|
|||
|
||||
/* Link frequency config */
|
||||
struct ov13858_link_freq_config {
|
||||
u32 pixel_rate;
|
||||
u32 pixels_per_line;
|
||||
|
||||
/* PLL registers for this link frequency */
|
||||
|
@ -238,11 +237,11 @@ static const struct ov13858_reg mode_4224x3136_regs[] = {
|
|||
{0x3800, 0x00},
|
||||
{0x3801, 0x00},
|
||||
{0x3802, 0x00},
|
||||
{0x3803, 0x00},
|
||||
{0x3803, 0x08},
|
||||
{0x3804, 0x10},
|
||||
{0x3805, 0x9f},
|
||||
{0x3806, 0x0c},
|
||||
{0x3807, 0x5f},
|
||||
{0x3807, 0x57},
|
||||
{0x3808, 0x10},
|
||||
{0x3809, 0x80},
|
||||
{0x380a, 0x0c},
|
||||
|
@ -948,6 +947,18 @@ static const char * const ov13858_test_pattern_menu[] = {
|
|||
#define OV13858_LINK_FREQ_INDEX_0 0
|
||||
#define OV13858_LINK_FREQ_INDEX_1 1
|
||||
|
||||
/*
|
||||
* pixel_rate = link_freq * data-rate * nr_of_lanes / bits_per_sample
|
||||
* data rate => double data rate; number of lanes => 4; bits per pixel => 10
|
||||
*/
|
||||
static u64 link_freq_to_pixel_rate(u64 f)
|
||||
{
|
||||
f *= 2 * 4;
|
||||
do_div(f, 10);
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
/* Menu items for LINK_FREQ V4L2 control */
|
||||
static const s64 link_freq_menu_items[OV13858_NUM_OF_LINK_FREQS] = {
|
||||
OV13858_LINK_FREQ_540MHZ,
|
||||
|
@ -958,8 +969,6 @@ static const s64 link_freq_menu_items[OV13858_NUM_OF_LINK_FREQS] = {
|
|||
static const struct ov13858_link_freq_config
|
||||
link_freq_configs[OV13858_NUM_OF_LINK_FREQS] = {
|
||||
{
|
||||
/* pixel_rate = link_freq * 2 * nr_of_lanes / bits_per_sample */
|
||||
.pixel_rate = (OV13858_LINK_FREQ_540MHZ * 2 * 4) / 10,
|
||||
.pixels_per_line = OV13858_PPL_540MHZ,
|
||||
.reg_list = {
|
||||
.num_of_regs = ARRAY_SIZE(mipi_data_rate_1080mbps),
|
||||
|
@ -967,8 +976,6 @@ static const struct ov13858_link_freq_config
|
|||
}
|
||||
},
|
||||
{
|
||||
/* pixel_rate = link_freq * 2 * nr_of_lanes / bits_per_sample */
|
||||
.pixel_rate = (OV13858_LINK_FREQ_270MHZ * 2 * 4) / 10,
|
||||
.pixels_per_line = OV13858_PPL_270MHZ,
|
||||
.reg_list = {
|
||||
.num_of_regs = ARRAY_SIZE(mipi_data_rate_540mbps),
|
||||
|
@ -1385,6 +1392,8 @@ ov13858_set_pad_format(struct v4l2_subdev *sd,
|
|||
s32 vblank_def;
|
||||
s32 vblank_min;
|
||||
s64 h_blank;
|
||||
s64 pixel_rate;
|
||||
s64 link_freq;
|
||||
|
||||
mutex_lock(&ov13858->mutex);
|
||||
|
||||
|
@ -1400,9 +1409,10 @@ ov13858_set_pad_format(struct v4l2_subdev *sd,
|
|||
} else {
|
||||
ov13858->cur_mode = mode;
|
||||
__v4l2_ctrl_s_ctrl(ov13858->link_freq, mode->link_freq_index);
|
||||
__v4l2_ctrl_s_ctrl_int64(
|
||||
ov13858->pixel_rate,
|
||||
link_freq_configs[mode->link_freq_index].pixel_rate);
|
||||
link_freq = link_freq_menu_items[mode->link_freq_index];
|
||||
pixel_rate = link_freq_to_pixel_rate(link_freq);
|
||||
__v4l2_ctrl_s_ctrl_int64(ov13858->pixel_rate, pixel_rate);
|
||||
|
||||
/* Update limits and set FPS to default */
|
||||
vblank_def = ov13858->cur_mode->vts_def -
|
||||
ov13858->cur_mode->height;
|
||||
|
@ -1617,6 +1627,10 @@ static int ov13858_init_controls(struct ov13858 *ov13858)
|
|||
s64 exposure_max;
|
||||
s64 vblank_def;
|
||||
s64 vblank_min;
|
||||
s64 hblank;
|
||||
s64 pixel_rate_min;
|
||||
s64 pixel_rate_max;
|
||||
const struct ov13858_mode *mode;
|
||||
int ret;
|
||||
|
||||
ctrl_hdlr = &ov13858->ctrl_handler;
|
||||
|
@ -1634,29 +1648,30 @@ static int ov13858_init_controls(struct ov13858 *ov13858)
|
|||
link_freq_menu_items);
|
||||
ov13858->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
|
||||
|
||||
pixel_rate_max = link_freq_to_pixel_rate(link_freq_menu_items[0]);
|
||||
pixel_rate_min = link_freq_to_pixel_rate(link_freq_menu_items[1]);
|
||||
/* By default, PIXEL_RATE is read only */
|
||||
ov13858->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &ov13858_ctrl_ops,
|
||||
V4L2_CID_PIXEL_RATE, 0,
|
||||
link_freq_configs[0].pixel_rate, 1,
|
||||
link_freq_configs[0].pixel_rate);
|
||||
V4L2_CID_PIXEL_RATE,
|
||||
pixel_rate_min, pixel_rate_max,
|
||||
1, pixel_rate_max);
|
||||
|
||||
vblank_def = ov13858->cur_mode->vts_def - ov13858->cur_mode->height;
|
||||
vblank_min = ov13858->cur_mode->vts_min - ov13858->cur_mode->height;
|
||||
mode = ov13858->cur_mode;
|
||||
vblank_def = mode->vts_def - mode->height;
|
||||
vblank_min = mode->vts_min - mode->height;
|
||||
ov13858->vblank = v4l2_ctrl_new_std(
|
||||
ctrl_hdlr, &ov13858_ctrl_ops, V4L2_CID_VBLANK,
|
||||
vblank_min,
|
||||
OV13858_VTS_MAX - ov13858->cur_mode->height, 1,
|
||||
vblank_min, OV13858_VTS_MAX - mode->height, 1,
|
||||
vblank_def);
|
||||
|
||||
hblank = link_freq_configs[mode->link_freq_index].pixels_per_line -
|
||||
mode->width;
|
||||
ov13858->hblank = v4l2_ctrl_new_std(
|
||||
ctrl_hdlr, &ov13858_ctrl_ops, V4L2_CID_HBLANK,
|
||||
OV13858_PPL_540MHZ - ov13858->cur_mode->width,
|
||||
OV13858_PPL_540MHZ - ov13858->cur_mode->width,
|
||||
1,
|
||||
OV13858_PPL_540MHZ - ov13858->cur_mode->width);
|
||||
hblank, hblank, 1, hblank);
|
||||
ov13858->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
|
||||
|
||||
exposure_max = ov13858->cur_mode->vts_def - 8;
|
||||
exposure_max = mode->vts_def - 8;
|
||||
ov13858->exposure = v4l2_ctrl_new_std(
|
||||
ctrl_hdlr, &ov13858_ctrl_ops,
|
||||
V4L2_CID_EXPOSURE, OV13858_EXPOSURE_MIN,
|
||||
|
@ -1746,7 +1761,7 @@ static int ov13858_probe(struct i2c_client *client,
|
|||
goto error_handler_free;
|
||||
}
|
||||
|
||||
ret = v4l2_async_register_subdev(&ov13858->sd);
|
||||
ret = v4l2_async_register_subdev_sensor_common(&ov13858->sd);
|
||||
if (ret < 0)
|
||||
goto error_media_entity;
|
||||
|
||||
|
|
|
@ -685,7 +685,7 @@ static int ov2640_mask_set(struct i2c_client *client,
|
|||
static int ov2640_reset(struct i2c_client *client)
|
||||
{
|
||||
int ret;
|
||||
const struct regval_list reset_seq[] = {
|
||||
static const struct regval_list reset_seq[] = {
|
||||
{BANK_SEL, BANK_SEL_SENS},
|
||||
{COM7, COM7_SRST},
|
||||
ENDMARKER,
|
||||
|
@ -1097,18 +1097,17 @@ static int ov2640_probe(struct i2c_client *client,
|
|||
return -EIO;
|
||||
}
|
||||
|
||||
priv = devm_kzalloc(&client->dev, sizeof(struct ov2640_priv), GFP_KERNEL);
|
||||
if (!priv) {
|
||||
dev_err(&adapter->dev,
|
||||
"Failed to allocate memory for private data!\n");
|
||||
priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (client->dev.of_node) {
|
||||
priv->clk = devm_clk_get(&client->dev, "xvclk");
|
||||
if (IS_ERR(priv->clk))
|
||||
return -EPROBE_DEFER;
|
||||
clk_prepare_enable(priv->clk);
|
||||
return PTR_ERR(priv->clk);
|
||||
ret = clk_prepare_enable(priv->clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = ov2640_probe_dt(client, priv);
|
||||
|
@ -1116,7 +1115,7 @@ static int ov2640_probe(struct i2c_client *client,
|
|||
goto err_clk;
|
||||
|
||||
v4l2_i2c_subdev_init(&priv->subdev, client, &ov2640_subdev_ops);
|
||||
priv->subdev.flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
|
||||
priv->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
|
||||
v4l2_ctrl_handler_init(&priv->hdl, 2);
|
||||
v4l2_ctrl_new_std(&priv->hdl, &ov2640_ctrl_ops,
|
||||
V4L2_CID_VFLIP, 0, 1, 1, 0);
|
||||
|
|
|
@ -2271,7 +2271,7 @@ static int ov5640_probe(struct i2c_client *client,
|
|||
|
||||
v4l2_i2c_subdev_init(&sensor->sd, client, &ov5640_subdev_ops);
|
||||
|
||||
sensor->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
|
||||
sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
|
||||
sensor->pad.flags = MEDIA_PAD_FL_SOURCE;
|
||||
sensor->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
|
||||
ret = media_entity_pads_init(&sensor->sd.entity, 1, &sensor->pad);
|
||||
|
|
|
@ -35,9 +35,18 @@
|
|||
|
||||
#define SENSOR_NAME "ov5647"
|
||||
|
||||
#define OV5647_SW_RESET 0x0103
|
||||
#define OV5647_REG_CHIPID_H 0x300A
|
||||
#define OV5647_REG_CHIPID_L 0x300B
|
||||
#define MIPI_CTRL00_CLOCK_LANE_GATE BIT(5)
|
||||
#define MIPI_CTRL00_BUS_IDLE BIT(2)
|
||||
#define MIPI_CTRL00_CLOCK_LANE_DISABLE BIT(0)
|
||||
|
||||
#define OV5647_SW_STANDBY 0x0100
|
||||
#define OV5647_SW_RESET 0x0103
|
||||
#define OV5647_REG_CHIPID_H 0x300A
|
||||
#define OV5647_REG_CHIPID_L 0x300B
|
||||
#define OV5640_REG_PAD_OUT 0x300D
|
||||
#define OV5647_REG_FRAME_OFF_NUMBER 0x4202
|
||||
#define OV5647_REG_MIPI_CTRL00 0x4800
|
||||
#define OV5647_REG_MIPI_CTRL14 0x4814
|
||||
|
||||
#define REG_TERM 0xfffe
|
||||
#define VAL_TERM 0xfe
|
||||
|
@ -241,34 +250,43 @@ static int ov5647_set_virtual_channel(struct v4l2_subdev *sd, int channel)
|
|||
u8 channel_id;
|
||||
int ret;
|
||||
|
||||
ret = ov5647_read(sd, 0x4814, &channel_id);
|
||||
ret = ov5647_read(sd, OV5647_REG_MIPI_CTRL14, &channel_id);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
channel_id &= ~(3 << 6);
|
||||
return ov5647_write(sd, 0x4814, channel_id | (channel << 6));
|
||||
return ov5647_write(sd, OV5647_REG_MIPI_CTRL14, channel_id | (channel << 6));
|
||||
}
|
||||
|
||||
static int ov5647_stream_on(struct v4l2_subdev *sd)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = ov5647_write(sd, 0x4202, 0x00);
|
||||
ret = ov5647_write(sd, OV5647_REG_MIPI_CTRL00, MIPI_CTRL00_BUS_IDLE);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return ov5647_write(sd, 0x300D, 0x00);
|
||||
ret = ov5647_write(sd, OV5647_REG_FRAME_OFF_NUMBER, 0x00);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return ov5647_write(sd, OV5640_REG_PAD_OUT, 0x00);
|
||||
}
|
||||
|
||||
static int ov5647_stream_off(struct v4l2_subdev *sd)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = ov5647_write(sd, 0x4202, 0x0f);
|
||||
ret = ov5647_write(sd, OV5647_REG_MIPI_CTRL00, MIPI_CTRL00_CLOCK_LANE_GATE
|
||||
| MIPI_CTRL00_BUS_IDLE | MIPI_CTRL00_CLOCK_LANE_DISABLE);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return ov5647_write(sd, 0x300D, 0x01);
|
||||
ret = ov5647_write(sd, OV5647_REG_FRAME_OFF_NUMBER, 0x0f);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return ov5647_write(sd, OV5640_REG_PAD_OUT, 0x01);
|
||||
}
|
||||
|
||||
static int set_sw_standby(struct v4l2_subdev *sd, bool standby)
|
||||
|
@ -276,7 +294,7 @@ static int set_sw_standby(struct v4l2_subdev *sd, bool standby)
|
|||
int ret;
|
||||
u8 rdval;
|
||||
|
||||
ret = ov5647_read(sd, 0x0100, &rdval);
|
||||
ret = ov5647_read(sd, OV5647_SW_STANDBY, &rdval);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
@ -285,7 +303,7 @@ static int set_sw_standby(struct v4l2_subdev *sd, bool standby)
|
|||
else
|
||||
rdval |= 0x01;
|
||||
|
||||
return ov5647_write(sd, 0x0100, rdval);
|
||||
return ov5647_write(sd, OV5647_SW_STANDBY, rdval);
|
||||
}
|
||||
|
||||
static int __sensor_init(struct v4l2_subdev *sd)
|
||||
|
@ -294,7 +312,7 @@ static int __sensor_init(struct v4l2_subdev *sd)
|
|||
u8 resetval, rdval;
|
||||
struct i2c_client *client = v4l2_get_subdevdata(sd);
|
||||
|
||||
ret = ov5647_read(sd, 0x0100, &rdval);
|
||||
ret = ov5647_read(sd, OV5647_SW_STANDBY, &rdval);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
@ -309,18 +327,21 @@ static int __sensor_init(struct v4l2_subdev *sd)
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = ov5647_read(sd, 0x0100, &resetval);
|
||||
ret = ov5647_read(sd, OV5647_SW_STANDBY, &resetval);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (!(resetval & 0x01)) {
|
||||
dev_err(&client->dev, "Device was in SW standby");
|
||||
ret = ov5647_write(sd, 0x0100, 0x01);
|
||||
ret = ov5647_write(sd, OV5647_SW_STANDBY, 0x01);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ov5647_write(sd, 0x4800, 0x04);
|
||||
/*
|
||||
* stream off to make the clock lane into LP-11 state.
|
||||
*/
|
||||
return ov5647_stream_off(sd);
|
||||
}
|
||||
|
||||
static int ov5647_sensor_power(struct v4l2_subdev *sd, int on)
|
||||
|
|
|
@ -390,7 +390,10 @@ static const struct ov5670_reg mode_2592x1944_regs[] = {
|
|||
{0x5792, 0x00},
|
||||
{0x5793, 0x52},
|
||||
{0x5794, 0xa3},
|
||||
{0x3503, 0x00}
|
||||
{0x3503, 0x00},
|
||||
{0x5045, 0x05},
|
||||
{0x4003, 0x40},
|
||||
{0x5048, 0x40}
|
||||
};
|
||||
|
||||
static const struct ov5670_reg mode_1296x972_regs[] = {
|
||||
|
@ -653,7 +656,10 @@ static const struct ov5670_reg mode_1296x972_regs[] = {
|
|||
{0x5792, 0x00},
|
||||
{0x5793, 0x52},
|
||||
{0x5794, 0xa3},
|
||||
{0x3503, 0x00}
|
||||
{0x3503, 0x00},
|
||||
{0x5045, 0x05},
|
||||
{0x4003, 0x40},
|
||||
{0x5048, 0x40}
|
||||
};
|
||||
|
||||
static const struct ov5670_reg mode_648x486_regs[] = {
|
||||
|
@ -916,7 +922,10 @@ static const struct ov5670_reg mode_648x486_regs[] = {
|
|||
{0x5792, 0x00},
|
||||
{0x5793, 0x52},
|
||||
{0x5794, 0xa3},
|
||||
{0x3503, 0x00}
|
||||
{0x3503, 0x00},
|
||||
{0x5045, 0x05},
|
||||
{0x4003, 0x40},
|
||||
{0x5048, 0x40}
|
||||
};
|
||||
|
||||
static const struct ov5670_reg mode_2560x1440_regs[] = {
|
||||
|
@ -1178,7 +1187,10 @@ static const struct ov5670_reg mode_2560x1440_regs[] = {
|
|||
{0x5791, 0x06},
|
||||
{0x5792, 0x00},
|
||||
{0x5793, 0x52},
|
||||
{0x5794, 0xa3}
|
||||
{0x5794, 0xa3},
|
||||
{0x5045, 0x05},
|
||||
{0x4003, 0x40},
|
||||
{0x5048, 0x40}
|
||||
};
|
||||
|
||||
static const struct ov5670_reg mode_1280x720_regs[] = {
|
||||
|
@ -1441,7 +1453,10 @@ static const struct ov5670_reg mode_1280x720_regs[] = {
|
|||
{0x5792, 0x00},
|
||||
{0x5793, 0x52},
|
||||
{0x5794, 0xa3},
|
||||
{0x3503, 0x00}
|
||||
{0x3503, 0x00},
|
||||
{0x5045, 0x05},
|
||||
{0x4003, 0x40},
|
||||
{0x5048, 0x40}
|
||||
};
|
||||
|
||||
static const struct ov5670_reg mode_640x360_regs[] = {
|
||||
|
@ -1704,7 +1719,10 @@ static const struct ov5670_reg mode_640x360_regs[] = {
|
|||
{0x5792, 0x00},
|
||||
{0x5793, 0x52},
|
||||
{0x5794, 0xa3},
|
||||
{0x3503, 0x00}
|
||||
{0x3503, 0x00},
|
||||
{0x5045, 0x05},
|
||||
{0x4003, 0x40},
|
||||
{0x5048, 0x40}
|
||||
};
|
||||
|
||||
static const char * const ov5670_test_pattern_menu[] = {
|
||||
|
@ -2323,8 +2341,6 @@ static int ov5670_start_streaming(struct ov5670 *ov5670)
|
|||
return ret;
|
||||
}
|
||||
|
||||
ov5670->streaming = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -2338,8 +2354,6 @@ static int ov5670_stop_streaming(struct ov5670 *ov5670)
|
|||
if (ret)
|
||||
dev_err(&client->dev, "%s failed to set stream\n", __func__);
|
||||
|
||||
ov5670->streaming = false;
|
||||
|
||||
/* Return success even if it was an error, as there is nothing the
|
||||
* caller can do about it.
|
||||
*/
|
||||
|
@ -2370,6 +2384,7 @@ static int ov5670_set_stream(struct v4l2_subdev *sd, int enable)
|
|||
ret = ov5670_stop_streaming(ov5670);
|
||||
pm_runtime_put(&client->dev);
|
||||
}
|
||||
ov5670->streaming = enable;
|
||||
goto unlock_and_return;
|
||||
|
||||
error:
|
||||
|
@ -2514,7 +2529,7 @@ static int ov5670_probe(struct i2c_client *client)
|
|||
}
|
||||
|
||||
/* Async register for subdev */
|
||||
ret = v4l2_async_register_subdev(&ov5670->sd);
|
||||
ret = v4l2_async_register_subdev_sensor_common(&ov5670->sd);
|
||||
if (ret < 0) {
|
||||
err_msg = "v4l2_async_register_subdev() error";
|
||||
goto error_entity_cleanup;
|
||||
|
|
|
@ -951,11 +951,8 @@ static int ov6650_probe(struct i2c_client *client,
|
|||
int ret;
|
||||
|
||||
priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv) {
|
||||
dev_err(&client->dev,
|
||||
"Failed to allocate memory for private data!\n");
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
v4l2_i2c_subdev_init(&priv->subdev, client, &ov6650_subdev_ops);
|
||||
v4l2_ctrl_handler_init(&priv->hdl, 13);
|
||||
|
|
|
@ -213,6 +213,9 @@ struct ov7670_devtype {
|
|||
struct ov7670_format_struct; /* coming later */
|
||||
struct ov7670_info {
|
||||
struct v4l2_subdev sd;
|
||||
#if defined(CONFIG_MEDIA_CONTROLLER)
|
||||
struct media_pad pad;
|
||||
#endif
|
||||
struct v4l2_ctrl_handler hdl;
|
||||
struct {
|
||||
/* gain cluster */
|
||||
|
@ -229,6 +232,7 @@ struct ov7670_info {
|
|||
struct v4l2_ctrl *saturation;
|
||||
struct v4l2_ctrl *hue;
|
||||
};
|
||||
struct v4l2_mbus_framefmt format;
|
||||
struct ov7670_format_struct *fmt; /* Current format */
|
||||
struct clk *clk;
|
||||
struct gpio_desc *resetb_gpio;
|
||||
|
@ -972,6 +976,9 @@ static int ov7670_try_fmt_internal(struct v4l2_subdev *sd,
|
|||
fmt->width = wsize->width;
|
||||
fmt->height = wsize->height;
|
||||
fmt->colorspace = ov7670_formats[index].colorspace;
|
||||
|
||||
info->format = *fmt;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -985,6 +992,9 @@ static int ov7670_set_fmt(struct v4l2_subdev *sd,
|
|||
struct ov7670_format_struct *ovfmt;
|
||||
struct ov7670_win_size *wsize;
|
||||
struct ov7670_info *info = to_state(sd);
|
||||
#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
|
||||
struct v4l2_mbus_framefmt *mbus_fmt;
|
||||
#endif
|
||||
unsigned char com7;
|
||||
int ret;
|
||||
|
||||
|
@ -995,8 +1005,13 @@ static int ov7670_set_fmt(struct v4l2_subdev *sd,
|
|||
ret = ov7670_try_fmt_internal(sd, &format->format, NULL, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
cfg->try_fmt = format->format;
|
||||
#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
|
||||
mbus_fmt = v4l2_subdev_get_try_format(sd, cfg, format->pad);
|
||||
*mbus_fmt = format->format;
|
||||
return 0;
|
||||
#else
|
||||
return -ENOTTY;
|
||||
#endif
|
||||
}
|
||||
|
||||
ret = ov7670_try_fmt_internal(sd, &format->format, &ovfmt, &wsize);
|
||||
|
@ -1038,6 +1053,30 @@ static int ov7670_set_fmt(struct v4l2_subdev *sd,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int ov7670_get_fmt(struct v4l2_subdev *sd,
|
||||
struct v4l2_subdev_pad_config *cfg,
|
||||
struct v4l2_subdev_format *format)
|
||||
{
|
||||
struct ov7670_info *info = to_state(sd);
|
||||
#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
|
||||
struct v4l2_mbus_framefmt *mbus_fmt;
|
||||
#endif
|
||||
|
||||
if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
|
||||
#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
|
||||
mbus_fmt = v4l2_subdev_get_try_format(sd, cfg, 0);
|
||||
format->format = *mbus_fmt;
|
||||
return 0;
|
||||
#else
|
||||
return -ENOTTY;
|
||||
#endif
|
||||
} else {
|
||||
format->format = info->format;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Implement G/S_PARM. There is a "high quality" mode we could try
|
||||
* to do someday; for now, we just do the frame rate tweak.
|
||||
|
@ -1505,6 +1544,46 @@ static int ov7670_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_regis
|
|||
}
|
||||
#endif
|
||||
|
||||
static int ov7670_s_power(struct v4l2_subdev *sd, int on)
|
||||
{
|
||||
struct ov7670_info *info = to_state(sd);
|
||||
|
||||
if (info->pwdn_gpio)
|
||||
gpiod_set_value(info->pwdn_gpio, !on);
|
||||
if (on && info->resetb_gpio) {
|
||||
gpiod_set_value(info->resetb_gpio, 1);
|
||||
usleep_range(500, 1000);
|
||||
gpiod_set_value(info->resetb_gpio, 0);
|
||||
usleep_range(3000, 5000);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ov7670_get_default_format(struct v4l2_subdev *sd,
|
||||
struct v4l2_mbus_framefmt *format)
|
||||
{
|
||||
struct ov7670_info *info = to_state(sd);
|
||||
|
||||
format->width = info->devtype->win_sizes[0].width;
|
||||
format->height = info->devtype->win_sizes[0].height;
|
||||
format->colorspace = info->fmt->colorspace;
|
||||
format->code = info->fmt->mbus_code;
|
||||
format->field = V4L2_FIELD_NONE;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
|
||||
static int ov7670_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
|
||||
{
|
||||
struct v4l2_mbus_framefmt *format =
|
||||
v4l2_subdev_get_try_format(sd, fh->pad, 0);
|
||||
|
||||
ov7670_get_default_format(sd, format);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
static const struct v4l2_subdev_core_ops ov7670_core_ops = {
|
||||
|
@ -1525,6 +1604,7 @@ static const struct v4l2_subdev_pad_ops ov7670_pad_ops = {
|
|||
.enum_frame_interval = ov7670_enum_frame_interval,
|
||||
.enum_frame_size = ov7670_enum_frame_size,
|
||||
.enum_mbus_code = ov7670_enum_mbus_code,
|
||||
.get_fmt = ov7670_get_fmt,
|
||||
.set_fmt = ov7670_set_fmt,
|
||||
};
|
||||
|
||||
|
@ -1534,6 +1614,12 @@ static const struct v4l2_subdev_ops ov7670_ops = {
|
|||
.pad = &ov7670_pad_ops,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
|
||||
static const struct v4l2_subdev_internal_ops ov7670_subdev_internal_ops = {
|
||||
.open = ov7670_open,
|
||||
};
|
||||
#endif
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
static const struct ov7670_devtype ov7670_devdata[] = {
|
||||
|
@ -1586,6 +1672,11 @@ static int ov7670_probe(struct i2c_client *client,
|
|||
sd = &info->sd;
|
||||
v4l2_i2c_subdev_init(sd, client, &ov7670_ops);
|
||||
|
||||
#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
|
||||
sd->internal_ops = &ov7670_subdev_internal_ops;
|
||||
sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
|
||||
#endif
|
||||
|
||||
info->clock_speed = 30; /* default: a guess */
|
||||
if (client->dev.platform_data) {
|
||||
struct ov7670_config *config = client->dev.platform_data;
|
||||
|
@ -1619,29 +1710,34 @@ static int ov7670_probe(struct i2c_client *client,
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = ov7670_init_gpio(client, info);
|
||||
if (ret)
|
||||
goto clk_disable;
|
||||
|
||||
info->clock_speed = clk_get_rate(info->clk) / 1000000;
|
||||
if (info->clock_speed < 10 || info->clock_speed > 48) {
|
||||
ret = -EINVAL;
|
||||
goto clk_disable;
|
||||
}
|
||||
|
||||
ret = ov7670_init_gpio(client, info);
|
||||
if (ret)
|
||||
goto clk_disable;
|
||||
|
||||
ov7670_s_power(sd, 1);
|
||||
|
||||
/* Make sure it's an ov7670 */
|
||||
ret = ov7670_detect(sd);
|
||||
if (ret) {
|
||||
v4l_dbg(1, debug, client,
|
||||
"chip found @ 0x%x (%s) is not an ov7670 chip.\n",
|
||||
client->addr << 1, client->adapter->name);
|
||||
goto clk_disable;
|
||||
goto power_off;
|
||||
}
|
||||
v4l_info(client, "chip found @ 0x%02x (%s)\n",
|
||||
client->addr << 1, client->adapter->name);
|
||||
|
||||
info->devtype = &ov7670_devdata[id->driver_data];
|
||||
info->fmt = &ov7670_formats[0];
|
||||
|
||||
ov7670_get_default_format(sd, &info->format);
|
||||
|
||||
info->clkrc = 0;
|
||||
|
||||
/* Set default frame rate to 30 fps */
|
||||
|
@ -1688,16 +1784,31 @@ static int ov7670_probe(struct i2c_client *client,
|
|||
v4l2_ctrl_auto_cluster(2, &info->auto_exposure,
|
||||
V4L2_EXPOSURE_MANUAL, false);
|
||||
v4l2_ctrl_cluster(2, &info->saturation);
|
||||
|
||||
#if defined(CONFIG_MEDIA_CONTROLLER)
|
||||
info->pad.flags = MEDIA_PAD_FL_SOURCE;
|
||||
info->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
|
||||
ret = media_entity_pads_init(&info->sd.entity, 1, &info->pad);
|
||||
if (ret < 0)
|
||||
goto hdl_free;
|
||||
#endif
|
||||
|
||||
v4l2_ctrl_handler_setup(&info->hdl);
|
||||
|
||||
ret = v4l2_async_register_subdev(&info->sd);
|
||||
if (ret < 0)
|
||||
goto hdl_free;
|
||||
goto entity_cleanup;
|
||||
|
||||
return 0;
|
||||
|
||||
entity_cleanup:
|
||||
#if defined(CONFIG_MEDIA_CONTROLLER)
|
||||
media_entity_cleanup(&info->sd.entity);
|
||||
#endif
|
||||
hdl_free:
|
||||
v4l2_ctrl_handler_free(&info->hdl);
|
||||
power_off:
|
||||
ov7670_s_power(sd, 0);
|
||||
clk_disable:
|
||||
clk_disable_unprepare(info->clk);
|
||||
return ret;
|
||||
|
@ -1712,6 +1823,10 @@ static int ov7670_remove(struct i2c_client *client)
|
|||
v4l2_device_unregister_subdev(sd);
|
||||
v4l2_ctrl_handler_free(&info->hdl);
|
||||
clk_disable_unprepare(info->clk);
|
||||
#if defined(CONFIG_MEDIA_CONTROLLER)
|
||||
media_entity_cleanup(&info->sd.entity);
|
||||
#endif
|
||||
ov7670_s_power(sd, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -985,7 +985,6 @@ static const struct v4l2_ctrl_ops ov965x_ctrl_ops = {
|
|||
static const char * const test_pattern_menu[] = {
|
||||
"Disabled",
|
||||
"Color bars",
|
||||
NULL
|
||||
};
|
||||
|
||||
static int ov965x_initialize_controls(struct ov965x *ov965x)
|
||||
|
|
|
@ -1239,6 +1239,10 @@ static int smiapp_power_on(struct device *dev)
|
|||
sleep = SMIAPP_RESET_DELAY(sensor->hwcfg->ext_clk);
|
||||
usleep_range(sleep, sleep);
|
||||
|
||||
mutex_lock(&sensor->mutex);
|
||||
|
||||
sensor->active = true;
|
||||
|
||||
/*
|
||||
* Failures to respond to the address change command have been noticed.
|
||||
* Those failures seem to be caused by the sensor requiring a longer
|
||||
|
@ -1313,7 +1317,7 @@ static int smiapp_power_on(struct device *dev)
|
|||
rval = smiapp_write(sensor, SMIAPP_REG_U8_DPHY_CTRL,
|
||||
SMIAPP_DPHY_CTRL_UI);
|
||||
if (rval < 0)
|
||||
return rval;
|
||||
goto out_cci_addr_fail;
|
||||
|
||||
rval = smiapp_call_quirk(sensor, post_poweron);
|
||||
if (rval) {
|
||||
|
@ -1321,28 +1325,28 @@ static int smiapp_power_on(struct device *dev)
|
|||
goto out_cci_addr_fail;
|
||||
}
|
||||
|
||||
/* Are we still initialising...? If yes, return here. */
|
||||
if (!sensor->pixel_array)
|
||||
return 0;
|
||||
/* Are we still initialising...? If not, proceed with control setup. */
|
||||
if (sensor->pixel_array) {
|
||||
rval = __v4l2_ctrl_handler_setup(
|
||||
&sensor->pixel_array->ctrl_handler);
|
||||
if (rval)
|
||||
goto out_cci_addr_fail;
|
||||
|
||||
rval = v4l2_ctrl_handler_setup(&sensor->pixel_array->ctrl_handler);
|
||||
if (rval)
|
||||
goto out_cci_addr_fail;
|
||||
rval = __v4l2_ctrl_handler_setup(&sensor->src->ctrl_handler);
|
||||
if (rval)
|
||||
goto out_cci_addr_fail;
|
||||
|
||||
rval = v4l2_ctrl_handler_setup(&sensor->src->ctrl_handler);
|
||||
if (rval)
|
||||
goto out_cci_addr_fail;
|
||||
rval = smiapp_update_mode(sensor);
|
||||
if (rval < 0)
|
||||
goto out_cci_addr_fail;
|
||||
}
|
||||
|
||||
mutex_lock(&sensor->mutex);
|
||||
rval = smiapp_update_mode(sensor);
|
||||
mutex_unlock(&sensor->mutex);
|
||||
if (rval < 0)
|
||||
goto out_cci_addr_fail;
|
||||
|
||||
return 0;
|
||||
|
||||
out_cci_addr_fail:
|
||||
|
||||
mutex_unlock(&sensor->mutex);
|
||||
gpiod_set_value(sensor->xshutdown, 0);
|
||||
clk_disable_unprepare(sensor->ext_clk);
|
||||
|
||||
|
@ -1360,6 +1364,8 @@ static int smiapp_power_off(struct device *dev)
|
|||
struct smiapp_sensor *sensor =
|
||||
container_of(ssd, struct smiapp_sensor, ssds[0]);
|
||||
|
||||
mutex_lock(&sensor->mutex);
|
||||
|
||||
/*
|
||||
* Currently power/clock to lens are enable/disabled separately
|
||||
* but they are essentially the same signals. So if the sensor is
|
||||
|
@ -1372,6 +1378,10 @@ static int smiapp_power_off(struct device *dev)
|
|||
SMIAPP_REG_U8_SOFTWARE_RESET,
|
||||
SMIAPP_SOFTWARE_RESET);
|
||||
|
||||
sensor->active = false;
|
||||
|
||||
mutex_unlock(&sensor->mutex);
|
||||
|
||||
gpiod_set_value(sensor->xshutdown, 0);
|
||||
clk_disable_unprepare(sensor->ext_clk);
|
||||
usleep_range(5000, 5000);
|
||||
|
@ -1381,29 +1391,6 @@ static int smiapp_power_off(struct device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int smiapp_set_power(struct v4l2_subdev *subdev, int on)
|
||||
{
|
||||
int rval;
|
||||
|
||||
if (!on) {
|
||||
pm_runtime_mark_last_busy(subdev->dev);
|
||||
pm_runtime_put_autosuspend(subdev->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
rval = pm_runtime_get_sync(subdev->dev);
|
||||
if (rval >= 0)
|
||||
return 0;
|
||||
|
||||
if (rval != -EBUSY && rval != -EAGAIN)
|
||||
pm_runtime_set_active(subdev->dev);
|
||||
|
||||
pm_runtime_put(subdev->dev);
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* Video stream management
|
||||
*/
|
||||
|
@ -1560,19 +1547,31 @@ static int smiapp_stop_streaming(struct smiapp_sensor *sensor)
|
|||
static int smiapp_set_stream(struct v4l2_subdev *subdev, int enable)
|
||||
{
|
||||
struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
|
||||
struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
|
||||
int rval;
|
||||
|
||||
if (sensor->streaming == enable)
|
||||
return 0;
|
||||
|
||||
if (enable) {
|
||||
rval = pm_runtime_get_sync(&client->dev);
|
||||
if (rval < 0) {
|
||||
if (rval != -EBUSY && rval != -EAGAIN)
|
||||
pm_runtime_set_active(&client->dev);
|
||||
pm_runtime_put(&client->dev);
|
||||
return rval;
|
||||
}
|
||||
|
||||
sensor->streaming = true;
|
||||
|
||||
rval = smiapp_start_streaming(sensor);
|
||||
if (rval < 0)
|
||||
sensor->streaming = false;
|
||||
} else {
|
||||
rval = smiapp_stop_streaming(sensor);
|
||||
sensor->streaming = false;
|
||||
pm_runtime_mark_last_busy(&client->dev);
|
||||
pm_runtime_put_autosuspend(&client->dev);
|
||||
}
|
||||
|
||||
return rval;
|
||||
|
@ -2650,7 +2649,6 @@ static int smiapp_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
|
|||
struct smiapp_subdev *ssd = to_smiapp_subdev(sd);
|
||||
struct smiapp_sensor *sensor = ssd->sensor;
|
||||
unsigned int i;
|
||||
int rval;
|
||||
|
||||
mutex_lock(&sensor->mutex);
|
||||
|
||||
|
@ -2677,22 +2675,6 @@ static int smiapp_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
|
|||
|
||||
mutex_unlock(&sensor->mutex);
|
||||
|
||||
rval = pm_runtime_get_sync(sd->dev);
|
||||
if (rval >= 0)
|
||||
return 0;
|
||||
|
||||
if (rval != -EBUSY && rval != -EAGAIN)
|
||||
pm_runtime_set_active(sd->dev);
|
||||
pm_runtime_put(sd->dev);
|
||||
|
||||
return rval;
|
||||
}
|
||||
|
||||
static int smiapp_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
|
||||
{
|
||||
pm_runtime_mark_last_busy(sd->dev);
|
||||
pm_runtime_put_autosuspend(sd->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -2700,10 +2682,6 @@ static const struct v4l2_subdev_video_ops smiapp_video_ops = {
|
|||
.s_stream = smiapp_set_stream,
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_core_ops smiapp_core_ops = {
|
||||
.s_power = smiapp_set_power,
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_pad_ops smiapp_pad_ops = {
|
||||
.enum_mbus_code = smiapp_enum_mbus_code,
|
||||
.get_fmt = smiapp_get_format,
|
||||
|
@ -2718,7 +2696,6 @@ static const struct v4l2_subdev_sensor_ops smiapp_sensor_ops = {
|
|||
};
|
||||
|
||||
static const struct v4l2_subdev_ops smiapp_ops = {
|
||||
.core = &smiapp_core_ops,
|
||||
.video = &smiapp_video_ops,
|
||||
.pad = &smiapp_pad_ops,
|
||||
.sensor = &smiapp_sensor_ops,
|
||||
|
@ -2732,12 +2709,10 @@ static const struct v4l2_subdev_internal_ops smiapp_internal_src_ops = {
|
|||
.registered = smiapp_registered,
|
||||
.unregistered = smiapp_unregistered,
|
||||
.open = smiapp_open,
|
||||
.close = smiapp_close,
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_internal_ops smiapp_internal_ops = {
|
||||
.open = smiapp_open,
|
||||
.close = smiapp_close,
|
||||
};
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
|
@ -2829,12 +2804,10 @@ static struct smiapp_hwconfig *smiapp_get_hwconfig(struct device *dev)
|
|||
/* NVM size is not mandatory */
|
||||
fwnode_property_read_u32(fwnode, "nokia,nvm-size", &hwcfg->nvm_size);
|
||||
|
||||
rval = fwnode_property_read_u32(fwnode, "clock-frequency",
|
||||
rval = fwnode_property_read_u32(dev_fwnode(dev), "clock-frequency",
|
||||
&hwcfg->ext_clk);
|
||||
if (rval) {
|
||||
dev_warn(dev, "can't get clock-frequency\n");
|
||||
goto out_err;
|
||||
}
|
||||
if (rval)
|
||||
dev_info(dev, "can't get clock-frequency\n");
|
||||
|
||||
dev_dbg(dev, "nvm %d, clk %d, mode %d\n",
|
||||
hwcfg->nvm_size, hwcfg->ext_clk, hwcfg->csi_signalling_mode);
|
||||
|
@ -2894,18 +2867,46 @@ static int smiapp_probe(struct i2c_client *client,
|
|||
}
|
||||
|
||||
sensor->ext_clk = devm_clk_get(&client->dev, NULL);
|
||||
if (IS_ERR(sensor->ext_clk)) {
|
||||
if (PTR_ERR(sensor->ext_clk) == -ENOENT) {
|
||||
dev_info(&client->dev, "no clock defined, continuing...\n");
|
||||
sensor->ext_clk = NULL;
|
||||
} else if (IS_ERR(sensor->ext_clk)) {
|
||||
dev_err(&client->dev, "could not get clock (%ld)\n",
|
||||
PTR_ERR(sensor->ext_clk));
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
|
||||
rval = clk_set_rate(sensor->ext_clk, sensor->hwcfg->ext_clk);
|
||||
if (rval < 0) {
|
||||
dev_err(&client->dev,
|
||||
"unable to set clock freq to %u\n",
|
||||
if (sensor->ext_clk) {
|
||||
if (sensor->hwcfg->ext_clk) {
|
||||
unsigned long rate;
|
||||
|
||||
rval = clk_set_rate(sensor->ext_clk,
|
||||
sensor->hwcfg->ext_clk);
|
||||
if (rval < 0) {
|
||||
dev_err(&client->dev,
|
||||
"unable to set clock freq to %u\n",
|
||||
sensor->hwcfg->ext_clk);
|
||||
return rval;
|
||||
}
|
||||
|
||||
rate = clk_get_rate(sensor->ext_clk);
|
||||
if (rate != sensor->hwcfg->ext_clk) {
|
||||
dev_err(&client->dev,
|
||||
"can't set clock freq, asked for %u but got %lu\n",
|
||||
sensor->hwcfg->ext_clk, rate);
|
||||
return rval;
|
||||
}
|
||||
} else {
|
||||
sensor->hwcfg->ext_clk = clk_get_rate(sensor->ext_clk);
|
||||
dev_dbg(&client->dev, "obtained clock freq %u\n",
|
||||
sensor->hwcfg->ext_clk);
|
||||
}
|
||||
} else if (sensor->hwcfg->ext_clk) {
|
||||
dev_dbg(&client->dev, "assuming clock freq %u\n",
|
||||
sensor->hwcfg->ext_clk);
|
||||
return rval;
|
||||
} else {
|
||||
dev_err(&client->dev, "unable to obtain clock freq\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
sensor->xshutdown = devm_gpiod_get_optional(&client->dev, "xshutdown",
|
||||
|
@ -3092,7 +3093,7 @@ static int smiapp_probe(struct i2c_client *client,
|
|||
if (rval < 0)
|
||||
goto out_media_entity_cleanup;
|
||||
|
||||
rval = v4l2_async_register_subdev(&sensor->src->sd);
|
||||
rval = v4l2_async_register_subdev_sensor_common(&sensor->src->sd);
|
||||
if (rval < 0)
|
||||
goto out_media_entity_cleanup;
|
||||
|
||||
|
|
|
@ -231,6 +231,9 @@ int smiapp_write_no_quirk(struct smiapp_sensor *sensor, u32 reg, u32 val)
|
|||
len != SMIAPP_REG_32BIT) || flags)
|
||||
return -EINVAL;
|
||||
|
||||
if (!sensor->active)
|
||||
return 0;
|
||||
|
||||
msg.addr = client->addr;
|
||||
msg.flags = 0; /* Write */
|
||||
msg.len = 2 + len;
|
||||
|
|
|
@ -206,6 +206,7 @@ struct smiapp_sensor {
|
|||
|
||||
u8 hvflip_inv_mask; /* H/VFLIP inversion due to sensor orientation */
|
||||
u8 frame_skip;
|
||||
bool active; /* is the sensor powered on? */
|
||||
u16 embedded_start; /* embedded data start line */
|
||||
u16 embedded_end;
|
||||
u16 image_start; /* image data start line */
|
||||
|
|
|
@ -335,8 +335,8 @@ static void ov9640_res_roundup(u32 *width, u32 *height)
|
|||
{
|
||||
int i;
|
||||
enum { QQCIF, QQVGA, QCIF, QVGA, CIF, VGA, SXGA };
|
||||
int res_x[] = { 88, 160, 176, 320, 352, 640, 1280 };
|
||||
int res_y[] = { 72, 120, 144, 240, 288, 480, 960 };
|
||||
static const int res_x[] = { 88, 160, 176, 320, 352, 640, 1280 };
|
||||
static const int res_y[] = { 72, 120, 144, 240, 288, 480, 960 };
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(res_x); i++) {
|
||||
if (res_x[i] >= *width && res_y[i] >= *height) {
|
||||
|
@ -675,12 +675,9 @@ static int ov9640_probe(struct i2c_client *client,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
priv = devm_kzalloc(&client->dev, sizeof(struct ov9640_priv), GFP_KERNEL);
|
||||
if (!priv) {
|
||||
dev_err(&client->dev,
|
||||
"Failed to allocate memory for private data!\n");
|
||||
priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
v4l2_i2c_subdev_init(&priv->subdev, client, &ov9640_subdev_ops);
|
||||
|
||||
|
|
|
@ -935,11 +935,9 @@ static int ov9740_probe(struct i2c_client *client,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
priv = devm_kzalloc(&client->dev, sizeof(struct ov9740_priv), GFP_KERNEL);
|
||||
if (!priv) {
|
||||
dev_err(&client->dev, "Failed to allocate private data!\n");
|
||||
priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
v4l2_i2c_subdev_init(&priv->subdev, client, &ov9740_subdev_ops);
|
||||
v4l2_ctrl_handler_init(&priv->hdl, 13);
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
#include <linux/workqueue.h>
|
||||
#include <linux/v4l2-dv-timings.h>
|
||||
#include <linux/hdmi.h>
|
||||
#include <media/cec.h>
|
||||
#include <media/v4l2-dv-timings.h>
|
||||
#include <media/v4l2-device.h>
|
||||
#include <media/v4l2-ctrls.h>
|
||||
|
@ -63,6 +64,7 @@ MODULE_LICENSE("GPL");
|
|||
|
||||
#define I2C_MAX_XFER_SIZE (EDID_BLOCK_SIZE + 2)
|
||||
|
||||
#define POLL_INTERVAL_CEC_MS 10
|
||||
#define POLL_INTERVAL_MS 1000
|
||||
|
||||
static const struct v4l2_dv_timings_cap tc358743_timings_cap = {
|
||||
|
@ -106,6 +108,8 @@ struct tc358743_state {
|
|||
u8 csi_lanes_in_use;
|
||||
|
||||
struct gpio_desc *reset_gpio;
|
||||
|
||||
struct cec_adapter *cec_adap;
|
||||
};
|
||||
|
||||
static void tc358743_enable_interrupts(struct v4l2_subdev *sd,
|
||||
|
@ -595,6 +599,7 @@ static void tc358743_set_ref_clk(struct v4l2_subdev *sd)
|
|||
struct tc358743_platform_data *pdata = &state->pdata;
|
||||
u32 sys_freq;
|
||||
u32 lockdet_ref;
|
||||
u32 cec_freq;
|
||||
u16 fh_min;
|
||||
u16 fh_max;
|
||||
|
||||
|
@ -626,6 +631,15 @@ static void tc358743_set_ref_clk(struct v4l2_subdev *sd)
|
|||
i2c_wr8_and_or(sd, NCO_F0_MOD, ~MASK_NCO_F0_MOD,
|
||||
(pdata->refclk_hz == 27000000) ?
|
||||
MASK_NCO_F0_MOD_27MHZ : 0x0);
|
||||
|
||||
/*
|
||||
* Trial and error suggests that the default register value
|
||||
* of 656 is for a 42 MHz reference clock. Use that to derive
|
||||
* a new value based on the actual reference clock.
|
||||
*/
|
||||
cec_freq = (656 * sys_freq) / 4200;
|
||||
i2c_wr16(sd, CECHCLK, cec_freq);
|
||||
i2c_wr16(sd, CECLCLK, cec_freq);
|
||||
}
|
||||
|
||||
static void tc358743_set_csi_color_space(struct v4l2_subdev *sd)
|
||||
|
@ -814,11 +828,17 @@ static void tc358743_initial_setup(struct v4l2_subdev *sd)
|
|||
struct tc358743_state *state = to_state(sd);
|
||||
struct tc358743_platform_data *pdata = &state->pdata;
|
||||
|
||||
/* CEC and IR are not supported by this driver */
|
||||
i2c_wr16_and_or(sd, SYSCTL, ~(MASK_CECRST | MASK_IRRST),
|
||||
(MASK_CECRST | MASK_IRRST));
|
||||
/*
|
||||
* IR is not supported by this driver.
|
||||
* CEC is only enabled if needed.
|
||||
*/
|
||||
i2c_wr16_and_or(sd, SYSCTL, ~(MASK_IRRST | MASK_CECRST),
|
||||
(MASK_IRRST | MASK_CECRST));
|
||||
|
||||
tc358743_reset(sd, MASK_CTXRST | MASK_HDMIRST);
|
||||
#ifdef CONFIG_VIDEO_TC358743_CEC
|
||||
tc358743_reset(sd, MASK_CECRST);
|
||||
#endif
|
||||
tc358743_sleep_mode(sd, false);
|
||||
|
||||
i2c_wr16(sd, FIFOCTL, pdata->fifo_level);
|
||||
|
@ -842,6 +862,133 @@ static void tc358743_initial_setup(struct v4l2_subdev *sd)
|
|||
i2c_wr8(sd, VOUT_SET3, MASK_VOUT_EXTCNT);
|
||||
}
|
||||
|
||||
/* --------------- CEC --------------- */
|
||||
|
||||
#ifdef CONFIG_VIDEO_TC358743_CEC
|
||||
static int tc358743_cec_adap_enable(struct cec_adapter *adap, bool enable)
|
||||
{
|
||||
struct tc358743_state *state = adap->priv;
|
||||
struct v4l2_subdev *sd = &state->sd;
|
||||
|
||||
i2c_wr32(sd, CECIMSK, enable ? MASK_CECTIM | MASK_CECRIM : 0);
|
||||
i2c_wr32(sd, CECICLR, MASK_CECTICLR | MASK_CECRICLR);
|
||||
i2c_wr32(sd, CECEN, enable);
|
||||
if (enable)
|
||||
i2c_wr32(sd, CECREN, MASK_CECREN);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tc358743_cec_adap_monitor_all_enable(struct cec_adapter *adap,
|
||||
bool enable)
|
||||
{
|
||||
struct tc358743_state *state = adap->priv;
|
||||
struct v4l2_subdev *sd = &state->sd;
|
||||
u32 reg;
|
||||
|
||||
reg = i2c_rd32(sd, CECRCTL1);
|
||||
if (enable)
|
||||
reg |= MASK_CECOTH;
|
||||
else
|
||||
reg &= ~MASK_CECOTH;
|
||||
i2c_wr32(sd, CECRCTL1, reg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tc358743_cec_adap_log_addr(struct cec_adapter *adap, u8 log_addr)
|
||||
{
|
||||
struct tc358743_state *state = adap->priv;
|
||||
struct v4l2_subdev *sd = &state->sd;
|
||||
unsigned int la = 0;
|
||||
|
||||
if (log_addr != CEC_LOG_ADDR_INVALID) {
|
||||
la = i2c_rd32(sd, CECADD);
|
||||
la |= 1 << log_addr;
|
||||
}
|
||||
i2c_wr32(sd, CECADD, la);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tc358743_cec_adap_transmit(struct cec_adapter *adap, u8 attempts,
|
||||
u32 signal_free_time, struct cec_msg *msg)
|
||||
{
|
||||
struct tc358743_state *state = adap->priv;
|
||||
struct v4l2_subdev *sd = &state->sd;
|
||||
unsigned int i;
|
||||
|
||||
i2c_wr32(sd, CECTCTL,
|
||||
(cec_msg_is_broadcast(msg) ? MASK_CECBRD : 0) |
|
||||
(signal_free_time - 1));
|
||||
for (i = 0; i < msg->len; i++)
|
||||
i2c_wr32(sd, CECTBUF1 + i * 4,
|
||||
msg->msg[i] | ((i == msg->len - 1) ? MASK_CECTEOM : 0));
|
||||
i2c_wr32(sd, CECTEN, MASK_CECTEN);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct cec_adap_ops tc358743_cec_adap_ops = {
|
||||
.adap_enable = tc358743_cec_adap_enable,
|
||||
.adap_log_addr = tc358743_cec_adap_log_addr,
|
||||
.adap_transmit = tc358743_cec_adap_transmit,
|
||||
.adap_monitor_all_enable = tc358743_cec_adap_monitor_all_enable,
|
||||
};
|
||||
|
||||
static void tc358743_cec_isr(struct v4l2_subdev *sd, u16 intstatus,
|
||||
bool *handled)
|
||||
{
|
||||
struct tc358743_state *state = to_state(sd);
|
||||
unsigned int cec_rxint, cec_txint;
|
||||
unsigned int clr = 0;
|
||||
|
||||
cec_rxint = i2c_rd32(sd, CECRSTAT);
|
||||
cec_txint = i2c_rd32(sd, CECTSTAT);
|
||||
|
||||
if (intstatus & MASK_CEC_RINT)
|
||||
clr |= MASK_CECRICLR;
|
||||
if (intstatus & MASK_CEC_TINT)
|
||||
clr |= MASK_CECTICLR;
|
||||
i2c_wr32(sd, CECICLR, clr);
|
||||
|
||||
if ((intstatus & MASK_CEC_TINT) && cec_txint) {
|
||||
if (cec_txint & MASK_CECTIEND)
|
||||
cec_transmit_attempt_done(state->cec_adap,
|
||||
CEC_TX_STATUS_OK);
|
||||
else if (cec_txint & MASK_CECTIAL)
|
||||
cec_transmit_attempt_done(state->cec_adap,
|
||||
CEC_TX_STATUS_ARB_LOST);
|
||||
else if (cec_txint & MASK_CECTIACK)
|
||||
cec_transmit_attempt_done(state->cec_adap,
|
||||
CEC_TX_STATUS_NACK);
|
||||
else if (cec_txint & MASK_CECTIUR) {
|
||||
/*
|
||||
* Not sure when this bit is set. Treat
|
||||
* it as an error for now.
|
||||
*/
|
||||
cec_transmit_attempt_done(state->cec_adap,
|
||||
CEC_TX_STATUS_ERROR);
|
||||
}
|
||||
*handled = true;
|
||||
}
|
||||
if ((intstatus & MASK_CEC_RINT) &&
|
||||
(cec_rxint & MASK_CECRIEND)) {
|
||||
struct cec_msg msg = {};
|
||||
unsigned int i;
|
||||
unsigned int v;
|
||||
|
||||
v = i2c_rd32(sd, CECRCTR);
|
||||
msg.len = v & 0x1f;
|
||||
for (i = 0; i < msg.len; i++) {
|
||||
v = i2c_rd32(sd, CECRBUF1 + i * 4);
|
||||
msg.msg[i] = v & 0xff;
|
||||
}
|
||||
cec_received_msg(state->cec_adap, &msg);
|
||||
*handled = true;
|
||||
}
|
||||
i2c_wr16(sd, INTSTATUS,
|
||||
intstatus & (MASK_CEC_RINT | MASK_CEC_TINT));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* --------------- IRQ --------------- */
|
||||
|
||||
static void tc358743_format_change(struct v4l2_subdev *sd)
|
||||
|
@ -1296,6 +1443,15 @@ static int tc358743_isr(struct v4l2_subdev *sd, u32 status, bool *handled)
|
|||
intstatus &= ~MASK_HDMI_INT;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_VIDEO_TC358743_CEC
|
||||
if (intstatus & (MASK_CEC_RINT | MASK_CEC_TINT)) {
|
||||
tc358743_cec_isr(sd, intstatus, handled);
|
||||
i2c_wr16(sd, INTSTATUS,
|
||||
intstatus & (MASK_CEC_RINT | MASK_CEC_TINT));
|
||||
intstatus &= ~(MASK_CEC_RINT | MASK_CEC_TINT);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (intstatus & MASK_CSI_INT) {
|
||||
u32 csi_int = i2c_rd32(sd, CSI_INT);
|
||||
|
||||
|
@ -1325,13 +1481,18 @@ static irqreturn_t tc358743_irq_handler(int irq, void *dev_id)
|
|||
return handled ? IRQ_HANDLED : IRQ_NONE;
|
||||
}
|
||||
|
||||
static void tc358743_irq_poll_timer(unsigned long arg)
|
||||
static void tc358743_irq_poll_timer(struct timer_list *t)
|
||||
{
|
||||
struct tc358743_state *state = (struct tc358743_state *)arg;
|
||||
struct tc358743_state *state = from_timer(state, t, timer);
|
||||
unsigned int msecs;
|
||||
|
||||
schedule_work(&state->work_i2c_poll);
|
||||
|
||||
mod_timer(&state->timer, jiffies + msecs_to_jiffies(POLL_INTERVAL_MS));
|
||||
/*
|
||||
* If CEC is present, then we need to poll more frequently,
|
||||
* otherwise we will miss CEC messages.
|
||||
*/
|
||||
msecs = state->cec_adap ? POLL_INTERVAL_CEC_MS : POLL_INTERVAL_MS;
|
||||
mod_timer(&state->timer, jiffies + msecs_to_jiffies(msecs));
|
||||
}
|
||||
|
||||
static void tc358743_work_i2c_poll(struct work_struct *work)
|
||||
|
@ -1488,7 +1649,7 @@ static int tc358743_s_stream(struct v4l2_subdev *sd, int enable)
|
|||
{
|
||||
enable_stream(sd, enable);
|
||||
if (!enable) {
|
||||
/* Put all lanes in PL-11 state (STOPSTATE) */
|
||||
/* Put all lanes in LP-11 state (STOPSTATE) */
|
||||
tc358743_set_csi(sd);
|
||||
}
|
||||
|
||||
|
@ -1621,6 +1782,8 @@ static int tc358743_s_edid(struct v4l2_subdev *sd,
|
|||
{
|
||||
struct tc358743_state *state = to_state(sd);
|
||||
u16 edid_len = edid->blocks * EDID_BLOCK_SIZE;
|
||||
u16 pa;
|
||||
int err;
|
||||
int i;
|
||||
|
||||
v4l2_dbg(2, debug, sd, "%s, pad %d, start block %d, blocks %d\n",
|
||||
|
@ -1638,6 +1801,12 @@ static int tc358743_s_edid(struct v4l2_subdev *sd,
|
|||
edid->blocks = EDID_NUM_BLOCKS_MAX;
|
||||
return -E2BIG;
|
||||
}
|
||||
pa = cec_get_edid_phys_addr(edid->edid, edid->blocks * 128, NULL);
|
||||
err = cec_phys_addr_validate(pa, &pa, NULL);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
cec_phys_addr_invalidate(state->cec_adap);
|
||||
|
||||
tc358743_disable_edid(sd);
|
||||
|
||||
|
@ -1654,6 +1823,8 @@ static int tc358743_s_edid(struct v4l2_subdev *sd,
|
|||
|
||||
state->edid_blocks_written = edid->blocks;
|
||||
|
||||
cec_s_phys_addr(state->cec_adap, pa, false);
|
||||
|
||||
if (tx_5v_power_present(sd))
|
||||
tc358743_enable_edid(sd);
|
||||
|
||||
|
@ -1770,6 +1941,11 @@ static int tc358743_probe_of(struct tc358743_state *state)
|
|||
goto free_endpoint;
|
||||
}
|
||||
|
||||
if (endpoint->bus.mipi_csi2.num_data_lanes > 4) {
|
||||
dev_err(dev, "invalid number of lanes\n");
|
||||
goto free_endpoint;
|
||||
}
|
||||
|
||||
state->bus = endpoint->bus.mipi_csi2;
|
||||
|
||||
ret = clk_prepare_enable(refclk);
|
||||
|
@ -1867,6 +2043,7 @@ static int tc358743_probe(struct i2c_client *client,
|
|||
struct tc358743_state *state;
|
||||
struct tc358743_platform_data *pdata = client->dev.platform_data;
|
||||
struct v4l2_subdev *sd;
|
||||
u16 irq_mask = MASK_HDMI_MSK | MASK_CSI_MSK;
|
||||
int err;
|
||||
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
||||
|
@ -1929,6 +2106,7 @@ static int tc358743_probe(struct i2c_client *client,
|
|||
}
|
||||
|
||||
state->pad.flags = MEDIA_PAD_FL_SOURCE;
|
||||
sd->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
|
||||
err = media_entity_pads_init(&sd->entity, 1, &state->pad);
|
||||
if (err < 0)
|
||||
goto err_hdl;
|
||||
|
@ -1945,6 +2123,17 @@ static int tc358743_probe(struct i2c_client *client,
|
|||
INIT_DELAYED_WORK(&state->delayed_work_enable_hotplug,
|
||||
tc358743_delayed_work_enable_hotplug);
|
||||
|
||||
#ifdef CONFIG_VIDEO_TC358743_CEC
|
||||
state->cec_adap = cec_allocate_adapter(&tc358743_cec_adap_ops,
|
||||
state, dev_name(&client->dev),
|
||||
CEC_CAP_DEFAULTS | CEC_CAP_MONITOR_ALL, CEC_MAX_LOG_ADDRS);
|
||||
if (IS_ERR(state->cec_adap)) {
|
||||
err = PTR_ERR(state->cec_adap);
|
||||
goto err_hdl;
|
||||
}
|
||||
irq_mask |= MASK_CEC_RMSK | MASK_CEC_TMSK;
|
||||
#endif
|
||||
|
||||
tc358743_initial_setup(sd);
|
||||
|
||||
tc358743_s_dv_timings(sd, &default_timing);
|
||||
|
@ -1964,15 +2153,22 @@ static int tc358743_probe(struct i2c_client *client,
|
|||
} else {
|
||||
INIT_WORK(&state->work_i2c_poll,
|
||||
tc358743_work_i2c_poll);
|
||||
state->timer.data = (unsigned long)state;
|
||||
state->timer.function = tc358743_irq_poll_timer;
|
||||
timer_setup(&state->timer, tc358743_irq_poll_timer, 0);
|
||||
state->timer.expires = jiffies +
|
||||
msecs_to_jiffies(POLL_INTERVAL_MS);
|
||||
add_timer(&state->timer);
|
||||
}
|
||||
|
||||
err = cec_register_adapter(state->cec_adap, &client->dev);
|
||||
if (err < 0) {
|
||||
pr_err("%s: failed to register the cec device\n", __func__);
|
||||
cec_delete_adapter(state->cec_adap);
|
||||
state->cec_adap = NULL;
|
||||
goto err_work_queues;
|
||||
}
|
||||
|
||||
tc358743_enable_interrupts(sd, tx_5v_power_present(sd));
|
||||
i2c_wr16(sd, INTMASK, ~(MASK_HDMI_MSK | MASK_CSI_MSK) & 0xffff);
|
||||
i2c_wr16(sd, INTMASK, ~irq_mask);
|
||||
|
||||
err = v4l2_ctrl_handler_setup(sd->ctrl_handler);
|
||||
if (err)
|
||||
|
@ -1984,6 +2180,7 @@ static int tc358743_probe(struct i2c_client *client,
|
|||
return 0;
|
||||
|
||||
err_work_queues:
|
||||
cec_unregister_adapter(state->cec_adap);
|
||||
if (!state->i2c_client->irq)
|
||||
flush_work(&state->work_i2c_poll);
|
||||
cancel_delayed_work(&state->delayed_work_enable_hotplug);
|
||||
|
@ -2004,6 +2201,7 @@ static int tc358743_remove(struct i2c_client *client)
|
|||
flush_work(&state->work_i2c_poll);
|
||||
}
|
||||
cancel_delayed_work(&state->delayed_work_enable_hotplug);
|
||||
cec_unregister_adapter(state->cec_adap);
|
||||
v4l2_async_unregister_subdev(sd);
|
||||
v4l2_device_unregister_subdev(sd);
|
||||
mutex_destroy(&state->confctl_mutex);
|
||||
|
|
|
@ -193,8 +193,98 @@
|
|||
#define CSI_START 0x0518
|
||||
#define MASK_STRT 0x00000001
|
||||
|
||||
#define CECEN 0x0600
|
||||
#define MASK_CECEN 0x0001
|
||||
/* *** CEC (32 bit) *** */
|
||||
#define CECHCLK 0x0028 /* 16 bits */
|
||||
#define MASK_CECHCLK (0x7ff << 0)
|
||||
|
||||
#define CECLCLK 0x002a /* 16 bits */
|
||||
#define MASK_CECLCLK (0x7ff << 0)
|
||||
|
||||
#define CECEN 0x0600
|
||||
#define MASK_CECEN 0x0001
|
||||
|
||||
#define CECADD 0x0604
|
||||
#define CECRST 0x0608
|
||||
#define MASK_CECRESET 0x0001
|
||||
|
||||
#define CECREN 0x060c
|
||||
#define MASK_CECREN 0x0001
|
||||
|
||||
#define CECRCTL1 0x0614
|
||||
#define MASK_CECACKDIS (1 << 24)
|
||||
#define MASK_CECHNC (3 << 20)
|
||||
#define MASK_CECLNC (7 << 16)
|
||||
#define MASK_CECMIN (7 << 12)
|
||||
#define MASK_CECMAX (7 << 8)
|
||||
#define MASK_CECDAT (7 << 4)
|
||||
#define MASK_CECTOUT (3 << 2)
|
||||
#define MASK_CECRIHLD (1 << 1)
|
||||
#define MASK_CECOTH (1 << 0)
|
||||
|
||||
#define CECRCTL2 0x0618
|
||||
#define MASK_CECSWAV3 (7 << 12)
|
||||
#define MASK_CECSWAV2 (7 << 8)
|
||||
#define MASK_CECSWAV1 (7 << 4)
|
||||
#define MASK_CECSWAV0 (7 << 0)
|
||||
|
||||
#define CECRCTL3 0x061c
|
||||
#define MASK_CECWAV3 (7 << 20)
|
||||
#define MASK_CECWAV2 (7 << 16)
|
||||
#define MASK_CECWAV1 (7 << 12)
|
||||
#define MASK_CECWAV0 (7 << 8)
|
||||
#define MASK_CECACKEI (1 << 4)
|
||||
#define MASK_CECMINEI (1 << 3)
|
||||
#define MASK_CECMAXEI (1 << 2)
|
||||
#define MASK_CECRSTEI (1 << 1)
|
||||
#define MASK_CECWAVEI (1 << 0)
|
||||
|
||||
#define CECTEN 0x0620
|
||||
#define MASK_CECTBUSY (1 << 1)
|
||||
#define MASK_CECTEN (1 << 0)
|
||||
|
||||
#define CECTCTL 0x0628
|
||||
#define MASK_CECSTRS (7 << 20)
|
||||
#define MASK_CECSPRD (7 << 16)
|
||||
#define MASK_CECDTRS (7 << 12)
|
||||
#define MASK_CECDPRD (15 << 8)
|
||||
#define MASK_CECBRD (1 << 4)
|
||||
#define MASK_CECFREE (15 << 0)
|
||||
|
||||
#define CECRSTAT 0x062c
|
||||
#define MASK_CECRIWA (1 << 6)
|
||||
#define MASK_CECRIOR (1 << 5)
|
||||
#define MASK_CECRIACK (1 << 4)
|
||||
#define MASK_CECRIMIN (1 << 3)
|
||||
#define MASK_CECRIMAX (1 << 2)
|
||||
#define MASK_CECRISTA (1 << 1)
|
||||
#define MASK_CECRIEND (1 << 0)
|
||||
|
||||
#define CECTSTAT 0x0630
|
||||
#define MASK_CECTIUR (1 << 4)
|
||||
#define MASK_CECTIACK (1 << 3)
|
||||
#define MASK_CECTIAL (1 << 2)
|
||||
#define MASK_CECTIEND (1 << 1)
|
||||
|
||||
#define CECRBUF1 0x0634
|
||||
#define MASK_CECRACK (1 << 9)
|
||||
#define MASK_CECEOM (1 << 8)
|
||||
#define MASK_CECRBYTE (0xff << 0)
|
||||
|
||||
#define CECTBUF1 0x0674
|
||||
#define MASK_CECTEOM (1 << 8)
|
||||
#define MASK_CECTBYTE (0xff << 0)
|
||||
|
||||
#define CECRCTR 0x06b4
|
||||
#define MASK_CECRCTR (0x1f << 0)
|
||||
|
||||
#define CECIMSK 0x06c0
|
||||
#define MASK_CECTIM (1 << 1)
|
||||
#define MASK_CECRIM (1 << 0)
|
||||
|
||||
#define CECICLR 0x06cc
|
||||
#define MASK_CECTICLR (1 << 1)
|
||||
#define MASK_CECRICLR (1 << 0)
|
||||
|
||||
|
||||
#define HDMI_INT0 0x8500
|
||||
#define MASK_I_KEY 0x80
|
||||
|
|
|
@ -300,9 +300,9 @@ static int chip_cmd(struct CHIPSTATE *chip, char *name, audiocmd *cmd)
|
|||
* if available, ...
|
||||
*/
|
||||
|
||||
static void chip_thread_wake(unsigned long data)
|
||||
static void chip_thread_wake(struct timer_list *t)
|
||||
{
|
||||
struct CHIPSTATE *chip = (struct CHIPSTATE*)data;
|
||||
struct CHIPSTATE *chip = from_timer(chip, t, wt);
|
||||
wake_up_process(chip->thread);
|
||||
}
|
||||
|
||||
|
@ -1995,7 +1995,7 @@ static int tvaudio_probe(struct i2c_client *client, const struct i2c_device_id *
|
|||
v4l2_ctrl_handler_setup(&chip->hdl);
|
||||
|
||||
chip->thread = NULL;
|
||||
init_timer(&chip->wt);
|
||||
timer_setup(&chip->wt, chip_thread_wake, 0);
|
||||
if (desc->flags & CHIP_NEED_CHECKMODE) {
|
||||
if (!desc->getrxsubchans || !desc->setaudmode) {
|
||||
/* This shouldn't be happen. Warn user, but keep working
|
||||
|
@ -2005,8 +2005,6 @@ static int tvaudio_probe(struct i2c_client *client, const struct i2c_device_id *
|
|||
return 0;
|
||||
}
|
||||
/* start async thread */
|
||||
chip->wt.function = chip_thread_wake;
|
||||
chip->wt.data = (unsigned long)chip;
|
||||
chip->thread = kthread_run(chip_thread, chip, "%s",
|
||||
client->name);
|
||||
if (IS_ERR(chip->thread)) {
|
||||
|
|
|
@ -214,12 +214,20 @@ void media_gobj_destroy(struct media_gobj *gobj)
|
|||
gobj->mdev = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO: Get rid of this.
|
||||
*/
|
||||
#define MEDIA_ENTITY_MAX_PADS 512
|
||||
|
||||
int media_entity_pads_init(struct media_entity *entity, u16 num_pads,
|
||||
struct media_pad *pads)
|
||||
{
|
||||
struct media_device *mdev = entity->graph_obj.mdev;
|
||||
unsigned int i;
|
||||
|
||||
if (num_pads >= MEDIA_ENTITY_MAX_PADS)
|
||||
return -E2BIG;
|
||||
|
||||
entity->num_pads = num_pads;
|
||||
entity->pads = pads;
|
||||
|
||||
|
@ -280,11 +288,6 @@ static struct media_entity *stack_pop(struct media_graph *graph)
|
|||
#define link_top(en) ((en)->stack[(en)->top].link)
|
||||
#define stack_top(en) ((en)->stack[(en)->top].entity)
|
||||
|
||||
/*
|
||||
* TODO: Get rid of this.
|
||||
*/
|
||||
#define MEDIA_ENTITY_MAX_PADS 512
|
||||
|
||||
/**
|
||||
* media_graph_walk_init - Allocate resources for graph walk
|
||||
* @graph: Media graph structure that will be used to walk the graph
|
||||
|
|
|
@ -11,5 +11,5 @@ config DVB_B2C2_FLEXCOP_PCI_DEBUG
|
|||
depends on DVB_B2C2_FLEXCOP_PCI
|
||||
select DVB_B2C2_FLEXCOP_DEBUG
|
||||
help
|
||||
Say Y if you want to enable the module option to control debug messages
|
||||
of all B2C2 FlexCop drivers.
|
||||
Say Y if you want to enable the module option to control debug messages
|
||||
of all B2C2 FlexCop drivers.
|
||||
|
|
|
@ -3652,9 +3652,9 @@ bttv_irq_wakeup_vbi(struct bttv *btv, struct bttv_buffer *wakeup,
|
|||
wake_up(&wakeup->vb.done);
|
||||
}
|
||||
|
||||
static void bttv_irq_timeout(unsigned long data)
|
||||
static void bttv_irq_timeout(struct timer_list *t)
|
||||
{
|
||||
struct bttv *btv = (struct bttv *)data;
|
||||
struct bttv *btv = from_timer(btv, t, timeout);
|
||||
struct bttv_buffer_set old,new;
|
||||
struct bttv_buffer *ovbi;
|
||||
struct bttv_buffer *item;
|
||||
|
@ -4043,7 +4043,7 @@ static int bttv_probe(struct pci_dev *dev, const struct pci_device_id *pci_id)
|
|||
INIT_LIST_HEAD(&btv->capture);
|
||||
INIT_LIST_HEAD(&btv->vcapture);
|
||||
|
||||
setup_timer(&btv->timeout, bttv_irq_timeout, (unsigned long)btv);
|
||||
timer_setup(&btv->timeout, bttv_irq_timeout, 0);
|
||||
|
||||
btv->i2c_rc = -1;
|
||||
btv->tuner_type = UNSET;
|
||||
|
|
|
@ -133,10 +133,10 @@ void bttv_input_irq(struct bttv *btv)
|
|||
ir_handle_key(btv);
|
||||
}
|
||||
|
||||
static void bttv_input_timer(unsigned long data)
|
||||
static void bttv_input_timer(struct timer_list *t)
|
||||
{
|
||||
struct bttv *btv = (struct bttv*)data;
|
||||
struct bttv_ir *ir = btv->remote;
|
||||
struct bttv_ir *ir = from_timer(ir, t, timer);
|
||||
struct bttv *btv = ir->btv;
|
||||
|
||||
if (btv->c.type == BTTV_BOARD_ENLTV_FM_2)
|
||||
ir_enltv_handle_key(btv);
|
||||
|
@ -189,9 +189,9 @@ static u32 bttv_rc5_decode(unsigned int code)
|
|||
return rc5;
|
||||
}
|
||||
|
||||
static void bttv_rc5_timer_end(unsigned long data)
|
||||
static void bttv_rc5_timer_end(struct timer_list *t)
|
||||
{
|
||||
struct bttv_ir *ir = (struct bttv_ir *)data;
|
||||
struct bttv_ir *ir = from_timer(ir, t, timer);
|
||||
ktime_t tv;
|
||||
u32 gap, rc5, scancode;
|
||||
u8 toggle, command, system;
|
||||
|
@ -296,15 +296,15 @@ static int bttv_rc5_irq(struct bttv *btv)
|
|||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
static void bttv_ir_start(struct bttv *btv, struct bttv_ir *ir)
|
||||
static void bttv_ir_start(struct bttv_ir *ir)
|
||||
{
|
||||
if (ir->polling) {
|
||||
setup_timer(&ir->timer, bttv_input_timer, (unsigned long)btv);
|
||||
timer_setup(&ir->timer, bttv_input_timer, 0);
|
||||
ir->timer.expires = jiffies + msecs_to_jiffies(1000);
|
||||
add_timer(&ir->timer);
|
||||
} else if (ir->rc5_gpio) {
|
||||
/* set timer_end for code completion */
|
||||
setup_timer(&ir->timer, bttv_rc5_timer_end, (unsigned long)ir);
|
||||
timer_setup(&ir->timer, bttv_rc5_timer_end, 0);
|
||||
ir->shift_by = 1;
|
||||
ir->rc5_remote_gap = ir_rc5_remote_gap;
|
||||
}
|
||||
|
@ -531,6 +531,7 @@ int bttv_input_init(struct bttv *btv)
|
|||
|
||||
/* init input device */
|
||||
ir->dev = rc;
|
||||
ir->btv = btv;
|
||||
|
||||
snprintf(ir->name, sizeof(ir->name), "bttv IR (card=%d)",
|
||||
btv->c.type);
|
||||
|
@ -553,7 +554,7 @@ int bttv_input_init(struct bttv *btv)
|
|||
rc->driver_name = MODULE_NAME;
|
||||
|
||||
btv->remote = ir;
|
||||
bttv_ir_start(btv, ir);
|
||||
bttv_ir_start(ir);
|
||||
|
||||
/* all done */
|
||||
err = rc_register_device(rc);
|
||||
|
|
|
@ -233,7 +233,7 @@ static void vbi_buffer_release(struct videobuf_queue *q, struct videobuf_buffer
|
|||
bttv_dma_free(q,fh->btv,buf);
|
||||
}
|
||||
|
||||
struct videobuf_queue_ops bttv_vbi_qops = {
|
||||
const struct videobuf_queue_ops bttv_vbi_qops = {
|
||||
.buf_setup = vbi_buffer_setup,
|
||||
.buf_prepare = vbi_buffer_prepare,
|
||||
.buf_queue = vbi_buffer_queue,
|
||||
|
|
|
@ -122,6 +122,7 @@ struct bttv_format {
|
|||
|
||||
struct bttv_ir {
|
||||
struct rc_dev *dev;
|
||||
struct bttv *btv;
|
||||
struct timer_list timer;
|
||||
|
||||
char name[32];
|
||||
|
@ -281,7 +282,7 @@ int bttv_try_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *f);
|
|||
int bttv_g_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *f);
|
||||
int bttv_s_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *f);
|
||||
|
||||
extern struct videobuf_queue_ops bttv_vbi_qops;
|
||||
extern const struct videobuf_queue_ops bttv_vbi_qops;
|
||||
|
||||
/* ---------------------------------------------------------- */
|
||||
/* bttv-gpio.c */
|
||||
|
|
|
@ -738,9 +738,6 @@ static int cobalt_probe(struct pci_dev *pci_dev,
|
|||
goto err_i2c;
|
||||
}
|
||||
|
||||
retval = v4l2_device_register_subdev_nodes(&cobalt->v4l2_dev);
|
||||
if (retval)
|
||||
goto err_i2c;
|
||||
retval = cobalt_nodes_register(cobalt);
|
||||
if (retval) {
|
||||
cobalt_err("Error %d registering device nodes\n", retval);
|
||||
|
@ -767,8 +764,6 @@ static int cobalt_probe(struct pci_dev *pci_dev,
|
|||
err_wq:
|
||||
destroy_workqueue(cobalt->irq_work_queues);
|
||||
err:
|
||||
if (retval == 0)
|
||||
retval = -ENODEV;
|
||||
cobalt_err("error %d on initialization\n", retval);
|
||||
|
||||
v4l2_device_unregister(&cobalt->v4l2_dev);
|
||||
|
|
|
@ -255,7 +255,7 @@ static void request_module_async(struct work_struct *work)
|
|||
request_module("cx18-alsa");
|
||||
|
||||
/* Initialize cx18-alsa for this instance of the cx18 device */
|
||||
if (cx18_ext_init != NULL)
|
||||
if (cx18_ext_init)
|
||||
cx18_ext_init(dev);
|
||||
}
|
||||
|
||||
|
@ -291,11 +291,11 @@ int cx18_msleep_timeout(unsigned int msecs, int intr)
|
|||
/* Release ioremapped memory */
|
||||
static void cx18_iounmap(struct cx18 *cx)
|
||||
{
|
||||
if (cx == NULL)
|
||||
if (!cx)
|
||||
return;
|
||||
|
||||
/* Release io memory */
|
||||
if (cx->enc_mem != NULL) {
|
||||
if (cx->enc_mem) {
|
||||
CX18_DEBUG_INFO("releasing enc_mem\n");
|
||||
iounmap(cx->enc_mem);
|
||||
cx->enc_mem = NULL;
|
||||
|
@ -649,15 +649,15 @@ static void cx18_process_options(struct cx18 *cx)
|
|||
CX18_INFO("User specified %s card\n", cx->card->name);
|
||||
else if (cx->options.cardtype != 0)
|
||||
CX18_ERR("Unknown user specified type, trying to autodetect card\n");
|
||||
if (cx->card == NULL) {
|
||||
if (!cx->card) {
|
||||
if (cx->pci_dev->subsystem_vendor == CX18_PCI_ID_HAUPPAUGE) {
|
||||
cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT);
|
||||
CX18_INFO("Autodetected Hauppauge card\n");
|
||||
}
|
||||
}
|
||||
if (cx->card == NULL) {
|
||||
if (!cx->card) {
|
||||
for (i = 0; (cx->card = cx18_get_card(i)); i++) {
|
||||
if (cx->card->pci_list == NULL)
|
||||
if (!cx->card->pci_list)
|
||||
continue;
|
||||
for (j = 0; cx->card->pci_list[j].device; j++) {
|
||||
if (cx->pci_dev->device !=
|
||||
|
@ -676,7 +676,7 @@ static void cx18_process_options(struct cx18 *cx)
|
|||
}
|
||||
done:
|
||||
|
||||
if (cx->card == NULL) {
|
||||
if (!cx->card) {
|
||||
cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT);
|
||||
CX18_ERR("Unknown card: vendor/device: [%04x:%04x]\n",
|
||||
cx->pci_dev->vendor, cx->pci_dev->device);
|
||||
|
@ -698,7 +698,7 @@ static int cx18_create_in_workq(struct cx18 *cx)
|
|||
snprintf(cx->in_workq_name, sizeof(cx->in_workq_name), "%s-in",
|
||||
cx->v4l2_dev.name);
|
||||
cx->in_work_queue = alloc_ordered_workqueue("%s", 0, cx->in_workq_name);
|
||||
if (cx->in_work_queue == NULL) {
|
||||
if (!cx->in_work_queue) {
|
||||
CX18_ERR("Unable to create incoming mailbox handler thread\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
@ -909,12 +909,10 @@ static int cx18_probe(struct pci_dev *pci_dev,
|
|||
return -ENOMEM;
|
||||
}
|
||||
|
||||
cx = kzalloc(sizeof(struct cx18), GFP_ATOMIC);
|
||||
if (cx == NULL) {
|
||||
printk(KERN_ERR "cx18: cannot manage card %d, out of memory\n",
|
||||
i);
|
||||
cx = kzalloc(sizeof(*cx), GFP_ATOMIC);
|
||||
if (!cx)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
cx->pci_dev = pci_dev;
|
||||
cx->instance = i;
|
||||
|
||||
|
@ -1256,7 +1254,7 @@ static void cx18_cancel_out_work_orders(struct cx18 *cx)
|
|||
{
|
||||
int i;
|
||||
for (i = 0; i < CX18_MAX_STREAMS; i++)
|
||||
if (&cx->streams[i].video_dev != NULL)
|
||||
if (&cx->streams[i].video_dev)
|
||||
cancel_work_sync(&cx->streams[i].out_work_order);
|
||||
}
|
||||
|
||||
|
@ -1301,7 +1299,7 @@ static void cx18_remove(struct pci_dev *pci_dev)
|
|||
|
||||
pci_disable_device(cx->pci_dev);
|
||||
|
||||
if (cx->vbi.sliced_mpeg_data[0] != NULL)
|
||||
if (cx->vbi.sliced_mpeg_data[0])
|
||||
for (i = 0; i < CX18_VBI_FRAMES; i++)
|
||||
kfree(cx->vbi.sliced_mpeg_data[i]);
|
||||
|
||||
|
|
|
@ -684,9 +684,9 @@ int cx18_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
void cx18_vb_timeout(unsigned long data)
|
||||
void cx18_vb_timeout(struct timer_list *t)
|
||||
{
|
||||
struct cx18_stream *s = (struct cx18_stream *)data;
|
||||
struct cx18_stream *s = from_timer(s, t, vb_timeout);
|
||||
struct cx18_videobuf_buffer *buf;
|
||||
unsigned long flags;
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ void cx18_stop_capture(struct cx18_open_id *id, int gop_end);
|
|||
void cx18_mute(struct cx18 *cx);
|
||||
void cx18_unmute(struct cx18 *cx);
|
||||
int cx18_v4l2_mmap(struct file *file, struct vm_area_struct *vma);
|
||||
void cx18_vb_timeout(unsigned long data);
|
||||
void cx18_vb_timeout(struct timer_list *t);
|
||||
|
||||
/* Shared with cx18-alsa module */
|
||||
int cx18_claim_stream(struct cx18_open_id *id, int type);
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue