media updates for v4.7-rc1
-----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJXPDJgAAoJEAhfPr2O5OEVtqIP/0Sz8w0RkfvBO1Rw39C5fuhm Qc5ANFwVEAVMq+0nSGfBUzRX1a6P7g7sJrWFeXzJ4iY3wInUK1CJKxUnfz/gvuNt Xjplq6ebvh81SP3VGaXJwBesH56NHfUCOioQnk8Oyo9MBsXwgBKvAbby2YiqwuP/ 1t6meQ/pSSqdC4g6Z5hrRIzlLEvf14DKOgDOBUHF1wdn8So3mXSDFwW3Y8T4C4g6 1WDqmCG8qlIMo4xMj4Dqk6bqgRkWnHuUrENkSWlvzguXkspKyRp/TEkOrJxqJnyp ZlFoIW7KSLl7uPY1e/JM6BI8v74WQLfmph37a7hEmsAVmCbVTskiKb+rfbDj6vOG THBKJhocsPrAtBjnK0C5Xgb6e64dHw84okVRb/6uz67qqdg5c3sRerf9pZR8QkCS P6ng27ulbfJAf4qQdEeP8cmWUQrif4tNjCv5qPTL9hEATNKnJAF7rAaR8Zv+Qf/G wTQ3fJ9qofS9xaKfNjKBtbVRNbtYoDysNJlvhEp6SWfVR+HyDoWiH9HMvryyG/Gk VAlQfhGRsocNvDW8V5j94NiKI3LjVtJMS3QOqbYyaChTSFSaJ5fRWcqQskweDRgS glS80VhlHzoHx3C81VxE7V7kNtGdxiIzgnQUaVtEV4w5FcbxEJG3ElUdaFVVjDgZ xVoie3zxLM2E9Q5hhIE+ =s0vv -----END PGP SIGNATURE----- Merge tag 'media/v4.7-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media Pull media updates from Mauro Carvalho Chehab: - added support for Intersil/Techwell TW686x-based video capture cards - v4l PCI skeleton driver moved to samples directory - Documentation cleanups and improvements - RC: reduced the memory footprint for IR raw events - tpg: Export the tpg code from vivid as a module - adv7180: Add device tree binding documentation - lots of driver improvements and fixes * tag 'media/v4.7-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (173 commits) [media] exynos-gsc: avoid build warning without CONFIG_OF [media] samples: v4l: from Documentation to samples directory [media] dib0700: add USB ID for another STK8096-PVR ref design based card [media] tvp5150: propagate I2C write error in .s_register callback [media] tvp5150: return I2C write operation failure to callers [media] em28xx: add support for Hauppauge WinTV-dualHD DVB tuner [media] em28xx: add missing USB IDs [media] update cx23885 and em28xx cardlists [media] media: au0828 fix au0828_v4l2_device_register() to not unlock and free [media] c8sectpfe: Rework firmware loading mechanism [media] c8sectpfe: Demote print to dev_dbg [media] c8sectpfe: Fix broken circular buffer wp management [media] media-device: Simplify compat32 logic [media] media: i2c: ths7303: remove redundant assignment on bt [media] dvb-usb: hide unused functions [media] xilinx-vipp: remove unnecessary of_node_put [media] drivers/media/media-devnode: clear private_data before put_device() [media] drivers/media/media-device: move debug log before _devnode_unregister() [media] drivers/media/rc: postpone kfree(rc_dev) [media] media/dvb-core: forward media_create_pad_links() return value ...
This commit is contained in:
commit
19c5abcb74
|
@ -233,6 +233,7 @@ X!Isound/sound_firmware.c
|
|||
!Iinclude/media/v4l2-mediabus.h
|
||||
!Iinclude/media/v4l2-mem2mem.h
|
||||
!Iinclude/media/v4l2-of.h
|
||||
!Iinclude/media/v4l2-rect.h
|
||||
!Iinclude/media/v4l2-subdev.h
|
||||
!Iinclude/media/videobuf2-core.h
|
||||
!Iinclude/media/videobuf2-v4l2.h
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
that are present on the transport stream. This is done through
|
||||
<constant>/dev/dvb/adapter?/net?</constant> device node.
|
||||
The data will be available via virtual <constant>dvb?_?</constant>
|
||||
network interfaces, and will be controled/routed via the standard
|
||||
network interfaces, and will be controlled/routed via the standard
|
||||
ip tools (like ip, route, netstat, ifconfig, etc).</para>
|
||||
<para> Data types and and ioctl definitions are defined via
|
||||
<constant>linux/dvb/net.h</constant> header.</para>
|
||||
|
|
|
@ -2685,10 +2685,6 @@ hardware may support both.</para>
|
|||
and may change in the future.</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>Video Output Overlay (OSD) Interface, <xref
|
||||
linkend="osd" />.</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>&VIDIOC-DBG-G-REGISTER; and &VIDIOC-DBG-S-REGISTER;
|
||||
ioctls.</para>
|
||||
|
@ -2696,40 +2692,6 @@ ioctls.</para>
|
|||
<listitem>
|
||||
<para>&VIDIOC-DBG-G-CHIP-INFO; ioctl.</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>&VIDIOC-ENUM-DV-TIMINGS;, &VIDIOC-QUERY-DV-TIMINGS; and
|
||||
&VIDIOC-DV-TIMINGS-CAP; ioctls.</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>Flash API. <xref linkend="flash-controls" /></para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>&VIDIOC-CREATE-BUFS; and &VIDIOC-PREPARE-BUF; ioctls.</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>Selection API. <xref linkend="selection-api" /></para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>Sub-device selection API: &VIDIOC-SUBDEV-G-SELECTION;
|
||||
and &VIDIOC-SUBDEV-S-SELECTION; ioctls.</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>Support for frequency band enumeration: &VIDIOC-ENUM-FREQ-BANDS; ioctl.</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>Vendor and device specific media bus pixel formats.
|
||||
<xref linkend="v4l2-mbus-vendor-spec-fmts" />.</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>Importing DMABUF file descriptors as a new IO method described
|
||||
in <xref linkend="dmabuf" />.</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>Exporting DMABUF files using &VIDIOC-EXPBUF; ioctl.</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>Software Defined Radio (SDR) Interface, <xref linkend="sdr" />.</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
|
||||
|
|
|
@ -4272,13 +4272,6 @@ manually or automatically if set to zero. Unit, range and step are driver-specif
|
|||
<section id="flash-controls">
|
||||
<title>Flash Control Reference</title>
|
||||
|
||||
<note>
|
||||
<title>Experimental</title>
|
||||
|
||||
<para>This is an <link linkend="experimental">experimental</link>
|
||||
interface and may change in the future.</para>
|
||||
</note>
|
||||
|
||||
<para>
|
||||
The V4L2 flash controls are intended to provide generic access
|
||||
to flash controller devices. Flash controller devices are
|
||||
|
@ -4743,14 +4736,6 @@ interface and may change in the future.</para>
|
|||
<section id="image-source-controls">
|
||||
<title>Image Source Control Reference</title>
|
||||
|
||||
<note>
|
||||
<title>Experimental</title>
|
||||
|
||||
<para>This is an <link
|
||||
linkend="experimental">experimental</link> interface and may
|
||||
change in the future.</para>
|
||||
</note>
|
||||
|
||||
<para>
|
||||
The Image Source control class is intended for low-level
|
||||
control of image source devices such as image sensors. The
|
||||
|
@ -4862,14 +4847,6 @@ interface and may change in the future.</para>
|
|||
<section id="image-process-controls">
|
||||
<title>Image Process Control Reference</title>
|
||||
|
||||
<note>
|
||||
<title>Experimental</title>
|
||||
|
||||
<para>This is an <link
|
||||
linkend="experimental">experimental</link> interface and may
|
||||
change in the future.</para>
|
||||
</note>
|
||||
|
||||
<para>
|
||||
The Image Process control class is intended for low-level control of
|
||||
image processing functions. Unlike
|
||||
|
@ -4955,14 +4932,6 @@ interface and may change in the future.</para>
|
|||
<section id="dv-controls">
|
||||
<title>Digital Video Control Reference</title>
|
||||
|
||||
<note>
|
||||
<title>Experimental</title>
|
||||
|
||||
<para>This is an <link
|
||||
linkend="experimental">experimental</link> interface and may
|
||||
change in the future.</para>
|
||||
</note>
|
||||
|
||||
<para>
|
||||
The Digital Video control class is intended to control receivers
|
||||
and transmitters for <ulink url="http://en.wikipedia.org/wiki/Vga">VGA</ulink>,
|
||||
|
|
|
@ -1,11 +1,5 @@
|
|||
<title>Software Defined Radio Interface (SDR)</title>
|
||||
|
||||
<note>
|
||||
<title>Experimental</title>
|
||||
<para>This is an <link linkend="experimental"> experimental </link>
|
||||
interface and may change in the future.</para>
|
||||
</note>
|
||||
|
||||
<para>
|
||||
SDR is an abbreviation of Software Defined Radio, the radio device
|
||||
which uses application software for modulation or demodulation. This interface
|
||||
|
|
|
@ -1,11 +1,5 @@
|
|||
<title>Sub-device Interface</title>
|
||||
|
||||
<note>
|
||||
<title>Experimental</title>
|
||||
<para>This is an <link linkend="experimental">experimental</link>
|
||||
interface and may change in the future.</para>
|
||||
</note>
|
||||
|
||||
<para>The complex nature of V4L2 devices, where hardware is often made of
|
||||
several integrated circuits that need to interact with each other in a
|
||||
controlled way, leads to complex V4L2 drivers. The drivers usually reflect
|
||||
|
|
|
@ -475,12 +475,6 @@ rest should be evident.</para>
|
|||
<section id="dmabuf">
|
||||
<title>Streaming I/O (DMA buffer importing)</title>
|
||||
|
||||
<note>
|
||||
<title>Experimental</title>
|
||||
<para>This is an <link linkend="experimental">experimental</link>
|
||||
interface and may change in the future.</para>
|
||||
</note>
|
||||
|
||||
<para>The DMABUF framework provides a generic method for sharing buffers
|
||||
between multiple devices. Device drivers that support DMABUF can export a DMA
|
||||
buffer to userspace as a file descriptor (known as the exporter role), import a
|
||||
|
|
|
@ -1,13 +1,6 @@
|
|||
<section id="selection-api">
|
||||
|
||||
<title>Experimental API for cropping, composing and scaling</title>
|
||||
|
||||
<note>
|
||||
<title>Experimental</title>
|
||||
|
||||
<para>This is an <link linkend="experimental">experimental</link>
|
||||
interface and may change in the future.</para>
|
||||
</note>
|
||||
<title>API for cropping, composing and scaling</title>
|
||||
|
||||
<section>
|
||||
<title>Introduction</title>
|
||||
|
|
|
@ -4002,12 +4002,6 @@ see <xref linkend="colorspaces" />.</entry>
|
|||
<section id="v4l2-mbus-vendor-spec-fmts">
|
||||
<title>Vendor and Device Specific Formats</title>
|
||||
|
||||
<note>
|
||||
<title>Experimental</title>
|
||||
<para>This is an <link linkend="experimental">experimental</link>
|
||||
interface and may change in the future.</para>
|
||||
</note>
|
||||
|
||||
<para>This section lists complex data formats that are either vendor or
|
||||
device specific.
|
||||
</para>
|
||||
|
|
|
@ -49,12 +49,6 @@
|
|||
<refsect1>
|
||||
<title>Description</title>
|
||||
|
||||
<note>
|
||||
<title>Experimental</title>
|
||||
<para>This is an <link linkend="experimental"> experimental </link>
|
||||
interface and may change in the future.</para>
|
||||
</note>
|
||||
|
||||
<para>This ioctl is used to create buffers for <link linkend="mmap">memory
|
||||
mapped</link> or <link linkend="userp">user pointer</link> or <link
|
||||
linkend="dmabuf">DMA buffer</link> I/O. It can be used as an alternative or in
|
||||
|
|
|
@ -49,14 +49,9 @@
|
|||
<refsect1>
|
||||
<title>Description</title>
|
||||
|
||||
<note>
|
||||
<title>Experimental</title>
|
||||
<para>This is an <link linkend="experimental"> experimental </link>
|
||||
interface and may change in the future.</para>
|
||||
</note>
|
||||
|
||||
<para>To query the capabilities of the DV receiver/transmitter applications
|
||||
can call the <constant>VIDIOC_DV_TIMINGS_CAP</constant> ioctl on a video node
|
||||
<para>To query the capabilities of the DV receiver/transmitter applications initialize the
|
||||
<structfield>pad</structfield> field to 0, zero the reserved array of &v4l2-dv-timings-cap;
|
||||
and call the <constant>VIDIOC_DV_TIMINGS_CAP</constant> ioctl on a video node
|
||||
and the driver will fill in the structure. Note that drivers may return
|
||||
different values after switching the video input or output.</para>
|
||||
|
||||
|
@ -65,8 +60,8 @@ queried by calling the <constant>VIDIOC_SUBDEV_DV_TIMINGS_CAP</constant> ioctl
|
|||
directly on a subdevice node. The capabilities are specific to inputs (for DV
|
||||
receivers) or outputs (for DV transmitters), applications must specify the
|
||||
desired pad number in the &v4l2-dv-timings-cap; <structfield>pad</structfield>
|
||||
field. Attempts to query capabilities on a pad that doesn't support them will
|
||||
return an &EINVAL;.</para>
|
||||
field and zero the <structfield>reserved</structfield> array. Attempts to query
|
||||
capabilities on a pad that doesn't support them will return an &EINVAL;.</para>
|
||||
|
||||
<table pgwide="1" frame="none" id="v4l2-bt-timings-cap">
|
||||
<title>struct <structname>v4l2_bt_timings_cap</structname></title>
|
||||
|
@ -145,7 +140,8 @@ return an &EINVAL;.</para>
|
|||
<row>
|
||||
<entry>__u32</entry>
|
||||
<entry><structfield>reserved</structfield>[2]</entry>
|
||||
<entry>Reserved for future extensions. Drivers must set the array to zero.</entry>
|
||||
<entry>Reserved for future extensions. Drivers and applications must
|
||||
set the array to zero.</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry>union</entry>
|
||||
|
|
|
@ -49,20 +49,15 @@
|
|||
<refsect1>
|
||||
<title>Description</title>
|
||||
|
||||
<note>
|
||||
<title>Experimental</title>
|
||||
<para>This is an <link linkend="experimental"> experimental </link>
|
||||
interface and may change in the future.</para>
|
||||
</note>
|
||||
|
||||
<para>While some DV receivers or transmitters support a wide range of timings, others
|
||||
support only a limited number of timings. With this ioctl applications can enumerate a list
|
||||
of known supported timings. Call &VIDIOC-DV-TIMINGS-CAP; to check if it also supports other
|
||||
standards or even custom timings that are not in this list.</para>
|
||||
|
||||
<para>To query the available timings, applications initialize the
|
||||
<structfield>index</structfield> field and zero the reserved array of &v4l2-enum-dv-timings;
|
||||
and call the <constant>VIDIOC_ENUM_DV_TIMINGS</constant> ioctl on a video node with a
|
||||
<structfield>index</structfield> field, set the <structfield>pad</structfield> field to 0,
|
||||
zero the reserved array of &v4l2-enum-dv-timings; and call the
|
||||
<constant>VIDIOC_ENUM_DV_TIMINGS</constant> ioctl on a video node with a
|
||||
pointer to this structure. Drivers fill the rest of the structure or return an
|
||||
&EINVAL; when the index is out of bounds. To enumerate all supported DV timings,
|
||||
applications shall begin at index zero, incrementing by one until the
|
||||
|
|
|
@ -49,12 +49,6 @@
|
|||
<refsect1>
|
||||
<title>Description</title>
|
||||
|
||||
<note>
|
||||
<title>Experimental</title>
|
||||
<para>This is an <link linkend="experimental"> experimental </link>
|
||||
interface and may change in the future.</para>
|
||||
</note>
|
||||
|
||||
<para>Enumerates the frequency bands that a tuner or modulator supports.
|
||||
To do this applications initialize the <structfield>tuner</structfield>,
|
||||
<structfield>type</structfield> and <structfield>index</structfield> fields,
|
||||
|
|
|
@ -49,12 +49,6 @@
|
|||
<refsect1>
|
||||
<title>Description</title>
|
||||
|
||||
<note>
|
||||
<title>Experimental</title>
|
||||
<para>This is an <link linkend="experimental"> experimental </link>
|
||||
interface and may change in the future.</para>
|
||||
</note>
|
||||
|
||||
<para>This ioctl is an extension to the <link linkend="mmap">memory
|
||||
mapping</link> I/O method, therefore it is available only for
|
||||
<constant>V4L2_MEMORY_MMAP</constant> buffers. It can be used to export a
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<refentry id="vidioc-g-edid">
|
||||
<refmeta>
|
||||
<refentrytitle>ioctl VIDIOC_G_EDID, VIDIOC_S_EDID</refentrytitle>
|
||||
<refentrytitle>ioctl VIDIOC_G_EDID, VIDIOC_S_EDID, VIDIOC_SUBDEV_G_EDID, VIDIOC_SUBDEV_S_EDID</refentrytitle>
|
||||
&manvol;
|
||||
</refmeta>
|
||||
|
||||
|
@ -71,7 +71,8 @@
|
|||
|
||||
<para>To get the EDID data the application has to fill in the <structfield>pad</structfield>,
|
||||
<structfield>start_block</structfield>, <structfield>blocks</structfield> and <structfield>edid</structfield>
|
||||
fields and call <constant>VIDIOC_G_EDID</constant>. The current EDID from block
|
||||
fields, zero the <structfield>reserved</structfield> array and call
|
||||
<constant>VIDIOC_G_EDID</constant>. The current EDID from block
|
||||
<structfield>start_block</structfield> and of size <structfield>blocks</structfield>
|
||||
will be placed in the memory <structfield>edid</structfield> points to. The <structfield>edid</structfield>
|
||||
pointer must point to memory at least <structfield>blocks</structfield> * 128 bytes
|
||||
|
@ -92,8 +93,9 @@
|
|||
the driver will set <structfield>blocks</structfield> to 0 and it returns 0.</para>
|
||||
|
||||
<para>To set the EDID blocks of a receiver the application has to fill in the <structfield>pad</structfield>,
|
||||
<structfield>blocks</structfield> and <structfield>edid</structfield> fields and set
|
||||
<structfield>start_block</structfield> to 0. It is not possible to set part of an EDID,
|
||||
<structfield>blocks</structfield> and <structfield>edid</structfield> fields, set
|
||||
<structfield>start_block</structfield> to 0 and zero the <structfield>reserved</structfield> array.
|
||||
It is not possible to set part of an EDID,
|
||||
it is always all or nothing. Setting the EDID data is only valid for receivers as it makes
|
||||
no sense for a transmitter.</para>
|
||||
|
||||
|
|
|
@ -50,12 +50,6 @@
|
|||
<refsect1>
|
||||
<title>Description</title>
|
||||
|
||||
<note>
|
||||
<title>Experimental</title>
|
||||
<para>This is an <link linkend="experimental"> experimental </link>
|
||||
interface and may change in the future.</para>
|
||||
</note>
|
||||
|
||||
<para>The ioctls are used to query and configure selection rectangles.</para>
|
||||
|
||||
<para>To query the cropping (composing) rectangle set &v4l2-selection;
|
||||
|
|
|
@ -48,12 +48,6 @@
|
|||
<refsect1>
|
||||
<title>Description</title>
|
||||
|
||||
<note>
|
||||
<title>Experimental</title>
|
||||
<para>This is an <link linkend="experimental"> experimental </link>
|
||||
interface and may change in the future.</para>
|
||||
</note>
|
||||
|
||||
<para>Applications can optionally call the
|
||||
<constant>VIDIOC_PREPARE_BUF</constant> ioctl to pass ownership of the buffer
|
||||
to the driver before actually enqueuing it, using the
|
||||
|
|
|
@ -50,12 +50,6 @@ input</refpurpose>
|
|||
<refsect1>
|
||||
<title>Description</title>
|
||||
|
||||
<note>
|
||||
<title>Experimental</title>
|
||||
<para>This is an <link linkend="experimental"> experimental </link>
|
||||
interface and may change in the future.</para>
|
||||
</note>
|
||||
|
||||
<para>The hardware may be able to detect the current DV timings
|
||||
automatically, similar to sensing the video standard. To do so, applications
|
||||
call <constant>VIDIOC_QUERY_DV_TIMINGS</constant> with a pointer to a
|
||||
|
|
|
@ -123,6 +123,14 @@ synchronize with other events.</para>
|
|||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><errorcode>ENOLINK</errorcode></term>
|
||||
<listitem>
|
||||
<para>The driver implements Media Controller interface and
|
||||
the pipeline link configuration is invalid.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
</refentry>
|
||||
|
|
|
@ -49,12 +49,6 @@
|
|||
<refsect1>
|
||||
<title>Description</title>
|
||||
|
||||
<note>
|
||||
<title>Experimental</title>
|
||||
<para>This is an <link linkend="experimental">experimental</link>
|
||||
interface and may change in the future.</para>
|
||||
</note>
|
||||
|
||||
<para>This ioctl lets applications enumerate available frame intervals on a
|
||||
given sub-device pad. Frame intervals only makes sense for sub-devices that
|
||||
can control the frame period on their own. This includes, for instance,
|
||||
|
|
|
@ -49,12 +49,6 @@
|
|||
<refsect1>
|
||||
<title>Description</title>
|
||||
|
||||
<note>
|
||||
<title>Experimental</title>
|
||||
<para>This is an <link linkend="experimental">experimental</link>
|
||||
interface and may change in the future.</para>
|
||||
</note>
|
||||
|
||||
<para>This ioctl allows applications to enumerate all frame sizes
|
||||
supported by a sub-device on the given pad for the given media bus format.
|
||||
Supported formats can be retrieved with the &VIDIOC-SUBDEV-ENUM-MBUS-CODE;
|
||||
|
|
|
@ -49,12 +49,6 @@
|
|||
<refsect1>
|
||||
<title>Description</title>
|
||||
|
||||
<note>
|
||||
<title>Experimental</title>
|
||||
<para>This is an <link linkend="experimental">experimental</link>
|
||||
interface and may change in the future.</para>
|
||||
</note>
|
||||
|
||||
<para>To enumerate media bus formats available at a given sub-device pad
|
||||
applications initialize the <structfield>pad</structfield>, <structfield>which</structfield>
|
||||
and <structfield>index</structfield> fields of &v4l2-subdev-mbus-code-enum; and
|
||||
|
|
|
@ -50,12 +50,6 @@
|
|||
<refsect1>
|
||||
<title>Description</title>
|
||||
|
||||
<note>
|
||||
<title>Experimental</title>
|
||||
<para>This is an <link linkend="experimental">experimental</link>
|
||||
interface and may change in the future.</para>
|
||||
</note>
|
||||
|
||||
<para>These ioctls are used to negotiate the frame format at specific
|
||||
subdev pads in the image pipeline.</para>
|
||||
|
||||
|
|
|
@ -50,12 +50,6 @@
|
|||
<refsect1>
|
||||
<title>Description</title>
|
||||
|
||||
<note>
|
||||
<title>Experimental</title>
|
||||
<para>This is an <link linkend="experimental">experimental</link>
|
||||
interface and may change in the future.</para>
|
||||
</note>
|
||||
|
||||
<para>These ioctls are used to get and set the frame interval at specific
|
||||
subdev pads in the image pipeline. The frame interval only makes sense for
|
||||
sub-devices that can control the frame period on their own. This includes,
|
||||
|
|
|
@ -49,12 +49,6 @@
|
|||
<refsect1>
|
||||
<title>Description</title>
|
||||
|
||||
<note>
|
||||
<title>Experimental</title>
|
||||
<para>This is an <link linkend="experimental">experimental</link>
|
||||
interface and may change in the future.</para>
|
||||
</note>
|
||||
|
||||
<para>The selections are used to configure various image
|
||||
processing functionality performed by the subdevs which affect the
|
||||
image size. This currently includes cropping, scaling and
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
subdir-y := accounting auxdisplay blackfin connector \
|
||||
filesystems filesystems ia64 laptops mic misc-devices \
|
||||
networking pcmcia prctl ptp timers vDSO video4linux \
|
||||
watchdog
|
||||
networking pcmcia prctl ptp timers vDSO watchdog
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
* Analog Devices ADV7180 analog video decoder family
|
||||
|
||||
The adv7180 family devices are used to capture analog video to different
|
||||
digital interfaces like MIPI CSI-2 or parallel video.
|
||||
|
||||
Required Properties :
|
||||
- compatible : value must be one of
|
||||
"adi,adv7180"
|
||||
"adi,adv7182"
|
||||
"adi,adv7280"
|
||||
"adi,adv7280-m"
|
||||
"adi,adv7281"
|
||||
"adi,adv7281-m"
|
||||
"adi,adv7281-ma"
|
||||
"adi,adv7282"
|
||||
"adi,adv7282-m"
|
||||
|
||||
Example:
|
||||
|
||||
i2c0@1c22000 {
|
||||
...
|
||||
...
|
||||
adv7180@21 {
|
||||
compatible = "adi,adv7180";
|
||||
reg = <0x21>;
|
||||
};
|
||||
...
|
||||
};
|
||||
|
|
@ -5,14 +5,22 @@ The rcar_vin device provides video input capabilities for the Renesas R-Car
|
|||
family of devices. The current blocks are always slaves and suppot one input
|
||||
channel which can be either RGB, YUYV or BT656.
|
||||
|
||||
- compatible: Must be one of the following
|
||||
- compatible: Must be one or more of the following
|
||||
- "renesas,vin-r8a7795" for the R8A7795 device
|
||||
- "renesas,vin-r8a7794" for the R8A7794 device
|
||||
- "renesas,vin-r8a7793" for the R8A7793 device
|
||||
- "renesas,vin-r8a7792" for the R8A7792 device
|
||||
- "renesas,vin-r8a7791" for the R8A7791 device
|
||||
- "renesas,vin-r8a7790" for the R8A7790 device
|
||||
- "renesas,vin-r8a7779" for the R8A7779 device
|
||||
- "renesas,vin-r8a7778" for the R8A7778 device
|
||||
- "renesas,rcar-gen2-vin" for a generic R-Car Gen2 compatible device.
|
||||
- "renesas,rcar-gen3-vin" for a generic R-Car Gen3 compatible device.
|
||||
|
||||
When compatible with the generic version nodes must list the
|
||||
SoC-specific version corresponding to the platform first
|
||||
followed by the generic version.
|
||||
|
||||
- reg: the register base and size for the device registers
|
||||
- interrupts: the interrupt for the device
|
||||
- clocks: Reference to the parent clock
|
||||
|
@ -37,7 +45,7 @@ Device node example
|
|||
};
|
||||
|
||||
vin0: vin@0xe6ef0000 {
|
||||
compatible = "renesas,vin-r8a7790";
|
||||
compatible = "renesas,vin-r8a7790", "renesas,rcar-gen2-vin";
|
||||
clocks = <&mstp8_clks R8A7790_CLK_VIN0>;
|
||||
reg = <0 0xe6ef0000 0 0x1000>;
|
||||
interrupts = <0 188 IRQ_TYPE_LEVEL_HIGH>;
|
||||
|
|
|
@ -20,7 +20,7 @@ The following properties are common to all Xilinx video IP cores.
|
|||
- xlnx,video-format: This property represents a video format transmitted on an
|
||||
AXI bus between video IP cores, using its VF code as defined in "AXI4-Stream
|
||||
Video IP and System Design Guide" [UG934]. How the format relates to the IP
|
||||
core is decribed in the IP core bindings documentation.
|
||||
core is described in the IP core bindings documentation.
|
||||
|
||||
- xlnx,video-width: This property qualifies the video format with the sample
|
||||
width expressed as a number of bits per pixel component. All components must
|
||||
|
|
|
@ -52,3 +52,5 @@
|
|||
51 -> DVBSky T982 [4254:0982]
|
||||
52 -> Hauppauge WinTV-HVR5525 [0070:f038]
|
||||
53 -> Hauppauge WinTV Starburst [0070:c12a]
|
||||
54 -> ViewCast 260e [1576:0260]
|
||||
55 -> ViewCast 460e [1576:0460]
|
||||
|
|
|
@ -76,9 +76,9 @@
|
|||
75 -> Dikom DK300 (em2882)
|
||||
76 -> KWorld PlusTV 340U or UB435-Q (ATSC) (em2870) [1b80:a340]
|
||||
77 -> EM2874 Leadership ISDBT (em2874)
|
||||
78 -> PCTV nanoStick T2 290e (em28174)
|
||||
78 -> PCTV nanoStick T2 290e (em28174) [2013:024f]
|
||||
79 -> Terratec Cinergy H5 (em2884) [eb1a:2885,0ccd:10a2,0ccd:10ad,0ccd:10b6]
|
||||
80 -> PCTV DVB-S2 Stick (460e) (em28174)
|
||||
80 -> PCTV DVB-S2 Stick (460e) (em28174) [2013:024c]
|
||||
81 -> Hauppauge WinTV HVR 930C (em2884) [2040:1605]
|
||||
82 -> Terratec Cinergy HTC Stick (em2884) [0ccd:00b2]
|
||||
83 -> Honestech Vidbox NW03 (em2860) [eb1a:5006]
|
||||
|
@ -90,9 +90,11 @@
|
|||
89 -> Delock 61959 (em2874) [1b80:e1cc]
|
||||
90 -> KWorld USB ATSC TV Stick UB435-Q V2 (em2874) [1b80:e346]
|
||||
91 -> SpeedLink Vicious And Devine Laplace webcam (em2765) [1ae7:9003,1ae7:9004]
|
||||
92 -> PCTV DVB-S2 Stick (461e) (em28178)
|
||||
92 -> PCTV DVB-S2 Stick (461e) (em28178) [2013:0258]
|
||||
93 -> KWorld USB ATSC TV Stick UB435-Q V3 (em2874) [1b80:e34c]
|
||||
94 -> PCTV tripleStick (292e) (em28178)
|
||||
94 -> PCTV tripleStick (292e) (em28178) [2013:025f,2040:0264]
|
||||
95 -> Leadtek VC100 (em2861) [0413:6f07]
|
||||
96 -> Terratec Cinergy T2 Stick HD (em28178)
|
||||
96 -> Terratec Cinergy T2 Stick HD (em28178) [eb1a:8179]
|
||||
97 -> Elgato EyeTV Hybrid 2008 INT (em2884) [0fd9:0018]
|
||||
98 -> PLEX PX-BCUD (em28178) [3275:0085]
|
||||
99 -> Hauppauge WinTV-dualHD DVB (em28174) [2040:0265]
|
||||
|
|
|
@ -35,7 +35,7 @@ need and this same framework should make it much easier to refactor
|
|||
common code into utility functions shared by all drivers.
|
||||
|
||||
A good example to look at as a reference is the v4l2-pci-skeleton.c
|
||||
source that is available in this directory. It is a skeleton driver for
|
||||
source that is available in samples/v4l/. It is a skeleton driver for
|
||||
a PCI capture card, and demonstrates how to use the V4L2 driver
|
||||
framework. It can be used as a template for real PCI video capture driver.
|
||||
|
||||
|
|
|
@ -294,7 +294,7 @@ the result will be.
|
|||
|
||||
These inputs support all combinations of the field setting. Special care has
|
||||
been taken to faithfully reproduce how fields are handled for the different
|
||||
TV standards. This is particularly noticable when generating a horizontally
|
||||
TV standards. This is particularly noticeable when generating a horizontally
|
||||
moving image so the temporal effect of using interlaced formats becomes clearly
|
||||
visible. For 50 Hz standards the top field is the oldest and the bottom field
|
||||
is the newest in time. For 60 Hz standards that is reversed: the bottom field
|
||||
|
@ -313,7 +313,7 @@ will be SMPTE-170M.
|
|||
The pixel aspect ratio will depend on the TV standard. The video aspect ratio
|
||||
can be selected through the 'Standard Aspect Ratio' Vivid control.
|
||||
Choices are '4x3', '16x9' which will give letterboxed widescreen video and
|
||||
'16x9 Anomorphic' which will give full screen squashed anamorphic widescreen
|
||||
'16x9 Anamorphic' which will give full screen squashed anamorphic widescreen
|
||||
video that will need to be scaled accordingly.
|
||||
|
||||
The TV 'tuner' supports a frequency range of 44-958 MHz. Channels are available
|
||||
|
@ -862,7 +862,7 @@ RDS Radio Text:
|
|||
RDS Stereo:
|
||||
RDS Artificial Head:
|
||||
RDS Compressed:
|
||||
RDS Dymanic PTY:
|
||||
RDS Dynamic PTY:
|
||||
RDS Traffic Announcement:
|
||||
RDS Traffic Program:
|
||||
RDS Music: these are all controls that set the RDS data that is transmitted by
|
||||
|
|
|
@ -11338,6 +11338,14 @@ W: https://linuxtv.org
|
|||
S: Odd Fixes
|
||||
F: drivers/media/pci/tw68/
|
||||
|
||||
TW686X VIDEO4LINUX DRIVER
|
||||
M: Ezequiel Garcia <ezequiel@vanguardiasur.com.ar>
|
||||
L: linux-media@vger.kernel.org
|
||||
T: git git://linuxtv.org/media_tree.git
|
||||
W: http://linuxtv.org
|
||||
S: Maintained
|
||||
F: drivers/media/pci/tw686x/
|
||||
|
||||
TPM DEVICE DRIVER
|
||||
M: Peter Huewe <peterhuewe@gmx.de>
|
||||
M: Marcel Selhorst <tpmdd@selhorst.net>
|
||||
|
|
|
@ -19,3 +19,4 @@ config CYPRESS_FIRMWARE
|
|||
source "drivers/media/common/b2c2/Kconfig"
|
||||
source "drivers/media/common/saa7146/Kconfig"
|
||||
source "drivers/media/common/siano/Kconfig"
|
||||
source "drivers/media/common/v4l2-tpg/Kconfig"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
obj-y += b2c2/ saa7146/ siano/
|
||||
obj-y += b2c2/ saa7146/ siano/ v4l2-tpg/
|
||||
obj-$(CONFIG_VIDEO_CX2341X) += cx2341x.o
|
||||
obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o
|
||||
obj-$(CONFIG_CYPRESS_FIRMWARE) += cypress_firmware.o
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
config VIDEO_V4L2_TPG
|
||||
tristate
|
|
@ -0,0 +1,3 @@
|
|||
v4l2-tpg-objs := v4l2-tpg-core.o v4l2-tpg-colors.o
|
||||
|
||||
obj-$(CONFIG_VIDEO_V4L2_TPG) += v4l2-tpg.o
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* vivid-color.c - A table that converts colors to various colorspaces
|
||||
* v4l2-tpg-colors.c - A table that converts colors to various colorspaces
|
||||
*
|
||||
* The test pattern generator uses the tpg_colors for its test patterns.
|
||||
* For testing colorspaces the first 8 colors of that table need to be
|
||||
|
@ -12,7 +12,7 @@
|
|||
* This source also contains the code used to generate the tpg_csc_colors
|
||||
* table. Run the following command to compile it:
|
||||
*
|
||||
* gcc vivid-tpg-colors.c -DCOMPILE_APP -o gen-colors -lm
|
||||
* gcc v4l2-tpg-colors.c -DCOMPILE_APP -o gen-colors -lm
|
||||
*
|
||||
* and run the utility.
|
||||
*
|
||||
|
@ -36,8 +36,7 @@
|
|||
*/
|
||||
|
||||
#include <linux/videodev2.h>
|
||||
|
||||
#include "vivid-tpg-colors.h"
|
||||
#include <media/v4l2-tpg-colors.h>
|
||||
|
||||
/* sRGB colors with range [0-255] */
|
||||
const struct color tpg_colors[TPG_COLOR_MAX] = {
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* vivid-tpg.c - Test Pattern Generator
|
||||
* v4l2-tpg-core.c - Test Pattern Generator
|
||||
*
|
||||
* Note: gen_twopix and tpg_gen_text are based on code from vivi.c. See the
|
||||
* vivi.c source for the copyright information of those functions.
|
||||
|
@ -20,7 +20,8 @@
|
|||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "vivid-tpg.h"
|
||||
#include <linux/module.h>
|
||||
#include <media/v4l2-tpg.h>
|
||||
|
||||
/* Must remain in sync with enum tpg_pattern */
|
||||
const char * const tpg_pattern_strings[] = {
|
||||
|
@ -48,6 +49,7 @@ const char * const tpg_pattern_strings[] = {
|
|||
"Noise",
|
||||
NULL
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(tpg_pattern_strings);
|
||||
|
||||
/* Must remain in sync with enum tpg_aspect */
|
||||
const char * const tpg_aspect_strings[] = {
|
||||
|
@ -58,6 +60,7 @@ const char * const tpg_aspect_strings[] = {
|
|||
"16x9 Anamorphic",
|
||||
NULL
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(tpg_aspect_strings);
|
||||
|
||||
/*
|
||||
* Sine table: sin[0] = 127 * sin(-180 degrees)
|
||||
|
@ -93,6 +96,7 @@ void tpg_set_font(const u8 *f)
|
|||
{
|
||||
font8x16 = f;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tpg_set_font);
|
||||
|
||||
void tpg_init(struct tpg_data *tpg, unsigned w, unsigned h)
|
||||
{
|
||||
|
@ -114,6 +118,7 @@ void tpg_init(struct tpg_data *tpg, unsigned w, unsigned h)
|
|||
tpg->colorspace = V4L2_COLORSPACE_SRGB;
|
||||
tpg->perc_fill = 100;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tpg_init);
|
||||
|
||||
int tpg_alloc(struct tpg_data *tpg, unsigned max_w)
|
||||
{
|
||||
|
@ -150,6 +155,7 @@ int tpg_alloc(struct tpg_data *tpg, unsigned max_w)
|
|||
}
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tpg_alloc);
|
||||
|
||||
void tpg_free(struct tpg_data *tpg)
|
||||
{
|
||||
|
@ -174,6 +180,7 @@ void tpg_free(struct tpg_data *tpg)
|
|||
tpg->random_line[plane] = NULL;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tpg_free);
|
||||
|
||||
bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc)
|
||||
{
|
||||
|
@ -403,6 +410,7 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc)
|
|||
}
|
||||
return true;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tpg_s_fourcc);
|
||||
|
||||
void tpg_s_crop_compose(struct tpg_data *tpg, const struct v4l2_rect *crop,
|
||||
const struct v4l2_rect *compose)
|
||||
|
@ -418,6 +426,7 @@ void tpg_s_crop_compose(struct tpg_data *tpg, const struct v4l2_rect *crop,
|
|||
tpg->scaled_width = 2;
|
||||
tpg->recalc_lines = true;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tpg_s_crop_compose);
|
||||
|
||||
void tpg_reset_source(struct tpg_data *tpg, unsigned width, unsigned height,
|
||||
u32 field)
|
||||
|
@ -442,6 +451,7 @@ void tpg_reset_source(struct tpg_data *tpg, unsigned width, unsigned height,
|
|||
(2 * tpg->hdownsampling[p]);
|
||||
tpg->recalc_square_border = true;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tpg_reset_source);
|
||||
|
||||
static enum tpg_color tpg_get_textbg_color(struct tpg_data *tpg)
|
||||
{
|
||||
|
@ -1250,6 +1260,7 @@ unsigned tpg_g_interleaved_plane(const struct tpg_data *tpg, unsigned buf_line)
|
|||
return 0;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tpg_g_interleaved_plane);
|
||||
|
||||
/* Return how many pattern lines are used by the current pattern. */
|
||||
static unsigned tpg_get_pat_lines(const struct tpg_data *tpg)
|
||||
|
@ -1725,6 +1736,7 @@ void tpg_gen_text(const struct tpg_data *tpg, u8 *basep[TPG_MAX_PLANES][2],
|
|||
}
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tpg_gen_text);
|
||||
|
||||
void tpg_update_mv_step(struct tpg_data *tpg)
|
||||
{
|
||||
|
@ -1773,6 +1785,7 @@ void tpg_update_mv_step(struct tpg_data *tpg)
|
|||
if (factor < 0)
|
||||
tpg->mv_vert_step = tpg->src_height - tpg->mv_vert_step;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tpg_update_mv_step);
|
||||
|
||||
/* Map the line number relative to the crop rectangle to a frame line number */
|
||||
static unsigned tpg_calc_frameline(const struct tpg_data *tpg, unsigned src_y,
|
||||
|
@ -1862,6 +1875,7 @@ void tpg_calc_text_basep(struct tpg_data *tpg,
|
|||
if (p == 0 && tpg->interleaved)
|
||||
tpg_calc_text_basep(tpg, basep, 1, vbuf);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tpg_calc_text_basep);
|
||||
|
||||
static int tpg_pattern_avg(const struct tpg_data *tpg,
|
||||
unsigned pat1, unsigned pat2)
|
||||
|
@ -1891,6 +1905,7 @@ void tpg_log_status(struct tpg_data *tpg)
|
|||
pr_info("tpg quantization: %d/%d\n", tpg->quantization, tpg->real_quantization);
|
||||
pr_info("tpg RGB range: %d/%d\n", tpg->rgb_range, tpg->real_rgb_range);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tpg_log_status);
|
||||
|
||||
/*
|
||||
* This struct contains common parameters used by both the drawing of the
|
||||
|
@ -2296,6 +2311,7 @@ void tpg_fill_plane_buffer(struct tpg_data *tpg, v4l2_std_id std,
|
|||
vbuf + buf_line * params.stride);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tpg_fill_plane_buffer);
|
||||
|
||||
void tpg_fillbuffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 *vbuf)
|
||||
{
|
||||
|
@ -2312,3 +2328,8 @@ void tpg_fillbuffer(struct tpg_data *tpg, v4l2_std_id std, unsigned p, u8 *vbuf)
|
|||
offset += tpg_calc_plane_size(tpg, i);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tpg_fillbuffer);
|
||||
|
||||
MODULE_DESCRIPTION("V4L2 Test Pattern Generator");
|
||||
MODULE_AUTHOR("Hans Verkuil");
|
||||
MODULE_LICENSE("GPL");
|
|
@ -58,6 +58,14 @@
|
|||
#define USB_VID_TELESTAR 0x10b9
|
||||
#define USB_VID_VISIONPLUS 0x13d3
|
||||
#define USB_VID_SONY 0x1415
|
||||
#define USB_PID_TEVII_S421 0xd421
|
||||
#define USB_PID_TEVII_S480_1 0xd481
|
||||
#define USB_PID_TEVII_S480_2 0xd482
|
||||
#define USB_PID_TEVII_S630 0xd630
|
||||
#define USB_PID_TEVII_S632 0xd632
|
||||
#define USB_PID_TEVII_S650 0xd650
|
||||
#define USB_PID_TEVII_S660 0xd660
|
||||
#define USB_PID_TEVII_S662 0xd662
|
||||
#define USB_VID_TWINHAN 0x1822
|
||||
#define USB_VID_ULTIMA_ELECTRONIC 0x05d8
|
||||
#define USB_VID_UNIWILL 0x1584
|
||||
|
@ -141,6 +149,7 @@
|
|||
#define USB_PID_GENIUS_TVGO_DVB_T03 0x4012
|
||||
#define USB_PID_GRANDTEC_DVBT_USB_COLD 0x0fa0
|
||||
#define USB_PID_GRANDTEC_DVBT_USB_WARM 0x0fa1
|
||||
#define USB_PID_GOTVIEW_SAT_HD 0x5456
|
||||
#define USB_PID_INTEL_CE9500 0x9500
|
||||
#define USB_PID_ITETECH_IT9135 0x9135
|
||||
#define USB_PID_ITETECH_IT9135_9005 0x9005
|
||||
|
@ -159,6 +168,8 @@
|
|||
#define USB_PID_KWORLD_UB499_2T_T09 0xe409
|
||||
#define USB_PID_KWORLD_VSTREAM_COLD 0x17de
|
||||
#define USB_PID_KWORLD_VSTREAM_WARM 0x17df
|
||||
#define USB_PID_PROF_1100 0xb012
|
||||
#define USB_PID_TERRATEC_CINERGY_S 0x0064
|
||||
#define USB_PID_TERRATEC_CINERGY_T_USB_XE 0x0055
|
||||
#define USB_PID_TERRATEC_CINERGY_T_USB_XE_REV2 0x0069
|
||||
#define USB_PID_TERRATEC_CINERGY_T_STICK 0x0093
|
||||
|
@ -361,6 +372,8 @@
|
|||
#define USB_PID_YUAN_STK7700D 0x1efc
|
||||
#define USB_PID_YUAN_STK7700D_2 0x1e8c
|
||||
#define USB_PID_DW2102 0x2102
|
||||
#define USB_PID_DW2104 0x2104
|
||||
#define USB_PID_DW3101 0x3101
|
||||
#define USB_PID_XTENSIONS_XD_380 0x0381
|
||||
#define USB_PID_TELESTAR_STARSTICK_2 0x8000
|
||||
#define USB_PID_MSI_DIGI_VOX_MINI_III 0x8807
|
||||
|
@ -373,6 +386,7 @@
|
|||
#define USB_PID_ELGATO_EYETV_DTT_Dlx 0x0020
|
||||
#define USB_PID_ELGATO_EYETV_SAT 0x002a
|
||||
#define USB_PID_ELGATO_EYETV_SAT_V2 0x0025
|
||||
#define USB_PID_ELGATO_EYETV_SAT_V3 0x0036
|
||||
#define USB_PID_DVB_T_USB_STICK_HIGH_SPEED_COLD 0x5000
|
||||
#define USB_PID_DVB_T_USB_STICK_HIGH_SPEED_WARM 0x5001
|
||||
#define USB_PID_FRIIO_WHITE 0x0001
|
||||
|
|
|
@ -676,13 +676,13 @@ int dvb_create_media_graph(struct dvb_adapter *adap,
|
|||
demux, 0, MEDIA_LNK_FL_ENABLED,
|
||||
false);
|
||||
if (ret)
|
||||
return -ENOMEM;
|
||||
return ret;
|
||||
}
|
||||
if (demux && ca) {
|
||||
ret = media_create_pad_link(demux, 1, ca,
|
||||
0, MEDIA_LNK_FL_ENABLED);
|
||||
if (ret)
|
||||
return -ENOMEM;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Create demux links for each ringbuffer/pad */
|
||||
|
|
|
@ -1121,7 +1121,7 @@ void dib0090_pwm_gain_reset(struct dvb_frontend *fe)
|
|||
(state->current_band == BAND_CBAND) ? "CBAND" : "NOT CBAND",
|
||||
state->identity.version & 0x1f);
|
||||
|
||||
if (rf_ramp && ((state->rf_ramp[0] == 0) ||
|
||||
if (rf_ramp && ((state->rf_ramp && state->rf_ramp[0] == 0) ||
|
||||
(state->current_band == BAND_CBAND &&
|
||||
(state->identity.version & 0x1f) <= P1D_E_F))) {
|
||||
dprintk("DE-Engage mux for direct gain reg control");
|
||||
|
|
|
@ -458,7 +458,7 @@ static int ds3000_read_status(struct dvb_frontend *fe, enum fe_status *status)
|
|||
|
||||
break;
|
||||
default:
|
||||
return 1;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (state->config->set_lock_led)
|
||||
|
@ -528,7 +528,7 @@ static int ds3000_read_ber(struct dvb_frontend *fe, u32* ber)
|
|||
*ber = 0xffffffff;
|
||||
break;
|
||||
default:
|
||||
return 1;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -623,7 +623,7 @@ static int ds3000_read_snr(struct dvb_frontend *fe, u16 *snr)
|
|||
snr_reading, *snr);
|
||||
break;
|
||||
default:
|
||||
return 1;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -661,7 +661,7 @@ static int ds3000_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
|
|||
state->prevUCBS2 = _ucblocks;
|
||||
break;
|
||||
default:
|
||||
return 1;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -754,7 +754,7 @@ static int ds3000_send_diseqc_msg(struct dvb_frontend *fe,
|
|||
data |= 0x80;
|
||||
ds3000_writereg(state, 0xa2, data);
|
||||
|
||||
return 1;
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
data = ds3000_readreg(state, 0xa2);
|
||||
|
@ -808,7 +808,7 @@ static int ds3000_diseqc_send_burst(struct dvb_frontend *fe,
|
|||
data |= 0x80;
|
||||
ds3000_writereg(state, 0xa2, data);
|
||||
|
||||
return 1;
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
data = ds3000_readreg(state, 0xa2);
|
||||
|
@ -951,7 +951,7 @@ static int ds3000_set_frontend(struct dvb_frontend *fe)
|
|||
ds3000_writereg(state, 0xfe, 0x98);
|
||||
break;
|
||||
default:
|
||||
return 1;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* enable 27MHz clock output */
|
||||
|
|
|
@ -46,7 +46,7 @@ struct m88ds3103_dev {
|
|||
/* auto detect chip id to do different config */
|
||||
u8 chip_id;
|
||||
/* main mclk is calculated for M88RS6000 dynamically */
|
||||
u32 mclk_khz;
|
||||
s32 mclk_khz;
|
||||
u64 post_bit_error;
|
||||
u64 post_bit_count;
|
||||
};
|
||||
|
|
|
@ -135,8 +135,7 @@ static void zl10353_calc_nominal_rate(struct dvb_frontend *fe,
|
|||
|
||||
value = (u64)10 * (1 << 23) / 7 * 125;
|
||||
value = (bw * value) + adc_clock / 2;
|
||||
do_div(value, adc_clock);
|
||||
*nominal_rate = value;
|
||||
*nominal_rate = div_u64(value, adc_clock);
|
||||
|
||||
dprintk("%s: bw %d, adc_clock %d => 0x%x\n",
|
||||
__func__, bw, adc_clock, *nominal_rate);
|
||||
|
@ -163,8 +162,7 @@ static void zl10353_calc_input_freq(struct dvb_frontend *fe,
|
|||
if (ife > adc_clock / 2)
|
||||
ife = adc_clock - ife;
|
||||
}
|
||||
value = (u64)65536 * ife + adc_clock / 2;
|
||||
do_div(value, adc_clock);
|
||||
value = div_u64((u64)65536 * ife + adc_clock / 2, adc_clock);
|
||||
*input_freq = -value;
|
||||
|
||||
dprintk("%s: if2 %d, ife %d, adc_clock %d => %d / 0x%x\n",
|
||||
|
|
|
@ -1130,8 +1130,6 @@ static int ad9389b_probe(struct i2c_client *client, const struct i2c_device_id *
|
|||
hdl = &state->hdl;
|
||||
v4l2_ctrl_handler_init(hdl, 5);
|
||||
|
||||
/* private controls */
|
||||
|
||||
state->hdmi_mode_ctrl = v4l2_ctrl_new_std_menu(hdl, &ad9389b_ctrl_ops,
|
||||
V4L2_CID_DV_TX_MODE, V4L2_DV_TX_MODE_HDMI,
|
||||
0, V4L2_DV_TX_MODE_DVI_D);
|
||||
|
@ -1151,12 +1149,6 @@ static int ad9389b_probe(struct i2c_client *client, const struct i2c_device_id *
|
|||
|
||||
goto err_hdl;
|
||||
}
|
||||
state->hdmi_mode_ctrl->is_private = true;
|
||||
state->hotplug_ctrl->is_private = true;
|
||||
state->rx_sense_ctrl->is_private = true;
|
||||
state->have_edid0_ctrl->is_private = true;
|
||||
state->rgb_quantization_range_ctrl->is_private = true;
|
||||
|
||||
state->pad.flags = MEDIA_PAD_FL_SINK;
|
||||
err = media_entity_pads_init(&sd->entity, 1, &state->pad);
|
||||
if (err)
|
||||
|
|
|
@ -466,9 +466,9 @@ static int adp1653_of_init(struct i2c_client *client,
|
|||
of_node_put(child);
|
||||
|
||||
pd->enable_gpio = devm_gpiod_get(&client->dev, "enable", GPIOD_OUT_LOW);
|
||||
if (!pd->enable_gpio) {
|
||||
if (IS_ERR(pd->enable_gpio)) {
|
||||
dev_err(&client->dev, "Error getting GPIO\n");
|
||||
return -EINVAL;
|
||||
return PTR_ERR(pd->enable_gpio);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -26,8 +26,9 @@
|
|||
#include <linux/i2c.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/of.h>
|
||||
#include <media/v4l2-ioctl.h>
|
||||
#include <linux/videodev2.h>
|
||||
#include <media/v4l2-ioctl.h>
|
||||
#include <media/v4l2-event.h>
|
||||
#include <media/v4l2-device.h>
|
||||
#include <media/v4l2-ctrls.h>
|
||||
#include <linux/mutex.h>
|
||||
|
@ -192,8 +193,8 @@ struct adv7180_state {
|
|||
struct mutex mutex; /* mutual excl. when accessing chip */
|
||||
int irq;
|
||||
v4l2_std_id curr_norm;
|
||||
bool autodetect;
|
||||
bool powered;
|
||||
bool streaming;
|
||||
u8 input;
|
||||
|
||||
struct i2c_client *client;
|
||||
|
@ -338,12 +339,26 @@ static int adv7180_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
|
|||
if (err)
|
||||
return err;
|
||||
|
||||
/* when we are interrupt driven we know the state */
|
||||
if (!state->autodetect || state->irq > 0)
|
||||
*std = state->curr_norm;
|
||||
else
|
||||
err = __adv7180_status(state, NULL, std);
|
||||
if (state->streaming) {
|
||||
err = -EBUSY;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
err = adv7180_set_video_standard(state,
|
||||
ADV7180_STD_AD_PAL_BG_NTSC_J_SECAM);
|
||||
if (err)
|
||||
goto unlock;
|
||||
|
||||
msleep(100);
|
||||
__adv7180_status(state, NULL, std);
|
||||
|
||||
err = v4l2_std_to_adv7180(state->curr_norm);
|
||||
if (err < 0)
|
||||
goto unlock;
|
||||
|
||||
err = adv7180_set_video_standard(state, err);
|
||||
|
||||
unlock:
|
||||
mutex_unlock(&state->mutex);
|
||||
return err;
|
||||
}
|
||||
|
@ -387,23 +402,13 @@ static int adv7180_program_std(struct adv7180_state *state)
|
|||
{
|
||||
int ret;
|
||||
|
||||
if (state->autodetect) {
|
||||
ret = adv7180_set_video_standard(state,
|
||||
ADV7180_STD_AD_PAL_BG_NTSC_J_SECAM);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
__adv7180_status(state, NULL, &state->curr_norm);
|
||||
} else {
|
||||
ret = v4l2_std_to_adv7180(state->curr_norm);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = adv7180_set_video_standard(state, ret);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
ret = v4l2_std_to_adv7180(state->curr_norm);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = adv7180_set_video_standard(state, ret);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -415,18 +420,12 @@ static int adv7180_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* all standards -> autodetect */
|
||||
if (std == V4L2_STD_ALL) {
|
||||
state->autodetect = true;
|
||||
} else {
|
||||
/* Make sure we can support this std */
|
||||
ret = v4l2_std_to_adv7180(std);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
/* Make sure we can support this std */
|
||||
ret = v4l2_std_to_adv7180(std);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
|
||||
state->curr_norm = std;
|
||||
state->autodetect = false;
|
||||
}
|
||||
state->curr_norm = std;
|
||||
|
||||
ret = adv7180_program_std(state);
|
||||
out:
|
||||
|
@ -434,6 +433,15 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int adv7180_g_std(struct v4l2_subdev *sd, v4l2_std_id *norm)
|
||||
{
|
||||
struct adv7180_state *state = to_state(sd);
|
||||
|
||||
*norm = state->curr_norm;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adv7180_set_power(struct adv7180_state *state, bool on)
|
||||
{
|
||||
u8 val;
|
||||
|
@ -717,17 +725,77 @@ static int adv7180_g_mbus_config(struct v4l2_subdev *sd,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int adv7180_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *cropcap)
|
||||
{
|
||||
struct adv7180_state *state = to_state(sd);
|
||||
|
||||
if (state->curr_norm & V4L2_STD_525_60) {
|
||||
cropcap->pixelaspect.numerator = 11;
|
||||
cropcap->pixelaspect.denominator = 10;
|
||||
} else {
|
||||
cropcap->pixelaspect.numerator = 54;
|
||||
cropcap->pixelaspect.denominator = 59;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adv7180_g_tvnorms(struct v4l2_subdev *sd, v4l2_std_id *norm)
|
||||
{
|
||||
*norm = V4L2_STD_ALL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adv7180_s_stream(struct v4l2_subdev *sd, int enable)
|
||||
{
|
||||
struct adv7180_state *state = to_state(sd);
|
||||
int ret;
|
||||
|
||||
/* It's always safe to stop streaming, no need to take the lock */
|
||||
if (!enable) {
|
||||
state->streaming = enable;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Must wait until querystd released the lock */
|
||||
ret = mutex_lock_interruptible(&state->mutex);
|
||||
if (ret)
|
||||
return ret;
|
||||
state->streaming = enable;
|
||||
mutex_unlock(&state->mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int adv7180_subscribe_event(struct v4l2_subdev *sd,
|
||||
struct v4l2_fh *fh,
|
||||
struct v4l2_event_subscription *sub)
|
||||
{
|
||||
switch (sub->type) {
|
||||
case V4L2_EVENT_SOURCE_CHANGE:
|
||||
return v4l2_src_change_event_subdev_subscribe(sd, fh, sub);
|
||||
case V4L2_EVENT_CTRL:
|
||||
return v4l2_ctrl_subdev_subscribe_event(sd, fh, sub);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct v4l2_subdev_video_ops adv7180_video_ops = {
|
||||
.s_std = adv7180_s_std,
|
||||
.g_std = adv7180_g_std,
|
||||
.querystd = adv7180_querystd,
|
||||
.g_input_status = adv7180_g_input_status,
|
||||
.s_routing = adv7180_s_routing,
|
||||
.g_mbus_config = adv7180_g_mbus_config,
|
||||
.cropcap = adv7180_cropcap,
|
||||
.g_tvnorms = adv7180_g_tvnorms,
|
||||
.s_stream = adv7180_s_stream,
|
||||
};
|
||||
|
||||
|
||||
static const struct v4l2_subdev_core_ops adv7180_core_ops = {
|
||||
.s_power = adv7180_s_power,
|
||||
.subscribe_event = adv7180_subscribe_event,
|
||||
.unsubscribe_event = v4l2_event_subdev_unsubscribe,
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_pad_ops adv7180_pad_ops = {
|
||||
|
@ -752,8 +820,14 @@ static irqreturn_t adv7180_irq(int irq, void *devid)
|
|||
/* clear */
|
||||
adv7180_write(state, ADV7180_REG_ICR3, isr3);
|
||||
|
||||
if (isr3 & ADV7180_IRQ3_AD_CHANGE && state->autodetect)
|
||||
__adv7180_status(state, NULL, &state->curr_norm);
|
||||
if (isr3 & ADV7180_IRQ3_AD_CHANGE) {
|
||||
static const struct v4l2_event src_ch = {
|
||||
.type = V4L2_EVENT_SOURCE_CHANGE,
|
||||
.u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION,
|
||||
};
|
||||
|
||||
v4l2_subdev_notify_event(&state->sd, &src_ch);
|
||||
}
|
||||
mutex_unlock(&state->mutex);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
|
@ -1198,7 +1272,7 @@ static int adv7180_probe(struct i2c_client *client,
|
|||
|
||||
state->irq = client->irq;
|
||||
mutex_init(&state->mutex);
|
||||
state->autodetect = true;
|
||||
state->curr_norm = V4L2_STD_NTSC;
|
||||
if (state->chip_info->flags & ADV7180_FLAG_RESET_POWERED)
|
||||
state->powered = true;
|
||||
else
|
||||
|
@ -1206,7 +1280,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;
|
||||
sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS;
|
||||
|
||||
ret = adv7180_init_controls(state);
|
||||
if (ret)
|
||||
|
@ -1328,6 +1402,14 @@ static SIMPLE_DEV_PM_OPS(adv7180_pm_ops, adv7180_suspend, adv7180_resume);
|
|||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id adv7180_of_id[] = {
|
||||
{ .compatible = "adi,adv7180", },
|
||||
{ .compatible = "adi,adv7182", },
|
||||
{ .compatible = "adi,adv7280", },
|
||||
{ .compatible = "adi,adv7280-m", },
|
||||
{ .compatible = "adi,adv7281", },
|
||||
{ .compatible = "adi,adv7281-m", },
|
||||
{ .compatible = "adi,adv7281-ma", },
|
||||
{ .compatible = "adi,adv7282", },
|
||||
{ .compatible = "adi,adv7282-m", },
|
||||
{ },
|
||||
};
|
||||
|
||||
|
|
|
@ -1502,12 +1502,6 @@ static int adv7511_probe(struct i2c_client *client, const struct i2c_device_id *
|
|||
err = hdl->error;
|
||||
goto err_hdl;
|
||||
}
|
||||
state->hdmi_mode_ctrl->is_private = true;
|
||||
state->hotplug_ctrl->is_private = true;
|
||||
state->rx_sense_ctrl->is_private = true;
|
||||
state->have_edid0_ctrl->is_private = true;
|
||||
state->rgb_quantization_range_ctrl->is_private = true;
|
||||
|
||||
state->pad.flags = MEDIA_PAD_FL_SINK;
|
||||
err = media_entity_pads_init(&sd->entity, 1, &state->pad);
|
||||
if (err)
|
||||
|
|
|
@ -3141,7 +3141,6 @@ static int adv76xx_probe(struct i2c_client *client,
|
|||
if (ctrl)
|
||||
ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
|
||||
|
||||
/* private controls */
|
||||
state->detect_tx_5v_ctrl = v4l2_ctrl_new_std(hdl, NULL,
|
||||
V4L2_CID_DV_RX_POWER_PRESENT, 0,
|
||||
(1 << state->info->num_dv_ports) - 1, 0, 0);
|
||||
|
@ -3164,13 +3163,6 @@ static int adv76xx_probe(struct i2c_client *client,
|
|||
err = hdl->error;
|
||||
goto err_hdl;
|
||||
}
|
||||
state->detect_tx_5v_ctrl->is_private = true;
|
||||
state->rgb_quantization_range_ctrl->is_private = true;
|
||||
if (adv76xx_has_afe(state))
|
||||
state->analog_sampling_phase_ctrl->is_private = true;
|
||||
state->free_run_color_manual_ctrl->is_private = true;
|
||||
state->free_run_color_ctrl->is_private = true;
|
||||
|
||||
if (adv76xx_s_detect_tx_5v_ctrl(sd)) {
|
||||
err = -ENODEV;
|
||||
goto err_hdl;
|
||||
|
|
|
@ -3300,12 +3300,6 @@ static int adv7842_probe(struct i2c_client *client,
|
|||
err = hdl->error;
|
||||
goto err_hdl;
|
||||
}
|
||||
state->detect_tx_5v_ctrl->is_private = true;
|
||||
state->rgb_quantization_range_ctrl->is_private = true;
|
||||
state->analog_sampling_phase_ctrl->is_private = true;
|
||||
state->free_run_color_ctrl_manual->is_private = true;
|
||||
state->free_run_color_ctrl->is_private = true;
|
||||
|
||||
if (adv7842_s_detect_tx_5v_ctrl(sd)) {
|
||||
err = -ENODEV;
|
||||
goto err_hdl;
|
||||
|
|
|
@ -405,7 +405,7 @@ static int m5mols_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
|
|||
struct v4l2_subdev *sd = to_sd(ctrl);
|
||||
struct m5mols_info *info = to_m5mols(sd);
|
||||
int ret = 0;
|
||||
u8 status;
|
||||
u8 status = REG_ISO_AUTO;
|
||||
|
||||
v4l2_dbg(1, m5mols_debug, sd, "%s: ctrl: %s (%d)\n",
|
||||
__func__, ctrl->name, info->isp_ready);
|
||||
|
|
|
@ -1798,6 +1798,21 @@ static int saa711x_detect_chip(struct i2c_client *client,
|
|||
return GM7113C;
|
||||
}
|
||||
|
||||
/* Check if it is a CJC7113 */
|
||||
if (!memcmp(name, "1111111111111111", CHIP_VER_SIZE)) {
|
||||
strlcpy(name, "cjc7113", CHIP_VER_SIZE);
|
||||
|
||||
if (!autodetect && strcmp(name, id->name))
|
||||
return -EINVAL;
|
||||
|
||||
v4l_dbg(1, debug, client,
|
||||
"It seems to be a %s chip (%*ph) @ 0x%x.\n",
|
||||
name, 16, chip_ver, client->addr << 1);
|
||||
|
||||
/* CJC7113 seems to be SAA7113-compatible */
|
||||
return SAA7113;
|
||||
}
|
||||
|
||||
/* Chip was not discovered. Return its ID and don't bind */
|
||||
v4l_dbg(1, debug, client, "chip %*ph @ 0x%x is unknown.\n",
|
||||
16, chip_ver, client->addr << 1);
|
||||
|
|
|
@ -188,6 +188,8 @@ static int smiapp_read_frame_fmt(struct smiapp_sensor *sensor)
|
|||
embedded_end = 0;
|
||||
}
|
||||
|
||||
sensor->image_start = image_start;
|
||||
|
||||
dev_dbg(&client->dev, "embedded data from lines %d to %d\n",
|
||||
embedded_start, embedded_end);
|
||||
dev_dbg(&client->dev, "image data starts at line %d\n", image_start);
|
||||
|
@ -2280,6 +2282,15 @@ static int smiapp_get_skip_frames(struct v4l2_subdev *subdev, u32 *frames)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int smiapp_get_skip_top_lines(struct v4l2_subdev *subdev, u32 *lines)
|
||||
{
|
||||
struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
|
||||
|
||||
*lines = sensor->image_start;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------------------
|
||||
* sysfs attributes
|
||||
*/
|
||||
|
@ -2890,6 +2901,7 @@ static const struct v4l2_subdev_pad_ops smiapp_pad_ops = {
|
|||
|
||||
static const struct v4l2_subdev_sensor_ops smiapp_sensor_ops = {
|
||||
.g_skip_frames = smiapp_get_skip_frames,
|
||||
.g_skip_top_lines = smiapp_get_skip_top_lines,
|
||||
};
|
||||
|
||||
static const struct v4l2_subdev_ops smiapp_ops = {
|
||||
|
|
|
@ -217,6 +217,7 @@ struct smiapp_sensor {
|
|||
|
||||
u8 hvflip_inv_mask; /* H/VFLIP inversion due to sensor orientation */
|
||||
u8 frame_skip;
|
||||
u16 image_start; /* Offset to first line after metadata lines */
|
||||
|
||||
int power_count;
|
||||
|
||||
|
|
|
@ -1551,6 +1551,8 @@ static int tc358743_g_edid(struct v4l2_subdev *sd,
|
|||
{
|
||||
struct tc358743_state *state = to_state(sd);
|
||||
|
||||
memset(edid->reserved, 0, sizeof(edid->reserved));
|
||||
|
||||
if (edid->pad != 0)
|
||||
return -EINVAL;
|
||||
|
||||
|
@ -1585,6 +1587,8 @@ static int tc358743_s_edid(struct v4l2_subdev *sd,
|
|||
v4l2_dbg(2, debug, sd, "%s, pad %d, start block %d, blocks %d\n",
|
||||
__func__, edid->pad, edid->start_block, edid->blocks);
|
||||
|
||||
memset(edid->reserved, 0, sizeof(edid->reserved));
|
||||
|
||||
if (edid->pad != 0)
|
||||
return -EINVAL;
|
||||
|
||||
|
@ -1859,7 +1863,6 @@ static int tc358743_probe(struct i2c_client *client,
|
|||
/* control handlers */
|
||||
v4l2_ctrl_handler_init(&state->hdl, 3);
|
||||
|
||||
/* private controls */
|
||||
state->detect_tx_5v_ctrl = v4l2_ctrl_new_std(&state->hdl, NULL,
|
||||
V4L2_CID_DV_RX_POWER_PRESENT, 0, 1, 0, 0);
|
||||
|
||||
|
|
|
@ -285,7 +285,7 @@ static int ths7303_log_status(struct v4l2_subdev *sd)
|
|||
v4l2_info(sd, "stream %s\n", state->stream_on ? "On" : "Off");
|
||||
|
||||
if (state->bt.pixelclock) {
|
||||
struct v4l2_bt_timings *bt = bt = &state->bt;
|
||||
struct v4l2_bt_timings *bt = &state->bt;
|
||||
u32 frame_width, frame_height;
|
||||
|
||||
frame_width = V4L2_DV_BT_FRAME_WIDTH(bt);
|
||||
|
|
|
@ -83,7 +83,7 @@ static int tvp5150_read(struct v4l2_subdev *sd, unsigned char addr)
|
|||
return rc;
|
||||
}
|
||||
|
||||
static inline void tvp5150_write(struct v4l2_subdev *sd, unsigned char addr,
|
||||
static int tvp5150_write(struct v4l2_subdev *sd, unsigned char addr,
|
||||
unsigned char value)
|
||||
{
|
||||
struct i2c_client *c = v4l2_get_subdevdata(sd);
|
||||
|
@ -92,7 +92,9 @@ static inline void tvp5150_write(struct v4l2_subdev *sd, unsigned char addr,
|
|||
v4l2_dbg(2, debug, sd, "tvp5150: writing 0x%02x 0x%02x\n", addr, value);
|
||||
rc = i2c_smbus_write_byte_data(c, addr, value);
|
||||
if (rc < 0)
|
||||
v4l2_dbg(0, debug, sd, "i2c i/o error: rc == %d\n", rc);
|
||||
v4l2_err(sd, "i2c i/o error: rc == %d\n", rc);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void dump_reg_range(struct v4l2_subdev *sd, char *s, u8 init,
|
||||
|
@ -1159,8 +1161,7 @@ static int tvp5150_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *
|
|||
|
||||
static int tvp5150_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg)
|
||||
{
|
||||
tvp5150_write(sd, reg->reg & 0xff, reg->val & 0xff);
|
||||
return 0;
|
||||
return tvp5150_write(sd, reg->reg & 0xff, reg->val & 0xff);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -90,18 +90,13 @@ static struct media_entity *find_entity(struct media_device *mdev, u32 id)
|
|||
|
||||
id &= ~MEDIA_ENT_ID_FLAG_NEXT;
|
||||
|
||||
spin_lock(&mdev->lock);
|
||||
|
||||
media_device_for_each_entity(entity, mdev) {
|
||||
if (((media_entity_id(entity) == id) && !next) ||
|
||||
((media_entity_id(entity) > id) && next)) {
|
||||
spin_unlock(&mdev->lock);
|
||||
return entity;
|
||||
}
|
||||
}
|
||||
|
||||
spin_unlock(&mdev->lock);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -431,6 +426,7 @@ static long media_device_ioctl(struct file *filp, unsigned int cmd,
|
|||
struct media_device *dev = to_media_device(devnode);
|
||||
long ret;
|
||||
|
||||
mutex_lock(&dev->graph_mutex);
|
||||
switch (cmd) {
|
||||
case MEDIA_IOC_DEVICE_INFO:
|
||||
ret = media_device_get_info(dev,
|
||||
|
@ -443,29 +439,24 @@ static long media_device_ioctl(struct file *filp, unsigned int cmd,
|
|||
break;
|
||||
|
||||
case MEDIA_IOC_ENUM_LINKS:
|
||||
mutex_lock(&dev->graph_mutex);
|
||||
ret = media_device_enum_links(dev,
|
||||
(struct media_links_enum __user *)arg);
|
||||
mutex_unlock(&dev->graph_mutex);
|
||||
break;
|
||||
|
||||
case MEDIA_IOC_SETUP_LINK:
|
||||
mutex_lock(&dev->graph_mutex);
|
||||
ret = media_device_setup_link(dev,
|
||||
(struct media_link_desc __user *)arg);
|
||||
mutex_unlock(&dev->graph_mutex);
|
||||
break;
|
||||
|
||||
case MEDIA_IOC_G_TOPOLOGY:
|
||||
mutex_lock(&dev->graph_mutex);
|
||||
ret = media_device_get_topology(dev,
|
||||
(struct media_v2_topology __user *)arg);
|
||||
mutex_unlock(&dev->graph_mutex);
|
||||
break;
|
||||
|
||||
default:
|
||||
ret = -ENOIOCTLCMD;
|
||||
}
|
||||
mutex_unlock(&dev->graph_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -508,12 +499,6 @@ static long media_device_compat_ioctl(struct file *filp, unsigned int cmd,
|
|||
long ret;
|
||||
|
||||
switch (cmd) {
|
||||
case MEDIA_IOC_DEVICE_INFO:
|
||||
case MEDIA_IOC_ENUM_ENTITIES:
|
||||
case MEDIA_IOC_SETUP_LINK:
|
||||
case MEDIA_IOC_G_TOPOLOGY:
|
||||
return media_device_ioctl(filp, cmd, arg);
|
||||
|
||||
case MEDIA_IOC_ENUM_LINKS32:
|
||||
mutex_lock(&dev->graph_mutex);
|
||||
ret = media_device_enum_links32(dev,
|
||||
|
@ -522,7 +507,7 @@ static long media_device_compat_ioctl(struct file *filp, unsigned int cmd,
|
|||
break;
|
||||
|
||||
default:
|
||||
ret = -ENOIOCTLCMD;
|
||||
return media_device_ioctl(filp, cmd, arg);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
@ -590,12 +575,12 @@ int __must_check media_device_register_entity(struct media_device *mdev,
|
|||
if (!ida_pre_get(&mdev->entity_internal_idx, GFP_KERNEL))
|
||||
return -ENOMEM;
|
||||
|
||||
spin_lock(&mdev->lock);
|
||||
mutex_lock(&mdev->graph_mutex);
|
||||
|
||||
ret = ida_get_new_above(&mdev->entity_internal_idx, 1,
|
||||
&entity->internal_idx);
|
||||
if (ret < 0) {
|
||||
spin_unlock(&mdev->lock);
|
||||
mutex_unlock(&mdev->graph_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -615,9 +600,6 @@ int __must_check media_device_register_entity(struct media_device *mdev,
|
|||
(notify)->notify(entity, notify->notify_data);
|
||||
}
|
||||
|
||||
spin_unlock(&mdev->lock);
|
||||
|
||||
mutex_lock(&mdev->graph_mutex);
|
||||
if (mdev->entity_internal_idx_max
|
||||
>= mdev->pm_count_walk.ent_enum.idx_max) {
|
||||
struct media_entity_graph new = { .top = 0 };
|
||||
|
@ -680,9 +662,9 @@ void media_device_unregister_entity(struct media_entity *entity)
|
|||
if (mdev == NULL)
|
||||
return;
|
||||
|
||||
spin_lock(&mdev->lock);
|
||||
mutex_lock(&mdev->graph_mutex);
|
||||
__media_device_unregister_entity(entity);
|
||||
spin_unlock(&mdev->lock);
|
||||
mutex_unlock(&mdev->graph_mutex);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(media_device_unregister_entity);
|
||||
|
||||
|
@ -703,7 +685,6 @@ void media_device_init(struct media_device *mdev)
|
|||
INIT_LIST_HEAD(&mdev->pads);
|
||||
INIT_LIST_HEAD(&mdev->links);
|
||||
INIT_LIST_HEAD(&mdev->entity_notify);
|
||||
spin_lock_init(&mdev->lock);
|
||||
mutex_init(&mdev->graph_mutex);
|
||||
ida_init(&mdev->entity_internal_idx);
|
||||
|
||||
|
@ -752,9 +733,9 @@ EXPORT_SYMBOL_GPL(__media_device_register);
|
|||
int __must_check media_device_register_entity_notify(struct media_device *mdev,
|
||||
struct media_entity_notify *nptr)
|
||||
{
|
||||
spin_lock(&mdev->lock);
|
||||
mutex_lock(&mdev->graph_mutex);
|
||||
list_add_tail(&nptr->list, &mdev->entity_notify);
|
||||
spin_unlock(&mdev->lock);
|
||||
mutex_unlock(&mdev->graph_mutex);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(media_device_register_entity_notify);
|
||||
|
@ -771,9 +752,9 @@ static void __media_device_unregister_entity_notify(struct media_device *mdev,
|
|||
void media_device_unregister_entity_notify(struct media_device *mdev,
|
||||
struct media_entity_notify *nptr)
|
||||
{
|
||||
spin_lock(&mdev->lock);
|
||||
mutex_lock(&mdev->graph_mutex);
|
||||
__media_device_unregister_entity_notify(mdev, nptr);
|
||||
spin_unlock(&mdev->lock);
|
||||
mutex_unlock(&mdev->graph_mutex);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(media_device_unregister_entity_notify);
|
||||
|
||||
|
@ -787,11 +768,11 @@ void media_device_unregister(struct media_device *mdev)
|
|||
if (mdev == NULL)
|
||||
return;
|
||||
|
||||
spin_lock(&mdev->lock);
|
||||
mutex_lock(&mdev->graph_mutex);
|
||||
|
||||
/* Check if mdev was ever registered at all */
|
||||
if (!media_devnode_is_registered(&mdev->devnode)) {
|
||||
spin_unlock(&mdev->lock);
|
||||
mutex_unlock(&mdev->graph_mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -811,12 +792,11 @@ void media_device_unregister(struct media_device *mdev)
|
|||
kfree(intf);
|
||||
}
|
||||
|
||||
spin_unlock(&mdev->lock);
|
||||
mutex_unlock(&mdev->graph_mutex);
|
||||
|
||||
device_remove_file(&mdev->devnode.dev, &dev_attr_model);
|
||||
dev_dbg(mdev->dev, "Media device unregistering\n");
|
||||
media_devnode_unregister(&mdev->devnode);
|
||||
|
||||
dev_dbg(mdev->dev, "Media device unregistered\n");
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(media_device_unregister);
|
||||
|
||||
|
|
|
@ -197,10 +197,11 @@ static int media_release(struct inode *inode, struct file *filp)
|
|||
if (mdev->fops->release)
|
||||
mdev->fops->release(filp);
|
||||
|
||||
filp->private_data = NULL;
|
||||
|
||||
/* decrease the refcount unconditionally since the release()
|
||||
return value is ignored. */
|
||||
put_device(&mdev->dev);
|
||||
filp->private_data = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -267,8 +268,11 @@ int __must_check media_devnode_register(struct media_devnode *mdev,
|
|||
return 0;
|
||||
|
||||
error:
|
||||
mutex_lock(&media_devnode_lock);
|
||||
cdev_del(&mdev->cdev);
|
||||
clear_bit(mdev->minor, media_devnode_nums);
|
||||
mutex_unlock(&media_devnode_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -219,7 +219,7 @@ int media_entity_pads_init(struct media_entity *entity, u16 num_pads,
|
|||
entity->pads = pads;
|
||||
|
||||
if (mdev)
|
||||
spin_lock(&mdev->lock);
|
||||
mutex_lock(&mdev->graph_mutex);
|
||||
|
||||
for (i = 0; i < num_pads; i++) {
|
||||
pads[i].entity = entity;
|
||||
|
@ -230,7 +230,7 @@ int media_entity_pads_init(struct media_entity *entity, u16 num_pads,
|
|||
}
|
||||
|
||||
if (mdev)
|
||||
spin_unlock(&mdev->lock);
|
||||
mutex_unlock(&mdev->graph_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -445,7 +445,7 @@ __must_check int __media_entity_pipeline_start(struct media_entity *entity,
|
|||
bitmap_or(active, active, has_no_links, entity->num_pads);
|
||||
|
||||
if (!bitmap_full(active, entity->num_pads)) {
|
||||
ret = -EPIPE;
|
||||
ret = -ENOLINK;
|
||||
dev_dbg(entity->graph_obj.mdev->dev,
|
||||
"\"%s\":%u must be connected by an enabled link\n",
|
||||
entity->name,
|
||||
|
@ -747,9 +747,9 @@ void media_entity_remove_links(struct media_entity *entity)
|
|||
if (mdev == NULL)
|
||||
return;
|
||||
|
||||
spin_lock(&mdev->lock);
|
||||
mutex_lock(&mdev->graph_mutex);
|
||||
__media_entity_remove_links(entity);
|
||||
spin_unlock(&mdev->lock);
|
||||
mutex_unlock(&mdev->graph_mutex);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(media_entity_remove_links);
|
||||
|
||||
|
@ -951,9 +951,9 @@ void media_remove_intf_link(struct media_link *link)
|
|||
if (mdev == NULL)
|
||||
return;
|
||||
|
||||
spin_lock(&mdev->lock);
|
||||
mutex_lock(&mdev->graph_mutex);
|
||||
__media_remove_intf_link(link);
|
||||
spin_unlock(&mdev->lock);
|
||||
mutex_unlock(&mdev->graph_mutex);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(media_remove_intf_link);
|
||||
|
||||
|
@ -975,8 +975,8 @@ void media_remove_intf_links(struct media_interface *intf)
|
|||
if (mdev == NULL)
|
||||
return;
|
||||
|
||||
spin_lock(&mdev->lock);
|
||||
mutex_lock(&mdev->graph_mutex);
|
||||
__media_remove_intf_links(intf);
|
||||
spin_unlock(&mdev->lock);
|
||||
mutex_unlock(&mdev->graph_mutex);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(media_remove_intf_links);
|
||||
|
|
|
@ -14,6 +14,7 @@ source "drivers/media/pci/meye/Kconfig"
|
|||
source "drivers/media/pci/solo6x10/Kconfig"
|
||||
source "drivers/media/pci/sta2x11/Kconfig"
|
||||
source "drivers/media/pci/tw68/Kconfig"
|
||||
source "drivers/media/pci/tw686x/Kconfig"
|
||||
source "drivers/media/pci/zoran/Kconfig"
|
||||
endif
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@ obj-$(CONFIG_VIDEO_BT848) += bt8xx/
|
|||
obj-$(CONFIG_VIDEO_SAA7134) += saa7134/
|
||||
obj-$(CONFIG_VIDEO_SAA7164) += saa7164/
|
||||
obj-$(CONFIG_VIDEO_TW68) += tw68/
|
||||
obj-$(CONFIG_VIDEO_TW686X) += tw686x/
|
||||
obj-$(CONFIG_VIDEO_DT3155) += dt3155/
|
||||
obj-$(CONFIG_VIDEO_MEYE) += meye/
|
||||
obj-$(CONFIG_STA2X11_VIP) += sta2x11/
|
||||
|
|
|
@ -4,6 +4,7 @@ config VIDEO_COBALT
|
|||
depends on PCI_MSI && MTD_COMPLEX_MAPPINGS
|
||||
depends on GPIOLIB || COMPILE_TEST
|
||||
depends on SND
|
||||
depends on MTD
|
||||
select I2C_ALGOBIT
|
||||
select VIDEO_ADV7604
|
||||
select VIDEO_ADV7511
|
||||
|
|
|
@ -707,11 +707,7 @@ static inline int cx18_raw_vbi(const struct cx18 *cx)
|
|||
/* Call the specified callback for all subdevs with a grp_id bit matching the
|
||||
* mask in hw (if 0, then match them all). Ignore any errors. */
|
||||
#define cx18_call_hw(cx, hw, o, f, args...) \
|
||||
do { \
|
||||
struct v4l2_subdev *__sd; \
|
||||
__v4l2_device_call_subdevs_p(&(cx)->v4l2_dev, __sd, \
|
||||
!(hw) || (__sd->grp_id & (hw)), o, f , ##args); \
|
||||
} while (0)
|
||||
v4l2_device_mask_call_all(&(cx)->v4l2_dev, hw, o, f, ##args)
|
||||
|
||||
#define cx18_call_all(cx, o, f, args...) cx18_call_hw(cx, 0, o, f , ##args)
|
||||
|
||||
|
@ -719,12 +715,7 @@ static inline int cx18_raw_vbi(const struct cx18 *cx)
|
|||
* mask in hw (if 0, then match them all). If the callback returns an error
|
||||
* other than 0 or -ENOIOCTLCMD, then return with that error code. */
|
||||
#define cx18_call_hw_err(cx, hw, o, f, args...) \
|
||||
({ \
|
||||
struct v4l2_subdev *__sd; \
|
||||
__v4l2_device_call_subdevs_until_err_p(&(cx)->v4l2_dev, \
|
||||
__sd, !(hw) || (__sd->grp_id & (hw)), o, f, \
|
||||
##args); \
|
||||
})
|
||||
v4l2_device_mask_call_until_err(&(cx)->v4l2_dev, hw, o, f, ##args)
|
||||
|
||||
#define cx18_call_all_err(cx, o, f, args...) \
|
||||
cx18_call_hw_err(cx, 0, o, f , ##args)
|
||||
|
|
|
@ -24,7 +24,7 @@ void cx23885_av_work_handler(struct work_struct *work)
|
|||
{
|
||||
struct cx23885_dev *dev =
|
||||
container_of(work, struct cx23885_dev, cx25840_work);
|
||||
bool handled;
|
||||
bool handled = false;
|
||||
|
||||
v4l2_subdev_call(dev->sd_cx25840, core, interrupt_service_routine,
|
||||
PCI_MSK_AV_CORE, &handled);
|
||||
|
|
|
@ -827,12 +827,7 @@ static inline int ivtv_raw_vbi(const struct ivtv *itv)
|
|||
/* Call the specified callback for all subdevs matching hw (if 0, then
|
||||
match them all). Ignore any errors. */
|
||||
#define ivtv_call_hw(itv, hw, o, f, args...) \
|
||||
do { \
|
||||
struct v4l2_subdev *__sd; \
|
||||
__v4l2_device_call_subdevs_p(&(itv)->v4l2_dev, __sd, \
|
||||
!(hw) ? true : (__sd->grp_id & (hw)), \
|
||||
o, f, ##args); \
|
||||
} while (0)
|
||||
v4l2_device_mask_call_all(&(itv)->v4l2_dev, hw, o, f, ##args)
|
||||
|
||||
#define ivtv_call_all(itv, o, f, args...) ivtv_call_hw(itv, 0, o, f , ##args)
|
||||
|
||||
|
@ -840,11 +835,7 @@ static inline int ivtv_raw_vbi(const struct ivtv *itv)
|
|||
match them all). If the callback returns an error other than 0 or
|
||||
-ENOIOCTLCMD, then return with that error code. */
|
||||
#define ivtv_call_hw_err(itv, hw, o, f, args...) \
|
||||
({ \
|
||||
struct v4l2_subdev *__sd; \
|
||||
__v4l2_device_call_subdevs_until_err_p(&(itv)->v4l2_dev, __sd, \
|
||||
!(hw) || (__sd->grp_id & (hw)), o, f , ##args); \
|
||||
})
|
||||
v4l2_device_mask_call_until_err(&(itv)->v4l2_dev, hw, o, f, ##args)
|
||||
|
||||
#define ivtv_call_all_err(itv, o, f, args...) ivtv_call_hw_err(itv, 0, o, f , ##args)
|
||||
|
||||
|
|
|
@ -203,7 +203,7 @@ int smi_ir_init(struct smi_dev *dev)
|
|||
rc_dev->dev.parent = &dev->pci_dev->dev;
|
||||
|
||||
rc_dev->driver_type = RC_DRIVER_SCANCODE;
|
||||
rc_dev->map_name = RC_MAP_DVBSKY;
|
||||
rc_dev->map_name = dev->info->rc_map;
|
||||
|
||||
ir->rc_dev = rc_dev;
|
||||
ir->dev = dev;
|
||||
|
|
|
@ -716,7 +716,8 @@ static int smi_fe_init(struct smi_port *port)
|
|||
/* init MAC.*/
|
||||
ret = smi_read_eeprom(&dev->i2c_bus[0], 0xc0, mac_ee, 16);
|
||||
dev_info(&port->dev->pci_dev->dev,
|
||||
"DVBSky SMI PCIe MAC= %pM\n", mac_ee + (port->idx)*8);
|
||||
"%s port %d MAC: %pM\n", dev->info->name,
|
||||
port->idx, mac_ee + (port->idx)*8);
|
||||
memcpy(adap->proposed_mac, mac_ee + (port->idx)*8, 6);
|
||||
return ret;
|
||||
}
|
||||
|
@ -1066,6 +1067,7 @@ static struct smi_cfg_info dvbsky_s950_cfg = {
|
|||
.ts_1 = SMI_TS_DMA_BOTH,
|
||||
.fe_0 = DVBSKY_FE_NULL,
|
||||
.fe_1 = DVBSKY_FE_M88DS3103,
|
||||
.rc_map = RC_MAP_DVBSKY,
|
||||
};
|
||||
|
||||
static struct smi_cfg_info dvbsky_s952_cfg = {
|
||||
|
@ -1075,6 +1077,7 @@ static struct smi_cfg_info dvbsky_s952_cfg = {
|
|||
.ts_1 = SMI_TS_DMA_BOTH,
|
||||
.fe_0 = DVBSKY_FE_M88RS6000,
|
||||
.fe_1 = DVBSKY_FE_M88RS6000,
|
||||
.rc_map = RC_MAP_DVBSKY,
|
||||
};
|
||||
|
||||
static struct smi_cfg_info dvbsky_t9580_cfg = {
|
||||
|
@ -1084,6 +1087,17 @@ static struct smi_cfg_info dvbsky_t9580_cfg = {
|
|||
.ts_1 = SMI_TS_DMA_BOTH,
|
||||
.fe_0 = DVBSKY_FE_SIT2,
|
||||
.fe_1 = DVBSKY_FE_M88DS3103,
|
||||
.rc_map = RC_MAP_DVBSKY,
|
||||
};
|
||||
|
||||
static struct smi_cfg_info technotrend_s2_4200_cfg = {
|
||||
.type = SMI_TECHNOTREND_S2_4200,
|
||||
.name = "TechnoTrend TT-budget S2-4200 Twin",
|
||||
.ts_0 = SMI_TS_DMA_BOTH,
|
||||
.ts_1 = SMI_TS_DMA_BOTH,
|
||||
.fe_0 = DVBSKY_FE_M88RS6000,
|
||||
.fe_1 = DVBSKY_FE_M88RS6000,
|
||||
.rc_map = RC_MAP_TT_1500,
|
||||
};
|
||||
|
||||
/* PCI IDs */
|
||||
|
@ -1096,6 +1110,7 @@ static const struct pci_device_id smi_id_table[] = {
|
|||
SMI_ID(0x4254, 0x0550, dvbsky_s950_cfg),
|
||||
SMI_ID(0x4254, 0x0552, dvbsky_s952_cfg),
|
||||
SMI_ID(0x4254, 0x5580, dvbsky_t9580_cfg),
|
||||
SMI_ID(0x13c2, 0x3016, technotrend_s2_4200_cfg),
|
||||
{0}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, smi_id_table);
|
||||
|
|
|
@ -216,6 +216,7 @@ struct smi_cfg_info {
|
|||
#define SMI_DVBSKY_S950 1
|
||||
#define SMI_DVBSKY_T9580 2
|
||||
#define SMI_DVBSKY_T982 3
|
||||
#define SMI_TECHNOTREND_S2_4200 4
|
||||
int type;
|
||||
char *name;
|
||||
#define SMI_TS_NULL 0
|
||||
|
@ -232,6 +233,7 @@ struct smi_cfg_info {
|
|||
#define DVBSKY_FE_SIT2 3
|
||||
int fe_0;
|
||||
int fe_1;
|
||||
char *rc_map;
|
||||
};
|
||||
|
||||
struct smi_rc {
|
||||
|
|
|
@ -444,27 +444,19 @@ static int vidioc_querycap(struct file *file, void *priv,
|
|||
static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id std)
|
||||
{
|
||||
struct sta2x11_vip *vip = video_drvdata(file);
|
||||
v4l2_std_id oldstd = vip->std, newstd;
|
||||
int status;
|
||||
|
||||
if (V4L2_STD_ALL == std) {
|
||||
v4l2_subdev_call(vip->decoder, video, s_std, std);
|
||||
ssleep(2);
|
||||
v4l2_subdev_call(vip->decoder, video, querystd, &newstd);
|
||||
v4l2_subdev_call(vip->decoder, video, g_input_status, &status);
|
||||
if (status & V4L2_IN_ST_NO_SIGNAL)
|
||||
/*
|
||||
* This is here for backwards compatibility only.
|
||||
* The use of V4L2_STD_ALL to trigger a querystd is non-standard.
|
||||
*/
|
||||
if (std == V4L2_STD_ALL) {
|
||||
v4l2_subdev_call(vip->decoder, video, querystd, &std);
|
||||
if (std == V4L2_STD_UNKNOWN)
|
||||
return -EIO;
|
||||
std = vip->std = newstd;
|
||||
if (oldstd != std) {
|
||||
if (V4L2_STD_525_60 & std)
|
||||
vip->format = formats_60[0];
|
||||
else
|
||||
vip->format = formats_50[0];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (oldstd != std) {
|
||||
if (vip->std != std) {
|
||||
vip->std = std;
|
||||
if (V4L2_STD_525_60 & std)
|
||||
vip->format = formats_60[0];
|
||||
else
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
config VIDEO_TW686X
|
||||
tristate "Intersil/Techwell TW686x video capture cards"
|
||||
depends on PCI && VIDEO_DEV && VIDEO_V4L2 && SND
|
||||
depends on HAS_DMA
|
||||
select VIDEOBUF2_VMALLOC
|
||||
select SND_PCM
|
||||
help
|
||||
Support for Intersil/Techwell TW686x-based frame grabber cards.
|
||||
|
||||
Currently supported chips:
|
||||
- TW6864 (4 video channels),
|
||||
- TW6865 (4 video channels, not tested, second generation chip),
|
||||
- TW6868 (8 video channels but only 4 first channels using
|
||||
built-in video decoder are supported, not tested),
|
||||
- TW6869 (8 video channels, second generation chip).
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be named tw686x.
|
|
@ -0,0 +1,3 @@
|
|||
tw686x-objs := tw686x-core.o tw686x-video.o tw686x-audio.o
|
||||
|
||||
obj-$(CONFIG_VIDEO_TW686X) += tw686x.o
|
|
@ -0,0 +1,386 @@
|
|||
/*
|
||||
* Copyright (C) 2015 VanguardiaSur - www.vanguardiasur.com.ar
|
||||
*
|
||||
* Based on the audio support from the tw6869 driver:
|
||||
* Copyright 2015 www.starterkit.ru <info@starterkit.ru>
|
||||
*
|
||||
* Based on:
|
||||
* Driver for Intersil|Techwell TW6869 based DVR cards
|
||||
* (c) 2011-12 liran <jli11@intersil.com> [Intersil|Techwell China]
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of version 2 of the GNU General Public License
|
||||
* as published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kmod.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include <sound/core.h>
|
||||
#include <sound/initval.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/control.h>
|
||||
#include "tw686x.h"
|
||||
#include "tw686x-regs.h"
|
||||
|
||||
#define AUDIO_CHANNEL_OFFSET 8
|
||||
|
||||
void tw686x_audio_irq(struct tw686x_dev *dev, unsigned long requests,
|
||||
unsigned int pb_status)
|
||||
{
|
||||
unsigned long flags;
|
||||
unsigned int ch, pb;
|
||||
|
||||
for_each_set_bit(ch, &requests, max_channels(dev)) {
|
||||
struct tw686x_audio_channel *ac = &dev->audio_channels[ch];
|
||||
struct tw686x_audio_buf *done = NULL;
|
||||
struct tw686x_audio_buf *next = NULL;
|
||||
struct tw686x_dma_desc *desc;
|
||||
|
||||
pb = !!(pb_status & BIT(AUDIO_CHANNEL_OFFSET + ch));
|
||||
|
||||
spin_lock_irqsave(&ac->lock, flags);
|
||||
|
||||
/* Sanity check */
|
||||
if (!ac->ss || !ac->curr_bufs[0] || !ac->curr_bufs[1]) {
|
||||
spin_unlock_irqrestore(&ac->lock, flags);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!list_empty(&ac->buf_list)) {
|
||||
next = list_first_entry(&ac->buf_list,
|
||||
struct tw686x_audio_buf, list);
|
||||
list_move_tail(&next->list, &ac->buf_list);
|
||||
done = ac->curr_bufs[!pb];
|
||||
ac->curr_bufs[pb] = next;
|
||||
}
|
||||
spin_unlock_irqrestore(&ac->lock, flags);
|
||||
|
||||
desc = &ac->dma_descs[pb];
|
||||
if (done && next && desc->virt) {
|
||||
memcpy(done->virt, desc->virt, desc->size);
|
||||
ac->ptr = done->dma - ac->buf[0].dma;
|
||||
snd_pcm_period_elapsed(ac->ss);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int tw686x_pcm_hw_params(struct snd_pcm_substream *ss,
|
||||
struct snd_pcm_hw_params *hw_params)
|
||||
{
|
||||
return snd_pcm_lib_malloc_pages(ss, params_buffer_bytes(hw_params));
|
||||
}
|
||||
|
||||
static int tw686x_pcm_hw_free(struct snd_pcm_substream *ss)
|
||||
{
|
||||
return snd_pcm_lib_free_pages(ss);
|
||||
}
|
||||
|
||||
/*
|
||||
* The audio device rate is global and shared among all
|
||||
* capture channels. The driver makes no effort to prevent
|
||||
* rate modifications. User is free change the rate, but it
|
||||
* means changing the rate for all capture sub-devices.
|
||||
*/
|
||||
static const struct snd_pcm_hardware tw686x_capture_hw = {
|
||||
.info = (SNDRV_PCM_INFO_MMAP |
|
||||
SNDRV_PCM_INFO_INTERLEAVED |
|
||||
SNDRV_PCM_INFO_BLOCK_TRANSFER |
|
||||
SNDRV_PCM_INFO_MMAP_VALID),
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE,
|
||||
.rates = SNDRV_PCM_RATE_8000_48000,
|
||||
.rate_min = 8000,
|
||||
.rate_max = 48000,
|
||||
.channels_min = 1,
|
||||
.channels_max = 1,
|
||||
.buffer_bytes_max = TW686X_AUDIO_PAGE_MAX * TW686X_AUDIO_PAGE_SZ,
|
||||
.period_bytes_min = TW686X_AUDIO_PAGE_SZ,
|
||||
.period_bytes_max = TW686X_AUDIO_PAGE_SZ,
|
||||
.periods_min = TW686X_AUDIO_PERIODS_MIN,
|
||||
.periods_max = TW686X_AUDIO_PERIODS_MAX,
|
||||
};
|
||||
|
||||
static int tw686x_pcm_open(struct snd_pcm_substream *ss)
|
||||
{
|
||||
struct tw686x_dev *dev = snd_pcm_substream_chip(ss);
|
||||
struct tw686x_audio_channel *ac = &dev->audio_channels[ss->number];
|
||||
struct snd_pcm_runtime *rt = ss->runtime;
|
||||
int err;
|
||||
|
||||
ac->ss = ss;
|
||||
rt->hw = tw686x_capture_hw;
|
||||
|
||||
err = snd_pcm_hw_constraint_integer(rt, SNDRV_PCM_HW_PARAM_PERIODS);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tw686x_pcm_close(struct snd_pcm_substream *ss)
|
||||
{
|
||||
struct tw686x_dev *dev = snd_pcm_substream_chip(ss);
|
||||
struct tw686x_audio_channel *ac = &dev->audio_channels[ss->number];
|
||||
|
||||
ac->ss = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tw686x_pcm_prepare(struct snd_pcm_substream *ss)
|
||||
{
|
||||
struct tw686x_dev *dev = snd_pcm_substream_chip(ss);
|
||||
struct tw686x_audio_channel *ac = &dev->audio_channels[ss->number];
|
||||
struct snd_pcm_runtime *rt = ss->runtime;
|
||||
unsigned int period_size = snd_pcm_lib_period_bytes(ss);
|
||||
struct tw686x_audio_buf *p_buf, *b_buf;
|
||||
unsigned long flags;
|
||||
int i;
|
||||
|
||||
spin_lock_irqsave(&dev->lock, flags);
|
||||
tw686x_disable_channel(dev, AUDIO_CHANNEL_OFFSET + ac->ch);
|
||||
spin_unlock_irqrestore(&dev->lock, flags);
|
||||
|
||||
if (dev->audio_rate != rt->rate) {
|
||||
u32 reg;
|
||||
|
||||
dev->audio_rate = rt->rate;
|
||||
reg = ((125000000 / rt->rate) << 16) +
|
||||
((125000000 % rt->rate) << 16) / rt->rate;
|
||||
|
||||
reg_write(dev, AUDIO_CONTROL2, reg);
|
||||
}
|
||||
|
||||
if (period_size != TW686X_AUDIO_PAGE_SZ ||
|
||||
rt->periods < TW686X_AUDIO_PERIODS_MIN ||
|
||||
rt->periods > TW686X_AUDIO_PERIODS_MAX) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&ac->lock, flags);
|
||||
INIT_LIST_HEAD(&ac->buf_list);
|
||||
|
||||
for (i = 0; i < rt->periods; i++) {
|
||||
ac->buf[i].dma = rt->dma_addr + period_size * i;
|
||||
ac->buf[i].virt = rt->dma_area + period_size * i;
|
||||
INIT_LIST_HEAD(&ac->buf[i].list);
|
||||
list_add_tail(&ac->buf[i].list, &ac->buf_list);
|
||||
}
|
||||
|
||||
p_buf = list_first_entry(&ac->buf_list, struct tw686x_audio_buf, list);
|
||||
list_move_tail(&p_buf->list, &ac->buf_list);
|
||||
|
||||
b_buf = list_first_entry(&ac->buf_list, struct tw686x_audio_buf, list);
|
||||
list_move_tail(&b_buf->list, &ac->buf_list);
|
||||
|
||||
ac->curr_bufs[0] = p_buf;
|
||||
ac->curr_bufs[1] = b_buf;
|
||||
ac->ptr = 0;
|
||||
spin_unlock_irqrestore(&ac->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tw686x_pcm_trigger(struct snd_pcm_substream *ss, int cmd)
|
||||
{
|
||||
struct tw686x_dev *dev = snd_pcm_substream_chip(ss);
|
||||
struct tw686x_audio_channel *ac = &dev->audio_channels[ss->number];
|
||||
unsigned long flags;
|
||||
int err = 0;
|
||||
|
||||
switch (cmd) {
|
||||
case SNDRV_PCM_TRIGGER_START:
|
||||
if (ac->curr_bufs[0] && ac->curr_bufs[1]) {
|
||||
spin_lock_irqsave(&dev->lock, flags);
|
||||
tw686x_enable_channel(dev,
|
||||
AUDIO_CHANNEL_OFFSET + ac->ch);
|
||||
spin_unlock_irqrestore(&dev->lock, flags);
|
||||
|
||||
mod_timer(&dev->dma_delay_timer,
|
||||
jiffies + msecs_to_jiffies(100));
|
||||
} else {
|
||||
err = -EIO;
|
||||
}
|
||||
break;
|
||||
case SNDRV_PCM_TRIGGER_STOP:
|
||||
spin_lock_irqsave(&dev->lock, flags);
|
||||
tw686x_disable_channel(dev, AUDIO_CHANNEL_OFFSET + ac->ch);
|
||||
spin_unlock_irqrestore(&dev->lock, flags);
|
||||
|
||||
spin_lock_irqsave(&ac->lock, flags);
|
||||
ac->curr_bufs[0] = NULL;
|
||||
ac->curr_bufs[1] = NULL;
|
||||
spin_unlock_irqrestore(&ac->lock, flags);
|
||||
break;
|
||||
default:
|
||||
err = -EINVAL;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static snd_pcm_uframes_t tw686x_pcm_pointer(struct snd_pcm_substream *ss)
|
||||
{
|
||||
struct tw686x_dev *dev = snd_pcm_substream_chip(ss);
|
||||
struct tw686x_audio_channel *ac = &dev->audio_channels[ss->number];
|
||||
|
||||
return bytes_to_frames(ss->runtime, ac->ptr);
|
||||
}
|
||||
|
||||
static struct snd_pcm_ops tw686x_pcm_ops = {
|
||||
.open = tw686x_pcm_open,
|
||||
.close = tw686x_pcm_close,
|
||||
.ioctl = snd_pcm_lib_ioctl,
|
||||
.hw_params = tw686x_pcm_hw_params,
|
||||
.hw_free = tw686x_pcm_hw_free,
|
||||
.prepare = tw686x_pcm_prepare,
|
||||
.trigger = tw686x_pcm_trigger,
|
||||
.pointer = tw686x_pcm_pointer,
|
||||
};
|
||||
|
||||
static int tw686x_snd_pcm_init(struct tw686x_dev *dev)
|
||||
{
|
||||
struct snd_card *card = dev->snd_card;
|
||||
struct snd_pcm *pcm;
|
||||
struct snd_pcm_substream *ss;
|
||||
unsigned int i;
|
||||
int err;
|
||||
|
||||
err = snd_pcm_new(card, card->driver, 0, 0, max_channels(dev), &pcm);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &tw686x_pcm_ops);
|
||||
snd_pcm_chip(pcm) = dev;
|
||||
pcm->info_flags = 0;
|
||||
strlcpy(pcm->name, "tw686x PCM", sizeof(pcm->name));
|
||||
|
||||
for (i = 0, ss = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream;
|
||||
ss; ss = ss->next, i++)
|
||||
snprintf(ss->name, sizeof(ss->name), "vch%u audio", i);
|
||||
|
||||
return snd_pcm_lib_preallocate_pages_for_all(pcm,
|
||||
SNDRV_DMA_TYPE_DEV,
|
||||
snd_dma_pci_data(dev->pci_dev),
|
||||
TW686X_AUDIO_PAGE_MAX * TW686X_AUDIO_PAGE_SZ,
|
||||
TW686X_AUDIO_PAGE_MAX * TW686X_AUDIO_PAGE_SZ);
|
||||
}
|
||||
|
||||
static void tw686x_audio_dma_free(struct tw686x_dev *dev,
|
||||
struct tw686x_audio_channel *ac)
|
||||
{
|
||||
int pb;
|
||||
|
||||
for (pb = 0; pb < 2; pb++) {
|
||||
if (!ac->dma_descs[pb].virt)
|
||||
continue;
|
||||
pci_free_consistent(dev->pci_dev, ac->dma_descs[pb].size,
|
||||
ac->dma_descs[pb].virt,
|
||||
ac->dma_descs[pb].phys);
|
||||
ac->dma_descs[pb].virt = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int tw686x_audio_dma_alloc(struct tw686x_dev *dev,
|
||||
struct tw686x_audio_channel *ac)
|
||||
{
|
||||
int pb;
|
||||
|
||||
for (pb = 0; pb < 2; pb++) {
|
||||
u32 reg = pb ? ADMA_B_ADDR[ac->ch] : ADMA_P_ADDR[ac->ch];
|
||||
void *virt;
|
||||
|
||||
virt = pci_alloc_consistent(dev->pci_dev, TW686X_AUDIO_PAGE_SZ,
|
||||
&ac->dma_descs[pb].phys);
|
||||
if (!virt) {
|
||||
dev_err(&dev->pci_dev->dev,
|
||||
"dma%d: unable to allocate audio DMA %s-buffer\n",
|
||||
ac->ch, pb ? "B" : "P");
|
||||
return -ENOMEM;
|
||||
}
|
||||
ac->dma_descs[pb].virt = virt;
|
||||
ac->dma_descs[pb].size = TW686X_AUDIO_PAGE_SZ;
|
||||
reg_write(dev, reg, ac->dma_descs[pb].phys);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void tw686x_audio_free(struct tw686x_dev *dev)
|
||||
{
|
||||
unsigned long flags;
|
||||
u32 dma_ch_mask;
|
||||
u32 dma_cmd;
|
||||
|
||||
spin_lock_irqsave(&dev->lock, flags);
|
||||
dma_cmd = reg_read(dev, DMA_CMD);
|
||||
dma_ch_mask = reg_read(dev, DMA_CHANNEL_ENABLE);
|
||||
reg_write(dev, DMA_CMD, dma_cmd & ~0xff00);
|
||||
reg_write(dev, DMA_CHANNEL_ENABLE, dma_ch_mask & ~0xff00);
|
||||
spin_unlock_irqrestore(&dev->lock, flags);
|
||||
|
||||
if (!dev->snd_card)
|
||||
return;
|
||||
snd_card_free(dev->snd_card);
|
||||
dev->snd_card = NULL;
|
||||
}
|
||||
|
||||
int tw686x_audio_init(struct tw686x_dev *dev)
|
||||
{
|
||||
struct pci_dev *pci_dev = dev->pci_dev;
|
||||
struct snd_card *card;
|
||||
int err, ch;
|
||||
|
||||
/*
|
||||
* AUDIO_CONTROL1
|
||||
* DMA byte length [31:19] = 4096 (i.e. ALSA period)
|
||||
* External audio enable [0] = enabled
|
||||
*/
|
||||
reg_write(dev, AUDIO_CONTROL1, 0x80000001);
|
||||
|
||||
err = snd_card_new(&pci_dev->dev, SNDRV_DEFAULT_IDX1,
|
||||
SNDRV_DEFAULT_STR1,
|
||||
THIS_MODULE, 0, &card);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
dev->snd_card = card;
|
||||
strlcpy(card->driver, "tw686x", sizeof(card->driver));
|
||||
strlcpy(card->shortname, "tw686x", sizeof(card->shortname));
|
||||
strlcpy(card->longname, pci_name(pci_dev), sizeof(card->longname));
|
||||
snd_card_set_dev(card, &pci_dev->dev);
|
||||
|
||||
for (ch = 0; ch < max_channels(dev); ch++) {
|
||||
struct tw686x_audio_channel *ac;
|
||||
|
||||
ac = &dev->audio_channels[ch];
|
||||
spin_lock_init(&ac->lock);
|
||||
ac->dev = dev;
|
||||
ac->ch = ch;
|
||||
|
||||
err = tw686x_audio_dma_alloc(dev, ac);
|
||||
if (err < 0)
|
||||
goto err_cleanup;
|
||||
}
|
||||
|
||||
err = tw686x_snd_pcm_init(dev);
|
||||
if (err < 0)
|
||||
goto err_cleanup;
|
||||
|
||||
err = snd_card_register(card);
|
||||
if (!err)
|
||||
return 0;
|
||||
|
||||
err_cleanup:
|
||||
for (ch = 0; ch < max_channels(dev); ch++) {
|
||||
if (!dev->audio_channels[ch].dev)
|
||||
continue;
|
||||
tw686x_audio_dma_free(dev, &dev->audio_channels[ch]);
|
||||
}
|
||||
snd_card_free(card);
|
||||
dev->snd_card = NULL;
|
||||
return err;
|
||||
}
|
|
@ -0,0 +1,415 @@
|
|||
/*
|
||||
* Copyright (C) 2015 VanguardiaSur - www.vanguardiasur.com.ar
|
||||
*
|
||||
* Based on original driver by Krzysztof Ha?asa:
|
||||
* Copyright (C) 2015 Industrial Research Institute for Automation
|
||||
* and Measurements PIAP
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of version 2 of the GNU General Public License
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* Notes
|
||||
* -----
|
||||
*
|
||||
* 1. Under stress-testing, it has been observed that the PCIe link
|
||||
* goes down, without reason. Therefore, the driver takes special care
|
||||
* to allow device hot-unplugging.
|
||||
*
|
||||
* 2. TW686X devices are capable of setting a few different DMA modes,
|
||||
* including: scatter-gather, field and frame modes. However,
|
||||
* under stress testings it has been found that the machine can
|
||||
* freeze completely if DMA registers are programmed while streaming
|
||||
* is active.
|
||||
* This driver tries to access hardware registers as infrequently
|
||||
* as possible by:
|
||||
* i. allocating fixed DMA buffers and memcpy'ing into
|
||||
* vmalloc'ed buffers
|
||||
* ii. using a timer to mitigate the rate of DMA reset operations,
|
||||
* on DMA channels error.
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci_ids.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/timer.h>
|
||||
|
||||
#include "tw686x.h"
|
||||
#include "tw686x-regs.h"
|
||||
|
||||
/*
|
||||
* This module parameter allows to control the DMA_TIMER_INTERVAL value.
|
||||
* The DMA_TIMER_INTERVAL register controls the minimum DMA interrupt
|
||||
* time span (iow, the maximum DMA interrupt rate) thus allowing for
|
||||
* IRQ coalescing.
|
||||
*
|
||||
* The chip datasheet does not mention a time unit for this value, so
|
||||
* users wanting fine-grain control over the interrupt rate should
|
||||
* determine the desired value through testing.
|
||||
*/
|
||||
static u32 dma_interval = 0x00098968;
|
||||
module_param(dma_interval, int, 0444);
|
||||
MODULE_PARM_DESC(dma_interval, "Minimum time span for DMA interrupting host");
|
||||
|
||||
void tw686x_disable_channel(struct tw686x_dev *dev, unsigned int channel)
|
||||
{
|
||||
u32 dma_en = reg_read(dev, DMA_CHANNEL_ENABLE);
|
||||
u32 dma_cmd = reg_read(dev, DMA_CMD);
|
||||
|
||||
dma_en &= ~BIT(channel);
|
||||
dma_cmd &= ~BIT(channel);
|
||||
|
||||
/* Must remove it from pending too */
|
||||
dev->pending_dma_en &= ~BIT(channel);
|
||||
dev->pending_dma_cmd &= ~BIT(channel);
|
||||
|
||||
/* Stop DMA if no channels are enabled */
|
||||
if (!dma_en)
|
||||
dma_cmd = 0;
|
||||
reg_write(dev, DMA_CHANNEL_ENABLE, dma_en);
|
||||
reg_write(dev, DMA_CMD, dma_cmd);
|
||||
}
|
||||
|
||||
void tw686x_enable_channel(struct tw686x_dev *dev, unsigned int channel)
|
||||
{
|
||||
u32 dma_en = reg_read(dev, DMA_CHANNEL_ENABLE);
|
||||
u32 dma_cmd = reg_read(dev, DMA_CMD);
|
||||
|
||||
dev->pending_dma_en |= dma_en | BIT(channel);
|
||||
dev->pending_dma_cmd |= dma_cmd | DMA_CMD_ENABLE | BIT(channel);
|
||||
}
|
||||
|
||||
/*
|
||||
* The purpose of this awful hack is to avoid enabling the DMA
|
||||
* channels "too fast" which makes some TW686x devices very
|
||||
* angry and freeze the CPU (see note 1).
|
||||
*/
|
||||
static void tw686x_dma_delay(unsigned long data)
|
||||
{
|
||||
struct tw686x_dev *dev = (struct tw686x_dev *)data;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&dev->lock, flags);
|
||||
|
||||
reg_write(dev, DMA_CHANNEL_ENABLE, dev->pending_dma_en);
|
||||
reg_write(dev, DMA_CMD, dev->pending_dma_cmd);
|
||||
dev->pending_dma_en = 0;
|
||||
dev->pending_dma_cmd = 0;
|
||||
|
||||
spin_unlock_irqrestore(&dev->lock, flags);
|
||||
}
|
||||
|
||||
static void tw686x_reset_channels(struct tw686x_dev *dev, unsigned int ch_mask)
|
||||
{
|
||||
u32 dma_en, dma_cmd;
|
||||
|
||||
dma_en = reg_read(dev, DMA_CHANNEL_ENABLE);
|
||||
dma_cmd = reg_read(dev, DMA_CMD);
|
||||
|
||||
/*
|
||||
* Save pending register status, the timer will
|
||||
* restore them.
|
||||
*/
|
||||
dev->pending_dma_en |= dma_en;
|
||||
dev->pending_dma_cmd |= dma_cmd;
|
||||
|
||||
/* Disable the reset channels */
|
||||
reg_write(dev, DMA_CHANNEL_ENABLE, dma_en & ~ch_mask);
|
||||
|
||||
if ((dma_en & ~ch_mask) == 0) {
|
||||
dev_dbg(&dev->pci_dev->dev, "reset: stopping DMA\n");
|
||||
dma_cmd &= ~DMA_CMD_ENABLE;
|
||||
}
|
||||
reg_write(dev, DMA_CMD, dma_cmd & ~ch_mask);
|
||||
}
|
||||
|
||||
static irqreturn_t tw686x_irq(int irq, void *dev_id)
|
||||
{
|
||||
struct tw686x_dev *dev = (struct tw686x_dev *)dev_id;
|
||||
unsigned int video_requests, audio_requests, reset_ch;
|
||||
u32 fifo_status, fifo_signal, fifo_ov, fifo_bad, fifo_errors;
|
||||
u32 int_status, dma_en, video_en, pb_status;
|
||||
unsigned long flags;
|
||||
|
||||
int_status = reg_read(dev, INT_STATUS); /* cleared on read */
|
||||
fifo_status = reg_read(dev, VIDEO_FIFO_STATUS);
|
||||
|
||||
/* INT_STATUS does not include FIFO_STATUS errors! */
|
||||
if (!int_status && !TW686X_FIFO_ERROR(fifo_status))
|
||||
return IRQ_NONE;
|
||||
|
||||
if (int_status & INT_STATUS_DMA_TOUT) {
|
||||
dev_dbg(&dev->pci_dev->dev,
|
||||
"DMA timeout. Resetting DMA for all channels\n");
|
||||
reset_ch = ~0;
|
||||
goto reset_channels;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&dev->lock, flags);
|
||||
dma_en = reg_read(dev, DMA_CHANNEL_ENABLE);
|
||||
spin_unlock_irqrestore(&dev->lock, flags);
|
||||
|
||||
video_en = dma_en & 0xff;
|
||||
fifo_signal = ~(fifo_status & 0xff) & video_en;
|
||||
fifo_ov = fifo_status >> 24;
|
||||
fifo_bad = fifo_status >> 16;
|
||||
|
||||
/* Mask of channels with signal and FIFO errors */
|
||||
fifo_errors = fifo_signal & (fifo_ov | fifo_bad);
|
||||
|
||||
reset_ch = 0;
|
||||
pb_status = reg_read(dev, PB_STATUS);
|
||||
|
||||
/* Coalesce video frame/error events */
|
||||
video_requests = (int_status & video_en) | fifo_errors;
|
||||
audio_requests = (int_status & dma_en) >> 8;
|
||||
|
||||
if (video_requests)
|
||||
tw686x_video_irq(dev, video_requests, pb_status,
|
||||
fifo_status, &reset_ch);
|
||||
if (audio_requests)
|
||||
tw686x_audio_irq(dev, audio_requests, pb_status);
|
||||
|
||||
reset_channels:
|
||||
if (reset_ch) {
|
||||
spin_lock_irqsave(&dev->lock, flags);
|
||||
tw686x_reset_channels(dev, reset_ch);
|
||||
spin_unlock_irqrestore(&dev->lock, flags);
|
||||
mod_timer(&dev->dma_delay_timer,
|
||||
jiffies + msecs_to_jiffies(100));
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void tw686x_dev_release(struct v4l2_device *v4l2_dev)
|
||||
{
|
||||
struct tw686x_dev *dev = container_of(v4l2_dev, struct tw686x_dev,
|
||||
v4l2_dev);
|
||||
unsigned int ch;
|
||||
|
||||
for (ch = 0; ch < max_channels(dev); ch++)
|
||||
v4l2_ctrl_handler_free(&dev->video_channels[ch].ctrl_handler);
|
||||
|
||||
v4l2_device_unregister(&dev->v4l2_dev);
|
||||
|
||||
kfree(dev->audio_channels);
|
||||
kfree(dev->video_channels);
|
||||
kfree(dev);
|
||||
}
|
||||
|
||||
static int tw686x_probe(struct pci_dev *pci_dev,
|
||||
const struct pci_device_id *pci_id)
|
||||
{
|
||||
struct tw686x_dev *dev;
|
||||
int err;
|
||||
|
||||
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
|
||||
if (!dev)
|
||||
return -ENOMEM;
|
||||
dev->type = pci_id->driver_data;
|
||||
sprintf(dev->name, "tw%04X", pci_dev->device);
|
||||
|
||||
dev->video_channels = kcalloc(max_channels(dev),
|
||||
sizeof(*dev->video_channels), GFP_KERNEL);
|
||||
if (!dev->video_channels) {
|
||||
err = -ENOMEM;
|
||||
goto free_dev;
|
||||
}
|
||||
|
||||
dev->audio_channels = kcalloc(max_channels(dev),
|
||||
sizeof(*dev->audio_channels), GFP_KERNEL);
|
||||
if (!dev->audio_channels) {
|
||||
err = -ENOMEM;
|
||||
goto free_video;
|
||||
}
|
||||
|
||||
pr_info("%s: PCI %s, IRQ %d, MMIO 0x%lx\n", dev->name,
|
||||
pci_name(pci_dev), pci_dev->irq,
|
||||
(unsigned long)pci_resource_start(pci_dev, 0));
|
||||
|
||||
dev->pci_dev = pci_dev;
|
||||
if (pci_enable_device(pci_dev)) {
|
||||
err = -EIO;
|
||||
goto free_audio;
|
||||
}
|
||||
|
||||
pci_set_master(pci_dev);
|
||||
err = pci_set_dma_mask(pci_dev, DMA_BIT_MASK(32));
|
||||
if (err) {
|
||||
dev_err(&pci_dev->dev, "32-bit PCI DMA not supported\n");
|
||||
err = -EIO;
|
||||
goto disable_pci;
|
||||
}
|
||||
|
||||
err = pci_request_regions(pci_dev, dev->name);
|
||||
if (err) {
|
||||
dev_err(&pci_dev->dev, "unable to request PCI region\n");
|
||||
goto disable_pci;
|
||||
}
|
||||
|
||||
dev->mmio = pci_ioremap_bar(pci_dev, 0);
|
||||
if (!dev->mmio) {
|
||||
dev_err(&pci_dev->dev, "unable to remap PCI region\n");
|
||||
err = -ENOMEM;
|
||||
goto free_region;
|
||||
}
|
||||
|
||||
/* Reset all subsystems */
|
||||
reg_write(dev, SYS_SOFT_RST, 0x0f);
|
||||
mdelay(1);
|
||||
|
||||
reg_write(dev, SRST[0], 0x3f);
|
||||
if (max_channels(dev) > 4)
|
||||
reg_write(dev, SRST[1], 0x3f);
|
||||
|
||||
/* Disable the DMA engine */
|
||||
reg_write(dev, DMA_CMD, 0);
|
||||
reg_write(dev, DMA_CHANNEL_ENABLE, 0);
|
||||
|
||||
/* Enable DMA FIFO overflow and pointer check */
|
||||
reg_write(dev, DMA_CONFIG, 0xffffff04);
|
||||
reg_write(dev, DMA_CHANNEL_TIMEOUT, 0x140c8584);
|
||||
reg_write(dev, DMA_TIMER_INTERVAL, dma_interval);
|
||||
|
||||
spin_lock_init(&dev->lock);
|
||||
|
||||
err = request_irq(pci_dev->irq, tw686x_irq, IRQF_SHARED,
|
||||
dev->name, dev);
|
||||
if (err < 0) {
|
||||
dev_err(&pci_dev->dev, "unable to request interrupt\n");
|
||||
goto iounmap;
|
||||
}
|
||||
|
||||
setup_timer(&dev->dma_delay_timer,
|
||||
tw686x_dma_delay, (unsigned long) dev);
|
||||
|
||||
/*
|
||||
* This must be set right before initializing v4l2_dev.
|
||||
* It's used to release resources after the last handle
|
||||
* held is released.
|
||||
*/
|
||||
dev->v4l2_dev.release = tw686x_dev_release;
|
||||
err = tw686x_video_init(dev);
|
||||
if (err) {
|
||||
dev_err(&pci_dev->dev, "can't register video\n");
|
||||
goto free_irq;
|
||||
}
|
||||
|
||||
err = tw686x_audio_init(dev);
|
||||
if (err)
|
||||
dev_warn(&pci_dev->dev, "can't register audio\n");
|
||||
|
||||
pci_set_drvdata(pci_dev, dev);
|
||||
return 0;
|
||||
|
||||
free_irq:
|
||||
free_irq(pci_dev->irq, dev);
|
||||
iounmap:
|
||||
pci_iounmap(pci_dev, dev->mmio);
|
||||
free_region:
|
||||
pci_release_regions(pci_dev);
|
||||
disable_pci:
|
||||
pci_disable_device(pci_dev);
|
||||
free_audio:
|
||||
kfree(dev->audio_channels);
|
||||
free_video:
|
||||
kfree(dev->video_channels);
|
||||
free_dev:
|
||||
kfree(dev);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void tw686x_remove(struct pci_dev *pci_dev)
|
||||
{
|
||||
struct tw686x_dev *dev = pci_get_drvdata(pci_dev);
|
||||
unsigned long flags;
|
||||
|
||||
/* This guarantees the IRQ handler is no longer running,
|
||||
* which means we can kiss good-bye some resources.
|
||||
*/
|
||||
free_irq(pci_dev->irq, dev);
|
||||
|
||||
tw686x_video_free(dev);
|
||||
tw686x_audio_free(dev);
|
||||
del_timer_sync(&dev->dma_delay_timer);
|
||||
|
||||
pci_iounmap(pci_dev, dev->mmio);
|
||||
pci_release_regions(pci_dev);
|
||||
pci_disable_device(pci_dev);
|
||||
|
||||
/*
|
||||
* Setting pci_dev to NULL allows to detect hardware is no longer
|
||||
* available and will be used by vb2_ops. This is required because
|
||||
* the device sometimes hot-unplugs itself as the result of a PCIe
|
||||
* link down.
|
||||
* The lock is really important here.
|
||||
*/
|
||||
spin_lock_irqsave(&dev->lock, flags);
|
||||
dev->pci_dev = NULL;
|
||||
spin_unlock_irqrestore(&dev->lock, flags);
|
||||
|
||||
/*
|
||||
* This calls tw686x_dev_release if it's the last reference.
|
||||
* Otherwise, release is postponed until there are no users left.
|
||||
*/
|
||||
v4l2_device_put(&dev->v4l2_dev);
|
||||
}
|
||||
|
||||
/*
|
||||
* On TW6864 and TW6868, all channels share the pair of video DMA SG tables,
|
||||
* with 10-bit start_idx and end_idx determining start and end of frame buffer
|
||||
* for particular channel.
|
||||
* TW6868 with all its 8 channels would be problematic (only 127 SG entries per
|
||||
* channel) but we support only 4 channels on this chip anyway (the first
|
||||
* 4 channels are driven with internal video decoder, the other 4 would require
|
||||
* an external TW286x part).
|
||||
*
|
||||
* On TW6865 and TW6869, each channel has its own DMA SG table, with indexes
|
||||
* starting with 0. Both chips have complete sets of internal video decoders
|
||||
* (respectively 4 or 8-channel).
|
||||
*
|
||||
* All chips have separate SG tables for two video frames.
|
||||
*/
|
||||
|
||||
/* driver_data is number of A/V channels */
|
||||
static const struct pci_device_id tw686x_pci_tbl[] = {
|
||||
{
|
||||
PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, 0x6864),
|
||||
.driver_data = 4
|
||||
},
|
||||
{
|
||||
PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, 0x6865), /* not tested */
|
||||
.driver_data = 4 | TYPE_SECOND_GEN
|
||||
},
|
||||
/*
|
||||
* TW6868 supports 8 A/V channels with an external TW2865 chip;
|
||||
* not supported by the driver.
|
||||
*/
|
||||
{
|
||||
PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, 0x6868), /* not tested */
|
||||
.driver_data = 4
|
||||
},
|
||||
{
|
||||
PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, 0x6869),
|
||||
.driver_data = 8 | TYPE_SECOND_GEN},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, tw686x_pci_tbl);
|
||||
|
||||
static struct pci_driver tw686x_pci_driver = {
|
||||
.name = "tw686x",
|
||||
.id_table = tw686x_pci_tbl,
|
||||
.probe = tw686x_probe,
|
||||
.remove = tw686x_remove,
|
||||
};
|
||||
module_pci_driver(tw686x_pci_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Driver for video frame grabber cards based on Intersil/Techwell TW686[4589]");
|
||||
MODULE_AUTHOR("Ezequiel Garcia <ezequiel@vanguardiasur.com.ar>");
|
||||
MODULE_AUTHOR("Krzysztof Ha?asa <khalasa@piap.pl>");
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -0,0 +1,122 @@
|
|||
/* DMA controller registers */
|
||||
#define REG8_1(a0) ((const u16[8]) { a0, a0 + 1, a0 + 2, a0 + 3, \
|
||||
a0 + 4, a0 + 5, a0 + 6, a0 + 7})
|
||||
#define REG8_2(a0) ((const u16[8]) { a0, a0 + 2, a0 + 4, a0 + 6, \
|
||||
a0 + 8, a0 + 0xa, a0 + 0xc, a0 + 0xe})
|
||||
#define REG8_8(a0) ((const u16[8]) { a0, a0 + 8, a0 + 0x10, a0 + 0x18, \
|
||||
a0 + 0x20, a0 + 0x28, a0 + 0x30, \
|
||||
a0 + 0x38})
|
||||
#define INT_STATUS 0x00
|
||||
#define PB_STATUS 0x01
|
||||
#define DMA_CMD 0x02
|
||||
#define VIDEO_FIFO_STATUS 0x03
|
||||
#define VIDEO_CHANNEL_ID 0x04
|
||||
#define VIDEO_PARSER_STATUS 0x05
|
||||
#define SYS_SOFT_RST 0x06
|
||||
#define DMA_PAGE_TABLE0_ADDR ((const u16[8]) { 0x08, 0xd0, 0xd2, 0xd4, \
|
||||
0xd6, 0xd8, 0xda, 0xdc })
|
||||
#define DMA_PAGE_TABLE1_ADDR ((const u16[8]) { 0x09, 0xd1, 0xd3, 0xd5, \
|
||||
0xd7, 0xd9, 0xdb, 0xdd })
|
||||
#define DMA_CHANNEL_ENABLE 0x0a
|
||||
#define DMA_CONFIG 0x0b
|
||||
#define DMA_TIMER_INTERVAL 0x0c
|
||||
#define DMA_CHANNEL_TIMEOUT 0x0d
|
||||
#define VDMA_CHANNEL_CONFIG REG8_1(0x10)
|
||||
#define ADMA_P_ADDR REG8_2(0x18)
|
||||
#define ADMA_B_ADDR REG8_2(0x19)
|
||||
#define DMA10_P_ADDR 0x28
|
||||
#define DMA10_B_ADDR 0x29
|
||||
#define VIDEO_CONTROL1 0x2a
|
||||
#define VIDEO_CONTROL2 0x2b
|
||||
#define AUDIO_CONTROL1 0x2c
|
||||
#define AUDIO_CONTROL2 0x2d
|
||||
#define PHASE_REF 0x2e
|
||||
#define GPIO_REG 0x2f
|
||||
#define INTL_HBAR_CTRL REG8_1(0x30)
|
||||
#define AUDIO_CONTROL3 0x38
|
||||
#define VIDEO_FIELD_CTRL REG8_1(0x39)
|
||||
#define HSCALER_CTRL REG8_1(0x42)
|
||||
#define VIDEO_SIZE REG8_1(0x4A)
|
||||
#define VIDEO_SIZE_F2 REG8_1(0x52)
|
||||
#define MD_CONF REG8_1(0x60)
|
||||
#define MD_INIT REG8_1(0x68)
|
||||
#define MD_MAP0 REG8_1(0x70)
|
||||
#define VDMA_P_ADDR REG8_8(0x80) /* not used in DMA SG mode */
|
||||
#define VDMA_WHP REG8_8(0x81)
|
||||
#define VDMA_B_ADDR REG8_8(0x82)
|
||||
#define VDMA_F2_P_ADDR REG8_8(0x84)
|
||||
#define VDMA_F2_WHP REG8_8(0x85)
|
||||
#define VDMA_F2_B_ADDR REG8_8(0x86)
|
||||
#define EP_REG_ADDR 0xfe
|
||||
#define EP_REG_DATA 0xff
|
||||
|
||||
/* Video decoder registers */
|
||||
#define VDREG8(a0) ((const u16[8]) { \
|
||||
a0 + 0x000, a0 + 0x010, a0 + 0x020, a0 + 0x030, \
|
||||
a0 + 0x100, a0 + 0x110, a0 + 0x120, a0 + 0x130})
|
||||
#define VIDSTAT VDREG8(0x100)
|
||||
#define BRIGHT VDREG8(0x101)
|
||||
#define CONTRAST VDREG8(0x102)
|
||||
#define SHARPNESS VDREG8(0x103)
|
||||
#define SAT_U VDREG8(0x104)
|
||||
#define SAT_V VDREG8(0x105)
|
||||
#define HUE VDREG8(0x106)
|
||||
#define CROP_HI VDREG8(0x107)
|
||||
#define VDELAY_LO VDREG8(0x108)
|
||||
#define VACTIVE_LO VDREG8(0x109)
|
||||
#define HDELAY_LO VDREG8(0x10a)
|
||||
#define HACTIVE_LO VDREG8(0x10b)
|
||||
#define MVSN VDREG8(0x10c)
|
||||
#define STATUS2 VDREG8(0x10d)
|
||||
#define SDT VDREG8(0x10e)
|
||||
#define SDT_EN VDREG8(0x10f)
|
||||
|
||||
#define VSCALE_LO VDREG8(0x144)
|
||||
#define SCALE_HI VDREG8(0x145)
|
||||
#define HSCALE_LO VDREG8(0x146)
|
||||
#define F2CROP_HI VDREG8(0x147)
|
||||
#define F2VDELAY_LO VDREG8(0x148)
|
||||
#define F2VACTIVE_LO VDREG8(0x149)
|
||||
#define F2HDELAY_LO VDREG8(0x14a)
|
||||
#define F2HACTIVE_LO VDREG8(0x14b)
|
||||
#define F2VSCALE_LO VDREG8(0x14c)
|
||||
#define F2SCALE_HI VDREG8(0x14d)
|
||||
#define F2HSCALE_LO VDREG8(0x14e)
|
||||
#define F2CNT VDREG8(0x14f)
|
||||
|
||||
#define VDREG2(a0) ((const u16[2]) { a0, a0 + 0x100 })
|
||||
#define SRST VDREG2(0x180)
|
||||
#define ACNTL VDREG2(0x181)
|
||||
#define ACNTL2 VDREG2(0x182)
|
||||
#define CNTRL1 VDREG2(0x183)
|
||||
#define CKHY VDREG2(0x184)
|
||||
#define SHCOR VDREG2(0x185)
|
||||
#define CORING VDREG2(0x186)
|
||||
#define CLMPG VDREG2(0x187)
|
||||
#define IAGC VDREG2(0x188)
|
||||
#define VCTRL1 VDREG2(0x18f)
|
||||
#define MISC1 VDREG2(0x194)
|
||||
#define LOOP VDREG2(0x195)
|
||||
#define MISC2 VDREG2(0x196)
|
||||
|
||||
#define CLMD VDREG2(0x197)
|
||||
#define ANPWRDOWN VDREG2(0x1ce)
|
||||
#define AIGAIN ((const u16[8]) { 0x1d0, 0x1d1, 0x1d2, 0x1d3, \
|
||||
0x2d0, 0x2d1, 0x2d2, 0x2d3 })
|
||||
|
||||
#define SYS_MODE_DMA_SHIFT 13
|
||||
|
||||
#define DMA_CMD_ENABLE BIT(31)
|
||||
#define INT_STATUS_DMA_TOUT BIT(17)
|
||||
#define TW686X_VIDSTAT_HLOCK BIT(6)
|
||||
#define TW686X_VIDSTAT_VDLOSS BIT(7)
|
||||
|
||||
#define TW686X_STD_NTSC_M 0
|
||||
#define TW686X_STD_PAL 1
|
||||
#define TW686X_STD_SECAM 2
|
||||
#define TW686X_STD_NTSC_443 3
|
||||
#define TW686X_STD_PAL_M 4
|
||||
#define TW686X_STD_PAL_CN 5
|
||||
#define TW686X_STD_PAL_60 6
|
||||
|
||||
#define TW686X_FIFO_ERROR(x) (x & ~(0xff))
|
|
@ -0,0 +1,937 @@
|
|||
/*
|
||||
* Copyright (C) 2015 VanguardiaSur - www.vanguardiasur.com.ar
|
||||
*
|
||||
* Based on original driver by Krzysztof Ha?asa:
|
||||
* Copyright (C) 2015 Industrial Research Institute for Automation
|
||||
* and Measurements PIAP
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of version 2 of the GNU General Public License
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <media/v4l2-common.h>
|
||||
#include <media/v4l2-event.h>
|
||||
#include <media/videobuf2-vmalloc.h>
|
||||
#include "tw686x.h"
|
||||
#include "tw686x-regs.h"
|
||||
|
||||
#define TW686X_INPUTS_PER_CH 4
|
||||
#define TW686X_VIDEO_WIDTH 720
|
||||
#define TW686X_VIDEO_HEIGHT(id) ((id & V4L2_STD_525_60) ? 480 : 576)
|
||||
|
||||
static const struct tw686x_format formats[] = {
|
||||
{
|
||||
.fourcc = V4L2_PIX_FMT_UYVY,
|
||||
.mode = 0,
|
||||
.depth = 16,
|
||||
}, {
|
||||
.fourcc = V4L2_PIX_FMT_RGB565,
|
||||
.mode = 5,
|
||||
.depth = 16,
|
||||
}, {
|
||||
.fourcc = V4L2_PIX_FMT_YUYV,
|
||||
.mode = 6,
|
||||
.depth = 16,
|
||||
}
|
||||
};
|
||||
|
||||
static unsigned int tw686x_fields_map(v4l2_std_id std, unsigned int fps)
|
||||
{
|
||||
static const unsigned int map[15] = {
|
||||
0x00000000, 0x00000001, 0x00004001, 0x00104001, 0x00404041,
|
||||
0x01041041, 0x01104411, 0x01111111, 0x04444445, 0x04511445,
|
||||
0x05145145, 0x05151515, 0x05515455, 0x05551555, 0x05555555
|
||||
};
|
||||
|
||||
static const unsigned int std_625_50[26] = {
|
||||
0, 1, 1, 2, 3, 3, 4, 4, 5, 5, 6, 7, 7,
|
||||
8, 8, 9, 10, 10, 11, 11, 12, 13, 13, 14, 14, 0
|
||||
};
|
||||
|
||||
static const unsigned int std_525_60[31] = {
|
||||
0, 1, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7,
|
||||
8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 0, 0
|
||||
};
|
||||
|
||||
unsigned int i;
|
||||
|
||||
if (std & V4L2_STD_525_60) {
|
||||
if (fps >= ARRAY_SIZE(std_525_60))
|
||||
fps = 30;
|
||||
i = std_525_60[fps];
|
||||
} else {
|
||||
if (fps >= ARRAY_SIZE(std_625_50))
|
||||
fps = 25;
|
||||
i = std_625_50[fps];
|
||||
}
|
||||
|
||||
return map[i];
|
||||
}
|
||||
|
||||
static void tw686x_set_framerate(struct tw686x_video_channel *vc,
|
||||
unsigned int fps)
|
||||
{
|
||||
unsigned int map;
|
||||
|
||||
if (vc->fps == fps)
|
||||
return;
|
||||
|
||||
map = tw686x_fields_map(vc->video_standard, fps) << 1;
|
||||
map |= map << 1;
|
||||
if (map > 0)
|
||||
map |= BIT(31);
|
||||
reg_write(vc->dev, VIDEO_FIELD_CTRL[vc->ch], map);
|
||||
vc->fps = fps;
|
||||
}
|
||||
|
||||
static const struct tw686x_format *format_by_fourcc(unsigned int fourcc)
|
||||
{
|
||||
unsigned int cnt;
|
||||
|
||||
for (cnt = 0; cnt < ARRAY_SIZE(formats); cnt++)
|
||||
if (formats[cnt].fourcc == fourcc)
|
||||
return &formats[cnt];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int tw686x_queue_setup(struct vb2_queue *vq,
|
||||
unsigned int *nbuffers, unsigned int *nplanes,
|
||||
unsigned int sizes[], void *alloc_ctxs[])
|
||||
{
|
||||
struct tw686x_video_channel *vc = vb2_get_drv_priv(vq);
|
||||
unsigned int szimage =
|
||||
(vc->width * vc->height * vc->format->depth) >> 3;
|
||||
|
||||
/*
|
||||
* Let's request at least three buffers: two for the
|
||||
* DMA engine and one for userspace.
|
||||
*/
|
||||
if (vq->num_buffers + *nbuffers < 3)
|
||||
*nbuffers = 3 - vq->num_buffers;
|
||||
|
||||
if (*nplanes) {
|
||||
if (*nplanes != 1 || sizes[0] < szimage)
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
sizes[0] = szimage;
|
||||
*nplanes = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tw686x_buf_queue(struct vb2_buffer *vb)
|
||||
{
|
||||
struct tw686x_video_channel *vc = vb2_get_drv_priv(vb->vb2_queue);
|
||||
struct tw686x_dev *dev = vc->dev;
|
||||
struct pci_dev *pci_dev;
|
||||
unsigned long flags;
|
||||
struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
|
||||
struct tw686x_v4l2_buf *buf =
|
||||
container_of(vbuf, struct tw686x_v4l2_buf, vb);
|
||||
|
||||
/* Check device presence */
|
||||
spin_lock_irqsave(&dev->lock, flags);
|
||||
pci_dev = dev->pci_dev;
|
||||
spin_unlock_irqrestore(&dev->lock, flags);
|
||||
if (!pci_dev) {
|
||||
vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&vc->qlock, flags);
|
||||
list_add_tail(&buf->list, &vc->vidq_queued);
|
||||
spin_unlock_irqrestore(&vc->qlock, flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* We can call this even when alloc_dma failed for the given channel
|
||||
*/
|
||||
static void tw686x_free_dma(struct tw686x_video_channel *vc, unsigned int pb)
|
||||
{
|
||||
struct tw686x_dma_desc *desc = &vc->dma_descs[pb];
|
||||
struct tw686x_dev *dev = vc->dev;
|
||||
struct pci_dev *pci_dev;
|
||||
unsigned long flags;
|
||||
|
||||
/* Check device presence. Shouldn't really happen! */
|
||||
spin_lock_irqsave(&dev->lock, flags);
|
||||
pci_dev = dev->pci_dev;
|
||||
spin_unlock_irqrestore(&dev->lock, flags);
|
||||
if (!pci_dev) {
|
||||
WARN(1, "trying to deallocate on missing device\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (desc->virt) {
|
||||
pci_free_consistent(dev->pci_dev, desc->size,
|
||||
desc->virt, desc->phys);
|
||||
desc->virt = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int tw686x_alloc_dma(struct tw686x_video_channel *vc, unsigned int pb)
|
||||
{
|
||||
struct tw686x_dev *dev = vc->dev;
|
||||
u32 reg = pb ? VDMA_B_ADDR[vc->ch] : VDMA_P_ADDR[vc->ch];
|
||||
unsigned int len;
|
||||
void *virt;
|
||||
|
||||
WARN(vc->dma_descs[pb].virt,
|
||||
"Allocating buffer but previous still here\n");
|
||||
|
||||
len = (vc->width * vc->height * vc->format->depth) >> 3;
|
||||
virt = pci_alloc_consistent(dev->pci_dev, len,
|
||||
&vc->dma_descs[pb].phys);
|
||||
if (!virt) {
|
||||
v4l2_err(&dev->v4l2_dev,
|
||||
"dma%d: unable to allocate %s-buffer\n",
|
||||
vc->ch, pb ? "B" : "P");
|
||||
return -ENOMEM;
|
||||
}
|
||||
vc->dma_descs[pb].size = len;
|
||||
vc->dma_descs[pb].virt = virt;
|
||||
reg_write(dev, reg, vc->dma_descs[pb].phys);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tw686x_buffer_refill(struct tw686x_video_channel *vc,
|
||||
unsigned int pb)
|
||||
{
|
||||
struct tw686x_v4l2_buf *buf;
|
||||
|
||||
while (!list_empty(&vc->vidq_queued)) {
|
||||
|
||||
buf = list_first_entry(&vc->vidq_queued,
|
||||
struct tw686x_v4l2_buf, list);
|
||||
list_del(&buf->list);
|
||||
|
||||
vc->curr_bufs[pb] = buf;
|
||||
return;
|
||||
}
|
||||
vc->curr_bufs[pb] = NULL;
|
||||
}
|
||||
|
||||
static void tw686x_clear_queue(struct tw686x_video_channel *vc,
|
||||
enum vb2_buffer_state state)
|
||||
{
|
||||
unsigned int pb;
|
||||
|
||||
while (!list_empty(&vc->vidq_queued)) {
|
||||
struct tw686x_v4l2_buf *buf;
|
||||
|
||||
buf = list_first_entry(&vc->vidq_queued,
|
||||
struct tw686x_v4l2_buf, list);
|
||||
list_del(&buf->list);
|
||||
vb2_buffer_done(&buf->vb.vb2_buf, state);
|
||||
}
|
||||
|
||||
for (pb = 0; pb < 2; pb++) {
|
||||
if (vc->curr_bufs[pb])
|
||||
vb2_buffer_done(&vc->curr_bufs[pb]->vb.vb2_buf, state);
|
||||
vc->curr_bufs[pb] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int tw686x_start_streaming(struct vb2_queue *vq, unsigned int count)
|
||||
{
|
||||
struct tw686x_video_channel *vc = vb2_get_drv_priv(vq);
|
||||
struct tw686x_dev *dev = vc->dev;
|
||||
struct pci_dev *pci_dev;
|
||||
unsigned long flags;
|
||||
int pb, err;
|
||||
|
||||
/* Check device presence */
|
||||
spin_lock_irqsave(&dev->lock, flags);
|
||||
pci_dev = dev->pci_dev;
|
||||
spin_unlock_irqrestore(&dev->lock, flags);
|
||||
if (!pci_dev) {
|
||||
err = -ENODEV;
|
||||
goto err_clear_queue;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&vc->qlock, flags);
|
||||
|
||||
/* Sanity check */
|
||||
if (!vc->dma_descs[0].virt || !vc->dma_descs[1].virt) {
|
||||
spin_unlock_irqrestore(&vc->qlock, flags);
|
||||
v4l2_err(&dev->v4l2_dev,
|
||||
"video%d: refusing to start without DMA buffers\n",
|
||||
vc->num);
|
||||
err = -ENOMEM;
|
||||
goto err_clear_queue;
|
||||
}
|
||||
|
||||
for (pb = 0; pb < 2; pb++)
|
||||
tw686x_buffer_refill(vc, pb);
|
||||
spin_unlock_irqrestore(&vc->qlock, flags);
|
||||
|
||||
vc->sequence = 0;
|
||||
vc->pb = 0;
|
||||
|
||||
spin_lock_irqsave(&dev->lock, flags);
|
||||
tw686x_enable_channel(dev, vc->ch);
|
||||
spin_unlock_irqrestore(&dev->lock, flags);
|
||||
|
||||
mod_timer(&dev->dma_delay_timer, jiffies + msecs_to_jiffies(100));
|
||||
|
||||
return 0;
|
||||
|
||||
err_clear_queue:
|
||||
spin_lock_irqsave(&vc->qlock, flags);
|
||||
tw686x_clear_queue(vc, VB2_BUF_STATE_QUEUED);
|
||||
spin_unlock_irqrestore(&vc->qlock, flags);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void tw686x_stop_streaming(struct vb2_queue *vq)
|
||||
{
|
||||
struct tw686x_video_channel *vc = vb2_get_drv_priv(vq);
|
||||
struct tw686x_dev *dev = vc->dev;
|
||||
struct pci_dev *pci_dev;
|
||||
unsigned long flags;
|
||||
|
||||
/* Check device presence */
|
||||
spin_lock_irqsave(&dev->lock, flags);
|
||||
pci_dev = dev->pci_dev;
|
||||
spin_unlock_irqrestore(&dev->lock, flags);
|
||||
if (pci_dev)
|
||||
tw686x_disable_channel(dev, vc->ch);
|
||||
|
||||
spin_lock_irqsave(&vc->qlock, flags);
|
||||
tw686x_clear_queue(vc, VB2_BUF_STATE_ERROR);
|
||||
spin_unlock_irqrestore(&vc->qlock, flags);
|
||||
}
|
||||
|
||||
static int tw686x_buf_prepare(struct vb2_buffer *vb)
|
||||
{
|
||||
struct tw686x_video_channel *vc = vb2_get_drv_priv(vb->vb2_queue);
|
||||
unsigned int size =
|
||||
(vc->width * vc->height * vc->format->depth) >> 3;
|
||||
|
||||
if (vb2_plane_size(vb, 0) < size)
|
||||
return -EINVAL;
|
||||
vb2_set_plane_payload(vb, 0, size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct vb2_ops tw686x_video_qops = {
|
||||
.queue_setup = tw686x_queue_setup,
|
||||
.buf_queue = tw686x_buf_queue,
|
||||
.buf_prepare = tw686x_buf_prepare,
|
||||
.start_streaming = tw686x_start_streaming,
|
||||
.stop_streaming = tw686x_stop_streaming,
|
||||
.wait_prepare = vb2_ops_wait_prepare,
|
||||
.wait_finish = vb2_ops_wait_finish,
|
||||
};
|
||||
|
||||
static int tw686x_s_ctrl(struct v4l2_ctrl *ctrl)
|
||||
{
|
||||
struct tw686x_video_channel *vc;
|
||||
struct tw686x_dev *dev;
|
||||
unsigned int ch;
|
||||
|
||||
vc = container_of(ctrl->handler, struct tw686x_video_channel,
|
||||
ctrl_handler);
|
||||
dev = vc->dev;
|
||||
ch = vc->ch;
|
||||
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_BRIGHTNESS:
|
||||
reg_write(dev, BRIGHT[ch], ctrl->val & 0xff);
|
||||
return 0;
|
||||
|
||||
case V4L2_CID_CONTRAST:
|
||||
reg_write(dev, CONTRAST[ch], ctrl->val);
|
||||
return 0;
|
||||
|
||||
case V4L2_CID_SATURATION:
|
||||
reg_write(dev, SAT_U[ch], ctrl->val);
|
||||
reg_write(dev, SAT_V[ch], ctrl->val);
|
||||
return 0;
|
||||
|
||||
case V4L2_CID_HUE:
|
||||
reg_write(dev, HUE[ch], ctrl->val & 0xff);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static const struct v4l2_ctrl_ops ctrl_ops = {
|
||||
.s_ctrl = tw686x_s_ctrl,
|
||||
};
|
||||
|
||||
static int tw686x_g_fmt_vid_cap(struct file *file, void *priv,
|
||||
struct v4l2_format *f)
|
||||
{
|
||||
struct tw686x_video_channel *vc = video_drvdata(file);
|
||||
|
||||
f->fmt.pix.width = vc->width;
|
||||
f->fmt.pix.height = vc->height;
|
||||
f->fmt.pix.field = V4L2_FIELD_INTERLACED;
|
||||
f->fmt.pix.pixelformat = vc->format->fourcc;
|
||||
f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
|
||||
f->fmt.pix.bytesperline = (f->fmt.pix.width * vc->format->depth) / 8;
|
||||
f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tw686x_try_fmt_vid_cap(struct file *file, void *priv,
|
||||
struct v4l2_format *f)
|
||||
{
|
||||
struct tw686x_video_channel *vc = video_drvdata(file);
|
||||
unsigned int video_height = TW686X_VIDEO_HEIGHT(vc->video_standard);
|
||||
const struct tw686x_format *format;
|
||||
|
||||
format = format_by_fourcc(f->fmt.pix.pixelformat);
|
||||
if (!format) {
|
||||
format = &formats[0];
|
||||
f->fmt.pix.pixelformat = format->fourcc;
|
||||
}
|
||||
|
||||
if (f->fmt.pix.width <= TW686X_VIDEO_WIDTH / 2)
|
||||
f->fmt.pix.width = TW686X_VIDEO_WIDTH / 2;
|
||||
else
|
||||
f->fmt.pix.width = TW686X_VIDEO_WIDTH;
|
||||
|
||||
if (f->fmt.pix.height <= video_height / 2)
|
||||
f->fmt.pix.height = video_height / 2;
|
||||
else
|
||||
f->fmt.pix.height = video_height;
|
||||
|
||||
f->fmt.pix.bytesperline = (f->fmt.pix.width * format->depth) / 8;
|
||||
f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
|
||||
f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
|
||||
f->fmt.pix.field = V4L2_FIELD_INTERLACED;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tw686x_s_fmt_vid_cap(struct file *file, void *priv,
|
||||
struct v4l2_format *f)
|
||||
{
|
||||
struct tw686x_video_channel *vc = video_drvdata(file);
|
||||
u32 val, width, line_width, height;
|
||||
unsigned long bitsperframe;
|
||||
int err, pb;
|
||||
|
||||
if (vb2_is_busy(&vc->vidq))
|
||||
return -EBUSY;
|
||||
|
||||
bitsperframe = vc->width * vc->height * vc->format->depth;
|
||||
err = tw686x_try_fmt_vid_cap(file, priv, f);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
vc->format = format_by_fourcc(f->fmt.pix.pixelformat);
|
||||
vc->width = f->fmt.pix.width;
|
||||
vc->height = f->fmt.pix.height;
|
||||
|
||||
/* We need new DMA buffers if the framesize has changed */
|
||||
if (bitsperframe != vc->width * vc->height * vc->format->depth) {
|
||||
for (pb = 0; pb < 2; pb++)
|
||||
tw686x_free_dma(vc, pb);
|
||||
|
||||
for (pb = 0; pb < 2; pb++) {
|
||||
err = tw686x_alloc_dma(vc, pb);
|
||||
if (err) {
|
||||
if (pb > 0)
|
||||
tw686x_free_dma(vc, 0);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val = reg_read(vc->dev, VDMA_CHANNEL_CONFIG[vc->ch]);
|
||||
|
||||
if (vc->width <= TW686X_VIDEO_WIDTH / 2)
|
||||
val |= BIT(23);
|
||||
else
|
||||
val &= ~BIT(23);
|
||||
|
||||
if (vc->height <= TW686X_VIDEO_HEIGHT(vc->video_standard) / 2)
|
||||
val |= BIT(24);
|
||||
else
|
||||
val &= ~BIT(24);
|
||||
|
||||
val &= ~(0x7 << 20);
|
||||
val |= vc->format->mode << 20;
|
||||
reg_write(vc->dev, VDMA_CHANNEL_CONFIG[vc->ch], val);
|
||||
|
||||
/* Program the DMA frame size */
|
||||
width = (vc->width * 2) & 0x7ff;
|
||||
height = vc->height / 2;
|
||||
line_width = (vc->width * 2) & 0x7ff;
|
||||
val = (height << 22) | (line_width << 11) | width;
|
||||
reg_write(vc->dev, VDMA_WHP[vc->ch], val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tw686x_querycap(struct file *file, void *priv,
|
||||
struct v4l2_capability *cap)
|
||||
{
|
||||
struct tw686x_video_channel *vc = video_drvdata(file);
|
||||
struct tw686x_dev *dev = vc->dev;
|
||||
|
||||
strlcpy(cap->driver, "tw686x", sizeof(cap->driver));
|
||||
strlcpy(cap->card, dev->name, sizeof(cap->card));
|
||||
snprintf(cap->bus_info, sizeof(cap->bus_info),
|
||||
"PCI:%s", pci_name(dev->pci_dev));
|
||||
cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING |
|
||||
V4L2_CAP_READWRITE;
|
||||
cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tw686x_s_std(struct file *file, void *priv, v4l2_std_id id)
|
||||
{
|
||||
struct tw686x_video_channel *vc = video_drvdata(file);
|
||||
struct v4l2_format f;
|
||||
u32 val, ret;
|
||||
|
||||
if (vc->video_standard == id)
|
||||
return 0;
|
||||
|
||||
if (vb2_is_busy(&vc->vidq))
|
||||
return -EBUSY;
|
||||
|
||||
if (id & V4L2_STD_NTSC)
|
||||
val = 0;
|
||||
else if (id & V4L2_STD_PAL)
|
||||
val = 1;
|
||||
else if (id & V4L2_STD_SECAM)
|
||||
val = 2;
|
||||
else if (id & V4L2_STD_NTSC_443)
|
||||
val = 3;
|
||||
else if (id & V4L2_STD_PAL_M)
|
||||
val = 4;
|
||||
else if (id & V4L2_STD_PAL_Nc)
|
||||
val = 5;
|
||||
else if (id & V4L2_STD_PAL_60)
|
||||
val = 6;
|
||||
else
|
||||
return -EINVAL;
|
||||
|
||||
vc->video_standard = id;
|
||||
reg_write(vc->dev, SDT[vc->ch], val);
|
||||
|
||||
val = reg_read(vc->dev, VIDEO_CONTROL1);
|
||||
if (id & V4L2_STD_525_60)
|
||||
val &= ~(1 << (SYS_MODE_DMA_SHIFT + vc->ch));
|
||||
else
|
||||
val |= (1 << (SYS_MODE_DMA_SHIFT + vc->ch));
|
||||
reg_write(vc->dev, VIDEO_CONTROL1, val);
|
||||
|
||||
/*
|
||||
* Adjust format after V4L2_STD_525_60/V4L2_STD_625_50 change,
|
||||
* calling g_fmt and s_fmt will sanitize the height
|
||||
* according to the standard.
|
||||
*/
|
||||
ret = tw686x_g_fmt_vid_cap(file, priv, &f);
|
||||
if (!ret)
|
||||
tw686x_s_fmt_vid_cap(file, priv, &f);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tw686x_querystd(struct file *file, void *priv, v4l2_std_id *std)
|
||||
{
|
||||
struct tw686x_video_channel *vc = video_drvdata(file);
|
||||
struct tw686x_dev *dev = vc->dev;
|
||||
unsigned int old_std, detected_std = 0;
|
||||
unsigned long end;
|
||||
|
||||
if (vb2_is_streaming(&vc->vidq))
|
||||
return -EBUSY;
|
||||
|
||||
/* Enable and start standard detection */
|
||||
old_std = reg_read(dev, SDT[vc->ch]);
|
||||
reg_write(dev, SDT[vc->ch], 0x7);
|
||||
reg_write(dev, SDT_EN[vc->ch], 0xff);
|
||||
|
||||
end = jiffies + msecs_to_jiffies(500);
|
||||
while (time_is_after_jiffies(end)) {
|
||||
|
||||
detected_std = reg_read(dev, SDT[vc->ch]);
|
||||
if (!(detected_std & BIT(7)))
|
||||
break;
|
||||
msleep(100);
|
||||
}
|
||||
reg_write(dev, SDT[vc->ch], old_std);
|
||||
|
||||
/* Exit if still busy */
|
||||
if (detected_std & BIT(7))
|
||||
return 0;
|
||||
|
||||
detected_std = (detected_std >> 4) & 0x7;
|
||||
switch (detected_std) {
|
||||
case TW686X_STD_NTSC_M:
|
||||
*std &= V4L2_STD_NTSC;
|
||||
break;
|
||||
case TW686X_STD_NTSC_443:
|
||||
*std &= V4L2_STD_NTSC_443;
|
||||
break;
|
||||
case TW686X_STD_PAL_M:
|
||||
*std &= V4L2_STD_PAL_M;
|
||||
break;
|
||||
case TW686X_STD_PAL_60:
|
||||
*std &= V4L2_STD_PAL_60;
|
||||
break;
|
||||
case TW686X_STD_PAL:
|
||||
*std &= V4L2_STD_PAL;
|
||||
break;
|
||||
case TW686X_STD_PAL_CN:
|
||||
*std &= V4L2_STD_PAL_Nc;
|
||||
break;
|
||||
case TW686X_STD_SECAM:
|
||||
*std &= V4L2_STD_SECAM;
|
||||
break;
|
||||
default:
|
||||
*std = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tw686x_g_std(struct file *file, void *priv, v4l2_std_id *id)
|
||||
{
|
||||
struct tw686x_video_channel *vc = video_drvdata(file);
|
||||
|
||||
*id = vc->video_standard;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tw686x_enum_fmt_vid_cap(struct file *file, void *priv,
|
||||
struct v4l2_fmtdesc *f)
|
||||
{
|
||||
if (f->index >= ARRAY_SIZE(formats))
|
||||
return -EINVAL;
|
||||
f->pixelformat = formats[f->index].fourcc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tw686x_s_input(struct file *file, void *priv, unsigned int i)
|
||||
{
|
||||
struct tw686x_video_channel *vc = video_drvdata(file);
|
||||
u32 val;
|
||||
|
||||
if (i >= TW686X_INPUTS_PER_CH)
|
||||
return -EINVAL;
|
||||
if (i == vc->input)
|
||||
return 0;
|
||||
/*
|
||||
* Not sure we are able to support on the fly input change
|
||||
*/
|
||||
if (vb2_is_busy(&vc->vidq))
|
||||
return -EBUSY;
|
||||
|
||||
vc->input = i;
|
||||
|
||||
val = reg_read(vc->dev, VDMA_CHANNEL_CONFIG[vc->ch]);
|
||||
val &= ~(0x3 << 30);
|
||||
val |= i << 30;
|
||||
reg_write(vc->dev, VDMA_CHANNEL_CONFIG[vc->ch], val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tw686x_g_input(struct file *file, void *priv, unsigned int *i)
|
||||
{
|
||||
struct tw686x_video_channel *vc = video_drvdata(file);
|
||||
|
||||
*i = vc->input;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tw686x_enum_input(struct file *file, void *priv,
|
||||
struct v4l2_input *i)
|
||||
{
|
||||
struct tw686x_video_channel *vc = video_drvdata(file);
|
||||
unsigned int vidstat;
|
||||
|
||||
if (i->index >= TW686X_INPUTS_PER_CH)
|
||||
return -EINVAL;
|
||||
|
||||
snprintf(i->name, sizeof(i->name), "Composite%d", i->index);
|
||||
i->type = V4L2_INPUT_TYPE_CAMERA;
|
||||
i->std = vc->device->tvnorms;
|
||||
i->capabilities = V4L2_IN_CAP_STD;
|
||||
|
||||
vidstat = reg_read(vc->dev, VIDSTAT[vc->ch]);
|
||||
i->status = 0;
|
||||
if (vidstat & TW686X_VIDSTAT_VDLOSS)
|
||||
i->status |= V4L2_IN_ST_NO_SIGNAL;
|
||||
if (!(vidstat & TW686X_VIDSTAT_HLOCK))
|
||||
i->status |= V4L2_IN_ST_NO_H_LOCK;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct v4l2_file_operations tw686x_video_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = v4l2_fh_open,
|
||||
.unlocked_ioctl = video_ioctl2,
|
||||
.release = vb2_fop_release,
|
||||
.poll = vb2_fop_poll,
|
||||
.read = vb2_fop_read,
|
||||
.mmap = vb2_fop_mmap,
|
||||
};
|
||||
|
||||
static const struct v4l2_ioctl_ops tw686x_video_ioctl_ops = {
|
||||
.vidioc_querycap = tw686x_querycap,
|
||||
.vidioc_g_fmt_vid_cap = tw686x_g_fmt_vid_cap,
|
||||
.vidioc_s_fmt_vid_cap = tw686x_s_fmt_vid_cap,
|
||||
.vidioc_enum_fmt_vid_cap = tw686x_enum_fmt_vid_cap,
|
||||
.vidioc_try_fmt_vid_cap = tw686x_try_fmt_vid_cap,
|
||||
|
||||
.vidioc_querystd = tw686x_querystd,
|
||||
.vidioc_g_std = tw686x_g_std,
|
||||
.vidioc_s_std = tw686x_s_std,
|
||||
|
||||
.vidioc_enum_input = tw686x_enum_input,
|
||||
.vidioc_g_input = tw686x_g_input,
|
||||
.vidioc_s_input = tw686x_s_input,
|
||||
|
||||
.vidioc_reqbufs = vb2_ioctl_reqbufs,
|
||||
.vidioc_querybuf = vb2_ioctl_querybuf,
|
||||
.vidioc_qbuf = vb2_ioctl_qbuf,
|
||||
.vidioc_dqbuf = vb2_ioctl_dqbuf,
|
||||
.vidioc_create_bufs = vb2_ioctl_create_bufs,
|
||||
.vidioc_streamon = vb2_ioctl_streamon,
|
||||
.vidioc_streamoff = vb2_ioctl_streamoff,
|
||||
.vidioc_prepare_buf = vb2_ioctl_prepare_buf,
|
||||
|
||||
.vidioc_log_status = v4l2_ctrl_log_status,
|
||||
.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
|
||||
.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
|
||||
};
|
||||
|
||||
static void tw686x_buffer_copy(struct tw686x_video_channel *vc,
|
||||
unsigned int pb, struct vb2_v4l2_buffer *vb)
|
||||
{
|
||||
struct tw686x_dma_desc *desc = &vc->dma_descs[pb];
|
||||
struct vb2_buffer *vb2_buf = &vb->vb2_buf;
|
||||
|
||||
vb->field = V4L2_FIELD_INTERLACED;
|
||||
vb->sequence = vc->sequence++;
|
||||
|
||||
memcpy(vb2_plane_vaddr(vb2_buf, 0), desc->virt, desc->size);
|
||||
vb2_buf->timestamp = ktime_get_ns();
|
||||
vb2_buffer_done(vb2_buf, VB2_BUF_STATE_DONE);
|
||||
}
|
||||
|
||||
void tw686x_video_irq(struct tw686x_dev *dev, unsigned long requests,
|
||||
unsigned int pb_status, unsigned int fifo_status,
|
||||
unsigned int *reset_ch)
|
||||
{
|
||||
struct tw686x_video_channel *vc;
|
||||
struct vb2_v4l2_buffer *vb;
|
||||
unsigned long flags;
|
||||
unsigned int ch, pb;
|
||||
|
||||
for_each_set_bit(ch, &requests, max_channels(dev)) {
|
||||
vc = &dev->video_channels[ch];
|
||||
|
||||
/*
|
||||
* This can either be a blue frame (with signal-lost bit set)
|
||||
* or a good frame (with signal-lost bit clear). If we have just
|
||||
* got signal, then this channel needs resetting.
|
||||
*/
|
||||
if (vc->no_signal && !(fifo_status & BIT(ch))) {
|
||||
v4l2_printk(KERN_DEBUG, &dev->v4l2_dev,
|
||||
"video%d: signal recovered\n", vc->num);
|
||||
vc->no_signal = false;
|
||||
*reset_ch |= BIT(ch);
|
||||
vc->pb = 0;
|
||||
continue;
|
||||
}
|
||||
vc->no_signal = !!(fifo_status & BIT(ch));
|
||||
|
||||
/* Check FIFO errors only if there's signal */
|
||||
if (!vc->no_signal) {
|
||||
u32 fifo_ov, fifo_bad;
|
||||
|
||||
fifo_ov = (fifo_status >> 24) & BIT(ch);
|
||||
fifo_bad = (fifo_status >> 16) & BIT(ch);
|
||||
if (fifo_ov || fifo_bad) {
|
||||
/* Mark this channel for reset */
|
||||
v4l2_printk(KERN_DEBUG, &dev->v4l2_dev,
|
||||
"video%d: FIFO error\n", vc->num);
|
||||
*reset_ch |= BIT(ch);
|
||||
vc->pb = 0;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
pb = !!(pb_status & BIT(ch));
|
||||
if (vc->pb != pb) {
|
||||
/* Mark this channel for reset */
|
||||
v4l2_printk(KERN_DEBUG, &dev->v4l2_dev,
|
||||
"video%d: unexpected p-b buffer!\n",
|
||||
vc->num);
|
||||
*reset_ch |= BIT(ch);
|
||||
vc->pb = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* handle video stream */
|
||||
spin_lock_irqsave(&vc->qlock, flags);
|
||||
if (vc->curr_bufs[pb]) {
|
||||
vb = &vc->curr_bufs[pb]->vb;
|
||||
tw686x_buffer_copy(vc, pb, vb);
|
||||
}
|
||||
vc->pb = !pb;
|
||||
tw686x_buffer_refill(vc, pb);
|
||||
spin_unlock_irqrestore(&vc->qlock, flags);
|
||||
}
|
||||
}
|
||||
|
||||
void tw686x_video_free(struct tw686x_dev *dev)
|
||||
{
|
||||
unsigned int ch, pb;
|
||||
|
||||
for (ch = 0; ch < max_channels(dev); ch++) {
|
||||
struct tw686x_video_channel *vc = &dev->video_channels[ch];
|
||||
|
||||
if (vc->device)
|
||||
video_unregister_device(vc->device);
|
||||
|
||||
for (pb = 0; pb < 2; pb++)
|
||||
tw686x_free_dma(vc, pb);
|
||||
}
|
||||
}
|
||||
|
||||
int tw686x_video_init(struct tw686x_dev *dev)
|
||||
{
|
||||
unsigned int ch, val, pb;
|
||||
int err;
|
||||
|
||||
err = v4l2_device_register(&dev->pci_dev->dev, &dev->v4l2_dev);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
for (ch = 0; ch < max_channels(dev); ch++) {
|
||||
struct tw686x_video_channel *vc = &dev->video_channels[ch];
|
||||
struct video_device *vdev;
|
||||
|
||||
mutex_init(&vc->vb_mutex);
|
||||
spin_lock_init(&vc->qlock);
|
||||
INIT_LIST_HEAD(&vc->vidq_queued);
|
||||
|
||||
vc->dev = dev;
|
||||
vc->ch = ch;
|
||||
|
||||
/* default settings */
|
||||
vc->format = &formats[0];
|
||||
vc->video_standard = V4L2_STD_NTSC;
|
||||
vc->width = TW686X_VIDEO_WIDTH;
|
||||
vc->height = TW686X_VIDEO_HEIGHT(vc->video_standard);
|
||||
vc->input = 0;
|
||||
|
||||
reg_write(vc->dev, SDT[ch], 0);
|
||||
tw686x_set_framerate(vc, 30);
|
||||
|
||||
reg_write(dev, VDELAY_LO[ch], 0x14);
|
||||
reg_write(dev, HACTIVE_LO[ch], 0xd0);
|
||||
reg_write(dev, VIDEO_SIZE[ch], 0);
|
||||
|
||||
for (pb = 0; pb < 2; pb++) {
|
||||
err = tw686x_alloc_dma(vc, pb);
|
||||
if (err)
|
||||
goto error;
|
||||
}
|
||||
|
||||
vc->vidq.io_modes = VB2_READ | VB2_MMAP | VB2_DMABUF;
|
||||
vc->vidq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
vc->vidq.drv_priv = vc;
|
||||
vc->vidq.buf_struct_size = sizeof(struct tw686x_v4l2_buf);
|
||||
vc->vidq.ops = &tw686x_video_qops;
|
||||
vc->vidq.mem_ops = &vb2_vmalloc_memops;
|
||||
vc->vidq.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
|
||||
vc->vidq.min_buffers_needed = 2;
|
||||
vc->vidq.lock = &vc->vb_mutex;
|
||||
vc->vidq.gfp_flags = GFP_DMA32;
|
||||
|
||||
err = vb2_queue_init(&vc->vidq);
|
||||
if (err) {
|
||||
v4l2_err(&dev->v4l2_dev,
|
||||
"dma%d: cannot init vb2 queue\n", ch);
|
||||
goto error;
|
||||
}
|
||||
|
||||
err = v4l2_ctrl_handler_init(&vc->ctrl_handler, 4);
|
||||
if (err) {
|
||||
v4l2_err(&dev->v4l2_dev,
|
||||
"dma%d: cannot init ctrl handler\n", ch);
|
||||
goto error;
|
||||
}
|
||||
v4l2_ctrl_new_std(&vc->ctrl_handler, &ctrl_ops,
|
||||
V4L2_CID_BRIGHTNESS, -128, 127, 1, 0);
|
||||
v4l2_ctrl_new_std(&vc->ctrl_handler, &ctrl_ops,
|
||||
V4L2_CID_CONTRAST, 0, 255, 1, 100);
|
||||
v4l2_ctrl_new_std(&vc->ctrl_handler, &ctrl_ops,
|
||||
V4L2_CID_SATURATION, 0, 255, 1, 128);
|
||||
v4l2_ctrl_new_std(&vc->ctrl_handler, &ctrl_ops,
|
||||
V4L2_CID_HUE, -128, 127, 1, 0);
|
||||
err = vc->ctrl_handler.error;
|
||||
if (err)
|
||||
goto error;
|
||||
|
||||
err = v4l2_ctrl_handler_setup(&vc->ctrl_handler);
|
||||
if (err)
|
||||
goto error;
|
||||
|
||||
vdev = video_device_alloc();
|
||||
if (!vdev) {
|
||||
v4l2_err(&dev->v4l2_dev,
|
||||
"dma%d: unable to allocate device\n", ch);
|
||||
err = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
|
||||
snprintf(vdev->name, sizeof(vdev->name), "%s video", dev->name);
|
||||
vdev->fops = &tw686x_video_fops;
|
||||
vdev->ioctl_ops = &tw686x_video_ioctl_ops;
|
||||
vdev->release = video_device_release;
|
||||
vdev->v4l2_dev = &dev->v4l2_dev;
|
||||
vdev->queue = &vc->vidq;
|
||||
vdev->tvnorms = V4L2_STD_525_60 | V4L2_STD_625_50;
|
||||
vdev->minor = -1;
|
||||
vdev->lock = &vc->vb_mutex;
|
||||
vdev->ctrl_handler = &vc->ctrl_handler;
|
||||
vc->device = vdev;
|
||||
video_set_drvdata(vdev, vc);
|
||||
|
||||
err = video_register_device(vdev, VFL_TYPE_GRABBER, -1);
|
||||
if (err < 0)
|
||||
goto error;
|
||||
vc->num = vdev->num;
|
||||
}
|
||||
|
||||
/* Set DMA frame mode on all channels. Only supported mode for now. */
|
||||
val = TW686X_DEF_PHASE_REF;
|
||||
for (ch = 0; ch < max_channels(dev); ch++)
|
||||
val |= TW686X_FRAME_MODE << (16 + ch * 2);
|
||||
reg_write(dev, PHASE_REF, val);
|
||||
|
||||
reg_write(dev, MISC2[0], 0xe7);
|
||||
reg_write(dev, VCTRL1[0], 0xcc);
|
||||
reg_write(dev, LOOP[0], 0xa5);
|
||||
if (max_channels(dev) > 4) {
|
||||
reg_write(dev, VCTRL1[1], 0xcc);
|
||||
reg_write(dev, LOOP[1], 0xa5);
|
||||
reg_write(dev, MISC2[1], 0xe7);
|
||||
}
|
||||
return 0;
|
||||
|
||||
error:
|
||||
tw686x_video_free(dev);
|
||||
return err;
|
||||
}
|
|
@ -0,0 +1,158 @@
|
|||
/*
|
||||
* Copyright (C) 2015 VanguardiaSur - www.vanguardiasur.com.ar
|
||||
*
|
||||
* Copyright (C) 2015 Industrial Research Institute for Automation
|
||||
* and Measurements PIAP
|
||||
* Written by Krzysztof Ha?asa
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of version 2 of the GNU General Public License
|
||||
* as published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/videodev2.h>
|
||||
#include <media/v4l2-common.h>
|
||||
#include <media/v4l2-ctrls.h>
|
||||
#include <media/v4l2-device.h>
|
||||
#include <media/v4l2-ioctl.h>
|
||||
#include <media/videobuf2-v4l2.h>
|
||||
#include <sound/pcm.h>
|
||||
|
||||
#include "tw686x-regs.h"
|
||||
|
||||
#define TYPE_MAX_CHANNELS 0x0f
|
||||
#define TYPE_SECOND_GEN 0x10
|
||||
#define TW686X_DEF_PHASE_REF 0x1518
|
||||
|
||||
#define TW686X_FIELD_MODE 0x3
|
||||
#define TW686X_FRAME_MODE 0x2
|
||||
/* 0x1 is reserved */
|
||||
#define TW686X_SG_MODE 0x0
|
||||
|
||||
#define TW686X_AUDIO_PAGE_SZ 4096
|
||||
#define TW686X_AUDIO_PAGE_MAX 16
|
||||
#define TW686X_AUDIO_PERIODS_MIN 2
|
||||
#define TW686X_AUDIO_PERIODS_MAX TW686X_AUDIO_PAGE_MAX
|
||||
|
||||
struct tw686x_format {
|
||||
char *name;
|
||||
unsigned int fourcc;
|
||||
unsigned int depth;
|
||||
unsigned int mode;
|
||||
};
|
||||
|
||||
struct tw686x_dma_desc {
|
||||
dma_addr_t phys;
|
||||
void *virt;
|
||||
unsigned int size;
|
||||
};
|
||||
|
||||
struct tw686x_audio_buf {
|
||||
dma_addr_t dma;
|
||||
void *virt;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
struct tw686x_v4l2_buf {
|
||||
struct vb2_v4l2_buffer vb;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
struct tw686x_audio_channel {
|
||||
struct tw686x_dev *dev;
|
||||
struct snd_pcm_substream *ss;
|
||||
unsigned int ch;
|
||||
struct tw686x_audio_buf *curr_bufs[2];
|
||||
struct tw686x_dma_desc dma_descs[2];
|
||||
dma_addr_t ptr;
|
||||
|
||||
struct tw686x_audio_buf buf[TW686X_AUDIO_PAGE_MAX];
|
||||
struct list_head buf_list;
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
||||
struct tw686x_video_channel {
|
||||
struct tw686x_dev *dev;
|
||||
|
||||
struct vb2_queue vidq;
|
||||
struct list_head vidq_queued;
|
||||
struct video_device *device;
|
||||
struct tw686x_v4l2_buf *curr_bufs[2];
|
||||
struct tw686x_dma_desc dma_descs[2];
|
||||
|
||||
struct v4l2_ctrl_handler ctrl_handler;
|
||||
const struct tw686x_format *format;
|
||||
struct mutex vb_mutex;
|
||||
spinlock_t qlock;
|
||||
v4l2_std_id video_standard;
|
||||
unsigned int width, height;
|
||||
unsigned int h_halve, v_halve;
|
||||
unsigned int ch;
|
||||
unsigned int num;
|
||||
unsigned int fps;
|
||||
unsigned int input;
|
||||
unsigned int sequence;
|
||||
unsigned int pb;
|
||||
bool no_signal;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct tw686x_dev - global device status
|
||||
* @lock: spinlock controlling access to the
|
||||
* shared device registers (DMA enable/disable).
|
||||
*/
|
||||
struct tw686x_dev {
|
||||
spinlock_t lock;
|
||||
|
||||
struct v4l2_device v4l2_dev;
|
||||
struct snd_card *snd_card;
|
||||
|
||||
char name[32];
|
||||
unsigned int type;
|
||||
struct pci_dev *pci_dev;
|
||||
__u32 __iomem *mmio;
|
||||
|
||||
void *alloc_ctx;
|
||||
|
||||
struct tw686x_video_channel *video_channels;
|
||||
struct tw686x_audio_channel *audio_channels;
|
||||
|
||||
int audio_rate; /* per-device value */
|
||||
|
||||
struct timer_list dma_delay_timer;
|
||||
u32 pending_dma_en; /* must be protected by lock */
|
||||
u32 pending_dma_cmd; /* must be protected by lock */
|
||||
};
|
||||
|
||||
static inline uint32_t reg_read(struct tw686x_dev *dev, unsigned int reg)
|
||||
{
|
||||
return readl(dev->mmio + reg);
|
||||
}
|
||||
|
||||
static inline void reg_write(struct tw686x_dev *dev, unsigned int reg,
|
||||
uint32_t value)
|
||||
{
|
||||
writel(value, dev->mmio + reg);
|
||||
}
|
||||
|
||||
static inline unsigned int max_channels(struct tw686x_dev *dev)
|
||||
{
|
||||
return dev->type & TYPE_MAX_CHANNELS; /* 4 or 8 channels */
|
||||
}
|
||||
|
||||
void tw686x_enable_channel(struct tw686x_dev *dev, unsigned int channel);
|
||||
void tw686x_disable_channel(struct tw686x_dev *dev, unsigned int channel);
|
||||
|
||||
int tw686x_video_init(struct tw686x_dev *dev);
|
||||
void tw686x_video_free(struct tw686x_dev *dev);
|
||||
void tw686x_video_irq(struct tw686x_dev *dev, unsigned long requests,
|
||||
unsigned int pb_status, unsigned int fifo_status,
|
||||
unsigned int *reset_ch);
|
||||
|
||||
int tw686x_audio_init(struct tw686x_dev *dev);
|
||||
void tw686x_audio_free(struct tw686x_dev *dev);
|
||||
void tw686x_audio_irq(struct tw686x_dev *dev, unsigned long requests,
|
||||
unsigned int pb_status);
|
|
@ -116,8 +116,9 @@ videocodec_attach (struct videocodec_master *master)
|
|||
goto out_module_put;
|
||||
}
|
||||
|
||||
snprintf(codec->name, sizeof(codec->name),
|
||||
"%s[%d]", codec->name, h->attached);
|
||||
res = strlen(codec->name);
|
||||
snprintf(codec->name + res, sizeof(codec->name) - res,
|
||||
"[%d]", h->attached);
|
||||
codec->master_data = master;
|
||||
res = codec->setup(codec);
|
||||
if (res == 0) {
|
||||
|
|
|
@ -238,7 +238,7 @@ config VIDEO_SH_VEU
|
|||
config VIDEO_RENESAS_JPU
|
||||
tristate "Renesas JPEG Processing Unit"
|
||||
depends on VIDEO_DEV && VIDEO_V4L2 && HAS_DMA
|
||||
depends on ARCH_SHMOBILE || COMPILE_TEST
|
||||
depends on ARCH_RENESAS || COMPILE_TEST
|
||||
select VIDEOBUF2_DMA_CONTIG
|
||||
select V4L2_MEM2MEM_DEV
|
||||
---help---
|
||||
|
@ -250,7 +250,7 @@ config VIDEO_RENESAS_JPU
|
|||
config VIDEO_RENESAS_VSP1
|
||||
tristate "Renesas VSP1 Video Processing Engine"
|
||||
depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && HAS_DMA
|
||||
depends on (ARCH_SHMOBILE && OF) || COMPILE_TEST
|
||||
depends on (ARCH_RENESAS && OF) || COMPILE_TEST
|
||||
select VIDEOBUF2_DMA_CONTIG
|
||||
---help---
|
||||
This is a V4L2 driver for the Renesas VSP1 video processing engine.
|
||||
|
|
|
@ -1047,7 +1047,7 @@ static int vpfe_get_ccdc_image_format(struct vpfe_device *vpfe,
|
|||
static int vpfe_config_ccdc_image_format(struct vpfe_device *vpfe)
|
||||
{
|
||||
enum ccdc_frmfmt frm_fmt = CCDC_FRMFMT_INTERLACED;
|
||||
int ret;
|
||||
int ret = 0;
|
||||
|
||||
vpfe_dbg(2, vpfe, "vpfe_config_ccdc_image_format\n");
|
||||
|
||||
|
@ -1706,7 +1706,7 @@ static int vpfe_get_app_input_index(struct vpfe_device *vpfe,
|
|||
sdinfo = &cfg->sub_devs[i];
|
||||
client = v4l2_get_subdevdata(sdinfo->sd);
|
||||
if (client->addr == curr_client->addr &&
|
||||
client->adapter->nr == client->adapter->nr) {
|
||||
client->adapter->nr == curr_client->adapter->nr) {
|
||||
if (vpfe->current_input >= 1)
|
||||
return -1;
|
||||
*app_input_index = j + vpfe->current_input;
|
||||
|
|
|
@ -967,15 +967,6 @@ static struct gsc_driverdata gsc_v_100_drvdata = {
|
|||
.lclk_frequency = 266000000UL,
|
||||
};
|
||||
|
||||
static const struct platform_device_id gsc_driver_ids[] = {
|
||||
{
|
||||
.name = "exynos-gsc",
|
||||
.driver_data = (unsigned long)&gsc_v_100_drvdata,
|
||||
},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, gsc_driver_ids);
|
||||
|
||||
static const struct of_device_id exynos_gsc_match[] = {
|
||||
{
|
||||
.compatible = "samsung,exynos5-gsc",
|
||||
|
@ -988,17 +979,11 @@ MODULE_DEVICE_TABLE(of, exynos_gsc_match);
|
|||
static void *gsc_get_drv_data(struct platform_device *pdev)
|
||||
{
|
||||
struct gsc_driverdata *driver_data = NULL;
|
||||
const struct of_device_id *match;
|
||||
|
||||
if (pdev->dev.of_node) {
|
||||
const struct of_device_id *match;
|
||||
match = of_match_node(exynos_gsc_match,
|
||||
pdev->dev.of_node);
|
||||
if (match)
|
||||
driver_data = (struct gsc_driverdata *)match->data;
|
||||
} else {
|
||||
driver_data = (struct gsc_driverdata *)
|
||||
platform_get_device_id(pdev)->driver_data;
|
||||
}
|
||||
match = of_match_node(exynos_gsc_match, pdev->dev.of_node);
|
||||
if (match)
|
||||
driver_data = (struct gsc_driverdata *)match->data;
|
||||
|
||||
return driver_data;
|
||||
}
|
||||
|
@ -1078,17 +1063,17 @@ static int gsc_probe(struct platform_device *pdev)
|
|||
struct resource *res;
|
||||
struct gsc_driverdata *drv_data = gsc_get_drv_data(pdev);
|
||||
struct device *dev = &pdev->dev;
|
||||
int ret = 0;
|
||||
int ret;
|
||||
|
||||
gsc = devm_kzalloc(dev, sizeof(struct gsc_dev), GFP_KERNEL);
|
||||
if (!gsc)
|
||||
return -ENOMEM;
|
||||
|
||||
if (dev->of_node)
|
||||
gsc->id = of_alias_get_id(pdev->dev.of_node, "gsc");
|
||||
else
|
||||
gsc->id = pdev->id;
|
||||
ret = of_alias_get_id(pdev->dev.of_node, "gsc");
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
gsc->id = ret;
|
||||
if (gsc->id >= drv_data->num_entities) {
|
||||
dev_err(dev, "Invalid platform device id: %d\n", gsc->id);
|
||||
return -EINVAL;
|
||||
|
@ -1096,7 +1081,6 @@ static int gsc_probe(struct platform_device *pdev)
|
|||
|
||||
gsc->variant = drv_data->variant[gsc->id];
|
||||
gsc->pdev = pdev;
|
||||
gsc->pdata = dev->platform_data;
|
||||
|
||||
init_waitqueue_head(&gsc->irq_queue);
|
||||
spin_lock_init(&gsc->slock);
|
||||
|
@ -1253,7 +1237,6 @@ static const struct dev_pm_ops gsc_pm_ops = {
|
|||
static struct platform_driver gsc_driver = {
|
||||
.probe = gsc_probe,
|
||||
.remove = gsc_remove,
|
||||
.id_table = gsc_driver_ids,
|
||||
.driver = {
|
||||
.name = GSC_MODULE_NAME,
|
||||
.pm = &gsc_pm_ops,
|
||||
|
|
|
@ -340,7 +340,6 @@ struct gsc_dev {
|
|||
void __iomem *regs;
|
||||
wait_queue_head_t irq_queue;
|
||||
struct gsc_m2m_device m2m;
|
||||
struct exynos_platform_gscaler *pdata;
|
||||
unsigned long state;
|
||||
struct vb2_alloc_ctx *alloc_ctx;
|
||||
struct video_device vdev;
|
||||
|
|
|
@ -1154,26 +1154,6 @@ static const struct fimc_pix_limit s5p_pix_limit[4] = {
|
|||
},
|
||||
};
|
||||
|
||||
static const struct fimc_variant fimc0_variant_s5p = {
|
||||
.has_inp_rot = 1,
|
||||
.has_out_rot = 1,
|
||||
.has_cam_if = 1,
|
||||
.min_inp_pixsize = 16,
|
||||
.min_out_pixsize = 16,
|
||||
.hor_offs_align = 8,
|
||||
.min_vsize_align = 16,
|
||||
.pix_limit = &s5p_pix_limit[0],
|
||||
};
|
||||
|
||||
static const struct fimc_variant fimc2_variant_s5p = {
|
||||
.has_cam_if = 1,
|
||||
.min_inp_pixsize = 16,
|
||||
.min_out_pixsize = 16,
|
||||
.hor_offs_align = 8,
|
||||
.min_vsize_align = 16,
|
||||
.pix_limit = &s5p_pix_limit[1],
|
||||
};
|
||||
|
||||
static const struct fimc_variant fimc0_variant_s5pv210 = {
|
||||
.has_inp_rot = 1,
|
||||
.has_out_rot = 1,
|
||||
|
@ -1206,18 +1186,6 @@ static const struct fimc_variant fimc2_variant_s5pv210 = {
|
|||
.pix_limit = &s5p_pix_limit[2],
|
||||
};
|
||||
|
||||
/* S5PC100 */
|
||||
static const struct fimc_drvdata fimc_drvdata_s5p = {
|
||||
.variant = {
|
||||
[0] = &fimc0_variant_s5p,
|
||||
[1] = &fimc0_variant_s5p,
|
||||
[2] = &fimc2_variant_s5p,
|
||||
},
|
||||
.num_entities = 3,
|
||||
.lclk_frequency = 133000000UL,
|
||||
.out_buf_count = 4,
|
||||
};
|
||||
|
||||
/* S5PV210, S5PC110 */
|
||||
static const struct fimc_drvdata fimc_drvdata_s5pv210 = {
|
||||
.variant = {
|
||||
|
@ -1251,23 +1219,6 @@ static const struct fimc_drvdata fimc_drvdata_exynos4x12 = {
|
|||
.out_buf_count = 32,
|
||||
};
|
||||
|
||||
static const struct platform_device_id fimc_driver_ids[] = {
|
||||
{
|
||||
.name = "s5p-fimc",
|
||||
.driver_data = (unsigned long)&fimc_drvdata_s5p,
|
||||
}, {
|
||||
.name = "s5pv210-fimc",
|
||||
.driver_data = (unsigned long)&fimc_drvdata_s5pv210,
|
||||
}, {
|
||||
.name = "exynos4-fimc",
|
||||
.driver_data = (unsigned long)&fimc_drvdata_exynos4210,
|
||||
}, {
|
||||
.name = "exynos4x12-fimc",
|
||||
.driver_data = (unsigned long)&fimc_drvdata_exynos4x12,
|
||||
},
|
||||
{ },
|
||||
};
|
||||
|
||||
static const struct of_device_id fimc_of_match[] = {
|
||||
{
|
||||
.compatible = "samsung,s5pv210-fimc",
|
||||
|
@ -1290,7 +1241,6 @@ static const struct dev_pm_ops fimc_pm_ops = {
|
|||
static struct platform_driver fimc_driver = {
|
||||
.probe = fimc_probe,
|
||||
.remove = fimc_remove,
|
||||
.id_table = fimc_driver_ids,
|
||||
.driver = {
|
||||
.of_match_table = fimc_of_match,
|
||||
.name = FIMC_DRIVER_NAME,
|
||||
|
|
|
@ -446,8 +446,10 @@ static int fimc_md_parse_port_node(struct fimc_md *fmd,
|
|||
else
|
||||
pd->fimc_bus_type = pd->sensor_bus_type;
|
||||
|
||||
if (WARN_ON(index >= ARRAY_SIZE(fmd->sensor)))
|
||||
if (WARN_ON(index >= ARRAY_SIZE(fmd->sensor))) {
|
||||
of_node_put(rem);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
fmd->sensor[index].asd.match_type = V4L2_ASYNC_MATCH_OF;
|
||||
fmd->sensor[index].asd.match.of.node = rem;
|
||||
|
@ -1130,7 +1132,7 @@ static int __fimc_md_modify_pipelines(struct media_entity *entity, bool enable,
|
|||
media_entity_graph_walk_start(graph, entity);
|
||||
|
||||
while ((entity = media_entity_graph_walk_next(graph))) {
|
||||
if (!is_media_entity_v4l2_io(entity))
|
||||
if (!is_media_entity_v4l2_video_device(entity))
|
||||
continue;
|
||||
|
||||
ret = __fimc_md_modify_pipeline(entity, enable);
|
||||
|
@ -1145,7 +1147,7 @@ err:
|
|||
media_entity_graph_walk_start(graph, entity_err);
|
||||
|
||||
while ((entity_err = media_entity_graph_walk_next(graph))) {
|
||||
if (!is_media_entity_v4l2_io(entity_err))
|
||||
if (!is_media_entity_v4l2_video_device(entity_err))
|
||||
continue;
|
||||
|
||||
__fimc_md_modify_pipeline(entity_err, !enable);
|
||||
|
|
|
@ -757,8 +757,10 @@ static int s5pcsis_parse_dt(struct platform_device *pdev,
|
|||
goto err;
|
||||
|
||||
state->index = endpoint.base.port - FIMC_INPUT_MIPI_CSI2_0;
|
||||
if (state->index >= CSIS_MAX_ENTITIES)
|
||||
return -ENXIO;
|
||||
if (state->index >= CSIS_MAX_ENTITIES) {
|
||||
ret = -ENXIO;
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Get MIPI CSI-2 bus configration from the endpoint node. */
|
||||
of_property_read_u32(node, "samsung,csis-hs-settle",
|
||||
|
|
|
@ -251,7 +251,7 @@ static int isp_video_get_graph_data(struct isp_video *video,
|
|||
if (entity == &video->video.entity)
|
||||
continue;
|
||||
|
||||
if (!is_media_entity_v4l2_io(entity))
|
||||
if (!is_media_entity_v4l2_video_device(entity))
|
||||
continue;
|
||||
|
||||
__video = to_isp_video(media_entity_to_video_device(entity));
|
||||
|
|
|
@ -719,16 +719,12 @@ static int g2d_probe(struct platform_device *pdev)
|
|||
|
||||
def_frame.stride = (def_frame.width * def_frame.fmt->depth) >> 3;
|
||||
|
||||
if (!pdev->dev.of_node) {
|
||||
dev->variant = g2d_get_drv_data(pdev);
|
||||
} else {
|
||||
of_id = of_match_node(exynos_g2d_match, pdev->dev.of_node);
|
||||
if (!of_id) {
|
||||
ret = -ENODEV;
|
||||
goto unreg_video_dev;
|
||||
}
|
||||
dev->variant = (struct g2d_variant *)of_id->data;
|
||||
of_id = of_match_node(exynos_g2d_match, pdev->dev.of_node);
|
||||
if (!of_id) {
|
||||
ret = -ENODEV;
|
||||
goto unreg_video_dev;
|
||||
}
|
||||
dev->variant = (struct g2d_variant *)of_id->data;
|
||||
|
||||
return 0;
|
||||
|
||||
|
@ -788,22 +784,9 @@ static const struct of_device_id exynos_g2d_match[] = {
|
|||
};
|
||||
MODULE_DEVICE_TABLE(of, exynos_g2d_match);
|
||||
|
||||
static const struct platform_device_id g2d_driver_ids[] = {
|
||||
{
|
||||
.name = "s5p-g2d",
|
||||
.driver_data = (unsigned long)&g2d_drvdata_v3x,
|
||||
}, {
|
||||
.name = "s5p-g2d-v4x",
|
||||
.driver_data = (unsigned long)&g2d_drvdata_v4x,
|
||||
},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, g2d_driver_ids);
|
||||
|
||||
static struct platform_driver g2d_pdrv = {
|
||||
.probe = g2d_probe,
|
||||
.remove = g2d_remove,
|
||||
.id_table = g2d_driver_ids,
|
||||
.driver = {
|
||||
.name = G2D_NAME,
|
||||
.of_match_table = exynos_g2d_match,
|
||||
|
|
|
@ -89,8 +89,3 @@ void g2d_set_flip(struct g2d_dev *d, u32 r);
|
|||
void g2d_set_v41_stretch(struct g2d_dev *d,
|
||||
struct g2d_frame *src, struct g2d_frame *dst);
|
||||
void g2d_set_cmd(struct g2d_dev *d, u32 c);
|
||||
|
||||
static inline struct g2d_variant *g2d_get_drv_data(struct platform_device *pdev)
|
||||
{
|
||||
return (struct g2d_variant *)platform_get_device_id(pdev)->driver_data;
|
||||
}
|
||||
|
|
|
@ -1548,8 +1548,10 @@ static int exynos4_jpeg_get_output_buffer_size(struct s5p_jpeg_ctx *ctx,
|
|||
struct v4l2_pix_format *pix = &f->fmt.pix;
|
||||
u32 pix_fmt = f->fmt.pix.pixelformat;
|
||||
int w = pix->width, h = pix->height, wh_align;
|
||||
int padding = 0;
|
||||
|
||||
if (pix_fmt == V4L2_PIX_FMT_RGB32 ||
|
||||
pix_fmt == V4L2_PIX_FMT_RGB565 ||
|
||||
pix_fmt == V4L2_PIX_FMT_NV24 ||
|
||||
pix_fmt == V4L2_PIX_FMT_NV42 ||
|
||||
pix_fmt == V4L2_PIX_FMT_NV12 ||
|
||||
|
@ -1564,7 +1566,10 @@ static int exynos4_jpeg_get_output_buffer_size(struct s5p_jpeg_ctx *ctx,
|
|||
&h, S5P_JPEG_MIN_HEIGHT,
|
||||
S5P_JPEG_MAX_HEIGHT, wh_align);
|
||||
|
||||
return w * h * fmt_depth >> 3;
|
||||
if (ctx->jpeg->variant->version == SJPEG_EXYNOS4)
|
||||
padding = PAGE_SIZE;
|
||||
|
||||
return (w * h * fmt_depth >> 3) + padding;
|
||||
}
|
||||
|
||||
static int exynos3250_jpeg_try_downscale(struct s5p_jpeg_ctx *ctx,
|
||||
|
|
|
@ -1489,27 +1489,6 @@ static struct s5p_mfc_variant mfc_drvdata_v8 = {
|
|||
.fw_name[0] = "s5p-mfc-v8.fw",
|
||||
};
|
||||
|
||||
static const struct platform_device_id mfc_driver_ids[] = {
|
||||
{
|
||||
.name = "s5p-mfc",
|
||||
.driver_data = (unsigned long)&mfc_drvdata_v5,
|
||||
}, {
|
||||
.name = "s5p-mfc-v5",
|
||||
.driver_data = (unsigned long)&mfc_drvdata_v5,
|
||||
}, {
|
||||
.name = "s5p-mfc-v6",
|
||||
.driver_data = (unsigned long)&mfc_drvdata_v6,
|
||||
}, {
|
||||
.name = "s5p-mfc-v7",
|
||||
.driver_data = (unsigned long)&mfc_drvdata_v7,
|
||||
}, {
|
||||
.name = "s5p-mfc-v8",
|
||||
.driver_data = (unsigned long)&mfc_drvdata_v8,
|
||||
},
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, mfc_driver_ids);
|
||||
|
||||
static const struct of_device_id exynos_mfc_match[] = {
|
||||
{
|
||||
.compatible = "samsung,mfc-v5",
|
||||
|
@ -1531,24 +1510,18 @@ MODULE_DEVICE_TABLE(of, exynos_mfc_match);
|
|||
static void *mfc_get_drv_data(struct platform_device *pdev)
|
||||
{
|
||||
struct s5p_mfc_variant *driver_data = NULL;
|
||||
const struct of_device_id *match;
|
||||
|
||||
match = of_match_node(exynos_mfc_match, pdev->dev.of_node);
|
||||
if (match)
|
||||
driver_data = (struct s5p_mfc_variant *)match->data;
|
||||
|
||||
if (pdev->dev.of_node) {
|
||||
const struct of_device_id *match;
|
||||
match = of_match_node(exynos_mfc_match,
|
||||
pdev->dev.of_node);
|
||||
if (match)
|
||||
driver_data = (struct s5p_mfc_variant *)match->data;
|
||||
} else {
|
||||
driver_data = (struct s5p_mfc_variant *)
|
||||
platform_get_device_id(pdev)->driver_data;
|
||||
}
|
||||
return driver_data;
|
||||
}
|
||||
|
||||
static struct platform_driver s5p_mfc_driver = {
|
||||
.probe = s5p_mfc_probe,
|
||||
.remove = s5p_mfc_remove,
|
||||
.id_table = mfc_driver_ids,
|
||||
.driver = {
|
||||
.name = S5P_MFC_NAME,
|
||||
.pm = &s5p_mfc_pm_ops,
|
||||
|
|
|
@ -300,7 +300,7 @@ void mxr_release_video(struct mxr_device *mdev);
|
|||
struct mxr_layer *mxr_graph_layer_create(struct mxr_device *mdev, int idx);
|
||||
struct mxr_layer *mxr_vp_layer_create(struct mxr_device *mdev, int idx);
|
||||
struct mxr_layer *mxr_base_layer_create(struct mxr_device *mdev,
|
||||
int idx, char *name, struct mxr_layer_ops *ops);
|
||||
int idx, char *name, const struct mxr_layer_ops *ops);
|
||||
|
||||
void mxr_base_layer_release(struct mxr_layer *layer);
|
||||
void mxr_layer_release(struct mxr_layer *layer);
|
||||
|
|
|
@ -235,7 +235,7 @@ struct mxr_layer *mxr_graph_layer_create(struct mxr_device *mdev, int idx)
|
|||
{
|
||||
struct mxr_layer *layer;
|
||||
int ret;
|
||||
struct mxr_layer_ops ops = {
|
||||
const struct mxr_layer_ops ops = {
|
||||
.release = mxr_graph_layer_release,
|
||||
.buffer_set = mxr_graph_buffer_set,
|
||||
.stream_set = mxr_graph_stream_set,
|
||||
|
|
|
@ -1070,7 +1070,7 @@ static void mxr_vfd_release(struct video_device *vdev)
|
|||
}
|
||||
|
||||
struct mxr_layer *mxr_base_layer_create(struct mxr_device *mdev,
|
||||
int idx, char *name, struct mxr_layer_ops *ops)
|
||||
int idx, char *name, const struct mxr_layer_ops *ops)
|
||||
{
|
||||
struct mxr_layer *layer;
|
||||
|
||||
|
|
|
@ -207,7 +207,7 @@ struct mxr_layer *mxr_vp_layer_create(struct mxr_device *mdev, int idx)
|
|||
{
|
||||
struct mxr_layer *layer;
|
||||
int ret;
|
||||
struct mxr_layer_ops ops = {
|
||||
const struct mxr_layer_ops ops = {
|
||||
.release = mxr_vp_layer_release,
|
||||
.buffer_set = mxr_vp_buffer_set,
|
||||
.stream_set = mxr_vp_stream_set,
|
||||
|
|
|
@ -28,7 +28,7 @@ config VIDEO_PXA27x
|
|||
config VIDEO_RCAR_VIN
|
||||
tristate "R-Car Video Input (VIN) support"
|
||||
depends on VIDEO_DEV && SOC_CAMERA
|
||||
depends on ARCH_SHMOBILE || COMPILE_TEST
|
||||
depends on ARCH_RENESAS || COMPILE_TEST
|
||||
depends on HAS_DMA
|
||||
select VIDEOBUF2_DMA_CONTIG
|
||||
select SOC_CAMERA_SCALE_CROP
|
||||
|
@ -45,7 +45,7 @@ config VIDEO_SH_MOBILE_CSI2
|
|||
config VIDEO_SH_MOBILE_CEU
|
||||
tristate "SuperH Mobile CEU Interface driver"
|
||||
depends on VIDEO_DEV && SOC_CAMERA && HAS_DMA && HAVE_CLK
|
||||
depends on ARCH_SHMOBILE || SUPERH || COMPILE_TEST
|
||||
depends on ARCH_SHMOBILE || COMPILE_TEST
|
||||
depends on HAS_DMA
|
||||
select VIDEOBUF2_DMA_CONTIG
|
||||
select SOC_CAMERA_SCALE_CROP
|
||||
|
|
|
@ -1845,6 +1845,8 @@ static const struct of_device_id rcar_vin_of_table[] = {
|
|||
{ .compatible = "renesas,vin-r8a7790", .data = (void *)RCAR_GEN2 },
|
||||
{ .compatible = "renesas,vin-r8a7779", .data = (void *)RCAR_H1 },
|
||||
{ .compatible = "renesas,vin-r8a7778", .data = (void *)RCAR_M1 },
|
||||
{ .compatible = "renesas,rcar-gen3-vin", .data = (void *)RCAR_GEN3 },
|
||||
{ .compatible = "renesas,rcar-gen2-vin", .data = (void *)RCAR_GEN2 },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, rcar_vin_of_table);
|
||||
|
|
|
@ -49,7 +49,7 @@ MODULE_FIRMWARE(FIRMWARE_MEMDMA);
|
|||
#define PID_TABLE_SIZE 1024
|
||||
#define POLL_MSECS 50
|
||||
|
||||
static int load_c8sectpfe_fw_step1(struct c8sectpfei *fei);
|
||||
static int load_c8sectpfe_fw(struct c8sectpfei *fei);
|
||||
|
||||
#define TS_PKT_SIZE 188
|
||||
#define HEADER_SIZE (4)
|
||||
|
@ -130,7 +130,7 @@ static void channel_swdemux_tsklet(unsigned long data)
|
|||
writel(channel->back_buffer_busaddr, channel->irec +
|
||||
DMA_PRDS_BUSRP_TP(0));
|
||||
else
|
||||
writel(wp, channel->irec + DMA_PRDS_BUSWP_TP(0));
|
||||
writel(wp, channel->irec + DMA_PRDS_BUSRP_TP(0));
|
||||
}
|
||||
|
||||
static int c8sectpfe_start_feed(struct dvb_demux_feed *dvbdmxfeed)
|
||||
|
@ -141,6 +141,7 @@ static int c8sectpfe_start_feed(struct dvb_demux_feed *dvbdmxfeed)
|
|||
struct channel_info *channel;
|
||||
u32 tmp;
|
||||
unsigned long *bitmap;
|
||||
int ret;
|
||||
|
||||
switch (dvbdmxfeed->type) {
|
||||
case DMX_TYPE_TS:
|
||||
|
@ -169,8 +170,9 @@ static int c8sectpfe_start_feed(struct dvb_demux_feed *dvbdmxfeed)
|
|||
}
|
||||
|
||||
if (!atomic_read(&fei->fw_loaded)) {
|
||||
dev_err(fei->dev, "%s: c8sectpfe fw not loaded\n", __func__);
|
||||
return -EINVAL;
|
||||
ret = load_c8sectpfe_fw(fei);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
mutex_lock(&fei->lock);
|
||||
|
@ -265,8 +267,9 @@ static int c8sectpfe_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
|
|||
unsigned long *bitmap;
|
||||
|
||||
if (!atomic_read(&fei->fw_loaded)) {
|
||||
dev_err(fei->dev, "%s: c8sectpfe fw not loaded\n", __func__);
|
||||
return -EINVAL;
|
||||
ret = load_c8sectpfe_fw(fei);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
mutex_lock(&fei->lock);
|
||||
|
@ -585,7 +588,7 @@ static int configure_memdma_and_inputblock(struct c8sectpfei *fei,
|
|||
writel(tsin->pid_buffer_busaddr,
|
||||
fei->io + PIDF_BASE(tsin->tsin_id));
|
||||
|
||||
dev_info(fei->dev, "chan=%d PIDF_BASE=0x%x pid_bus_addr=%pad\n",
|
||||
dev_dbg(fei->dev, "chan=%d PIDF_BASE=0x%x pid_bus_addr=%pad\n",
|
||||
tsin->tsin_id, readl(fei->io + PIDF_BASE(tsin->tsin_id)),
|
||||
&tsin->pid_buffer_busaddr);
|
||||
|
||||
|
@ -880,13 +883,6 @@ static int c8sectpfe_probe(struct platform_device *pdev)
|
|||
goto err_clk_disable;
|
||||
}
|
||||
|
||||
/* ensure all other init has been done before requesting firmware */
|
||||
ret = load_c8sectpfe_fw_step1(fei);
|
||||
if (ret) {
|
||||
dev_err(dev, "Couldn't load slim core firmware\n");
|
||||
goto err_clk_disable;
|
||||
}
|
||||
|
||||
c8sectpfe_debugfs_init(fei);
|
||||
|
||||
return 0;
|
||||
|
@ -1091,15 +1087,14 @@ static void load_dmem_segment(struct c8sectpfei *fei, Elf32_Phdr *phdr,
|
|||
phdr->p_memsz - phdr->p_filesz);
|
||||
}
|
||||
|
||||
static int load_slim_core_fw(const struct firmware *fw, void *context)
|
||||
static int load_slim_core_fw(const struct firmware *fw, struct c8sectpfei *fei)
|
||||
{
|
||||
struct c8sectpfei *fei = context;
|
||||
Elf32_Ehdr *ehdr;
|
||||
Elf32_Phdr *phdr;
|
||||
u8 __iomem *dst;
|
||||
int err = 0, i;
|
||||
|
||||
if (!fw || !context)
|
||||
if (!fw || !fei)
|
||||
return -EINVAL;
|
||||
|
||||
ehdr = (Elf32_Ehdr *)fw->data;
|
||||
|
@ -1151,29 +1146,35 @@ static int load_slim_core_fw(const struct firmware *fw, void *context)
|
|||
return err;
|
||||
}
|
||||
|
||||
static void load_c8sectpfe_fw_cb(const struct firmware *fw, void *context)
|
||||
static int load_c8sectpfe_fw(struct c8sectpfei *fei)
|
||||
{
|
||||
struct c8sectpfei *fei = context;
|
||||
const struct firmware *fw;
|
||||
int err;
|
||||
|
||||
dev_info(fei->dev, "Loading firmware: %s\n", FIRMWARE_MEMDMA);
|
||||
|
||||
err = request_firmware(&fw, FIRMWARE_MEMDMA, fei->dev);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = c8sectpfe_elf_sanity_check(fei, fw);
|
||||
if (err) {
|
||||
dev_err(fei->dev, "c8sectpfe_elf_sanity_check failed err=(%d)\n"
|
||||
, err);
|
||||
goto err;
|
||||
return err;
|
||||
}
|
||||
|
||||
err = load_slim_core_fw(fw, context);
|
||||
err = load_slim_core_fw(fw, fei);
|
||||
if (err) {
|
||||
dev_err(fei->dev, "load_slim_core_fw failed err=(%d)\n", err);
|
||||
goto err;
|
||||
return err;
|
||||
}
|
||||
|
||||
/* now the firmware is loaded configure the input blocks */
|
||||
err = configure_channels(fei);
|
||||
if (err) {
|
||||
dev_err(fei->dev, "configure_channels failed err=(%d)\n", err);
|
||||
goto err;
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1186,28 +1187,6 @@ static void load_c8sectpfe_fw_cb(const struct firmware *fw, void *context)
|
|||
writel(0x1, fei->io + DMA_CPU_RUN);
|
||||
|
||||
atomic_set(&fei->fw_loaded, 1);
|
||||
err:
|
||||
complete_all(&fei->fw_ack);
|
||||
}
|
||||
|
||||
static int load_c8sectpfe_fw_step1(struct c8sectpfei *fei)
|
||||
{
|
||||
int err;
|
||||
|
||||
dev_info(fei->dev, "Loading firmware: %s\n", FIRMWARE_MEMDMA);
|
||||
|
||||
init_completion(&fei->fw_ack);
|
||||
atomic_set(&fei->fw_loaded, 0);
|
||||
|
||||
err = request_firmware_nowait(THIS_MODULE, FW_ACTION_HOTPLUG,
|
||||
FIRMWARE_MEMDMA, fei->dev, GFP_KERNEL, fei,
|
||||
load_c8sectpfe_fw_cb);
|
||||
|
||||
if (err) {
|
||||
dev_err(fei->dev, "request_firmware_nowait err: %d.\n", err);
|
||||
complete_all(&fei->fw_ack);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ config VIDEO_VIVID
|
|||
select FB_CFB_COPYAREA
|
||||
select FB_CFB_IMAGEBLIT
|
||||
select VIDEOBUF2_VMALLOC
|
||||
select VIDEO_V4L2_TPG
|
||||
default n
|
||||
---help---
|
||||
Enables a virtual video driver. This driver emulates a webcam,
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue