[PATCH v2] libgencec: Add userspace library for the generic CEC kernel interface

Kamil Debski
2015-05-04T17:35:08Z

This is the first version of the libGenCEC library. It was designed to
act as an interface between the generic CEC kernel API and userspace
applications. It provides a simple interface for applications and an
example application that can be used to test the CEC functionality.

signed-off-by: Kamil Debski <k.debski@samsung.com>
---
AUTHORS | 1 +
INSTALL | 9 +
LICENSE | 202 ++++++++++++++++
Makefile.am | 4 +
README | 22 ++
configure.ac | 24 ++
doc/index.html | 345 +++++++++++++++++++++++++++
examples/Makefile.am | 4 +
examples/cectest.c | 631 ++++++++++++++++++++++++++++++++++++++++++++++++++
include/gencec.h | 255 ++++++++++++++++++++
libgencec.pc.in | 10 +
src/Makefile.am | 4 +
src/gencec.c | 445 +++++++++++++++++++++++++++++++++++
13 files changed, 1956 insertions(+)
create mode 100644 AUTHORS
create mode 100644 INSTALL
create mode 100644 LICENSE
create mode 100644 Makefile.am
create mode 100644 README
create mode 100644 configure.ac
create mode 100644 doc/index.html
create mode 100644 examples/Makefile.am
create mode 100644 examples/cectest.c
create mode 100644 include/gencec.h
create mode 100644 libgencec.pc.in
create mode 100644 src/Makefile.am
create mode 100644 src/gencec.c

diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..e4b7117
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1 @@
+Kamil Debski <k.debski@samsung.com>
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..aac6101
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,9 @@
+To install libgencec run following commands:
+
+autoreconf -i
+./configure
+make
+make install
+
+A cross compilation example for ARM:
+CFLAGS=-I<kernel headers> ./configure --host=arm-linux-gnueabi --prefix=<installation prefix>
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..d9e0449
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,4 @@
+SUBDIRS = src examples
+ACLOCAL_AMFLAGS = -I m4
+library_includedir=$(includedir)
+library_include_HEADERS = include/gencec.h
diff --git a/README b/README
new file mode 100644
index 0000000..bb817b7
--- /dev/null
+++ b/README
@@ -0,0 +1,22 @@
+libGenCEC - library for the generic HDMI CEC kernel interface
+--------------------------------------------------------------------------
+
+The libGenCEC library is a simple library that was written to facilitate
+proper configuration and use of HDMI CEC devices that use the generic HDMI
+CEC kernel interface.
+
+The library provides a range of functions that wrap around the ioctls of the
+kernel API. It contains a test application that can be used to communicate
+through the CEC bus with other compatible devices.
+
+The test application also serves as a code example on how to use the library.
+
+The library calls are documented in the gencec.h file.
+
+Example application use
+--------------------------------------------------------------------------
+The following command will initiate the devic, set the name and enable
+keypress forwarding. Tested on a Samsung TV model LE32C650.
+
+./cectest -e -l playback -P -O Test123 -T -A -M on
+
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..e7639a2
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,24 @@
+AC_INIT([libgencec], [0.1], [k.debski@samsung.com])
+AM_INIT_AUTOMAKE([-Wall -Werror foreign])
+
+AC_PROG_CC
+AM_PROG_AR
+AC_CONFIG_MACRO_DIR([m4])
+AC_DEFINE([_GNU_SOURCE], [], [Use GNU extensions])
+
+LT_INIT
+
+# Checks for typedefs, structures, and compiler characteristics.
+AC_C_INLINE
+AC_TYPE_SIZE_T
+AC_TYPE_UINT16_T
+AC_TYPE_UINT32_T
+AC_TYPE_UINT8_T
+
+#AC_CHECK_LIB([c], [malloc])
+# Checks for library functions.
+#AC_FUNC_MALLOC
+
+AC_CONFIG_FILES([Makefile src/Makefile examples/Makefile libgencec.pc])
+
+AC_OUTPUT
diff --git a/doc/index.html b/doc/index.html
new file mode 100644
index 0000000..914413e
--- /dev/null
+++ b/doc/index.html
@@ -0,0 +1,345 @@
+ struct cec_device - a structure used to keep context of the current used CEC device
+struct cec_device {
+ void * caps;
+ int handle;
+ int initialised;
+ uint32_t log_addr[CEC_MAX_NUM_LOG_ADDR];
+ uint32_t log_addr_type_int[CEC_MAX_NUM_LOG_ADDR];
+ enum cec_device_type dev_type[CEC_MAX_NUM_LOG_ADDR];
+ uint32_t dev_type_int[CEC_MAX_NUM_LOG_ADDR];
+ int num_log_addr;
+};
+ Members
+
+ caps
+ used to keep a pointer to the kernel caps structure for the
+device
+ handle
+ this is used to keep the file handle to the CEC device
+ initialised
+ flag set if the structure was properly initialised
+ log_addr[CEC_MAX_NUM_LOG_ADDR]
+ an array containing the assigned logical addresses
+ log_addr_type_int[CEC_MAX_NUM_LOG_ADDR]
+ an array containing the logical addresses' types as
+needed by the kernel
+ dev_type[CEC_MAX_NUM_LOG_ADDR]
+ device type, as neede by the library
+ dev_type_int[CEC_MAX_NUM_LOG_ADDR]
+ primary device type, as needed by the kernel driver
+ num_log_addr
+ number of ssigned logical addresses
+
+
+ struct hdmi_port_info - Information about a HDMI port
+struct hdmi_port_info {
+ uint8_t port_number;
+};
+ Members
+
+ port_number
+ the port number
+
+
+ struct cec_info - a structure used to get information about the CEC device
+struct cec_info {
+ enum cec_version version;
+ uint32_t vendor_id;
+ unsigned int ports_num;
+ struct hdmi_port_info ports_info[MAX_NUM_OF_HDMI_PORTS];
+};
+ Members
+
+ version
+ supported CEC version
+ vendor_id
+ the vendor ID
+ ports_num
+ number of HDMI ports available in the system
+ ports_info[MAX_NUM_OF_HDMI_PORTS]
+ an array containing information about HDMI ports
+
+
+ struct cec_buffer - a structure used to store message that were received or are to be sent
+struct cec_buffer {
+ uint8_t dst;
+ uint8_t src;
+ uint8_t len;
+ uint8_t payload[CEC_MAX_LENGTH];
+ struct timespec ts;
+};
+ Members
+
+ dst
+ The address of the destination device
+ src
+ The address of the source device
+ len
+ The length of the payload of the message
+ payload[CEC_MAX_LENGTH]
+ The payload of the message
+ ts
+ The timestamp for received messages
+
+
+ cec_open - Open a CEC device
+int
+cec_open
+(struct cec_device * dev,
+char * path)
+ Arguments
+
+ dev
+ pointer to a structure that will hold the state of the device
+ path
+ path to the CEC device
+
+ Returns
+
+on success CEC_OK, on error returns an negative error code
+
+
+ cec_close - Close a CEC device
+int
+cec_close
+(struct cec_device * dev)
+ Arguments
+
+ dev
+ pointer to a structure that holds the state of the device
+
+ Returns
+
+on success CEC_OK, on error returns an negative error code
+
+
+ cec_is_enabled - Check whether the CEC device is enabled
+bool
+cec_is_enabled
+(struct cec_device * dev)
+ Arguments
+
+ dev
+ pointer to a structure that holds the state of the device
+
+ Returns
+
+true if all is ok and the CEC device is enabled, false otherwise
+
+
+ cec_enable - Enable a CEC device
+int
+cec_enable
+(struct cec_device * dev,
+bool enable)
+ Arguments
+
+ dev
+ pointer to a structure that will hold the state of the device
+ enable
+ true to enable the CEC device, false to disable the CEC device
+
+ Returns
+
+on success CEC_OK, on error returns an negative error code
+
+
+ cec_passthrough - Enable a CEC device
+int
+cec_passthrough
+(struct cec_device * dev,
+bool enable)
+ Arguments
+
+ dev
+ pointer to a structure that will hold the state of the device
+ enable
+ true to enable the passthrough mode, false to disable
+
+ Returns
+
+on success CEC_OK, on error returns an negative error code
+
+
+ cec_get_info - Returns information about the CEC device
+int
+cec_get_info
+(struct cec_device * dev,
+struct cec_info * info)
+ Arguments
+
+ dev
+ pointer to a structure that holds the state of the device
+ info
+ pointer to a info structure that will hold the information about
+the CEC device
+
+ Returns
+
+on success CEC_OK, on error returns an negative error code
+
+
+ cec_is_connected - Return information about whether a device is connected to the port
+int
+cec_is_connected
+(struct cec_device * dev)
+ Arguments
+
+ dev
+ pointer to a structure that holds the state of the device
+
+ Returns
+
+when a device is connected to the port returns CEC_CONNECTED,
+CEC_DISCONNECTED when there is no device connected, on error
+returns an negative error code
+
+
+ cec_send_message - Send a message over the CEC bus
+int
+cec_send_message
+(struct cec_device * dev,
+struct cec_buffer * msg)
+ Arguments
+
+ dev
+ pointer to a structure that holds the state of the device
+ msg
+ the message do be sent over the CEC bus
+
+ Returns
+
+CEC_OK on success
+CEC_REPLY on successful send and reply receive
+CEC_REPLY_TIMEOUT when waiting for reply timed out
+CEC_TIMEOUT when a timeout occurred while sending the message
+negative error code on other error
+
+
+ cec_receive_message - Receive a message over the CEC bus
+int
+cec_receive_message
+(struct cec_device * dev,
+struct cec_buffer * msg)
+ Arguments
+
+ dev
+ pointer to a structure that holds the state of the device
+ msg
+ a structure used to store the message received over the CEC bus
+
+ Returns
+
+CEC_OK on success
+CEC_TIMEOUT when a timeout occurred while waiting for message
+negative error code on error
+
+ Remarks
+
+when waiting for a reply, the reply is stored in the msg struct
+
+
+ cec_get_logical_addrs - Add a new logical address to the CEC device
+int
+cec_get_logical_addrs
+(struct cec_device * dev,
+uint8_t * addr,
+int * num_addr)
+ Arguments
+
+ dev
+ pointer to a structure that holds the state of the device
+ addr
+ pointer to an array to hold the list of assigned logical
+addresses, the size should be CEC_MAX_NUM_LOG_ADDR
+ num_addr
+ pointer to an int that will hold the number of assigned
+logical addresses
+
+ Returns
+
+CEC_OK on success
+negative error code on error
+
+
+ cec_add_logical_addr - Add a new logical address to the CEC device
+int
+cec_add_logical_addr
+(struct cec_device * dev,
+enum cec_device_type type,
+uint8_t * addr)
+ Arguments
+
+ dev
+ pointer to a structure that holds the state of the device
+ type
+ the type of the device that is to be added, please note that
+this indicated the type and not the address that will be
+assigned
+ addr
+ a pointer to a location where to store the assigned logical
+address
+
+ Returns
+
+CEC_OK on success
+CEC_TIMEOUT when a timeout occurred while waiting for message
+CEC_NO_ADDR_LEFT when all addresses related to the chosen device
+type are already taken
+negative error code on error
+
+
+ cec_clear_logical_addrs - Clear the logical addresses that were assigned to the device
+int
+cec_clear_logical_addrs
+(struct cec_device * dev)
+ Arguments
+
+ dev
+ pointer to a structure that holds the state of the device
+
+ Returns
+
+CEC_OK on success
+CEC_TIMEOUT when a timeout occurred while waiting for message
+negative error code on error
+
+
+ cec_get_physical_addr - Get the physical addr of the CEC device
+int
+cec_get_physical_addr
+(struct cec_device * dev,
+uint16_t * phys_addr)
+ Arguments
+
+ dev
+ pointer to a structure that holds the state of the device
+ phys_addr
+ pointer to a uint16_t which will hold the physical address
+
+ Returns
+
+CEC_OK on success
+CEC_TIMEOUT when a timeout occurred while waiting for message
+negative error code on error
+
+
+ cec_set_physical_addr - Get the physical addr of the CEC device
+int
+cec_set_physical_addr
+(struct cec_device * dev,
+uint16_t phys_addr)
+ Arguments
+
+ dev
+ pointer to a structure that holds the state of the device
+ phys_addr
+ a uint16_t which holding the physical address
+
+ Returns
+
+CEC_OK on success
+CEC_TIMEOUT when a timeout occurred while waiting for message
+negative error code on error
+
+
diff --git a/examples/Makefile.am b/examples/Makefile.am
new file mode 100644
index 0000000..1a007eb
--- /dev/null
+++ b/examples/Makefile.am
@@ -0,0 +1,4 @@
+bin_PROGRAMS = cectest
+cectest_SOURCES = cectest.c
+AM_CPPFLAGS=-I$(top_srcdir)/include/
+AM_LDFLAGS=-L../src/ -lgencec
diff --git a/examples/cectest.c b/examples/cectest.c
new file mode 100644
index 0000000..659f841
--- /dev/null
+++ b/examples/cectest.c
@@ -0,0 +1,631 @@
+/*
+ * Copyright 2015 Samsung Electronics Co. Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gencec.h>
+#include <getopt.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* A single entry in the list of tasks to be done */
+struct todo {
+ char cmd;
+ char *param;
+ struct todo *next;
+};
+
+/* Print a help message with the list and the description of all commands */
+void print_usage(char *name)
+{
+ printf("\nUsage:\n");
+ printf("\t%s\n", name);
+
+ printf("General options:\n");
+ printf("\t--help/-h - display this message\n");
+ printf("\t--device/-D <device name> - name of the CEC device (default is /dev/cec0)\n");
+
+ printf("CEC device related commands:\n");
+ printf("\t--enable/-e - enable the CEC adapter\n");
+ printf("\t--disable/-d - disable the CEC adapter\n");
+ printf("\t--add-logical/-l <addr_type> - add logical address of given type\n");
+ printf("\t\tTypes: tv, record, tuner, playback, audio, switch, videoproc\n");
+ printf("\t--clear-logical/-c - clear logical addresses\n");
+ printf("\t--get-logical/-G - get logical address(es)\n");
+ printf("\t--get-physical/-g - get the physical address\n");
+ printf("\t--set-physical/-s <addr> - set the physical address\n");
+ printf("\t\t<addr> should be in the following format N.N.N.N where N is between 0 and 15\n");
+ printf("\t\te.g. --set-physical 1.0.0.11\n");
+ printf("\t--info/-i - print information about the CEC device\n");
+ printf("\t--send/-S <addr>:<contents> - send a message to a specified address\n");
+ printf("\t\t<addr> should be an integer ranging from 0 to 15 (where 15 is a broadcast address\n");
+ printf("\t\t<contents> should be an array of hexadecimal bytes\n");
+ printf("\t\te.g. --send 11:010b0cf6 which will send a message consisting of 010b0cf6 to\n");
+ printf("\t\tthe device with logical address 11\n");
+ printf("\t\t<contents> should be a hexadecimal number that represents the bytes to be sent\n");
+ printf("\t--receive/-R - receive a single CEC message\n");
+ printf("\t--passthrough/-p <state> - enable/disable passthrough mode\n");
+
+ printf("Useful CEC standard commands:\n");
+ printf("\t--osd/-O <OSD name> - set the OSD name for device\n");
+ printf("\t--give-power-status/-P <status> - give device power status\n");
+ printf("\t--text-view-on/-T - Sent by a source device to the TV whenever it enters the active state \n");
+ printf("\t--active-source/-A - indicate that it has started to transmit a stream\n");
+ printf("\t--menu-state/-M <state> - used to indicate that the device is showing a menu (enable keycode forwarding)\n");
+ printf("\t\t<state> = \"on\" or \"off\"\n");
+ printf("\t\n");
+ printf("\tCommands are executed in the order given in argument list.\n");
+}
+
+/* Parse the arguments list and prepare a list with task that are to be done */
+struct todo *parse_args(int argc, char **argv)
+{
+ struct todo *list = 0;
+ struct todo *tmp;
+
+ int c;
+ int option_index = 0;
+
+ static struct option long_options[] =
+ {
+ {"device", required_argument, 0, 'D'},
+ {"help", no_argument, 0, 'h'},
+
+ {"enable", no_argument, 0, 'e'},
+ {"disable", no_argument, 0, 'd'},
+ {"add-logical", required_argument, 0, 'l'},
+ {"clear-logical", no_argument, 0, 'c'},
+ {"get-logical", no_argument, 0, 'G'},
+ {"get-physical", no_argument, 0, 'g'},
+ {"set-physical", required_argument, 0, 's'},
+ {"info", no_argument, 0, 'i'},
+ {"passthrough", required_argument, 0, 'p'},
+
+ {"send", required_argument, 0, 'S'},
+ {"receive", no_argument, 0, 'R'},
+
+ {"osd", required_argument, 0, 'O'},
+ {"give-power-status", required_argument, 0, 'P'},
+ {"text-view-on", no_argument, 0, 'T'},
+ {"active-source", no_argument, 0, 'A'},
+ {"menu-state", required_argument, 0, 'M'},
+
+ {0, 0, 0, 0}
+ };
+
+ while (1) {
+ c = getopt_long(argc, argv, "D:edl:cGgs:S:RO:PTAM:ip:", long_options, &option_index);
+ if (c == -1)
+ break;
+ switch (c) {
+ case 'D':
+ /* add as first element in todo */
+ tmp = malloc(sizeof(struct todo));
+ if (!tmp)
+ exit(1);
+ tmp->cmd = c;
+ tmp->param = strdup(optarg);
+ tmp->next = list;
+ list = tmp;
+ break;
+ /* cmds with no arg */
+ case 'A': case 'c': case 'd': case 'e':
+ case 'g': case 'G': case 'i': case 'P':
+ case 'R': case 'S': case 'T':
+ /* cmds with arg */
+ case 'l': case 'M': case 'O': case 's':
+ case 'p':
+ /* add as last element */
+ if (!list) {
+ list = tmp = malloc(sizeof(struct todo));
+ if (!tmp)
+ exit(1);
+ } else {
+ tmp = list;
+
+ while (tmp->next)
+ tmp = tmp->next;
+ tmp->next = malloc(sizeof(struct todo));
+ if (!tmp)
+ exit(1);
+ tmp = tmp->next;
+ }
+ tmp->cmd = c;
+ if (optarg)
+ tmp->param = strdup(optarg);
+ else
+ tmp->param = 0;
+ tmp->next = 0;
+ break;
+ case 'h':
+ default:
+ while (list) {
+ tmp = list->next;
+ free(list->param);
+ free(list);
+ list = tmp;
+ }
+ return 0;
+ }
+ }
+
+ return list;
+}
+
+/* Parse a physical address which format is dd.dd.dd.dd
+ * where dd is a integer ranging from 0 to 15 */
+int parse_paddr(char *s)
+{
+ char c;
+ int r = 0;
+ int t = 0;
+ int dots = 0;
+ if (!s)
+ return -1;
+ while ((c = *(s++))) {
+ if (c == '.') {
+ r <<= 4;
+ r |= t;
+ t = 0;
+ dots++;
+ } else if (c >= '0' && c <= '9') {
+ t = t * 10 + c - '0';
+ } else {
+ return -1;
+ }
+ }
+ if (dots != 3)
+ return -1;
+ r <<= 4;
+ r |= t;
+ return r;
+}
+
+/* Get the first logical address assigned to the used CEC device */
+int get_addr(struct cec_device *cec)
+{
+ uint8_t addrs[CEC_MAX_NUM_LOG_ADDR];
+ int num_addrs;
+ int ret;
+
+ ret = cec_get_logical_addrs(cec, addrs, &num_addrs);
+ if (ret != CEC_OK)
+ return -1;
+
+ if (num_addrs)
+ return addrs[0];
+ else
+ return -1;
+}
+
+/* Convert a single character containing a single hexadecimal digit
+ * to an int */
+int hexdigit(char c)
+{
+ if (c >= '0' && c <= '9')
+ return c - '0';
+ if (c >= 'a' && c <= 'f')
+ return 10 + c - 'a';
+ if (c >= 'A' && c <= 'F')
+ return 10 + c - 'A';
+ return -1;
+}
+
+/* Parse string in the format of dd:xxxx
+ * where dd - is an integer denoting the logical address of the recipient device
+ * and xxxx is an array of bytes written in hexadecimal notation.
+ * e.g. 11:1234 means send a message consisting of the following two bytes 0x12
+ * and 0x34 to the device with logical address 11 */
+int parse_message(struct cec_buffer *msg, char *s)
+{
+ int i;
+ int tmp;
+
+ if (*s > '9' || *s < '0')
+ return 1;
+ msg->dst = *s - '0';
+ s++;
+ if (*s != ':') {
+ if (*s> '9' || *s < '0')
+ return 1;
+ msg->dst *= 10;
+ msg->dst += *s - '0';
+ s++;
+ }
+
+ if (*s != ':')
+ return 1;
+ s++;
+
+ i = 0;
+ while (*s) {
+ if (i > CEC_MAX_LENGTH * 2)
+ return 1;
+ tmp = hexdigit(*s);
+ if (tmp == -1)
+ return 1;
+ if (i % 2 == 0)
+ msg->payload[i / 2] = tmp << 4;
+ else
+ msg->payload[i / 2] |= tmp;
+ s++;
+ i++;
+ }
+
+ msg->len = i / 2;
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ struct todo *list;
+ struct cec_device cec;
+ uint8_t addr;
+ int ret;
+
+ printf("libgencec test application (c) Samsung 2015\n");
+
+ list = parse_args(argc, argv);
+
+ if (!list) {
+ print_usage(argv[0]);
+ return 1;
+ }
+
+ if (list->cmd == 'D') {
+ ret = cec_open(&cec, list->param);
+ list = list->next;
+ } else {
+ ret = cec_open(&cec, "/dev/cec0");
+ }
+ if (ret != CEC_OK) {
+ printf("Failed to open CEC device\n");
+ return 1;
+ }
+
+ printf("Succesfully opened CEC device\n");
+
+ /* Main processing loop */
+ while (list) {
+ switch (list->cmd) {
+ case 'd':
+ case 'e':
+ ret = cec_enable(&cec, list->cmd == 'e');
+ if (ret != CEC_OK) {
+ printf("Failed to %s CEC device\n",
+ list->cmd == 'e' ? "enable":"disable");
+ return 1;
+ }
+ printf("Successfully %s CEC device\n",
+ list->cmd == 'e' ? "enabled":"disabled");
+ break;
+ case 'l': {
+ enum cec_device_type type;
+ if (!strcasecmp(list->param, "tv"))
+ type = CEC_DEVICE_TYPE_TV;
+ else if (!strcasecmp(list->param, "record"))
+ type = CEC_DEVICE_TYPE_RECORD;
+ else if (!strcasecmp(list->param, "tuner"))
+ type = CEC_DEVICE_TYPE_TUNER;
+ else if (!strcasecmp(list->param, "playback"))
+ type = CEC_DEVICE_TYPE_PLAYBACK;
+ else if (!strcasecmp(list->param, "audio"))
+ type = CEC_DEVICE_TYPE_AUDIOSYSTEM;
+ else if (!strcasecmp(list->param, "switch"))
+ type = CEC_DEVICE_TYPE_SWITCH;
+ else if (!strcasecmp(list->param, "videoproc"))
+ type = CEC_DEVICE_TYPE_VIDEOPROC;
+ else {
+ printf("Unrecognised logical address type\n");
+ return 1;
+ }
+
+ ret = cec_add_logical_addr(&cec, type, &addr);
+ if (ret != CEC_OK) {
+ printf("Failed to add a logical address\n");
+ return 1;
+ }
+ printf("Successfully added logical address of type '%s', id=%d\n", list->param, addr);
+ break;
+ }
+ case 'c':
+ ret = cec_clear_logical_addrs(&cec);
+ if (ret != CEC_OK) {
+ printf("Failed to clear logical addresses\n");
+ return 1;
+ }
+ printf("Successfully cleared logical addresses\n");
+ break;
+ case 'G': {
+ uint8_t addrs[CEC_MAX_NUM_LOG_ADDR];
+ int num_addrs;
+ int i;
+
+ ret = cec_get_logical_addrs(&cec, addrs, &num_addrs);
+ if (ret != CEC_OK) {
+ printf("Failed to get logical addresses\n");
+ return 1;
+ }
+ if (num_addrs) {
+ for (i = 0; i < num_addrs; i++)
+ printf("Assigned logical address %d\n",
+ addrs[i]);
+ } else {
+ printf("No logical addresses assigned\n");
+ }
+
+ break;
+ }
+ case 'g': {
+ uint16_t paddr;
+ ret = cec_get_physical_addr(&cec, &paddr);
+ if (ret != CEC_OK) {
+ printf("Failed to get physical address\n");
+ return 1;
+ }
+ printf("Got physical addr: %d.%d.%d.%d\n",
+ paddr >> 12 & 0xf, paddr >> 8 & 0xf,
+ paddr >> 4 & 0xf, paddr & 0xf);
+ break;
+ }
+ case 's': {
+ uint16_t paddr;
+ paddr = parse_paddr(list->param);
+ if (paddr == -1) {
+ printf("Failed to parse physical address (%s)\n", list->param);
+ return -1;
+ }
+ ret = cec_set_physical_addr(&cec, paddr);
+ if (ret != CEC_OK) {
+ printf("Failed to set physical address\n");
+ return 1;
+ }
+ printf("Set physical addr: %d.%d.%d.%d\n",
+ paddr >> 12 & 0xf, paddr >> 8 & 0xf,
+ paddr >> 4 & 0xf, paddr & 0xf);
+ break;
+ }
+ case 'i': {
+ struct cec_info info;
+
+ ret = cec_get_info(&cec, &info);
+ if (ret != CEC_OK) {
+ printf("Failed to get CEC info\n");
+ return 1;
+ }
+
+ printf( "Got info: \n"
+ "version = %d\n"
+ "vendor_id = 0x%08x\n"
+ "ports_num = %d\n\n",
+ info.version,
+ info.vendor_id,
+ info.ports_num);
+
+ break;
+ }
+ case 'p': {
+ int passthrough;
+
+ addr = get_addr(&cec);
+ if (strcasecmp(list->param, "on") == 0) {
+ passthrough = 1;
+ } else if (strcasecmp(list->param, "off") == 0) {
+ passthrough = 0;
+ } else {
+ printf("Unknown state \"%s\"\n", list->param);
+ return 1;
+ }
+
+ printf("Successfully switched passthrought mode %s\n", list->param);
+ break;
+ }
+ case 'O': {
+ struct cec_buffer msg;
+ int addr;
+
+ if (strlen(list->param) > CEC_MAX_LENGTH) {
+ printf("OSD name too long\n");
+ return -1;
+ }
+
+ addr = get_addr(&cec);
+ if (addr == -1) {
+ printf("Failed to get logical address of the CEC device\n");
+ return 1;
+ }
+
+ msg.src = addr;
+ msg.dst = 0x0; /* The TV */
+ msg.len = 1 + strlen(list->param);
+ msg.payload[0] = 0x47;
+ memcpy(msg.payload + 1, list->param, strlen(list->param));
+
+ ret = cec_send_message(&cec, &msg);
+ if (ret != CEC_OK) {
+ printf("Failed to send message\n");
+ return 1;
+ }
+ printf("Successfully sent message - set OSD name to\"%s\"\n", list->param);
+ break;
+ }
+ case 'P': {
+ struct cec_buffer msg;
+ int addr;
+
+ addr = get_addr(&cec);
+ if (addr == -1) {
+ printf("Failed to get logical address of the CEC device\n");
+ return 1;
+ }
+
+ msg.src = addr;
+ msg.dst = 0x0; /* The TV */
+ msg.len = 1;
+ msg.payload[0] = 0x8f;
+
+ ret = cec_send_message(&cec, &msg);
+ if (ret != CEC_OK) {
+ printf("Failed to send message\n");
+ return 1;
+ }
+ printf("Successfully sent message - Give Power Status\n");
+ break;
+ }
+ case 'T': {
+ struct cec_buffer msg;
+ int addr;
+
+ addr = get_addr(&cec);
+ if (addr == -1) {
+ printf("Failed to get logical address of the CEC device\n");
+ return 1;
+ }
+
+ msg.src = addr;
+ msg.dst = 0x0; /* The TV */
+ msg.len = 1;
+ msg.payload[0] = 0x0d;
+
+ ret = cec_send_message(&cec, &msg);
+ if (ret != CEC_OK) {
+ printf("Failed to send message\n");
+ return 1;
+ }
+ printf("Successfully sent message - Text View On\n");
+ break;
+ }
+ case 'A': {
+ struct cec_buffer msg;
+ uint16_t paddr;
+ int addr;
+
+ addr = get_addr(&cec);
+ if (addr == -1) {
+ printf("Failed to get logical address of the CEC device\n");
+ return 1;
+ }
+ ret = cec_get_physical_addr(&cec, &paddr);
+ if (ret != CEC_OK) {
+ printf("Failed to get physical address\n");
+ return 1;
+ }
+
+ msg.src = addr;
+ msg.dst = 0xf; /* The TV */
+ msg.len = 3;
+ msg.payload[0] = 0x82;
+ msg.payload[1] = paddr >> 8;
+ msg.payload[2] = paddr & 0xff;
+
+ ret = cec_send_message(&cec, &msg);
+ if (ret != CEC_OK) {
+ printf("Failed to send message\n");
+ return 1;
+ }
+ printf("Successfully sent message - Active Source\n");
+ break;
+ }
+ case 'M': {
+ struct cec_buffer msg;
+ int addr;
+
+ addr = get_addr(&cec);
+ if (addr == -1) {
+ printf("Failed to get logical address of the CEC device\n");
+ return 1;
+ }
+
+ msg.src = addr;
+ msg.dst = 0x0; /* The TV */
+ msg.len = 2;
+ msg.payload[0] = 0x8e;
+ if (strcasecmp(list->param, "on") == 0) {
+ msg.payload[1] = 0;
+ } else if (strcasecmp(list->param, "off") == 0) {
+ msg.payload[1] = 1;
+ } else {
+ printf("Unknown state \"%s\"\n", list->param);
+ return 1;
+ }
+
+ ret = cec_send_message(&cec, &msg);
+ if (ret != CEC_OK) {
+ printf("Failed to send message\n");
+ return 1;
+ }
+ printf("Successfully sent message - Menu Status\n");
+ break;
+ }
+ case 'S': {
+ struct cec_buffer msg;
+ int addr;
+ int ret;
+ int i;
+
+ ret = parse_message(&msg, list->param);
+ if (ret) {
+ printf("Failed to parse message to send\n");
+ return 1;
+ }
+ printf("Sending message=0x");
+ for (i = 0; i < msg.len; i++)
+ printf("%02x", msg.payload[i]);
+ printf(" (length=%d) to addr=%d\n", msg.len, msg.dst);
+ addr = get_addr(&cec);
+ if (addr == -1) {
+ printf("Failed to get logical address of the CEC device\n");
+ return 1;
+ }
+ msg.src = addr;
+
+ ret = cec_send_message(&cec, &msg);
+ if (ret != CEC_OK) {
+ printf("Failed to send message\n");
+ return 1;
+ }
+ printf("Successfully sent custom message\n");
+ break;
+ }
+ case 'R': {
+ struct cec_buffer msg;
+ int i;
+
+ ret = cec_receive_message(&cec, &msg);
+ if (ret == CEC_TIMEOUT) {
+ printf("CEC receive message timed out\n");
+ return 2;
+ } else if (ret != CEC_OK) {
+ printf("Failed to receive a message\n");
+ return 1;
+ }
+
+ printf("Received message of length %d\n", msg.len);
+ for (i = 0; i < msg.len; i++)
+ printf("%02x", msg.payload[i]);
+ printf("\n");
+ break;
+ }
+ default:
+ printf("Command '%c' not yet implemented.\n", list->cmd);
+ break;
+ }
+
+ list = list->next;
+ }
+
+ return 0;
+}
diff --git a/include/gencec.h b/include/gencec.h
new file mode 100644
index 0000000..b727ddc
--- /dev/null
+++ b/include/gencec.h
@@ -0,0 +1,255 @@
+/*
+ * Copyright 2015 Samsung Electronics Co. Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __GENCEC_H__
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <time.h>
+
+/* Maximum length of the CEC message */
+#define CEC_MAX_LENGTH 15 /* 16 including the automatically added
+ * address byte. */
+#define MAX_NUM_OF_HDMI_PORTS 16
+#define CEC_MAX_NUM_LOG_ADDR 4
+#define DEFAULT_TIMEOUT 1000
+
+/* cec_version: list of CEC versions */
+enum cec_version {
+ CEC_VER_UNKNOWN,
+ CEC_VER_1_0,
+ CEC_VER_1_1,
+ CEC_VER_1_2,
+ CEC_VER_1_3,
+ CEC_VER_1_3A,
+ CEC_VER_1_3B,
+ CEC_VER_1_3C,
+ CEC_VER_1_4,
+ CEC_VER_1_4B,
+ CEC_VER_2_0,
+};
+
+enum cec_device_type {
+ /* Used internally for error handling */
+ CEC_DEVICE_TYPE_EMPTY,
+ CEC_DEVICE_TYPE_TV,
+ CEC_DEVICE_TYPE_RECORD,
+ CEC_DEVICE_TYPE_TUNER,
+ CEC_DEVICE_TYPE_PLAYBACK,
+ CEC_DEVICE_TYPE_AUDIOSYSTEM,
+ CEC_DEVICE_TYPE_SWITCH,
+ CEC_DEVICE_TYPE_VIDEOPROC,
+};
+
+/**
+ * struct cec_device - a structure used to keep context of the current used CEC
+ * device
+ * @caps: used to keep a pointer to the kernel caps structure for the
+ * device
+ * @handle: this is used to keep the file handle to the CEC device
+ * @initialised: flag set if the structure was properly initialised
+ * @log_addr: an array containing the assigned logical addresses
+ * @log_addr_type_int: an array containing the logical addresses' types as
+ * needed by the kernel
+ * @dev_type: device type, as neede by the library
+ * @dev_type_int: primary device type, as needed by the kernel driver
+ * @num_log_addr: number of ssigned logical addresses
+ */
+struct cec_device {
+ void *caps;
+ int handle;
+ int initialised;
+ uint32_t log_addr[CEC_MAX_NUM_LOG_ADDR];
+ uint32_t log_addr_type_int[CEC_MAX_NUM_LOG_ADDR];
+ enum cec_device_type dev_type[CEC_MAX_NUM_LOG_ADDR];
+ uint32_t dev_type_int[CEC_MAX_NUM_LOG_ADDR];
+ int num_log_addr;
+};
+
+/* cec_error: list of CEC framework errors */
+enum cec_error {
+ CEC_OK /* Success */,
+ CEC_TIMEOUT /* Timeout occured */,
+ CEC_NO_ADDR_LEFT /* No more logical addresses left */,
+ CEC_ERROR,
+};
+
+/**
+ * struct hdmi_port_info - Information about a HDMI port
+ * @port_number: the port number
+ */
+struct hdmi_port_info {
+ uint8_t port_number;
+};
+
+/**
+ * struct cec_info - a structure used to get information about the CEC device
+ * @version: supported CEC version
+ * @vendor_id: the vendor ID
+ * @ports_num: number of HDMI ports available in the system
+ * @ports_info: an array containing information about HDMI ports
+ * */
+struct cec_info {
+ enum cec_version version;
+ uint32_t vendor_id;
+ unsigned int ports_num;
+ struct hdmi_port_info ports_info[MAX_NUM_OF_HDMI_PORTS];
+};
+
+/**
+ * struct cec_msg - a structure used to store message that were received or are
+ * to be sent
+ * @dst: The address of the destination device
+ * @src: The address of the source device
+ * @len: The length of the payload of the message
+ * @payload: The payload of the message
+ * @ts: The timestamp for received messages
+ */
+struct cec_buffer {
+ uint8_t dst;
+ uint8_t src;
+ uint8_t len;
+ uint8_t payload[CEC_MAX_LENGTH];
+ struct timespec ts;
+};
+
+/**
+ * cec_open() - Open a CEC device
+ * @dev: pointer to a structure that will hold the state of the device
+ * @path: path to the CEC device
+ * Returns: on success CEC_OK, on error returns an negative error code
+ */
+int cec_open(struct cec_device *dev, char *path);
+/**
+ * cec_close() - Close a CEC device
+ * @dev: pointer to a structure that holds the state of the device
+ * Returns: on success CEC_OK, on error returns an negative error code
+ */
+int cec_close(struct cec_device *dev);
+/**
+ * cec_is_enabled() - Check whether the CEC device is enabled
+ * @dev: pointer to a structure that holds the state of the device
+ * Returns: true if all is ok and the CEC device is enabled, false otherwise
+ */
+bool cec_is_enabled(struct cec_device *dev);
+/**
+ * cec_enable() - Enable a CEC device
+ * @dev: pointer to a structure that will hold the state of the device
+ * @enable: true to enable the CEC device, false to disable the CEC device
+ * Returns: on success CEC_OK, on error returns an negative error code
+ */
+int cec_enable(struct cec_device *dev, bool enable);
+/**
+ * cec_passthrough() - Enable a CEC device
+ * @dev: pointer to a structure that will hold the state of the device
+ * @enable: true to enable the passthrough mode, false to disable
+ * Returns: on success CEC_OK, on error returns an negative error code
+ */
+int cec_passthrough(struct cec_device *dev, bool enable);
+/**
+ * cec_info() - Returns information about the CEC device
+ * @dev: pointer to a structure that holds the state of the device
+ * @info: pointer to a info structure that will hold the information about
+ * the CEC device
+ * Returns: on success CEC_OK, on error returns an negative error code
+ */
+int cec_get_info(struct cec_device *dev, struct cec_info *info);
+/**
+ * cec_is_connected() - Return information about whether a device is connected
+ * to the port
+ * @dev: pointer to a structure that holds the state of the device
+ * Returns: when a device is connected to the port returns CEC_CONNECTED,
+ * CEC_DISCONNECTED when there is no device connected, on error
+ * returns an negative error code
+ */
+int cec_is_connected(struct cec_device *dev);
+/**
+ * cec_send_message() - Send a message over the CEC bus
+ * @dev: pointer to a structure that holds the state of the device
+ * @msg: the message do be sent over the CEC bus
+ * Returns: CEC_OK on success
+ * CEC_REPLY on successful send and reply receive
+ * CEC_REPLY_TIMEOUT when waiting for reply timed out
+ * CEC_TIMEOUT when a timeout occurred while sending the message
+ * negative error code on other error
+ */
+int cec_send_message(struct cec_device *dev, struct cec_buffer *msg);
+/**
+ * cec_receive_message() - Receive a message over the CEC bus
+ * @dev: pointer to a structure that holds the state of the device
+ * @msg: a structure used to store the message received over the CEC bus
+ * Returns: CEC_OK on success
+ * CEC_TIMEOUT when a timeout occurred while waiting for message
+ * negative error code on error
+ * Remarks: when waiting for a reply, the reply is stored in the msg struct
+ */
+int cec_receive_message(struct cec_device *dev, struct cec_buffer *msg);
+/**
+ * cec_get_logical_addrs() - Add a new logical address to the CEC device
+ * @dev: pointer to a structure that holds the state of the device
+ * @addr: pointer to an array to hold the list of assigned logical
+ * addresses, the size should be CEC_MAX_NUM_LOG_ADDR
+ * @num_addr: pointer to an int that will hold the number of assigned
+ * logical addresses
+ * Returns: CEC_OK on success
+ * negative error code on error
+ */
+int cec_get_logical_addrs(struct cec_device *dev, uint8_t *addr, int *num_addr);
+/**
+ * cec_add_logical_addr() - Add a new logical address to the CEC device
+ * @dev: pointer to a structure that holds the state of the device
+ * @type: the type of the device that is to be added, please note that
+ * this indicated the type and not the address that will be
+ * assigned
+ * @addr: a pointer to a location where to store the assigned logical
+ * address
+ * Returns: CEC_OK on success
+ * CEC_TIMEOUT when a timeout occurred while waiting for message
+ * CEC_NO_ADDR_LEFT when all addresses related to the chosen device
+ * type are already taken
+ * negative error code on error
+ */
+int cec_add_logical_addr(struct cec_device *dev, enum cec_device_type type,
+ uint8_t *addr);
+/**
+ * cec_clear_logical_addrs() - Clear the logical addresses that were assigned to
+ * the device
+ * @dev: pointer to a structure that holds the state of the device
+ * Returns: CEC_OK on success
+ * CEC_TIMEOUT when a timeout occurred while waiting for message
+ * negative error code on error
+ */
+int cec_clear_logical_addrs(struct cec_device *dev);
+/**
+ * cec_get_physical_addr() - Get the physical addr of the CEC device
+ * @dev: pointer to a structure that holds the state of the device
+ * @phys_addr: pointer to a uint16_t which will hold the physical address
+ * Returns: CEC_OK on success
+ * CEC_TIMEOUT when a timeout occurred while waiting for message
+ * negative error code on error
+ */
+int cec_get_physical_addr(struct cec_device *dev, uint16_t *phys_addr);
+/**
+ * cec_set_physical_addr() - Get the physical addr of the CEC device
+ * @dev: pointer to a structure that holds the state of the device
+ * @phys_addr: a uint16_t which holding the physical address
+ * Returns: CEC_OK on success
+ * CEC_TIMEOUT when a timeout occurred while waiting for message
+ * negative error code on error
+ */
+int cec_set_physical_addr(struct cec_device *dev, uint16_t phys_addr);
+
+#endif /* __GENCEC_H__ */
diff --git a/libgencec.pc.in b/libgencec.pc.in
new file mode 100644
index 0000000..8d75c4d
--- /dev/null
+++ b/libgencec.pc.in
@@ -0,0 +1,10 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: libGenCEC
+Description: General CEC framework library.
+Version: @VERSION@
+Libs: -L${libdir} -lgencec
+Cflags: -I${includedir}
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..cb024f0
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,4 @@
+lib_LTLIBRARIES = libgencec.la
+libgencec_la_SOURCES = gencec.c
+libgencec_la_LDFLAGS = -version-info 0:1:0
+AM_CPPFLAGS=-I$(top_srcdir)/include
diff --git a/src/gencec.c b/src/gencec.c
new file mode 100644
index 0000000..2224115
--- /dev/null
+++ b/src/gencec.c
@@ -0,0 +1,445 @@
+/*
+ * Copyright 2015 Samsung Electronics Co. Ltd
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <linux/cec.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "gencec.h"
+
+bool cec_is_enabled(struct cec_device *dev)
+{
+ struct cec_caps *caps = (struct cec_caps *)dev->caps;
+ int ret;
+
+ if (!dev)
+ return CEC_ERROR;
+ if (!dev->initialised)
+ return CEC_ERROR;
+
+ if (caps->capabilities && CEC_CAP_STATE) {
+ uint32_t arg;
+
+ ret = ioctl(dev->handle, CEC_G_ADAP_STATE, &arg);
+ if (ret)
+ return CEC_ERROR;
+ if (arg == 0)
+ return false;
+ }
+
+ return true;
+}
+
+int cec_enable(struct cec_device *dev, bool enable)
+{
+ struct cec_caps *caps = (struct cec_caps *)dev->caps;
+ int ret;
+
+ if (!dev)
+ return CEC_ERROR;
+ if (!dev->initialised)
+ return CEC_ERROR;
+
+ if (caps->capabilities && CEC_CAP_STATE) {
+ uint32_t arg;
+
+ arg = enable ? CEC_STATE_ENABLED : CEC_STATE_DISABLED;
+ ret = ioctl(dev->handle, CEC_S_ADAP_STATE, &arg);
+ if (ret)
+ return CEC_ERROR;
+ }
+
+ return CEC_OK;
+}
+
+int cec_passthrough(struct cec_device *dev, bool enable)
+{
+ struct cec_caps *caps = (struct cec_caps *)dev->caps;
+ int ret;
+
+ if (!dev)
+ return CEC_ERROR;
+ if (!dev->initialised)
+ return CEC_ERROR;
+
+ if (caps->capabilities && CEC_CAP_PASSTHROUGH) {
+ uint32_t arg;
+
+ arg = enable ? CEC_PASSTHROUGH_ENABLED : CEC_PASSTHROUGH_DISABLED;
+ ret = ioctl(dev->handle, CEC_S_PASSTHROUGH, &arg);
+ if (ret)
+ return CEC_ERROR;
+ }
+
+ return CEC_OK;
+}
+
+static int check_state(struct cec_device *dev)
+{
+ if (!dev)
+ return CEC_ERROR;
+ if (!dev->initialised)
+ return CEC_ERROR;
+ if (!cec_is_enabled(dev))
+ return CEC_ERROR;
+ return CEC_OK;
+}
+
+int cec_open(struct cec_device *dev, char *path)
+{
+ int ret;
+
+ if (!dev || !path)
+ return CEC_ERROR;
+
+ memset(dev, 0, sizeof(*dev));
+
+ dev->handle = open(path, O_RDWR);
+ if (dev->handle == -1)
+ return CEC_ERROR;
+
+ dev->caps = malloc(sizeof(struct cec_caps));
+ if (!dev->caps) {
+ close(dev->handle);
+ return CEC_ERROR;
+ }
+
+ ret = ioctl(dev->handle, CEC_G_CAPS, dev->caps);
+ if (ret) {
+ free(dev->caps);
+ close(dev->handle);
+ return CEC_ERROR;
+ }
+
+ dev->initialised = 1;
+
+ return CEC_OK;
+}
+
+int cec_close(struct cec_device *dev)
+{
+ if (!dev)
+ return CEC_ERROR;
+ if (close(dev->handle) == -1)
+ return CEC_ERROR;
+ dev->initialised = 0;
+ return CEC_OK;
+}
+
+int cec_get_info(struct cec_device *dev, struct cec_info *info)
+{
+ struct cec_caps *caps;
+ int i;
+
+ if (check_state(dev) != CEC_OK || !info)
+ return CEC_ERROR;
+
+ caps = (struct cec_caps *)(dev->caps);
+
+ info->vendor_id = caps->vendor_id;
+ switch (caps->version) {
+ case CEC_VERSION_1_4:
+ info->version = CEC_VER_1_4;
+ break;
+ case CEC_VERSION_2_0:
+ info->version = CEC_VER_2_0;
+ break;
+ default:
+ info->version = CEC_VER_UNKNOWN;
+ break;
+ }
+ info->ports_num = 1; /* ? */
+
+ for (i = 0; i < MAX_NUM_OF_HDMI_PORTS; i++) {
+ info->ports_info[i].port_number = i;
+ }
+
+ return CEC_OK;
+}
+
+int cec_is_connected(struct cec_device *dev)
+{
+ if (!dev)
+ return CEC_ERROR;
+ /* TODO */
+ return CEC_OK;
+}
+
+int cec_send_message(struct cec_device *dev, struct cec_buffer *msg)
+{
+ struct cec_msg msg_int;
+ int i, ret;
+
+ if (check_state(dev) != CEC_OK || !msg)
+ return CEC_ERROR;
+
+ if (msg->len > CEC_MAX_LENGTH)
+ return CEC_ERROR;
+
+ msg_int.len = msg->len + 1;
+ msg_int.msg[0] = msg->src << 4 & 0xf0;
+ msg_int.msg[0] |= msg->dst & 0x0f;
+ for (i = 0; i < msg->len; i++)
+ msg_int.msg[i + 1] = msg->payload[i];
+ msg_int.reply = 0;
+ msg_int.timeout = DEFAULT_TIMEOUT;
+
+ ret = ioctl(dev->handle, CEC_TRANSMIT, &msg_int);
+ if (ret) {
+ if (errno == ETIMEDOUT)
+ return CEC_TIMEOUT;
+ return CEC_ERROR;
+ }
+
+
+ return CEC_OK;
+}
+
+int cec_receive_message(struct cec_device *dev, struct cec_buffer *msg)
+{
+ struct cec_msg msg_int;
+ int i, ret;
+
+ if (check_state(dev) != CEC_OK || !msg)
+ return CEC_ERROR;
+
+ msg_int.timeout = DEFAULT_TIMEOUT;
+ ret = ioctl(dev->handle, CEC_RECEIVE, &msg_int);
+ if (ret) {
+ if (errno == ETIMEDOUT)
+ return CEC_TIMEOUT;
+ return CEC_ERROR;
+ }
+ if (msg_int.len == 0 || msg_int.len > CEC_MAX_LENGTH + 1)
+ return CEC_ERROR;
+
+ msg->src = msg_int.msg[0] >> 4 & 0xf;
+ msg->dst = msg_int.msg[0] & 0xf;
+ msg->ts.tv_sec = msg_int.ts / 1000000000;
+ msg->ts.tv_nsec = msg_int.ts % 1000000000;
+ msg->len = msg_int.len - 1;
+ for (i = 0; i < msg->len; i++)
+ msg->payload[i] = msg_int.msg[i + 1];
+
+ return CEC_OK;
+}
+
+static int dev_type_to_int_dev_type(enum cec_device_type type)
+{
+ switch (type) {
+ case CEC_DEVICE_TYPE_TV:
+ return CEC_PRIM_DEVTYPE_TV;
+ case CEC_DEVICE_TYPE_RECORD:
+ return CEC_PRIM_DEVTYPE_RECORD;
+ case CEC_DEVICE_TYPE_TUNER:
+ return CEC_PRIM_DEVTYPE_TUNER;
+ case CEC_DEVICE_TYPE_PLAYBACK:
+ return CEC_PRIM_DEVTYPE_PLAYBACK;
+ case CEC_DEVICE_TYPE_AUDIOSYSTEM:
+ return CEC_PRIM_DEVTYPE_AUDIOSYSTEM;
+ case CEC_DEVICE_TYPE_SWITCH:
+ return CEC_PRIM_DEVTYPE_SWITCH;
+ case CEC_DEVICE_TYPE_VIDEOPROC:
+ return CEC_PRIM_DEVTYPE_VIDEOPROC;
+ }
+ return -1;
+}
+
+static int dev_type_to_int_addr_type(enum cec_device_type type)
+{
+ switch (type) {
+ case CEC_DEVICE_TYPE_TV:
+ return CEC_LOG_ADDR_TYPE_TV;
+ case CEC_DEVICE_TYPE_RECORD:
+ return CEC_LOG_ADDR_TYPE_RECORD;
+ case CEC_DEVICE_TYPE_TUNER:
+ return CEC_LOG_ADDR_TYPE_TUNER;
+ case CEC_DEVICE_TYPE_PLAYBACK:
+ return CEC_LOG_ADDR_TYPE_PLAYBACK;
+ case CEC_DEVICE_TYPE_AUDIOSYSTEM:
+ return CEC_LOG_ADDR_TYPE_AUDIOSYSTEM;
+ case CEC_DEVICE_TYPE_SWITCH:
+ return CEC_LOG_ADDR_TYPE_UNREGISTERED;
+ case CEC_DEVICE_TYPE_VIDEOPROC:
+ return CEC_LOG_ADDR_TYPE_SPECIFIC;
+ case CEC_DEVICE_TYPE_EMPTY:
+ default:
+ return -1;
+ }
+}
+
+#if (CEC_MAX_LOG_ADDRS < CEC_MAX_NUM_LOG_ADDR)
+#error The CEC_MAX_NUM_LOG_ADDR (lib define) is more than CEC_MAX_LOG_ADDRS \
+ (kernel framework defined)
+#endif
+
+static int _cec_get_logical_addrs(struct cec_device *dev)
+{
+ struct cec_log_addrs log_addr;
+ uint32_t dev_type;
+ uint32_t addr_type;
+ int ret;
+ int i;
+
+ if (check_state(dev) != CEC_OK)
+ return CEC_ERROR;
+
+ memset(&log_addr, 0, sizeof(log_addr));
+ ret = ioctl(dev->handle, CEC_G_ADAP_LOG_ADDRS, &log_addr);
+ if (ret)
+ return CEC_ERROR;
+
+ for (i = 0; i < log_addr.num_log_addrs; i++) {
+ dev->dev_type_int[i] = log_addr.primary_device_type[i];
+ dev->log_addr_type_int[i] = log_addr.log_addr_type[i];
+ dev->log_addr[i] = log_addr.log_addr[i];
+ }
+
+ dev->num_log_addr = log_addr.num_log_addrs;
+
+ return CEC_OK;
+}
+
+int cec_get_logical_addrs(struct cec_device *dev, uint8_t *addr, int *num_addr)
+{
+ int i;
+
+ if (!addr || !num_addr)
+ return CEC_ERROR;
+
+ if (_cec_get_logical_addrs(dev) != CEC_OK)
+ return CEC_ERROR;
+
+ *num_addr = dev->num_log_addr;
+ for (i = 0; i < *num_addr; i++)
+ addr[i] = dev->log_addr[i];
+
+ return CEC_OK;
+}
+
+int cec_add_logical_addr(struct cec_device *dev, enum cec_device_type type,
+ uint8_t *addr)
+{
+ struct cec_log_addrs log_addr;
+ uint32_t dev_type;
+ uint32_t addr_type;
+ int ret;
+ int i;
+
+ if (check_state(dev) != CEC_OK)
+ return CEC_ERROR;
+
+ /* Refresh copy of logical addrs */
+ if (_cec_get_logical_addrs(dev) != CEC_OK)
+ return CEC_ERROR;
+
+ if (dev->num_log_addr >= CEC_MAX_NUM_LOG_ADDR)
+ return CEC_NO_ADDR_LEFT;
+
+ memset(&log_addr, 0, sizeof(log_addr));
+
+ if (type != CEC_DEVICE_TYPE_EMPTY) {
+ dev->dev_type[dev->num_log_addr] = type;
+ dev->dev_type_int[dev->num_log_addr] = dev_type_to_int_dev_type(type);
+ dev->log_addr_type_int[dev->num_log_addr] = dev_type_to_int_addr_type(type);
+ if (dev->dev_type_int[dev->num_log_addr] == -1 ||
+ dev->log_addr_type_int[dev->num_log_addr] == -1)
+ return CEC_ERROR;
+ dev->num_log_addr++;
+ if (dev->num_log_addr >= CEC_MAX_NUM_LOG_ADDR) {
+ dev->num_log_addr--;
+ return CEC_NO_ADDR_LEFT;
+ }
+ }
+
+ log_addr.cec_version = CEC_VERSION_1_4;
+ log_addr.num_log_addrs = dev->num_log_addr;
+ for (i = 0; i < dev->num_log_addr; i++) {
+ log_addr.primary_device_type[i] = dev->dev_type_int[i];
+ log_addr.log_addr_type[i] = dev->log_addr_type_int[i];
+ }
+ ret = ioctl(dev->handle, CEC_S_ADAP_LOG_ADDRS, &log_addr);
+ if (ret) {
+ /* Should it call set log addr again without the last added address? */
+ if (--dev->num_log_addr > 0)
+ cec_add_logical_addr(dev, CEC_DEVICE_TYPE_EMPTY, 0);
+ return CEC_ERROR;
+ }
+
+ dev->log_addr[i - 1] = log_addr.log_addr[i - 1];
+ if (addr)
+ *addr = log_addr.log_addr[i - 1];
+
+ return CEC_OK;
+}
+
+int cec_clear_logical_addrs(struct cec_device *dev)
+{
+ struct cec_log_addrs log_addr;
+ uint32_t dev_type;
+ uint32_t addr_type;
+ int ret;
+ int i;
+
+ if (check_state(dev) != CEC_OK)
+ return CEC_ERROR;
+
+ memset(&log_addr, 0, sizeof(log_addr));
+ log_addr.num_log_addrs = 0;
+ log_addr.cec_version = CEC_VERSION_1_4;
+
+ ret = ioctl(dev->handle, CEC_S_ADAP_LOG_ADDRS, &log_addr);
+ if (ret)
+ return CEC_ERROR;
+
+ return CEC_OK;
+}
+
+int cec_get_physical_addr(struct cec_device *dev, uint16_t *phys_addr)
+{
+ int ret;
+
+ if (check_state(dev) != CEC_OK || !phys_addr)
+ return CEC_ERROR;
+ ret = ioctl(dev->handle, CEC_G_ADAP_PHYS_ADDR, phys_addr);
+ if (ret)
+ return CEC_ERROR;
+
+ return CEC_OK;
+}
+
+int cec_set_physical_addr(struct cec_device *dev, uint16_t phys_addr)
+{
+ int ret;
+
+ if (check_state(dev) != CEC_OK)
+ return CEC_ERROR;
+ ret = ioctl(dev->handle, CEC_S_ADAP_PHYS_ADDR, &phys_addr);
+ if (ret)
+ return CEC_ERROR;
+
+ return CEC_OK;
+}
+
--
1.7.9.5