linux-media.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v6 00/11]
@ 2015-05-04 17:32 Kamil Debski
  2015-05-04 17:32 ` [PATCH v6 01/11] dts: exynos4*: add HDMI CEC pin definition to pinctrl Kamil Debski
                   ` (13 more replies)
  0 siblings, 14 replies; 30+ messages in thread
From: Kamil Debski @ 2015-05-04 17:32 UTC (permalink / raw)
  To: dri-devel, linux-media
  Cc: m.szyprowski, k.debski, mchehab, hverkuil, kyungmin.park, thomas,
	sean, dmitry.torokhov, linux-input, linux-samsung-soc, lars

Hi,

The sixth version of this patchset addresses recent comments on the mailing
list. Please see the changelog below for details.

Best wishes,
Kamil Debski

Changes since v5
================
- drop struct cec_timeval in favour of a __u64 that keeps the timestamp in ns
- remove userspace documentation from Documentation/cec.txt as userspace API
  is described in the DocBook
- add missing documentation for the passthrough mode to the DocBook
- add information about the number of events that can be queued
- fix misspelling of reply
- fix behaviour of posting an event in cec_received_msg, such that the behaviour
  is consistent with the documentation

Changes since v4
================
- add sequence numbering to transmitted messages
- add sequence number handling to event hanlding
- add passthrough mode
- change reserved field sizes
- fixed CEC version defines and addec CEC 2.0 commands
- add DocBook documentation

Changes since v3
================
- remove the promiscuous mode
- rewrite the devicetree patches
- fixes, expansion and partial rewrite of the documentation
- reorder of API structures and addition of reserved fields
- use own struct to report time (32/64 bit safe)
- fix of handling events
- add cec.h to include/uapi/linux/Kbuild
- fixes in the adv76xx driver (add missing methods, change adv7604 to adv76xx)
- cleanup of debug messages in s5p-cec driver
- remove non necessary claiming of a gpio in the s5p-cec driver
- cleanup headers of the s5p-cec driver

Changes since v2
===============-
- added promiscuous mode
- added new key codes to the input framework
- add vendor ID reporting
- add the possibility to clear assigned logical addresses
- cleanup of the rc cec map

Changes since v1
================
- documentation edited and moved to the Documentation folder
- added key up/down message handling
- add missing CEC commands to the cec.h file

Background
==========

The work on a common CEC framework was started over three years ago by Hans
Verkuil. Unfortunately the work has stalled. As I have received the task of
creating a driver for the CEC interface module present on the Exynos range of
SoCs, I got in touch with Hans. He replied that the work stalled due to his
lack of time.

Original RFC by Hans Verkuil/Martin Bugge
=========================================
https://www.mail-archive.com/linux-media@vger.kernel.org/msg28735.html


Hans Verkuil (5):
  cec: add HDMI CEC framework
  DocBook/media: add CEC documentation
  v4l2-subdev: add HDMI CEC ops
  cec: adv7604: add cec support.
  cec: adv7511: add cec support.

Kamil Debski (6):
  dts: exynos4*: add HDMI CEC pin definition to pinctrl
  dts: exynos4: add node for the HDMI CEC device
  dts: exynos4412-odroid*: enable the HDMI CEC device
  HID: add HDMI CEC specific keycodes
  rc: Add HDMI CEC protoctol handling
  cec: s5p-cec: Add s5p-cec driver

 Documentation/DocBook/media/Makefile               |    4 +-
 Documentation/DocBook/media/v4l/biblio.xml         |   10 +
 Documentation/DocBook/media/v4l/cec-api.xml        |   74 ++
 Documentation/DocBook/media/v4l/cec-func-close.xml |   59 +
 Documentation/DocBook/media/v4l/cec-func-ioctl.xml |   73 ++
 Documentation/DocBook/media/v4l/cec-func-open.xml  |   94 ++
 Documentation/DocBook/media/v4l/cec-func-poll.xml  |   89 ++
 .../DocBook/media/v4l/cec-ioc-g-adap-log-addrs.xml |  275 +++++
 .../DocBook/media/v4l/cec-ioc-g-adap-phys-addr.xml |   78 ++
 .../DocBook/media/v4l/cec-ioc-g-adap-state.xml     |   87 ++
 Documentation/DocBook/media/v4l/cec-ioc-g-caps.xml |  173 +++
 .../DocBook/media/v4l/cec-ioc-g-event.xml          |  125 ++
 .../DocBook/media/v4l/cec-ioc-g-passthrough.xml    |   88 ++
 .../DocBook/media/v4l/cec-ioc-g-vendor-id.xml      |   70 ++
 .../DocBook/media/v4l/cec-ioc-receive.xml          |  185 +++
 Documentation/DocBook/media_api.tmpl               |    6 +-
 Documentation/cec.txt                              |  165 +++
 .../devicetree/bindings/media/s5p-cec.txt          |   33 +
 arch/arm/boot/dts/exynos4.dtsi                     |   12 +
 arch/arm/boot/dts/exynos4210-pinctrl.dtsi          |    7 +
 arch/arm/boot/dts/exynos4412-odroid-common.dtsi    |    4 +
 arch/arm/boot/dts/exynos4x12-pinctrl.dtsi          |    7 +
 drivers/media/Kconfig                              |    6 +
 drivers/media/Makefile                             |    2 +
 drivers/media/cec.c                                | 1191 ++++++++++++++++++++
 drivers/media/i2c/adv7511.c                        |  347 +++++-
 drivers/media/i2c/adv7604.c                        |  207 +++-
 drivers/media/platform/Kconfig                     |   10 +
 drivers/media/platform/Makefile                    |    1 +
 drivers/media/platform/s5p-cec/Makefile            |    4 +
 drivers/media/platform/s5p-cec/exynos_hdmi_cec.h   |   37 +
 .../media/platform/s5p-cec/exynos_hdmi_cecctrl.c   |  208 ++++
 drivers/media/platform/s5p-cec/regs-cec.h          |   96 ++
 drivers/media/platform/s5p-cec/s5p_cec.c           |  283 +++++
 drivers/media/platform/s5p-cec/s5p_cec.h           |   76 ++
 drivers/media/rc/keymaps/Makefile                  |    1 +
 drivers/media/rc/keymaps/rc-cec.c                  |  144 +++
 drivers/media/rc/rc-main.c                         |    1 +
 include/media/adv7511.h                            |    6 +-
 include/media/cec.h                                |  142 +++
 include/media/rc-core.h                            |    1 +
 include/media/rc-map.h                             |    5 +-
 include/media/v4l2-subdev.h                        |    8 +
 include/uapi/linux/Kbuild                          |    1 +
 include/uapi/linux/cec.h                           |  332 ++++++
 include/uapi/linux/input.h                         |   12 +
 46 files changed, 4824 insertions(+), 15 deletions(-)
 create mode 100644 Documentation/DocBook/media/v4l/cec-api.xml
 create mode 100644 Documentation/DocBook/media/v4l/cec-func-close.xml
 create mode 100644 Documentation/DocBook/media/v4l/cec-func-ioctl.xml
 create mode 100644 Documentation/DocBook/media/v4l/cec-func-open.xml
 create mode 100644 Documentation/DocBook/media/v4l/cec-func-poll.xml
 create mode 100644 Documentation/DocBook/media/v4l/cec-ioc-g-adap-log-addrs.xml
 create mode 100644 Documentation/DocBook/media/v4l/cec-ioc-g-adap-phys-addr.xml
 create mode 100644 Documentation/DocBook/media/v4l/cec-ioc-g-adap-state.xml
 create mode 100644 Documentation/DocBook/media/v4l/cec-ioc-g-caps.xml
 create mode 100644 Documentation/DocBook/media/v4l/cec-ioc-g-event.xml
 create mode 100644 Documentation/DocBook/media/v4l/cec-ioc-g-passthrough.xml
 create mode 100644 Documentation/DocBook/media/v4l/cec-ioc-g-vendor-id.xml
 create mode 100644 Documentation/DocBook/media/v4l/cec-ioc-receive.xml
 create mode 100644 Documentation/cec.txt
 create mode 100644 Documentation/devicetree/bindings/media/s5p-cec.txt
 create mode 100644 drivers/media/cec.c
 create mode 100644 drivers/media/platform/s5p-cec/Makefile
 create mode 100644 drivers/media/platform/s5p-cec/exynos_hdmi_cec.h
 create mode 100644 drivers/media/platform/s5p-cec/exynos_hdmi_cecctrl.c
 create mode 100644 drivers/media/platform/s5p-cec/regs-cec.h
 create mode 100644 drivers/media/platform/s5p-cec/s5p_cec.c
 create mode 100644 drivers/media/platform/s5p-cec/s5p_cec.h
 create mode 100644 drivers/media/rc/keymaps/rc-cec.c
 create mode 100644 include/media/cec.h
 create mode 100644 include/uapi/linux/cec.h

-- 
1.7.9.5


^ permalink raw reply	[flat|nested] 30+ messages in thread

* [PATCH v6 01/11] dts: exynos4*: add HDMI CEC pin definition to pinctrl
  2015-05-04 17:32 [PATCH v6 00/11] Kamil Debski
@ 2015-05-04 17:32 ` Kamil Debski
  2015-05-05  3:59   ` Krzysztof Kozłowski
  2015-05-04 17:32 ` [PATCH v6 02/11] dts: exynos4: add node for the HDMI CEC device Kamil Debski
                   ` (12 subsequent siblings)
  13 siblings, 1 reply; 30+ messages in thread
From: Kamil Debski @ 2015-05-04 17:32 UTC (permalink / raw)
  To: dri-devel, linux-media
  Cc: m.szyprowski, k.debski, mchehab, hverkuil, kyungmin.park, thomas,
	sean, dmitry.torokhov, linux-input, linux-samsung-soc, lars

Add pinctrl nodes for the HDMI CEC device to the Exynos4210 and
Exynos4x12 SoCs. These are required by the HDMI CEC device.

Signed-off-by: Kamil Debski <k.debski@samsung.com>
---
 arch/arm/boot/dts/exynos4210-pinctrl.dtsi |    7 +++++++
 arch/arm/boot/dts/exynos4x12-pinctrl.dtsi |    7 +++++++
 2 files changed, 14 insertions(+)

diff --git a/arch/arm/boot/dts/exynos4210-pinctrl.dtsi b/arch/arm/boot/dts/exynos4210-pinctrl.dtsi
index a7c2128..9331c62 100644
--- a/arch/arm/boot/dts/exynos4210-pinctrl.dtsi
+++ b/arch/arm/boot/dts/exynos4210-pinctrl.dtsi
@@ -820,6 +820,13 @@
 			samsung,pin-pud = <1>;
 			samsung,pin-drv = <0>;
 		};
+
+		hdmi_cec: hdmi-cec {
+			samsung,pins = "gpx3-6";
+			samsung,pin-function = <3>;
+			samsung,pin-pud = <0>;
+			samsung,pin-drv = <0>;
+		};
 	};
 
 	pinctrl@03860000 {
diff --git a/arch/arm/boot/dts/exynos4x12-pinctrl.dtsi b/arch/arm/boot/dts/exynos4x12-pinctrl.dtsi
index c141931..875464e 100644
--- a/arch/arm/boot/dts/exynos4x12-pinctrl.dtsi
+++ b/arch/arm/boot/dts/exynos4x12-pinctrl.dtsi
@@ -885,6 +885,13 @@
 			samsung,pin-pud = <0>;
 			samsung,pin-drv = <0>;
 		};
+
+		hdmi_cec: hdmi-cec {
+			samsung,pins = "gpx3-6";
+			samsung,pin-function = <3>;
+			samsung,pin-pud = <0>;
+			samsung,pin-drv = <0>;
+		};
 	};
 
 	pinctrl@03860000 {
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH v6 02/11] dts: exynos4: add node for the HDMI CEC device
  2015-05-04 17:32 [PATCH v6 00/11] Kamil Debski
  2015-05-04 17:32 ` [PATCH v6 01/11] dts: exynos4*: add HDMI CEC pin definition to pinctrl Kamil Debski
@ 2015-05-04 17:32 ` Kamil Debski
  2015-05-05  3:59   ` Krzysztof Kozłowski
  2015-05-04 17:32 ` [PATCH v6 03/11] dts: exynos4412-odroid*: enable " Kamil Debski
                   ` (11 subsequent siblings)
  13 siblings, 1 reply; 30+ messages in thread
From: Kamil Debski @ 2015-05-04 17:32 UTC (permalink / raw)
  To: dri-devel, linux-media
  Cc: m.szyprowski, k.debski, mchehab, hverkuil, kyungmin.park, thomas,
	sean, dmitry.torokhov, linux-input, linux-samsung-soc, lars

This patch adds HDMI CEC node specific to the Exynos4210/4x12 SoC series.

Signed-off-by: Kamil Debski <k.debski@samsung.com>
---
 arch/arm/boot/dts/exynos4.dtsi |   12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/arch/arm/boot/dts/exynos4.dtsi b/arch/arm/boot/dts/exynos4.dtsi
index e20cdc2..8776db9 100644
--- a/arch/arm/boot/dts/exynos4.dtsi
+++ b/arch/arm/boot/dts/exynos4.dtsi
@@ -704,6 +704,18 @@
 		status = "disabled";
 	};
 
+	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 = "disabled";
+	};
+
 	mixer: mixer@12C10000 {
 		compatible = "samsung,exynos4210-mixer";
 		interrupts = <0 91 0>;
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH v6 03/11] dts: exynos4412-odroid*: enable the HDMI CEC device
  2015-05-04 17:32 [PATCH v6 00/11] Kamil Debski
  2015-05-04 17:32 ` [PATCH v6 01/11] dts: exynos4*: add HDMI CEC pin definition to pinctrl Kamil Debski
  2015-05-04 17:32 ` [PATCH v6 02/11] dts: exynos4: add node for the HDMI CEC device Kamil Debski
@ 2015-05-04 17:32 ` Kamil Debski
  2015-05-05  4:00   ` Krzysztof Kozłowski
  2015-05-04 17:32 ` [PATCH v6 04/11] HID: add HDMI CEC specific keycodes Kamil Debski
                   ` (10 subsequent siblings)
  13 siblings, 1 reply; 30+ messages in thread
From: Kamil Debski @ 2015-05-04 17:32 UTC (permalink / raw)
  To: dri-devel, linux-media
  Cc: m.szyprowski, k.debski, mchehab, hverkuil, kyungmin.park, thomas,
	sean, dmitry.torokhov, linux-input, linux-samsung-soc, lars

Add a dts node entry and enable the HDMI CEC device present in the Exynos4
family of SoCs.

Signed-off-by: Kamil Debski <k.debski@samsung.com>
---
 arch/arm/boot/dts/exynos4412-odroid-common.dtsi |    4 ++++
 1 file changed, 4 insertions(+)

diff --git a/arch/arm/boot/dts/exynos4412-odroid-common.dtsi b/arch/arm/boot/dts/exynos4412-odroid-common.dtsi
index 8de12af..e50862d 100644
--- a/arch/arm/boot/dts/exynos4412-odroid-common.dtsi
+++ b/arch/arm/boot/dts/exynos4412-odroid-common.dtsi
@@ -469,6 +469,10 @@
 		status = "okay";
 	};
 
+	cec@100B0000 {
+		status = "okay";
+	};
+
 	hdmi_ddc: i2c@13880000 {
 		status = "okay";
 		pinctrl-names = "default";
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH v6 04/11] HID: add HDMI CEC specific keycodes
  2015-05-04 17:32 [PATCH v6 00/11] Kamil Debski
                   ` (2 preceding siblings ...)
  2015-05-04 17:32 ` [PATCH v6 03/11] dts: exynos4412-odroid*: enable " Kamil Debski
@ 2015-05-04 17:32 ` Kamil Debski
  2015-05-08 11:00   ` Hans Verkuil
  2015-05-04 17:32 ` [PATCH v6 05/11] rc: Add HDMI CEC protoctol handling Kamil Debski
                   ` (9 subsequent siblings)
  13 siblings, 1 reply; 30+ messages in thread
From: Kamil Debski @ 2015-05-04 17:32 UTC (permalink / raw)
  To: dri-devel, linux-media
  Cc: m.szyprowski, k.debski, mchehab, hverkuil, kyungmin.park, thomas,
	sean, dmitry.torokhov, linux-input, linux-samsung-soc, lars

Add HDMI CEC specific keycodes to the keycodes definition.

Signed-off-by: Kamil Debski <k.debski@samsung.com>
---
 include/uapi/linux/input.h |   12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/include/uapi/linux/input.h b/include/uapi/linux/input.h
index 731417c..7430a3f 100644
--- a/include/uapi/linux/input.h
+++ b/include/uapi/linux/input.h
@@ -752,6 +752,18 @@ struct input_keymap_entry {
 #define KEY_KBDINPUTASSIST_ACCEPT		0x264
 #define KEY_KBDINPUTASSIST_CANCEL		0x265
 
+#define KEY_RIGHT_UP			0x266
+#define KEY_RIGHT_DOWN			0x267
+#define KEY_LEFT_UP			0x268
+#define KEY_LEFT_DOWN			0x269
+
+#define KEY_NEXT_FAVORITE		0x270
+#define KEY_STOP_RECORD			0x271
+#define KEY_PAUSE_RECORD		0x272
+#define KEY_VOD				0x273
+#define KEY_UNMUTE			0x274
+#define KEY_DVB				0x275
+
 #define BTN_TRIGGER_HAPPY		0x2c0
 #define BTN_TRIGGER_HAPPY1		0x2c0
 #define BTN_TRIGGER_HAPPY2		0x2c1
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH v6 05/11] rc: Add HDMI CEC protoctol handling
  2015-05-04 17:32 [PATCH v6 00/11] Kamil Debski
                   ` (3 preceding siblings ...)
  2015-05-04 17:32 ` [PATCH v6 04/11] HID: add HDMI CEC specific keycodes Kamil Debski
@ 2015-05-04 17:32 ` Kamil Debski
  2015-05-08 11:02   ` Hans Verkuil
  2015-05-04 17:32 ` [PATCH v6 06/11] cec: add HDMI CEC framework Kamil Debski
                   ` (8 subsequent siblings)
  13 siblings, 1 reply; 30+ messages in thread
From: Kamil Debski @ 2015-05-04 17:32 UTC (permalink / raw)
  To: dri-devel, linux-media
  Cc: m.szyprowski, k.debski, mchehab, hverkuil, kyungmin.park, thomas,
	sean, dmitry.torokhov, linux-input, linux-samsung-soc, lars

Add handling of remote control events coming from the HDMI CEC bus.
This patch includes a new keymap that maps values found in the CEC
messages to the keys pressed and released. Also, a new protocol has
been added to the core.

Signed-off-by: Kamil Debski <k.debski@samsung.com>
---
 drivers/media/rc/keymaps/Makefile |    1 +
 drivers/media/rc/keymaps/rc-cec.c |  144 +++++++++++++++++++++++++++++++++++++
 drivers/media/rc/rc-main.c        |    1 +
 include/media/rc-core.h           |    1 +
 include/media/rc-map.h            |    5 +-
 5 files changed, 151 insertions(+), 1 deletion(-)
 create mode 100644 drivers/media/rc/keymaps/rc-cec.c

diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile
index abf6079..56f10d6 100644
--- a/drivers/media/rc/keymaps/Makefile
+++ b/drivers/media/rc/keymaps/Makefile
@@ -18,6 +18,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \
 			rc-behold.o \
 			rc-behold-columbus.o \
 			rc-budget-ci-old.o \
+			rc-cec.o \
 			rc-cinergy-1400.o \
 			rc-cinergy.o \
 			rc-delock-61959.o \
diff --git a/drivers/media/rc/keymaps/rc-cec.c b/drivers/media/rc/keymaps/rc-cec.c
new file mode 100644
index 0000000..cc5b318
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-cec.c
@@ -0,0 +1,144 @@
+/* Keytable for the CEC remote control
+ *
+ * Copyright (c) 2015 by Kamil Debski
+ *
+ * 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.
+ */
+
+#include <media/rc-map.h>
+#include <linux/module.h>
+
+/* CEC Spec "High-Definition Multimedia Interface Specification" can be obtained
+ * here: http://xtreamerdev.googlecode.com/files/CEC_Specs.pdf
+ * The list of control codes is listed in Table 27: User Control Codes p. 95 */
+
+static struct rc_map_table cec[] = {
+	{ 0x00, KEY_OK },
+	{ 0x01, KEY_UP },
+	{ 0x02, KEY_DOWN },
+	{ 0x03, KEY_LEFT },
+	{ 0x04, KEY_RIGHT },
+	{ 0x05, KEY_RIGHT_UP },
+	{ 0x06, KEY_RIGHT_DOWN },
+	{ 0x07, KEY_LEFT_UP },
+	{ 0x08, KEY_LEFT_DOWN },
+	{ 0x09, KEY_CONTEXT_MENU }, /* CEC Spec: Root Menu - see Note 2 */
+	/* Note 2: This is the initial display that a device shows. It is
+	 * device-dependent and can be, for example, a contents menu, setup
+	 * menu, favorite menu or other menu. The actual menu displayed
+	 * may also depend on the device’s current state. */
+	{ 0x0a, KEY_SETUP },
+	{ 0x0b, KEY_MENU }, /* CEC Spec: Contents Menu */
+	{ 0x0c, KEY_FAVORITES }, /* CEC Spec: Favorite Menu */
+	{ 0x0d, KEY_EXIT },
+	/* 0x0e-0x1f: Reserved */
+	/* 0x20-0x29: Keys 0 to 9 */
+	{ 0x20, KEY_NUMERIC_0 },
+	{ 0x21, KEY_NUMERIC_1 },
+	{ 0x22, KEY_NUMERIC_2 },
+	{ 0x23, KEY_NUMERIC_3 },
+	{ 0x24, KEY_NUMERIC_4 },
+	{ 0x25, KEY_NUMERIC_5 },
+	{ 0x26, KEY_NUMERIC_6 },
+	{ 0x27, KEY_NUMERIC_7 },
+	{ 0x28, KEY_NUMERIC_8 },
+	{ 0x29, KEY_NUMERIC_9 },
+	{ 0x2a, KEY_DOT },
+	{ 0x2b, KEY_ENTER },
+	{ 0x2c, KEY_CLEAR },
+	/* 0x2d-0x2e: Reserved */
+	{ 0x2f, KEY_NEXT_FAVORITE }, /* CEC Spec: Next Favorite */
+	{ 0x30, KEY_CHANNELUP },
+	{ 0x31, KEY_CHANNELDOWN },
+	{ 0x32, KEY_PREVIOUS }, /* CEC Spec: Previous Channel */
+	{ 0x33, KEY_SOUND }, /* CEC Spec: Sound Select */
+	{ 0x34, KEY_VIDEO }, /* 0x34: CEC Spec: Input Select */
+	{ 0x35, KEY_INFO }, /* CEC Spec: Display Information */
+	{ 0x36, KEY_HELP },
+	{ 0x37, KEY_PAGEUP },
+	{ 0x38, KEY_PAGEDOWN },
+	/* 0x39-0x3f: Reserved */
+	{ 0x40, KEY_POWER },
+	{ 0x41, KEY_VOLUMEUP },
+	{ 0x42, KEY_VOLUMEDOWN },
+	{ 0x43, KEY_MUTE },
+	{ 0x44, KEY_PLAY },
+	{ 0x45, KEY_STOP },
+	{ 0x46, KEY_PAUSE },
+	{ 0x47, KEY_RECORD },
+	{ 0x48, KEY_REWIND },
+	{ 0x49, KEY_FASTFORWARD },
+	{ 0x4a, KEY_EJECTCD }, /* CEC Spec: Eject */
+	{ 0x4b, KEY_FORWARD },
+	{ 0x4c, KEY_BACK },
+	{ 0x4d, KEY_STOP_RECORD }, /* CEC Spec: Stop-Record */
+	{ 0x4e, KEY_PAUSE_RECORD }, /* CEC Spec: Pause-Record */
+	/* 0x4f: Reserved */
+	{ 0x50, KEY_ANGLE },
+	{ 0x51, KEY_TV2 },
+	{ 0x52, KEY_VOD }, /* CEC Spec: Video on Demand */
+	{ 0x53, KEY_EPG },
+	{ 0x54, KEY_TIME }, /* CEC Spec: Timer */
+	{ 0x55, KEY_CONFIG },
+	/* 0x56-0x5f: Reserved */
+	{ 0x60, KEY_PLAY }, /* CEC Spec: Play Function */
+	{ 0x6024, KEY_PLAY },
+	{ 0x6020, KEY_PAUSE },
+	{ 0x61, KEY_PLAYPAUSE }, /* CEC Spec: Pause-Play Function */
+	{ 0x62, KEY_RECORD }, /* Spec: Record Function */
+	{ 0x63, KEY_PAUSE }, /* CEC Spec: Pause-Record Function */
+	{ 0x64, KEY_STOP }, /* CEC Spec: Stop Function */
+	{ 0x65, KEY_MUTE }, /* CEC Spec: Mute Function */
+	{ 0x66, KEY_UNMUTE }, /* CEC Spec: Restore the volume */
+	/* The following codes are hard to implement at this moment, as they
+	 * carry an additional additional argument. Most likely changes to RC
+	 * framework are necessary.
+	 * For now they are interpreted by the CEC framework as non keycodes
+	 * and are passed as messages enabling user application to parse them.
+	 * */
+	/* 0x67: CEC Spec: Tune Function */
+	/* 0x68: CEC Spec: Seleect Media Function */
+	/* 0x69: CEC Spec: Select A/V Input Function */
+	/* 0x6a: CEC Spec: Select Audio Input Function */
+	{ 0x6b, KEY_POWER }, /* CEC Spec: Power Toggle Function */
+	{ 0x6c, KEY_SLEEP }, /* CEC Spec: Power Off Function */
+	{ 0x6d, KEY_WAKEUP }, /* CEC Spec: Power On Function */
+	/* 0x6e-0x70: Reserved */
+	{ 0x71, KEY_BLUE }, /* CEC Spec: F1 (Blue) */
+	{ 0x72, KEY_RED }, /* CEC Spec: F2 (Red) */
+	{ 0x73, KEY_GREEN }, /* CEC Spec: F3 (Green) */
+	{ 0x74, KEY_YELLOW }, /* CEC Spec: F4 (Yellow) */
+	{ 0x75, KEY_F5 },
+	{ 0x76, KEY_DVB }, /* CEC Spec: Data - see Note 3 */
+	/* Note 3: This is used, for example, to enter or leave a digital TV
+	 * data broadcast application. */
+	/* 0x77-0xff: Reserved */
+};
+
+static struct rc_map_list cec_map = {
+	.map = {
+		.scan		= cec,
+		.size		= ARRAY_SIZE(cec),
+		.rc_type	= RC_TYPE_CEC,
+		.name		= RC_MAP_CEC,
+	}
+};
+
+static int __init init_rc_map_cec(void)
+{
+	return rc_map_register(&cec_map);
+}
+
+static void __exit exit_rc_map_cec(void)
+{
+	rc_map_unregister(&cec_map);
+}
+
+module_init(init_rc_map_cec);
+module_exit(exit_rc_map_cec);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Kamil Debski");
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index f8c5e47..37d1ce0 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -801,6 +801,7 @@ static struct {
 	{ RC_BIT_MCE_KBD,	"mce_kbd"	},
 	{ RC_BIT_LIRC,		"lirc"		},
 	{ RC_BIT_XMP,		"xmp"		},
+	{ RC_BIT_CEC,		"cec"		},
 };
 
 /**
diff --git a/include/media/rc-core.h b/include/media/rc-core.h
index 2c7fbca..7c9d15d 100644
--- a/include/media/rc-core.h
+++ b/include/media/rc-core.h
@@ -32,6 +32,7 @@ do {								\
 enum rc_driver_type {
 	RC_DRIVER_SCANCODE = 0,	/* Driver or hardware generates a scancode */
 	RC_DRIVER_IR_RAW,	/* Needs a Infra-Red pulse/space decoder */
+	RC_DRIVER_CEC,
 };
 
 /**
diff --git a/include/media/rc-map.h b/include/media/rc-map.h
index e7a1514..2058a89 100644
--- a/include/media/rc-map.h
+++ b/include/media/rc-map.h
@@ -32,6 +32,7 @@ enum rc_type {
 	RC_TYPE_RC6_MCE		= 17,	/* MCE (Philips RC6-6A-32 subtype) protocol */
 	RC_TYPE_SHARP		= 18,	/* Sharp protocol */
 	RC_TYPE_XMP		= 19,	/* XMP protocol */
+	RC_TYPE_CEC		= 20,	/* CEC protocol */
 };
 
 #define RC_BIT_NONE		0
@@ -55,6 +56,7 @@ enum rc_type {
 #define RC_BIT_RC6_MCE		(1 << RC_TYPE_RC6_MCE)
 #define RC_BIT_SHARP		(1 << RC_TYPE_SHARP)
 #define RC_BIT_XMP		(1 << RC_TYPE_XMP)
+#define RC_BIT_CEC		(1 << RC_TYPE_CEC)
 
 #define RC_BIT_ALL	(RC_BIT_UNKNOWN | RC_BIT_OTHER | RC_BIT_LIRC | \
 			 RC_BIT_RC5 | RC_BIT_RC5X | RC_BIT_RC5_SZ | \
@@ -63,7 +65,7 @@ enum rc_type {
 			 RC_BIT_NEC | RC_BIT_SANYO | RC_BIT_MCE_KBD | \
 			 RC_BIT_RC6_0 | RC_BIT_RC6_6A_20 | RC_BIT_RC6_6A_24 | \
 			 RC_BIT_RC6_6A_32 | RC_BIT_RC6_MCE | RC_BIT_SHARP | \
-			 RC_BIT_XMP)
+			 RC_BIT_XMP | RC_BIT_CEC)
 
 
 #define RC_SCANCODE_UNKNOWN(x)			(x)
@@ -125,6 +127,7 @@ void rc_map_init(void);
 #define RC_MAP_BEHOLD_COLUMBUS           "rc-behold-columbus"
 #define RC_MAP_BEHOLD                    "rc-behold"
 #define RC_MAP_BUDGET_CI_OLD             "rc-budget-ci-old"
+#define RC_MAP_CEC                       "rc-cec"
 #define RC_MAP_CINERGY_1400              "rc-cinergy-1400"
 #define RC_MAP_CINERGY                   "rc-cinergy"
 #define RC_MAP_DELOCK_61959              "rc-delock-61959"
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH v6 06/11] cec: add HDMI CEC framework
  2015-05-04 17:32 [PATCH v6 00/11] Kamil Debski
                   ` (4 preceding siblings ...)
  2015-05-04 17:32 ` [PATCH v6 05/11] rc: Add HDMI CEC protoctol handling Kamil Debski
@ 2015-05-04 17:32 ` Kamil Debski
  2015-05-08 11:30   ` Hans Verkuil
                     ` (4 more replies)
  2015-05-04 17:33 ` [PATCH v6 07/11] DocBook/media: add CEC documentation Kamil Debski
                   ` (7 subsequent siblings)
  13 siblings, 5 replies; 30+ messages in thread
From: Kamil Debski @ 2015-05-04 17:32 UTC (permalink / raw)
  To: dri-devel, linux-media
  Cc: m.szyprowski, k.debski, mchehab, hverkuil, kyungmin.park, thomas,
	sean, dmitry.torokhov, linux-input, linux-samsung-soc, lars,
	Hans Verkuil

From: Hans Verkuil <hansverk@cisco.com>

The added HDMI CEC framework provides a generic kernel interface for
HDMI CEC devices.

Signed-off-by: Hans Verkuil <hansverk@cisco.com>
[k.debski@samsung.com: Merged CEC Updates commit by Hans Verkuil]
[k.debski@samsung.com: Merged Update author commit by Hans Verkuil]
[k.debski@samsung.com: change kthread handling when setting logical
address]
[k.debski@samsung.com: code cleanup and fixes]
[k.debski@samsung.com: add missing CEC commands to match spec]
[k.debski@samsung.com: add RC framework support]
[k.debski@samsung.com: move and edit documentation]
[k.debski@samsung.com: add vendor id reporting]
[k.debski@samsung.com: add possibility to clear assigned logical
addresses]
[k.debski@samsung.com: documentation fixes, clenaup and expansion]
[k.debski@samsung.com: reorder of API structs and add reserved fields]
[k.debski@samsung.com: fix handling of events and fix 32/64bit timespec
problem]
[k.debski@samsung.com: add cec.h to include/uapi/linux/Kbuild]
[k.debski@samsung.com: add sequence number handling]
[k.debski@samsung.com: add passthrough mode]
[k.debski@samsung.com: fix CEC defines, add missing CEC 2.0 commands]
[k.debski@samsung.com: add DocBook documentation by Hans Verkuil, with
minor additions]
Signed-off-by: Kamil Debski <k.debski@samsung.com>
---
 Documentation/cec.txt     |  165 +++++++
 drivers/media/Kconfig     |    6 +
 drivers/media/Makefile    |    2 +
 drivers/media/cec.c       | 1191 +++++++++++++++++++++++++++++++++++++++++++++
 include/media/cec.h       |  142 ++++++
 include/uapi/linux/Kbuild |    1 +
 include/uapi/linux/cec.h  |  332 +++++++++++++
 7 files changed, 1839 insertions(+)
 create mode 100644 Documentation/cec.txt
 create mode 100644 drivers/media/cec.c
 create mode 100644 include/media/cec.h
 create mode 100644 include/uapi/linux/cec.h

diff --git a/Documentation/cec.txt b/Documentation/cec.txt
new file mode 100644
index 0000000..a52017c2
--- /dev/null
+++ b/Documentation/cec.txt
@@ -0,0 +1,165 @@
+CEC Kernel Support
+==================
+
+The CEC framework provides a unified kernel interface for use with HDMI CEC
+hardware. It is designed to handle a multiple variants of hardware. Adding to
+the flexibility of the framework it enables to set which parts of the CEC
+protocol processing is handled by the hardware, by the driver and by the
+userspace application.
+
+
+The CEC Protocol
+----------------
+
+The CEC protocol enables consumer electronic devices to communicate with each
+other through the HDMI connection. The protocol uses logical addresses in the
+communication. The logical address is strictly connected with the functionality
+provided by the device. The TV acting as the communication hub is always
+assigned address 0. The physical address is determined by the physical
+connection between devices.
+
+The protocol enables control of compatible devices with a single remote.
+Synchronous power on/standby, instant playback with changing the content source
+on the TV.
+
+The Kernel Interface
+====================
+
+CEC Adapter
+-----------
+
+#define CEC_LOG_ADDR_INVALID 0xff
+
+/* The maximum number of logical addresses one device can be assigned to.
+ * The CEC 2.0 spec allows for only 2 logical addresses at the moment. The
+ * Analog Devices CEC hardware supports 3. So let's go wild and go for 4. */
+#define CEC_MAX_LOG_ADDRS 4
+
+/* The "Primary Device Type" */
+#define CEC_PRIM_DEVTYPE_TV		0
+#define CEC_PRIM_DEVTYPE_RECORD		1
+#define CEC_PRIM_DEVTYPE_TUNER		3
+#define CEC_PRIM_DEVTYPE_PLAYBACK	4
+#define CEC_PRIM_DEVTYPE_AUDIOSYSTEM	5
+#define CEC_PRIM_DEVTYPE_SWITCH		6
+#define CEC_PRIM_DEVTYPE_VIDEOPROC	7
+
+/* The "All Device Types" flags (CEC 2.0) */
+#define CEC_FL_ALL_DEVTYPE_TV		(1 << 7)
+#define CEC_FL_ALL_DEVTYPE_RECORD	(1 << 6)
+#define CEC_FL_ALL_DEVTYPE_TUNER	(1 << 5)
+#define CEC_FL_ALL_DEVTYPE_PLAYBACK	(1 << 4)
+#define CEC_FL_ALL_DEVTYPE_AUDIOSYSTEM	(1 << 3)
+#define CEC_FL_ALL_DEVTYPE_SWITCH	(1 << 2)
+/* And if you wondering what happened to VIDEOPROC devices: those should
+ * be mapped to a SWITCH. */
+
+/* The logical address types that the CEC device wants to claim */
+#define CEC_LOG_ADDR_TYPE_TV		0
+#define CEC_LOG_ADDR_TYPE_RECORD	1
+#define CEC_LOG_ADDR_TYPE_TUNER		2
+#define CEC_LOG_ADDR_TYPE_PLAYBACK	3
+#define CEC_LOG_ADDR_TYPE_AUDIOSYSTEM	4
+#define CEC_LOG_ADDR_TYPE_SPECIFIC	5
+#define CEC_LOG_ADDR_TYPE_UNREGISTERED	6
+/* Switches should use UNREGISTERED.
+ * Video processors should use SPECIFIC. */
+
+/* The CEC version */
+#define CEC_VERSION_1_4B		5
+#define CEC_VERSION_2_0			6
+
+struct cec_adapter {
+	/* internal fields removed */
+
+	u16 phys_addr;
+	u32 capabilities;
+	u8 version;
+	u8 num_log_addrs;
+	u8 prim_device[CEC_MAX_LOG_ADDRS];
+	u8 log_addr_type[CEC_MAX_LOG_ADDRS];
+	u8 log_addr[CEC_MAX_LOG_ADDRS];
+
+	int (*adap_enable)(struct cec_adapter *adap, bool enable);
+	int (*adap_log_addr)(struct cec_adapter *adap, u8 logical_addr);
+	int (*adap_transmit)(struct cec_adapter *adap, struct cec_msg *msg);
+	void (*adap_transmit_timed_out)(struct cec_adapter *adap);
+
+	void (*claimed_log_addr)(struct cec_adapter *adap, u8 idx);
+	int (*received)(struct cec_adapter *adap, struct cec_msg *msg);
+};
+
+int cec_create_adapter(struct cec_adapter *adap, u32 caps);
+void cec_delete_adapter(struct cec_adapter *adap);
+int cec_transmit_msg(struct cec_adapter *adap, struct cec_data *data, bool block);
+
+/* Called by the adapter */
+void cec_transmit_done(struct cec_adapter *adap, u32 status);
+void cec_received_msg(struct cec_adapter *adap, struct cec_msg *msg);
+
+int cec_receive_msg(struct cec_adapter *adap, struct cec_msg *msg, bool block);
+int cec_claim_log_addrs(struct cec_adapter *adap, struct cec_log_addrs *log_addrs, bool block);
+
+The device type defines are defined by the CEC standard.
+
+The cec_adapter structure represents the adapter. It has a number of
+operations that have to be implemented in the driver: adap_enable() enables
+or disables the physical adapter, adap_log_addr() tells the driver which
+logical address should be configured. This may be called multiple times
+to configure multiple logical addresses. Calling adap_enable(false) or
+adap_log_addr(CEC_LOG_ADDR_INVALID) will clear all configured logical
+addresses.
+
+The adap_transmit op will setup the hardware to send out the given CEC message.
+This will return without waiting for the transmission to finish. The
+adap_transmit_timed_out() function is called when the current transmission timed
+out and the hardware needs to be informed of this (the hardware should go back
+from transmitter to receiver mode).
+
+The adapter driver will also call into the adapter: it should call
+cec_transmit_done() when a cec transfer was finalized and cec_received_msg()
+when a new message was received.
+
+When a message is received the received() op is called.
+
+The driver has to call cec_create_adapter to initialize the structure. If
+the 'caps' argument is non-zero, then it will also create a /dev/cecX
+device node to allow userspace to interact with the CEC device. Userspace
+can request those capabilities with the CEC_G_CAPS ioctl.
+
+In order for a CEC adapter to be configured it needs a physical address.
+This is normally assigned by the driver. It is either 0.0.0.0 for a TV (aka
+video receiver) or it is derived from the EDID that the source received
+from the sink. This is normally set by the driver before enabling the CEC
+adapter, or it is set from userspace in the case of CEC USB dongles (although
+embedded systems might also want to set this manually).
+
+After enabling the CEC adapter it has to be configured.
+
+The userspace has to inform the CEC adapter of which type of device it requests
+the adapter to identify itself. After this information is set by userspace, the
+CEC framework will attempt to to find and claim a logical addresses matching the
+requested device type. If none are found, then it will fall back to logical
+address Unregistered (15). To clear the logical addresses list from the list the
+userspace application should set the num_log_addrs field of struct cec_log_addr
+to 0.
+
+The type of device is set from the userspace with the CEC_S_ADAP_LOG_ADDRS. In
+addition, claiming logical addresses can be initiated from the kernel side by
+calling the cec_claim_log_addrs function.
+
+Before the addresses are claimed it is possible to send and receive messages.
+Sending all messages is possible as it is up to the userspace to the source
+and destination addresses in the message payload. However, only broadcast
+messages can be received until a regular logical address is claimed.
+
+When a CEC message is received the CEC framework will take care of the CEC
+core messages CEC_OP_GET_CEC_VERSION, CEC_OP_GIVE_PHYS_ADDR and CEC_OP_ABORT.
+Then it will call the received() op (if set), and finally it will queue it
+for handling by userspace if create_devnode was true, or send back
+FEATURE_ABORT if create_devnode was false.
+
+Drivers can also use the cec_transmit_msg() call to transmit a message. This
+can either be fire-and-forget (the CEC framework will queue up messages in a
+transmit queue), or a blocking wait until there is either an error or a
+reply to the message.
diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig
index 3ef0f90..262e9ad 100644
--- a/drivers/media/Kconfig
+++ b/drivers/media/Kconfig
@@ -15,6 +15,12 @@ if MEDIA_SUPPORT
 
 comment "Multimedia core support"
 
+config CEC
+	tristate "CEC API (EXPERIMENTAL)"
+	select RC_CORE
+	---help---
+	  Enable the CEC API.
+
 #
 # Multimedia support - automatically enable V4L2 and DVB core
 #
diff --git a/drivers/media/Makefile b/drivers/media/Makefile
index e608bbc..db66014 100644
--- a/drivers/media/Makefile
+++ b/drivers/media/Makefile
@@ -2,6 +2,8 @@
 # Makefile for the kernel multimedia device drivers.
 #
 
+obj-$(CONFIG_CEC) += cec.o
+
 media-objs	:= media-device.o media-devnode.o media-entity.o
 
 #
diff --git a/drivers/media/cec.c b/drivers/media/cec.c
new file mode 100644
index 0000000..52d936a
--- /dev/null
+++ b/drivers/media/cec.c
@@ -0,0 +1,1191 @@
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/kmod.h>
+#include <linux/ktime.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/uaccess.h>
+#include <media/cec.h>
+
+#define CEC_NUM_DEVICES	256
+#define CEC_NAME	"cec"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "debug level (0-1)");
+
+struct cec_transmit_notifier {
+	struct completion c;
+	struct cec_data *data;
+};
+
+#define dprintk(fmt, arg...)						\
+	do {								\
+		if (debug)						\
+			pr_info("cec-%s: " fmt, adap->name, ## arg);	\
+	} while (0)
+
+static dev_t cec_dev_t;
+
+/* Active devices */
+static DEFINE_MUTEX(cec_devnode_lock);
+static DECLARE_BITMAP(cec_devnode_nums, CEC_NUM_DEVICES);
+
+/* dev to cec_devnode */
+#define to_cec_devnode(cd) container_of(cd, struct cec_devnode, dev)
+
+static inline struct cec_devnode *cec_devnode_data(struct file *filp)
+{
+	return filp->private_data;
+}
+
+static int cec_log_addr2idx(const struct cec_adapter *adap, u8 log_addr)
+{
+	int i;
+
+	for (i = 0; i < adap->num_log_addrs; i++)
+		if (adap->log_addr[i] == log_addr)
+			return i;
+	return -1;
+}
+
+static unsigned cec_log_addr2dev(const struct cec_adapter *adap, u8 log_addr)
+{
+	int i = cec_log_addr2idx(adap, log_addr);
+
+	return adap->prim_device[i < 0 ? 0 : i];
+}
+
+/* Called when the last user of the cec device exits. */
+static void cec_devnode_release(struct device *cd)
+{
+	struct cec_devnode *cecdev = to_cec_devnode(cd);
+
+	mutex_lock(&cec_devnode_lock);
+
+	/* Delete the cdev on this minor as well */
+	cdev_del(&cecdev->cdev);
+
+	/* Mark device node number as free */
+	clear_bit(cecdev->minor, cec_devnode_nums);
+
+	mutex_unlock(&cec_devnode_lock);
+
+	/* Release cec_devnode and perform other cleanups as needed. */
+	if (cecdev->release)
+		cecdev->release(cecdev);
+}
+
+static struct bus_type cec_bus_type = {
+	.name = CEC_NAME,
+};
+
+static bool cec_sleep(struct cec_adapter *adap, int timeout)
+{
+	bool timed_out = false;
+
+	DECLARE_WAITQUEUE(wait, current);
+
+	add_wait_queue(&adap->kthread_waitq, &wait);
+	if (!kthread_should_stop()) {
+		if (timeout < 0) {
+			set_current_state(TASK_INTERRUPTIBLE);
+			schedule();
+		} else {
+			timed_out = !schedule_timeout_interruptible
+				(msecs_to_jiffies(timeout));
+		}
+	}
+
+	remove_wait_queue(&adap->kthread_waitq, &wait);
+	return timed_out;
+}
+
+/*
+ * Main CEC state machine
+ *
+ * In the IDLE state the CEC adapter is ready to receive or transmit messages.
+ * If it is woken up it will check if a new message is queued, and if so it
+ * will be transmitted and the state will go to TRANSMITTING.
+ *
+ * When the transmit is marked as done the state machine will check if it
+ * should wait for a reply. If not, it will call the notifier and go back
+ * to the IDLE state. Else it will switch to the WAIT state and wait for a
+ * reply. When the reply arrives it will call the notifier and go back
+ * to IDLE state.
+ *
+ * For the transmit and the wait-for-reply states a timeout is used of
+ * 1 second as per the standard.
+ */
+static int cec_thread_func(void *data)
+{
+	struct cec_adapter *adap = data;
+	int timeout = -1;
+
+	for (;;) {
+		bool timed_out = cec_sleep(adap, timeout);
+
+		if (kthread_should_stop())
+			break;
+		timeout = -1;
+		mutex_lock(&adap->lock);
+		dprintk("state %d timedout: %d tx: %d@%d\n", adap->state,
+			timed_out, adap->tx_qcount, adap->tx_qstart);
+		if (adap->state == CEC_ADAP_STATE_TRANSMITTING && timed_out)
+			adap->adap_transmit_timed_out(adap);
+
+		if (adap->state == CEC_ADAP_STATE_WAIT ||
+		    adap->state == CEC_ADAP_STATE_TRANSMITTING) {
+			struct cec_data *data = adap->tx_queue +
+						adap->tx_qstart;
+
+			if (adap->state == CEC_ADAP_STATE_TRANSMITTING &&
+			    data->msg.reply && !timed_out &&
+			    data->msg.status == CEC_TX_STATUS_OK) {
+				adap->state = CEC_ADAP_STATE_WAIT;
+				timeout = 1000;
+			} else {
+				if (timed_out) {
+					data->msg.reply = 0;
+					if (adap->state ==
+					    CEC_ADAP_STATE_TRANSMITTING)
+						data->msg.status =
+						    CEC_TX_STATUS_RETRY_TIMEOUT;
+					else
+						data->msg.status =
+						    CEC_TX_STATUS_REPLY_TIMEOUT;
+				}
+				adap->state = CEC_ADAP_STATE_IDLE;
+				if (data->func) {
+					mutex_unlock(&adap->lock);
+					data->func(adap, data, data->priv);
+					mutex_lock(&adap->lock);
+				}
+				adap->tx_qstart = (adap->tx_qstart + 1) %
+						  CEC_TX_QUEUE_SZ;
+				adap->tx_qcount--;
+				wake_up_interruptible(&adap->waitq);
+			}
+		}
+		if (adap->state == CEC_ADAP_STATE_IDLE && adap->tx_qcount) {
+			adap->state = CEC_ADAP_STATE_TRANSMITTING;
+			timeout = adap->tx_queue[adap->tx_qstart].msg.len == 1 ?
+				  200 : 1000;
+			adap->adap_transmit(adap,
+					  &adap->tx_queue[adap->tx_qstart].msg);
+			mutex_unlock(&adap->lock);
+			continue;
+		}
+		mutex_unlock(&adap->lock);
+	}
+	return 0;
+}
+
+static int cec_transmit_notify(struct cec_adapter *adap, struct cec_data *data,
+		void *priv)
+{
+	struct cec_transmit_notifier *n = priv;
+
+	*(n->data) = *data;
+	complete(&n->c);
+	return 0;
+}
+
+int cec_transmit_msg(struct cec_adapter *adap, struct cec_data *data,
+		     bool block)
+{
+	struct cec_transmit_notifier notifier;
+	struct cec_msg *msg = &data->msg;
+	int res = 0;
+	unsigned idx;
+
+	if (msg->len == 0 || msg->len > 16)
+		return -EINVAL;
+	if (msg->reply && (msg->len == 1 || cec_msg_is_broadcast(msg)))
+		return -EINVAL;
+	if (msg->len > 1 && !cec_msg_is_broadcast(msg) &&
+	    cec_msg_initiator(msg) == cec_msg_destination(msg))
+		return -EINVAL;
+	if (cec_msg_initiator(msg) != 0xf &&
+	    cec_log_addr2idx(adap, cec_msg_initiator(msg)) < 0)
+		return -EINVAL;
+
+	if (msg->len == 1)
+		dprintk("cec_transmit_msg: 0x%02x%s\n",
+				msg->msg[0], !block ? " nb" : "");
+	else if (msg->reply)
+		dprintk("cec_transmit_msg: 0x%02x 0x%02x (wait for 0x%02x)%s\n",
+				msg->msg[0], msg->msg[1],
+				msg->reply, !block ? " nb" : "");
+	else
+		dprintk("cec_transmit_msg: 0x%02x 0x%02x%s\n",
+				msg->msg[0], msg->msg[1],
+				!block ? " nb" : "");
+
+	msg->status = 0;
+	msg->ts = 0;
+	if (msg->reply)
+		msg->timeout = 1000;
+	if (block) {
+		init_completion(&notifier.c);
+		notifier.data = data;
+		data->func = cec_transmit_notify;
+		data->priv = &notifier;
+	} else {
+		data->func = NULL;
+		data->priv = NULL;
+	}
+	mutex_lock(&adap->lock);
+	idx = (adap->tx_qstart + adap->tx_qcount) % CEC_TX_QUEUE_SZ;
+	if (adap->tx_qcount == CEC_TX_QUEUE_SZ) {
+		res = -EBUSY;
+	} else {
+		adap->tx_queue[idx] = *data;
+		adap->tx_qcount++;
+		if (adap->state == CEC_ADAP_STATE_IDLE)
+			wake_up_interruptible(&adap->kthread_waitq);
+	}
+	msg->sequence = adap->sequence++;
+	data->blocking = block;
+	mutex_unlock(&adap->lock);
+	if (res || !block)
+		return res;
+	wait_for_completion_interruptible(&notifier.c);
+	return res;
+}
+EXPORT_SYMBOL_GPL(cec_transmit_msg);
+
+void cec_transmit_done(struct cec_adapter *adap, u32 status)
+{
+	struct cec_msg *msg;
+
+	dprintk("cec_transmit_done\n");
+	mutex_lock(&adap->lock);
+	if (adap->state == CEC_ADAP_STATE_TRANSMITTING) {
+		msg = &adap->tx_queue[adap->tx_qstart].msg;
+		msg->status = status;
+		if (status)
+			msg->reply = 0;
+		msg->ts = ktime_get_ns();
+		wake_up_interruptible(&adap->kthread_waitq);
+	}
+	mutex_unlock(&adap->lock);
+}
+EXPORT_SYMBOL_GPL(cec_transmit_done);
+
+static int cec_receive_notify(struct cec_adapter *adap, struct cec_msg *msg)
+{
+	bool is_broadcast = cec_msg_is_broadcast(msg);
+	u8 dest_laddr = cec_msg_destination(msg);
+	u8 devtype = cec_log_addr2dev(adap, dest_laddr);
+	bool is_directed = cec_log_addr2idx(adap, dest_laddr) >= 0;
+	struct cec_data tx_data;
+	int res = 0;
+	unsigned idx;
+
+	if (msg->len <= 1)
+		return 0;
+	if (!is_directed && !is_broadcast && !adap->passthrough)
+		return 0;	/* Not for us */
+
+	tx_data.msg.msg[0] = (msg->msg[0] << 4) | (msg->msg[0] >> 4);
+	tx_data.msg.reply = 0;
+
+	if (adap->received) {
+		res = adap->received(adap, msg);
+		if (res != -ENOMSG)
+			return 0;
+		res = 0;
+	}
+
+	if (adap->passthrough)
+		goto skip_processing;
+
+	switch (msg->msg[1]) {
+	case CEC_OP_GET_CEC_VERSION:
+		if (is_broadcast)
+			return 0;
+		tx_data.msg.len = 3;
+		tx_data.msg.msg[1] = CEC_OP_CEC_VERSION;
+		tx_data.msg.msg[2] = adap->version;
+		return cec_transmit_msg(adap, &tx_data, false);
+
+	case CEC_OP_GIVE_PHYSICAL_ADDR:
+		if (!is_directed)
+			return 0;
+		/* Do nothing for CEC switches using addr 15 */
+		if (devtype == CEC_PRIM_DEVTYPE_SWITCH && dest_laddr == 15)
+			return 0;
+		tx_data.msg.len = 5;
+		tx_data.msg.msg[1] = CEC_OP_REPORT_PHYSICAL_ADDR;
+		tx_data.msg.msg[2] = adap->phys_addr >> 8;
+		tx_data.msg.msg[3] = adap->phys_addr & 0xff;
+		tx_data.msg.msg[4] = devtype;
+		return cec_transmit_msg(adap, &tx_data, false);
+
+	case CEC_OP_ABORT:
+		/* Do nothing for CEC switches */
+		if (devtype == CEC_PRIM_DEVTYPE_SWITCH)
+			return 0;
+		tx_data.msg.len = 4;
+		tx_data.msg.msg[1] = CEC_OP_FEATURE_ABORT;
+		tx_data.msg.msg[2] = msg->msg[1];
+		tx_data.msg.msg[3] = 4;	/* Refused */
+		return cec_transmit_msg(adap, &tx_data, false);
+
+	case CEC_OP_USER_CONTROL_PRESSED:
+		switch (msg->msg[2]) {
+		/* Play function, this message can have variable length
+		 * depending on the specific play function that is used.
+		 */
+		case 0x60:
+			if (msg->len == 3)
+				rc_keydown(adap->rc, RC_TYPE_CEC,
+					   msg->msg[2] << 8 | msg->msg[3], 0);
+			else
+				rc_keydown(adap->rc, RC_TYPE_CEC, msg->msg[2],
+					   0);
+			break;
+		/* Other function messages that are not handled.
+		 * Currently the RC framework does not allow to supply an
+		 * additional parameter to a keypress. These "keys" contain
+		 * other information such as channel number, an input number
+		 * etc.
+		 * For the time being these messages are not processed by the
+		 * framework and are simply forwarded to the user space.
+		 */
+		case 0x67: case 0x68: case 0x69: case 0x6a:
+			break;
+		default:
+			rc_keydown(adap->rc, RC_TYPE_CEC, msg->msg[2], 0);
+		}
+		break;
+	case CEC_OP_USER_CONTROL_RELEASED:
+		rc_keyup(adap->rc);
+		return 0;
+	}
+
+skip_processing:
+	if ((adap->capabilities & CEC_CAP_RECEIVE) == 0)
+		return 0;
+	mutex_lock(&adap->lock);
+	idx = (adap->rx_qstart + adap->rx_qcount) % CEC_RX_QUEUE_SZ;
+	if (adap->rx_qcount == CEC_RX_QUEUE_SZ) {
+		res = -EBUSY;
+	} else {
+		adap->rx_queue[idx] = *msg;
+		adap->rx_qcount++;
+		wake_up_interruptible(&adap->waitq);
+	}
+	mutex_unlock(&adap->lock);
+	return res;
+}
+
+int cec_receive_msg(struct cec_adapter *adap, struct cec_msg *msg, bool block)
+{
+	int res;
+
+	do {
+		mutex_lock(&adap->lock);
+		if (adap->rx_qcount) {
+			*msg = adap->rx_queue[adap->rx_qstart];
+			adap->rx_qstart = (adap->rx_qstart + 1) %
+					  CEC_RX_QUEUE_SZ;
+			adap->rx_qcount--;
+			res = 0;
+		} else {
+			res = -EAGAIN;
+		}
+		mutex_unlock(&adap->lock);
+		if (!block || !res)
+			break;
+		if (msg->timeout) {
+			res = wait_event_interruptible_timeout(adap->waitq,
+				adap->rx_qcount,
+				msecs_to_jiffies(msg->timeout));
+			if (res == 0)
+				res = -ETIMEDOUT;
+			else if (res > 0)
+				res = 0;
+		} else {
+			res = wait_event_interruptible(adap->waitq,
+				adap->rx_qcount);
+		}
+	} while (!res);
+	return res;
+}
+EXPORT_SYMBOL_GPL(cec_receive_msg);
+
+void cec_received_msg(struct cec_adapter *adap, struct cec_msg *msg)
+{
+	struct cec_data *dst_data = &adap->tx_queue[adap->tx_qstart];
+	bool is_reply = false;
+
+	mutex_lock(&adap->lock);
+	msg->ts = ktime_get_ns();
+	dprintk("cec_received_msg: %02x %02x\n", msg->msg[0], msg->msg[1]);
+	if (!cec_msg_is_broadcast(msg) && msg->len > 1 &&
+	    adap->state == CEC_ADAP_STATE_WAIT) {
+		struct cec_msg *dst = &dst_data->msg;
+
+		if (msg->msg[1] == dst->reply ||
+		    msg->msg[1] == CEC_OP_FEATURE_ABORT) {
+			msg->sequence = dst->sequence;
+			*dst = *msg;
+			is_reply = true;
+			if (msg->msg[1] == CEC_OP_FEATURE_ABORT) {
+				dst->reply = 0;
+				dst->status = CEC_TX_STATUS_FEATURE_ABORT;
+			}
+			wake_up_interruptible(&adap->kthread_waitq);
+		}
+	}
+	mutex_unlock(&adap->lock);
+	if (!is_reply || (is_reply && !dst_data->blocking))
+		adap->recv_notifier(adap, msg);
+	if (is_reply && !dst_data->blocking)
+		cec_post_event(adap, CEC_EVENT_GOT_REPLY, msg->sequence);
+}
+EXPORT_SYMBOL_GPL(cec_received_msg);
+
+void cec_post_event(struct cec_adapter *adap, u32 event, u32 sequence)
+{
+	unsigned idx;
+
+	mutex_lock(&adap->lock);
+	if (adap->ev_qcount == CEC_EV_QUEUE_SZ) {
+		/* Drop oldest event */
+		adap->ev_qstart = (adap->ev_qstart + 1) % CEC_EV_QUEUE_SZ;
+		adap->ev_qcount--;
+	}
+
+	idx = (adap->ev_qstart + adap->ev_qcount) % CEC_EV_QUEUE_SZ;
+
+	adap->ev_queue[idx].event = event;
+	adap->ev_queue[idx].sequence = sequence;
+	adap->ev_queue[idx].ts = ktime_get_ns();
+
+	adap->ev_qcount++;
+	mutex_unlock(&adap->lock);
+}
+EXPORT_SYMBOL_GPL(cec_post_event);
+
+static int cec_report_phys_addr(struct cec_adapter *adap, unsigned logical_addr)
+{
+	struct cec_data data;
+
+	/* Report Physical Address */
+	data.msg.len = 5;
+	data.msg.msg[0] = (logical_addr << 4) | 0x0f;
+	data.msg.msg[1] = CEC_OP_REPORT_PHYSICAL_ADDR;
+	data.msg.msg[2] = adap->phys_addr >> 8;
+	data.msg.msg[3] = adap->phys_addr & 0xff;
+	data.msg.msg[4] = cec_log_addr2dev(adap, logical_addr);
+	data.msg.reply = 0;
+	dprintk("config: la %d pa %x.%x.%x.%x\n",
+			logical_addr, cec_phys_addr_exp(adap->phys_addr));
+	return cec_transmit_msg(adap, &data, true);
+}
+
+int cec_enable(struct cec_adapter *adap, bool enable)
+{
+	int ret;
+
+	mutex_lock(&adap->lock);
+	ret = adap->adap_enable(adap, enable);
+	if (ret) {
+		mutex_unlock(&adap->lock);
+		return ret;
+	}
+	if (!enable) {
+		adap->state = CEC_ADAP_STATE_DISABLED;
+		adap->tx_qcount = 0;
+		adap->rx_qcount = 0;
+		adap->ev_qcount = 0;
+		adap->num_log_addrs = 0;
+	} else {
+		adap->state = CEC_ADAP_STATE_UNCONF;
+	}
+	mutex_unlock(&adap->lock);
+	return 0;
+}
+EXPORT_SYMBOL_GPL(cec_enable);
+
+struct cec_log_addrs_int {
+	struct cec_adapter *adap;
+	struct cec_log_addrs log_addrs;
+	struct completion c;
+	bool free_on_exit;
+	int err;
+};
+
+static int cec_config_log_addrs(struct cec_adapter *adap,
+				struct cec_log_addrs *log_addrs)
+{
+	static const u8 tv_log_addrs[] = {
+		0, CEC_LOG_ADDR_INVALID
+	};
+	static const u8 record_log_addrs[] = {
+		1, 2, 9, 12, 13, CEC_LOG_ADDR_INVALID
+	};
+	static const u8 tuner_log_addrs[] = {
+		3, 6, 7, 10, 12, 13, CEC_LOG_ADDR_INVALID
+	};
+	static const u8 playback_log_addrs[] = {
+		4, 8, 11, 12, 13, CEC_LOG_ADDR_INVALID
+	};
+	static const u8 audiosystem_log_addrs[] = {
+		5, 12, 13, CEC_LOG_ADDR_INVALID
+	};
+	static const u8 specific_use_log_addrs[] = {
+		14, 12, 13, CEC_LOG_ADDR_INVALID
+	};
+	static const u8 unregistered_log_addrs[] = {
+		CEC_LOG_ADDR_INVALID
+	};
+	static const u8 *type2addrs[7] = {
+		[CEC_LOG_ADDR_TYPE_TV] = tv_log_addrs,
+		[CEC_LOG_ADDR_TYPE_RECORD] = record_log_addrs,
+		[CEC_LOG_ADDR_TYPE_TUNER] = tuner_log_addrs,
+		[CEC_LOG_ADDR_TYPE_PLAYBACK] = playback_log_addrs,
+		[CEC_LOG_ADDR_TYPE_AUDIOSYSTEM] = audiosystem_log_addrs,
+		[CEC_LOG_ADDR_TYPE_SPECIFIC] = specific_use_log_addrs,
+		[CEC_LOG_ADDR_TYPE_UNREGISTERED] = unregistered_log_addrs,
+	};
+	struct cec_data data;
+	u32 claimed_addrs = 0;
+	int i, j;
+	int err;
+
+	if (adap->phys_addr) {
+		/* The TV functionality can only map to physical address 0.
+		   For any other address, try the Specific functionality
+		   instead as per the spec. */
+		for (i = 0; i < log_addrs->num_log_addrs; i++)
+			if (log_addrs->log_addr_type[i] == CEC_LOG_ADDR_TYPE_TV)
+				log_addrs->log_addr_type[i] =
+						CEC_LOG_ADDR_TYPE_SPECIFIC;
+	}
+
+	memcpy(adap->prim_device, log_addrs->primary_device_type,
+			log_addrs->num_log_addrs);
+	dprintk("physical address: %x.%x.%x.%x, claim %d logical addresses\n",
+			cec_phys_addr_exp(adap->phys_addr),
+			log_addrs->num_log_addrs);
+	adap->num_log_addrs = 0;
+	adap->state = CEC_ADAP_STATE_IDLE;
+
+	/* TODO: remember last used logical addr type to achieve
+	   faster logical address polling by trying that one first.
+	 */
+	for (i = 0; i < log_addrs->num_log_addrs; i++) {
+		const u8 *la_list = type2addrs[log_addrs->log_addr_type[i]];
+
+		if (kthread_should_stop())
+			return -EINTR;
+
+		for (j = 0; la_list[j] != CEC_LOG_ADDR_INVALID; j++) {
+			u8 log_addr = la_list[j];
+
+			if (claimed_addrs & (1 << log_addr))
+				continue;
+
+			/* Send polling message */
+			data.msg.len = 1;
+			data.msg.msg[0] = 0xf0 | log_addr;
+			data.msg.reply = 0;
+			err = cec_transmit_msg(adap, &data, true);
+			if (err)
+				return err;
+			if (data.msg.status == CEC_TX_STATUS_RETRY_TIMEOUT) {
+				/* Message not acknowledged, so this logical
+				   address is free to use. */
+				claimed_addrs |= 1 << log_addr;
+				adap->log_addr[adap->num_log_addrs++] =
+								log_addr;
+				log_addrs->log_addr[i] = log_addr;
+				err = adap->adap_log_addr(adap, log_addr);
+				dprintk("claim addr %d (%d)\n", log_addr,
+							adap->prim_device[i]);
+				if (err)
+					return err;
+				cec_report_phys_addr(adap, log_addr);
+				if (adap->claimed_log_addr)
+					adap->claimed_log_addr(adap, i);
+				break;
+			}
+		}
+	}
+	if (adap->num_log_addrs == 0) {
+		if (log_addrs->num_log_addrs > 1)
+			dprintk("could not claim last %d addresses\n",
+				log_addrs->num_log_addrs - 1);
+		adap->log_addr[adap->num_log_addrs++] = 15;
+		log_addrs->log_addr_type[0] = CEC_LOG_ADDR_TYPE_UNREGISTERED;
+		log_addrs->log_addr[0] = 15;
+		log_addrs->num_log_addrs = 1;
+		err = adap->adap_log_addr(adap, 15);
+		dprintk("claim addr %d (%d)\n", 15, adap->prim_device[0]);
+		if (err)
+			return err;
+		cec_report_phys_addr(adap, 15);
+		if (adap->claimed_log_addr)
+			adap->claimed_log_addr(adap, 0);
+	}
+	return 0;
+}
+
+static int cec_config_thread_func(void *arg)
+{
+	struct cec_log_addrs_int *cla_int = arg;
+	int err;
+
+	cla_int->err = err = cec_config_log_addrs(cla_int->adap,
+						  &cla_int->log_addrs);
+	cla_int->adap->kthread_config = NULL;
+	if (cla_int->free_on_exit)
+		kfree(cla_int);
+	else
+		complete(&cla_int->c);
+
+	cec_post_event(cla_int->adap, CEC_EVENT_READY, 0);
+	return err;
+}
+
+int cec_claim_log_addrs(struct cec_adapter *adap,
+			struct cec_log_addrs *log_addrs, bool block)
+{
+	struct cec_log_addrs_int *cla_int;
+	int i;
+
+	if (adap->state == CEC_ADAP_STATE_DISABLED)
+		return -EINVAL;
+
+	if (log_addrs->num_log_addrs > CEC_MAX_LOG_ADDRS)
+		return -EINVAL;
+	if (log_addrs->num_log_addrs == 0) {
+		adap->num_log_addrs = 0;
+		adap->state = CEC_ADAP_STATE_IDLE;
+		return 0;
+	}
+	if (log_addrs->cec_version != CEC_VERSION_1_4 &&
+	    log_addrs->cec_version != CEC_VERSION_2_0)
+		return -EINVAL;
+	if (log_addrs->num_log_addrs > 1)
+		for (i = 0; i < log_addrs->num_log_addrs; i++)
+			if (log_addrs->log_addr_type[i] ==
+					CEC_LOG_ADDR_TYPE_UNREGISTERED)
+				return -EINVAL;
+	for (i = 0; i < log_addrs->num_log_addrs; i++) {
+		if (log_addrs->primary_device_type[i] >
+						CEC_PRIM_DEVTYPE_VIDEOPROC)
+			return -EINVAL;
+		if (log_addrs->primary_device_type[i] == 2)
+			return -EINVAL;
+		if (log_addrs->log_addr_type[i] >
+						CEC_LOG_ADDR_TYPE_UNREGISTERED)
+			return -EINVAL;
+	}
+
+	/* For phys addr 0xffff only the Unregistered functionality is
+	   allowed. */
+	if (adap->phys_addr == 0xffff &&
+	    (log_addrs->num_log_addrs > 1 ||
+	     log_addrs->log_addr_type[0] != CEC_LOG_ADDR_TYPE_UNREGISTERED))
+		return -EINVAL;
+
+	cla_int = kzalloc(sizeof(*cla_int), GFP_KERNEL);
+	if (cla_int == NULL)
+		return -ENOMEM;
+	init_completion(&cla_int->c);
+	cla_int->free_on_exit = !block;
+	cla_int->adap = adap;
+	cla_int->log_addrs = *log_addrs;
+	adap->kthread_config = kthread_run(cec_config_thread_func, cla_int,
+							"cec_log_addrs");
+	if (block) {
+		wait_for_completion(&cla_int->c);
+		*log_addrs = cla_int->log_addrs;
+		kfree(cla_int);
+	}
+	return 0;
+}
+EXPORT_SYMBOL_GPL(cec_claim_log_addrs);
+
+static unsigned int cec_poll(struct file *filp,
+			       struct poll_table_struct *poll)
+{
+	struct cec_devnode *cecdev = cec_devnode_data(filp);
+	struct cec_adapter *adap = to_cec_adapter(cecdev);
+	unsigned res = 0;
+
+	if (!cec_devnode_is_registered(cecdev))
+		return POLLERR | POLLHUP;
+	mutex_lock(&adap->lock);
+	if (adap->tx_qcount < CEC_TX_QUEUE_SZ)
+		res |= POLLOUT | POLLWRNORM;
+	if (adap->rx_qcount)
+		res |= POLLIN | POLLRDNORM;
+	if (adap->ev_qcount)
+		res |= POLLPRI;
+	poll_wait(filp, &adap->waitq, poll);
+	mutex_unlock(&adap->lock);
+	return res;
+}
+
+static long cec_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+	struct cec_devnode *cecdev = cec_devnode_data(filp);
+	struct cec_adapter *adap = to_cec_adapter(cecdev);
+	void __user *parg = (void __user *)arg;
+	int err;
+
+	if (!cec_devnode_is_registered(cecdev))
+		return -EIO;
+
+	switch (cmd) {
+	case CEC_G_CAPS: {
+		struct cec_caps caps;
+
+		caps.available_log_addrs = 3;
+		caps.capabilities = adap->capabilities;
+		caps.version = adap->version;
+		caps.vendor_id = adap->vendor_id;
+		if (copy_to_user(parg, &caps, sizeof(caps)))
+			return -EFAULT;
+		break;
+	}
+
+	case CEC_TRANSMIT: {
+		struct cec_data data;
+
+		if (!(adap->capabilities & CEC_CAP_TRANSMIT))
+			return -ENOTTY;
+		if (copy_from_user(&data.msg, parg, sizeof(data.msg)))
+			return -EFAULT;
+		err = cec_transmit_msg(adap, &data,
+						!(filp->f_flags & O_NONBLOCK));
+		if (err)
+			return err;
+		if (copy_to_user(parg, &data.msg, sizeof(data.msg)))
+			return -EFAULT;
+		break;
+	}
+
+	case CEC_RECEIVE: {
+		struct cec_data data;
+
+		if (!(adap->capabilities & CEC_CAP_RECEIVE))
+			return -ENOTTY;
+		if (copy_from_user(&data.msg, parg, sizeof(data.msg)))
+			return -EFAULT;
+		err = cec_receive_msg(adap, &data.msg,
+						!(filp->f_flags & O_NONBLOCK));
+		if (err)
+			return err;
+		if (copy_to_user(parg, &data.msg, sizeof(data.msg)))
+			return -EFAULT;
+		break;
+	}
+
+	case CEC_G_EVENT: {
+		struct cec_event ev;
+
+		mutex_lock(&adap->lock);
+		err = -EAGAIN;
+		if (adap->ev_qcount) {
+			err = 0;
+			ev = adap->ev_queue[adap->ev_qstart];
+			adap->ev_qstart = (adap->ev_qstart + 1) %
+								CEC_EV_QUEUE_SZ;
+			adap->ev_qcount--;
+		}
+		mutex_unlock(&adap->lock);
+		if (err)
+			return err;
+		if (copy_to_user((void __user *)arg, &ev, sizeof(ev)))
+			return -EFAULT;
+		break;
+	}
+
+	case CEC_G_ADAP_STATE: {
+		u32 state = adap->state != CEC_ADAP_STATE_DISABLED;
+
+		if (copy_to_user(parg, &state, sizeof(state)))
+			return -EFAULT;
+		break;
+	}
+
+	case CEC_S_ADAP_STATE: {
+		u32 state;
+
+		if (!(adap->capabilities & CEC_CAP_STATE))
+			return -ENOTTY;
+		if (copy_from_user(&state, parg, sizeof(state)))
+			return -EFAULT;
+		if (!state && adap->state == CEC_ADAP_STATE_DISABLED)
+			return 0;
+		if (state && adap->state != CEC_ADAP_STATE_DISABLED)
+			return 0;
+		cec_enable(adap, !!state);
+		break;
+	}
+
+	case CEC_G_ADAP_PHYS_ADDR:
+		if (copy_to_user(parg, &adap->phys_addr,
+						sizeof(adap->phys_addr)))
+			return -EFAULT;
+		break;
+
+	case CEC_S_ADAP_PHYS_ADDR: {
+		u16 phys_addr;
+
+		if (!(adap->capabilities & CEC_CAP_PHYS_ADDR))
+			return -ENOTTY;
+		if (copy_from_user(&phys_addr, parg, sizeof(phys_addr)))
+			return -EFAULT;
+		adap->phys_addr = phys_addr;
+		break;
+	}
+
+	case CEC_G_ADAP_LOG_ADDRS: {
+		struct cec_log_addrs log_addrs;
+
+		log_addrs.cec_version = adap->version;
+		log_addrs.num_log_addrs = adap->num_log_addrs;
+		memcpy(log_addrs.primary_device_type, adap->prim_device,
+							CEC_MAX_LOG_ADDRS);
+		memcpy(log_addrs.log_addr_type, adap->log_addr_type,
+							CEC_MAX_LOG_ADDRS);
+		memcpy(log_addrs.log_addr, adap->log_addr,
+							CEC_MAX_LOG_ADDRS);
+
+		if (copy_to_user(parg, &log_addrs, sizeof(log_addrs)))
+			return -EFAULT;
+		break;
+	}
+
+	case CEC_S_ADAP_LOG_ADDRS: {
+		struct cec_log_addrs log_addrs;
+
+		if (!(adap->capabilities & CEC_CAP_LOG_ADDRS))
+			return -ENOTTY;
+		if (copy_from_user(&log_addrs, parg, sizeof(log_addrs)))
+			return -EFAULT;
+		err = cec_claim_log_addrs(adap, &log_addrs,
+					!(filp->f_flags & O_NONBLOCK));
+		if (err)
+			return err;
+
+		if (copy_to_user(parg, &log_addrs, sizeof(log_addrs)))
+			return -EFAULT;
+		break;
+	}
+
+	case CEC_G_VENDOR_ID:
+		if (copy_to_user(parg, &adap->vendor_id,
+						sizeof(adap->vendor_id)))
+			return -EFAULT;
+		break;
+
+	case CEC_S_VENDOR_ID: {
+		u32 vendor_id;
+
+		if (!(adap->capabilities & CEC_CAP_VENDOR_ID))
+			return -ENOTTY;
+		if (copy_from_user(&vendor_id, parg, sizeof(vendor_id)))
+			return -EFAULT;
+		/* Vendori ID is a 24 bit number, so check if the value is
+		 * within the correct range. */
+		if ((vendor_id & 0xff000000) != 0)
+			return -EINVAL;
+		adap->vendor_id = vendor_id;
+		break;
+	}
+
+	case CEC_G_PASSTHROUGH: {
+		u32 state = adap->passthrough;
+
+		if (copy_to_user(parg, &state, sizeof(state)))
+			return -EFAULT;
+		break;
+	}
+
+	case CEC_S_PASSTHROUGH: {
+		u32 state;
+
+		if (!(adap->capabilities & CEC_CAP_PASSTHROUGH))
+			return -ENOTTY;
+		if (copy_from_user(&state, parg, sizeof(state)))
+			return -EFAULT;
+		if (state == CEC_PASSTHROUGH_DISABLED)
+			adap->passthrough = state;
+		else if (state == CEC_PASSTHROUGH_ENABLED)
+			adap->passthrough = state;
+		else
+			return -EINVAL;
+		break;
+	}
+
+	default:
+		return -ENOTTY;
+	}
+	return 0;
+}
+
+/* Override for the open function */
+static int cec_open(struct inode *inode, struct file *filp)
+{
+	struct cec_devnode *cecdev;
+
+	/* Check if the cec device is available. This needs to be done with
+	 * the cec_devnode_lock held to prevent an open/unregister race:
+	 * without the lock, the device could be unregistered and freed between
+	 * the cec_devnode_is_registered() and get_device() calls, leading to
+	 * a crash.
+	 */
+	mutex_lock(&cec_devnode_lock);
+	cecdev = container_of(inode->i_cdev, struct cec_devnode, cdev);
+	/* return ENXIO if the cec device has been removed
+	   already or if it is not registered anymore. */
+	if (!cec_devnode_is_registered(cecdev)) {
+		mutex_unlock(&cec_devnode_lock);
+		return -ENXIO;
+	}
+	/* and increase the device refcount */
+	get_device(&cecdev->dev);
+	mutex_unlock(&cec_devnode_lock);
+
+	filp->private_data = cecdev;
+
+	return 0;
+}
+
+/* Override for the release function */
+static int cec_release(struct inode *inode, struct file *filp)
+{
+	struct cec_devnode *cecdev = cec_devnode_data(filp);
+	int ret = 0;
+
+	/* decrease the refcount unconditionally since the release()
+	   return value is ignored. */
+	put_device(&cecdev->dev);
+	filp->private_data = NULL;
+	return ret;
+}
+
+static const struct file_operations cec_devnode_fops = {
+	.owner = THIS_MODULE,
+	.open = cec_open,
+	.unlocked_ioctl = cec_ioctl,
+	.release = cec_release,
+	.poll = cec_poll,
+	.llseek = no_llseek,
+};
+
+/**
+ * cec_devnode_register - register a cec device node
+ * @cecdev: cec device node structure we want to register
+ *
+ * The registration code assigns minor numbers and registers the new device node
+ * with the kernel. An error is returned if no free minor number can be found,
+ * or if the registration of the device node fails.
+ *
+ * Zero is returned on success.
+ *
+ * Note that if the cec_devnode_register call fails, the release() callback of
+ * the cec_devnode structure is *not* called, so the caller is responsible for
+ * freeing any data.
+ */
+static int __must_check cec_devnode_register(struct cec_devnode *cecdev,
+		struct module *owner)
+{
+	int minor;
+	int ret;
+
+	/* Part 1: Find a free minor number */
+	mutex_lock(&cec_devnode_lock);
+	minor = find_next_zero_bit(cec_devnode_nums, CEC_NUM_DEVICES, 0);
+	if (minor == CEC_NUM_DEVICES) {
+		mutex_unlock(&cec_devnode_lock);
+		pr_err("could not get a free minor\n");
+		return -ENFILE;
+	}
+
+	set_bit(minor, cec_devnode_nums);
+	mutex_unlock(&cec_devnode_lock);
+
+	cecdev->minor = minor;
+
+	/* Part 2: Initialize and register the character device */
+	cdev_init(&cecdev->cdev, &cec_devnode_fops);
+	cecdev->cdev.owner = owner;
+
+	ret = cdev_add(&cecdev->cdev, MKDEV(MAJOR(cec_dev_t), cecdev->minor),
+									1);
+	if (ret < 0) {
+		pr_err("%s: cdev_add failed\n", __func__);
+		goto error;
+	}
+
+	/* Part 3: Register the cec device */
+	cecdev->dev.bus = &cec_bus_type;
+	cecdev->dev.devt = MKDEV(MAJOR(cec_dev_t), cecdev->minor);
+	cecdev->dev.release = cec_devnode_release;
+	if (cecdev->parent)
+		cecdev->dev.parent = cecdev->parent;
+	dev_set_name(&cecdev->dev, "cec%d", cecdev->minor);
+	ret = device_register(&cecdev->dev);
+	if (ret < 0) {
+		pr_err("%s: device_register failed\n", __func__);
+		goto error;
+	}
+
+	/* Part 4: Activate this minor. The char device can now be used. */
+	set_bit(CEC_FLAG_REGISTERED, &cecdev->flags);
+
+	return 0;
+
+error:
+	cdev_del(&cecdev->cdev);
+	clear_bit(cecdev->minor, cec_devnode_nums);
+	return ret;
+}
+
+/**
+ * cec_devnode_unregister - unregister a cec device node
+ * @cecdev: the device node to unregister
+ *
+ * This unregisters the passed device. Future open calls will be met with
+ * errors.
+ *
+ * This function can safely be called if the device node has never been
+ * registered or has already been unregistered.
+ */
+static void cec_devnode_unregister(struct cec_devnode *cecdev)
+{
+	/* Check if cecdev was ever registered at all */
+	if (!cec_devnode_is_registered(cecdev))
+		return;
+
+	mutex_lock(&cec_devnode_lock);
+	clear_bit(CEC_FLAG_REGISTERED, &cecdev->flags);
+	mutex_unlock(&cec_devnode_lock);
+	device_unregister(&cecdev->dev);
+}
+
+int cec_create_adapter(struct cec_adapter *adap, const char *name, u32 caps)
+{
+	int res = 0;
+
+	adap->state = CEC_ADAP_STATE_DISABLED;
+	adap->name = name;
+	adap->phys_addr = 0xffff;
+	adap->capabilities = caps;
+	adap->version = CEC_VERSION_1_4;
+	adap->sequence = 0;
+	mutex_init(&adap->lock);
+	adap->kthread = kthread_run(cec_thread_func, adap, name);
+	init_waitqueue_head(&adap->kthread_waitq);
+	init_waitqueue_head(&adap->waitq);
+	if (IS_ERR(adap->kthread)) {
+		pr_err("cec-%s: kernel_thread() failed\n", name);
+		return PTR_ERR(adap->kthread);
+	}
+	if (caps) {
+		res = cec_devnode_register(&adap->devnode, adap->owner);
+		if (res)
+			kthread_stop(adap->kthread);
+	}
+	adap->recv_notifier = cec_receive_notify;
+
+	/* Prepare the RC input device */
+	adap->rc = rc_allocate_device();
+	if (!adap->rc) {
+		pr_err("cec-%s: failed to allocate memory for rc_dev\n", name);
+		cec_devnode_unregister(&adap->devnode);
+		kthread_stop(adap->kthread);
+		return -ENOMEM;
+	}
+
+	snprintf(adap->input_name, sizeof(adap->input_name), "RC for %s", name);
+	snprintf(adap->input_phys, sizeof(adap->input_phys), "%s/input0", name);
+	strncpy(adap->input_drv, name, sizeof(adap->input_drv));
+
+	adap->rc->input_name = adap->input_name;
+	adap->rc->input_phys = adap->input_phys;
+	adap->rc->dev.parent = &adap->devnode.dev;
+	adap->rc->driver_name = adap->input_drv;
+	adap->rc->driver_type = RC_DRIVER_CEC;
+	adap->rc->allowed_protocols = RC_BIT_CEC;
+	adap->rc->priv = adap;
+	adap->rc->map_name = RC_MAP_CEC;
+	adap->rc->timeout = MS_TO_NS(100);
+
+	res = rc_register_device(adap->rc);
+
+	if (res) {
+		pr_err("cec-%s: failed to prepare input device\n", name);
+		cec_devnode_unregister(&adap->devnode);
+		rc_free_device(adap->rc);
+		kthread_stop(adap->kthread);
+	}
+
+	return res;
+}
+EXPORT_SYMBOL_GPL(cec_create_adapter);
+
+void cec_delete_adapter(struct cec_adapter *adap)
+{
+	if (adap->kthread == NULL)
+		return;
+	kthread_stop(adap->kthread);
+	if (adap->kthread_config)
+		kthread_stop(adap->kthread_config);
+	adap->state = CEC_ADAP_STATE_DISABLED;
+	if (cec_devnode_is_registered(&adap->devnode))
+		cec_devnode_unregister(&adap->devnode);
+}
+EXPORT_SYMBOL_GPL(cec_delete_adapter);
+
+/*
+ *	Initialise cec for linux
+ */
+static int __init cec_devnode_init(void)
+{
+	int ret;
+
+	pr_info("Linux cec interface: v0.10\n");
+	ret = alloc_chrdev_region(&cec_dev_t, 0, CEC_NUM_DEVICES,
+				  CEC_NAME);
+	if (ret < 0) {
+		pr_warn("cec: unable to allocate major\n");
+		return ret;
+	}
+
+	ret = bus_register(&cec_bus_type);
+	if (ret < 0) {
+		unregister_chrdev_region(cec_dev_t, CEC_NUM_DEVICES);
+		pr_warn("cec: bus_register failed\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static void __exit cec_devnode_exit(void)
+{
+	bus_unregister(&cec_bus_type);
+	unregister_chrdev_region(cec_dev_t, CEC_NUM_DEVICES);
+}
+
+subsys_initcall(cec_devnode_init);
+module_exit(cec_devnode_exit)
+
+MODULE_AUTHOR("Hans Verkuil <hans.verkuil@cisco.com>");
+MODULE_DESCRIPTION("Device node registration for cec drivers");
+MODULE_LICENSE("GPL");
diff --git a/include/media/cec.h b/include/media/cec.h
new file mode 100644
index 0000000..d835e76
--- /dev/null
+++ b/include/media/cec.h
@@ -0,0 +1,142 @@
+#ifndef _CEC_DEVNODE_H
+#define _CEC_DEVNODE_H
+
+#include <linux/poll.h>
+#include <linux/fs.h>
+#include <linux/device.h>
+#include <linux/cdev.h>
+#include <linux/kthread.h>
+#include <linux/cec.h>
+#include <media/rc-core.h>
+
+#define cec_phys_addr_exp(pa) \
+	((pa) >> 12), ((pa) >> 8) & 0xf, ((pa) >> 4) & 0xf, (pa) & 0xf
+
+/*
+ * Flag to mark the cec_devnode struct as registered. Drivers must not touch
+ * this flag directly, it will be set and cleared by cec_devnode_register and
+ * cec_devnode_unregister.
+ */
+#define CEC_FLAG_REGISTERED	0
+
+/**
+ * struct cec_devnode - cec device node
+ * @parent:	parent device
+ * @minor:	device node minor number
+ * @flags:	flags, combination of the CEC_FLAG_* constants
+ *
+ * This structure represents a cec-related device node.
+ *
+ * The @parent is a physical device. It must be set by core or device drivers
+ * before registering the node.
+ */
+struct cec_devnode {
+	/* sysfs */
+	struct device dev;		/* cec device */
+	struct cdev cdev;		/* character device */
+	struct device *parent;		/* device parent */
+
+	/* device info */
+	int minor;
+	unsigned long flags;		/* Use bitops to access flags */
+
+	/* callbacks */
+	void (*release)(struct cec_devnode *cecdev);
+};
+
+static inline int cec_devnode_is_registered(struct cec_devnode *cecdev)
+{
+	return test_bit(CEC_FLAG_REGISTERED, &cecdev->flags);
+}
+
+struct cec_adapter;
+struct cec_data;
+
+typedef int (*cec_notify)(struct cec_adapter *adap, struct cec_data *data,
+			  void *priv);
+typedef int (*cec_recv_notify)(struct cec_adapter *adap, struct cec_msg *msg);
+
+struct cec_data {
+	struct cec_msg msg;
+	cec_notify func;
+	void *priv;
+	bool blocking;
+};
+
+/* Unconfigured state */
+#define CEC_ADAP_STATE_DISABLED		0
+#define CEC_ADAP_STATE_UNCONF		1
+#define CEC_ADAP_STATE_IDLE		2
+#define CEC_ADAP_STATE_TRANSMITTING	3
+#define CEC_ADAP_STATE_WAIT		4
+#define CEC_ADAP_STATE_RECEIVED		5
+
+#define CEC_TX_QUEUE_SZ	(4)
+#define CEC_RX_QUEUE_SZ	(4)
+#define CEC_EV_QUEUE_SZ	(40)
+
+struct cec_adapter {
+	struct module *owner;
+	const char *name;
+	struct cec_devnode devnode;
+	struct mutex lock;
+	struct rc_dev *rc;
+
+	struct cec_data tx_queue[CEC_TX_QUEUE_SZ];
+	u8 tx_qstart, tx_qcount;
+
+	struct cec_msg rx_queue[CEC_RX_QUEUE_SZ];
+	u8 rx_qstart, rx_qcount;
+
+	struct cec_event ev_queue[CEC_EV_QUEUE_SZ];
+	u8 ev_qstart, ev_qcount;
+
+	cec_recv_notify recv_notifier;
+	struct task_struct *kthread_config;
+
+	struct task_struct *kthread;
+	wait_queue_head_t kthread_waitq;
+	wait_queue_head_t waitq;
+
+	u8 state;
+	u32 capabilities;
+	u16 phys_addr;
+	u32 vendor_id;
+	u8 version;
+	u8 num_log_addrs;
+	u8 prim_device[CEC_MAX_LOG_ADDRS];
+	u8 log_addr_type[CEC_MAX_LOG_ADDRS];
+	u8 log_addr[CEC_MAX_LOG_ADDRS];
+	u8 passthrough;
+	u32 sequence;
+
+	char input_name[32];
+	char input_phys[32];
+	char input_drv[32];
+
+	int (*adap_enable)(struct cec_adapter *adap, bool enable);
+	int (*adap_log_addr)(struct cec_adapter *adap, u8 logical_addr);
+	int (*adap_transmit)(struct cec_adapter *adap, struct cec_msg *msg);
+	void (*adap_transmit_timed_out)(struct cec_adapter *adap);
+
+	void (*claimed_log_addr)(struct cec_adapter *adap, u8 idx);
+	int (*received)(struct cec_adapter *adap, struct cec_msg *msg);
+};
+
+#define to_cec_adapter(node) container_of(node, struct cec_adapter, devnode)
+
+int cec_create_adapter(struct cec_adapter *adap, const char *name, u32 caps);
+void cec_delete_adapter(struct cec_adapter *adap);
+int cec_transmit_msg(struct cec_adapter *adap, struct cec_data *data,
+		     bool block);
+int cec_receive_msg(struct cec_adapter *adap, struct cec_msg *msg, bool block);
+void cec_post_event(struct cec_adapter *adap, u32 event, u32 sequence);
+int cec_claim_log_addrs(struct cec_adapter *adap,
+			struct cec_log_addrs *log_addrs, bool block);
+int cec_enable(struct cec_adapter *adap, bool enable);
+
+/* Called by the adapter */
+void cec_transmit_done(struct cec_adapter *adap, u32 status);
+void cec_received_msg(struct cec_adapter *adap, struct cec_msg *msg);
+
+#endif /* _CEC_DEVNODE_H */
diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild
index 1a0006a..cea279e 100644
--- a/include/uapi/linux/Kbuild
+++ b/include/uapi/linux/Kbuild
@@ -81,6 +81,7 @@ header-y += capi.h
 header-y += cciss_defs.h
 header-y += cciss_ioctl.h
 header-y += cdrom.h
+header-y += cec.h
 header-y += cgroupstats.h
 header-y += chio.h
 header-y += cm4000_cs.h
diff --git a/include/uapi/linux/cec.h b/include/uapi/linux/cec.h
new file mode 100644
index 0000000..67b0049
--- /dev/null
+++ b/include/uapi/linux/cec.h
@@ -0,0 +1,332 @@
+#ifndef _CEC_H
+#define _CEC_H
+
+#include <linux/types.h>
+
+struct cec_msg {
+	__u64 ts;
+	__u32 len;
+	__u32 status;
+	__u32 timeout;
+	/* timeout (in ms) is used to timeout CEC_RECEIVE.
+	   Set to 0 if you want to wait forever. */
+	__u8  msg[16];
+	__u8  reply;
+	/* If non-zero, then wait for a reply with this opcode.
+	   If there was an error when sending the msg or FeatureAbort
+	   was returned, then reply is set to 0.
+	   If reply is non-zero upon return, then len/msg are set to
+	   the received message.
+	   If reply is zero upon return and status has the
+	   CEC_TX_STATUS_FEATURE_ABORT bit set, then len/msg are set to the
+	   received feature abort message.
+	   If reply is zero upon return and status has the
+	   CEC_TX_STATUS_REPLY_TIMEOUT
+	   bit set, then no reply was seen at all.
+	   This field is ignored with CEC_RECEIVE.
+	   If reply is non-zero for CEC_TRANSMIT and the message is a broadcast,
+	   then -EINVAL is returned.
+	   if reply is non-zero, then timeout is set to 1000 (the required
+	   maximum response time).
+	 */
+	__u32 sequence;
+	/* The framework assigns a sequence number to messages that are sent.
+	 * This can be used to track replies to previously sent messages.
+	 */
+	__u8 reserved[35];
+};
+
+static inline __u8 cec_msg_initiator(const struct cec_msg *msg)
+{
+	return msg->msg[0] >> 4;
+}
+
+static inline __u8 cec_msg_destination(const struct cec_msg *msg)
+{
+	return msg->msg[0] & 0xf;
+}
+
+static inline bool cec_msg_is_broadcast(const struct cec_msg *msg)
+{
+	return (msg->msg[0] & 0xf) == 0xf;
+}
+
+/* cec status field */
+#define CEC_TX_STATUS_OK            (0)
+#define CEC_TX_STATUS_ARB_LOST      (1 << 0)
+#define CEC_TX_STATUS_RETRY_TIMEOUT (1 << 1)
+#define CEC_TX_STATUS_FEATURE_ABORT (1 << 2)
+#define CEC_TX_STATUS_REPLY_TIMEOUT (1 << 3)
+#define CEC_RX_STATUS_READY         (0)
+
+#define CEC_LOG_ADDR_INVALID 0xff
+
+/* The maximum number of logical addresses one device can be assigned to.
+ * The CEC 2.0 spec allows for only 2 logical addresses at the moment. The
+ * Analog Devices CEC hardware supports 3. So let's go wild and go for 4. */
+#define CEC_MAX_LOG_ADDRS 4
+
+/* The "Primary Device Type" */
+#define CEC_PRIM_DEVTYPE_TV		0
+#define CEC_PRIM_DEVTYPE_RECORD		1
+#define CEC_PRIM_DEVTYPE_TUNER		3
+#define CEC_PRIM_DEVTYPE_PLAYBACK	4
+#define CEC_PRIM_DEVTYPE_AUDIOSYSTEM	5
+#define CEC_PRIM_DEVTYPE_SWITCH		6
+#define CEC_PRIM_DEVTYPE_VIDEOPROC	7
+
+/* The "All Device Types" flags (CEC 2.0) */
+#define CEC_FL_ALL_DEVTYPE_TV		(1 << 7)
+#define CEC_FL_ALL_DEVTYPE_RECORD	(1 << 6)
+#define CEC_FL_ALL_DEVTYPE_TUNER	(1 << 5)
+#define CEC_FL_ALL_DEVTYPE_PLAYBACK	(1 << 4)
+#define CEC_FL_ALL_DEVTYPE_AUDIOSYSTEM	(1 << 3)
+#define CEC_FL_ALL_DEVTYPE_SWITCH	(1 << 2)
+/* And if you wondering what happened to VIDEOPROC devices: those should
+ * be mapped to a SWITCH. */
+
+/* The logical address types that the CEC device wants to claim */
+#define CEC_LOG_ADDR_TYPE_TV		0
+#define CEC_LOG_ADDR_TYPE_RECORD	1
+#define CEC_LOG_ADDR_TYPE_TUNER		2
+#define CEC_LOG_ADDR_TYPE_PLAYBACK	3
+#define CEC_LOG_ADDR_TYPE_AUDIOSYSTEM	4
+#define CEC_LOG_ADDR_TYPE_SPECIFIC	5
+#define CEC_LOG_ADDR_TYPE_UNREGISTERED	6
+/* Switches should use UNREGISTERED.
+ * Video processors should use SPECIFIC. */
+
+/* The CEC version */
+#define CEC_VERSION_1_3A		4
+#define CEC_VERSION_1_4			5
+#define CEC_VERSION_2_0			6
+
+struct cec_event {
+	__u64 ts;
+	__u32 event;
+	__u32 sequence;
+	__u8 reserved[8];
+};
+
+/* The CEC state */
+#define CEC_STATE_DISABLED		0
+#define CEC_STATE_ENABLED		1
+
+/* The passthrough mode state */
+#define CEC_PASSTHROUGH_DISABLED	0
+#define CEC_PASSTHROUGH_ENABLED		1
+
+/* Userspace has to configure the adapter state (enable/disable) */
+#define CEC_CAP_STATE		(1 << 0)
+/* Userspace has to configure the physical address */
+#define CEC_CAP_PHYS_ADDR	(1 << 1)
+/* Userspace has to configure the logical addresses */
+#define CEC_CAP_LOG_ADDRS	(1 << 2)
+/* Userspace can transmit messages */
+#define CEC_CAP_TRANSMIT	(1 << 3)
+/* Userspace can receive messages */
+#define CEC_CAP_RECEIVE		(1 << 4)
+/* Userspace has to configure the vendor id */
+#define CEC_CAP_VENDOR_ID	(1 << 5)
+/* The hardware has the possibility to work in the passthrough */
+#define CEC_CAP_PASSTHROUGH	(1 << 6)
+
+struct cec_caps {
+	__u32 available_log_addrs;
+	__u32 capabilities;
+	__u32 vendor_id;
+	__u8  version;
+	__u8  reserved[35];
+};
+
+struct cec_log_addrs {
+	__u8 cec_version;
+	__u8 num_log_addrs;
+	__u8 primary_device_type[CEC_MAX_LOG_ADDRS];
+	__u8 log_addr_type[CEC_MAX_LOG_ADDRS];
+	__u8 log_addr[CEC_MAX_LOG_ADDRS];
+
+	/* CEC 2.0 */
+	__u8 all_device_types;
+	__u8 features[CEC_MAX_LOG_ADDRS][12];
+
+	__u8 reserved[65];
+};
+
+/* Commands */
+
+/* One Touch Play Feature */
+#define CEC_OP_ACTIVE_SOURCE			0x82
+#define CEC_OP_IMAGE_VIEW_ON			0x04
+#define CEC_OP_TEXT_VIEW_ON			0x0d
+
+/* Routing Control Feature */
+#define CEC_OP_ACTIVE_SOURCE			0x82
+#define CEC_OP_INACTIVE_SOURCE			0x9d
+#define CEC_OP_REQUEST_ACTIVE_SOURCE		0x85
+#define CEC_OP_ROUTING_CHANGE			0x80
+#define CEC_OP_ROUTING_INFORMATION		0x81
+#define CEC_OP_SET_STREAM_PATH			0x86
+
+/* Standby Feature */
+#define CEC_OP_STANDBY				0x36
+
+/* One Touch Record Feature */
+#define CEC_OP_RECORD_OFF			0x0b
+#define CEC_OP_RECORD_ON			0x09
+#define CEC_OP_RECORD_STATUS			0x0a
+#define CEC_OP_RECORD_TV_SCREEN			0x0f
+
+/* Timer Programming Feature */
+#define CEC_OP_CLEAR_ANALOGUE_TIMER		0x33
+#define CEC_OP_CLEAR_DIGITAL_TIMER		0x99
+#define CEC_OP_CLEAR_EXT_TIMER			0xa1
+#define CEC_OP_SET_ANALOGUE_TIMER		0x34
+#define CEC_OP_SET_DIGITAL_TIMER		0x97
+#define CEC_OP_SET_EXT_TIMER			0xa2
+#define CEC_OP_SET_EXT_PROGRAM_TIMER		0x67
+#define CEC_OP_TIMER_CLEARED_STATUS		0x43
+#define CEC_OP_TIMER_STATUS			0x35
+
+/* System Information Feature */
+#define CEC_OP_CEC_VERSION			0x9e
+#define CEC_OP_GET_CEC_VERSION			0x9f
+#define CEC_OP_GIVE_PHYSICAL_ADDR		0x83
+#define CEC_OP_GET_MENU_LANGUAGE		0x91
+#define CEC_OP_REPORT_PHYSICAL_ADDR		0x84
+#define CEC_OP_SET_MENU_LANGUAGE		0x32
+#define CEC_OP_REPORT_FEATURES			0xa6	/* HDMI 2.0 */
+#define CEC_OP_GIVE_FEATURES			0xa5	/* HDMI 2.0 */
+
+/* Deck Control Feature */
+#define CEC_OP_DECK_CONTROL			0x42
+#define CEC_OP_DECK_STATUS			0x1b
+#define CEC_OP_GIVE_DECK_STATUS			0x1a
+#define CEC_OP_PLAY				0x41
+
+/* Tuner Control Feature */
+#define CEC_OP_GIVE_TUNER_DEVICE_STATUS		0x08
+#define CEC_OP_SELECT_ANALOGUE_SERVICE		0x92
+#define CEC_OP_SELECT_DIGITAL_SERVICE		0x93
+#define CEC_OP_TUNER_DEVICE_STATUS		0x07
+#define CEC_OP_TUNER_STEP_DECREMENT		0x06
+#define CEC_OP_TUNER_STEP_INCREMENT		0x05
+
+/* Vendor Specific Commands Feature */
+#define CEC_OP_CEC_VERSION			0x9e
+#define CEC_OP_DEVICE_VENDOR_ID			0x87
+#define CEC_OP_GET_CEC_VERSION			0x9f
+#define CEC_OP_GIVE_DEVICE_VENDOR_ID		0x8c
+#define CEC_OP_VENDOR_COMMAND			0x89
+#define CEC_OP_VENDOR_COMMAND_WITH_ID		0xa0
+#define CEC_OP_VENDOR_REMOTE_BUTTON_DOWN	0x8a
+#define CEC_OP_VENDOR_REMOTE_BUTTON_UP		0x8b
+
+/* OSD Display Feature */
+#define CEC_OP_SET_OSD_STRING			0x64
+
+/* Device OSD Transfer Feature */
+#define CEC_OP_GIVE_OSD_NAME			0x46
+#define CEC_OP_SET_OSD_NAME			0x47
+
+/* Device Menu Control Feature */
+#define CEC_OP_MENU_REQUEST			0x8d
+#define CEC_OP_MENU_STATUS			0x8e
+#define CEC_OP_USER_CONTROL_PRESSED		0x44
+#define CEC_OP_USER_CONTROL_RELEASED		0x45
+
+/* Power Status Feature */
+#define CEC_OP_GIVE_DEVICE_POWER_STATUS		0x8f
+#define CEC_OP_REPORT_POWER_STATUS		0x90
+#define CEC_OP_FEATURE_ABORT			0x00
+#define CEC_OP_ABORT				0xff
+
+/* System Audio Control Feature */
+#define CEC_OP_GIVE_AUDIO_STATUS		0x71
+#define CEC_OP_GIVE_SYSTEM_AUDIO_MODE_STATUS	0x7d
+#define CEC_OP_REPORT_AUDIO_STATUS		0x7a
+#define CEC_OP_SET_SYSTEM_AUDIO_MODE		0x72
+#define CEC_OP_SYSTEM_AUDIO_MODE_REQUEST	0x70
+#define CEC_OP_SYSTEM_AUDIO_MODE_STATUS		0x7e
+
+/* Audio Rate Control Feature */
+#define CEC_OP_SET_AUDIO_RATE			0x9a
+
+/* Audio Return Channel Control Feature */
+#define CEC_OP_INITIATE_ARC			0xc0
+#define CEC_OP_REPORT_ARC_INITIATED		0xc1
+#define CEC_OP_REPORT_ARC_TERMINATED		0xc2
+#define CEC_OP_REQUEST_ARC_INITIATION		0xc3
+#define CEC_OP_REQUEST_ARC_TERMINATION		0xc4
+#define CEC_OP_TERMINATE_ARC			0xc5
+
+/* Dynamic Audio Lipsync Feature, HDMI 2.0 */
+#define CEC_OP_REQUEST_CURRENT_LATENCY		0xa7
+#define CEC_OP_REPORT_CURRENT_LATENCY		0xa8
+
+/* Capability Discovery and Control Feature */
+#define CEC_OP_CDC_MESSAGE			0xf8
+
+/* Events */
+/* Event that occurs when a cable is connected */
+#define CEC_EVENT_CONNECT	1
+/* Event that occurs when all logical addresses were claimed */
+#define CEC_EVENT_READY		2
+/* Event that is sent when the cable is disconnected */
+#define CEC_EVENT_DISCONNECT	3
+/* This event is sent when a reply to a message is received */
+#define CEC_EVENT_GOT_REPLY	4
+
+/* ioctls */
+
+/* issue a CEC command */
+#define CEC_G_CAPS		_IOWR('a', 0, struct cec_caps)
+#define CEC_TRANSMIT		_IOWR('a', 1, struct cec_msg)
+#define CEC_RECEIVE		_IOWR('a', 2, struct cec_msg)
+
+/*
+   Configure the CEC adapter. It sets the device type and which
+   logical types it will try to claim. It will return which
+   logical addresses it could actually claim.
+   An error is returned if the adapter is disabled or if there
+   is no physical address assigned.
+ */
+
+#define CEC_G_ADAP_LOG_ADDRS	_IOR('a', 3, struct cec_log_addrs)
+#define CEC_S_ADAP_LOG_ADDRS	_IOWR('a', 4, struct cec_log_addrs)
+
+/*
+   Enable/disable the adapter. The Set state ioctl may not
+   be available if that is handled internally.
+ */
+#define CEC_G_ADAP_STATE	_IOR('a', 5, __u32)
+#define CEC_S_ADAP_STATE	_IOW('a', 6, __u32)
+
+/*
+   phys_addr is either 0 (if this is the CEC root device)
+   or a valid physical address obtained from the sink's EDID
+   as read by this CEC device (if this is a source device)
+   or a physical address obtained and modified from a sink
+   EDID and used for a sink CEC device.
+   If nothing is connected, then phys_addr is 0xffff.
+   See HDMI 1.4b, section 8.7 (Physical Address).
+
+   The Set ioctl may not be available if that is handled
+   internally.
+ */
+#define CEC_G_ADAP_PHYS_ADDR	_IOR('a', 7, __u16)
+#define CEC_S_ADAP_PHYS_ADDR	_IOW('a', 8, __u16)
+
+#define CEC_G_EVENT		_IOWR('a', 9, struct cec_event)
+/*
+   Read and set the vendor ID of the CEC adapter.
+ */
+#define CEC_G_VENDOR_ID		_IOR('a', 10, __u32)
+#define CEC_S_VENDOR_ID		_IOW('a', 11, __u32)
+/*
+   Enable/disable the passthrough mode
+ */
+#define CEC_G_PASSTHROUGH	_IOR('a', 12, __u32)
+#define CEC_S_PASSTHROUGH	_IOW('a', 13, __u32)
+
+#endif
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH v6 07/11] DocBook/media: add CEC documentation
  2015-05-04 17:32 [PATCH v6 00/11] Kamil Debski
                   ` (5 preceding siblings ...)
  2015-05-04 17:32 ` [PATCH v6 06/11] cec: add HDMI CEC framework Kamil Debski
@ 2015-05-04 17:33 ` Kamil Debski
  2015-05-08 10:45   ` Hans Verkuil
  2015-05-04 17:33 ` [PATCH v6 08/11] v4l2-subdev: add HDMI CEC ops Kamil Debski
                   ` (6 subsequent siblings)
  13 siblings, 1 reply; 30+ messages in thread
From: Kamil Debski @ 2015-05-04 17:33 UTC (permalink / raw)
  To: dri-devel, linux-media
  Cc: m.szyprowski, k.debski, mchehab, hverkuil, kyungmin.park, thomas,
	sean, dmitry.torokhov, linux-input, linux-samsung-soc, lars,
	Hans Verkuil

From: Hans Verkuil <hverkuil@xs4all.nl>

Add DocBook documentation for the CEC API.

Signed-off-by: Hans Verkuil <hansverk@cisco.com>
[k.debski@samsung.com: add documentation for passthrough mode]
[k.debski@samsung.com: minor fixes and change of reserved field sizes]
Signed-off-by: Kamil Debski <k.debski@samsung.com>
---
 Documentation/DocBook/media/Makefile               |    4 +-
 Documentation/DocBook/media/v4l/biblio.xml         |   10 +
 Documentation/DocBook/media/v4l/cec-api.xml        |   74 ++++++
 Documentation/DocBook/media/v4l/cec-func-close.xml |   59 +++++
 Documentation/DocBook/media/v4l/cec-func-ioctl.xml |   73 ++++++
 Documentation/DocBook/media/v4l/cec-func-open.xml  |   94 +++++++
 Documentation/DocBook/media/v4l/cec-func-poll.xml  |   89 +++++++
 .../DocBook/media/v4l/cec-ioc-g-adap-log-addrs.xml |  275 ++++++++++++++++++++
 .../DocBook/media/v4l/cec-ioc-g-adap-phys-addr.xml |   78 ++++++
 .../DocBook/media/v4l/cec-ioc-g-adap-state.xml     |   87 +++++++
 Documentation/DocBook/media/v4l/cec-ioc-g-caps.xml |  173 ++++++++++++
 .../DocBook/media/v4l/cec-ioc-g-event.xml          |  125 +++++++++
 .../DocBook/media/v4l/cec-ioc-g-passthrough.xml    |   88 +++++++
 .../DocBook/media/v4l/cec-ioc-g-vendor-id.xml      |   70 +++++
 .../DocBook/media/v4l/cec-ioc-receive.xml          |  185 +++++++++++++
 Documentation/DocBook/media_api.tmpl               |    6 +-
 16 files changed, 1487 insertions(+), 3 deletions(-)
 create mode 100644 Documentation/DocBook/media/v4l/cec-api.xml
 create mode 100644 Documentation/DocBook/media/v4l/cec-func-close.xml
 create mode 100644 Documentation/DocBook/media/v4l/cec-func-ioctl.xml
 create mode 100644 Documentation/DocBook/media/v4l/cec-func-open.xml
 create mode 100644 Documentation/DocBook/media/v4l/cec-func-poll.xml
 create mode 100644 Documentation/DocBook/media/v4l/cec-ioc-g-adap-log-addrs.xml
 create mode 100644 Documentation/DocBook/media/v4l/cec-ioc-g-adap-phys-addr.xml
 create mode 100644 Documentation/DocBook/media/v4l/cec-ioc-g-adap-state.xml
 create mode 100644 Documentation/DocBook/media/v4l/cec-ioc-g-caps.xml
 create mode 100644 Documentation/DocBook/media/v4l/cec-ioc-g-event.xml
 create mode 100644 Documentation/DocBook/media/v4l/cec-ioc-g-passthrough.xml
 create mode 100644 Documentation/DocBook/media/v4l/cec-ioc-g-vendor-id.xml
 create mode 100644 Documentation/DocBook/media/v4l/cec-ioc-receive.xml

diff --git a/Documentation/DocBook/media/Makefile b/Documentation/DocBook/media/Makefile
index 8bf7c61..9650332 100644
--- a/Documentation/DocBook/media/Makefile
+++ b/Documentation/DocBook/media/Makefile
@@ -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/uapi/linux/cec.h) \
 	$(shell perl -ne 'print "$$1 " if /\#define\s+([^\s]+)\s+_IO/' $(srctree)/include/uapi/linux/v4l2-subdev.h) \
 	VIDIOC_SUBDEV_G_FRAME_INTERVAL \
 	VIDIOC_SUBDEV_S_FRAME_INTERVAL \
@@ -98,6 +99,7 @@ STRUCTS = \
 	$(shell perl -ne 'print "$$1 " if (/^struct\s+([A-Z][^\s]+)\s+/)' $(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/uapi/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)
 
@@ -300,7 +302,7 @@ $(MEDIA_OBJ_DIR)/media-entities.tmpl: $(MEDIA_OBJ_DIR)/v4l2.xml
 	@(								\
 	for ident in $(IOCTLS) ; do					\
 	  entity=`echo $$ident | tr _ -` ;				\
-	  id=`grep "<refname>$$ident" $(MEDIA_OBJ_DIR)/vidioc-*.xml $(MEDIA_OBJ_DIR)/media-ioc-*.xml | sed -r s,"^.*/(.*).xml.*","\1",` ; \
+	  id=`grep "<refname>$$ident" $(MEDIA_OBJ_DIR)/vidioc-*.xml $(MEDIA_OBJ_DIR)/media-ioc-*.xml $(MEDIA_OBJ_DIR)/cec-ioc-*.xml | sed -r s,"^.*/(.*).xml.*","\1",` ; \
 	  echo "<!ENTITY $$entity \"<link"				\
 	    "linkend='$$id'><constant>$$ident</constant></link>\">"	\
 	  >>$@ ;							\
diff --git a/Documentation/DocBook/media/v4l/biblio.xml b/Documentation/DocBook/media/v4l/biblio.xml
index fdee6b3..bed940b 100644
--- a/Documentation/DocBook/media/v4l/biblio.xml
+++ b/Documentation/DocBook/media/v4l/biblio.xml
@@ -324,6 +324,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>
diff --git a/Documentation/DocBook/media/v4l/cec-api.xml b/Documentation/DocBook/media/v4l/cec-api.xml
new file mode 100644
index 0000000..b59f610
--- /dev/null
+++ b/Documentation/DocBook/media/v4l/cec-api.xml
@@ -0,0 +1,74 @@
+<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>2015</year>
+    <holder>Hans Verkuil</holder>
+  </copyright>
+
+  <revhistory>
+    <!-- Put document revisions here, newest first. -->
+    <revision>
+      <revnumber>1.0.0</revnumber>
+      <date>2015-04-27</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>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 and that allow (or require) userspace to handle CEC
+    messages and/or configure the CEC adapter will create a CEC device node (/dev/cecX)
+    to give userspace access to the CEC adapter. The &CEC-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-g-caps;
+  &sub-cec-ioc-receive;
+  &sub-cec-ioc-g-adap-log-addrs;
+  &sub-cec-ioc-g-adap-state;
+  &sub-cec-ioc-g-adap-phys-addr;
+  &sub-cec-ioc-g-event;
+  &sub-cec-ioc-g-vendor-id;
+  &sub-cec-ioc-g-passthrough;
+</appendix>
diff --git a/Documentation/DocBook/media/v4l/cec-func-close.xml b/Documentation/DocBook/media/v4l/cec-func-close.xml
new file mode 100644
index 0000000..c3978af
--- /dev/null
+++ b/Documentation/DocBook/media/v4l/cec-func-close.xml
@@ -0,0 +1,59 @@
+<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>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>
diff --git a/Documentation/DocBook/media/v4l/cec-func-ioctl.xml b/Documentation/DocBook/media/v4l/cec-func-ioctl.xml
new file mode 100644
index 0000000..ad85973
--- /dev/null
+++ b/Documentation/DocBook/media/v4l/cec-func-ioctl.xml
@@ -0,0 +1,73 @@
+<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_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>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>
diff --git a/Documentation/DocBook/media/v4l/cec-func-open.xml b/Documentation/DocBook/media/v4l/cec-func-open.xml
new file mode 100644
index 0000000..d814847
--- /dev/null
+++ b/Documentation/DocBook/media/v4l/cec-func-open.xml
@@ -0,0 +1,94 @@
+<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 either <constant>O_RDONLY</constant>
+	  or <constant>O_RDWR</constant>. Other flags have no effect.</para>
+	</listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+  <refsect1>
+    <title>Description</title>
+    <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 are:</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>
diff --git a/Documentation/DocBook/media/v4l/cec-func-poll.xml b/Documentation/DocBook/media/v4l/cec-func-poll.xml
new file mode 100644
index 0000000..6853817
--- /dev/null
+++ b/Documentation/DocBook/media/v4l/cec-func-poll.xml
@@ -0,0 +1,89 @@
+<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>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>
diff --git a/Documentation/DocBook/media/v4l/cec-ioc-g-adap-log-addrs.xml b/Documentation/DocBook/media/v4l/cec-ioc-g-adap-log-addrs.xml
new file mode 100644
index 0000000..7bed57f
--- /dev/null
+++ b/Documentation/DocBook/media/v4l/cec-ioc-g-adap-log-addrs.xml
@@ -0,0 +1,275 @@
+<refentry id="cec-ioc-g-adap-log-addrs">
+  <refmeta>
+    <refentrytitle>ioctl CEC_G_ADAP_LOG_ADDRS, CEC_S_ADAP_LOG_ADDRS</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>CEC_G_ADAP_LOG_ADDRS</refname>
+    <refname>CEC_S_ADAP_LOG_ADDRS</refname>
+    <refpurpose>Get or set the logical addresses</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_log_addrs *<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_G_ADAP_LOG_ADDRS, CEC_S_ADAP_LOG_ADDRS</para>
+	</listitem>
+      </varlistentry>
+      <varlistentry>
+	<term><parameter>argp</parameter></term>
+	<listitem>
+	  <para></para>
+	</listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para>To query the current CEC logical addresses applications call the
+<constant>CEC_G_ADAP_LOG_ADDRS</constant> ioctl with a pointer to a
+<structname>cec_log_addrs</structname> structure where the drivers stores the
+logical addresses.</para>
+
+    <para>To set new logical addresses applications fill in struct <structname>cec_log_addrs</structname>
+and call the <constant>CEC_S_ADAP_LOG_ADDRS</constant> ioctl with a pointer to this struct.
+The <constant>CEC_S_ADAP_LOG_ADDRS</constant> ioctl is only available if
+<constant>CEC_CAP_LOG_ADDRS</constant> is set. This ioctl will block until all
+requested logical addresses have been claimed.</para>
+
+    <table pgwide="1" frame="none" id="cec-log-addrs">
+      <title>struct <structname>cec_log_addrs</structname></title>
+      <tgroup cols="3">
+	&cs-str;
+	<tbody valign="top">
+	  <row>
+	    <entry>__u8</entry>
+	    <entry><structfield>cec_version</structfield></entry>
+	    <entry>The CEC version that this adapter shall use. See
+	    <xref linkend="cec-versions" />.
+	    Used to implement the <constant>CEC_OP_CEC_VERSION</constant> and
+	    <constant>CEC_OP_REPORT_FEATURES</constant> messages. Note that
+	    <constant>CEC_VERSION_1_3A</constant> is not allowed
+	    by the CEC framework.
+	    </entry>
+	  </row>
+	  <row>
+	    <entry>__u8</entry>
+	    <entry><structfield>num_log_addrs</structfield></entry>
+	    <entry>Number of logical addresses to set up. Must be &le;
+	    <structfield>available_log_addrs</structfield> as returned by
+	    &CEC-G-CAPS;. All arrays in this structure are only filled up to
+	    index <structfield>available_log_addrs</structfield>-1. The remaining
+	    array elements will be ignored. Note that the CEC 2.0 standard allows
+	    for a maximum of 2 logical addresses, although some hardware has support
+	    for more. <constant>CEC_MAX_LOG_ADDRS</constant> is 4. The driver will
+	    return the actual number of logical addresses it could claim, which may
+	    be less than what was requested. If this field is set to 0, then the
+	    CEC adapter shall clear all claimed logical addresses and all other
+	    fields will be ignored.</entry>
+	  </row>
+	  <row>
+	    <entry>__u8</entry>
+	    <entry><structfield>primary_device_type</structfield>[CEC_MAX_LOG_ADDRS]</entry>
+	    <entry>Primary device type for each logical address. See
+	    <xref linkend="cec-prim-dev-types" /> for possible types.</entry>
+	  </row>
+	  <row>
+	    <entry>__u8</entry>
+	    <entry><structfield>log_addr_type</structfield>[CEC_MAX_LOG_ADDRS]</entry>
+	    <entry>Logical address types. See <xref linkend="cec-log-addr-types" /> for
+	    possible types. The driver will update this with the actual logical address
+	    type that it claimed (e.g. it may have to fallback to
+	    <constant>CEC_LOG_ADDR_TYPE_UNREGISTERED</constant>).</entry>
+	  </row>
+	  <row>
+	    <entry>__u8</entry>
+	    <entry><structfield>log_addr</structfield>[CEC_MAX_LOG_ADDRS]</entry>
+	    <entry>The actual logical addresses that were claimed. This is set by the
+	    driver. If no logical address could be claimed, then it is set to
+	    <constant>CEC_LOG_ADDR_INVALID</constant>.</entry>
+	  </row>
+	  <row>
+	    <entry>__u8</entry>
+	    <entry><structfield>all_device_types</structfield></entry>
+	    <entry>CEC 2.0 specific: all device types. See <xref linkend="cec-all-dev-types-flags" />.
+	    Used to implement the <constant>CEC_OP_REPORT_FEATURES</constant> message.
+	    This field is ignored if <structfield>cec_version</structfield> &lt;
+	    <constant>CEC_VERSION_2_0</constant>.</entry>
+	  </row>
+	  <row>
+	    <entry>__u8</entry>
+	    <entry><structfield>features</structfield>[CEC_MAX_LOG_ADDRS][12]</entry>
+	    <entry>Features for each logical address. Used to implement the
+	    <constant>CEC_OP_REPORT_FEATURES</constant> message. The 12 bytes include
+	    both the RC Profile and the Device Features.
+	    This field is ignored if <structfield>cec_version</structfield> &lt;
+	    <constant>CEC_VERSION_2_0</constant>.</entry>
+	  </row>
+	  <row>
+	    <entry>__u8</entry>
+	    <entry><structfield>reserved</structfield>[65]</entry>
+	    <entry>Reserved for future extensions. Drivers and applications must
+	    set this array to zero.</entry>
+	  </row>
+	</tbody>
+      </tgroup>
+    </table>
+
+    <table pgwide="1" frame="none" id="cec-prim-dev-types">
+      <title>CEC Primary Device Types</title>
+      <tgroup cols="3">
+	&cs-def;
+	<tbody valign="top">
+	  <row>
+	    <entry><constant>CEC_PRIM_DEVTYPE_TV</constant></entry>
+	    <entry>0</entry>
+	    <entry>Use for a TV.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>CEC_PRIM_DEVTYPE_RECORD</constant></entry>
+	    <entry>1</entry>
+	    <entry>Use for a recording device.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>CEC_PRIM_DEVTYPE_TUNER</constant></entry>
+	    <entry>3</entry>
+	    <entry>Use for a device with a tuner.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>CEC_PRIM_DEVTYPE_PLAYBACK</constant></entry>
+	    <entry>4</entry>
+	    <entry>Use for a playback device.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>CEC_PRIM_DEVTYPE_AUDIOSYSTEM</constant></entry>
+	    <entry>5</entry>
+	    <entry>Use for an audio system (e.g. an audio/video receiver).</entry>
+	  </row>
+	  <row>
+	    <entry><constant>CEC_PRIM_DEVTYPE_SWITCH</constant></entry>
+	    <entry>6</entry>
+	    <entry>Use for a CEC switch.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>CEC_PRIM_DEVTYPE_VIDEOPROC</constant></entry>
+	    <entry>7</entry>
+	    <entry>Use for a video processor device.</entry>
+	  </row>
+	</tbody>
+      </tgroup>
+    </table>
+
+    <table pgwide="1" frame="none" id="cec-log-addr-types">
+      <title>CEC Logical Address Types</title>
+      <tgroup cols="3">
+	&cs-def;
+	<tbody valign="top">
+	  <row>
+	    <entry><constant>CEC_LOG_ADDR_TYPE_TV</constant></entry>
+	    <entry>0</entry>
+	    <entry>Use for a TV.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>CEC_LOG_ADDR_TYPE_RECORD</constant></entry>
+	    <entry>1</entry>
+	    <entry>Use for a recording device.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>CEC_LOG_ADDR_TYPE_TUNER</constant></entry>
+	    <entry>2</entry>
+	    <entry>Use for a tuner device.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>CEC_LOG_ADDR_TYPE_PLAYBACK</constant></entry>
+	    <entry>3</entry>
+	    <entry>Use for a playback device.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>CEC_LOG_ADDR_TYPE_AUDIOSYSTEM</constant></entry>
+	    <entry>4</entry>
+	    <entry>Use for an audio system device.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>CEC_LOG_ADDR_TYPE_SPECIFIC</constant></entry>
+	    <entry>5</entry>
+	    <entry>Use for a second TV or for a video processor device.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>CEC_LOG_ADDR_TYPE_UNREGISTERED</constant></entry>
+	    <entry>6</entry>
+	    <entry>Fallback if all relevant logical addresses are claimed, or for
+	    pure CEC switches or CDC-only devices (CDC: Capability Discovery and Control).</entry>
+	  </row>
+	</tbody>
+      </tgroup>
+    </table>
+
+    <table pgwide="1" frame="none" id="cec-all-dev-types-flags">
+      <title>CEC All Device Types Flags</title>
+      <tgroup cols="3">
+	&cs-def;
+	<tbody valign="top">
+	  <row>
+	    <entry><constant>CEC_FL_ALL_DEVTYPE_TV</constant></entry>
+	    <entry>0x80</entry>
+	    <entry>This supports the TV type.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>CEC_FL_ALL_DEVTYPE_RECORD</constant></entry>
+	    <entry>0x40</entry>
+	    <entry>This supports the Recording type.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>CEC_FL_ALL_DEVTYPE_TUNER</constant></entry>
+	    <entry>0x20</entry>
+	    <entry>This supports the Tuner type.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>CEC_FL_ALL_DEVTYPE_PLAYBACK</constant></entry>
+	    <entry>0x10</entry>
+	    <entry>This supports the Playback type.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>CEC_FL_ALL_DEVTYPE_AUDIOSYSTEM</constant></entry>
+	    <entry>0x08</entry>
+	    <entry>This supports the Audio System type.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>CEC_FL_ALL_DEVTYPE_SWITCH</constant></entry>
+	    <entry>0x04</entry>
+	    <entry>This supports the CEC Switch or Video Processing type.</entry>
+	  </row>
+	</tbody>
+      </tgroup>
+    </table>
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+  </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/media/v4l/cec-ioc-g-adap-phys-addr.xml b/Documentation/DocBook/media/v4l/cec-ioc-g-adap-phys-addr.xml
new file mode 100644
index 0000000..0e201af
--- /dev/null
+++ b/Documentation/DocBook/media/v4l/cec-ioc-g-adap-phys-addr.xml
@@ -0,0 +1,78 @@
+<refentry id="cec-ioc-g-adap-phys-addr">
+  <refmeta>
+    <refentrytitle>ioctl CEC_G_ADAP_PHYS_ADDR, CEC_S_ADAP_PHYS_ADDR</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>CEC_G_ADAP_PHYS_ADDR</refname>
+    <refname>CEC_S_ADAP_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_G_ADAP_PHYS_ADDR, CEC_S_ADAP_PHYS_ADDR</para>
+	</listitem>
+      </varlistentry>
+      <varlistentry>
+	<term><parameter>argp</parameter></term>
+	<listitem>
+	  <para></para>
+	</listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para>To query the current physical address applications call the
+<constant>CEC_G_ADAP_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_S_ADAP_PHYS_ADDR</constant> ioctl with a
+pointer to this integer. <constant>CEC_S_ADAP_PHYS_ADDR</constant> is only
+available if <constant>CEC_CAP_PHYS_ADDR</constant> is set.</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>
diff --git a/Documentation/DocBook/media/v4l/cec-ioc-g-adap-state.xml b/Documentation/DocBook/media/v4l/cec-ioc-g-adap-state.xml
new file mode 100644
index 0000000..f20dd17
--- /dev/null
+++ b/Documentation/DocBook/media/v4l/cec-ioc-g-adap-state.xml
@@ -0,0 +1,87 @@
+<refentry id="cec-ioc-g-adap-state">
+  <refmeta>
+    <refentrytitle>ioctl CEC_G_ADAP_STATE, CEC_S_ADAP_STATE</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>CEC_G_ADAP_STATE</refname>
+    <refname>CEC_S_ADAP_STATE</refname>
+    <refpurpose>Get or set the adapter state</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+	<funcdef>int <function>ioctl</function></funcdef>
+	<paramdef>int <parameter>fd</parameter></paramdef>
+	<paramdef>int <parameter>request</parameter></paramdef>
+	<paramdef>__u32 *<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_G_ADAP_STATE, CEC_S_ADAP_STATE</para>
+	</listitem>
+      </varlistentry>
+      <varlistentry>
+	<term><parameter>argp</parameter></term>
+	<listitem>
+	  <para></para>
+	</listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para>To query the current adapter state applications call the
+<constant>CEC_G_ADAP_STATE</constant> ioctl with a pointer to an __u32
+where the driver stores the state.</para>
+
+    <para>To set the adapter state applications store the CEC adapter state
+in an __u32 and call the <constant>CEC_S_ADAP_STATE</constant> ioctl with a
+pointer to this integer. <constant>CEC_S_ADAP_STATE</constant> is only
+available if <constant>CEC_CAP_STATE</constant> is set.</para>
+
+    <para>Available states are:</para>
+
+    <table pgwide="1" frame="none" id="cec-adap-states">
+      <title>Adapter States</title>
+      <tgroup cols="3">
+	&cs-def;
+	<tbody valign="top">
+	  <row>
+	    <entry><constant>CEC_STATE_DISABLED</constant></entry>
+	    <entry>0</entry>
+	    <entry>The adapter is disabled.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>CEC_STATE_ENABLED</constant></entry>
+	    <entry>1</entry>
+	    <entry>The adapter is enabled.</entry>
+	  </row>
+	</tbody>
+      </tgroup>
+    </table>
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+  </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/media/v4l/cec-ioc-g-caps.xml b/Documentation/DocBook/media/v4l/cec-ioc-g-caps.xml
new file mode 100644
index 0000000..63b7ef5
--- /dev/null
+++ b/Documentation/DocBook/media/v4l/cec-ioc-g-caps.xml
@@ -0,0 +1,173 @@
+<refentry id="cec-ioc-g-caps">
+  <refmeta>
+    <refentrytitle>ioctl CEC_G_CAPS</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>CEC_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_G_CAPS</para>
+	</listitem>
+      </varlistentry>
+      <varlistentry>
+	<term><parameter>argp</parameter></term>
+	<listitem>
+	  <para></para>
+	</listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para>All cec devices must support the <constant>CEC_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>__u32</entry>
+	    <entry><structfield>available_log_addrs</structfield></entry>
+	    <entry>How many logical addresses does the CEC adapter support. This will
+	    be at most <constant>CEC_MAX_LOG_ADDRS</constant>.</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>vendor_id</structfield></entry>
+	    <entry>The CEC vendor ID.</entry>
+	  </row>
+	  <row>
+	    <entry>__u8</entry>
+	    <entry><structfield>version</structfield></entry>
+	    <entry>The CEC version supported by this device, see
+	    <xref linkend="cec-versions" />.</entry>
+	  </row>
+	  <row>
+	    <entry>__u8</entry>
+	    <entry><structfield>reserved</structfield>[35]</entry>
+	    <entry>Reserved for future extensions. Drivers must
+	    set this array to zero.</entry>
+	  </row>
+	</tbody>
+      </tgroup>
+    </table>
+
+    <table pgwide="1" frame="none" id="cec-versions">
+      <title>CEC Versions</title>
+      <tgroup cols="3">
+	&cs-def;
+	<tbody valign="top">
+	  <row>
+	    <entry><constant>CEC_VERSION_1_3A</constant></entry>
+	    <entry>4</entry>
+	    <entry>CEC version according to the HDMI 1.3a standard.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>CEC_VERSION_1_4B</constant></entry>
+	    <entry>5</entry>
+	    <entry>CEC version according to the HDMI 1.4b standard.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>CEC_VERSION_2_0</constant></entry>
+	    <entry>6</entry>
+	    <entry>CEC version according to the HDMI 2.0 standard.</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_STATE</constant></entry>
+	    <entry>0x00000001</entry>
+	    <entry>Userspace has to configure the adapter state (enable or disable it) by
+	    calling &CEC-S-ADAP-STATE;.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>CEC_CAP_PHYS_ADDR</constant></entry>
+	    <entry>0x00000002</entry>
+	    <entry>Userspace has to configure the physical address by
+	    calling &CEC-S-ADAP-PHYS-ADDR;.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>CEC_CAP_LOG_ADDRS</constant></entry>
+	    <entry>0x00000004</entry>
+	    <entry>Userspace has to configure the logical addresses by
+	    calling &CEC-S-ADAP-LOG-ADDRS;.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>CEC_CAP_TRANSMIT</constant></entry>
+	    <entry>0x00000008</entry>
+	    <entry>Userspace can transmit messages by calling &CEC-TRANSMIT;.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>CEC_CAP_RECEIVE</constant></entry>
+	    <entry>0x00000010</entry>
+	    <entry>Userspace can receive messages by calling &CEC-RECEIVE;.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>CEC_CAP_VENDOR_ID</constant></entry>
+	    <entry>0x00000020</entry>
+	    <entry>Userspace has to configure the vendor ID by
+	    calling &CEC-S-VENDOR-ID;.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>CEC_CAP_PASSTHROUGH</constant></entry>
+	    <entry>0x00000040</entry>
+	    <entry>Userspace can use the passthrough mode by
+	    calling &CEC-S-PASSTHROUGH;.</entry>
+	  </row>
+	</tbody>
+      </tgroup>
+    </table>
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+  </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/media/v4l/cec-ioc-g-event.xml b/Documentation/DocBook/media/v4l/cec-ioc-g-event.xml
new file mode 100644
index 0000000..cbde320
--- /dev/null
+++ b/Documentation/DocBook/media/v4l/cec-ioc-g-event.xml
@@ -0,0 +1,125 @@
+<refentry id="cec-ioc-g-event">
+  <refmeta>
+    <refentrytitle>ioctl CEC_G_EVENT</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>CEC_G_EVENT</refname>
+    <refpurpose>Get 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_G_EVENT</para>
+	</listitem>
+      </varlistentry>
+      <varlistentry>
+	<term><parameter>argp</parameter></term>
+	<listitem>
+	  <para></para>
+	</listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para>CEC devices can send asynchronous events. These can be retrieved by calling
+    the <constant>CEC_G_EVENT</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>There can be up to 40 events queued up. If more events are added, then the oldest event will be discarded.</para>
+
+    <table pgwide="1" frame="none" id="cec-event">
+      <title>struct <structname>cec_event</structname></title>
+      <tgroup cols="3">
+	&cs-str;
+	<tbody valign="top">
+	  <row>
+	    <entry>__u64</entry>
+	    <entry><structfield>ts</structfield></entry>
+	    <entry>Timestamp of the event in ns.</entry>
+	  </row>
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>event</structfield></entry>
+	    <entry>The event, see <xref linkend="cec-events" />.</entry>
+	  </row>
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>sequence</structfield></entry>
+	    <entry>For the <constant>CEC_EVENT_GOT_REPLY</constant> event this
+	    holds the sequence number of message that requested the reply.
+	    </entry>
+	  </row>
+	  <row>
+	    <entry>__u8</entry>
+	    <entry><structfield>reserved</structfield>[8]</entry>
+	    <entry>Reserved for future extensions. Drivers must
+	    set this array to zero.</entry>
+	  </row>
+	</tbody>
+      </tgroup>
+    </table>
+
+    <table pgwide="1" frame="none" id="cec-events">
+      <title>CEC Events</title>
+      <tgroup cols="3">
+	&cs-def;
+	<tbody valign="top">
+	  <row>
+	    <entry><constant>CEC_EVENT_CONNECT</constant></entry>
+	    <entry>1</entry>
+	    <entry>Generated when the HDMI cable is connected.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>CEC_EVENT_READY</constant></entry>
+	    <entry>2</entry>
+	    <entry>Generated when all logical addresses are claimed.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>CEC_EVENT_DISCONNECT</constant></entry>
+	    <entry>3</entry>
+	    <entry>Generated when the HDMI cable is disconnected.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>CEC_EVENT_GOT_REPLY</constant></entry>
+	    <entry>4</entry>
+	    <entry>Generated when a reply is received for a previously sent
+	    message. Generated only if a reply was requested and only if the
+	    message was sent in non-blocking mode.</entry>
+	  </row>
+	</tbody>
+      </tgroup>
+    </table>
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+  </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/media/v4l/cec-ioc-g-passthrough.xml b/Documentation/DocBook/media/v4l/cec-ioc-g-passthrough.xml
new file mode 100644
index 0000000..aa8cb51
--- /dev/null
+++ b/Documentation/DocBook/media/v4l/cec-ioc-g-passthrough.xml
@@ -0,0 +1,88 @@
+<refentry id="cec-ioc-g-passthrough">
+  <refmeta>
+    <refentrytitle>ioctl CEC_G_PASSTHROUGH, CEC_S_PASSTHROUGH</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>CEC_G_PASSTHROUGH</refname>
+    <refname>CEC_S_PASSTHROUGH</refname>
+    <refpurpose>Get or set the passthrough mode</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+	<funcdef>int <function>ioctl</function></funcdef>
+	<paramdef>int <parameter>fd</parameter></paramdef>
+	<paramdef>int <parameter>request</parameter></paramdef>
+	<paramdef>__u32 *<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_G_PASSTHROUGH, CEC_S_PASSTHROUGH</para>
+	</listitem>
+      </varlistentry>
+      <varlistentry>
+	<term><parameter>argp</parameter></term>
+	<listitem>
+	  <para></para>
+	</listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para>To query the current state of the passhrough mode the applications
+    call the <constant>CEC_G_PASSTHROUGH</constant> ioctl with a pointer to an
+    __u32 where the driver stores the state.</para>
+
+    <para>To set the state of the passthrough mode applications store the
+    passthrough mode state in an __u32 and call the <constant>CEC_S_PASSTHROUGH
+    </constant> ioctl with a pointer to this integer.
+    <constant>CEC_S_PASSTHROUGH</constant> is only available if
+    <constant>CEC_CAP_PASSTHROUGH</constant> is set.</para>
+
+    <para>Available states are:</para>
+
+    <table pgwide="1" frame="none" id="cec-adap-states">
+      <title>Adapter States</title>
+      <tgroup cols="3">
+	&cs-def;
+	<tbody valign="top">
+	  <row>
+	    <entry><constant>CEC_PASSTHROUGH_DISABLED</constant></entry>
+	    <entry>0</entry>
+	    <entry>The passthrough mode is disabled.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>CEC_PASSTHROUGH_ENABLED</constant></entry>
+	    <entry>1</entry>
+	    <entry>The passthrough is enabled.</entry>
+	  </row>
+	</tbody>
+      </tgroup>
+    </table>
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+  </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/media/v4l/cec-ioc-g-vendor-id.xml b/Documentation/DocBook/media/v4l/cec-ioc-g-vendor-id.xml
new file mode 100644
index 0000000..642e6b5
--- /dev/null
+++ b/Documentation/DocBook/media/v4l/cec-ioc-g-vendor-id.xml
@@ -0,0 +1,70 @@
+<refentry id="cec-ioc-g-vendor-id">
+  <refmeta>
+    <refentrytitle>ioctl CEC_G_VENDOR_ID, CEC_S_VENDOR_ID</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>CEC_G_VENDOR_ID</refname>
+    <refname>CEC_S_VENDOR_ID</refname>
+    <refpurpose>Get or set vendor ID</refpurpose>
+  </refnamediv>
+
+  <refsynopsisdiv>
+    <funcsynopsis>
+      <funcprototype>
+	<funcdef>int <function>ioctl</function></funcdef>
+	<paramdef>int <parameter>fd</parameter></paramdef>
+	<paramdef>int <parameter>request</parameter></paramdef>
+	<paramdef>__u32 *<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_G_VENDOR_ID, CEC_S_VENDOR_ID</para>
+	</listitem>
+      </varlistentry>
+      <varlistentry>
+	<term><parameter>argp</parameter></term>
+	<listitem>
+	  <para></para>
+	</listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para>To query the current CEC vendor ID applications call the
+<constant>CEC_G_VENDOR_ID</constant> ioctl with a pointer to an __u32
+where the driver stores the vendor ID.</para>
+
+    <para>To set a new vendor ID applications store the vendor ID in
+an __u32 and call the <constant>CEC_S_VENDOR_ID</constant> ioctl with a
+pointer to this integer. <constant>CEC_S_VENDOR_ID</constant> is only
+available if <constant>CEC_CAP_VENDOR_ID</constant> is set.</para>
+
+    <para>The vendor ID is a 24-bit number that identifies the specific
+vendor or entity. Based on this ID vendor specific commands may be
+defined.</para>
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+  </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/media/v4l/cec-ioc-receive.xml b/Documentation/DocBook/media/v4l/cec-ioc-receive.xml
new file mode 100644
index 0000000..dbec20a
--- /dev/null
+++ b/Documentation/DocBook/media/v4l/cec-ioc-receive.xml
@@ -0,0 +1,185 @@
+<refentry id="cec-ioc-receive">
+  <refmeta>
+    <refentrytitle>ioctl CEC_RECEIVE, CEC_TRANSMIT</refentrytitle>
+    &manvol;
+  </refmeta>
+
+  <refnamediv>
+    <refname>CEC_RECEIVE</refname>
+    <refname>CEC_TRANSMIT</refname>
+    <refpurpose>Receive or transmit a CEC message</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_msg *<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_RECEIVE, CEC_TRANSMIT</para>
+	</listitem>
+      </varlistentry>
+      <varlistentry>
+	<term><parameter>argp</parameter></term>
+	<listitem>
+	  <para></para>
+	</listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect1>
+
+  <refsect1>
+    <title>Description</title>
+
+    <para>To receive a CEC message the application has to fill in the
+    <structname>cec_msg</structname> structure and pass it to the
+    <constant>CEC_RECEIVE</constant> ioctl. <constant>CEC_RECEIVE</constant> is
+    only available if <constant>CEC_CAP_RECEIVE</constant> is set. If the
+    file descriptor is in non-blocking mode and there are no received
+    messages pending, then it will return -1 and set errno to the &EAGAIN;.
+    If the file descriptor is in blocking mode and <structfield>timeout</structfield>
+    is non-zero and no message arrived within <structfield>timeout</structfield>
+    milliseconds, then it will return -1 and set errno to the &ETIMEDOUT;.</para>
+
+    <para>To send a CEC message the application has to fill in the
+    <structname>cec_msg</structname> structure and pass it to the
+    <constant>CEC_TRANSMIT</constant> ioctl. <constant>CEC_TRANSMIT</constant> is
+    only available if <constant>CEC_CAP_TRANSMIT</constant> is set.
+    If there is no more room in the transmit queue, then it will return
+    -1 and set errno to the &EBUSY;.</para>
+
+    <table pgwide="1" frame="none" id="cec-msg">
+      <title>struct <structname>cec_msg</structname></title>
+      <tgroup cols="3">
+	&cs-str;
+	<tbody valign="top">
+	  <row>
+	    <entry>__u64</entry>
+	    <entry><structfield>ts</structfield></entry>
+	    <entry>Timestamp of when the message was transmitted in ns in the case
+	    of <constant>CEC_TRANSMIT</constant> with <structfield>reply</structfield>
+	    set to 0, or the timestamp of the received message in all other cases.</entry>
+	  </row>
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>len</structfield></entry>
+	    <entry>The length of the message. For <constant>CEC_TRANSMIT</constant> this
+	    is filled in by the application. The driver will fill this in for
+	    <constant>CEC_RECEIVE</constant> and for <constant>CEC_TRANSMIT</constant>
+	    it will be filled in with the length of the reply message if
+	    <structfield>reply</structfield> was set.</entry>
+	  </row>
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>status</structfield></entry>
+	    <entry>The status of the message. When used with <constant>CEC_RECEIVE</constant>
+	    this is always set to <constant>CEC_RX_STATUS_READY</constant>. When
+	    used with <constant>CEC_TRANSMIT</constant> see <xref linkend="cec-tx-status" />
+	    for the possible status values.</entry>
+	  </row>
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>timeout</structfield></entry>
+	    <entry>The timeout in milliseconds. This is the time we wait for a message to
+	    be received. If it is set to 0, then we wait indefinitely.
+	    It is ignored by <constant>CEC_TRANSMIT</constant>.</entry>
+	  </row>
+	  <row>
+	    <entry>__u8</entry>
+	    <entry><structfield>msg</structfield>[16]</entry>
+	    <entry>The message payload. For <constant>CEC_TRANSMIT</constant> this
+	    is filled in by the application. The driver will fill this in for
+	    <constant>CEC_RECEIVE</constant> and for <constant>CEC_TRANSMIT</constant>
+	    it will be filled in with the payload of the reply message if
+	    <structfield>reply</structfield> was set.</entry>
+	  </row>
+	  <row>
+	    <entry>__u8</entry>
+	    <entry><structfield>reply</structfield></entry>
+	    <entry>Wait until this message is replied. If <structfield>reply</structfield>
+	    is 0, then don't wait for a reply but return after transmitting the
+	    message. If there was an error as indicated by a non-zero <structfield>status</structfield>
+	    field, then <structfield>reply</structfield> is set to 0 by the driver.
+	    Ignored by <constant>CEC_RECEIVE</constant>.</entry>
+	  </row>
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>sequence</structfield></entry>
+	    <entry>The sequence number is automatically assigned by the CEC
+	    framework for all transmitted messages. It can be later used by the
+	    framework to generate an event if a reply for a message was
+	    requested and the message was transmitted in a non-blocking mode.
+	    </entry>
+	  </row>
+	  <row>
+	    <entry>__u8</entry>
+	    <entry><structfield>reserved</structfield>[35]</entry>
+	    <entry>Reserved for future extensions. Drivers and applications must
+	    set this array to zero.</entry>
+	  </row>
+	</tbody>
+      </tgroup>
+    </table>
+
+    <table pgwide="1" frame="none" id="cec-tx-status">
+      <title>CEC Transmit Status</title>
+      <tgroup cols="3">
+	&cs-def;
+	<tbody valign="top">
+	  <row>
+	    <entry><constant>CEC_TX_STATUS_OK</constant></entry>
+	    <entry>0x00</entry>
+	    <entry>The message was transmitted successfully.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>CEC_TX_STATUS_ARB_LOST</constant></entry>
+	    <entry>0x01</entry>
+	    <entry>CEC line arbitration was lost.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>CEC_TX_STATUS_RETRY_TIMEOUT</constant></entry>
+	    <entry>0x02</entry>
+	    <entry>The transmit timed out. The timeout period is 200 ms for a polling
+	    message and 1 second for other messages as specified by the CEC protocol.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>CEC_TX_STATUS_FEATURE_ABORT</constant></entry>
+	    <entry>0x04</entry>
+	    <entry>The message was transmitted successfully but the reply was
+	    <constant>CEC_OP_FEATURE_ABORT</constant>.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>CEC_TX_STATUS_REPLY_TIMEOUT</constant></entry>
+	    <entry>0x08</entry>
+	    <entry>The message was transmitted successfully but the reply was never
+	    received within the 1 second timeout period (this timeout value is
+	    specified by the CEC protocol).</entry>
+	  </row>
+	</tbody>
+      </tgroup>
+    </table>
+  </refsect1>
+
+  <refsect1>
+    &return-value;
+  </refsect1>
+</refentry>
diff --git a/Documentation/DocBook/media_api.tmpl b/Documentation/DocBook/media_api.tmpl
index 03f9a1f..ebddc3f 100644
--- a/Documentation/DocBook/media_api.tmpl
+++ b/Documentation/DocBook/media_api.tmpl
@@ -37,7 +37,7 @@
 	<title>LINUX MEDIA INFRASTRUCTURE API</title>
 
 	<copyright>
-		<year>2009-2014</year>
+		<year>2009-2015</year>
 		<holder>LinuxTV Developers</holder>
 	</copyright>
 
@@ -60,7 +60,7 @@
 		analog and digital TV receiver cards, AM/FM receiver cards,
 		streaming capture and output devices, codec devices and remote
 		controllers.</para>
-	<para>It is divided into four parts.</para>
+	<para>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
@@ -71,6 +71,7 @@
 		to document support also for DVB-S2, ISDB-T and ISDB-S.</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>For additional information and for the latest development code,
 		see: <ulink url="http://linuxtv.org">http://linuxtv.org</ulink>.</para>
 	<para>For discussing improvements, reporting troubles, sending new drivers, etc, please mail to: <ulink url="http://vger.kernel.org/vger-lists.html#linux-media">Linux Media Mailing List (LMML).</ulink>.</para>
@@ -80,6 +81,7 @@
 <part id="dvbapi">&sub-dvbapi;</part>
 <part id="remotes">&sub-remote_controllers;</part>
 <part id="media_common">&sub-media-controller;</part>
+<part id="cec">&sub-cec-api;</part>
 
 <chapter id="gen_errors">&sub-gen-errors;</chapter>
 
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH v6 08/11] v4l2-subdev: add HDMI CEC ops
  2015-05-04 17:32 [PATCH v6 00/11] Kamil Debski
                   ` (6 preceding siblings ...)
  2015-05-04 17:33 ` [PATCH v6 07/11] DocBook/media: add CEC documentation Kamil Debski
@ 2015-05-04 17:33 ` Kamil Debski
  2015-05-04 17:33 ` [PATCH v6 09/11] cec: adv7604: add cec support Kamil Debski
                   ` (5 subsequent siblings)
  13 siblings, 0 replies; 30+ messages in thread
From: Kamil Debski @ 2015-05-04 17:33 UTC (permalink / raw)
  To: dri-devel, linux-media
  Cc: m.szyprowski, k.debski, mchehab, hverkuil, kyungmin.park, thomas,
	sean, dmitry.torokhov, linux-input, linux-samsung-soc, lars,
	Hans Verkuil

From: Hans Verkuil <hansverk@cisco.com>

Add callbacks to the v4l2_subdev_video_ops.

Signed-off-by: Hans Verkuil <hansverk@cisco.com>
[k.debski@samsung.com: Merged changes from CEC Updates commit by Hans Verkuil]
Signed-off-by: Kamil Debski <k.debski@samsung.com>
---
 include/media/v4l2-subdev.h |    8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
index 2f0a345..9323e10 100644
--- a/include/media/v4l2-subdev.h
+++ b/include/media/v4l2-subdev.h
@@ -40,6 +40,9 @@
 #define V4L2_SUBDEV_IR_TX_NOTIFY		_IOW('v', 1, u32)
 #define V4L2_SUBDEV_IR_TX_FIFO_SERVICE_REQ	0x00000001
 
+#define V4L2_SUBDEV_CEC_TX_DONE			_IOW('v', 2, u32)
+#define V4L2_SUBDEV_CEC_RX_MSG			_IOW('v', 3, struct cec_msg)
+
 struct v4l2_device;
 struct v4l2_ctrl_handler;
 struct v4l2_event_subscription;
@@ -48,6 +51,7 @@ struct v4l2_subdev;
 struct v4l2_subdev_fh;
 struct tuner_setup;
 struct v4l2_mbus_frame_desc;
+struct cec_msg;
 
 /* decode_vbi_line */
 struct v4l2_decode_vbi_line {
@@ -352,6 +356,10 @@ struct v4l2_subdev_video_ops {
 			     const struct v4l2_mbus_config *cfg);
 	int (*s_rx_buffer)(struct v4l2_subdev *sd, void *buf,
 			   unsigned int *size);
+	int (*cec_enable)(struct v4l2_subdev *sd, bool enable);
+	int (*cec_log_addr)(struct v4l2_subdev *sd, u8 logical_addr);
+	int (*cec_transmit)(struct v4l2_subdev *sd, struct cec_msg *msg);
+	void (*cec_transmit_timed_out)(struct v4l2_subdev *sd);
 };
 
 /*
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH v6 09/11] cec: adv7604: add cec support.
  2015-05-04 17:32 [PATCH v6 00/11] Kamil Debski
                   ` (7 preceding siblings ...)
  2015-05-04 17:33 ` [PATCH v6 08/11] v4l2-subdev: add HDMI CEC ops Kamil Debski
@ 2015-05-04 17:33 ` Kamil Debski
  2015-05-04 17:33 ` [PATCH v6 10/11] cec: adv7511: " Kamil Debski
                   ` (4 subsequent siblings)
  13 siblings, 0 replies; 30+ messages in thread
From: Kamil Debski @ 2015-05-04 17:33 UTC (permalink / raw)
  To: dri-devel, linux-media
  Cc: m.szyprowski, k.debski, mchehab, hverkuil, kyungmin.park, thomas,
	sean, dmitry.torokhov, linux-input, linux-samsung-soc, lars,
	Hans Verkuil

From: Hans Verkuil <hansverk@cisco.com>

Add CEC support to the adv7604 driver.

Signed-off-by: Hans Verkuil <hansverk@cisco.com>
[k.debski@samsung.com: Merged changes from CEC Updates commit by Hans Verkuil]
[k.debski@samsung.com: add missing methods cec/io_write_and_or]
[k.debski@samsung.com: change adv7604 to adv76xx in added functions]
Signed-off-by: Kamil Debski <k.debski@samsung.com>
---
 drivers/media/i2c/adv7604.c |  207 ++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 206 insertions(+), 1 deletion(-)

diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c
index 60ffcf0..4921276 100644
--- a/drivers/media/i2c/adv7604.c
+++ b/drivers/media/i2c/adv7604.c
@@ -38,6 +38,7 @@
 #include <linux/workqueue.h>
 
 #include <media/adv7604.h>
+#include <media/cec.h>
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-dv-timings.h>
@@ -77,6 +78,8 @@ MODULE_LICENSE("GPL");
 
 #define ADV76XX_OP_SWAP_CB_CR				(1 << 0)
 
+#define ADV76XX_MAX_ADDRS (3)
+
 enum adv76xx_type {
 	ADV7604,
 	ADV7611,
@@ -159,6 +162,10 @@ struct adv76xx_state {
 	u16 spa_port_a[2];
 	struct v4l2_fract aspect_ratio;
 	u32 rgb_quantization_range;
+	u8   cec_addr[ADV76XX_MAX_ADDRS];
+	u8   cec_valid_addrs;
+	bool cec_enabled_adap;
+
 	struct workqueue_struct *work_queues;
 	struct delayed_work delayed_work_enable_hotplug;
 	bool restart_stdi_once;
@@ -424,7 +431,15 @@ static inline int io_write(struct v4l2_subdev *sd, u8 reg, u8 val)
 	return adv_smbus_write_byte_data(state, ADV76XX_PAGE_IO, reg, val);
 }
 
-static inline int io_write_clr_set(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val)
+static inline int io_write_and_or(struct v4l2_subdev *sd, u8 reg, u8 mask,
+				  u8 val)
+{
+	return io_write(sd, reg, (io_read(sd, reg) & mask) | val);
+}
+
+
+static inline int io_write_clr_set(struct v4l2_subdev *sd, u8 reg, u8 mask,
+				   u8 val)
 {
 	return io_write(sd, reg, (io_read(sd, reg) & ~mask) | val);
 }
@@ -457,6 +472,12 @@ static inline int cec_write(struct v4l2_subdev *sd, u8 reg, u8 val)
 	return adv_smbus_write_byte_data(state, ADV76XX_PAGE_CEC, reg, val);
 }
 
+static inline int cec_write_and_or(struct v4l2_subdev *sd, u8 reg, u8 mask,
+				   u8 val)
+{
+	return cec_write(sd, reg, (cec_read(sd, reg) & mask) | val);
+}
+
 static inline int infoframe_read(struct v4l2_subdev *sd, u8 reg)
 {
 	struct adv76xx_state *state = to_state(sd);
@@ -1865,6 +1886,183 @@ static int adv76xx_set_format(struct v4l2_subdev *sd,
 	return 0;
 }
 
+static void adv76xx_cec_tx_raw_status(struct v4l2_subdev *sd, u8 tx_raw_status)
+{
+	if ((cec_read(sd, 0x11) & 0x01) == 0) {
+		v4l2_dbg(1, debug, sd, "%s: tx raw: tx disabled\n", __func__);
+		return;
+	}
+
+	if (tx_raw_status & 0x02) {
+		v4l2_dbg(1, debug, sd, "%s: tx raw: arbitration lost\n",
+			 __func__);
+		v4l2_subdev_notify(sd, V4L2_SUBDEV_CEC_TX_DONE,
+				   (void *)CEC_TX_STATUS_ARB_LOST);
+		return;
+	}
+	if (tx_raw_status & 0x04) {
+		v4l2_dbg(1, debug, sd, "%s: tx raw: retry failed\n", __func__);
+		v4l2_subdev_notify(sd, V4L2_SUBDEV_CEC_TX_DONE,
+				   (void *)CEC_TX_STATUS_RETRY_TIMEOUT);
+		return;
+	}
+	if (tx_raw_status & 0x01) {
+		v4l2_dbg(1, debug, sd, "%s: tx raw: ready ok\n", __func__);
+		v4l2_subdev_notify(sd, V4L2_SUBDEV_CEC_TX_DONE,
+				   (void *)CEC_TX_STATUS_OK);
+		return;
+	}
+}
+
+static void adv76xx_cec_isr(struct v4l2_subdev *sd, bool *handled)
+{
+	struct cec_msg msg;
+	u8 cec_irq;
+
+	/* cec controller */
+	cec_irq = io_read(sd, 0x4d) & 0x0f;
+	if (!cec_irq)
+		return;
+
+	v4l2_dbg(1, debug, sd, "%s: cec: irq 0x%x\n", __func__, cec_irq);
+	adv76xx_cec_tx_raw_status(sd, cec_irq);
+	if (cec_irq & 0x08) {
+		msg.len = cec_read(sd, 0x25) & 0x1f;
+		if (msg.len > 16)
+			msg.len = 16;
+
+		if (msg.len) {
+			u8 i;
+
+			for (i = 0; i < msg.len; i++)
+				msg.msg[i] = cec_read(sd, i + 0x15);
+			cec_write(sd, 0x26, 0x01); /* re-enable rx */
+			v4l2_subdev_notify(sd, V4L2_SUBDEV_CEC_RX_MSG, &msg);
+		}
+	}
+
+	/* note: the bit order is swapped between 0x4d and 0x4e */
+	cec_irq = ((cec_irq & 0x08) >> 3) | ((cec_irq & 0x04) >> 1) |
+		  ((cec_irq & 0x02) << 1) | ((cec_irq & 0x01) << 3);
+	io_write(sd, 0x4e, cec_irq);
+
+	if (handled)
+		*handled = true;
+}
+
+static int adv76xx_cec_enable(struct v4l2_subdev *sd, bool enable)
+{
+	struct adv76xx_state *state = to_state(sd);
+
+	if (!state->cec_enabled_adap && enable) {
+		cec_write_and_or(sd, 0x2a, 0xfe, 0x01);	/* power up cec */
+		cec_write(sd, 0x2c, 0x01);	/* cec soft reset */
+		cec_write_and_or(sd, 0x11, 0xfe, 0);  /* initially disable tx */
+		/* enabled irqs: */
+		/* tx: ready */
+		/* tx: arbitration lost */
+		/* tx: retry timeout */
+		/* rx: ready */
+		io_write_and_or(sd, 0x50, 0xf0, 0x0f);
+		cec_write(sd, 0x26, 0x01);            /* enable rx */
+	} else if (state->cec_enabled_adap && !enable) {
+		/* disable cec interrupts */
+		io_write_and_or(sd, 0x50, 0xf0, 0x00);
+		/* disable address mask 1-3 */
+		cec_write_and_or(sd, 0x27, 0x8f, 0x70);
+		/* power down cec section */
+		cec_write_and_or(sd, 0x2a, 0xfe, 0x00);
+		state->cec_valid_addrs = 0;
+	}
+	state->cec_enabled_adap = enable;
+	return 0;
+}
+
+static int adv76xx_cec_log_addr(struct v4l2_subdev *sd, u8 addr)
+{
+	struct adv76xx_state *state = to_state(sd);
+	unsigned i, free_idx = ADV76XX_MAX_ADDRS;
+
+	if (!state->cec_enabled_adap)
+		return -EIO;
+
+	for (i = 0; i < ADV76XX_MAX_ADDRS; i++) {
+		bool is_valid = state->cec_valid_addrs & (1 << i);
+
+		if (free_idx == ADV76XX_MAX_ADDRS && !is_valid)
+			free_idx = i;
+		if (is_valid && state->cec_addr[i] == addr)
+			return 0;
+	}
+	if (i == ADV76XX_MAX_ADDRS) {
+		i = free_idx;
+		if (i == ADV76XX_MAX_ADDRS)
+			return -ENXIO;
+	}
+	state->cec_addr[i] = addr;
+	state->cec_valid_addrs |= 1 << i;
+
+	switch (i) {
+	case 0:
+		/* enable address mask 0 */
+		cec_write_and_or(sd, 0x27, 0xef, 0x10);
+		/* set address for mask 0 */
+		cec_write_and_or(sd, 0x28, 0xf0, addr);
+		break;
+	case 1:
+		/* enable address mask 1 */
+		cec_write_and_or(sd, 0x27, 0xdf, 0x20);
+		/* set address for mask 1 */
+		cec_write_and_or(sd, 0x28, 0x0f, addr << 4);
+		break;
+	case 2:
+		/* enable address mask 2 */
+		cec_write_and_or(sd, 0x27, 0xbf, 0x40);
+		/* set address for mask 1 */
+		cec_write_and_or(sd, 0x29, 0xf0, addr);
+		break;
+	}
+	return 0;
+}
+
+static int adv76xx_cec_transmit(struct v4l2_subdev *sd, struct cec_msg *msg)
+{
+	u8 len = msg->len;
+	unsigned i;
+
+	if (len == 1)
+		/* allow for one retry for polling */
+		cec_write_and_or(sd, 0x12, 0xf8, 1);
+	else
+		/* allow for three retries */
+		cec_write_and_or(sd, 0x12, 0xf8, 3);
+
+	if (len > 16) {
+		v4l2_err(sd, "%s: len exceeded 16 (%d)\n", __func__, len);
+		return -EINVAL;
+	}
+
+	/* write data */
+	for (i = 0; i < len; i++)
+		cec_write(sd, i, msg->msg[i]);
+
+	/* set length (data + header) */
+	cec_write(sd, 0x10, len);
+	/* start transmit, enable tx */
+	cec_write(sd, 0x11, 0x01);
+	/* For some reason sometimes the
+	 * transmit won't start.
+	 * Doing it twice seems to help ?
+	*/
+	cec_write(sd, 0x11, 0x01);
+	return 0;
+}
+
+static void adv76xx_cec_transmit_timed_out(struct v4l2_subdev *sd)
+{
+	cec_write_and_or(sd, 0x11, 0xfe, 0);  /* disable tx */
+}
+
 static int adv76xx_isr(struct v4l2_subdev *sd, u32 status, bool *handled)
 {
 	struct adv76xx_state *state = to_state(sd);
@@ -1910,6 +2108,9 @@ static int adv76xx_isr(struct v4l2_subdev *sd, u32 status, bool *handled)
 			*handled = true;
 	}
 
+	/* cec */
+	adv76xx_cec_isr(sd, handled);
+
 	/* tx 5v detect */
 	tx_5v = io_read(sd, 0x70) & info->cable_det_mask;
 	if (tx_5v) {
@@ -2304,6 +2505,10 @@ static const struct v4l2_subdev_video_ops adv76xx_video_ops = {
 	.s_dv_timings = adv76xx_s_dv_timings,
 	.g_dv_timings = adv76xx_g_dv_timings,
 	.query_dv_timings = adv76xx_query_dv_timings,
+	.cec_enable = adv76xx_cec_enable,
+	.cec_log_addr = adv76xx_cec_log_addr,
+	.cec_transmit = adv76xx_cec_transmit,
+	.cec_transmit_timed_out = adv76xx_cec_transmit_timed_out,
 };
 
 static const struct v4l2_subdev_pad_ops adv76xx_pad_ops = {
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH v6 10/11] cec: adv7511: add cec support.
  2015-05-04 17:32 [PATCH v6 00/11] Kamil Debski
                   ` (8 preceding siblings ...)
  2015-05-04 17:33 ` [PATCH v6 09/11] cec: adv7604: add cec support Kamil Debski
@ 2015-05-04 17:33 ` Kamil Debski
  2015-05-04 17:33 ` [PATCH v6 11/11] cec: s5p-cec: Add s5p-cec driver Kamil Debski
                   ` (3 subsequent siblings)
  13 siblings, 0 replies; 30+ messages in thread
From: Kamil Debski @ 2015-05-04 17:33 UTC (permalink / raw)
  To: dri-devel, linux-media
  Cc: m.szyprowski, k.debski, mchehab, hverkuil, kyungmin.park, thomas,
	sean, dmitry.torokhov, linux-input, linux-samsung-soc, lars,
	Hans Verkuil

From: Hans Verkuil <hansverk@cisco.com>

Add CEC support to the adv7511 driver.

Signed-off-by: Hans Verkuil <hansverk@cisco.com>
[k.debski@samsung.com: Merged changes from CEC Updates commit by Hans Verkuil]
Signed-off-by: Kamil Debski <k.debski@samsung.com>
---
 drivers/media/i2c/adv7511.c |  347 ++++++++++++++++++++++++++++++++++++++++++-
 include/media/adv7511.h     |    6 +-
 2 files changed, 343 insertions(+), 10 deletions(-)

diff --git a/drivers/media/i2c/adv7511.c b/drivers/media/i2c/adv7511.c
index 12d9320..d56e110 100644
--- a/drivers/media/i2c/adv7511.c
+++ b/drivers/media/i2c/adv7511.c
@@ -33,6 +33,7 @@
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-dv-timings.h>
 #include <media/adv7511.h>
+#include <media/cec.h>
 
 static int debug;
 module_param(debug, int, 0644);
@@ -91,6 +92,12 @@ struct adv7511_state {
 	int chip_revision;
 	uint8_t i2c_edid_addr;
 	uint8_t i2c_cec_addr;
+
+	struct i2c_client *i2c_cec;
+	u8   cec_addr[3];
+	u8   cec_valid_addrs;
+	bool cec_enabled_adap;
+
 	/* Is the adv7511 powered on? */
 	bool power_on;
 	/* Did we receive hotplug and rx-sense signals? */
@@ -222,7 +229,7 @@ static int adv_smbus_read_i2c_block_data(struct i2c_client *client,
 	return ret;
 }
 
-static inline void adv7511_edid_rd(struct v4l2_subdev *sd, uint16_t len, uint8_t *buf)
+static void adv7511_edid_rd(struct v4l2_subdev *sd, uint16_t len, uint8_t *buf)
 {
 	struct adv7511_state *state = get_adv7511_state(sd);
 	int i;
@@ -237,6 +244,34 @@ static inline void adv7511_edid_rd(struct v4l2_subdev *sd, uint16_t len, uint8_t
 		v4l2_err(sd, "%s: i2c read error\n", __func__);
 }
 
+static inline int cec_read(struct v4l2_subdev *sd, u8 reg)
+{
+	struct adv7511_state *state = get_adv7511_state(sd);
+
+	return i2c_smbus_read_byte_data(state->i2c_cec, reg);
+}
+
+static int cec_write(struct v4l2_subdev *sd, u8 reg, u8 val)
+{
+	struct adv7511_state *state = get_adv7511_state(sd);
+	int ret;
+	int i;
+
+	for (i = 0; i < 3; i++) {
+		ret = i2c_smbus_write_byte_data(state->i2c_cec, reg, val);
+		if (ret == 0)
+			return 0;
+	}
+	v4l2_err(sd, "%s: I2C Write Problem\n", __func__);
+	return ret;
+}
+
+static inline int cec_write_and_or(struct v4l2_subdev *sd, u8 reg, u8 mask,
+				   u8 val)
+{
+	return cec_write(sd, reg, (cec_read(sd, reg) & mask) | val);
+}
+
 static inline bool adv7511_have_hotplug(struct v4l2_subdev *sd)
 {
 	return adv7511_rd(sd, 0x42) & MASK_ADV7511_HPD_DETECT;
@@ -381,16 +416,28 @@ static const struct v4l2_ctrl_ops adv7511_ctrl_ops = {
 #ifdef CONFIG_VIDEO_ADV_DEBUG
 static void adv7511_inv_register(struct v4l2_subdev *sd)
 {
+	struct adv7511_state *state = get_adv7511_state(sd);
+
 	v4l2_info(sd, "0x000-0x0ff: Main Map\n");
+	if (state->i2c_cec)
+		v4l2_info(sd, "0x100-0x1ff: CEC Map\n");
 }
 
 static int adv7511_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
 {
+	struct adv7511_state *state = get_adv7511_state(sd);
+
 	reg->size = 1;
 	switch (reg->reg >> 8) {
 	case 0:
 		reg->val = adv7511_rd(sd, reg->reg & 0xff);
 		break;
+	case 1:
+		if (state->i2c_cec) {
+			reg->val = cec_read(sd, reg->reg & 0xff);
+			break;
+		}
+		/* fall through */
 	default:
 		v4l2_info(sd, "Register %03llx not supported\n", reg->reg);
 		adv7511_inv_register(sd);
@@ -401,10 +448,18 @@ static int adv7511_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *
 
 static int adv7511_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_register *reg)
 {
+	struct adv7511_state *state = get_adv7511_state(sd);
+
 	switch (reg->reg >> 8) {
 	case 0:
 		adv7511_wr(sd, reg->reg & 0xff, reg->val & 0xff);
 		break;
+	case 1:
+		if (state->i2c_cec) {
+			cec_write(sd, reg->reg & 0xff, reg->val & 0xff);
+			break;
+		}
+		/* fall through */
 	default:
 		v4l2_info(sd, "Register %03llx not supported\n", reg->reg);
 		adv7511_inv_register(sd);
@@ -418,6 +473,7 @@ static int adv7511_log_status(struct v4l2_subdev *sd)
 {
 	struct adv7511_state *state = get_adv7511_state(sd);
 	struct adv7511_state_edid *edid = &state->edid;
+	int i;
 
 	static const char * const states[] = {
 		"in reset",
@@ -486,7 +542,21 @@ static int adv7511_log_status(struct v4l2_subdev *sd)
 	else
 		v4l2_info(sd, "no timings set\n");
 	v4l2_info(sd, "i2c edid addr: 0x%x\n", state->i2c_edid_addr);
+
+	if (state->i2c_cec == NULL)
+		return 0;
+
 	v4l2_info(sd, "i2c cec addr: 0x%x\n", state->i2c_cec_addr);
+
+	if (cec_read(sd, 0x4e) & 0x01) {
+		v4l2_info(sd, "cec: enabled\n");
+		for (i = 0; i < 3; i++)
+			if (state->cec_valid_addrs & (1 << i))
+				v4l2_info(sd, "cec device %d: addr %d\n", i,
+					  state->cec_addr[i]);
+	} else {
+		v4l2_info(sd, "cec: disabled\n");
+	}
 	return 0;
 }
 
@@ -542,15 +612,136 @@ static int adv7511_s_power(struct v4l2_subdev *sd, int on)
 	return true;
 }
 
+static int adv7511_cec_enable(struct v4l2_subdev *sd, bool enable)
+{
+	struct adv7511_state *state = get_adv7511_state(sd);
+
+	if (!state->cec_enabled_adap && enable) {
+		/* power up cec section */
+		cec_write_and_or(sd, 0x4e, 0xfc, 0x01);
+		/* legacy mode and clear all rx buffers */
+		cec_write(sd, 0x4a, 0x07);
+		cec_write(sd, 0x4a, 0);
+		cec_write_and_or(sd, 0x11, 0xfe, 0); /* initially disable tx */
+		/* enabled irqs: */
+		/* tx: ready */
+		/* tx: arbitration lost */
+		/* tx: retry timeout */
+		/* rx: ready 1 */
+		adv7511_wr_and_or(sd, 0x95, 0xc0, 0x39);
+	} else if (state->cec_enabled_adap && !enable) {
+		adv7511_wr_and_or(sd, 0x95, 0xc0, 0x00);
+		/* disable address mask 1-3 */
+		cec_write_and_or(sd, 0x4b, 0x8f, 0x00);
+		/* power down cec section */
+		cec_write_and_or(sd, 0x4e, 0xfc, 0x00);
+		state->cec_valid_addrs = 0;
+	}
+	state->cec_enabled_adap = enable;
+	return 0;
+}
+
+#define ADV7511_MAX_ADDRS 3
+
+static int adv7511_cec_log_addr(struct v4l2_subdev *sd, u8 addr)
+{
+	struct adv7511_state *state = get_adv7511_state(sd);
+	unsigned i, free_idx = ADV7511_MAX_ADDRS;
+
+	if (!state->cec_enabled_adap)
+		return -EIO;
+
+	for (i = 0; i < ADV7511_MAX_ADDRS; i++) {
+		bool is_valid = state->cec_valid_addrs & (1 << i);
+
+		if (free_idx == ADV7511_MAX_ADDRS && !is_valid)
+			free_idx = i;
+		if (is_valid && state->cec_addr[i] == addr)
+			return 0;
+	}
+	if (i == ADV7511_MAX_ADDRS) {
+		i = free_idx;
+		if (i == ADV7511_MAX_ADDRS)
+			return -ENXIO;
+	}
+	state->cec_addr[i] = addr;
+	state->cec_valid_addrs |= 1 << i;
+
+	switch (i) {
+	case 0:
+		/* enable address mask 0 */
+		cec_write_and_or(sd, 0x4b, 0xef, 0x10);
+		/* set address for mask 0 */
+		cec_write_and_or(sd, 0x4c, 0xf0, addr);
+		break;
+	case 1:
+		/* enable address mask 1 */
+		cec_write_and_or(sd, 0x4b, 0xdf, 0x20);
+		/* set address for mask 1 */
+		cec_write_and_or(sd, 0x4c, 0x0f, addr << 4);
+		break;
+	case 2:
+		/* enable address mask 2 */
+		cec_write_and_or(sd, 0x4b, 0xbf, 0x40);
+		/* set address for mask 1 */
+		cec_write_and_or(sd, 0x4d, 0xf0, addr);
+		break;
+	}
+	return 0;
+}
+
+static int adv7511_cec_transmit(struct v4l2_subdev *sd, struct cec_msg *msg)
+{
+	u8 len = msg->len;
+	unsigned i;
+
+	v4l2_dbg(1, debug, sd, "%s: len %d\n", __func__, len);
+
+	if (len > 16) {
+		v4l2_err(sd, "%s: len exceeded 16 (%d)\n", __func__, len);
+		return -EINVAL;
+	}
+
+	/* blocking, clear cec tx irq status */
+	adv7511_wr_and_or(sd, 0x97, 0xc7, 0x38);
+
+	/* write data */
+	for (i = 0; i < len; i++)
+		cec_write(sd, i, msg->msg[i]);
+
+	/* set length (data + header) */
+	cec_write(sd, 0x10, len);
+	/* start transmit, enable tx */
+	cec_write(sd, 0x11, 0x01);
+	return 0;
+}
+
+static void adv7511_cec_transmit_timed_out(struct v4l2_subdev *sd)
+{
+	cec_write_and_or(sd, 0x11, 0xfe, 0); /* disable tx */
+}
+
 /* Enable interrupts */
 static void adv7511_set_isr(struct v4l2_subdev *sd, bool enable)
 {
+	struct adv7511_state *state = get_adv7511_state(sd);
 	uint8_t irqs = MASK_ADV7511_HPD_INT | MASK_ADV7511_MSEN_INT;
 	uint8_t irqs_rd;
 	int retries = 100;
 
 	v4l2_dbg(2, debug, sd, "%s: %s\n", __func__, enable ? "enable" : "disable");
 
+	if (state->i2c_cec) {
+		/*
+		 * Enabled CEC irqs:
+		 * tx: ready
+		 * tx: arbitration lost
+		 * tx: retry timeout
+		 * rx: ready 1
+		 */
+		adv7511_wr_and_or(sd, 0x95, 0xc0, enable ? 0x39 : 0);
+	}
+
 	/* The datasheet says that the EDID ready interrupt should be
 	   disabled if there is no hotplug. */
 	if (!enable)
@@ -576,24 +767,82 @@ static void adv7511_set_isr(struct v4l2_subdev *sd, bool enable)
 	v4l2_err(sd, "Could not set interrupts: hw failure?\n");
 }
 
+static void adv_cec_tx_raw_status(struct v4l2_subdev *sd, u8 tx_raw_status)
+{
+	if ((cec_read(sd, 0x11) & 0x01) == 0) {
+		v4l2_dbg(1, debug, sd, "%s: tx raw: tx disabled\n", __func__);
+		return;
+	}
+
+	if (tx_raw_status & 0x10) {
+		v4l2_dbg(1, debug, sd,
+			 "%s: tx raw: arbitration lost\n", __func__);
+		v4l2_subdev_notify(sd, V4L2_SUBDEV_CEC_TX_DONE,
+				   (void *)CEC_TX_STATUS_ARB_LOST);
+		return;
+	}
+	if (tx_raw_status & 0x08) {
+		v4l2_dbg(1, debug, sd, "%s: tx raw: retry failed\n", __func__);
+		v4l2_subdev_notify(sd, V4L2_SUBDEV_CEC_TX_DONE,
+				   (void *)CEC_TX_STATUS_RETRY_TIMEOUT);
+		return;
+	}
+	if (tx_raw_status & 0x20) {
+		v4l2_dbg(1, debug, sd, "%s: tx raw: ready ok\n", __func__);
+		v4l2_subdev_notify(sd, V4L2_SUBDEV_CEC_TX_DONE,
+				   (void *)CEC_TX_STATUS_OK);
+		return;
+	}
+}
+
 /* Interrupt handler */
 static int adv7511_isr(struct v4l2_subdev *sd, u32 status, bool *handled)
 {
 	uint8_t irq_status;
+	uint8_t cec_irq;
 
 	/* disable interrupts to prevent a race condition */
 	adv7511_set_isr(sd, false);
 	irq_status = adv7511_rd(sd, 0x96);
+	cec_irq = adv7511_rd(sd, 0x97);
 	/* clear detected interrupts */
 	adv7511_wr(sd, 0x96, irq_status);
+	adv7511_wr(sd, 0x97, cec_irq);
 
-	v4l2_dbg(1, debug, sd, "%s: irq 0x%x\n", __func__, irq_status);
+	v4l2_dbg(1, debug, sd, "%s: irq 0x%x, cec-irq 0x%x\n", __func__,
+		 irq_status, cec_irq);
 
 	if (irq_status & (MASK_ADV7511_HPD_INT | MASK_ADV7511_MSEN_INT))
 		adv7511_check_monitor_present_status(sd);
 	if (irq_status & MASK_ADV7511_EDID_RDY_INT)
 		adv7511_check_edid_status(sd);
 
+	if (cec_irq & 0x38)
+		adv_cec_tx_raw_status(sd, cec_irq);
+
+	if (cec_irq & 1) {
+		struct cec_msg msg;
+
+		msg.len = cec_read(sd, 0x25) & 0x1f;
+
+		v4l2_dbg(1, debug, sd, "%s: cec msg len %d\n", __func__,
+			 msg.len);
+
+		if (msg.len > 16)
+			msg.len = 16;
+
+		if (msg.len) {
+			u8 i;
+
+			for (i = 0; i < msg.len; i++)
+				msg.msg[i] = cec_read(sd, i + 0x15);
+
+			cec_write(sd, 0x4a, 1); /* toggle to re-enable rx 1 */
+			cec_write(sd, 0x4a, 0);
+			v4l2_subdev_notify(sd, V4L2_SUBDEV_CEC_RX_MSG, &msg);
+		}
+	}
+
 	/* enable interrupts */
 	adv7511_set_isr(sd, true);
 
@@ -697,6 +946,10 @@ static const struct v4l2_subdev_video_ops adv7511_video_ops = {
 	.s_stream = adv7511_s_stream,
 	.s_dv_timings = adv7511_s_dv_timings,
 	.g_dv_timings = adv7511_g_dv_timings,
+	.cec_enable = adv7511_cec_enable,
+	.cec_log_addr = adv7511_cec_log_addr,
+	.cec_transmit = adv7511_cec_transmit,
+	.cec_transmit_timed_out = adv7511_cec_transmit_timed_out,
 };
 
 /* ------------------------------ AUDIO OPS ------------------------------ */
@@ -1080,6 +1333,7 @@ static void adv7511_edid_handler(struct work_struct *work)
 	/* We failed to read the EDID, so send an event for this. */
 	ed.present = false;
 	ed.segment = adv7511_rd(sd, 0xc4);
+	ed.phys_addr = 0xffff;
 	v4l2_subdev_notify(sd, ADV7511_EDID_DETECT, (void *)&ed);
 	v4l2_dbg(1, debug, sd, "%s: no edid found\n", __func__);
 }
@@ -1220,10 +1474,39 @@ static bool edid_verify_header(struct v4l2_subdev *sd, u32 segment)
 	return !memcmp(data, hdmi_header, sizeof(hdmi_header));
 }
 
+static int get_edid_spa_location(const u8 *edid)
+{
+	u8 d;
+
+	if ((edid[0x7e] != 1) ||
+			(edid[0x80] != 0x02) ||
+			(edid[0x81] != 0x03)) {
+		return -1;
+	}
+
+	/* search Vendor Specific Data Block (tag 3) */
+	d = edid[0x82] & 0x7f;
+	if (d > 4) {
+		int i = 0x84;
+		int end = 0x80 + d;
+
+		do {
+			u8 tag = edid[i] >> 5;
+			u8 len = edid[i] & 0x1f;
+
+			if ((tag == 3) && (len >= 5))
+				return i + 4;
+			i += len + 1;
+		} while (i < end);
+	}
+	return -1;
+}
+
 static bool adv7511_check_edid_status(struct v4l2_subdev *sd)
 {
 	struct adv7511_state *state = get_adv7511_state(sd);
 	uint8_t edidRdy = adv7511_rd(sd, 0xc5);
+	int offset;
 
 	v4l2_dbg(1, debug, sd, "%s: edid ready (retries: %d)\n",
 			 __func__, EDID_MAX_RETRIES - state->edid.read_retries);
@@ -1269,6 +1552,12 @@ static bool adv7511_check_edid_status(struct v4l2_subdev *sd)
 
 		v4l2_dbg(1, debug, sd, "%s: edid complete with %d segment(s)\n", __func__, state->edid.segments);
 		state->edid.complete = true;
+		offset = get_edid_spa_location(state->edid.data);
+		if (offset > 0)
+			ed.phys_addr = (state->edid.data[offset] << 8) |
+					state->edid.data[offset + 1];
+		else
+			ed.phys_addr = 0xffff;
 
 		/* report when we have all segments
 		   but report only for segment 0
@@ -1290,11 +1579,14 @@ static void adv7511_init_setup(struct v4l2_subdev *sd)
 {
 	struct adv7511_state *state = get_adv7511_state(sd);
 	struct adv7511_state_edid *edid = &state->edid;
+	u32 cec_clk = state->pdata.cec_clk;
+	u8 ratio;
 
 	v4l2_dbg(1, debug, sd, "%s\n", __func__);
 
 	/* clear all interrupts */
 	adv7511_wr(sd, 0x96, 0xff);
+	adv7511_wr(sd, 0x97, 0xff);
 	/*
 	 * Stop HPD from resetting a lot of registers.
 	 * It might leave the chip in a partly un-initialized state,
@@ -1306,6 +1598,25 @@ static void adv7511_init_setup(struct v4l2_subdev *sd)
 	adv7511_set_isr(sd, false);
 	adv7511_s_stream(sd, false);
 	adv7511_s_audio_stream(sd, false);
+
+	if (state->i2c_cec == NULL)
+		return;
+
+	v4l2_dbg(1, debug, sd, "%s: cec_clk %d\n", __func__, cec_clk);
+
+	/* cec soft reset */
+	cec_write(sd, 0x50, 0x01);
+	cec_write(sd, 0x50, 0x00);
+
+	/* legacy mode */
+	cec_write(sd, 0x4a, 0x00);
+
+	if (cec_clk % 750000 != 0)
+		v4l2_err(sd, "%s: cec_clk %d, not multiple of 750 Khz\n",
+			 __func__, cec_clk);
+
+	ratio = (cec_clk / 750000) - 1;
+	cec_write(sd, 0x4e, ratio << 2);
 }
 
 static int adv7511_probe(struct i2c_client *client, const struct i2c_device_id *id)
@@ -1381,19 +1692,40 @@ static int adv7511_probe(struct i2c_client *client, const struct i2c_device_id *
 	chip_id[0] = adv7511_rd(sd, 0xf5);
 	chip_id[1] = adv7511_rd(sd, 0xf6);
 	if (chip_id[0] != 0x75 || chip_id[1] != 0x11) {
-		v4l2_err(sd, "chip_id != 0x7511, read 0x%02x%02x\n", chip_id[0], chip_id[1]);
+		v4l2_err(sd, "chip_id != 0x7511, read 0x%02x%02x\n", chip_id[0],
+			 chip_id[1]);
 		err = -EIO;
 		goto err_entity;
 	}
 
-	state->i2c_edid = i2c_new_dummy(client->adapter, state->i2c_edid_addr >> 1);
+	state->i2c_edid = i2c_new_dummy(client->adapter,
+					state->i2c_edid_addr >> 1);
 	if (state->i2c_edid == NULL) {
 		v4l2_err(sd, "failed to register edid i2c client\n");
 		err = -ENOMEM;
 		goto err_entity;
 	}
 
-	adv7511_wr(sd, 0xe2, 0x01); /* power down cec section */
+	adv7511_wr(sd, 0xe1, state->i2c_cec_addr);
+	if (state->pdata.cec_clk < 3000000 ||
+	    state->pdata.cec_clk > 100000000) {
+		v4l2_err(sd, "%s: cec_clk %u outside range, disabling cec\n",
+				__func__, state->pdata.cec_clk);
+		state->pdata.cec_clk = 0;
+	}
+
+	if (state->pdata.cec_clk) {
+		state->i2c_cec = i2c_new_dummy(client->adapter,
+					       (state->i2c_cec_addr>>1));
+		if (state->i2c_cec == NULL) {
+			v4l2_err(sd, "failed to register cec i2c client\n");
+			goto err_unreg_edid;
+		}
+		adv7511_wr(sd, 0xe2, 0x00); /* power up cec section */
+	} else {
+		adv7511_wr(sd, 0xe2, 0x01); /* power down cec section */
+	}
+
 	state->work_queue = create_singlethread_workqueue(sd->name);
 	if (state->work_queue == NULL) {
 		v4l2_err(sd, "could not create workqueue\n");
@@ -1412,6 +1744,9 @@ static int adv7511_probe(struct i2c_client *client, const struct i2c_device_id *
 	return 0;
 
 err_unreg_cec:
+	if (state->i2c_cec)
+		i2c_unregister_device(state->i2c_cec);
+err_unreg_edid:
 	i2c_unregister_device(state->i2c_edid);
 err_entity:
 	media_entity_cleanup(&sd->entity);
@@ -1435,6 +1770,8 @@ static int adv7511_remove(struct i2c_client *client)
 	adv7511_init_setup(sd);
 	cancel_delayed_work(&state->edid_handler);
 	i2c_unregister_device(state->i2c_edid);
+	if (state->i2c_cec)
+		i2c_unregister_device(state->i2c_cec);
 	destroy_workqueue(state->work_queue);
 	v4l2_device_unregister_subdev(sd);
 	media_entity_cleanup(&sd->entity);
diff --git a/include/media/adv7511.h b/include/media/adv7511.h
index bb78bed..c971b52 100644
--- a/include/media/adv7511.h
+++ b/include/media/adv7511.h
@@ -32,11 +32,7 @@ struct adv7511_monitor_detect {
 struct adv7511_edid_detect {
 	int present;
 	int segment;
-};
-
-struct adv7511_cec_arg {
-	void *arg;
-	u32 f_flags;
+	uint16_t phys_addr;
 };
 
 struct adv7511_platform_data {
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH v6 11/11] cec: s5p-cec: Add s5p-cec driver
  2015-05-04 17:32 [PATCH v6 00/11] Kamil Debski
                   ` (9 preceding siblings ...)
  2015-05-04 17:33 ` [PATCH v6 10/11] cec: adv7511: " Kamil Debski
@ 2015-05-04 17:33 ` Kamil Debski
  2015-05-04 17:33 ` [PATCH v2] libgencec: Add userspace library for the generic CEC kernel interface Kamil Debski
                   ` (2 subsequent siblings)
  13 siblings, 0 replies; 30+ messages in thread
From: Kamil Debski @ 2015-05-04 17:33 UTC (permalink / raw)
  To: dri-devel, linux-media
  Cc: m.szyprowski, k.debski, mchehab, hverkuil, kyungmin.park, thomas,
	sean, dmitry.torokhov, linux-input, linux-samsung-soc, lars

Add CEC interface driver present in the Samsung Exynos range of
SoCs.

The following files were based on work by SangPil Moon:
- exynos_hdmi_cec.h
- exynos_hdmi_cecctl.c

Signed-off-by: Kamil Debski <k.debski@samsung.com>
---
 .../devicetree/bindings/media/s5p-cec.txt          |   33 +++
 drivers/media/platform/Kconfig                     |   10 +
 drivers/media/platform/Makefile                    |    1 +
 drivers/media/platform/s5p-cec/Makefile            |    4 +
 drivers/media/platform/s5p-cec/exynos_hdmi_cec.h   |   37 +++
 .../media/platform/s5p-cec/exynos_hdmi_cecctrl.c   |  208 ++++++++++++++
 drivers/media/platform/s5p-cec/regs-cec.h          |   96 +++++++
 drivers/media/platform/s5p-cec/s5p_cec.c           |  283 ++++++++++++++++++++
 drivers/media/platform/s5p-cec/s5p_cec.h           |   76 ++++++
 9 files changed, 748 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/media/s5p-cec.txt
 create mode 100644 drivers/media/platform/s5p-cec/Makefile
 create mode 100644 drivers/media/platform/s5p-cec/exynos_hdmi_cec.h
 create mode 100644 drivers/media/platform/s5p-cec/exynos_hdmi_cecctrl.c
 create mode 100644 drivers/media/platform/s5p-cec/regs-cec.h
 create mode 100644 drivers/media/platform/s5p-cec/s5p_cec.c
 create mode 100644 drivers/media/platform/s5p-cec/s5p_cec.h

diff --git a/Documentation/devicetree/bindings/media/s5p-cec.txt b/Documentation/devicetree/bindings/media/s5p-cec.txt
new file mode 100644
index 0000000..97ca664
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/s5p-cec.txt
@@ -0,0 +1,33 @@
+* 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 follwoing
+	"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";
+};
+
+
diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig
index 421f531..203bc06 100644
--- a/drivers/media/platform/Kconfig
+++ b/drivers/media/platform/Kconfig
@@ -157,6 +157,16 @@ config VIDEO_MEM2MEM_DEINTERLACE
 	help
 	    Generic deinterlacing V4L2 driver.
 
+config VIDEO_SAMSUNG_S5P_CEC
+	tristate "Samsung S5P CEC driver"
+	depends on CEC && VIDEO_DEV && VIDEO_V4L2 && (PLAT_S5P || ARCH_EXYNOS)
+	default n
+	---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.
+
 config VIDEO_SAMSUNG_S5P_G2D
 	tristate "Samsung S5P and EXYNOS4 G2D 2d graphics accelerator driver"
 	depends on VIDEO_DEV && VIDEO_V4L2
diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile
index 8f85561..f96c9a3 100644
--- a/drivers/media/platform/Makefile
+++ b/drivers/media/platform/Makefile
@@ -27,6 +27,7 @@ obj-$(CONFIG_VIDEO_MEM2MEM_DEINTERLACE)	+= m2m-deinterlace.o
 
 obj-$(CONFIG_VIDEO_S3C_CAMIF) 		+= s3c-camif/
 obj-$(CONFIG_VIDEO_SAMSUNG_EXYNOS4_IS) 	+= exynos4-is/
+obj-$(CONFIG_VIDEO_SAMSUNG_S5P_CEC)	+= s5p-cec/
 obj-$(CONFIG_VIDEO_SAMSUNG_S5P_JPEG)	+= s5p-jpeg/
 obj-$(CONFIG_VIDEO_SAMSUNG_S5P_MFC)	+= s5p-mfc/
 obj-$(CONFIG_VIDEO_SAMSUNG_S5P_TV)	+= s5p-tv/
diff --git a/drivers/media/platform/s5p-cec/Makefile b/drivers/media/platform/s5p-cec/Makefile
new file mode 100644
index 0000000..7f84226
--- /dev/null
+++ b/drivers/media/platform/s5p-cec/Makefile
@@ -0,0 +1,4 @@
+obj-$(CONFIG_VIDEO_SAMSUNG_S5P_CEC)	+= s5p-cec.o
+s5p-cec-y += s5p_cec.o exynos_hdmi_cecctrl.o
+
+
diff --git a/drivers/media/platform/s5p-cec/exynos_hdmi_cec.h b/drivers/media/platform/s5p-cec/exynos_hdmi_cec.h
new file mode 100644
index 0000000..d008695
--- /dev/null
+++ b/drivers/media/platform/s5p-cec/exynos_hdmi_cec.h
@@ -0,0 +1,37 @@
+/* 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);
+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_ */
diff --git a/drivers/media/platform/s5p-cec/exynos_hdmi_cecctrl.c b/drivers/media/platform/s5p-cec/exynos_hdmi_cecctrl.c
new file mode 100644
index 0000000..134e50b
--- /dev/null
+++ b/drivers/media/platform/s5p-cec/exynos_hdmi_cecctrl.c
@@ -0,0 +1,208 @@
+/* drivers/media/platform/s5p-cec/exynos_hdmi_cecctrl.c
+ *
+ * Copyright (c) 2009, 2014 Samsung Electronics
+ *		http://www.samsung.com/
+ *
+ * cec ftn 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.
+ */
+
+#include <linux/io.h>
+#include <linux/device.h>
+
+#include "exynos_hdmi_cec.h"
+#include "regs-cec.h"
+
+#define S5P_HDMI_FIN			24000000
+#define CEC_DIV_RATIO			320000
+
+#define CEC_MESSAGE_BROADCAST_MASK	0x0F
+#define CEC_MESSAGE_BROADCAST		0x0F
+#define CEC_FILTER_THRESHOLD		0x15
+
+void s5p_cec_set_divider(struct s5p_cec_dev *cec)
+{
+	u32 div_ratio, div_val;
+	unsigned int reg;
+
+	div_ratio  = S5P_HDMI_FIN / CEC_DIV_RATIO - 1;
+
+	if (regmap_read(cec->pmu, EXYNOS_HDMI_PHY_CONTROL, &reg)) {
+		dev_err(cec->dev, "failed to read phy control\n");
+		return;
+	}
+
+	reg = (reg & ~(0x3FF << 16)) | (div_ratio << 16);
+
+	if (regmap_write(cec->pmu, EXYNOS_HDMI_PHY_CONTROL, reg)) {
+		dev_err(cec->dev, "failed to write phy control\n");
+		return;
+	}
+
+	div_val = CEC_DIV_RATIO * 0.00005 - 1;
+
+	writeb(0x0, cec->reg + S5P_CEC_DIVISOR_3);
+	writeb(0x0, cec->reg + S5P_CEC_DIVISOR_2);
+	writeb(0x0, cec->reg + S5P_CEC_DIVISOR_1);
+	writeb(div_val, cec->reg + S5P_CEC_DIVISOR_0);
+}
+
+void s5p_cec_enable_rx(struct s5p_cec_dev *cec)
+{
+	u8 reg;
+
+	reg = readb(cec->reg + S5P_CEC_RX_CTRL);
+	reg |= S5P_CEC_RX_CTRL_ENABLE;
+	writeb(reg, cec->reg + S5P_CEC_RX_CTRL);
+}
+
+void s5p_cec_mask_rx_interrupts(struct s5p_cec_dev *cec)
+{
+	u8 reg;
+
+	reg = readb(cec->reg + S5P_CEC_IRQ_MASK);
+	reg |= S5P_CEC_IRQ_RX_DONE;
+	reg |= S5P_CEC_IRQ_RX_ERROR;
+	writeb(reg, cec->reg + S5P_CEC_IRQ_MASK);
+}
+
+void s5p_cec_unmask_rx_interrupts(struct s5p_cec_dev *cec)
+{
+	u8 reg;
+
+	reg = readb(cec->reg + S5P_CEC_IRQ_MASK);
+	reg &= ~S5P_CEC_IRQ_RX_DONE;
+	reg &= ~S5P_CEC_IRQ_RX_ERROR;
+	writeb(reg, cec->reg + S5P_CEC_IRQ_MASK);
+}
+
+void s5p_cec_mask_tx_interrupts(struct s5p_cec_dev *cec)
+{
+	u8 reg;
+
+	reg = readb(cec->reg + S5P_CEC_IRQ_MASK);
+	reg |= S5P_CEC_IRQ_TX_DONE;
+	reg |= S5P_CEC_IRQ_TX_ERROR;
+	writeb(reg, cec->reg + S5P_CEC_IRQ_MASK);
+
+}
+
+void s5p_cec_unmask_tx_interrupts(struct s5p_cec_dev *cec)
+{
+	u8 reg;
+
+	reg = readb(cec->reg + S5P_CEC_IRQ_MASK);
+	reg &= ~S5P_CEC_IRQ_TX_DONE;
+	reg &= ~S5P_CEC_IRQ_TX_ERROR;
+	writeb(reg, cec->reg + S5P_CEC_IRQ_MASK);
+}
+
+void s5p_cec_reset(struct s5p_cec_dev *cec)
+{
+	u8 reg;
+
+	writeb(S5P_CEC_RX_CTRL_RESET, cec->reg + S5P_CEC_RX_CTRL);
+	writeb(S5P_CEC_TX_CTRL_RESET, cec->reg + S5P_CEC_TX_CTRL);
+
+	reg = readb(cec->reg + 0xc4);
+	reg &= ~0x1;
+	writeb(reg, cec->reg + 0xc4);
+}
+
+void s5p_cec_tx_reset(struct s5p_cec_dev *cec)
+{
+	writeb(S5P_CEC_TX_CTRL_RESET, cec->reg + S5P_CEC_TX_CTRL);
+}
+
+void s5p_cec_rx_reset(struct s5p_cec_dev *cec)
+{
+	u8 reg;
+
+	writeb(S5P_CEC_RX_CTRL_RESET, cec->reg + S5P_CEC_RX_CTRL);
+
+	reg = readb(cec->reg + 0xc4);
+	reg &= ~0x1;
+	writeb(reg, cec->reg + 0xc4);
+}
+
+void s5p_cec_threshold(struct s5p_cec_dev *cec)
+{
+	writeb(CEC_FILTER_THRESHOLD, cec->reg + S5P_CEC_RX_FILTER_TH);
+	writeb(0, cec->reg + S5P_CEC_RX_FILTER_CTRL);
+}
+
+void s5p_cec_copy_packet(struct s5p_cec_dev *cec, char *data, size_t count)
+{
+	char debug[40];
+	int i = 0;
+	u8 reg;
+
+	while (i < count) {
+		writeb(data[i], cec->reg + (S5P_CEC_TX_BUFF0 + (i * 4)));
+		sprintf(debug + i * 2, "%02x ", data[i]);
+		i++;
+	}
+
+	writeb(count, cec->reg + S5P_CEC_TX_BYTES);
+	reg = readb(cec->reg + S5P_CEC_TX_CTRL);
+	reg |= S5P_CEC_TX_CTRL_START;
+
+	if ((data[0] & CEC_MESSAGE_BROADCAST_MASK) == CEC_MESSAGE_BROADCAST) {
+		dev_dbg(cec->dev, "Broadcast");
+		reg |= S5P_CEC_TX_CTRL_BCAST;
+	} else {
+		dev_dbg(cec->dev, "No Broadcast");
+		reg &= ~S5P_CEC_TX_CTRL_BCAST;
+	}
+
+	reg |= 0x50;
+	writeb(reg, cec->reg + S5P_CEC_TX_CTRL);
+	dev_dbg(cec->dev, "cec-tx: cec count(%d): %s", count, debug);
+}
+
+void s5p_cec_set_addr(struct s5p_cec_dev *cec, u32 addr)
+{
+	writeb(addr & 0x0F, cec->reg + S5P_CEC_LOGIC_ADDR);
+}
+
+u32 s5p_cec_get_status(struct s5p_cec_dev *cec)
+{
+	u32 status = 0;
+
+	status = readb(cec->reg + S5P_CEC_STATUS_0);
+	status |= readb(cec->reg + S5P_CEC_STATUS_1) << 8;
+	status |= readb(cec->reg + S5P_CEC_STATUS_2) << 16;
+	status |= readb(cec->reg + S5P_CEC_STATUS_3) << 24;
+
+	dev_dbg(cec->dev, "status = 0x%x!\n", status);
+
+	return status;
+}
+
+void s5p_clr_pending_tx(struct s5p_cec_dev *cec)
+{
+	writeb(S5P_CEC_IRQ_TX_DONE | S5P_CEC_IRQ_TX_ERROR,
+					cec->reg + S5P_CEC_IRQ_CLEAR);
+}
+
+void s5p_clr_pending_rx(struct s5p_cec_dev *cec)
+{
+	writeb(S5P_CEC_IRQ_RX_DONE | S5P_CEC_IRQ_RX_ERROR,
+					cec->reg + S5P_CEC_IRQ_CLEAR);
+}
+
+void s5p_cec_get_rx_buf(struct s5p_cec_dev *cec, u32 size, u8 *buffer)
+{
+	u32 i = 0;
+	char debug[40];
+
+	while (i < size) {
+		buffer[i] = readb(cec->reg + S5P_CEC_RX_BUFF0 + (i * 4));
+		sprintf(debug + i * 2, "%02x ", buffer[i]);
+		i++;
+	}
+	dev_dbg(cec->dev, "cec-rx: cec size(%d): %s", size, debug);
+}
diff --git a/drivers/media/platform/s5p-cec/regs-cec.h b/drivers/media/platform/s5p-cec/regs-cec.h
new file mode 100644
index 0000000..b2e7e12
--- /dev/null
+++ b/drivers/media/platform/s5p-cec/regs-cec.h
@@ -0,0 +1,96 @@
+/* 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	*/
diff --git a/drivers/media/platform/s5p-cec/s5p_cec.c b/drivers/media/platform/s5p-cec/s5p_cec.c
new file mode 100644
index 0000000..a3dbcdb
--- /dev/null
+++ b/drivers/media/platform/s5p-cec/s5p_cec.c
@@ -0,0 +1,283 @@
+/* drivers/media/platform/s5p-cec/s5p_cec.c
+ *
+ * Samsung S5P 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.
+ *
+ * This driver is based on the "cec interface driver for exynos soc" by
+ * SangPil Moon.
+ */
+
+#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"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "debug level (0-2)");
+
+static int s5p_cec_enable(struct cec_adapter *adap, bool enable)
+{
+	struct s5p_cec_dev *cec = container_of(adap, struct s5p_cec_dev, adap);
+	int ret;
+
+	if (enable) {
+		ret = pm_runtime_get_sync(cec->dev);
+
+		adap->phys_addr = 0x100b;
+		s5p_cec_reset(cec);
+
+		s5p_cec_set_divider(cec);
+		s5p_cec_threshold(cec);
+
+		s5p_cec_unmask_tx_interrupts(cec);
+		s5p_cec_unmask_rx_interrupts(cec);
+		s5p_cec_enable_rx(cec);
+	} else {
+		s5p_cec_mask_tx_interrupts(cec);
+		s5p_cec_mask_rx_interrupts(cec);
+		pm_runtime_disable(cec->dev);
+	}
+
+	return 0;
+}
+
+static int s5p_cec_log_addr(struct cec_adapter *adap, u8 addr)
+{
+	struct s5p_cec_dev *cec = container_of(adap, struct s5p_cec_dev, adap);
+
+	s5p_cec_set_addr(cec, addr);
+	return 0;
+}
+
+static int s5p_cec_trasmit(struct cec_adapter *adap, struct cec_msg *msg)
+{
+	struct s5p_cec_dev *cec = container_of(adap, struct s5p_cec_dev, adap);
+
+	s5p_cec_copy_packet(cec, msg->msg, msg->len);
+	return 0;
+}
+
+static void s5p_cec_transmit_timed_out(struct cec_adapter *adap)
+{
+
+}
+
+static irqreturn_t s5p_cec_irq_handler(int irq, void *priv)
+{
+	struct s5p_cec_dev *cec = priv;
+	u32 status = 0;
+
+	status = s5p_cec_get_status(cec);
+
+	dev_dbg(cec->dev, "irq received\n");
+
+	if (status & CEC_STATUS_TX_DONE) {
+		if (status & CEC_STATUS_TX_ERROR) {
+			dev_dbg(cec->dev, "CEC_STATUS_TX_ERROR set\n");
+			cec->tx = STATE_ERROR;
+		} else {
+			dev_dbg(cec->dev, "CEC_STATUS_TX_DONE\n");
+			cec->tx = STATE_DONE;
+		}
+		s5p_clr_pending_tx(cec);
+	}
+
+	if (status & CEC_STATUS_RX_DONE) {
+		if (status & CEC_STATUS_RX_ERROR) {
+			dev_dbg(cec->dev, "CEC_STATUS_RX_ERROR set\n");
+			s5p_cec_rx_reset(cec);
+			s5p_cec_enable_rx(cec);
+		} else {
+			dev_dbg(cec->dev, "CEC_STATUS_RX_DONE set\n");
+			if (cec->rx != STATE_IDLE)
+				dev_dbg(cec->dev, "Buffer overrun (worker did not process previous message)\n");
+			cec->rx = STATE_BUSY;
+			cec->msg.len = status >> 24;
+			cec->msg.status = CEC_RX_STATUS_READY;
+			s5p_cec_get_rx_buf(cec, cec->msg.len,
+					cec->msg.msg);
+			cec->rx = STATE_DONE;
+			s5p_cec_enable_rx(cec);
+		}
+		/* Clear interrupt pending bit */
+		s5p_clr_pending_rx(cec);
+	}
+	return IRQ_WAKE_THREAD;
+}
+
+static irqreturn_t s5p_cec_irq_handler_thread(int irq, void *priv)
+{
+	struct s5p_cec_dev *cec = priv;
+
+	dev_dbg(cec->dev, "irq processing thread\n");
+	switch (cec->tx) {
+	case STATE_DONE:
+		cec_transmit_done(&cec->adap, CEC_TX_STATUS_OK);
+		cec->tx = STATE_IDLE;
+		break;
+	case STATE_ERROR:
+		cec_transmit_done(&cec->adap, CEC_TX_STATUS_RETRY_TIMEOUT);
+		cec->tx = STATE_IDLE;
+		break;
+	case STATE_BUSY:
+		dev_err(cec->dev, "state set to busy, this should not occur here\n");
+		break;
+	default:
+		break;
+	}
+
+	switch (cec->rx) {
+	case STATE_DONE:
+		cec_received_msg(&cec->adap, &cec->msg);
+		cec->rx = STATE_IDLE;
+	default:
+		break;
+	};
+
+	return IRQ_HANDLED;
+}
+
+static int s5p_cec_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct resource *res;
+	struct s5p_cec_dev *cec;
+	int ret;
+
+	cec = devm_kzalloc(&pdev->dev, sizeof(*cec), GFP_KERNEL);
+	if (!dev)
+		return -ENOMEM;
+
+	cec->dev = dev;
+
+	cec->irq = platform_get_irq(pdev, 0);
+	if (IS_ERR_VALUE(cec->irq))
+		return cec->irq;
+
+	ret = devm_request_threaded_irq(dev, cec->irq, s5p_cec_irq_handler,
+		s5p_cec_irq_handler_thread, 0, pdev->name, cec);
+	if (IS_ERR_VALUE(ret))
+		return ret;
+
+	cec->clk = devm_clk_get(dev, "hdmicec");
+	if (IS_ERR(cec->clk))
+		return PTR_ERR(cec->clk);
+
+	cec->pmu = syscon_regmap_lookup_by_phandle(dev->of_node,
+						 "samsung,syscon-phandle");
+	if (IS_ERR(cec->pmu))
+		return -EPROBE_DEFER;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	cec->reg = devm_ioremap_resource(dev, res);
+	if (IS_ERR(cec->reg))
+		return PTR_ERR(cec->reg);
+
+	cec->adap.adap_enable = s5p_cec_enable;
+	cec->adap.adap_log_addr = s5p_cec_log_addr;
+	cec->adap.adap_transmit = s5p_cec_trasmit;
+	cec->adap.adap_transmit_timed_out = s5p_cec_transmit_timed_out;
+	cec_create_adapter(&cec->adap, CEC_NAME, CEC_CAP_STATE |
+		CEC_CAP_LOG_ADDRS | CEC_CAP_TRANSMIT |
+		CEC_CAP_RECEIVE);
+
+	platform_set_drvdata(pdev, cec);
+	pm_runtime_enable(dev);
+
+	dev_dbg(dev, "successfuly probed\n");
+	return 0;
+}
+
+static int s5p_cec_remove(struct platform_device *pdev)
+{
+	struct s5p_cec_dev *cec = platform_get_drvdata(pdev);
+
+	cec_delete_adapter(&cec->adap);
+	pm_runtime_disable(&pdev->dev);
+	return 0;
+}
+
+static int s5p_cec_runtime_suspend(struct device *dev)
+{
+	struct s5p_cec_dev *cec = dev_get_drvdata(dev);
+
+	clk_disable_unprepare(cec->clk);
+	return 0;
+}
+
+static int s5p_cec_runtime_resume(struct device *dev)
+{
+	struct s5p_cec_dev *cec = dev_get_drvdata(dev);
+	int ret;
+
+	ret = clk_prepare_enable(cec->clk);
+	if (ret < 0)
+		return ret;
+	return 0;
+}
+
+static int s5p_cec_suspend(struct device *dev)
+{
+	if (pm_runtime_suspended(dev))
+		return 0;
+	return s5p_cec_runtime_suspend(dev);
+}
+
+static int s5p_cec_resume(struct device *dev)
+{
+	if (pm_runtime_suspended(dev))
+		return 0;
+	return s5p_cec_runtime_resume(dev);
+}
+
+static const struct dev_pm_ops s5p_cec_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(s5p_cec_suspend, s5p_cec_resume)
+	SET_RUNTIME_PM_OPS(s5p_cec_runtime_suspend, s5p_cec_runtime_resume,
+			   NULL)
+};
+
+static const struct of_device_id s5p_cec_match[] = {
+	{
+		.compatible	= "samsung,s5p-cec",
+	},
+	{},
+};
+
+static struct platform_driver s5p_cec_pdrv = {
+	.probe	= s5p_cec_probe,
+	.remove	= s5p_cec_remove,
+	.driver	= {
+		.name		= CEC_NAME,
+		.owner		= THIS_MODULE,
+		.of_match_table	= s5p_cec_match,
+		.pm		= &s5p_cec_pm_ops,
+	},
+};
+
+module_platform_driver(s5p_cec_pdrv);
+
+MODULE_AUTHOR("Kamil Debski <k.debski@samsung.com>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Samsung S5P CEC driver");
+
diff --git a/drivers/media/platform/s5p-cec/s5p_cec.h b/drivers/media/platform/s5p-cec/s5p_cec.h
new file mode 100644
index 0000000..d6ffd92
--- /dev/null
+++ b/drivers/media/platform/s5p-cec/s5p_cec.h
@@ -0,0 +1,76 @@
+/* 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_ */
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH v2] libgencec: Add userspace library for the generic CEC kernel interface
  2015-05-04 17:32 [PATCH v6 00/11] Kamil Debski
                   ` (10 preceding siblings ...)
  2015-05-04 17:33 ` [PATCH v6 11/11] cec: s5p-cec: Add s5p-cec driver Kamil Debski
@ 2015-05-04 17:33 ` Kamil Debski
  2015-05-08 10:59   ` Hans Verkuil
  2015-05-04 17:34 ` [PATCH v6 00/11] HDMI CEC framework Kamil Debski
  2015-06-16  6:22 ` [PATCH v6 00/11] Hans Verkuil
  13 siblings, 1 reply; 30+ messages in thread
From: Kamil Debski @ 2015-05-04 17:33 UTC (permalink / raw)
  To: dri-devel, linux-media
  Cc: m.szyprowski, k.debski, mchehab, hverkuil, kyungmin.park, thomas,
	sean, dmitry.torokhov, linux-input, linux-samsung-soc, lars

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 @@
+<h2>struct cec_device - a structure used to keep context of the current used CEC device</h2>
+<b>struct cec_device</b> {<br>
+&nbsp; &nbsp; <i>void *</i> <b>caps</b>;<br>
+&nbsp; &nbsp; <i>int</i> <b>handle</b>;<br>
+&nbsp; &nbsp; <i>int</i> <b>initialised</b>;<br>
+&nbsp; &nbsp; <i>uint32_t</i> <b>log_addr[CEC_MAX_NUM_LOG_ADDR]</b>;<br>
+&nbsp; &nbsp; <i>uint32_t</i> <b>log_addr_type_int[CEC_MAX_NUM_LOG_ADDR]</b>;<br>
+&nbsp; &nbsp; <i>enum cec_device_type</i> <b>dev_type[CEC_MAX_NUM_LOG_ADDR]</b>;<br>
+&nbsp; &nbsp; <i>uint32_t</i> <b>dev_type_int[CEC_MAX_NUM_LOG_ADDR]</b>;<br>
+&nbsp; &nbsp; <i>int</i> <b>num_log_addr</b>;<br>
+};<br>
+<h3>Members</h3>
+<dl>
+<dt><b>caps</b>
+<dd>used to keep a pointer to the kernel caps structure for the
+device
+<dt><b>handle</b>
+<dd>this is used to keep the file handle to the CEC device
+<dt><b>initialised</b>
+<dd>flag set if the structure was properly initialised
+<dt><b>log_addr[CEC_MAX_NUM_LOG_ADDR]</b>
+<dd>an array containing the assigned logical addresses
+<dt><b>log_addr_type_int[CEC_MAX_NUM_LOG_ADDR]</b>
+<dd>an array containing the logical addresses' types as
+needed by the kernel
+<dt><b>dev_type[CEC_MAX_NUM_LOG_ADDR]</b>
+<dd>device type, as neede by the library
+<dt><b>dev_type_int[CEC_MAX_NUM_LOG_ADDR]</b>
+<dd>primary device type, as needed by the kernel driver
+<dt><b>num_log_addr</b>
+<dd>number of ssigned logical addresses
+</dl>
+<hr>
+<h2>struct hdmi_port_info - Information about a HDMI port</h2>
+<b>struct hdmi_port_info</b> {<br>
+&nbsp; &nbsp; <i>uint8_t</i> <b>port_number</b>;<br>
+};<br>
+<h3>Members</h3>
+<dl>
+<dt><b>port_number</b>
+<dd>the port number
+</dl>
+<hr>
+<h2>struct cec_info - a structure used to get information about the CEC device</h2>
+<b>struct cec_info</b> {<br>
+&nbsp; &nbsp; <i>enum cec_version</i> <b>version</b>;<br>
+&nbsp; &nbsp; <i>uint32_t</i> <b>vendor_id</b>;<br>
+&nbsp; &nbsp; <i>unsigned int</i> <b>ports_num</b>;<br>
+&nbsp; &nbsp; <i>struct hdmi_port_info</i> <b>ports_info[MAX_NUM_OF_HDMI_PORTS]</b>;<br>
+};<br>
+<h3>Members</h3>
+<dl>
+<dt><b>version</b>
+<dd>supported CEC version
+<dt><b>vendor_id</b>
+<dd>the vendor ID
+<dt><b>ports_num</b>
+<dd>number of HDMI ports available in the system
+<dt><b>ports_info[MAX_NUM_OF_HDMI_PORTS]</b>
+<dd>an array containing information about HDMI ports
+</dl>
+<hr>
+<h2>struct cec_buffer - a structure used to store message that were received or are to be sent</h2>
+<b>struct cec_buffer</b> {<br>
+&nbsp; &nbsp; <i>uint8_t</i> <b>dst</b>;<br>
+&nbsp; &nbsp; <i>uint8_t</i> <b>src</b>;<br>
+&nbsp; &nbsp; <i>uint8_t</i> <b>len</b>;<br>
+&nbsp; &nbsp; <i>uint8_t</i> <b>payload[CEC_MAX_LENGTH]</b>;<br>
+&nbsp; &nbsp; <i>struct timespec</i> <b>ts</b>;<br>
+};<br>
+<h3>Members</h3>
+<dl>
+<dt><b>dst</b>
+<dd>The address of the destination device
+<dt><b>src</b>
+<dd>The address of the source device
+<dt><b>len</b>
+<dd>The length of the payload of the message
+<dt><b>payload[CEC_MAX_LENGTH]</b>
+<dd>The payload of the message
+<dt><b>ts</b>
+<dd>The timestamp for received messages
+</dl>
+<hr>
+<h2>cec_open - Open a CEC device</h2>
+<i>int</i>
+<b>cec_open</b>
+(<i>struct cec_device *</i> <b>dev</b>,
+<i>char *</i> <b>path</b>)
+<h3>Arguments</h3>
+<dl>
+<dt><b>dev</b>
+<dd>pointer to a structure that will hold the state of the device
+<dt><b>path</b>
+<dd>path to the CEC device
+</dl>
+<h3>Returns</h3>
+<blockquote>
+on success CEC_OK, on error returns an negative error code
+</blockquote>
+<hr>
+<h2>cec_close - Close a CEC device</h2>
+<i>int</i>
+<b>cec_close</b>
+(<i>struct cec_device *</i> <b>dev</b>)
+<h3>Arguments</h3>
+<dl>
+<dt><b>dev</b>
+<dd>pointer to a structure that holds the state of the device
+</dl>
+<h3>Returns</h3>
+<blockquote>
+on success CEC_OK, on error returns an negative error code
+</blockquote>
+<hr>
+<h2>cec_is_enabled - Check whether the CEC device is enabled</h2>
+<i>bool</i>
+<b>cec_is_enabled</b>
+(<i>struct cec_device *</i> <b>dev</b>)
+<h3>Arguments</h3>
+<dl>
+<dt><b>dev</b>
+<dd>pointer to a structure that holds the state of the device
+</dl>
+<h3>Returns</h3>
+<blockquote>
+true if all is ok and the CEC device is enabled, false otherwise
+</blockquote>
+<hr>
+<h2>cec_enable - Enable a CEC device</h2>
+<i>int</i>
+<b>cec_enable</b>
+(<i>struct cec_device *</i> <b>dev</b>,
+<i>bool</i> <b>enable</b>)
+<h3>Arguments</h3>
+<dl>
+<dt><b>dev</b>
+<dd>pointer to a structure that will hold the state of the device
+<dt><b>enable</b>
+<dd>true to enable the CEC device, false to disable the CEC device
+</dl>
+<h3>Returns</h3>
+<blockquote>
+on success CEC_OK, on error returns an negative error code
+</blockquote>
+<hr>
+<h2>cec_passthrough - Enable a CEC device</h2>
+<i>int</i>
+<b>cec_passthrough</b>
+(<i>struct cec_device *</i> <b>dev</b>,
+<i>bool</i> <b>enable</b>)
+<h3>Arguments</h3>
+<dl>
+<dt><b>dev</b>
+<dd>pointer to a structure that will hold the state of the device
+<dt><b>enable</b>
+<dd>true to enable the passthrough mode, false to disable
+</dl>
+<h3>Returns</h3>
+<blockquote>
+on success CEC_OK, on error returns an negative error code
+</blockquote>
+<hr>
+<h2>cec_get_info - Returns information about the CEC device</h2>
+<i>int</i>
+<b>cec_get_info</b>
+(<i>struct cec_device *</i> <b>dev</b>,
+<i>struct cec_info *</i> <b>info</b>)
+<h3>Arguments</h3>
+<dl>
+<dt><b>dev</b>
+<dd>pointer to a structure that holds the state of the device
+<dt><b>info</b>
+<dd>pointer to a info structure that will hold the information about
+the CEC device
+</dl>
+<h3>Returns</h3>
+<blockquote>
+on success CEC_OK, on error returns an negative error code
+</blockquote>
+<hr>
+<h2>cec_is_connected - Return information about whether a device is connected to the port</h2>
+<i>int</i>
+<b>cec_is_connected</b>
+(<i>struct cec_device *</i> <b>dev</b>)
+<h3>Arguments</h3>
+<dl>
+<dt><b>dev</b>
+<dd>pointer to a structure that holds the state of the device
+</dl>
+<h3>Returns</h3>
+<blockquote>
+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
+</blockquote>
+<hr>
+<h2>cec_send_message - Send a message over the CEC bus</h2>
+<i>int</i>
+<b>cec_send_message</b>
+(<i>struct cec_device *</i> <b>dev</b>,
+<i>struct cec_buffer *</i> <b>msg</b>)
+<h3>Arguments</h3>
+<dl>
+<dt><b>dev</b>
+<dd>pointer to a structure that holds the state of the device
+<dt><b>msg</b>
+<dd>the message do be sent over the CEC bus
+</dl>
+<h3>Returns</h3>
+<blockquote>
+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
+</blockquote>
+<hr>
+<h2>cec_receive_message - Receive a message over the CEC bus</h2>
+<i>int</i>
+<b>cec_receive_message</b>
+(<i>struct cec_device *</i> <b>dev</b>,
+<i>struct cec_buffer *</i> <b>msg</b>)
+<h3>Arguments</h3>
+<dl>
+<dt><b>dev</b>
+<dd>pointer to a structure that holds the state of the device
+<dt><b>msg</b>
+<dd>a structure used to store the message received over the CEC bus
+</dl>
+<h3>Returns</h3>
+<blockquote>
+CEC_OK on success
+CEC_TIMEOUT when a timeout occurred while waiting for message
+negative error code on error
+</blockquote>
+<h3>Remarks</h3>
+<blockquote>
+when waiting for a reply, the reply is stored in the msg struct
+</blockquote>
+<hr>
+<h2>cec_get_logical_addrs - Add a new logical address to the CEC device</h2>
+<i>int</i>
+<b>cec_get_logical_addrs</b>
+(<i>struct cec_device *</i> <b>dev</b>,
+<i>uint8_t *</i> <b>addr</b>,
+<i>int *</i> <b>num_addr</b>)
+<h3>Arguments</h3>
+<dl>
+<dt><b>dev</b>
+<dd>pointer to a structure that holds the state of the device
+<dt><b>addr</b>
+<dd>pointer to an array to hold the list of assigned logical
+addresses, the size should be CEC_MAX_NUM_LOG_ADDR
+<dt><b>num_addr</b>
+<dd>pointer to an int that will hold the number of assigned
+logical addresses
+</dl>
+<h3>Returns</h3>
+<blockquote>
+CEC_OK on success
+negative error code on error
+</blockquote>
+<hr>
+<h2>cec_add_logical_addr - Add a new logical address to the CEC device</h2>
+<i>int</i>
+<b>cec_add_logical_addr</b>
+(<i>struct cec_device *</i> <b>dev</b>,
+<i>enum cec_device_type</i> <b>type</b>,
+<i>uint8_t *</i> <b>addr</b>)
+<h3>Arguments</h3>
+<dl>
+<dt><b>dev</b>
+<dd>pointer to a structure that holds the state of the device
+<dt><b>type</b>
+<dd>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
+<dt><b>addr</b>
+<dd>a pointer to a location where to store the assigned logical
+address
+</dl>
+<h3>Returns</h3>
+<blockquote>
+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
+</blockquote>
+<hr>
+<h2>cec_clear_logical_addrs - Clear the logical addresses that were assigned to the device</h2>
+<i>int</i>
+<b>cec_clear_logical_addrs</b>
+(<i>struct cec_device *</i> <b>dev</b>)
+<h3>Arguments</h3>
+<dl>
+<dt><b>dev</b>
+<dd>pointer to a structure that holds the state of the device
+</dl>
+<h3>Returns</h3>
+<blockquote>
+CEC_OK on success
+CEC_TIMEOUT when a timeout occurred while waiting for message
+negative error code on error
+</blockquote>
+<hr>
+<h2>cec_get_physical_addr - Get the physical addr of the CEC device</h2>
+<i>int</i>
+<b>cec_get_physical_addr</b>
+(<i>struct cec_device *</i> <b>dev</b>,
+<i>uint16_t *</i> <b>phys_addr</b>)
+<h3>Arguments</h3>
+<dl>
+<dt><b>dev</b>
+<dd>pointer to a structure that holds the state of the device
+<dt><b>phys_addr</b>
+<dd>pointer to a uint16_t which will hold the physical address
+</dl>
+<h3>Returns</h3>
+<blockquote>
+CEC_OK on success
+CEC_TIMEOUT when a timeout occurred while waiting for message
+negative error code on error
+</blockquote>
+<hr>
+<h2>cec_set_physical_addr - Get the physical addr of the CEC device</h2>
+<i>int</i>
+<b>cec_set_physical_addr</b>
+(<i>struct cec_device *</i> <b>dev</b>,
+<i>uint16_t</i> <b>phys_addr</b>)
+<h3>Arguments</h3>
+<dl>
+<dt><b>dev</b>
+<dd>pointer to a structure that holds the state of the device
+<dt><b>phys_addr</b>
+<dd>a uint16_t which holding the physical address
+</dl>
+<h3>Returns</h3>
+<blockquote>
+CEC_OK on success
+CEC_TIMEOUT when a timeout occurred while waiting for message
+negative error code on error
+</blockquote>
+<hr>
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


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* RE: [PATCH v6 00/11] HDMI CEC framework
  2015-05-04 17:32 [PATCH v6 00/11] Kamil Debski
                   ` (11 preceding siblings ...)
  2015-05-04 17:33 ` [PATCH v2] libgencec: Add userspace library for the generic CEC kernel interface Kamil Debski
@ 2015-05-04 17:34 ` Kamil Debski
  2015-06-16  6:22 ` [PATCH v6 00/11] Hans Verkuil
  13 siblings, 0 replies; 30+ messages in thread
From: Kamil Debski @ 2015-05-04 17:34 UTC (permalink / raw)
  To: 'Kamil Debski', dri-devel, linux-media
  Cc: m.szyprowski, mchehab, hverkuil, kyungmin.park, thomas, sean,
	dmitry.torokhov, linux-input, linux-samsung-soc, lars

Hi,

Sorry, I missed the subject for this cover-letter. Added it in this reply.

Best wishes,
-- 
Kamil Debski
Samsung R&D Institute Poland


> -----Original Message-----
> From: Kamil Debski [mailto:k.debski@samsung.com]
> Sent: Monday, May 04, 2015 7:33 PM
> To: dri-devel@lists.freedesktop.org; linux-media@vger.kernel.org
> Cc: m.szyprowski@samsung.com; k.debski@samsung.com;
> mchehab@osg.samsung.com; hverkuil@xs4all.nl; kyungmin.park@samsung.com;
> thomas@tommie-lie.de; sean@mess.org; dmitry.torokhov@gmail.com; linux-
> input@vger.kernel.org; linux-samsung-soc@vger.kernel.org;
> lars@opdenkamp.eu
> Subject: [PATCH v6 00/11]
> 
> Hi,
> 
> The sixth version of this patchset addresses recent comments on the
> mailing list. Please see the changelog below for details.
> 
> Best wishes,
> Kamil Debski
> 
> Changes since v5
> ================
> - drop struct cec_timeval in favour of a __u64 that keeps the timestamp
> in ns
> - remove userspace documentation from Documentation/cec.txt as
> userspace API
>   is described in the DocBook
> - add missing documentation for the passthrough mode to the DocBook
> - add information about the number of events that can be queued
> - fix misspelling of reply
> - fix behaviour of posting an event in cec_received_msg, such that the
> behaviour
>   is consistent with the documentation
> 
> Changes since v4
> ================
> - add sequence numbering to transmitted messages
> - add sequence number handling to event hanlding
> - add passthrough mode
> - change reserved field sizes
> - fixed CEC version defines and addec CEC 2.0 commands
> - add DocBook documentation
> 
> Changes since v3
> ================
> - remove the promiscuous mode
> - rewrite the devicetree patches
> - fixes, expansion and partial rewrite of the documentation
> - reorder of API structures and addition of reserved fields
> - use own struct to report time (32/64 bit safe)
> - fix of handling events
> - add cec.h to include/uapi/linux/Kbuild
> - fixes in the adv76xx driver (add missing methods, change adv7604 to
> adv76xx)
> - cleanup of debug messages in s5p-cec driver
> - remove non necessary claiming of a gpio in the s5p-cec driver
> - cleanup headers of the s5p-cec driver
> 
> Changes since v2
> ===============-
> - added promiscuous mode
> - added new key codes to the input framework
> - add vendor ID reporting
> - add the possibility to clear assigned logical addresses
> - cleanup of the rc cec map
> 
> Changes since v1
> ================
> - documentation edited and moved to the Documentation folder
> - added key up/down message handling
> - add missing CEC commands to the cec.h file
> 
> Background
> ==========
> 
> The work on a common CEC framework was started over three years ago by
> Hans Verkuil. Unfortunately the work has stalled. As I have received
> the task of creating a driver for the CEC interface module present on
> the Exynos range of SoCs, I got in touch with Hans. He replied that the
> work stalled due to his lack of time.
> 
> Original RFC by Hans Verkuil/Martin Bugge
> =========================================
> https://www.mail-archive.com/linux-media@vger.kernel.org/msg28735.html
> 
> 
> Hans Verkuil (5):
>   cec: add HDMI CEC framework
>   DocBook/media: add CEC documentation
>   v4l2-subdev: add HDMI CEC ops
>   cec: adv7604: add cec support.
>   cec: adv7511: add cec support.
> 
> Kamil Debski (6):
>   dts: exynos4*: add HDMI CEC pin definition to pinctrl
>   dts: exynos4: add node for the HDMI CEC device
>   dts: exynos4412-odroid*: enable the HDMI CEC device
>   HID: add HDMI CEC specific keycodes
>   rc: Add HDMI CEC protoctol handling
>   cec: s5p-cec: Add s5p-cec driver
> 
>  Documentation/DocBook/media/Makefile               |    4 +-
>  Documentation/DocBook/media/v4l/biblio.xml         |   10 +
>  Documentation/DocBook/media/v4l/cec-api.xml        |   74 ++
>  Documentation/DocBook/media/v4l/cec-func-close.xml |   59 +
>  Documentation/DocBook/media/v4l/cec-func-ioctl.xml |   73 ++
>  Documentation/DocBook/media/v4l/cec-func-open.xml  |   94 ++
>  Documentation/DocBook/media/v4l/cec-func-poll.xml  |   89 ++
>  .../DocBook/media/v4l/cec-ioc-g-adap-log-addrs.xml |  275 +++++
>  .../DocBook/media/v4l/cec-ioc-g-adap-phys-addr.xml |   78 ++
>  .../DocBook/media/v4l/cec-ioc-g-adap-state.xml     |   87 ++
>  Documentation/DocBook/media/v4l/cec-ioc-g-caps.xml |  173 +++
>  .../DocBook/media/v4l/cec-ioc-g-event.xml          |  125 ++
>  .../DocBook/media/v4l/cec-ioc-g-passthrough.xml    |   88 ++
>  .../DocBook/media/v4l/cec-ioc-g-vendor-id.xml      |   70 ++
>  .../DocBook/media/v4l/cec-ioc-receive.xml          |  185 +++
>  Documentation/DocBook/media_api.tmpl               |    6 +-
>  Documentation/cec.txt                              |  165 +++
>  .../devicetree/bindings/media/s5p-cec.txt          |   33 +
>  arch/arm/boot/dts/exynos4.dtsi                     |   12 +
>  arch/arm/boot/dts/exynos4210-pinctrl.dtsi          |    7 +
>  arch/arm/boot/dts/exynos4412-odroid-common.dtsi    |    4 +
>  arch/arm/boot/dts/exynos4x12-pinctrl.dtsi          |    7 +
>  drivers/media/Kconfig                              |    6 +
>  drivers/media/Makefile                             |    2 +
>  drivers/media/cec.c                                | 1191
> ++++++++++++++++++++
>  drivers/media/i2c/adv7511.c                        |  347 +++++-
>  drivers/media/i2c/adv7604.c                        |  207 +++-
>  drivers/media/platform/Kconfig                     |   10 +
>  drivers/media/platform/Makefile                    |    1 +
>  drivers/media/platform/s5p-cec/Makefile            |    4 +
>  drivers/media/platform/s5p-cec/exynos_hdmi_cec.h   |   37 +
>  .../media/platform/s5p-cec/exynos_hdmi_cecctrl.c   |  208 ++++
>  drivers/media/platform/s5p-cec/regs-cec.h          |   96 ++
>  drivers/media/platform/s5p-cec/s5p_cec.c           |  283 +++++
>  drivers/media/platform/s5p-cec/s5p_cec.h           |   76 ++
>  drivers/media/rc/keymaps/Makefile                  |    1 +
>  drivers/media/rc/keymaps/rc-cec.c                  |  144 +++
>  drivers/media/rc/rc-main.c                         |    1 +
>  include/media/adv7511.h                            |    6 +-
>  include/media/cec.h                                |  142 +++
>  include/media/rc-core.h                            |    1 +
>  include/media/rc-map.h                             |    5 +-
>  include/media/v4l2-subdev.h                        |    8 +
>  include/uapi/linux/Kbuild                          |    1 +
>  include/uapi/linux/cec.h                           |  332 ++++++
>  include/uapi/linux/input.h                         |   12 +
>  46 files changed, 4824 insertions(+), 15 deletions(-)  create mode
> 100644 Documentation/DocBook/media/v4l/cec-api.xml
>  create mode 100644 Documentation/DocBook/media/v4l/cec-func-close.xml
>  create mode 100644 Documentation/DocBook/media/v4l/cec-func-ioctl.xml
>  create mode 100644 Documentation/DocBook/media/v4l/cec-func-open.xml
>  create mode 100644 Documentation/DocBook/media/v4l/cec-func-poll.xml
>  create mode 100644 Documentation/DocBook/media/v4l/cec-ioc-g-adap-log-
> addrs.xml
>  create mode 100644 Documentation/DocBook/media/v4l/cec-ioc-g-adap-
> phys-addr.xml
>  create mode 100644 Documentation/DocBook/media/v4l/cec-ioc-g-adap-
> state.xml
>  create mode 100644 Documentation/DocBook/media/v4l/cec-ioc-g-caps.xml
>  create mode 100644 Documentation/DocBook/media/v4l/cec-ioc-g-event.xml
>  create mode 100644 Documentation/DocBook/media/v4l/cec-ioc-g-
> passthrough.xml
>  create mode 100644 Documentation/DocBook/media/v4l/cec-ioc-g-vendor-
> id.xml
>  create mode 100644 Documentation/DocBook/media/v4l/cec-ioc-receive.xml
>  create mode 100644 Documentation/cec.txt  create mode 100644
> Documentation/devicetree/bindings/media/s5p-cec.txt
>  create mode 100644 drivers/media/cec.c
>  create mode 100644 drivers/media/platform/s5p-cec/Makefile
>  create mode 100644 drivers/media/platform/s5p-cec/exynos_hdmi_cec.h
>  create mode 100644 drivers/media/platform/s5p-
> cec/exynos_hdmi_cecctrl.c
>  create mode 100644 drivers/media/platform/s5p-cec/regs-cec.h
>  create mode 100644 drivers/media/platform/s5p-cec/s5p_cec.c
>  create mode 100644 drivers/media/platform/s5p-cec/s5p_cec.h
>  create mode 100644 drivers/media/rc/keymaps/rc-cec.c  create mode
> 100644 include/media/cec.h  create mode 100644 include/uapi/linux/cec.h
> 
> --
> 1.7.9.5


^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v6 01/11] dts: exynos4*: add HDMI CEC pin definition to pinctrl
  2015-05-04 17:32 ` [PATCH v6 01/11] dts: exynos4*: add HDMI CEC pin definition to pinctrl Kamil Debski
@ 2015-05-05  3:59   ` Krzysztof Kozłowski
  0 siblings, 0 replies; 30+ messages in thread
From: Krzysztof Kozłowski @ 2015-05-05  3:59 UTC (permalink / raw)
  To: Kamil Debski
  Cc: dri-devel, linux-media, Marek Szyprowski, mchehab, hverkuil,
	kyungmin.park, thomas, sean, dmitry.torokhov, linux-input,
	linux-samsung-soc, lars

2015-05-05 2:32 GMT+09:00 Kamil Debski <k.debski@samsung.com>:
> Add pinctrl nodes for the HDMI CEC device to the Exynos4210 and
> Exynos4x12 SoCs. These are required by the HDMI CEC device.
>
> Signed-off-by: Kamil Debski <k.debski@samsung.com>

Acked-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>

Are there any objections to picking the DTS changes independently?

Best regards,
Krzysztof

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v6 02/11] dts: exynos4: add node for the HDMI CEC device
  2015-05-04 17:32 ` [PATCH v6 02/11] dts: exynos4: add node for the HDMI CEC device Kamil Debski
@ 2015-05-05  3:59   ` Krzysztof Kozłowski
  0 siblings, 0 replies; 30+ messages in thread
From: Krzysztof Kozłowski @ 2015-05-05  3:59 UTC (permalink / raw)
  To: Kamil Debski
  Cc: dri-devel, linux-media, Marek Szyprowski, mchehab, hverkuil,
	kyungmin.park, thomas, sean, dmitry.torokhov, linux-input,
	linux-samsung-soc, lars

2015-05-05 2:32 GMT+09:00 Kamil Debski <k.debski@samsung.com>:
> This patch adds HDMI CEC node specific to the Exynos4210/4x12 SoC series.
>
> Signed-off-by: Kamil Debski <k.debski@samsung.com>

Acked-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>

Best regards,
Krzysztof

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v6 03/11] dts: exynos4412-odroid*: enable the HDMI CEC device
  2015-05-04 17:32 ` [PATCH v6 03/11] dts: exynos4412-odroid*: enable " Kamil Debski
@ 2015-05-05  4:00   ` Krzysztof Kozłowski
  0 siblings, 0 replies; 30+ messages in thread
From: Krzysztof Kozłowski @ 2015-05-05  4:00 UTC (permalink / raw)
  To: Kamil Debski
  Cc: dri-devel, linux-media, Marek Szyprowski, mchehab, hverkuil,
	kyungmin.park, thomas, sean, dmitry.torokhov, linux-input,
	linux-samsung-soc, lars

2015-05-05 2:32 GMT+09:00 Kamil Debski <k.debski@samsung.com>:
> Add a dts node entry and enable the HDMI CEC device present in the Exynos4
> family of SoCs.
>
> Signed-off-by: Kamil Debski <k.debski@samsung.com>

Acked-by: Krzysztof Kozlowski <k.kozlowski@samsung.com>

Best regards,
Krzysztof

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v6 07/11] DocBook/media: add CEC documentation
  2015-05-04 17:33 ` [PATCH v6 07/11] DocBook/media: add CEC documentation Kamil Debski
@ 2015-05-08 10:45   ` Hans Verkuil
  0 siblings, 0 replies; 30+ messages in thread
From: Hans Verkuil @ 2015-05-08 10:45 UTC (permalink / raw)
  To: Kamil Debski, dri-devel, linux-media
  Cc: m.szyprowski, mchehab, kyungmin.park, thomas, sean,
	dmitry.torokhov, linux-input, linux-samsung-soc, lars,
	Hans Verkuil

Hi Kamil,

A few more comments about the documentation:

First of all you should add some documentation about what the passthrough mode
actually is. Right now all this says is that you can enable or disable it, but
not what it actually does.

And next I have a few small comments about the timestamp documentation:

> diff --git a/Documentation/DocBook/media/v4l/cec-ioc-g-event.xml b/Documentation/DocBook/media/v4l/cec-ioc-g-event.xml
> new file mode 100644
> index 0000000..cbde320
> --- /dev/null
> +++ b/Documentation/DocBook/media/v4l/cec-ioc-g-event.xml
> @@ -0,0 +1,125 @@

...

> +  <refsect1>
> +    <title>Description</title>
> +
> +    <para>CEC devices can send asynchronous events. These can be retrieved by calling
> +    the <constant>CEC_G_EVENT</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>There can be up to 40 events queued up. If more events are added, then the oldest event will be discarded.</para>
> +
> +    <table pgwide="1" frame="none" id="cec-event">
> +      <title>struct <structname>cec_event</structname></title>
> +      <tgroup cols="3">
> +	&cs-str;
> +	<tbody valign="top">
> +	  <row>
> +	    <entry>__u64</entry>
> +	    <entry><structfield>ts</structfield></entry>
> +	    <entry>Timestamp of the event in ns.</entry>

"Timestamp of the event in ns. This is based on the monotonic clock. Applications
can access this clock using <function>clock_gettime(2)</function> with clock ID
<constant>CLOCK_MONOTONIC</constant>. To turn this into a <structname>struct timespec</structname>
use:

<programlisting>
	struct timespec tmspec;

	tmspec.tv_sec = ts / 1000000000;
	tmspec.tv_nsec = ts % 1000000000;
<programlisting>"

(I hope the docbook syntax for programlisting is correct)

<snip>

> diff --git a/Documentation/DocBook/media/v4l/cec-ioc-receive.xml b/Documentation/DocBook/media/v4l/cec-ioc-receive.xml
> new file mode 100644
> index 0000000..dbec20a
> --- /dev/null
> +++ b/Documentation/DocBook/media/v4l/cec-ioc-receive.xml
> @@ -0,0 +1,185 @@

...

> +    <table pgwide="1" frame="none" id="cec-msg">
> +      <title>struct <structname>cec_msg</structname></title>
> +      <tgroup cols="3">
> +	&cs-str;
> +	<tbody valign="top">
> +	  <row>
> +	    <entry>__u64</entry>
> +	    <entry><structfield>ts</structfield></entry>
> +	    <entry>Timestamp of when the message was transmitted in ns in the case
> +	    of <constant>CEC_TRANSMIT</constant> with <structfield>reply</structfield>
> +	    set to 0, or the timestamp of the received message in all other cases.</entry>

The same timestamp explanation should be given here.

Regards,

	Hans

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v2] libgencec: Add userspace library for the generic CEC kernel interface
  2015-05-04 17:33 ` [PATCH v2] libgencec: Add userspace library for the generic CEC kernel interface Kamil Debski
@ 2015-05-08 10:59   ` Hans Verkuil
  0 siblings, 0 replies; 30+ messages in thread
From: Hans Verkuil @ 2015-05-08 10:59 UTC (permalink / raw)
  To: Kamil Debski, dri-devel, linux-media
  Cc: m.szyprowski, mchehab, kyungmin.park, thomas, sean,
	dmitry.torokhov, linux-input, linux-samsung-soc, lars

Hi Kamil,

On 05/04/2015 07:33 PM, Kamil Debski wrote:
> 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>

I still strongly recommend that this library is added to the v4l-utils
repo. That already has support for v4l, dvb, media controller and IR
(i.e. everything under drivers/media), and the CEC library/utility should
be added there IMHO.

For example, I might want to use it in qv4l2, so being able to link it
knowing that I always get the latest version is very useful.

Also, v4l-utils is always updated to be in sync with the latest media_tree
kernel, and since CEC is part of that you really don't want to reinvent the
wheel in that respect.

There were objections in the past to renaming v4l-utils to media-utils, but
perhaps this should be revisited as it hasn't been v4l specific for a long 
time now.

Regards,

	Hans

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v6 04/11] HID: add HDMI CEC specific keycodes
  2015-05-04 17:32 ` [PATCH v6 04/11] HID: add HDMI CEC specific keycodes Kamil Debski
@ 2015-05-08 11:00   ` Hans Verkuil
  0 siblings, 0 replies; 30+ messages in thread
From: Hans Verkuil @ 2015-05-08 11:00 UTC (permalink / raw)
  To: Kamil Debski, dri-devel, linux-media
  Cc: m.szyprowski, mchehab, kyungmin.park, thomas, sean,
	dmitry.torokhov, linux-input, linux-samsung-soc, lars

On 05/04/2015 07:32 PM, Kamil Debski wrote:
> Add HDMI CEC specific keycodes to the keycodes definition.
> 
> Signed-off-by: Kamil Debski <k.debski@samsung.com>

Acked-by: Hans Verkuil <hans.verkuil@cisco.com>

> ---
>  include/uapi/linux/input.h |   12 ++++++++++++
>  1 file changed, 12 insertions(+)
> 
> diff --git a/include/uapi/linux/input.h b/include/uapi/linux/input.h
> index 731417c..7430a3f 100644
> --- a/include/uapi/linux/input.h
> +++ b/include/uapi/linux/input.h
> @@ -752,6 +752,18 @@ struct input_keymap_entry {
>  #define KEY_KBDINPUTASSIST_ACCEPT		0x264
>  #define KEY_KBDINPUTASSIST_CANCEL		0x265
>  
> +#define KEY_RIGHT_UP			0x266
> +#define KEY_RIGHT_DOWN			0x267
> +#define KEY_LEFT_UP			0x268
> +#define KEY_LEFT_DOWN			0x269
> +
> +#define KEY_NEXT_FAVORITE		0x270
> +#define KEY_STOP_RECORD			0x271
> +#define KEY_PAUSE_RECORD		0x272
> +#define KEY_VOD				0x273
> +#define KEY_UNMUTE			0x274
> +#define KEY_DVB				0x275
> +
>  #define BTN_TRIGGER_HAPPY		0x2c0
>  #define BTN_TRIGGER_HAPPY1		0x2c0
>  #define BTN_TRIGGER_HAPPY2		0x2c1
> 


^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v6 05/11] rc: Add HDMI CEC protoctol handling
  2015-05-04 17:32 ` [PATCH v6 05/11] rc: Add HDMI CEC protoctol handling Kamil Debski
@ 2015-05-08 11:02   ` Hans Verkuil
  2015-05-08 11:18     ` Hans Verkuil
  0 siblings, 1 reply; 30+ messages in thread
From: Hans Verkuil @ 2015-05-08 11:02 UTC (permalink / raw)
  To: Kamil Debski, dri-devel, linux-media
  Cc: m.szyprowski, mchehab, kyungmin.park, thomas, sean,
	dmitry.torokhov, linux-input, linux-samsung-soc, lars

On 05/04/2015 07:32 PM, Kamil Debski wrote:
> Add handling of remote control events coming from the HDMI CEC bus.
> This patch includes a new keymap that maps values found in the CEC
> messages to the keys pressed and released. Also, a new protocol has
> been added to the core.
> 
> Signed-off-by: Kamil Debski <k.debski@samsung.com>

Acked-by: Hans Verkuil <hans.verkuil@cisco.com>

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v6 05/11] rc: Add HDMI CEC protoctol handling
  2015-05-08 11:02   ` Hans Verkuil
@ 2015-05-08 11:18     ` Hans Verkuil
  0 siblings, 0 replies; 30+ messages in thread
From: Hans Verkuil @ 2015-05-08 11:18 UTC (permalink / raw)
  To: Kamil Debski, dri-devel, linux-media
  Cc: m.szyprowski, mchehab, kyungmin.park, thomas, sean,
	dmitry.torokhov, linux-input, linux-samsung-soc, lars

On 05/08/2015 01:02 PM, Hans Verkuil wrote:
> On 05/04/2015 07:32 PM, Kamil Debski wrote:
>> Add handling of remote control events coming from the HDMI CEC bus.
>> This patch includes a new keymap that maps values found in the CEC
>> messages to the keys pressed and released. Also, a new protocol has
>> been added to the core.
>>
>> Signed-off-by: Kamil Debski <k.debski@samsung.com>
> 
> Acked-by: Hans Verkuil <hans.verkuil@cisco.com>

But if you could fix the typo in the subject: protoctol -> protocol, then
that would be appreciated...

Regards,

	Hans

> --
> To unsubscribe from this list: send the line "unsubscribe linux-media" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 


^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v6 06/11] cec: add HDMI CEC framework
  2015-05-04 17:32 ` [PATCH v6 06/11] cec: add HDMI CEC framework Kamil Debski
@ 2015-05-08 11:30   ` Hans Verkuil
  2015-05-13  8:03   ` Hans Verkuil
                     ` (3 subsequent siblings)
  4 siblings, 0 replies; 30+ messages in thread
From: Hans Verkuil @ 2015-05-08 11:30 UTC (permalink / raw)
  To: Kamil Debski, dri-devel, linux-media
  Cc: m.szyprowski, mchehab, kyungmin.park, thomas, sean,
	dmitry.torokhov, linux-input, linux-samsung-soc, lars,
	Hans Verkuil

Hi Kamil,

Just two tiny issues, and after that you can add my:

Reviewed-by: Hans Verkuil <hans.verkuil@ciso.com>

to this.

On 05/04/2015 07:32 PM, Kamil Debski wrote:
> diff --git a/include/uapi/linux/cec.h b/include/uapi/linux/cec.h
> new file mode 100644
> index 0000000..67b0049
> --- /dev/null
> +++ b/include/uapi/linux/cec.h
> @@ -0,0 +1,332 @@
> +#ifndef _CEC_H
> +#define _CEC_H
> +
> +#include <linux/types.h>
> +
> +struct cec_msg {
> +	__u64 ts;
> +	__u32 len;
> +	__u32 status;
> +	__u32 timeout;
> +	/* timeout (in ms) is used to timeout CEC_RECEIVE.
> +	   Set to 0 if you want to wait forever. */
> +	__u8  msg[16];
> +	__u8  reply;
> +	/* If non-zero, then wait for a reply with this opcode.
> +	   If there was an error when sending the msg or FeatureAbort
> +	   was returned, then reply is set to 0.
> +	   If reply is non-zero upon return, then len/msg are set to
> +	   the received message.
> +	   If reply is zero upon return and status has the
> +	   CEC_TX_STATUS_FEATURE_ABORT bit set, then len/msg are set to the
> +	   received feature abort message.
> +	   If reply is zero upon return and status has the
> +	   CEC_TX_STATUS_REPLY_TIMEOUT
> +	   bit set, then no reply was seen at all.
> +	   This field is ignored with CEC_RECEIVE.
> +	   If reply is non-zero for CEC_TRANSMIT and the message is a broadcast,
> +	   then -EINVAL is returned.
> +	   if reply is non-zero, then timeout is set to 1000 (the required
> +	   maximum response time).
> +	 */
> +	__u32 sequence;
> +	/* The framework assigns a sequence number to messages that are sent.
> +	 * This can be used to track replies to previously sent messages.
> +	 */
> +	__u8 reserved[35];
> +};

It is confusing in struct cec_msg that the comments come *after* the field
they belong to instead of just before. Can you change this?

> +
> +#define CEC_G_EVENT		_IOWR('a', 9, struct cec_event)

This can be __IOR since we never write anything.

> +/*
> +   Read and set the vendor ID of the CEC adapter.
> + */
> +#define CEC_G_VENDOR_ID		_IOR('a', 10, __u32)
> +#define CEC_S_VENDOR_ID		_IOW('a', 11, __u32)
> +/*
> +   Enable/disable the passthrough mode
> + */
> +#define CEC_G_PASSTHROUGH	_IOR('a', 12, __u32)
> +#define CEC_S_PASSTHROUGH	_IOW('a', 13, __u32)
> +
> +#endif
> 

Regards,

	Hans

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v6 06/11] cec: add HDMI CEC framework
  2015-05-04 17:32 ` [PATCH v6 06/11] cec: add HDMI CEC framework Kamil Debski
  2015-05-08 11:30   ` Hans Verkuil
@ 2015-05-13  8:03   ` Hans Verkuil
  2015-05-13  8:28   ` Hans Verkuil
                     ` (2 subsequent siblings)
  4 siblings, 0 replies; 30+ messages in thread
From: Hans Verkuil @ 2015-05-13  8:03 UTC (permalink / raw)
  To: Kamil Debski, dri-devel, linux-media
  Cc: m.szyprowski, mchehab, kyungmin.park, thomas, sean,
	dmitry.torokhov, linux-input, linux-samsung-soc, lars,
	Hans Verkuil

Hi Kamil,

I've started work on a cec-compliance utility and while doing that I
noticed a confusing name:

On 05/04/15 19:32, Kamil Debski wrote:
> +struct cec_caps {
> +	__u32 available_log_addrs;
> +	__u32 capabilities;
> +	__u32 vendor_id;
> +	__u8  version;
> +	__u8  reserved[35];
> +};

I think 'version' should be renamed to 'cec_version' to indicate that we
are talking about the CEC version that the adapter supports, and not about
the driver version.

Regards,

	Hans

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v6 06/11] cec: add HDMI CEC framework
  2015-05-04 17:32 ` [PATCH v6 06/11] cec: add HDMI CEC framework Kamil Debski
  2015-05-08 11:30   ` Hans Verkuil
  2015-05-13  8:03   ` Hans Verkuil
@ 2015-05-13  8:28   ` Hans Verkuil
  2015-05-13  9:43   ` Hans Verkuil
  2015-05-13 11:10   ` Sean Young
  4 siblings, 0 replies; 30+ messages in thread
From: Hans Verkuil @ 2015-05-13  8:28 UTC (permalink / raw)
  To: Kamil Debski, dri-devel, linux-media
  Cc: m.szyprowski, mchehab, kyungmin.park, thomas, sean,
	dmitry.torokhov, linux-input, linux-samsung-soc, lars,
	Hans Verkuil

Hi Kamil,

Here is the first cec-compliance bug report:

CEC_G_CAPS doesn't zero the reserved field!

cec.c needs a memset there.

I think this is missing in cec.c for all structs with a reserved
field in them. Only G_EVENT looks to be OK.

Regards,

	Hans

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v6 06/11] cec: add HDMI CEC framework
  2015-05-04 17:32 ` [PATCH v6 06/11] cec: add HDMI CEC framework Kamil Debski
                     ` (2 preceding siblings ...)
  2015-05-13  8:28   ` Hans Verkuil
@ 2015-05-13  9:43   ` Hans Verkuil
  2015-05-13 11:10   ` Sean Young
  4 siblings, 0 replies; 30+ messages in thread
From: Hans Verkuil @ 2015-05-13  9:43 UTC (permalink / raw)
  To: Kamil Debski, dri-devel, linux-media
  Cc: m.szyprowski, mchehab, kyungmin.park, thomas, sean,
	dmitry.torokhov, linux-input, linux-samsung-soc, lars,
	Hans Verkuil

Typo and question:

On 05/04/15 19:32, Kamil Debski wrote:
> +static long cec_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
> +{
> +	struct cec_devnode *cecdev = cec_devnode_data(filp);
> +	struct cec_adapter *adap = to_cec_adapter(cecdev);
> +	void __user *parg = (void __user *)arg;
> +	int err;
> +
> +	if (!cec_devnode_is_registered(cecdev))
> +		return -EIO;
> +
> +	switch (cmd) {

snip

> +	case CEC_G_ADAP_STATE: {
> +		u32 state = adap->state != CEC_ADAP_STATE_DISABLED;
> +
> +		if (copy_to_user(parg, &state, sizeof(state)))
> +			return -EFAULT;
> +		break;
> +	}
> +
> +	case CEC_S_ADAP_STATE: {
> +		u32 state;
> +
> +		if (!(adap->capabilities & CEC_CAP_STATE))
> +			return -ENOTTY;
> +		if (copy_from_user(&state, parg, sizeof(state)))
> +			return -EFAULT;
> +		if (!state && adap->state == CEC_ADAP_STATE_DISABLED)
> +			return 0;
> +		if (state && adap->state != CEC_ADAP_STATE_DISABLED)
> +			return 0;
> +		cec_enable(adap, !!state);
> +		break;
> +	}
> +
> +	case CEC_G_ADAP_PHYS_ADDR:
> +		if (copy_to_user(parg, &adap->phys_addr,
> +						sizeof(adap->phys_addr)))
> +			return -EFAULT;

If the adapter requires that userspace sets up the phys addr, then what
should this return if no such address has been set up?

I see two options: either 0xffff (which should be used if the HDMI cable
is disconnected), or return an error (perhaps ENODATA).

I think 0xffff might be best. This will still allow the unregistered
logical address.

Note that the comment in uapi/linux/cec.h for G_ADAP_LOG_ADDRS says that it
will return an error if the physical address is not set. That's not true
as far as I can tell, and if we go for 0xffff as the default in a case like
that, then it isn't necessary either to return an error.

cec_create_adapter already initialized the physical address to 0xffff, so
that looks good. But it should be documented in cec-ioc-g-adap-phys-addr.xml.

> +		break;
> +
> +	case CEC_S_ADAP_PHYS_ADDR: {
> +		u16 phys_addr;
> +
> +		if (!(adap->capabilities & CEC_CAP_PHYS_ADDR))
> +			return -ENOTTY;
> +		if (copy_from_user(&phys_addr, parg, sizeof(phys_addr)))
> +			return -EFAULT;
> +		adap->phys_addr = phys_addr;
> +		break;
> +	}
> +
> +	case CEC_G_ADAP_LOG_ADDRS: {
> +		struct cec_log_addrs log_addrs;
> +
> +		log_addrs.cec_version = adap->version;
> +		log_addrs.num_log_addrs = adap->num_log_addrs;
> +		memcpy(log_addrs.primary_device_type, adap->prim_device,
> +							CEC_MAX_LOG_ADDRS);
> +		memcpy(log_addrs.log_addr_type, adap->log_addr_type,
> +							CEC_MAX_LOG_ADDRS);
> +		memcpy(log_addrs.log_addr, adap->log_addr,
> +							CEC_MAX_LOG_ADDRS);
> +
> +		if (copy_to_user(parg, &log_addrs, sizeof(log_addrs)))
> +			return -EFAULT;
> +		break;
> +	}
> +
> +	case CEC_S_ADAP_LOG_ADDRS: {
> +		struct cec_log_addrs log_addrs;
> +
> +		if (!(adap->capabilities & CEC_CAP_LOG_ADDRS))
> +			return -ENOTTY;
> +		if (copy_from_user(&log_addrs, parg, sizeof(log_addrs)))
> +			return -EFAULT;
> +		err = cec_claim_log_addrs(adap, &log_addrs,
> +					!(filp->f_flags & O_NONBLOCK));
> +		if (err)
> +			return err;
> +
> +		if (copy_to_user(parg, &log_addrs, sizeof(log_addrs)))
> +			return -EFAULT;
> +		break;
> +	}
> +
> +	case CEC_G_VENDOR_ID:
> +		if (copy_to_user(parg, &adap->vendor_id,
> +						sizeof(adap->vendor_id)))
> +			return -EFAULT;

I've been reading up on this. If I understand it correctly, then this is
optional (only if a device supports vendor commands does it have to implement
this).

So if the VENDOR capability is set, then userspace *may* change it. If it is
left undefined, then no vendor commands are allowed.

I think this should be redesigned:

One CEC_CAP_VENDOR_CMDS: if set, then vendor commands are allowed.
One CEC_CAP_VENDOR_ID: userspace may set the Vendor ID. No vendor commands are
allowed as long as no vendor ID was set.

So if VENDOR_CMDS is set and VENDOR_ID isn't, then that means that the driver
will have set the vendor ID and the application can retrieve it with G_VENDOR_ID.
If both are set, then userspace has to provide a vendor ID before vendor commands
will be allowed.

That leaves the problem of determining that no vendor ID was set. Unfortunately
the whole range of 0x000000-0xffffff is valid (and 0x000000 maps in fact to a
company (Xerox) according to the IEEE Registration Authority Committee website.

We can define a CEC_VENDOR_ID_INVALID 0xffffffff, that might be the easiest way
of doing this.

A related question: should userspace be allowed to change a valid physical
address or a valid vendor ID to something else once the logical addresses have
been claimed? Or should that result in -EBUSY? I'm leaning towards that.

Actually, the same question is true for S_LOG_ADDRS: that should be done only
once as well as long as the adapter is enabled.

BTW, the documentation does not mention the order in which S_PHYS_ADDR and
S_VENDOR_ID should be issued: should this be done before the adapter is
enabled or before the logical addresses are claimed?

> +		break;
> +
> +	case CEC_S_VENDOR_ID: {
> +		u32 vendor_id;
> +
> +		if (!(adap->capabilities & CEC_CAP_VENDOR_ID))
> +			return -ENOTTY;
> +		if (copy_from_user(&vendor_id, parg, sizeof(vendor_id)))
> +			return -EFAULT;
> +		/* Vendori ID is a 24 bit number, so check if the value is

Typo: Vendori -> Vendor


> +		 * within the correct range. */
> +		if ((vendor_id & 0xff000000) != 0)
> +			return -EINVAL;
> +		adap->vendor_id = vendor_id;
> +		break;
> +	}

Working on a compliance test is always a great way of finding all these
corner cases...

Regards,

	Hans

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v6 06/11] cec: add HDMI CEC framework
  2015-05-04 17:32 ` [PATCH v6 06/11] cec: add HDMI CEC framework Kamil Debski
                     ` (3 preceding siblings ...)
  2015-05-13  9:43   ` Hans Verkuil
@ 2015-05-13 11:10   ` Sean Young
  2015-05-19 11:03     ` Hans Verkuil
  4 siblings, 1 reply; 30+ messages in thread
From: Sean Young @ 2015-05-13 11:10 UTC (permalink / raw)
  To: Kamil Debski
  Cc: dri-devel, linux-media, m.szyprowski, mchehab, hverkuil,
	kyungmin.park, thomas, dmitry.torokhov, linux-input,
	linux-samsung-soc, lars, Hans Verkuil

On Mon, May 04, 2015 at 07:32:59PM +0200, Kamil Debski wrote:
> From: Hans Verkuil <hansverk@cisco.com>
> 
> The added HDMI CEC framework provides a generic kernel interface for
> HDMI CEC devices.
> 
> Signed-off-by: Hans Verkuil <hansverk@cisco.com>

-snip-

> +int cec_create_adapter(struct cec_adapter *adap, const char *name, u32 caps)
> +{
> +	int res = 0;
> +
> +	adap->state = CEC_ADAP_STATE_DISABLED;
> +	adap->name = name;
> +	adap->phys_addr = 0xffff;
> +	adap->capabilities = caps;
> +	adap->version = CEC_VERSION_1_4;
> +	adap->sequence = 0;
> +	mutex_init(&adap->lock);
> +	adap->kthread = kthread_run(cec_thread_func, adap, name);
> +	init_waitqueue_head(&adap->kthread_waitq);
> +	init_waitqueue_head(&adap->waitq);
> +	if (IS_ERR(adap->kthread)) {
> +		pr_err("cec-%s: kernel_thread() failed\n", name);
> +		return PTR_ERR(adap->kthread);
> +	}
> +	if (caps) {
> +		res = cec_devnode_register(&adap->devnode, adap->owner);
> +		if (res)
> +			kthread_stop(adap->kthread);
> +	}
> +	adap->recv_notifier = cec_receive_notify;
> +
> +	/* Prepare the RC input device */
> +	adap->rc = rc_allocate_device();
> +	if (!adap->rc) {
> +		pr_err("cec-%s: failed to allocate memory for rc_dev\n", name);
> +		cec_devnode_unregister(&adap->devnode);
> +		kthread_stop(adap->kthread);
> +		return -ENOMEM;
> +	}
> +
> +	snprintf(adap->input_name, sizeof(adap->input_name), "RC for %s", name);
> +	snprintf(adap->input_phys, sizeof(adap->input_phys), "%s/input0", name);
> +	strncpy(adap->input_drv, name, sizeof(adap->input_drv));
> +
> +	adap->rc->input_name = adap->input_name;
> +	adap->rc->input_phys = adap->input_phys;
> +	adap->rc->dev.parent = &adap->devnode.dev;
> +	adap->rc->driver_name = adap->input_drv;
> +	adap->rc->driver_type = RC_DRIVER_CEC;
> +	adap->rc->allowed_protocols = RC_BIT_CEC;
> +	adap->rc->priv = adap;
> +	adap->rc->map_name = RC_MAP_CEC;
> +	adap->rc->timeout = MS_TO_NS(100);
> +

rc->input_id is not populated. It would be nice if input_phys has some 
resemblance to a physical path (like the output of usb_make_path() if it
is a usb device).

> +	res = rc_register_device(adap->rc);
> +
> +	if (res) {
> +		pr_err("cec-%s: failed to prepare input device\n", name);
> +		cec_devnode_unregister(&adap->devnode);
> +		rc_free_device(adap->rc);
> +		kthread_stop(adap->kthread);
> +	}
> +
> +	return res;
> +}
> +EXPORT_SYMBOL_GPL(cec_create_adapter);
> +
> +void cec_delete_adapter(struct cec_adapter *adap)
> +{
> +	if (adap->kthread == NULL)
> +		return;
> +	kthread_stop(adap->kthread);
> +	if (adap->kthread_config)
> +		kthread_stop(adap->kthread_config);
> +	adap->state = CEC_ADAP_STATE_DISABLED;
> +	if (cec_devnode_is_registered(&adap->devnode))
> +		cec_devnode_unregister(&adap->devnode);

I think you're missing a rc_unregister_device() here.

> +}
> +EXPORT_SYMBOL_GPL(cec_delete_adapter);


Sean

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v6 06/11] cec: add HDMI CEC framework
  2015-05-13 11:10   ` Sean Young
@ 2015-05-19 11:03     ` Hans Verkuil
  0 siblings, 0 replies; 30+ messages in thread
From: Hans Verkuil @ 2015-05-19 11:03 UTC (permalink / raw)
  To: Sean Young, Kamil Debski
  Cc: dri-devel, linux-media, m.szyprowski, mchehab, kyungmin.park,
	thomas, dmitry.torokhov, linux-input, linux-samsung-soc, lars,
	Hans Verkuil

Hi Sean,

I'm taking over this patch series from Kamil for the time being with his
permission (he's switching jobs and moving house so he can't spend any time
on this for a while).

On 05/13/15 13:10, Sean Young wrote:
> On Mon, May 04, 2015 at 07:32:59PM +0200, Kamil Debski wrote:
>> From: Hans Verkuil <hansverk@cisco.com>
>>
>> The added HDMI CEC framework provides a generic kernel interface for
>> HDMI CEC devices.
>>
>> Signed-off-by: Hans Verkuil <hansverk@cisco.com>
> 
> -snip-
> 
>> +int cec_create_adapter(struct cec_adapter *adap, const char *name, u32 caps)
>> +{
>> +	int res = 0;
>> +
>> +	adap->state = CEC_ADAP_STATE_DISABLED;
>> +	adap->name = name;
>> +	adap->phys_addr = 0xffff;
>> +	adap->capabilities = caps;
>> +	adap->version = CEC_VERSION_1_4;
>> +	adap->sequence = 0;
>> +	mutex_init(&adap->lock);
>> +	adap->kthread = kthread_run(cec_thread_func, adap, name);
>> +	init_waitqueue_head(&adap->kthread_waitq);
>> +	init_waitqueue_head(&adap->waitq);
>> +	if (IS_ERR(adap->kthread)) {
>> +		pr_err("cec-%s: kernel_thread() failed\n", name);
>> +		return PTR_ERR(adap->kthread);
>> +	}
>> +	if (caps) {
>> +		res = cec_devnode_register(&adap->devnode, adap->owner);
>> +		if (res)
>> +			kthread_stop(adap->kthread);
>> +	}
>> +	adap->recv_notifier = cec_receive_notify;
>> +
>> +	/* Prepare the RC input device */
>> +	adap->rc = rc_allocate_device();
>> +	if (!adap->rc) {
>> +		pr_err("cec-%s: failed to allocate memory for rc_dev\n", name);
>> +		cec_devnode_unregister(&adap->devnode);
>> +		kthread_stop(adap->kthread);
>> +		return -ENOMEM;
>> +	}
>> +
>> +	snprintf(adap->input_name, sizeof(adap->input_name), "RC for %s", name);
>> +	snprintf(adap->input_phys, sizeof(adap->input_phys), "%s/input0", name);
>> +	strncpy(adap->input_drv, name, sizeof(adap->input_drv));
>> +
>> +	adap->rc->input_name = adap->input_name;
>> +	adap->rc->input_phys = adap->input_phys;
>> +	adap->rc->dev.parent = &adap->devnode.dev;
>> +	adap->rc->driver_name = adap->input_drv;
>> +	adap->rc->driver_type = RC_DRIVER_CEC;
>> +	adap->rc->allowed_protocols = RC_BIT_CEC;
>> +	adap->rc->priv = adap;
>> +	adap->rc->map_name = RC_MAP_CEC;
>> +	adap->rc->timeout = MS_TO_NS(100);
>> +
> 
> rc->input_id is not populated. It would be nice if input_phys has some 
> resemblance to a physical path (like the output of usb_make_path() if it
> is a usb device).

I've added a BUS_CEC type, the version field can probably get the CEC version
used, but the vendor/product IDs are difficult: there isn't a product ID in
the CEC protocol, but there is a 24-bit vendor ID. I'm wondering whether I
should just put the top 8 bits of the vendor ID in the vendor field and the
remaining 16 in the product field. That way the combination of the two will be
unique.

What do you think?

>> +	res = rc_register_device(adap->rc);
>> +
>> +	if (res) {
>> +		pr_err("cec-%s: failed to prepare input device\n", name);
>> +		cec_devnode_unregister(&adap->devnode);
>> +		rc_free_device(adap->rc);
>> +		kthread_stop(adap->kthread);
>> +	}
>> +
>> +	return res;
>> +}
>> +EXPORT_SYMBOL_GPL(cec_create_adapter);
>> +
>> +void cec_delete_adapter(struct cec_adapter *adap)
>> +{
>> +	if (adap->kthread == NULL)
>> +		return;
>> +	kthread_stop(adap->kthread);
>> +	if (adap->kthread_config)
>> +		kthread_stop(adap->kthread_config);
>> +	adap->state = CEC_ADAP_STATE_DISABLED;
>> +	if (cec_devnode_is_registered(&adap->devnode))
>> +		cec_devnode_unregister(&adap->devnode);
> 
> I think you're missing a rc_unregister_device() here.

Yes indeed. Added.

Regards,

	Hans

> 
>> +}
>> +EXPORT_SYMBOL_GPL(cec_delete_adapter);
> 
> 
> Sean
> --
> To unsubscribe from this list: send the line "unsubscribe linux-media" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v6 00/11]
  2015-05-04 17:32 [PATCH v6 00/11] Kamil Debski
                   ` (12 preceding siblings ...)
  2015-05-04 17:34 ` [PATCH v6 00/11] HDMI CEC framework Kamil Debski
@ 2015-06-16  6:22 ` Hans Verkuil
  2015-06-16  7:08   ` [PATCH v6 00/11] CEC update Hans Verkuil
  13 siblings, 1 reply; 30+ messages in thread
From: Hans Verkuil @ 2015-06-16  6:22 UTC (permalink / raw)
  To: Kamil Debski, dri-devel, linux-media
  Cc: m.szyprowski, mchehab, kyungmin.park, thomas, sean,
	dmitry.torokhov, linux-input, linux-samsung-soc, lars

On 05/04/2015 07:32 PM, Kamil Debski wrote:
> Hi,
> 
> The sixth version of this patchset addresses recent comments on the mailing
> list. Please see the changelog below for details.

Just in case people are wondering what happened to this: about a month ago I
took over from Kamil and I am working hard to get a v7 posted. I'm currently
working on a utility to send messages over the cec line and once that's done
I plan on posting a new version which should be close to the final version.

One of the main problems is making sure that the framework covers the full
CEC 2.0 functionality (or at least, making sure that any missing pieces can
be added seamlessly later). CEC 2.0 is a lot more strict in what should and
what shouldn't be implemented, so this takes time.

Regards,

	Hans

> 
> Best wishes,
> Kamil Debski
> 
> Changes since v5
> ================
> - drop struct cec_timeval in favour of a __u64 that keeps the timestamp in ns
> - remove userspace documentation from Documentation/cec.txt as userspace API
>   is described in the DocBook
> - add missing documentation for the passthrough mode to the DocBook
> - add information about the number of events that can be queued
> - fix misspelling of reply
> - fix behaviour of posting an event in cec_received_msg, such that the behaviour
>   is consistent with the documentation
> 
> Changes since v4
> ================
> - add sequence numbering to transmitted messages
> - add sequence number handling to event hanlding
> - add passthrough mode
> - change reserved field sizes
> - fixed CEC version defines and addec CEC 2.0 commands
> - add DocBook documentation
> 
> Changes since v3
> ================
> - remove the promiscuous mode
> - rewrite the devicetree patches
> - fixes, expansion and partial rewrite of the documentation
> - reorder of API structures and addition of reserved fields
> - use own struct to report time (32/64 bit safe)
> - fix of handling events
> - add cec.h to include/uapi/linux/Kbuild
> - fixes in the adv76xx driver (add missing methods, change adv7604 to adv76xx)
> - cleanup of debug messages in s5p-cec driver
> - remove non necessary claiming of a gpio in the s5p-cec driver
> - cleanup headers of the s5p-cec driver
> 
> Changes since v2
> ===============-
> - added promiscuous mode
> - added new key codes to the input framework
> - add vendor ID reporting
> - add the possibility to clear assigned logical addresses
> - cleanup of the rc cec map
> 
> Changes since v1
> ================
> - documentation edited and moved to the Documentation folder
> - added key up/down message handling
> - add missing CEC commands to the cec.h file
> 
> Background
> ==========
> 
> The work on a common CEC framework was started over three years ago by Hans
> Verkuil. Unfortunately the work has stalled. As I have received the task of
> creating a driver for the CEC interface module present on the Exynos range of
> SoCs, I got in touch with Hans. He replied that the work stalled due to his
> lack of time.
> 
> Original RFC by Hans Verkuil/Martin Bugge
> =========================================
> https://www.mail-archive.com/linux-media@vger.kernel.org/msg28735.html
> 
> 
> Hans Verkuil (5):
>   cec: add HDMI CEC framework
>   DocBook/media: add CEC documentation
>   v4l2-subdev: add HDMI CEC ops
>   cec: adv7604: add cec support.
>   cec: adv7511: add cec support.
> 
> Kamil Debski (6):
>   dts: exynos4*: add HDMI CEC pin definition to pinctrl
>   dts: exynos4: add node for the HDMI CEC device
>   dts: exynos4412-odroid*: enable the HDMI CEC device
>   HID: add HDMI CEC specific keycodes
>   rc: Add HDMI CEC protoctol handling
>   cec: s5p-cec: Add s5p-cec driver
> 
>  Documentation/DocBook/media/Makefile               |    4 +-
>  Documentation/DocBook/media/v4l/biblio.xml         |   10 +
>  Documentation/DocBook/media/v4l/cec-api.xml        |   74 ++
>  Documentation/DocBook/media/v4l/cec-func-close.xml |   59 +
>  Documentation/DocBook/media/v4l/cec-func-ioctl.xml |   73 ++
>  Documentation/DocBook/media/v4l/cec-func-open.xml  |   94 ++
>  Documentation/DocBook/media/v4l/cec-func-poll.xml  |   89 ++
>  .../DocBook/media/v4l/cec-ioc-g-adap-log-addrs.xml |  275 +++++
>  .../DocBook/media/v4l/cec-ioc-g-adap-phys-addr.xml |   78 ++
>  .../DocBook/media/v4l/cec-ioc-g-adap-state.xml     |   87 ++
>  Documentation/DocBook/media/v4l/cec-ioc-g-caps.xml |  173 +++
>  .../DocBook/media/v4l/cec-ioc-g-event.xml          |  125 ++
>  .../DocBook/media/v4l/cec-ioc-g-passthrough.xml    |   88 ++
>  .../DocBook/media/v4l/cec-ioc-g-vendor-id.xml      |   70 ++
>  .../DocBook/media/v4l/cec-ioc-receive.xml          |  185 +++
>  Documentation/DocBook/media_api.tmpl               |    6 +-
>  Documentation/cec.txt                              |  165 +++
>  .../devicetree/bindings/media/s5p-cec.txt          |   33 +
>  arch/arm/boot/dts/exynos4.dtsi                     |   12 +
>  arch/arm/boot/dts/exynos4210-pinctrl.dtsi          |    7 +
>  arch/arm/boot/dts/exynos4412-odroid-common.dtsi    |    4 +
>  arch/arm/boot/dts/exynos4x12-pinctrl.dtsi          |    7 +
>  drivers/media/Kconfig                              |    6 +
>  drivers/media/Makefile                             |    2 +
>  drivers/media/cec.c                                | 1191 ++++++++++++++++++++
>  drivers/media/i2c/adv7511.c                        |  347 +++++-
>  drivers/media/i2c/adv7604.c                        |  207 +++-
>  drivers/media/platform/Kconfig                     |   10 +
>  drivers/media/platform/Makefile                    |    1 +
>  drivers/media/platform/s5p-cec/Makefile            |    4 +
>  drivers/media/platform/s5p-cec/exynos_hdmi_cec.h   |   37 +
>  .../media/platform/s5p-cec/exynos_hdmi_cecctrl.c   |  208 ++++
>  drivers/media/platform/s5p-cec/regs-cec.h          |   96 ++
>  drivers/media/platform/s5p-cec/s5p_cec.c           |  283 +++++
>  drivers/media/platform/s5p-cec/s5p_cec.h           |   76 ++
>  drivers/media/rc/keymaps/Makefile                  |    1 +
>  drivers/media/rc/keymaps/rc-cec.c                  |  144 +++
>  drivers/media/rc/rc-main.c                         |    1 +
>  include/media/adv7511.h                            |    6 +-
>  include/media/cec.h                                |  142 +++
>  include/media/rc-core.h                            |    1 +
>  include/media/rc-map.h                             |    5 +-
>  include/media/v4l2-subdev.h                        |    8 +
>  include/uapi/linux/Kbuild                          |    1 +
>  include/uapi/linux/cec.h                           |  332 ++++++
>  include/uapi/linux/input.h                         |   12 +
>  46 files changed, 4824 insertions(+), 15 deletions(-)
>  create mode 100644 Documentation/DocBook/media/v4l/cec-api.xml
>  create mode 100644 Documentation/DocBook/media/v4l/cec-func-close.xml
>  create mode 100644 Documentation/DocBook/media/v4l/cec-func-ioctl.xml
>  create mode 100644 Documentation/DocBook/media/v4l/cec-func-open.xml
>  create mode 100644 Documentation/DocBook/media/v4l/cec-func-poll.xml
>  create mode 100644 Documentation/DocBook/media/v4l/cec-ioc-g-adap-log-addrs.xml
>  create mode 100644 Documentation/DocBook/media/v4l/cec-ioc-g-adap-phys-addr.xml
>  create mode 100644 Documentation/DocBook/media/v4l/cec-ioc-g-adap-state.xml
>  create mode 100644 Documentation/DocBook/media/v4l/cec-ioc-g-caps.xml
>  create mode 100644 Documentation/DocBook/media/v4l/cec-ioc-g-event.xml
>  create mode 100644 Documentation/DocBook/media/v4l/cec-ioc-g-passthrough.xml
>  create mode 100644 Documentation/DocBook/media/v4l/cec-ioc-g-vendor-id.xml
>  create mode 100644 Documentation/DocBook/media/v4l/cec-ioc-receive.xml
>  create mode 100644 Documentation/cec.txt
>  create mode 100644 Documentation/devicetree/bindings/media/s5p-cec.txt
>  create mode 100644 drivers/media/cec.c
>  create mode 100644 drivers/media/platform/s5p-cec/Makefile
>  create mode 100644 drivers/media/platform/s5p-cec/exynos_hdmi_cec.h
>  create mode 100644 drivers/media/platform/s5p-cec/exynos_hdmi_cecctrl.c
>  create mode 100644 drivers/media/platform/s5p-cec/regs-cec.h
>  create mode 100644 drivers/media/platform/s5p-cec/s5p_cec.c
>  create mode 100644 drivers/media/platform/s5p-cec/s5p_cec.h
>  create mode 100644 drivers/media/rc/keymaps/rc-cec.c
>  create mode 100644 include/media/cec.h
>  create mode 100644 include/uapi/linux/cec.h
> 


^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [PATCH v6 00/11] CEC update
  2015-06-16  6:22 ` [PATCH v6 00/11] Hans Verkuil
@ 2015-06-16  7:08   ` Hans Verkuil
  0 siblings, 0 replies; 30+ messages in thread
From: Hans Verkuil @ 2015-06-16  7:08 UTC (permalink / raw)
  To: Kamil Debski, dri-devel, linux-media
  Cc: m.szyprowski, mchehab, kyungmin.park, thomas, sean,
	dmitry.torokhov, linux-input, linux-samsung-soc, lars

Let me fill in the subject line so people know what it is about :-)

	Hans

On 06/16/15 08:22, Hans Verkuil wrote:
> On 05/04/2015 07:32 PM, Kamil Debski wrote:
>> Hi,
>>
>> The sixth version of this patchset addresses recent comments on the mailing
>> list. Please see the changelog below for details.
> 
> Just in case people are wondering what happened to this: about a month ago I
> took over from Kamil and I am working hard to get a v7 posted. I'm currently
> working on a utility to send messages over the cec line and once that's done
> I plan on posting a new version which should be close to the final version.
> 
> One of the main problems is making sure that the framework covers the full
> CEC 2.0 functionality (or at least, making sure that any missing pieces can
> be added seamlessly later). CEC 2.0 is a lot more strict in what should and
> what shouldn't be implemented, so this takes time.
> 
> Regards,
> 
> 	Hans
> 
>>
>> Best wishes,
>> Kamil Debski
>>
>> Changes since v5
>> ================
>> - drop struct cec_timeval in favour of a __u64 that keeps the timestamp in ns
>> - remove userspace documentation from Documentation/cec.txt as userspace API
>>   is described in the DocBook
>> - add missing documentation for the passthrough mode to the DocBook
>> - add information about the number of events that can be queued
>> - fix misspelling of reply
>> - fix behaviour of posting an event in cec_received_msg, such that the behaviour
>>   is consistent with the documentation
>>
>> Changes since v4
>> ================
>> - add sequence numbering to transmitted messages
>> - add sequence number handling to event hanlding
>> - add passthrough mode
>> - change reserved field sizes
>> - fixed CEC version defines and addec CEC 2.0 commands
>> - add DocBook documentation
>>
>> Changes since v3
>> ================
>> - remove the promiscuous mode
>> - rewrite the devicetree patches
>> - fixes, expansion and partial rewrite of the documentation
>> - reorder of API structures and addition of reserved fields
>> - use own struct to report time (32/64 bit safe)
>> - fix of handling events
>> - add cec.h to include/uapi/linux/Kbuild
>> - fixes in the adv76xx driver (add missing methods, change adv7604 to adv76xx)
>> - cleanup of debug messages in s5p-cec driver
>> - remove non necessary claiming of a gpio in the s5p-cec driver
>> - cleanup headers of the s5p-cec driver
>>
>> Changes since v2
>> ===============-
>> - added promiscuous mode
>> - added new key codes to the input framework
>> - add vendor ID reporting
>> - add the possibility to clear assigned logical addresses
>> - cleanup of the rc cec map
>>
>> Changes since v1
>> ================
>> - documentation edited and moved to the Documentation folder
>> - added key up/down message handling
>> - add missing CEC commands to the cec.h file
>>
>> Background
>> ==========
>>
>> The work on a common CEC framework was started over three years ago by Hans
>> Verkuil. Unfortunately the work has stalled. As I have received the task of
>> creating a driver for the CEC interface module present on the Exynos range of
>> SoCs, I got in touch with Hans. He replied that the work stalled due to his
>> lack of time.
>>
>> Original RFC by Hans Verkuil/Martin Bugge
>> =========================================
>> https://www.mail-archive.com/linux-media@vger.kernel.org/msg28735.html
>>
>>
>> Hans Verkuil (5):
>>   cec: add HDMI CEC framework
>>   DocBook/media: add CEC documentation
>>   v4l2-subdev: add HDMI CEC ops
>>   cec: adv7604: add cec support.
>>   cec: adv7511: add cec support.
>>
>> Kamil Debski (6):
>>   dts: exynos4*: add HDMI CEC pin definition to pinctrl
>>   dts: exynos4: add node for the HDMI CEC device
>>   dts: exynos4412-odroid*: enable the HDMI CEC device
>>   HID: add HDMI CEC specific keycodes
>>   rc: Add HDMI CEC protoctol handling
>>   cec: s5p-cec: Add s5p-cec driver
>>
>>  Documentation/DocBook/media/Makefile               |    4 +-
>>  Documentation/DocBook/media/v4l/biblio.xml         |   10 +
>>  Documentation/DocBook/media/v4l/cec-api.xml        |   74 ++
>>  Documentation/DocBook/media/v4l/cec-func-close.xml |   59 +
>>  Documentation/DocBook/media/v4l/cec-func-ioctl.xml |   73 ++
>>  Documentation/DocBook/media/v4l/cec-func-open.xml  |   94 ++
>>  Documentation/DocBook/media/v4l/cec-func-poll.xml  |   89 ++
>>  .../DocBook/media/v4l/cec-ioc-g-adap-log-addrs.xml |  275 +++++
>>  .../DocBook/media/v4l/cec-ioc-g-adap-phys-addr.xml |   78 ++
>>  .../DocBook/media/v4l/cec-ioc-g-adap-state.xml     |   87 ++
>>  Documentation/DocBook/media/v4l/cec-ioc-g-caps.xml |  173 +++
>>  .../DocBook/media/v4l/cec-ioc-g-event.xml          |  125 ++
>>  .../DocBook/media/v4l/cec-ioc-g-passthrough.xml    |   88 ++
>>  .../DocBook/media/v4l/cec-ioc-g-vendor-id.xml      |   70 ++
>>  .../DocBook/media/v4l/cec-ioc-receive.xml          |  185 +++
>>  Documentation/DocBook/media_api.tmpl               |    6 +-
>>  Documentation/cec.txt                              |  165 +++
>>  .../devicetree/bindings/media/s5p-cec.txt          |   33 +
>>  arch/arm/boot/dts/exynos4.dtsi                     |   12 +
>>  arch/arm/boot/dts/exynos4210-pinctrl.dtsi          |    7 +
>>  arch/arm/boot/dts/exynos4412-odroid-common.dtsi    |    4 +
>>  arch/arm/boot/dts/exynos4x12-pinctrl.dtsi          |    7 +
>>  drivers/media/Kconfig                              |    6 +
>>  drivers/media/Makefile                             |    2 +
>>  drivers/media/cec.c                                | 1191 ++++++++++++++++++++
>>  drivers/media/i2c/adv7511.c                        |  347 +++++-
>>  drivers/media/i2c/adv7604.c                        |  207 +++-
>>  drivers/media/platform/Kconfig                     |   10 +
>>  drivers/media/platform/Makefile                    |    1 +
>>  drivers/media/platform/s5p-cec/Makefile            |    4 +
>>  drivers/media/platform/s5p-cec/exynos_hdmi_cec.h   |   37 +
>>  .../media/platform/s5p-cec/exynos_hdmi_cecctrl.c   |  208 ++++
>>  drivers/media/platform/s5p-cec/regs-cec.h          |   96 ++
>>  drivers/media/platform/s5p-cec/s5p_cec.c           |  283 +++++
>>  drivers/media/platform/s5p-cec/s5p_cec.h           |   76 ++
>>  drivers/media/rc/keymaps/Makefile                  |    1 +
>>  drivers/media/rc/keymaps/rc-cec.c                  |  144 +++
>>  drivers/media/rc/rc-main.c                         |    1 +
>>  include/media/adv7511.h                            |    6 +-
>>  include/media/cec.h                                |  142 +++
>>  include/media/rc-core.h                            |    1 +
>>  include/media/rc-map.h                             |    5 +-
>>  include/media/v4l2-subdev.h                        |    8 +
>>  include/uapi/linux/Kbuild                          |    1 +
>>  include/uapi/linux/cec.h                           |  332 ++++++
>>  include/uapi/linux/input.h                         |   12 +
>>  46 files changed, 4824 insertions(+), 15 deletions(-)
>>  create mode 100644 Documentation/DocBook/media/v4l/cec-api.xml
>>  create mode 100644 Documentation/DocBook/media/v4l/cec-func-close.xml
>>  create mode 100644 Documentation/DocBook/media/v4l/cec-func-ioctl.xml
>>  create mode 100644 Documentation/DocBook/media/v4l/cec-func-open.xml
>>  create mode 100644 Documentation/DocBook/media/v4l/cec-func-poll.xml
>>  create mode 100644 Documentation/DocBook/media/v4l/cec-ioc-g-adap-log-addrs.xml
>>  create mode 100644 Documentation/DocBook/media/v4l/cec-ioc-g-adap-phys-addr.xml
>>  create mode 100644 Documentation/DocBook/media/v4l/cec-ioc-g-adap-state.xml
>>  create mode 100644 Documentation/DocBook/media/v4l/cec-ioc-g-caps.xml
>>  create mode 100644 Documentation/DocBook/media/v4l/cec-ioc-g-event.xml
>>  create mode 100644 Documentation/DocBook/media/v4l/cec-ioc-g-passthrough.xml
>>  create mode 100644 Documentation/DocBook/media/v4l/cec-ioc-g-vendor-id.xml
>>  create mode 100644 Documentation/DocBook/media/v4l/cec-ioc-receive.xml
>>  create mode 100644 Documentation/cec.txt
>>  create mode 100644 Documentation/devicetree/bindings/media/s5p-cec.txt
>>  create mode 100644 drivers/media/cec.c
>>  create mode 100644 drivers/media/platform/s5p-cec/Makefile
>>  create mode 100644 drivers/media/platform/s5p-cec/exynos_hdmi_cec.h
>>  create mode 100644 drivers/media/platform/s5p-cec/exynos_hdmi_cecctrl.c
>>  create mode 100644 drivers/media/platform/s5p-cec/regs-cec.h
>>  create mode 100644 drivers/media/platform/s5p-cec/s5p_cec.c
>>  create mode 100644 drivers/media/platform/s5p-cec/s5p_cec.h
>>  create mode 100644 drivers/media/rc/keymaps/rc-cec.c
>>  create mode 100644 include/media/cec.h
>>  create mode 100644 include/uapi/linux/cec.h
>>
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-media" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 

^ permalink raw reply	[flat|nested] 30+ messages in thread

end of thread, other threads:[~2015-06-16  7:09 UTC | newest]

Thread overview: 30+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-05-04 17:32 [PATCH v6 00/11] Kamil Debski
2015-05-04 17:32 ` [PATCH v6 01/11] dts: exynos4*: add HDMI CEC pin definition to pinctrl Kamil Debski
2015-05-05  3:59   ` Krzysztof Kozłowski
2015-05-04 17:32 ` [PATCH v6 02/11] dts: exynos4: add node for the HDMI CEC device Kamil Debski
2015-05-05  3:59   ` Krzysztof Kozłowski
2015-05-04 17:32 ` [PATCH v6 03/11] dts: exynos4412-odroid*: enable " Kamil Debski
2015-05-05  4:00   ` Krzysztof Kozłowski
2015-05-04 17:32 ` [PATCH v6 04/11] HID: add HDMI CEC specific keycodes Kamil Debski
2015-05-08 11:00   ` Hans Verkuil
2015-05-04 17:32 ` [PATCH v6 05/11] rc: Add HDMI CEC protoctol handling Kamil Debski
2015-05-08 11:02   ` Hans Verkuil
2015-05-08 11:18     ` Hans Verkuil
2015-05-04 17:32 ` [PATCH v6 06/11] cec: add HDMI CEC framework Kamil Debski
2015-05-08 11:30   ` Hans Verkuil
2015-05-13  8:03   ` Hans Verkuil
2015-05-13  8:28   ` Hans Verkuil
2015-05-13  9:43   ` Hans Verkuil
2015-05-13 11:10   ` Sean Young
2015-05-19 11:03     ` Hans Verkuil
2015-05-04 17:33 ` [PATCH v6 07/11] DocBook/media: add CEC documentation Kamil Debski
2015-05-08 10:45   ` Hans Verkuil
2015-05-04 17:33 ` [PATCH v6 08/11] v4l2-subdev: add HDMI CEC ops Kamil Debski
2015-05-04 17:33 ` [PATCH v6 09/11] cec: adv7604: add cec support Kamil Debski
2015-05-04 17:33 ` [PATCH v6 10/11] cec: adv7511: " Kamil Debski
2015-05-04 17:33 ` [PATCH v6 11/11] cec: s5p-cec: Add s5p-cec driver Kamil Debski
2015-05-04 17:33 ` [PATCH v2] libgencec: Add userspace library for the generic CEC kernel interface Kamil Debski
2015-05-08 10:59   ` Hans Verkuil
2015-05-04 17:34 ` [PATCH v6 00/11] HDMI CEC framework Kamil Debski
2015-06-16  6:22 ` [PATCH v6 00/11] Hans Verkuil
2015-06-16  7:08   ` [PATCH v6 00/11] CEC update Hans Verkuil

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).