Commit cbb5c835 authored by Mauro Carvalho Chehab's avatar Mauro Carvalho Chehab

Merge branch 'topic/cec' into patchwork

* topic/cec:
  [media] DocBook/media: add CEC documentation
  [media] s5p_cec: get rid of an unused var
  [media] move s5p-cec to staging
  [media] vivid: add CEC emulation
  [media] cec: s5p-cec: Add s5p-cec driver
  [media] cec: adv7511: add cec support
  [media] cec: adv7842: add cec support
  [media] cec: adv7604: add cec support
  [media] cec: add compat32 ioctl support
  [media] cec/TODO: add TODO file so we know why this is still in staging
  [media] cec: add HDMI CEC framework (api)
  [media] cec: add HDMI CEC framework (adapter)
  [media] cec: add HDMI CEC framework (core)
  [media] cec-funcs.h: static inlines to pack/unpack CEC messages
  [media] cec.h: add cec header
  [media] cec-edid: add module for EDID CEC helper functions
  [media] cec.txt: add CEC framework documentation
  [media] rc: Add HDMI CEC protocol handling
parents fb810cb5 c7169ad5
......@@ -300,6 +300,9 @@ X!Isound/sound_firmware.c
!Iinclude/media/media-devnode.h
!Iinclude/media/media-entity.h
</sect1>
<sect1><title>Consumer Electronics Control devices</title>
!Iinclude/media/cec-edid.h
</sect1>
</chapter>
......
......@@ -64,6 +64,7 @@ IOCTLS = \
$(shell perl -ne 'print "$$1 " if /\#define\s+([A-Z][^\s]+)\s+_IO/' $(srctree)/include/uapi/linux/dvb/net.h) \
$(shell perl -ne 'print "$$1 " if /\#define\s+([^\s]+)\s+_IO/' $(srctree)/include/uapi/linux/dvb/video.h) \
$(shell perl -ne 'print "$$1 " if /\#define\s+([^\s]+)\s+_IO/' $(srctree)/include/uapi/linux/media.h) \
$(shell perl -ne 'print "$$1 " if /\#define\s+([^\s]+)\s+_IO/' $(srctree)/include/linux/cec.h) \
$(shell perl -ne 'print "$$1 " if /\#define\s+([^\s]+)\s+_IO/' $(srctree)/include/uapi/linux/v4l2-subdev.h) \
DEFINES = \
......@@ -100,6 +101,7 @@ STRUCTS = \
$(shell perl -ne 'print "$$1 " if (/^struct\s+([^\s]+)\s+/ && !/_old/)' $(srctree)/include/uapi/linux/dvb/net.h) \
$(shell perl -ne 'print "$$1 " if (/^struct\s+([^\s]+)\s+/)' $(srctree)/include/uapi/linux/dvb/video.h) \
$(shell perl -ne 'print "$$1 " if /^struct\s+([^\s]+)\s+/' $(srctree)/include/uapi/linux/media.h) \
$(shell perl -ne 'print "$$1 " if /^struct\s+([^\s]+)\s+/' $(srctree)/include/linux/cec.h) \
$(shell perl -ne 'print "$$1 " if /^struct\s+([^\s]+)\s+/' $(srctree)/include/uapi/linux/v4l2-subdev.h) \
$(shell perl -ne 'print "$$1 " if /^struct\s+([^\s]+)\s+/' $(srctree)/include/uapi/linux/v4l2-mediabus.h)
......
......@@ -342,6 +342,16 @@ in the frequency range from 87,5 to 108,0 MHz</title>
<subtitle>Specification Version 1.4a</subtitle>
</biblioentry>
<biblioentry id="hdmi2">
<abbrev>HDMI2</abbrev>
<authorgroup>
<corpauthor>HDMI Licensing LLC
(<ulink url="http://www.hdmi.org">http://www.hdmi.org</ulink>)</corpauthor>
</authorgroup>
<title>High-Definition Multimedia Interface</title>
<subtitle>Specification Version 2.0</subtitle>
</biblioentry>
<biblioentry id="dp">
<abbrev>DP</abbrev>
<authorgroup>
......
<partinfo>
<authorgroup>
<author>
<firstname>Hans</firstname>
<surname>Verkuil</surname>
<affiliation><address><email>hans.verkuil@cisco.com</email></address></affiliation>
<contrib>Initial version.</contrib>
</author>
</authorgroup>
<copyright>
<year>2016</year>
<holder>Hans Verkuil</holder>
</copyright>
<revhistory>
<!-- Put document revisions here, newest first. -->
<revision>
<revnumber>1.0.0</revnumber>
<date>2016-03-17</date>
<authorinitials>hv</authorinitials>
<revremark>Initial revision</revremark>
</revision>
</revhistory>
</partinfo>
<title>CEC API</title>
<chapter id="cec-api">
<title>CEC: Consumer Electronics Control</title>
<section id="cec-intro">
<title>Introduction</title>
<para>
Note: this documents the proposed CEC API. This API is not yet finalized and
is currently only available as a staging kernel module.
</para>
<para>HDMI connectors provide a single pin for use by the Consumer Electronics
Control protocol. This protocol allows different devices connected by an HDMI cable
to communicate. The protocol for CEC version 1.4 is defined in supplements 1 (CEC)
and 2 (HEAC or HDMI Ethernet and Audio Return Channel) of the HDMI 1.4a
(<xref linkend="hdmi" />) specification and the extensions added to CEC version 2.0
are defined in chapter 11 of the HDMI 2.0 (<xref linkend="hdmi2" />) specification.
</para>
<para>The bitrate is very slow (effectively no more than 36 bytes per second) and
is based on the ancient AV.link protocol used in old SCART connectors. The protocol
closely resembles a crazy Rube Goldberg contraption and is an unholy mix of low and
high level messages. Some messages, especially those part of the HEAC protocol layered
on top of CEC, need to be handled by the kernel, others can be handled either by the
kernel or by userspace.</para>
<para>In addition, CEC can be implemented in HDMI receivers, transmitters and in USB
devices that have an HDMI input and an HDMI output and that control just the CEC pin.</para>
<para>Drivers that support CEC will create a CEC device node (/dev/cecX)
to give userspace access to the CEC adapter. The &CEC-ADAP-G-CAPS; ioctl will tell userspace
what it is allowed to do.</para>
</section>
</chapter>
<appendix id="cec-user-func">
<title>Function Reference</title>
<!-- Keep this alphabetically sorted. -->
&sub-cec-func-open;
&sub-cec-func-close;
&sub-cec-func-ioctl;
&sub-cec-func-poll;
<!-- All ioctls go here. -->
&sub-cec-ioc-adap-g-caps;
&sub-cec-ioc-adap-g-log-addrs;
&sub-cec-ioc-adap-g-phys-addr;
&sub-cec-ioc-dqevent;
&sub-cec-ioc-g-mode;
&sub-cec-ioc-receive;
</appendix>
<refentry id="cec-func-close">
<refmeta>
<refentrytitle>cec close()</refentrytitle>
&manvol;
</refmeta>
<refnamediv>
<refname>cec-close</refname>
<refpurpose>Close a cec device</refpurpose>
</refnamediv>
<refsynopsisdiv>
<funcsynopsis>
<funcsynopsisinfo>#include &lt;unistd.h&gt;</funcsynopsisinfo>
<funcprototype>
<funcdef>int <function>close</function></funcdef>
<paramdef>int <parameter>fd</parameter></paramdef>
</funcprototype>
</funcsynopsis>
</refsynopsisdiv>
<refsect1>
<title>Arguments</title>
<variablelist>
<varlistentry>
<term><parameter>fd</parameter></term>
<listitem>
<para>&fd;</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>Description</title>
<para>
Note: this documents the proposed CEC API. This API is not yet finalized and
is currently only available as a staging kernel module.
</para>
<para>Closes the cec device. Resources associated with the file descriptor
are freed. The device configuration remain unchanged.</para>
</refsect1>
<refsect1>
<title>Return Value</title>
<para><function>close</function> returns 0 on success. On error, -1 is
returned, and <varname>errno</varname> is set appropriately. Possible error
codes are:</para>
<variablelist>
<varlistentry>
<term><errorcode>EBADF</errorcode></term>
<listitem>
<para><parameter>fd</parameter> is not a valid open file descriptor.
</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
</refentry>
<refentry id="cec-func-ioctl">
<refmeta>
<refentrytitle>cec ioctl()</refentrytitle>
&manvol;
</refmeta>
<refnamediv>
<refname>cec-ioctl</refname>
<refpurpose>Control a cec device</refpurpose>
</refnamediv>
<refsynopsisdiv>
<funcsynopsis>
<funcsynopsisinfo>#include &lt;sys/ioctl.h&gt;</funcsynopsisinfo>
<funcprototype>
<funcdef>int <function>ioctl</function></funcdef>
<paramdef>int <parameter>fd</parameter></paramdef>
<paramdef>int <parameter>request</parameter></paramdef>
<paramdef>void *<parameter>argp</parameter></paramdef>
</funcprototype>
</funcsynopsis>
</refsynopsisdiv>
<refsect1>
<title>Arguments</title>
<variablelist>
<varlistentry>
<term><parameter>fd</parameter></term>
<listitem>
<para>&fd;</para>
</listitem>
</varlistentry>
<varlistentry>
<term><parameter>request</parameter></term>
<listitem>
<para>CEC ioctl request code as defined in the cec.h header file,
for example CEC_ADAP_G_CAPS.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><parameter>argp</parameter></term>
<listitem>
<para>Pointer to a request-specific structure.</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>Description</title>
<para>
Note: this documents the proposed CEC API. This API is not yet finalized and
is currently only available as a staging kernel module.
</para>
<para>The <function>ioctl()</function> function manipulates cec device
parameters. The argument <parameter>fd</parameter> must be an open file
descriptor.</para>
<para>The ioctl <parameter>request</parameter> code specifies the cec
function to be called. It has encoded in it whether the argument is an
input, output or read/write parameter, and the size of the argument
<parameter>argp</parameter> in bytes.</para>
<para>Macros and structures definitions specifying cec ioctl requests and
their parameters are located in the cec.h header file. All cec ioctl
requests, their respective function and parameters are specified in
<xref linkend="cec-user-func" />.</para>
</refsect1>
<refsect1>
&return-value;
<para>Request-specific error codes are listed in the
individual requests descriptions.</para>
<para>When an ioctl that takes an output or read/write parameter fails,
the parameter remains unmodified.</para>
</refsect1>
</refentry>
<refentry id="cec-func-open">
<refmeta>
<refentrytitle>cec open()</refentrytitle>
&manvol;
</refmeta>
<refnamediv>
<refname>cec-open</refname>
<refpurpose>Open a cec device</refpurpose>
</refnamediv>
<refsynopsisdiv>
<funcsynopsis>
<funcsynopsisinfo>#include &lt;fcntl.h&gt;</funcsynopsisinfo>
<funcprototype>
<funcdef>int <function>open</function></funcdef>
<paramdef>const char *<parameter>device_name</parameter></paramdef>
<paramdef>int <parameter>flags</parameter></paramdef>
</funcprototype>
</funcsynopsis>
</refsynopsisdiv>
<refsect1>
<title>Arguments</title>
<variablelist>
<varlistentry>
<term><parameter>device_name</parameter></term>
<listitem>
<para>Device to be opened.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><parameter>flags</parameter></term>
<listitem>
<para>Open flags. Access mode must be <constant>O_RDWR</constant>.
</para>
<para>When the <constant>O_NONBLOCK</constant> flag is
given, the &CEC-RECEIVE; ioctl will return &EAGAIN; when no message is
available, and the &CEC-TRANSMIT;, &CEC-ADAP-S-PHYS-ADDR; and
&CEC-ADAP-S-LOG-ADDRS; ioctls all act in non-blocking mode.</para>
<para>Other flags have no effect.</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>Description</title>
<para>
Note: this documents the proposed CEC API. This API is not yet finalized and
is currently only available as a staging kernel module.
</para>
<para>To open a cec device applications call <function>open()</function>
with the desired device name. The function has no side effects; the device
configuration remain unchanged.</para>
<para>When the device is opened in read-only mode, attempts to modify its
configuration will result in an error, and <varname>errno</varname> will be
set to <errorcode>EBADF</errorcode>.</para>
</refsect1>
<refsect1>
<title>Return Value</title>
<para><function>open</function> returns the new file descriptor on success.
On error, -1 is returned, and <varname>errno</varname> is set appropriately.
Possible error codes include:</para>
<variablelist>
<varlistentry>
<term><errorcode>EACCES</errorcode></term>
<listitem>
<para>The requested access to the file is not allowed.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><errorcode>EMFILE</errorcode></term>
<listitem>
<para>The process already has the maximum number of files open.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><errorcode>ENFILE</errorcode></term>
<listitem>
<para>The system limit on the total number of open files has been
reached.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><errorcode>ENOMEM</errorcode></term>
<listitem>
<para>Insufficient kernel memory was available.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><errorcode>ENXIO</errorcode></term>
<listitem>
<para>No device corresponding to this device special file exists.
</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
</refentry>
<refentry id="cec-func-poll">
<refmeta>
<refentrytitle>cec poll()</refentrytitle>
&manvol;
</refmeta>
<refnamediv>
<refname>cec-poll</refname>
<refpurpose>Wait for some event on a file descriptor</refpurpose>
</refnamediv>
<refsynopsisdiv>
<funcsynopsis>
<funcsynopsisinfo>#include &lt;sys/poll.h&gt;</funcsynopsisinfo>
<funcprototype>
<funcdef>int <function>poll</function></funcdef>
<paramdef>struct pollfd *<parameter>ufds</parameter></paramdef>
<paramdef>unsigned int <parameter>nfds</parameter></paramdef>
<paramdef>int <parameter>timeout</parameter></paramdef>
</funcprototype>
</funcsynopsis>
</refsynopsisdiv>
<refsect1>
<title>Description</title>
<para>
Note: this documents the proposed CEC API. This API is not yet finalized and
is currently only available as a staging kernel module.
</para>
<para>With the <function>poll()</function> function applications
can wait for CEC events.</para>
<para>On success <function>poll()</function> returns the number of
file descriptors that have been selected (that is, file descriptors
for which the <structfield>revents</structfield> field of the
respective <structname>pollfd</structname> structure is non-zero).
CEC devices set the <constant>POLLIN</constant> and
<constant>POLLRDNORM</constant> flags in the
<structfield>revents</structfield> field if there are messages in the
receive queue. If the transmit queue has room for new messages, the
<constant>POLLOUT</constant> and <constant>POLLWRNORM</constant>
flags are set. If there are events in the event queue, then the
<constant>POLLPRI</constant> flag is set.
When the function timed out it returns a value of zero, on
failure it returns <returnvalue>-1</returnvalue> and the
<varname>errno</varname> variable is set appropriately.
</para>
<para>For more details see the
<function>poll()</function> manual page.</para>
</refsect1>
<refsect1>
<title>Return Value</title>
<para>On success, <function>poll()</function> returns the number
structures which have non-zero <structfield>revents</structfield>
fields, or zero if the call timed out. On error
<returnvalue>-1</returnvalue> is returned, and the
<varname>errno</varname> variable is set appropriately:</para>
<variablelist>
<varlistentry>
<term><errorcode>EBADF</errorcode></term>
<listitem>
<para>One or more of the <parameter>ufds</parameter> members
specify an invalid file descriptor.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><errorcode>EFAULT</errorcode></term>
<listitem>
<para><parameter>ufds</parameter> references an inaccessible
memory area.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><errorcode>EINTR</errorcode></term>
<listitem>
<para>The call was interrupted by a signal.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><errorcode>EINVAL</errorcode></term>
<listitem>
<para>The <parameter>nfds</parameter> argument is greater
than <constant>OPEN_MAX</constant>.</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
</refentry>
<refentry id="cec-ioc-adap-g-caps">
<refmeta>
<refentrytitle>ioctl CEC_ADAP_G_CAPS</refentrytitle>
&manvol;
</refmeta>
<refnamediv>
<refname>CEC_ADAP_G_CAPS</refname>
<refpurpose>Query device capabilities</refpurpose>
</refnamediv>
<refsynopsisdiv>
<funcsynopsis>
<funcprototype>
<funcdef>int <function>ioctl</function></funcdef>
<paramdef>int <parameter>fd</parameter></paramdef>
<paramdef>int <parameter>request</parameter></paramdef>
<paramdef>struct cec_caps *<parameter>argp</parameter></paramdef>
</funcprototype>
</funcsynopsis>
</refsynopsisdiv>
<refsect1>
<title>Arguments</title>
<variablelist>
<varlistentry>
<term><parameter>fd</parameter></term>
<listitem>
<para>File descriptor returned by
<link linkend='cec-func-open'><function>open()</function></link>.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><parameter>request</parameter></term>
<listitem>
<para>CEC_ADAP_G_CAPS</para>
</listitem>
</varlistentry>
<varlistentry>
<term><parameter>argp</parameter></term>
<listitem>
<para></para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>Description</title>
<para>
Note: this documents the proposed CEC API. This API is not yet finalized and
is currently only available as a staging kernel module.
</para>
<para>All cec devices must support the <constant>CEC_ADAP_G_CAPS</constant>
ioctl. To query device information, applications call the ioctl with a
pointer to a &cec-caps;. The driver fills the structure and returns
the information to the application.
The ioctl never fails.</para>
<table pgwide="1" frame="none" id="cec-caps">
<title>struct <structname>cec_caps</structname></title>
<tgroup cols="3">
&cs-str;
<tbody valign="top">
<row>
<entry>char</entry>
<entry><structfield>driver[32]</structfield></entry>
<entry>The name of the cec adapter driver.</entry>
</row>
<row>
<entry>char</entry>
<entry><structfield>name[32]</structfield></entry>
<entry>The name of this CEC adapter. The combination <structfield>driver</structfield>
and <structfield>name</structfield> must be unique.</entry>
</row>
<row>
<entry>__u32</entry>
<entry><structfield>capabilities</structfield></entry>
<entry>The capabilities of the CEC adapter, see <xref
linkend="cec-capabilities" />.</entry>
</row>
<row>
<entry>__u32</entry>
<entry><structfield>version</structfield></entry>
<entry>CEC Framework API version, formatted with the
<constant>KERNEL_VERSION()</constant> macro.</entry>
</row>
</tbody>
</tgroup>
</table>
<table pgwide="1" frame="none" id="cec-capabilities">
<title>CEC Capabilities Flags</title>
<tgroup cols="3">
&cs-def;
<tbody valign="top">
<row>
<entry><constant>CEC_CAP_PHYS_ADDR</constant></entry>
<entry>0x00000001</entry>
<entry>Userspace has to configure the physical address by
calling &CEC-ADAP-S-PHYS-ADDR;. If this capability isn't set,
then setting the physical address is handled by the kernel
whenever the EDID is set (for an HDMI receiver) or read (for
an HDMI transmitter).</entry>
</row>
<row>
<entry><constant>CEC_CAP_LOG_ADDRS</constant></entry>
<entry>0x00000002</entry>
<entry>Userspace has to configure the logical addresses by
calling &CEC-ADAP-S-LOG-ADDRS;. If this capability isn't set,
then the kernel will have configured this.</entry>
</row>
<row>
<entry><constant>CEC_CAP_TRANSMIT</constant></entry>
<entry>0x00000004</entry>
<entry>Userspace can transmit CEC messages by calling &CEC-TRANSMIT;. This
implies that userspace can be a follower as well, since being able to
transmit messages is a prerequisite of becoming a follower. If this
capability isn't set, then the kernel will handle all CEC transmits
and process all CEC messages it receives.
</entry>
</row>
<row>
<entry><constant>CEC_CAP_PASSTHROUGH</constant></entry>
<entry>0x00000008</entry>
<entry>Userspace can use the passthrough mode by
calling &CEC-S-MODE;.</entry>
</row>
<row>
<entry><constant>CEC_CAP_RC</constant></entry>
<entry>0x00000010</entry>
<entry>This adapter supports the remote control protocol.</entry>
</row>
<row>
<entry><constant>CEC_CAP_MONITOR_ALL</constant></entry>
<entry>0x00000020</entry>
<entry>The CEC hardware can monitor all messages, not just directed and
broadcast messages.</entry>
</row>
</tbody>
</tgroup>
</table>
</refsect1>
<refsect1>
&return-value;
</refsect1>
</refentry>
This diff is collapsed.
<refentry id="cec-ioc-adap-g-phys-addr">
<refmeta>
<refentrytitle>ioctl CEC_ADAP_G_PHYS_ADDR, CEC_ADAP_S_PHYS_ADDR</refentrytitle>
&manvol;
</refmeta>
<refnamediv>
<refname>CEC_ADAP_G_PHYS_ADDR</refname>
<refname>CEC_ADAP_S_PHYS_ADDR</refname>
<refpurpose>Get or set the physical address</refpurpose>
</refnamediv>
<refsynopsisdiv>
<funcsynopsis>
<funcprototype>
<funcdef>int <function>ioctl</function></funcdef>
<paramdef>int <parameter>fd</parameter></paramdef>
<paramdef>int <parameter>request</parameter></paramdef>
<paramdef>__u16 *<parameter>argp</parameter></paramdef>
</funcprototype>
</funcsynopsis>
</refsynopsisdiv>
<refsect1>
<title>Arguments</title>
<variablelist>
<varlistentry>
<term><parameter>fd</parameter></term>
<listitem>
<para>File descriptor returned by
<link linkend='cec-func-open'><function>open()</function></link>.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><parameter>request</parameter></term>
<listitem>
<para>CEC_ADAP_G_PHYS_ADDR, CEC_ADAP_S_PHYS_ADDR</para>
</listitem>
</varlistentry>
<varlistentry>
<term><parameter>argp</parameter></term>
<listitem>
<para></para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>Description</title>
<para>
Note: this documents the proposed CEC API. This API is not yet finalized and
is currently only available as a staging kernel module.
</para>
<para>To query the current physical address applications call the
<constant>CEC_ADAP_G_PHYS_ADDR</constant> ioctl with a pointer to an __u16
where the driver stores the physical address.</para>
<para>To set a new physical address applications store the physical address in
an __u16 and call the <constant>CEC_ADAP_S_PHYS_ADDR</constant> ioctl with a
pointer to this integer. <constant>CEC_ADAP_S_PHYS_ADDR</constant> is only
available if <constant>CEC_CAP_PHYS_ADDR</constant> is set (&ENOTTY; will be returned
otherwise). <constant>CEC_ADAP_S_PHYS_ADDR</constant>
can only be called by a file handle in initiator mode (see &CEC-S-MODE;), if not
&EBUSY; will be returned.</para>
<para>The physical address is a 16-bit number where each group of 4 bits
represent a digit of the physical address a.b.c.d where the most significant
4 bits represent 'a'. The CEC root device (usually the TV) has address 0.0.0.0.
Every device that is hooked up to an input of the TV has address a.0.0.0 (where
'a' is &ge; 1), devices hooked up to those in turn have addresses a.b.0.0, etc.
So a topology of up to 5 devices deep is supported. The physical address a
device shall use is stored in the EDID of the sink.</para>
<para>For example, the EDID for each HDMI input of the TV will have a different
physical address of the form a.0.0.0 that the sources will read out and use as
their physical address.</para>
</refsect1>
<refsect1>
&return-value;
</refsect1>
</refentry>
<refentry id="cec-ioc-g-event">
<refmeta>
<refentrytitle>ioctl CEC_DQEVENT</refentrytitle>
&manvol;
</refmeta>
<refnamediv>
<refname>CEC_DQEVENT</refname>
<refpurpose>Dequeue a CEC event</refpurpose>
</refnamediv>
<refsynopsisdiv>
<funcsynopsis>
<funcprototype>
<funcdef>int <function>ioctl</function></funcdef>
<paramdef>int <parameter>fd</parameter></paramdef>
<paramdef>int <parameter>request</parameter></paramdef>
<paramdef>struct cec_event *<parameter>argp</parameter></paramdef>
</funcprototype>
</funcsynopsis>
</refsynopsisdiv>
<refsect1>
<title>Arguments</title>
<variablelist>
<varlistentry>
<term><parameter>fd</parameter></term>
<listitem>
<para>File descriptor returned by
<link linkend='cec-func-open'><function>open()</function></link>.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><parameter>request</parameter></term>
<listitem>
<para>CEC_DQEVENT</para>
</listitem>
</varlistentry>
<varlistentry>
<term><parameter>argp</parameter></term>
<listitem>
<para></para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>Description</title>
<para>
Note: this documents the proposed CEC API. This API is not yet finalized and
is currently only available as a staging kernel module.
</para>
<para>CEC devices can send asynchronous events. These can be retrieved by calling
the <constant>CEC_DQEVENT</constant> ioctl. If the file descriptor is in non-blocking
mode and no event is pending, then it will return -1 and set errno to the &EAGAIN;.</para>
<para>The internal event queues are per-filehandle and per-event type. If there is
no more room in a queue then the last event is overwritten with the new one. This
means that intermediate results can be thrown away but that the latest event is always
available. This also means that is it possible to read two successive events that have
the same value (e.g. two CEC_EVENT_STATE_CHANGE events with the same state). In that
case the intermediate state changes were lost but it is guaranteed that the state
did change in between the two events.</para>
<table pgwide="1" frame="none" id="cec-event-state-change">
<title>struct <structname>cec_event_state_change</structname></title>
<tgroup cols="3">
&cs-str;
<tbody valign="top">
<row>
<entry>__u16</entry>
<entry><structfield>phys_addr</structfield></entry>
<entry>The current physical address.</entry>
</row>
<row>
<entry>__u16</entry>
<entry><structfield>log_addr_mask</structfield></entry>
<entry>The current set of claimed logical addresses.</entry>
</row>
</tbody>
</tgroup>
</table>
<table pgwide="1" frame="none" id="cec-event-lost-msgs">
<title>struct <structname>cec_event_lost_msgs</structname></title>
<tgroup cols="3">
&cs-str;
<tbody valign="top">
<row>
<entry>__u32</entry>
<entry><structfield>lost_msgs</structfield></entry>
<entry>Set to the number of lost messages since the filehandle
was opened or since the last time this event was dequeued for
this filehandle. The messages lost are the oldest messages. So
when a new message arrives and there is no more room, then the
oldest message is discarded to make room for the new one. The
internal size of the message queue guarantees that all messages
received in the last two seconds will be stored. Since messages
should be replied to within a second according to the CEC
specification, this is more than enough.
</entry>
</row>
</tbody>
</tgroup>
</table>
<table pgwide="1" frame="none" id="cec-event">
<title>struct <structname>cec_event</structname></title>
<tgroup cols="4">
&cs-str;
<tbody valign="top">
<row>
<entry>__u64</entry>
<entry><structfield>ts</structfield></entry>
<entry>Timestamp of the event in ns.</entry>
<entry></entry>
</row>
<row>
<entry>__u32</entry>
<entry><structfield>event</structfield></entry>
<entry>The CEC event type, see <xref linkend="cec-events" />.</entry>
<entry></entry>
</row>
<row>
<entry>__u32</entry>
<entry><structfield>flags</structfield></entry>
<entry>Event flags, see <xref linkend="cec-event-flags" />.</entry>
<entry></entry>
</row>
<row>
<entry>union</entry>
<entry>(anonymous)</entry>
<entry></entry>
<entry></entry>
</row>
<row>
<entry></entry>
<entry>struct cec_event_state_change</entry>
<entry><structfield>state_change</structfield></entry>
<entry>The new adapter state as sent by the <constant>CEC_EVENT_STATE_CHANGE</constant>
event.</entry>
</row>
<row>
<entry></entry>
<entry>struct cec_event_lost_msgs</entry>
<entry><structfield>lost_msgs</structfield></entry>
<entry>The number of lost messages as sent by the <constant>CEC_EVENT_LOST_MSGS</constant>
event.</entry>
</row>
</tbody>
</tgroup>
</table>
<table pgwide="1" frame="none" id="cec-events">
<title>CEC Events Types</title>
<tgroup cols="3">
&cs-def;
<tbody valign="top">
<row>
<entry><constant>CEC_EVENT_STATE_CHANGE</constant></entry>
<entry>1</entry>
<entry>Generated when the CEC Adapter's state changes. When open() is
called an initial event will be generated for that filehandle with the
CEC Adapter's state at that time.
</entry>
</row>
<row>
<entry><constant>CEC_EVENT_LOST_MSGS</constant></entry>
<entry>2</entry>
<entry>Generated if one or more CEC messages were lost because the
application didn't dequeue CEC messages fast enough.</entry>
</row>
</tbody>
</tgroup>
</table>
<table pgwide="1" frame="none" id="cec-event-flags">
<title>CEC Event Flags</title>
<tgroup cols="3">
&cs-def;
<tbody valign="top">
<row>
<entry><constant>CEC_EVENT_FL_INITIAL_VALUE</constant></entry>
<entry>1</entry>
<entry>Set for the initial events that are generated when the device is
opened. See the table above for which events do this. This allows
applications to learn the initial state of the CEC adapter at open()
time.</entry>
</row>
</tbody>
</tgroup>
</table>
</refsect1>
<refsect1>
&return-value;
</refsect1>
</refentry>
This diff is collapsed.
This diff is collapsed.
......@@ -75,7 +75,7 @@
</mediaobject>
</figure>
<para>The media infrastructure API was designed to control such
devices. It is divided into four parts.</para>
devices. It is divided into five parts.</para>
<para>The first part covers radio, video capture and output,
cameras, analog TV devices and codecs.</para>
<para>The second part covers the
......@@ -87,6 +87,7 @@
<xref linkend="fe-delivery-system-t" />.</para>
<para>The third part covers the Remote Controller API.</para>
<para>The fourth part covers the Media Controller API.</para>
<para>The fifth part covers the CEC (Consumer Electronics Control) API.</para>
<para>It should also be noted that a media device may also have audio
components, like mixers, PCM capture, PCM playback, etc, which
are controlled via ALSA API.</para>
......@@ -107,6 +108,9 @@
<part id="media_common">
&sub-media-controller;
</part>
<part id="cec">
&sub-cec-api;
</part>
<chapter id="gen_errors">
&sub-gen-errors;
......
This diff is collapsed.
* Samsung HDMI CEC driver
The HDMI CEC module is present is Samsung SoCs and its purpose is to
handle communication between HDMI connected devices over the CEC bus.
Required properties:
- compatible : value should be following
"samsung,s5p-cec"
- reg : Physical base address of the IP registers and length of memory
mapped region.
- interrupts : HDMI CEC interrupt number to the CPU.
- clocks : from common clock binding: handle to HDMI CEC clock.
- clock-names : from common clock binding: must contain "hdmicec",
corresponding to entry in the clocks property.
- samsung,syscon-phandle - phandle to the PMU system controller
Example:
hdmicec: cec@100B0000 {
compatible = "samsung,s5p-cec";
reg = <0x100B0000 0x200>;
interrupts = <0 114 0>;
clocks = <&clock CLK_HDMI_CEC>;
clock-names = "hdmicec";
samsung,syscon-phandle = <&pmu_system_controller>;
pinctrl-names = "default";
pinctrl-0 = <&hdmi_cec>;
status = "okay";
};
......@@ -74,7 +74,8 @@ Section 11: Cropping, Composing, Scaling
Section 12: Formats
Section 13: Capture Overlay
Section 14: Output Overlay
Section 15: Some Future Improvements
Section 15: CEC (Consumer Electronics Control)
Section 16: Some Future Improvements
Section 1: Configuring the driver
......@@ -364,7 +365,11 @@ For HDMI inputs it is possible to set the EDID. By default a simple EDID
is provided. You can only set the EDID for HDMI inputs. Internally, however,
the EDID is shared between all HDMI inputs.
No interpretation is done of the EDID data.
No interpretation is done of the EDID data with the exception of the
physical address. See the CEC section for more details.
There is a maximum of 15 HDMI inputs (if there are more, then they will be
reduced to 15) since that's the limitation of the EDID physical address.
Section 3: Video Output
......@@ -409,6 +414,9 @@ standard, and for all others a 1:1 pixel aspect ratio is returned.
An HDMI output has a valid EDID which can be obtained through VIDIOC_G_EDID.
There is a maximum of 15 HDMI outputs (if there are more, then they will be
reduced to 15) since that's the limitation of the EDID physical address. See
also the CEC section for more details.
Section 4: VBI Capture
----------------------
......@@ -1108,7 +1116,26 @@ capabilities will slow down the video loop considerably as a lot of checks have
to be done per pixel.
Section 15: Some Future Improvements
Section 15: CEC (Consumer Electronics Control)
----------------------------------------------
If there are HDMI inputs then a CEC adapter will be created that has
the same number of input ports. This is the equivalent of e.g. a TV that
has that number of inputs. Each HDMI output will also create a
CEC adapter that is hooked up to the corresponding input port, or (if there
are more outputs than inputs) is not hooked up at all. In other words,
this is the equivalent of hooking up each output device to an input port of
the TV. Any remaining output devices remain unconnected.
The EDID that each output reads reports a unique CEC physical address that is
based on the physical address of the EDID of the input. So if the EDID of the
receiver has physical address A.B.0.0, then each output will see an EDID
containing physical address A.B.C.0 where C is 1 to the number of inputs. If
there are more outputs than inputs then the remaining outputs have a CEC adapter
that is disabled and reports an invalid physical address.
Section 16: Some Future Improvements
------------------------------------
Just as a reminder and in no particular order:
......@@ -1121,8 +1148,6 @@ Just as a reminder and in no particular order:
- Fix sequence/field numbering when looping of video with alternate fields
- Add support for V4L2_CID_BG_COLOR for video outputs
- Add ARGB888 overlay support: better testing of the alpha channel
- Add custom DV timings support
- Add support for V4L2_DV_FL_REDUCED_FPS
- Improve pixel aspect support in the tpg code by passing a real v4l2_fract
- Use per-queue locks and/or per-device locks to improve throughput
- Add support to loop from a specific output to a specific input across
......@@ -1133,3 +1158,4 @@ Just as a reminder and in no particular order:
- Make a thread for the RDS generation, that would help in particular for the
"Controls" RDS Rx I/O Mode as the read-only RDS controls could be updated
in real-time.
- Changing the EDID should cause hotplug detect emulation to happen.
......@@ -1647,6 +1647,13 @@ L: linux-media@vger.kernel.org
S: Maintained
F: drivers/media/platform/s5p-tv/
ARM/SAMSUNG S5P SERIES HDMI CEC SUBSYSTEM SUPPORT
M: Kyungmin Park <kyungmin.park@samsung.com>
L: linux-arm-kernel@lists.infradead.org
L: linux-media@vger.kernel.org
S: Maintained
F: drivers/staging/media/platform/s5p-cec/
ARM/SAMSUNG S5P SERIES JPEG CODEC SUPPORT
M: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
M: Jacek Anaszewski <j.anaszewski@samsung.com>
......@@ -2852,6 +2859,22 @@ F: drivers/net/ieee802154/cc2520.c
F: include/linux/spi/cc2520.h
F: Documentation/devicetree/bindings/net/ieee802154/cc2520.txt
CEC DRIVER
M: Hans Verkuil <hans.verkuil@cisco.com>
L: linux-media@vger.kernel.org
T: git git://linuxtv.org/media_tree.git
W: http://linuxtv.org
S: Supported
F: Documentation/cec.txt
F: Documentation/DocBook/media/v4l/cec*
F: drivers/staging/media/cec/
F: drivers/media/cec-edid.c
F: drivers/media/rc/keymaps/rc-cec.c
F: include/media/cec.h
F: include/media/cec-edid.h
F: include/linux/cec.h
F: include/linux/cec-funcs.h
CELL BROADBAND ENGINE ARCHITECTURE
M: Arnd Bergmann <arnd@arndb.de>
L: linuxppc-dev@lists.ozlabs.org
......
......@@ -80,6 +80,9 @@ config MEDIA_RC_SUPPORT
Say Y when you have a TV or an IR device.
config MEDIA_CEC_EDID
tristate
#
# Media controller
# Selectable only for webcam/grabbers, as other drivers don't use it
......
......@@ -2,6 +2,8 @@
# Makefile for the kernel multimedia device drivers.
#
obj-$(CONFIG_MEDIA_CEC_EDID) += cec-edid.o
media-objs := media-device.o media-devnode.o media-entity.o
#
......
/*
* cec-edid - HDMI Consumer Electronics Control EDID & CEC helper functions
*
* Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
*
* This program is free software; you may redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <media/cec-edid.h>
/*
* This EDID is expected to be a CEA-861 compliant, which means that there are
* at least two blocks and one or more of the extensions blocks are CEA-861
* blocks.
*
* The returned location is guaranteed to be < size - 1.
*/
static unsigned int cec_get_edid_spa_location(const u8 *edid, unsigned int size)
{
unsigned int blocks = size / 128;
unsigned int block;
u8 d;
/* Sanity check: at least 2 blocks and a multiple of the block size */
if (blocks < 2 || size % 128)
return 0;
/*
* If there are fewer extension blocks than the size, then update
* 'blocks'. It is allowed to have more extension blocks than the size,
* since some hardware can only read e.g. 256 bytes of the EDID, even
* though more blocks are present. The first CEA-861 extension block
* should normally be in block 1 anyway.
*/
if (edid[0x7e] + 1 < blocks)
blocks = edid[0x7e] + 1;
for (block = 1; block < blocks; block++) {
unsigned int offset = block * 128;
/* Skip any non-CEA-861 extension blocks */
if (edid[offset] != 0x02 || edid[offset + 1] != 0x03)
continue;
/* search Vendor Specific Data Block (tag 3) */
d = edid[offset + 2] & 0x7f;
/* Check if there are Data Blocks */
if (d <= 4)
continue;
if (d > 4) {
unsigned int i = offset + 4;
unsigned int end = offset + d;
/* Note: 'end' is always < 'size' */
do {
u8 tag = edid[i] >> 5;
u8 len = edid[i] & 0x1f;
if (tag == 3 && len >= 5 && i + len <= end)
return i + 4;
i += len + 1;
} while (i < end);
}
}
return 0;
}
u16 cec_get_edid_phys_addr(const u8 *edid, unsigned int size,
unsigned int *offset)
{
unsigned int loc = cec_get_edid_spa_location(edid, size);
if (offset)
*offset = loc;
if (loc == 0)
return CEC_PHYS_ADDR_INVALID;
return (edid[loc] << 8) | edid[loc + 1];
}
EXPORT_SYMBOL_GPL(cec_get_edid_phys_addr);
void cec_set_edid_phys_addr(u8 *edid, unsigned int size, u16 phys_addr)
{
unsigned int loc = cec_get_edid_spa_location(edid, size);
u8 sum = 0;
unsigned int i;
if (loc == 0)
return;
edid[loc] = phys_addr >> 8;
edid[loc + 1] = phys_addr & 0xff;
loc &= ~0x7f;
/* update the checksum */
for (i = loc; i < loc + 127; i++)
sum += edid[i];
edid[i] = 256 - sum;
}
EXPORT_SYMBOL_GPL(cec_set_edid_phys_addr);
u16 cec_phys_addr_for_input(u16 phys_addr, u8 input)
{
/* Check if input is sane */
if (WARN_ON(input == 0 || input > 0xf))
return CEC_PHYS_ADDR_INVALID;
if (phys_addr == 0)
return input << 12;
if ((phys_addr & 0x0fff) == 0)
return phys_addr | (input << 8);
if ((phys_addr & 0x00ff) == 0)
return phys_addr | (input << 4);
if ((phys_addr & 0x000f) == 0)
return phys_addr | input;
/*
* All nibbles are used so no valid physical addresses can be assigned
* to the input.
*/
return CEC_PHYS_ADDR_INVALID;
}
EXPORT_SYMBOL_GPL(cec_phys_addr_for_input);
int cec_phys_addr_validate(u16 phys_addr, u16 *parent, u16 *port)
{
int i;
if (parent)
*parent = phys_addr;
if (port)
*port = 0;
if (phys_addr == CEC_PHYS_ADDR_INVALID)
return 0;
for (i = 0; i < 16; i += 4)
if (phys_addr & (0xf << i))
break;
if (i == 16)
return 0;
if (parent)
*parent = phys_addr & (0xfff0 << i);
if (port)
*port = (phys_addr >> i) & 0xf;
for (i += 4; i < 16; i += 4)
if ((phys_addr & (0xf << i)) == 0)
return -EINVAL;
return 0;
}
EXPORT_SYMBOL_GPL(cec_phys_addr_validate);
MODULE_AUTHOR("Hans Verkuil <hans.verkuil@cisco.com>");
MODULE_DESCRIPTION("CEC EDID helper functions");
MODULE_LICENSE("GPL");
......@@ -209,6 +209,7 @@ config VIDEO_ADV7604
depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API
depends on GPIOLIB || COMPILE_TEST
select HDMI
select MEDIA_CEC_EDID
---help---
Support for the Analog Devices ADV7604 video decoder.
......@@ -218,10 +219,18 @@ config VIDEO_ADV7604
To compile this driver as a module, choose M here: the
module will be called adv7604.
config VIDEO_ADV7604_CEC
bool "Enable Analog Devices ADV7604 CEC support"
depends on VIDEO_ADV7604 && MEDIA_CEC
---help---
When selected the adv7604 will support the optional
HDMI CEC feature.
config VIDEO_ADV7842
tristate "Analog Devices ADV7842 decoder"
depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API
select HDMI
select MEDIA_CEC_EDID
---help---
Support for the Analog Devices ADV7842 video decoder.
......@@ -231,6 +240,13 @@ config VIDEO_ADV7842
To compile this driver as a module, choose M here: the
module will be called adv7842.
config VIDEO_ADV7842_CEC
bool "Enable Analog Devices ADV7842 CEC support"
depends on VIDEO_ADV7842 && MEDIA_CEC
---help---
When selected the adv7842 will support the optional
HDMI CEC feature.
config VIDEO_BT819
tristate "BT819A VideoStream decoder"
depends on VIDEO_V4L2 && I2C
......@@ -447,6 +463,7 @@ config VIDEO_ADV7511
tristate "Analog Devices ADV7511 encoder"
depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API
select HDMI
select MEDIA_CEC_EDID
---help---
Support for the Analog Devices ADV7511 video encoder.
......@@ -455,6 +472,13 @@ config VIDEO_ADV7511
To compile this driver as a module, choose M here: the
module will be called adv7511.
config VIDEO_ADV7511_CEC
bool "Enable Analog Devices ADV7511 CEC support"
depends on VIDEO_ADV7511 && MEDIA_CEC
---help---
When selected the adv7511 will support the optional
HDMI CEC feature.
config VIDEO_AD9389B
tristate "Analog Devices AD9389B encoder"
depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -6,6 +6,7 @@ config VIDEO_VIVID
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
select MEDIA_CEC_EDID
select VIDEOBUF2_VMALLOC
select VIDEO_V4L2_TPG
default n
......@@ -22,6 +23,13 @@ config VIDEO_VIVID
Say Y here if you want to test video apps or debug V4L devices.
When in doubt, say N.
config VIDEO_VIVID_CEC
bool "Enable CEC emulation support"
depends on VIDEO_VIVID && MEDIA_CEC
---help---
When selected the vivid module will emulate the optional
HDMI CEC feature.
config VIDEO_VIVID_MAX_DEVS
int "Maximum number of devices"
depends on VIDEO_VIVID
......
......@@ -3,4 +3,8 @@ vivid-objs := vivid-core.o vivid-ctrls.o vivid-vid-common.o vivid-vbi-gen.o \
vivid-radio-rx.o vivid-radio-tx.o vivid-radio-common.o \
vivid-rds-gen.o vivid-sdr-cap.o vivid-vbi-cap.o vivid-vbi-out.o \
vivid-osd.o
ifeq ($(CONFIG_VIDEO_VIVID_CEC),y)
vivid-objs += vivid-cec.o
endif
obj-$(CONFIG_VIDEO_VIVID) += vivid.o
/*
* vivid-cec.c - A Virtual Video Test Driver, cec emulation
*
* Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
*
* This program is free software; you may redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <media/cec.h>
#include "vivid-core.h"
#include "vivid-cec.h"
void vivid_cec_bus_free_work(struct vivid_dev *dev)
{
spin_lock(&dev->cec_slock);
while (!list_empty(&dev->cec_work_list)) {
struct vivid_cec_work *cw =
list_first_entry(&dev->cec_work_list,
struct vivid_cec_work, list);
spin_unlock(&dev->cec_slock);
cancel_delayed_work_sync(&cw->work);
spin_lock(&dev->cec_slock);
list_del(&cw->list);
cec_transmit_done(cw->adap, CEC_TX_STATUS_LOW_DRIVE, 0, 0, 1, 0);
kfree(cw);
}
spin_unlock(&dev->cec_slock);
}
static struct cec_adapter *vivid_cec_find_dest_adap(struct vivid_dev *dev,
struct cec_adapter *adap,
u8 dest)
{
unsigned int i;
if (dest >= 0xf)
return NULL;
if (adap != dev->cec_rx_adap && dev->cec_rx_adap &&
dev->cec_rx_adap->is_configured &&
cec_has_log_addr(dev->cec_rx_adap, dest))
return dev->cec_rx_adap;
for (i = 0; i < MAX_OUTPUTS && dev->cec_tx_adap[i]; i++) {
if (adap == dev->cec_tx_adap[i])
continue;
if (!dev->cec_tx_adap[i]->is_configured)
continue;
if (cec_has_log_addr(dev->cec_tx_adap[i], dest))
return dev->cec_tx_adap[i];
}
return NULL;
}
static void vivid_cec_xfer_done_worker(struct work_struct *work)
{
struct vivid_cec_work *cw =
container_of(work, struct vivid_cec_work, work.work);
struct vivid_dev *dev = cw->dev;
struct cec_adapter *adap = cw->adap;
bool is_poll = cw->msg.len == 1;
u8 dest = cec_msg_destination(&cw->msg);
struct cec_adapter *dest_adap = NULL;
bool valid_dest;
unsigned int i;
valid_dest = cec_msg_is_broadcast(&cw->msg);
if (!valid_dest) {
dest_adap = vivid_cec_find_dest_adap(dev, adap, dest);
if (dest_adap)
valid_dest = true;
}
cw->tx_status = valid_dest ? CEC_TX_STATUS_OK : CEC_TX_STATUS_NACK;
spin_lock(&dev->cec_slock);
dev->cec_xfer_time_jiffies = 0;
dev->cec_xfer_start_jiffies = 0;
list_del(&cw->list);
spin_unlock(&dev->cec_slock);
cec_transmit_done(cw->adap, cw->tx_status, 0, valid_dest ? 0 : 1, 0, 0);
if (!is_poll && dest_adap) {
/* Directed message */
cec_received_msg(dest_adap, &cw->msg);
} else if (!is_poll && valid_dest) {
/* Broadcast message */
if (adap != dev->cec_rx_adap &&
dev->cec_rx_adap->log_addrs.log_addr_mask)
cec_received_msg(dev->cec_rx_adap, &cw->msg);
for (i = 0; i < MAX_OUTPUTS && dev->cec_tx_adap[i]; i++) {
if (adap == dev->cec_tx_adap[i] ||
!dev->cec_tx_adap[i]->log_addrs.log_addr_mask)
continue;
cec_received_msg(dev->cec_tx_adap[i], &cw->msg);
}
}
kfree(cw);
}
static void vivid_cec_xfer_try_worker(struct work_struct *work)
{
struct vivid_cec_work *cw =
container_of(work, struct vivid_cec_work, work.work);
struct vivid_dev *dev = cw->dev;
spin_lock(&dev->cec_slock);
if (dev->cec_xfer_time_jiffies) {
list_del(&cw->list);
spin_unlock(&dev->cec_slock);
cec_transmit_done(cw->adap, CEC_TX_STATUS_ARB_LOST, 1, 0, 0, 0);
kfree(cw);
} else {
INIT_DELAYED_WORK(&cw->work, vivid_cec_xfer_done_worker);
dev->cec_xfer_start_jiffies = jiffies;
dev->cec_xfer_time_jiffies = usecs_to_jiffies(cw->usecs);
spin_unlock(&dev->cec_slock);
schedule_delayed_work(&cw->work, dev->cec_xfer_time_jiffies);
}
}
static int vivid_cec_adap_enable(struct cec_adapter *adap, bool enable)
{
return 0;
}
static int vivid_cec_adap_log_addr(struct cec_adapter *adap, u8 log_addr)
{
return 0;
}
/*
* One data bit takes 2400 us, each byte needs 10 bits so that's 24000 us
* per byte.
*/
#define USECS_PER_BYTE 24000
static int vivid_cec_adap_transmit(struct cec_adapter *adap, u8 attempts,
u32 signal_free_time, struct cec_msg *msg)
{
struct vivid_dev *dev = adap->priv;
struct vivid_cec_work *cw = kzalloc(sizeof(*cw), GFP_KERNEL);
long delta_jiffies = 0;
if (cw == NULL)
return -ENOMEM;
cw->dev = dev;
cw->adap = adap;
cw->usecs = CEC_FREE_TIME_TO_USEC(signal_free_time) +
msg->len * USECS_PER_BYTE;
cw->msg = *msg;
spin_lock(&dev->cec_slock);
list_add(&cw->list, &dev->cec_work_list);
if (dev->cec_xfer_time_jiffies == 0) {
INIT_DELAYED_WORK(&cw->work, vivid_cec_xfer_done_worker);
dev->cec_xfer_start_jiffies = jiffies;
dev->cec_xfer_time_jiffies = usecs_to_jiffies(cw->usecs);
delta_jiffies = dev->cec_xfer_time_jiffies;
} else {
INIT_DELAYED_WORK(&cw->work, vivid_cec_xfer_try_worker);
delta_jiffies = dev->cec_xfer_start_jiffies +
dev->cec_xfer_time_jiffies - jiffies;
}
spin_unlock(&dev->cec_slock);
schedule_delayed_work(&cw->work, delta_jiffies < 0 ? 0 : delta_jiffies);
return 0;
}
static int vivid_received(struct cec_adapter *adap, struct cec_msg *msg)
{
struct vivid_dev *dev = adap->priv;
struct cec_msg reply;
u8 dest = cec_msg_destination(msg);
u16 pa;
u8 disp_ctl;
char osd[14];
if (cec_msg_is_broadcast(msg))
dest = adap->log_addrs.log_addr[0];
cec_msg_init(&reply, dest, cec_msg_initiator(msg));
switch (cec_msg_opcode(msg)) {
case CEC_MSG_SET_STREAM_PATH:
if (cec_is_sink(adap))
return -ENOMSG;
cec_ops_set_stream_path(msg, &pa);
if (pa != adap->phys_addr)
return -ENOMSG;
cec_msg_active_source(&reply, adap->phys_addr);
cec_transmit_msg(adap, &reply, false);
break;
case CEC_MSG_SET_OSD_STRING:
if (!cec_is_sink(adap))
return -ENOMSG;
cec_ops_set_osd_string(msg, &disp_ctl, osd);
switch (disp_ctl) {
case CEC_OP_DISP_CTL_DEFAULT:
strcpy(dev->osd, osd);
dev->osd_jiffies = jiffies;
break;
case CEC_OP_DISP_CTL_UNTIL_CLEARED:
strcpy(dev->osd, osd);
dev->osd_jiffies = 0;
break;
case CEC_OP_DISP_CTL_CLEAR:
dev->osd[0] = 0;
dev->osd_jiffies = 0;
break;
default:
cec_msg_feature_abort(&reply, cec_msg_opcode(msg),
CEC_OP_ABORT_INVALID_OP);
cec_transmit_msg(adap, &reply, false);
break;
}
break;
default:
return -ENOMSG;
}
return 0;
}
static const struct cec_adap_ops vivid_cec_adap_ops = {
.adap_enable = vivid_cec_adap_enable,
.adap_log_addr = vivid_cec_adap_log_addr,
.adap_transmit = vivid_cec_adap_transmit,
.received = vivid_received,
};
struct cec_adapter *vivid_cec_alloc_adap(struct vivid_dev *dev,
unsigned int idx,
struct device *parent,
bool is_source)
{
char name[sizeof(dev->vid_out_dev.name) + 2];
u32 caps = CEC_CAP_TRANSMIT | CEC_CAP_LOG_ADDRS |
CEC_CAP_PASSTHROUGH | CEC_CAP_RC;
snprintf(name, sizeof(name), "%s%d",
is_source ? dev->vid_out_dev.name : dev->vid_cap_dev.name,
idx);
return cec_allocate_adapter(&vivid_cec_adap_ops, dev,
name, caps, 1, parent);
}
/*
* vivid-cec.h - A Virtual Video Test Driver, cec emulation
*
* Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
*
* This program is free software; you may redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifdef CONFIG_VIDEO_VIVID_CEC
struct cec_adapter *vivid_cec_alloc_adap(struct vivid_dev *dev,
unsigned int idx,
struct device *parent,
bool is_source);
void vivid_cec_bus_free_work(struct vivid_dev *dev);
#else
static inline void vivid_cec_bus_free_work(struct vivid_dev *dev)
{
}
#endif
......@@ -46,6 +46,7 @@
#include "vivid-vbi-cap.h"
#include "vivid-vbi-out.h"
#include "vivid-osd.h"
#include "vivid-cec.h"
#include "vivid-ctrls.h"
#define VIVID_MODULE_NAME "vivid"
......@@ -684,6 +685,11 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
dev->input_name_counter[i] = in_type_counter[dev->input_type[i]]++;
}
dev->has_audio_inputs = in_type_counter[TV] && in_type_counter[SVID];
if (in_type_counter[HDMI] == 16) {
/* The CEC physical address only allows for max 15 inputs */
in_type_counter[HDMI]--;
dev->num_inputs--;
}
/* how many outputs do we have and of what type? */
dev->num_outputs = num_outputs[inst];
......@@ -696,6 +702,15 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
dev->output_name_counter[i] = out_type_counter[dev->output_type[i]]++;
}
dev->has_audio_outputs = out_type_counter[SVID];
if (out_type_counter[HDMI] == 16) {
/*
* The CEC physical address only allows for max 15 inputs,
* so outputs are also limited to 15 to allow for easy
* CEC output to input mapping.
*/
out_type_counter[HDMI]--;
dev->num_outputs--;
}
/* do we create a video capture device? */
dev->has_vid_cap = node_type & 0x0001;
......@@ -1010,6 +1025,17 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
INIT_LIST_HEAD(&dev->vbi_out_active);
INIT_LIST_HEAD(&dev->sdr_cap_active);
INIT_LIST_HEAD(&dev->cec_work_list);
spin_lock_init(&dev->cec_slock);
/*
* Same as create_singlethread_workqueue, but now I can use the
* string formatting of alloc_ordered_workqueue.
*/
dev->cec_workqueue =
alloc_ordered_workqueue("vivid-%03d-cec", WQ_MEM_RECLAIM, inst);
if (!dev->cec_workqueue)
goto unreg_dev;
/* start creating the vb2 queues */
if (dev->has_vid_cap) {
/* initialize vid_cap queue */
......@@ -1117,7 +1143,8 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
/* finally start creating the device nodes */
if (dev->has_vid_cap) {
vfd = &dev->vid_cap_dev;
strlcpy(vfd->name, "vivid-vid-cap", sizeof(vfd->name));
snprintf(vfd->name, sizeof(vfd->name),
"vivid-%03d-vid-cap", inst);
vfd->fops = &vivid_fops;
vfd->ioctl_ops = &vivid_ioctl_ops;
vfd->device_caps = dev->vid_cap_caps;
......@@ -1133,6 +1160,27 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
vfd->lock = &dev->mutex;
video_set_drvdata(vfd, dev);
#ifdef CONFIG_VIDEO_VIVID_CEC
if (in_type_counter[HDMI]) {
struct cec_adapter *adap;
adap = vivid_cec_alloc_adap(dev, 0, &pdev->dev, false);
ret = PTR_ERR_OR_ZERO(adap);
if (ret < 0)
goto unreg_dev;
dev->cec_rx_adap = adap;
ret = cec_register_adapter(adap);
if (ret < 0) {
cec_delete_adapter(adap);
dev->cec_rx_adap = NULL;
goto unreg_dev;
}
cec_s_phys_addr(adap, 0, false);
v4l2_info(&dev->v4l2_dev, "CEC adapter %s registered for HDMI input %d\n",
dev_name(&adap->devnode.dev), i);
}
#endif
ret = video_register_device(vfd, VFL_TYPE_GRABBER, vid_cap_nr[inst]);
if (ret < 0)
goto unreg_dev;
......@@ -1141,8 +1189,13 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
}
if (dev->has_vid_out) {
#ifdef CONFIG_VIDEO_VIVID_CEC
unsigned int bus_cnt = 0;
#endif
vfd = &dev->vid_out_dev;
strlcpy(vfd->name, "vivid-vid-out", sizeof(vfd->name));
snprintf(vfd->name, sizeof(vfd->name),
"vivid-%03d-vid-out", inst);
vfd->vfl_dir = VFL_DIR_TX;
vfd->fops = &vivid_fops;
vfd->ioctl_ops = &vivid_ioctl_ops;
......@@ -1159,6 +1212,35 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
vfd->lock = &dev->mutex;
video_set_drvdata(vfd, dev);
#ifdef CONFIG_VIDEO_VIVID_CEC
for (i = 0; i < dev->num_outputs; i++) {
struct cec_adapter *adap;
if (dev->output_type[i] != HDMI)
continue;
dev->cec_output2bus_map[i] = bus_cnt;
adap = vivid_cec_alloc_adap(dev, bus_cnt,
&pdev->dev, true);
ret = PTR_ERR_OR_ZERO(adap);
if (ret < 0)
goto unreg_dev;
dev->cec_tx_adap[bus_cnt] = adap;
ret = cec_register_adapter(adap);
if (ret < 0) {
cec_delete_adapter(adap);
dev->cec_tx_adap[bus_cnt] = NULL;
goto unreg_dev;
}
bus_cnt++;
if (bus_cnt <= in_type_counter[HDMI])
cec_s_phys_addr(adap, bus_cnt << 12, false);
else
cec_s_phys_addr(adap, 0x1000, false);
v4l2_info(&dev->v4l2_dev, "CEC adapter %s registered for HDMI output %d\n",
dev_name(&adap->devnode.dev), i);
}
#endif
ret = video_register_device(vfd, VFL_TYPE_GRABBER, vid_out_nr[inst]);
if (ret < 0)
goto unreg_dev;
......@@ -1168,7 +1250,8 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
if (dev->has_vbi_cap) {
vfd = &dev->vbi_cap_dev;
strlcpy(vfd->name, "vivid-vbi-cap", sizeof(vfd->name));
snprintf(vfd->name, sizeof(vfd->name),
"vivid-%03d-vbi-cap", inst);
vfd->fops = &vivid_fops;
vfd->ioctl_ops = &vivid_ioctl_ops;
vfd->device_caps = dev->vbi_cap_caps;
......@@ -1191,7 +1274,8 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
if (dev->has_vbi_out) {
vfd = &dev->vbi_out_dev;
strlcpy(vfd->name, "vivid-vbi-out", sizeof(vfd->name));
snprintf(vfd->name, sizeof(vfd->name),
"vivid-%03d-vbi-out", inst);
vfd->vfl_dir = VFL_DIR_TX;
vfd->fops = &vivid_fops;
vfd->ioctl_ops = &vivid_ioctl_ops;
......@@ -1215,7 +1299,8 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
if (dev->has_sdr_cap) {
vfd = &dev->sdr_cap_dev;
strlcpy(vfd->name, "vivid-sdr-cap", sizeof(vfd->name));
snprintf(vfd->name, sizeof(vfd->name),
"vivid-%03d-sdr-cap", inst);
vfd->fops = &vivid_fops;
vfd->ioctl_ops = &vivid_ioctl_ops;
vfd->device_caps = dev->sdr_cap_caps;
......@@ -1234,7 +1319,8 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
if (dev->has_radio_rx) {
vfd = &dev->radio_rx_dev;
strlcpy(vfd->name, "vivid-rad-rx", sizeof(vfd->name));
snprintf(vfd->name, sizeof(vfd->name),
"vivid-%03d-rad-rx", inst);
vfd->fops = &vivid_radio_fops;
vfd->ioctl_ops = &vivid_ioctl_ops;
vfd->device_caps = dev->radio_rx_caps;
......@@ -1252,7 +1338,8 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
if (dev->has_radio_tx) {
vfd = &dev->radio_tx_dev;
strlcpy(vfd->name, "vivid-rad-tx", sizeof(vfd->name));
snprintf(vfd->name, sizeof(vfd->name),
"vivid-%03d-rad-tx", inst);
vfd->vfl_dir = VFL_DIR_TX;
vfd->fops = &vivid_radio_fops;
vfd->ioctl_ops = &vivid_ioctl_ops;
......@@ -1282,6 +1369,13 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
video_unregister_device(&dev->vbi_cap_dev);
video_unregister_device(&dev->vid_out_dev);
video_unregister_device(&dev->vid_cap_dev);
cec_unregister_adapter(dev->cec_rx_adap);
for (i = 0; i < MAX_OUTPUTS; i++)
cec_unregister_adapter(dev->cec_tx_adap[i]);
if (dev->cec_workqueue) {
vivid_cec_bus_free_work(dev);
destroy_workqueue(dev->cec_workqueue);
}
free_dev:
v4l2_device_put(&dev->v4l2_dev);
return ret;
......@@ -1331,8 +1425,7 @@ static int vivid_probe(struct platform_device *pdev)
static int vivid_remove(struct platform_device *pdev)
{
struct vivid_dev *dev;
unsigned i;
unsigned int i, j;
for (i = 0; i < n_devs; i++) {
dev = vivid_devs[i];
......@@ -1380,6 +1473,13 @@ static int vivid_remove(struct platform_device *pdev)
unregister_framebuffer(&dev->fb_info);
vivid_fb_release_buffers(dev);
}
cec_unregister_adapter(dev->cec_rx_adap);
for (j = 0; j < MAX_OUTPUTS; j++)
cec_unregister_adapter(dev->cec_tx_adap[j]);
if (dev->cec_workqueue) {
vivid_cec_bus_free_work(dev);
destroy_workqueue(dev->cec_workqueue);
}
v4l2_device_put(&dev->v4l2_dev);
vivid_devs[i] = NULL;
}
......
......@@ -21,6 +21,8 @@
#define _VIVID_CORE_H_
#include <linux/fb.h>
#include <linux/workqueue.h>
#include <media/cec.h>
#include <media/videobuf2-v4l2.h>
#include <media/v4l2-device.h>
#include <media/v4l2-dev.h>
......@@ -132,6 +134,17 @@ enum vivid_colorspace {
#define VIVID_INVALID_SIGNAL(mode) \
((mode) == NO_SIGNAL || (mode) == NO_LOCK || (mode) == OUT_OF_RANGE)
struct vivid_cec_work {
struct list_head list;
struct delayed_work work;
struct cec_adapter *adap;
struct vivid_dev *dev;
unsigned int usecs;
unsigned int timeout_ms;
u8 tx_status;
struct cec_msg msg;
};
struct vivid_dev {
unsigned inst;
struct v4l2_device v4l2_dev;
......@@ -497,6 +510,20 @@ struct vivid_dev {
/* Shared between radio receiver and transmitter */
bool radio_rds_loop;
struct timespec radio_rds_init_ts;
/* CEC */
struct cec_adapter *cec_rx_adap;
struct cec_adapter *cec_tx_adap[MAX_OUTPUTS];
struct workqueue_struct *cec_workqueue;
spinlock_t cec_slock;
struct list_head cec_work_list;
unsigned int cec_xfer_time_jiffies;
unsigned long cec_xfer_start_jiffies;
u8 cec_output2bus_map[MAX_OUTPUTS];
/* CEC OSD String */
char osd[14];
unsigned long osd_jiffies;
};
static inline bool vivid_is_webcam(const struct vivid_dev *dev)
......
......@@ -552,6 +552,19 @@ static void vivid_fillbuff(struct vivid_dev *dev, struct vivid_buffer *buf)
snprintf(str, sizeof(str), " button pressed!");
tpg_gen_text(tpg, basep, line++ * line_height, 16, str);
}
if (dev->osd[0]) {
if (vivid_is_hdmi_cap(dev)) {
snprintf(str, sizeof(str),
" OSD \"%s\"", dev->osd);
tpg_gen_text(tpg, basep, line++ * line_height,
16, str);
}
if (dev->osd_jiffies &&
time_is_before_jiffies(dev->osd_jiffies + 5 * HZ)) {
dev->osd[0] = 0;
dev->osd_jiffies = 0;
}
}
}
/*
......
......@@ -1695,6 +1695,9 @@ int vidioc_s_edid(struct file *file, void *_fh,
struct v4l2_edid *edid)
{
struct vivid_dev *dev = video_drvdata(file);
u16 phys_addr;
unsigned int i;
int ret;
memset(edid->reserved, 0, sizeof(edid->reserved));
if (edid->pad >= dev->num_inputs)
......@@ -1703,14 +1706,32 @@ int vidioc_s_edid(struct file *file, void *_fh,
return -EINVAL;
if (edid->blocks == 0) {
dev->edid_blocks = 0;
return 0;
phys_addr = CEC_PHYS_ADDR_INVALID;
goto set_phys_addr;
}
if (edid->blocks > dev->edid_max_blocks) {
edid->blocks = dev->edid_max_blocks;
return -E2BIG;
}
phys_addr = cec_get_edid_phys_addr(edid->edid, edid->blocks * 128, NULL);
ret = cec_phys_addr_validate(phys_addr, &phys_addr, NULL);
if (ret)
return ret;
if (vb2_is_busy(&dev->vb_vid_cap_q))
return -EBUSY;
dev->edid_blocks = edid->blocks;
memcpy(dev->edid, edid->edid, edid->blocks * 128);
set_phys_addr:
/* TODO: a proper hotplug detect cycle should be emulated here */
cec_s_phys_addr(dev->cec_rx_adap, phys_addr, false);
for (i = 0; i < MAX_OUTPUTS && dev->cec_tx_adap[i]; i++)
cec_s_phys_addr(dev->cec_tx_adap[i],
cec_phys_addr_for_input(phys_addr, i + 1),
false);
return 0;
}
......
......@@ -811,6 +811,7 @@ int vidioc_g_edid(struct file *file, void *_fh,
{
struct vivid_dev *dev = video_drvdata(file);
struct video_device *vdev = video_devdata(file);
struct cec_adapter *adap;
memset(edid->reserved, 0, sizeof(edid->reserved));
if (vdev->vfl_dir == VFL_DIR_RX) {
......@@ -818,11 +819,16 @@ int vidioc_g_edid(struct file *file, void *_fh,
return -EINVAL;
if (dev->input_type[edid->pad] != HDMI)
return -EINVAL;
adap = dev->cec_rx_adap;
} else {
unsigned int bus_idx;
if (edid->pad >= dev->num_outputs)
return -EINVAL;
if (dev->output_type[edid->pad] != HDMI)
return -EINVAL;
bus_idx = dev->cec_output2bus_map[edid->pad];
adap = dev->cec_tx_adap[bus_idx];
}
if (edid->start_block == 0 && edid->blocks == 0) {
edid->blocks = dev->edid_blocks;
......@@ -835,5 +841,6 @@ int vidioc_g_edid(struct file *file, void *_fh,
if (edid->start_block + edid->blocks > dev->edid_blocks)
edid->blocks = dev->edid_blocks - edid->start_block;
memcpy(edid->edid, dev->edid, edid->blocks * 128);
cec_set_edid_phys_addr(edid->edid, edid->blocks * 128, adap->phys_addr);
return 0;
}
......@@ -810,6 +810,7 @@ static const struct {
{ RC_BIT_SHARP, "sharp", "ir-sharp-decoder" },
{ RC_BIT_MCE_KBD, "mce_kbd", "ir-mce_kbd-decoder" },
{ RC_BIT_XMP, "xmp", "ir-xmp-decoder" },
{ RC_BIT_CEC, "cec", NULL },
};
/**
......
......@@ -21,6 +21,8 @@ if STAGING_MEDIA
# Please keep them in alphabetic order
source "drivers/staging/media/bcm2048/Kconfig"
source "drivers/staging/media/cec/Kconfig"
source "drivers/staging/media/cxd2099/Kconfig"
source "drivers/staging/media/davinci_vpfe/Kconfig"
......@@ -29,6 +31,8 @@ source "drivers/staging/media/omap4iss/Kconfig"
source "drivers/staging/media/tw686x-kh/Kconfig"
source "drivers/staging/media/s5p-cec/Kconfig"
# Keep LIRC at the end, as it has sub-menus
source "drivers/staging/media/lirc/Kconfig"
......
obj-$(CONFIG_I2C_BCM2048) += bcm2048/
obj-$(CONFIG_MEDIA_CEC) += cec/
obj-$(CONFIG_VIDEO_SAMSUNG_S5P_CEC) += s5p-cec/
obj-$(CONFIG_DVB_CXD2099) += cxd2099/
obj-$(CONFIG_LIRC_STAGING) += lirc/
obj-$(CONFIG_VIDEO_DM365_VPFE) += davinci_vpfe/
......
config MEDIA_CEC
tristate "CEC API (EXPERIMENTAL)"
select MEDIA_CEC_EDID
---help---
Enable the CEC API.
To compile this driver as a module, choose M here: the
module will be called cec.
config MEDIA_CEC_DEBUG
bool "CEC debugfs interface (EXPERIMENTAL)"
depends on MEDIA_CEC && DEBUG_FS
---help---
Turns on the DebugFS interface for CEC devices.
cec-objs := cec-core.o cec-adap.o cec-api.o
obj-$(CONFIG_MEDIA_CEC) += cec.o
The reason why cec.c is still in staging is that I would like
to have a bit more confidence in the uABI. The kABI is fine,
no problem there, but I would like to let the public API mature
a bit.
Once I'm confident that I didn't miss anything then the cec.c source
can move to drivers/media and the linux/cec.h and linux/cec-funcs.h
headers can move to uapi/linux and added to uapi/linux/Kbuild to make
them public.
Hopefully this will happen later in 2016.
Other TODOs:
- Add a flag to inhibit passing CEC RC messages to the rc subsystem.
Applications should be able to choose this when calling S_LOG_ADDRS.
- Convert cec.txt to sphinx.
- If the reply field of cec_msg is set then when the reply arrives it
is only sent to the filehandle that transmitted the original message
and not to any followers. Should this behavior change or perhaps
controlled through a cec_msg flag?
- Should CEC_LOG_ADDR_TYPE_SPECIFIC be replaced by TYPE_2ND_TV and TYPE_PROCESSOR?
And also TYPE_SWITCH and TYPE_CDC_ONLY in addition to the TYPE_UNREGISTERED?
This should give the framework more information about the device type
since SPECIFIC and UNREGISTERED give no useful information.
Hans Verkuil <hans.verkuil@cisco.com>
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
/*
* cec-priv.h - HDMI Consumer Electronics Control internal header
*
* Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
*
* This program is free software; you may redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef _CEC_PRIV_H
#define _CEC_PRIV_H
#include <linux/cec-funcs.h>
#include <media/cec.h>
#define dprintk(lvl, fmt, arg...) \
do { \
if (lvl <= cec_debug) \
pr_info("cec-%s: " fmt, adap->name, ## arg); \
} while (0)
/* devnode to cec_adapter */
#define to_cec_adapter(node) container_of(node, struct cec_adapter, devnode)
/* cec-core.c */
extern int cec_debug;
int cec_get_device(struct cec_devnode *devnode);
void cec_put_device(struct cec_devnode *devnode);
/* cec-adap.c */
int cec_monitor_all_cnt_inc(struct cec_adapter *adap);
void cec_monitor_all_cnt_dec(struct cec_adapter *adap);
int cec_adap_status(struct seq_file *file, void *priv);
int cec_thread_func(void *_adap);
void __cec_s_phys_addr(struct cec_adapter *adap, u16 phys_addr, bool block);
int __cec_s_log_addrs(struct cec_adapter *adap,
struct cec_log_addrs *log_addrs, bool block);
int cec_transmit_msg_fh(struct cec_adapter *adap, struct cec_msg *msg,
struct cec_fh *fh, bool block);
void cec_queue_event_fh(struct cec_fh *fh,
const struct cec_event *new_ev, u64 ts);
/* cec-api.c */
extern const struct file_operations cec_devnode_fops;
#endif
config VIDEO_SAMSUNG_S5P_CEC
tristate "Samsung S5P CEC driver"
depends on VIDEO_DEV && MEDIA_CEC && (PLAT_S5P || ARCH_EXYNOS || COMPILE_TEST)
---help---
This is a driver for Samsung S5P HDMI CEC interface. It uses the
generic CEC framework interface.
CEC bus is present in the HDMI connector and enables communication
between compatible devices.
obj-$(CONFIG_VIDEO_SAMSUNG_S5P_CEC) += s5p-cec.o
s5p-cec-y += s5p_cec.o exynos_hdmi_cecctrl.o
There's nothing wrong on this driver, except that it depends on
the media staging core, that it is currently at staging. So,
this should be kept here while the core is not promoted.
/* drivers/media/platform/s5p-cec/exynos_hdmi_cec.h
*
* Copyright (c) 2010, 2014 Samsung Electronics
* http://www.samsung.com/
*
* Header file for interface of Samsung Exynos hdmi cec hardware
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef _EXYNOS_HDMI_CEC_H_
#define _EXYNOS_HDMI_CEC_H_ __FILE__
#include <linux/regmap.h>
#include <linux/miscdevice.h>
#include "s5p_cec.h"
void s5p_cec_set_divider(struct s5p_cec_dev *cec);
void s5p_cec_enable_rx(struct s5p_cec_dev *cec);
void s5p_cec_mask_rx_interrupts(struct s5p_cec_dev *cec);
void s5p_cec_unmask_rx_interrupts(struct s5p_cec_dev *cec);
void s5p_cec_mask_tx_interrupts(struct s5p_cec_dev *cec);
void s5p_cec_unmask_tx_interrupts(struct s5p_cec_dev *cec);
void s5p_cec_reset(struct s5p_cec_dev *cec);
void s5p_cec_tx_reset(struct s5p_cec_dev *cec);
void s5p_cec_rx_reset(struct s5p_cec_dev *cec);
void s5p_cec_threshold(struct s5p_cec_dev *cec);
void s5p_cec_copy_packet(struct s5p_cec_dev *cec, char *data,
size_t count, u8 retries);
void s5p_cec_set_addr(struct s5p_cec_dev *cec, u32 addr);
u32 s5p_cec_get_status(struct s5p_cec_dev *cec);
void s5p_clr_pending_tx(struct s5p_cec_dev *cec);
void s5p_clr_pending_rx(struct s5p_cec_dev *cec);
void s5p_cec_get_rx_buf(struct s5p_cec_dev *cec, u32 size, u8 *buffer);
#endif /* _EXYNOS_HDMI_CEC_H_ */
This diff is collapsed.
/* drivers/media/platform/s5p-cec/regs-cec.h
*
* Copyright (c) 2010 Samsung Electronics
* http://www.samsung.com/
*
* register header file for Samsung TVOUT driver
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef __EXYNOS_REGS__H
#define __EXYNOS_REGS__H
/*
* Register part
*/
#define S5P_CEC_STATUS_0 (0x0000)
#define S5P_CEC_STATUS_1 (0x0004)
#define S5P_CEC_STATUS_2 (0x0008)
#define S5P_CEC_STATUS_3 (0x000C)
#define S5P_CEC_IRQ_MASK (0x0010)
#define S5P_CEC_IRQ_CLEAR (0x0014)
#define S5P_CEC_LOGIC_ADDR (0x0020)
#define S5P_CEC_DIVISOR_0 (0x0030)
#define S5P_CEC_DIVISOR_1 (0x0034)
#define S5P_CEC_DIVISOR_2 (0x0038)
#define S5P_CEC_DIVISOR_3 (0x003C)
#define S5P_CEC_TX_CTRL (0x0040)
#define S5P_CEC_TX_BYTES (0x0044)
#define S5P_CEC_TX_STAT0 (0x0060)
#define S5P_CEC_TX_STAT1 (0x0064)
#define S5P_CEC_TX_BUFF0 (0x0080)
#define S5P_CEC_TX_BUFF1 (0x0084)
#define S5P_CEC_TX_BUFF2 (0x0088)
#define S5P_CEC_TX_BUFF3 (0x008C)
#define S5P_CEC_TX_BUFF4 (0x0090)
#define S5P_CEC_TX_BUFF5 (0x0094)
#define S5P_CEC_TX_BUFF6 (0x0098)
#define S5P_CEC_TX_BUFF7 (0x009C)
#define S5P_CEC_TX_BUFF8 (0x00A0)
#define S5P_CEC_TX_BUFF9 (0x00A4)
#define S5P_CEC_TX_BUFF10 (0x00A8)
#define S5P_CEC_TX_BUFF11 (0x00AC)
#define S5P_CEC_TX_BUFF12 (0x00B0)
#define S5P_CEC_TX_BUFF13 (0x00B4)
#define S5P_CEC_TX_BUFF14 (0x00B8)
#define S5P_CEC_TX_BUFF15 (0x00BC)
#define S5P_CEC_RX_CTRL (0x00C0)
#define S5P_CEC_RX_STAT0 (0x00E0)
#define S5P_CEC_RX_STAT1 (0x00E4)
#define S5P_CEC_RX_BUFF0 (0x0100)
#define S5P_CEC_RX_BUFF1 (0x0104)
#define S5P_CEC_RX_BUFF2 (0x0108)
#define S5P_CEC_RX_BUFF3 (0x010C)
#define S5P_CEC_RX_BUFF4 (0x0110)
#define S5P_CEC_RX_BUFF5 (0x0114)
#define S5P_CEC_RX_BUFF6 (0x0118)
#define S5P_CEC_RX_BUFF7 (0x011C)
#define S5P_CEC_RX_BUFF8 (0x0120)
#define S5P_CEC_RX_BUFF9 (0x0124)
#define S5P_CEC_RX_BUFF10 (0x0128)
#define S5P_CEC_RX_BUFF11 (0x012C)
#define S5P_CEC_RX_BUFF12 (0x0130)
#define S5P_CEC_RX_BUFF13 (0x0134)
#define S5P_CEC_RX_BUFF14 (0x0138)
#define S5P_CEC_RX_BUFF15 (0x013C)
#define S5P_CEC_RX_FILTER_CTRL (0x0180)
#define S5P_CEC_RX_FILTER_TH (0x0184)
/*
* Bit definition part
*/
#define S5P_CEC_IRQ_TX_DONE (1<<0)
#define S5P_CEC_IRQ_TX_ERROR (1<<1)
#define S5P_CEC_IRQ_RX_DONE (1<<4)
#define S5P_CEC_IRQ_RX_ERROR (1<<5)
#define S5P_CEC_TX_CTRL_START (1<<0)
#define S5P_CEC_TX_CTRL_BCAST (1<<1)
#define S5P_CEC_TX_CTRL_RETRY (0x04<<4)
#define S5P_CEC_TX_CTRL_RESET (1<<7)
#define S5P_CEC_RX_CTRL_ENABLE (1<<0)
#define S5P_CEC_RX_CTRL_RESET (1<<7)
#define S5P_CEC_LOGIC_ADDR_MASK (0xF)
/* PMU Registers for PHY */
#define EXYNOS_HDMI_PHY_CONTROL 0x700
#endif /* __EXYNOS_REGS__H */
This diff is collapsed.
/* drivers/media/platform/s5p-cec/s5p_cec.h
*
* Samsung S5P HDMI CEC driver
*
* Copyright (c) 2014 Samsung Electronics Co., Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#ifndef _S5P_CEC_H_
#define _S5P_CEC_H_ __FILE__
#include <linux/clk.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/timer.h>
#include <linux/version.h>
#include <linux/workqueue.h>
#include <media/cec.h>
#include "exynos_hdmi_cec.h"
#include "regs-cec.h"
#include "s5p_cec.h"
#define CEC_NAME "s5p-cec"
#define CEC_STATUS_TX_RUNNING (1 << 0)
#define CEC_STATUS_TX_TRANSFERRING (1 << 1)
#define CEC_STATUS_TX_DONE (1 << 2)
#define CEC_STATUS_TX_ERROR (1 << 3)
#define CEC_STATUS_TX_BYTES (0xFF << 8)
#define CEC_STATUS_RX_RUNNING (1 << 16)
#define CEC_STATUS_RX_RECEIVING (1 << 17)
#define CEC_STATUS_RX_DONE (1 << 18)
#define CEC_STATUS_RX_ERROR (1 << 19)
#define CEC_STATUS_RX_BCAST (1 << 20)
#define CEC_STATUS_RX_BYTES (0xFF << 24)
#define CEC_WORKER_TX_DONE (1 << 0)
#define CEC_WORKER_RX_MSG (1 << 1)
/* CEC Rx buffer size */
#define CEC_RX_BUFF_SIZE 16
/* CEC Tx buffer size */
#define CEC_TX_BUFF_SIZE 16
enum cec_state {
STATE_IDLE,
STATE_BUSY,
STATE_DONE,
STATE_ERROR
};
struct s5p_cec_dev {
struct cec_adapter *adap;
struct clk *clk;
struct device *dev;
struct mutex lock;
struct regmap *pmu;
int irq;
void __iomem *reg;
enum cec_state rx;
enum cec_state tx;
struct cec_msg msg;
};
#endif /* _S5P_CEC_H_ */
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment