All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC v2 0/7] HDMI CEC framework
@ 2015-01-22 16:04 ` Kamil Debski
  0 siblings, 0 replies; 34+ messages in thread
From: Kamil Debski @ 2015-01-22 16:04 UTC (permalink / raw)
  To: dri-devel, linux-media
  Cc: m.szyprowski, k.debski, mchehab, hverkuil, kyungmin.park, thomas, sean

Hi,

This is the second version of my attempt at the CEC framework patches.
As mentioned in the previous cover letter the original work was done by
Hans Verkuil, but he was short of time and the CEC framework was stalled
for some time. The original cover letter attached below will surely shed
more light on the history of these patches.

Thank you very much for your comments to the v1 . It was near the end of the
year when I sent the previous version, so I really appreciate your time.

Apart from fixes and additions to the documentation this version of the RFC
tackles the subject of processing the key down/up from the remote. To make
the solution most flexible there are two modes. In the default the mesages
related to key presses on the remote are parsed and handled by the CEC
framework. In the pass-through mode the key down/up messages are not handled
by the CEC framewrok and are passed to the userspace. The mode can be changed by
an appropriate ioctl. I would especially welcome comment to the CEC keymap.

Best wishes,
Kamil Debski

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

Original cover letter
=====================

Hi,

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 repied that the work stalled due to his
lack of time.

The driver was done in the most part and there were only minor fixes that needed
to be implemented. I would like to bring back the discussion on a common CEC
interface framework.

There are a few things that were still left as TODO, I think they might need
some discussion - for instance the way how the remote controls should be
handled.

Best wishes,
Kamil Debski

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

Hans Verkuil (3):
  v4l2-subdev: add cec ops.
  adv7604: add cec support.
  adv7511: add cec support.

Kamil Debski (4):
  ARM: dts: add hdmi cec driver to exynos4412-odroidu3
  media: rc: Add cec protocol handling
  cec: add new framework for cec support.
  s5p-cec: Add s5p-cec driver

 Documentation/cec.txt                              |  318 ++++++
 arch/arm/boot/dts/exynos4412-odroid-common.dtsi    |    7 +
 arch/arm/boot/dts/exynos4412-odroidu3.dts          |   13 +
 drivers/media/Kconfig                              |    5 +
 drivers/media/Makefile                             |    2 +
 drivers/media/cec.c                                | 1111 ++++++++++++++++++++
 drivers/media/i2c/adv7511.c                        |  325 +++++-
 drivers/media/i2c/adv7604.c                        |  182 ++++
 drivers/media/platform/Kconfig                     |    7 +
 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           |  290 +++++
 drivers/media/platform/s5p-cec/s5p_cec.h           |  113 ++
 drivers/media/rc/keymaps/Makefile                  |    1 +
 drivers/media/rc/keymaps/rc-cec.c                  |  133 +++
 drivers/media/rc/rc-main.c                         |    1 +
 include/media/adv7511.h                            |    6 +-
 include/media/cec.h                                |  136 +++
 include/media/rc-core.h                            |    1 +
 include/media/rc-map.h                             |    5 +-
 include/media/v4l2-subdev.h                        |    8 +
 include/uapi/linux/cec.h                           |  276 +++++
 25 files changed, 3277 insertions(+), 9 deletions(-)
 create mode 100644 Documentation/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] 34+ messages in thread

* [RFC v2 0/7] HDMI CEC framework
@ 2015-01-22 16:04 ` Kamil Debski
  0 siblings, 0 replies; 34+ messages in thread
From: Kamil Debski @ 2015-01-22 16:04 UTC (permalink / raw)
  To: dri-devel, linux-media; +Cc: sean, mchehab, kyungmin.park, thomas, m.szyprowski

Hi,

This is the second version of my attempt at the CEC framework patches.
As mentioned in the previous cover letter the original work was done by
Hans Verkuil, but he was short of time and the CEC framework was stalled
for some time. The original cover letter attached below will surely shed
more light on the history of these patches.

Thank you very much for your comments to the v1 . It was near the end of the
year when I sent the previous version, so I really appreciate your time.

Apart from fixes and additions to the documentation this version of the RFC
tackles the subject of processing the key down/up from the remote. To make
the solution most flexible there are two modes. In the default the mesages
related to key presses on the remote are parsed and handled by the CEC
framework. In the pass-through mode the key down/up messages are not handled
by the CEC framewrok and are passed to the userspace. The mode can be changed by
an appropriate ioctl. I would especially welcome comment to the CEC keymap.

Best wishes,
Kamil Debski

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

Original cover letter
=====================

Hi,

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 repied that the work stalled due to his
lack of time.

The driver was done in the most part and there were only minor fixes that needed
to be implemented. I would like to bring back the discussion on a common CEC
interface framework.

There are a few things that were still left as TODO, I think they might need
some discussion - for instance the way how the remote controls should be
handled.

Best wishes,
Kamil Debski

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

Hans Verkuil (3):
  v4l2-subdev: add cec ops.
  adv7604: add cec support.
  adv7511: add cec support.

Kamil Debski (4):
  ARM: dts: add hdmi cec driver to exynos4412-odroidu3
  media: rc: Add cec protocol handling
  cec: add new framework for cec support.
  s5p-cec: Add s5p-cec driver

 Documentation/cec.txt                              |  318 ++++++
 arch/arm/boot/dts/exynos4412-odroid-common.dtsi    |    7 +
 arch/arm/boot/dts/exynos4412-odroidu3.dts          |   13 +
 drivers/media/Kconfig                              |    5 +
 drivers/media/Makefile                             |    2 +
 drivers/media/cec.c                                | 1111 ++++++++++++++++++++
 drivers/media/i2c/adv7511.c                        |  325 +++++-
 drivers/media/i2c/adv7604.c                        |  182 ++++
 drivers/media/platform/Kconfig                     |    7 +
 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           |  290 +++++
 drivers/media/platform/s5p-cec/s5p_cec.h           |  113 ++
 drivers/media/rc/keymaps/Makefile                  |    1 +
 drivers/media/rc/keymaps/rc-cec.c                  |  133 +++
 drivers/media/rc/rc-main.c                         |    1 +
 include/media/adv7511.h                            |    6 +-
 include/media/cec.h                                |  136 +++
 include/media/rc-core.h                            |    1 +
 include/media/rc-map.h                             |    5 +-
 include/media/v4l2-subdev.h                        |    8 +
 include/uapi/linux/cec.h                           |  276 +++++
 25 files changed, 3277 insertions(+), 9 deletions(-)
 create mode 100644 Documentation/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

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* [RFC v2 1/7] ARM: dts: add hdmi cec driver to exynos4412-odroidu3
  2015-01-22 16:04 ` Kamil Debski
@ 2015-01-22 16:04   ` Kamil Debski
  -1 siblings, 0 replies; 34+ messages in thread
From: Kamil Debski @ 2015-01-22 16:04 UTC (permalink / raw)
  To: dri-devel, linux-media
  Cc: m.szyprowski, k.debski, mchehab, hverkuil, kyungmin.park, thomas, sean

Add device tree node for the s5p-cec hdmi CEC driver.

Signed-off-by: Kamil Debski <k.debski@samsung.com>
---
 arch/arm/boot/dts/exynos4412-odroid-common.dtsi |    7 +++++++
 arch/arm/boot/dts/exynos4412-odroidu3.dts       |   13 +++++++++++++
 2 files changed, 20 insertions(+)

diff --git a/arch/arm/boot/dts/exynos4412-odroid-common.dtsi b/arch/arm/boot/dts/exynos4412-odroid-common.dtsi
index 3fbf588..0aa6664 100644
--- a/arch/arm/boot/dts/exynos4412-odroid-common.dtsi
+++ b/arch/arm/boot/dts/exynos4412-odroid-common.dtsi
@@ -403,4 +403,11 @@
 		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>;
+	};
 };
diff --git a/arch/arm/boot/dts/exynos4412-odroidu3.dts b/arch/arm/boot/dts/exynos4412-odroidu3.dts
index c8a64be..934c9f8 100644
--- a/arch/arm/boot/dts/exynos4412-odroidu3.dts
+++ b/arch/arm/boot/dts/exynos4412-odroidu3.dts
@@ -31,6 +31,19 @@
 			linux,default-trigger = "heartbeat";
 		};
 	};
+
+	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>;
+		cec-gpio = <&gpx3 6 0>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&hdmi_cec>;
+		status = "okay";
+	};
 };
 
 &usb3503 {
-- 
1.7.9.5


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

* [RFC v2 1/7] ARM: dts: add hdmi cec driver to exynos4412-odroidu3
@ 2015-01-22 16:04   ` Kamil Debski
  0 siblings, 0 replies; 34+ messages in thread
From: Kamil Debski @ 2015-01-22 16:04 UTC (permalink / raw)
  To: dri-devel, linux-media; +Cc: sean, mchehab, kyungmin.park, thomas, m.szyprowski

Add device tree node for the s5p-cec hdmi CEC driver.

Signed-off-by: Kamil Debski <k.debski@samsung.com>
---
 arch/arm/boot/dts/exynos4412-odroid-common.dtsi |    7 +++++++
 arch/arm/boot/dts/exynos4412-odroidu3.dts       |   13 +++++++++++++
 2 files changed, 20 insertions(+)

diff --git a/arch/arm/boot/dts/exynos4412-odroid-common.dtsi b/arch/arm/boot/dts/exynos4412-odroid-common.dtsi
index 3fbf588..0aa6664 100644
--- a/arch/arm/boot/dts/exynos4412-odroid-common.dtsi
+++ b/arch/arm/boot/dts/exynos4412-odroid-common.dtsi
@@ -403,4 +403,11 @@
 		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>;
+	};
 };
diff --git a/arch/arm/boot/dts/exynos4412-odroidu3.dts b/arch/arm/boot/dts/exynos4412-odroidu3.dts
index c8a64be..934c9f8 100644
--- a/arch/arm/boot/dts/exynos4412-odroidu3.dts
+++ b/arch/arm/boot/dts/exynos4412-odroidu3.dts
@@ -31,6 +31,19 @@
 			linux,default-trigger = "heartbeat";
 		};
 	};
+
+	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>;
+		cec-gpio = <&gpx3 6 0>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&hdmi_cec>;
+		status = "okay";
+	};
 };
 
 &usb3503 {
-- 
1.7.9.5

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* [RFC v2 2/7] media: rc: Add cec protocol handling
  2015-01-22 16:04 ` Kamil Debski
  (?)
  (?)
@ 2015-01-22 16:04 ` Kamil Debski
  2015-03-08 14:20     ` Mauro Carvalho Chehab
  -1 siblings, 1 reply; 34+ messages in thread
From: Kamil Debski @ 2015-01-22 16:04 UTC (permalink / raw)
  To: dri-devel, linux-media
  Cc: m.szyprowski, k.debski, mchehab, hverkuil, kyungmin.park, thomas, sean

Add cec protocol handling the RC framework.

Signed-off-by: Kamil Debski <k.debski@samsung.com>
---
 drivers/media/rc/keymaps/Makefile |    1 +
 drivers/media/rc/keymaps/rc-cec.c |  133 +++++++++++++++++++++++++++++++++++++
 drivers/media/rc/rc-main.c        |    1 +
 include/media/rc-core.h           |    1 +
 include/media/rc-map.h            |    5 +-
 5 files changed, 140 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..f2826c5
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-cec.c
@@ -0,0 +1,133 @@
+/* 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_SELECT }, /* XXX CEC Spec: Select, should it be KEY_SELECT or KEY_OK? */
+	{ 0x01, KEY_UP },
+	{ 0x02, KEY_DOWN },
+	{ 0x03, KEY_LEFT },
+	{ 0x04, KEY_RIGHT },
+	/* XXX 0x05-0x08 CEC Spec: Right-Up, Right-Down, Left-Up, 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_0 },
+	{ 0x21, KEY_1 },
+	{ 0x22, KEY_2 },
+	{ 0x23, KEY_3 },
+	{ 0x24, KEY_4 },
+	{ 0x25, KEY_5 },
+	{ 0x26, KEY_6 },
+	{ 0x27, KEY_7 },
+	{ 0x28, KEY_8 },
+	{ 0x29, KEY_9 },
+	{ 0x2a, KEY_DOT },
+	{ 0x2b, KEY_ENTER },
+	{ 0x2c, KEY_CLEAR },
+	/* 0x2d-0x2e: Reserved */
+	/* XXX 0x2f: CEC Spec: Next Favorite */
+	{ 0x30, KEY_CHANNELUP },
+	{ 0x31, KEY_CHANNELDOWN },
+	{ 0x32, KEY_PREVIOUS }, /* CEC Spec: Previous Channel */
+	{ 0x33, KEY_SOUND }, /* CEC Spec: Sound Select */
+	/* XXX 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 }, /* XXX CEC Spec: Stop, what about KEY_STOPCD? */
+	{ 0x46, KEY_PAUSE },/* XXX CEC Spec: Pause, what about KEY_PAUSECD? */
+	{ 0x47, KEY_RECORD },
+	{ 0x48, KEY_REWIND },
+	{ 0x49, KEY_FASTFORWARD },
+	{ 0x4a, KEY_EJECTCD }, /* CEC Spec: Eject */
+	{ 0x4b, KEY_FORWARD },
+	{ 0x4c, }, /* XXX */
+	{ 0x4d, KEY_STOP }, /* XXX CEC Spec: Stop-Record, what about KEY_STOPCD? */
+	{ 0x4e, KEY_PAUSE }, /* XXX CEC Spec: Pause-Record, what about KEY_PAUSECD? */
+	/* 0x4f: Reserved */
+	{ 0x50, KEY_ANGLE },
+	{ 0x51, KEY_SUBTITLE }, /* XXX CEC Spec: Sub picture, should it be KEY_SUBTITLE or something else? */
+	{ 0x52, KEY_VIDEO }, /* XXX CEC Spec: Video on Demand / input.h: AL Movie Browser, maybe KEY_DIRECTORY? */
+	{ 0x53, KEY_EPG },
+	{ 0x54, KEY_TIME }, /* XXX CEC Spec: Timer */
+	{ 0x55, KEY_CONFIG },
+	/* 0x56-0x5f: Reserved */
+	{ 0x60, KEY_PLAY }, /* XXX CEC Spec: Play Function */
+	{ 0x61, KEY_PLAYPAUSE }, /* XXX CEC Spec: Pause-Play Function */
+	{ 0x62, KEY_RECORD }, /* XXX CEC Spec: Record Function */
+	{ 0x63, KEY_PAUSE }, /* XXX CEC Spec: Pause-Record Function */
+	{ 0x64, KEY_STOP }, /* XXX CEC Spec: Stop Function */
+	{ 0x65, KEY_MUTE }, /* XXX CEC Spec: Mute Function */
+	/* 0x66: CEC Spec: Restore Volume Function */
+	{ 0x67, KEY_TUNER }, /* XXX CEC Spec: Tune Function */
+	{ 0x68, KEY_MEDIA }, /* CEC Spec: Select Media Function */
+	{ 0x69, KEY_SWITCHVIDEOMODE} /* XXX CEC Spec: Select A/V Input Function */,
+	{ 0x6a, KEY_AUDIO} /* CEC Spec: Select Audio Input Function */,
+	{ 0x6b, KEY_POWER} /* CEC Spec: Power Toggle Function */,
+	{ 0x6c, KEY_SLEEP} /* XXX CEC Spec: Power Off Function */,
+	{ 0x6d, KEY_WAKEUP} /* XXX CEC Spec: Power On Function */,
+	/* 0x6e-0x70: Reserved */
+	{ 0x71, KEY_BLUE }, /* XXX CEC Spec: F1 (Blue) */
+	{ 0x72, KEY_RED }, /* XXX CEC Spec: F2 (Red) */
+	{ 0x73, KEY_GREEN }, /* XXX CEC Spec: F3 (Green) */
+	{ 0x74, KEY_YELLOW }, /* XXX CEC Spec: F4 (Yellow) */
+	{ 0x75, KEY_F5 },
+	{ 0x76, KEY_CONNECT }, /* XXX 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] 34+ messages in thread

* [RFC v2 3/7] cec: add new framework for cec support.
  2015-01-22 16:04 ` Kamil Debski
                   ` (2 preceding siblings ...)
  (?)
@ 2015-01-22 16:04 ` Kamil Debski
  2015-01-23 11:07   ` Sean Young
  -1 siblings, 1 reply; 34+ messages in thread
From: Kamil Debski @ 2015-01-22 16:04 UTC (permalink / raw)
  To: dri-devel, linux-media
  Cc: m.szyprowski, k.debski, mchehab, hverkuil, kyungmin.park, thomas,
	sean, Hans Verkuil

Add the CEC framework.

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]
[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]
---
 Documentation/cec.txt    |  318 +++++++++++++
 drivers/media/Kconfig    |    5 +
 drivers/media/Makefile   |    2 +
 drivers/media/cec.c      | 1111 ++++++++++++++++++++++++++++++++++++++++++++++
 include/media/cec.h      |  136 ++++++
 include/uapi/linux/cec.h |  276 ++++++++++++
 6 files changed, 1848 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..8a04be3
--- /dev/null
+++ b/Documentation/cec.txt
@@ -0,0 +1,318 @@
+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 cosumer 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 physicall addressis determined by 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 Adaptor
+-----------
+
+#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);
+
+	int (*received_tv)(struct cec_adapter *adap, struct cec_msg *msg);
+	int (*received_record)(struct cec_adapter *adap, struct cec_msg *msg);
+	int (*received_tuner)(struct cec_adapter *adap, struct cec_msg *msg);
+	int (*received_playback)(struct cec_adapter *adap, struct cec_msg *msg);
+	int (*received_audiosystem)(struct cec_adapter *adap, struct cec_msg *msg);
+	int (*received_switch)(struct cec_adapter *adap, struct cec_msg *msg);
+	int (*received_videoproc)(struct cec_adapter *adap, struct cec_msg *msg);
+	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_adap_transmit_done(struct cec_adapter *adap, u32 status);
+void cec_adap_received_msg(struct cec_adapter *adap, struct cec_msg *msg);
+
+
+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 corresponding received() op is called depending
+on the logical address it is received on. If the message is not handled by
+that the received op is called as fallback. The driver can hook into these ops
+and do whatever it needs to do in order to respond to the message.
+
+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 CEC adapter has
+to be informed for which CEC device types a logical address has to be found.
+The CEC framework will attempt to find such logical addresses. If none are
+found, then it will fall back to logical address Unregistered (15).
+
+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.
+
+
+The Userspace API
+=================
+
+CEC communication
+-----------------
+
+This is the main message struct:
+
+struct cec_msg {
+	__u32 len;
+	__u8  msg[16];
+	__u32 status;
+	/* 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).
+	 */
+	__u8  reply;
+	/* timeout (in ms) is used to timeout CEC_RECEIVE.
+	   Set to 0 if you want to wait forever. */
+	__u32 timeout;
+	struct timespec ts;
+};
+
+16 bytes for the message, the length of the message, a status value
+in case of errors. Optionally you can request the CEC framework to
+wait after transmitting the message until the 'reply' message is
+returned (or Feature Abort). This is done asynchronously, i.e. it
+does not require that the reply comes right after the transmit, but
+other messages in between are allowed.
+
+#define CEC_TRANSMIT		_IOWR('a', 1, struct cec_msg)
+#define CEC_RECEIVE		_IOWR('a', 2, struct cec_msg)
+
+With CEC_TRANSMIT you can transmit a message, either blocking or
+non-blocking. With CEC_RECEIVE you can dequeue a pending received
+message from the internal queue or wait for a message to arrive
+(if called in blocking mode).
+
+
+/* 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)
+
+struct cec_caps {
+	__u32 available_log_addrs;
+	__u32 capabilities;
+};
+
+#define CEC_G_CAPS			_IOR('a', 0, struct cec_caps)
+
+Obtain some of the CEC adapter capabilities: the number of logical addresses
+that the adapter can configure and what can be controlled from userspace.
+
+/*
+   Enable/disable the adapter. The S_ADAP_STATE ioctl is not available
+   unless CEC_CAP_STATE is set.
+ */
+#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 S_ADAP_PHYS_ADDR ioctl is not available unless CEC_CAP_PHYS_ADDR
+   is set.
+ */
+#define CEC_G_ADAP_PHYS_ADDR	_IOR('a', 7, __u16)
+#define CEC_S_ADAP_PHYS_ADDR	_IOW('a', 8, __u16)
+
+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];
+};
+
+/*
+   Configure the CEC adapter.
+
+   The cec_version determines which CEC version should be followed.
+
+   It will try to claim num_log_addrs devices. The log_addr_type array has
+   the logical address type that needs to be claimed for that device, and
+   the log_addr array will receive the actual logical address that was
+   claimed for that device or 0xff if no address could be claimed.
+
+   The primary_device_type contains the primary device for each logical
+   address.
+
+   For CEC 2.0 devices the all_device_types parameter to use with the
+   Report Features command, and 'features' contains the remaining parameters
+   (RC Profile and Device Features) to use in Report Features.
+
+   An error is returned if the adapter is disabled or if there
+   is no physical address assigned or if cec_version is unknown.
+
+   If no logical address of one or more of the given types could be claimed,
+   then log_addr will be set to CEC_LOG_ADDR_INVALID.
+
+   If no logical address could be claimed at all, then num_log_addrs will
+   be set to 1, log_addr_type[0] to UNREGISTERED and log_addr[0] to 0xf.
+
+   The S_ADAP_LOG_ADDRS ioctl is not available unless CEC_CAP_LOG_ADDRS
+   is set.
+ */
+#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)
+
+The event ioctl is used to get a single struct cec_event if it was
+previously posted by the driver by the cec_post_event function.
+
+#define CEC_G_EVENT		_IOWR('a', 9, struct cec_event)
+
+Remote control handling
+-----------------------
+
+The CEC framework provides two ways of handling the key messages of remote
+control. In the first case, the CEC framework will handle these messages and
+provide the keypressed via the RC framework. In the second case the messages
+related to the key down/up events are not parsed by the framework and are
+passed to the userspace as raw messages.
+
+Switching between these modes is done with a special ioctl.
+
+#define CEC_G_KEY_PASSTHROUGH	_IOR('a', 10, __u8)
+#define CEC_S_KEY_PASSTHROUGH	_IOW('a', 11, __u8)
+#define CEC_KEY_PASSTHROUGH_DISABLE	0
+#define CEC_KEY_PASSTHROUGH_ENABLE	1
+
diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig
index 49cd308..e0653a1 100644
--- a/drivers/media/Kconfig
+++ b/drivers/media/Kconfig
@@ -15,6 +15,11 @@ if MEDIA_SUPPORT
 
 comment "Multimedia core support"
 
+config CEC
+	tristate "CEC API (EXPERIMENTAL)"
+	---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..7a2d081
--- /dev/null
+++ b/drivers/media/cec.c
@@ -0,0 +1,1111 @@
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/kmod.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;
+	memset(&msg->ts, 0, sizeof(msg->ts));
+	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);
+	}
+	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;
+		ktime_get_ts(&msg->ts);
+		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)
+		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;
+	}
+
+	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:
+		if (adap->key_passthrough != CEC_KEY_PASSTHROUGH_ENABLE) {
+			rc_keydown(adap->rc, RC_TYPE_CEC, msg->msg[2], 0);
+			return 0;
+		}
+		break;
+
+	case CEC_OP_USER_CONTROL_RELEASED:
+		if (adap->key_passthrough != CEC_KEY_PASSTHROUGH_ENABLE) {
+			rc_keyup(adap->rc);
+			return 0;
+		}
+		break;
+	}
+
+	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)
+{
+	bool is_reply = false;
+
+	mutex_lock(&adap->lock);
+	ktime_get_ts(&msg->ts);
+	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 = &adap->tx_queue[adap->tx_qstart].msg;
+
+		if (msg->msg[1] == dst->reply ||
+		    msg->msg[1] == CEC_OP_FEATURE_ABORT) {
+			*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)
+		adap->recv_notifier(adap, msg);
+}
+EXPORT_SYMBOL_GPL(cec_received_msg);
+
+void cec_post_event(struct cec_adapter *adap, u32 event)
+{
+	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;
+	ktime_get_ts(&adap->ev_queue[idx].ts);
+	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);
+	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 == 0 ||
+	    log_addrs->num_log_addrs > CEC_MAX_LOG_ADDRS)
+		return -EINVAL;
+	if (log_addrs->cec_version != CEC_VERSION_1_4B &&
+	    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);
+		kfree(cla_int);
+	}
+	return 0;
+}
+EXPORT_SYMBOL_GPL(cec_claim_log_addrs);
+
+static ssize_t cec_read(struct file *filp, char __user *buf,
+		size_t sz, loff_t *off)
+{
+	struct cec_devnode *cecdev = cec_devnode_data(filp);
+
+	if (!cec_devnode_is_registered(cecdev))
+		return -EIO;
+	return 0;
+}
+
+static ssize_t cec_write(struct file *filp, const char __user *buf,
+		size_t sz, loff_t *off)
+{
+	struct cec_devnode *cecdev = cec_devnode_data(filp);
+
+	if (!cec_devnode_is_registered(cecdev))
+		return -EIO;
+	return 0;
+}
+
+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;
+	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;
+		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, true);
+		if (err)
+			return err;
+
+		if (copy_to_user(parg, &log_addrs, sizeof(log_addrs)))
+			return -EFAULT;
+		break;
+	}
+
+	case CEC_G_KEY_PASSTHROUGH: {
+		if (put_user(adap->key_passthrough, (__u8 __user *)parg))
+			return -EFAULT;
+		break;
+	}
+
+	case CEC_S_KEY_PASSTHROUGH: {
+		__u8 state;
+		if (get_user(state, (__u8 __user *)parg))
+			return -EFAULT;
+		if (state != CEC_KEY_PASSTHROUGH_DISABLE &&
+		    state != CEC_KEY_PASSTHROUGH_ENABLE)
+			return -EINVAL;
+		adap->key_passthrough = state;
+		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,
+	.read = cec_read,
+	.write = cec_write,
+	.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_4B;
+	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->priv = adap;
+	adap->rc->map_name = RC_MAP_CEC;
+	adap->rc->timeout = MS_TO_NS(100);
+	adap->rc->allowed_protocols = RC_BIT_CEC;
+	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..ff21e22
--- /dev/null
+++ b/include/media/cec.h
@@ -0,0 +1,136 @@
+#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;
+};
+
+/* 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	(16)
+
+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;
+	u8 version;
+	u8 num_log_addrs;
+	u8 key_passthrough;
+	u8 prim_device[CEC_MAX_LOG_ADDRS];
+	u8 log_addr_type[CEC_MAX_LOG_ADDRS];
+	u8 log_addr[CEC_MAX_LOG_ADDRS];
+
+	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);
+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/cec.h b/include/uapi/linux/cec.h
new file mode 100644
index 0000000..e2ea190
--- /dev/null
+++ b/include/uapi/linux/cec.h
@@ -0,0 +1,276 @@
+#ifndef _CEC_H
+#define _CEC_H
+
+#include <linux/types.h>
+
+struct cec_msg {
+	__u32 len;
+	__u8  msg[16];
+	__u32 status;
+	/* 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).
+	 */
+	__u8  reply;
+	/* timeout (in ms) is used to timeout CEC_RECEIVE.
+	   Set to 0 if you want to wait forever. */
+	__u32 timeout;
+	struct timespec ts;
+};
+
+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_4B		5
+#define CEC_VERSION_2_0			6
+
+struct cec_event {
+	__u32 event;
+	struct timespec ts;
+};
+
+/* 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)
+
+struct cec_caps {
+	__u32 available_log_addrs;
+	__u32 capabilities;
+};
+
+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];
+};
+
+/* 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
+
+/* 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
+
+/* ioctls */
+
+#define CEC_EVENT_READY		1
+#define CEC_EVENT_DISCONNECT	2
+
+/* 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)
+
+#define CEC_G_KEY_PASSTHROUGH	_IOR('a', 10, __u8)
+#define CEC_S_KEY_PASSTHROUGH	_IOW('a', 11, __u8)
+#define CEC_KEY_PASSTHROUGH_DISABLE	0
+#define CEC_KEY_PASSTHROUGH_ENABLE	1
+
+#endif
-- 
1.7.9.5


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

* [RFC v2 4/7] v4l2-subdev: add cec ops.
  2015-01-22 16:04 ` Kamil Debski
                   ` (3 preceding siblings ...)
  (?)
@ 2015-01-22 16:04 ` Kamil Debski
  -1 siblings, 0 replies; 34+ messages in thread
From: Kamil Debski @ 2015-01-22 16:04 UTC (permalink / raw)
  To: dri-devel, linux-media
  Cc: m.szyprowski, k.debski, mchehab, hverkuil, kyungmin.park, thomas,
	sean, 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 5beeb87..fdf620d 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 {
@@ -354,6 +358,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] 34+ messages in thread

* [RFC v2 5/7] adv7604: add cec support.
  2015-01-22 16:04 ` Kamil Debski
@ 2015-01-22 16:04   ` Kamil Debski
  -1 siblings, 0 replies; 34+ messages in thread
From: Kamil Debski @ 2015-01-22 16:04 UTC (permalink / raw)
  To: dri-devel, linux-media
  Cc: m.szyprowski, k.debski, mchehab, hverkuil, kyungmin.park, thomas,
	sean, Hans Verkuil

From: Hans Verkuil <hansverk@cisco.com>

Add CEC support ot the adv7604 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/adv7604.c |  182 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 182 insertions(+)

diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c
index e43dd2e..f0ea929 100644
--- a/drivers/media/i2c/adv7604.c
+++ b/drivers/media/i2c/adv7604.c
@@ -42,6 +42,7 @@
 #include <media/v4l2-device.h>
 #include <media/v4l2-dv-timings.h>
 #include <media/v4l2-of.h>
+#include <media/cec.h>
 
 static int debug;
 module_param(debug, int, 0644);
@@ -158,6 +159,10 @@ struct adv7604_state {
 	u16 spa_port_a[2];
 	struct v4l2_fract aspect_ratio;
 	u32 rgb_quantization_range;
+	u8   cec_addr[3];
+	u8   cec_valid_addrs;
+	bool cec_enabled_adap;
+
 	struct workqueue_struct *work_queues;
 	struct delayed_work delayed_work_enable_hotplug;
 	bool restart_stdi_once;
@@ -1935,6 +1940,176 @@ static int adv7604_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
 	return 0;
 }
 
+static void adv7604_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 adv7604_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);
+	adv7604_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 adv7604_cec_enable(struct v4l2_subdev *sd, bool enable)
+{
+	struct adv7604_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) {
+		io_write_and_or(sd, 0x50, 0xf0, 0x00);  /* disable cec interrupts */
+		cec_write_and_or(sd, 0x27, 0x8f, 0x70); /* disable address mask 1-3 */
+		cec_write_and_or(sd, 0x2a, 0xfe, 0x00); /* power down cec section */
+		state->cec_valid_addrs = 0;
+	}
+	state->cec_enabled_adap = enable;
+	return 0;
+}
+
+#define ADV7604_MAX_ADDRS (3)
+
+static int adv7604_cec_log_addr(struct v4l2_subdev *sd, u8 addr)
+{
+	struct adv7604_state *state = to_state(sd);
+	unsigned i, free_idx = ADV7604_MAX_ADDRS;
+	
+	if (!state->cec_enabled_adap)
+		return -EIO;
+
+	for (i = 0; i < ADV7604_MAX_ADDRS; i++) {
+		bool is_valid = state->cec_valid_addrs & (1 << i);
+
+		if (free_idx == ADV7604_MAX_ADDRS && !is_valid)
+			free_idx = i;
+		if (is_valid && state->cec_addr[i] == addr)
+			return 0;
+	}
+	if (i == ADV7604_MAX_ADDRS) {
+		i = free_idx;
+		if (i == ADV7604_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 adv7604_cec_transmit(struct v4l2_subdev *sd, struct cec_msg *msg)
+{
+	u8 len = msg->len;
+	unsigned i;
+
+	if (len == 1)
+		cec_write_and_or(sd, 0x12, 0xf8, 1);  /* allow for one retry for polling */
+	else
+		cec_write_and_or(sd, 0x12, 0xf8, 3);  /* allow for three retries */
+
+	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 adv7604_cec_transmit_timed_out(struct v4l2_subdev *sd)
+{
+	cec_write_and_or(sd, 0x11, 0xfe, 0);  /* disable tx */
+}
+
 static int adv7604_isr(struct v4l2_subdev *sd, u32 status, bool *handled)
 {
 	struct adv7604_state *state = to_state(sd);
@@ -1980,6 +2155,9 @@ static int adv7604_isr(struct v4l2_subdev *sd, u32 status, bool *handled)
 			*handled = true;
 	}
 
+ 	/* cec */
+ 	adv7604_cec_isr(sd, handled);
+
 	/* tx 5v detect */
 	tx_5v = io_read(sd, 0x70) & info->cable_det_mask;
 	if (tx_5v) {
@@ -2374,6 +2552,10 @@ static const struct v4l2_subdev_video_ops adv7604_video_ops = {
 	.s_dv_timings = adv7604_s_dv_timings,
 	.g_dv_timings = adv7604_g_dv_timings,
 	.query_dv_timings = adv7604_query_dv_timings,
+	.cec_enable = adv7604_cec_enable,
+	.cec_log_addr = adv7604_cec_log_addr,
+	.cec_transmit = adv7604_cec_transmit,
+	.cec_transmit_timed_out = adv7604_cec_transmit_timed_out,
 };
 
 static const struct v4l2_subdev_pad_ops adv7604_pad_ops = {
-- 
1.7.9.5


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

* [RFC v2 5/7] adv7604: add cec support.
@ 2015-01-22 16:04   ` Kamil Debski
  0 siblings, 0 replies; 34+ messages in thread
From: Kamil Debski @ 2015-01-22 16:04 UTC (permalink / raw)
  To: dri-devel, linux-media
  Cc: Hans Verkuil, sean, mchehab, kyungmin.park, thomas, m.szyprowski

From: Hans Verkuil <hansverk@cisco.com>

Add CEC support ot the adv7604 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/adv7604.c |  182 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 182 insertions(+)

diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c
index e43dd2e..f0ea929 100644
--- a/drivers/media/i2c/adv7604.c
+++ b/drivers/media/i2c/adv7604.c
@@ -42,6 +42,7 @@
 #include <media/v4l2-device.h>
 #include <media/v4l2-dv-timings.h>
 #include <media/v4l2-of.h>
+#include <media/cec.h>
 
 static int debug;
 module_param(debug, int, 0644);
@@ -158,6 +159,10 @@ struct adv7604_state {
 	u16 spa_port_a[2];
 	struct v4l2_fract aspect_ratio;
 	u32 rgb_quantization_range;
+	u8   cec_addr[3];
+	u8   cec_valid_addrs;
+	bool cec_enabled_adap;
+
 	struct workqueue_struct *work_queues;
 	struct delayed_work delayed_work_enable_hotplug;
 	bool restart_stdi_once;
@@ -1935,6 +1940,176 @@ static int adv7604_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
 	return 0;
 }
 
+static void adv7604_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 adv7604_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);
+	adv7604_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 adv7604_cec_enable(struct v4l2_subdev *sd, bool enable)
+{
+	struct adv7604_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) {
+		io_write_and_or(sd, 0x50, 0xf0, 0x00);  /* disable cec interrupts */
+		cec_write_and_or(sd, 0x27, 0x8f, 0x70); /* disable address mask 1-3 */
+		cec_write_and_or(sd, 0x2a, 0xfe, 0x00); /* power down cec section */
+		state->cec_valid_addrs = 0;
+	}
+	state->cec_enabled_adap = enable;
+	return 0;
+}
+
+#define ADV7604_MAX_ADDRS (3)
+
+static int adv7604_cec_log_addr(struct v4l2_subdev *sd, u8 addr)
+{
+	struct adv7604_state *state = to_state(sd);
+	unsigned i, free_idx = ADV7604_MAX_ADDRS;
+	
+	if (!state->cec_enabled_adap)
+		return -EIO;
+
+	for (i = 0; i < ADV7604_MAX_ADDRS; i++) {
+		bool is_valid = state->cec_valid_addrs & (1 << i);
+
+		if (free_idx == ADV7604_MAX_ADDRS && !is_valid)
+			free_idx = i;
+		if (is_valid && state->cec_addr[i] == addr)
+			return 0;
+	}
+	if (i == ADV7604_MAX_ADDRS) {
+		i = free_idx;
+		if (i == ADV7604_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 adv7604_cec_transmit(struct v4l2_subdev *sd, struct cec_msg *msg)
+{
+	u8 len = msg->len;
+	unsigned i;
+
+	if (len == 1)
+		cec_write_and_or(sd, 0x12, 0xf8, 1);  /* allow for one retry for polling */
+	else
+		cec_write_and_or(sd, 0x12, 0xf8, 3);  /* allow for three retries */
+
+	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 adv7604_cec_transmit_timed_out(struct v4l2_subdev *sd)
+{
+	cec_write_and_or(sd, 0x11, 0xfe, 0);  /* disable tx */
+}
+
 static int adv7604_isr(struct v4l2_subdev *sd, u32 status, bool *handled)
 {
 	struct adv7604_state *state = to_state(sd);
@@ -1980,6 +2155,9 @@ static int adv7604_isr(struct v4l2_subdev *sd, u32 status, bool *handled)
 			*handled = true;
 	}
 
+ 	/* cec */
+ 	adv7604_cec_isr(sd, handled);
+
 	/* tx 5v detect */
 	tx_5v = io_read(sd, 0x70) & info->cable_det_mask;
 	if (tx_5v) {
@@ -2374,6 +2552,10 @@ static const struct v4l2_subdev_video_ops adv7604_video_ops = {
 	.s_dv_timings = adv7604_s_dv_timings,
 	.g_dv_timings = adv7604_g_dv_timings,
 	.query_dv_timings = adv7604_query_dv_timings,
+	.cec_enable = adv7604_cec_enable,
+	.cec_log_addr = adv7604_cec_log_addr,
+	.cec_transmit = adv7604_cec_transmit,
+	.cec_transmit_timed_out = adv7604_cec_transmit_timed_out,
 };
 
 static const struct v4l2_subdev_pad_ops adv7604_pad_ops = {
-- 
1.7.9.5

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* [RFC v2 6/7] adv7511: add cec support.
  2015-01-22 16:04 ` Kamil Debski
                   ` (5 preceding siblings ...)
  (?)
@ 2015-01-22 16:04 ` Kamil Debski
  -1 siblings, 0 replies; 34+ messages in thread
From: Kamil Debski @ 2015-01-22 16:04 UTC (permalink / raw)
  To: dri-devel, linux-media
  Cc: m.szyprowski, k.debski, mchehab, hverkuil, kyungmin.park, thomas,
	sean, 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 |  325 ++++++++++++++++++++++++++++++++++++++++++-
 include/media/adv7511.h     |    6 +-
 2 files changed, 323 insertions(+), 8 deletions(-)

diff --git a/drivers/media/i2c/adv7511.c b/drivers/media/i2c/adv7511.c
index 81736aa..63ec6c1 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,33 @@ 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 +415,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 +447,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 +472,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 +541,20 @@ 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 +610,132 @@ 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) {
+		cec_write_and_or(sd, 0x4e, 0xfc, 0x01); /* power up cec section */
+		cec_write(sd, 0x4a, 0x07); /* legacy mode and clear all rx buffers */
+		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);
+		cec_write_and_or(sd, 0x4b, 0x8f, 0x00); /* disable address mask 1-3 */
+		cec_write_and_or(sd, 0x4e, 0xfc, 0x00); /* power down cec section */
+		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 +761,76 @@ 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 +934,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 ------------------------------ */
@@ -1078,6 +1319,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__);
 }
@@ -1218,10 +1460,38 @@ 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);
@@ -1267,6 +1537,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
@@ -1288,11 +1564,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,
@@ -1304,6 +1583,24 @@ 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)
@@ -1391,7 +1688,24 @@ static int adv7511_probe(struct i2c_client *client, const struct i2c_device_id *
 		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");
@@ -1410,6 +1724,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);
@@ -1433,6 +1750,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] 34+ messages in thread

* [RFC v2 7/7] s5p-cec: Add s5p-cec driver
  2015-01-22 16:04 ` Kamil Debski
                   ` (6 preceding siblings ...)
  (?)
@ 2015-01-22 16:04 ` Kamil Debski
  -1 siblings, 0 replies; 34+ messages in thread
From: Kamil Debski @ 2015-01-22 16:04 UTC (permalink / raw)
  To: dri-devel, linux-media
  Cc: m.szyprowski, k.debski, mchehab, hverkuil, kyungmin.park, thomas, sean

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>
---
 drivers/media/platform/Kconfig                     |    7 +
 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           |  290 ++++++++++++++++++++
 drivers/media/platform/s5p-cec/s5p_cec.h           |  113 ++++++++
 8 files changed, 756 insertions(+)
 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/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig
index 71e8873..4d199ac 100644
--- a/drivers/media/platform/Kconfig
+++ b/drivers/media/platform/Kconfig
@@ -156,6 +156,13 @@ config VIDEO_MEM2MEM_DEINTERLACE
 	help
 	    Generic deinterlacing V4L2 driver.
 
+config VIDEO_SAMSUNG_S5P_CEC
+	tristate "Samsung S5P CEC driver"
+	depends on VIDEO_DEV && VIDEO_V4L2 && (PLAT_S5P || ARCH_EXYNOS)
+	default n
+	---help---
+	  This is a v4l2 driver for Samsung S5P HDMI CEC interface.
+
 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 3ec1547..17be832 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..65fe55e
--- /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_err(cec->dev, "Broadcast");
+		reg |= S5P_CEC_TX_CTRL_BCAST;
+	} else {
+		dev_err(cec->dev, "No Broadcast");
+		reg &= ~S5P_CEC_TX_CTRL_BCAST;
+	}
+
+	reg |= 0x50;
+	writeb(reg, cec->reg + S5P_CEC_TX_CTRL);
+	dev_err(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_err(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..e8869a6
--- /dev/null
+++ b/drivers/media/platform/s5p-cec/s5p_cec.c
@@ -0,0 +1,290 @@
+/* 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_gpio.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;
+
+	printk(KERN_ERR "%s:%s:%d enable=%s\n", __FILE__, __func__, __LINE__, (enable?"true":"false"));
+
+	if (enable) {
+		/* TODO get physical address from edid */
+		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_err(cec->dev, "CEC_STATUS_TX_ERROR set\n");
+			cec->tx = STATE_ERROR;
+		} else {
+			dev_err(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->gpio = of_get_named_gpio(dev->of_node, "cec-gpio", 0);
+	if (IS_ERR_VALUE(cec->gpio))
+		return cec->gpio;
+
+	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, IRQF_DISABLED, 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..0c082f0
--- /dev/null
+++ b/drivers/media/platform/s5p-cec/s5p_cec.h
@@ -0,0 +1,113 @@
+/* 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/delay.h>
+#include <linux/fs.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/timer.h>
+#include <linux/v4l2-dv-timings.h>
+#include <linux/version.h>
+#include <linux/videodev2.h>
+#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>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/v4l2-of.h>
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include "regs-cec.h"
+*/
+//#include "exynos_hdmi_cec.h"
+
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of_gpio.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			gpio;
+	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] 34+ messages in thread

* Re: [RFC v2 3/7] cec: add new framework for cec support.
  2015-01-22 16:04 ` [RFC v2 3/7] cec: add new framework for cec support Kamil Debski
@ 2015-01-23 11:07   ` Sean Young
  2015-01-26  8:41     ` Hans Verkuil
  2015-03-06 16:14       ` Kamil Debski
  0 siblings, 2 replies; 34+ messages in thread
From: Sean Young @ 2015-01-23 11:07 UTC (permalink / raw)
  To: Kamil Debski
  Cc: dri-devel, linux-media, m.szyprowski, mchehab, hverkuil,
	kyungmin.park, thomas, Hans Verkuil

On Thu, Jan 22, 2015 at 05:04:35PM +0100, Kamil Debski wrote:
> Add the CEC framework.
-snip-
> +Remote control handling
> +-----------------------
> +
> +The CEC framework provides two ways of handling the key messages of remote
> +control. In the first case, the CEC framework will handle these messages and
> +provide the keypressed via the RC framework. In the second case the messages
> +related to the key down/up events are not parsed by the framework and are
> +passed to the userspace as raw messages.
> +
> +Switching between these modes is done with a special ioctl.
> +
> +#define CEC_G_KEY_PASSTHROUGH	_IOR('a', 10, __u8)
> +#define CEC_S_KEY_PASSTHROUGH	_IOW('a', 11, __u8)
> +#define CEC_KEY_PASSTHROUGH_DISABLE	0
> +#define CEC_KEY_PASSTHROUGH_ENABLE	1

This is ugly. This ioctl stops keypresses from going to rc-core. The cec 
device is still registered with rc-core but no keys will be passed to it. 
This could also be handled by loading an empty keymap; this way the input 
layer will still receive scancodes but no keypresses.

> +static ssize_t cec_read(struct file *filp, char __user *buf,
> +		size_t sz, loff_t *off)
> +{
> +	struct cec_devnode *cecdev = cec_devnode_data(filp);
> +
> +	if (!cec_devnode_is_registered(cecdev))
> +		return -EIO;
> +	return 0;
> +}
> +
> +static ssize_t cec_write(struct file *filp, const char __user *buf,
> +		size_t sz, loff_t *off)
> +{
> +	struct cec_devnode *cecdev = cec_devnode_data(filp);
> +
> +	if (!cec_devnode_is_registered(cecdev))
> +		return -EIO;
> +	return 0;
> +}

Both read and write do nothing; they should either -ENOSYS or the fuctions
should be removed.


Sean

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

* Re: [RFC v2 3/7] cec: add new framework for cec support.
  2015-01-23 11:07   ` Sean Young
@ 2015-01-26  8:41     ` Hans Verkuil
  2015-03-06 16:14       ` Kamil Debski
  1 sibling, 0 replies; 34+ messages in thread
From: Hans Verkuil @ 2015-01-26  8:41 UTC (permalink / raw)
  To: Sean Young, Kamil Debski
  Cc: dri-devel, linux-media, m.szyprowski, mchehab, kyungmin.park,
	thomas, Hans Verkuil

On 01/23/2015 12:07 PM, Sean Young wrote:
> On Thu, Jan 22, 2015 at 05:04:35PM +0100, Kamil Debski wrote:
>> Add the CEC framework.
> -snip-
>> +Remote control handling
>> +-----------------------
>> +
>> +The CEC framework provides two ways of handling the key messages of remote
>> +control. In the first case, the CEC framework will handle these messages and
>> +provide the keypressed via the RC framework. In the second case the messages
>> +related to the key down/up events are not parsed by the framework and are
>> +passed to the userspace as raw messages.
>> +
>> +Switching between these modes is done with a special ioctl.
>> +
>> +#define CEC_G_KEY_PASSTHROUGH	_IOR('a', 10, __u8)
>> +#define CEC_S_KEY_PASSTHROUGH	_IOW('a', 11, __u8)
>> +#define CEC_KEY_PASSTHROUGH_DISABLE	0
>> +#define CEC_KEY_PASSTHROUGH_ENABLE	1
> 
> This is ugly. This ioctl stops keypresses from going to rc-core. The cec 
> device is still registered with rc-core but no keys will be passed to it. 
> This could also be handled by loading an empty keymap; this way the input 
> layer will still receive scancodes but no keypresses.
> 
>> +static ssize_t cec_read(struct file *filp, char __user *buf,
>> +		size_t sz, loff_t *off)
>> +{
>> +	struct cec_devnode *cecdev = cec_devnode_data(filp);
>> +
>> +	if (!cec_devnode_is_registered(cecdev))
>> +		return -EIO;
>> +	return 0;
>> +}
>> +
>> +static ssize_t cec_write(struct file *filp, const char __user *buf,
>> +		size_t sz, loff_t *off)
>> +{
>> +	struct cec_devnode *cecdev = cec_devnode_data(filp);
>> +
>> +	if (!cec_devnode_is_registered(cecdev))
>> +		return -EIO;
>> +	return 0;
>> +}
> 
> Both read and write do nothing; they should either -ENOSYS or the fuctions
> should be removed.

These can be removed. These are leftovers from the very first cec driver I
wrote. The idea at the time was to use read and write to handle CEC messages,
but in the end that never happened and ioctls were used instead,


Regards,

	Hans

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

* RE: [RFC v2 3/7] cec: add new framework for cec support.
  2015-01-23 11:07   ` Sean Young
@ 2015-03-06 16:14       ` Kamil Debski
  2015-03-06 16:14       ` Kamil Debski
  1 sibling, 0 replies; 34+ messages in thread
From: Kamil Debski @ 2015-03-06 16:14 UTC (permalink / raw)
  To: 'Sean Young'
  Cc: dri-devel, linux-media, Marek Szyprowski, mchehab, hverkuil,
	kyungmin.park, thomas, 'Hans Verkuil'

Hi Sean, Hans,

I am sorry to reply so late, I was busy with other work. I am preparing the
next version
of the CEC framework and I would like to discuss your comment.

From: Sean Young [mailto:sean@mess.org]
Sent: Friday, January 23, 2015 12:08 PM
> 
> On Thu, Jan 22, 2015 at 05:04:35PM +0100, Kamil Debski wrote:
> > Add the CEC framework.
> -snip-
> > +Remote control handling
> > +-----------------------
> > +
> > +The CEC framework provides two ways of handling the key messages of
> > +remote control. In the first case, the CEC framework will handle
> > +these messages and provide the keypressed via the RC framework. In
> > +the second case the messages related to the key down/up events are
> > +not parsed by the framework and are passed to the userspace as raw
> messages.
> > +
> > +Switching between these modes is done with a special ioctl.
> > +
> > +#define CEC_G_KEY_PASSTHROUGH	_IOR('a', 10, __u8)
> > +#define CEC_S_KEY_PASSTHROUGH	_IOW('a', 11, __u8)
> > +#define CEC_KEY_PASSTHROUGH_DISABLE	0
> > +#define CEC_KEY_PASSTHROUGH_ENABLE	1
> 
> This is ugly. This ioctl stops keypresses from going to rc-core. The
> cec device is still registered with rc-core but no keys will be passed
> to it.
> This could also be handled by loading an empty keymap; this way the
> input layer will still receive scancodes but no keypresses.

I see here a few options that can be done:

1) Remove the past through option altogether
I think I would opt for leaving it. There should be some mode that would
enable
raw access to the CEC bus. Maybe it should be something more like a
promiscuous mode
in Wi-Fi networks. What do you think? Sean, Hans?

2) Leave the pass through mode, but without disabling passing the keyup/down
events to
the RC framework. This way an application could capture all messages, but
the input device
would not be crippled in any way. The problem with this solution is that key
presses could
be accounted twice.

3) As you suggested - load an empty keymap whenever the pass through mode is
enabled.
I am not that familiar with the RC core. Is there a simple way to switch to
an empty map
from the kernel? There is the ir_setkeytable function, but it is static in
rc-main.c, so it
cannot be used in other kernel modules. Any hints, Sean?

4) Remove the input device whenever a pass through mode is enabled. This is
an alternative to
the solution number 3. I think it would not be great, because a
/dev/input/event* that appears
and disappears could be confusing.

> 
> > +static ssize_t cec_read(struct file *filp, char __user *buf,
> > +		size_t sz, loff_t *off)
> > +{
> > +	struct cec_devnode *cecdev = cec_devnode_data(filp);
> > +
> > +	if (!cec_devnode_is_registered(cecdev))
> > +		return -EIO;
> > +	return 0;
> > +}
> > +
> > +static ssize_t cec_write(struct file *filp, const char __user *buf,
> > +		size_t sz, loff_t *off)
> > +{
> > +	struct cec_devnode *cecdev = cec_devnode_data(filp);
> > +
> > +	if (!cec_devnode_is_registered(cecdev))
> > +		return -EIO;
> > +	return 0;
> > +}
> 
> Both read and write do nothing; they should either -ENOSYS or the
> fuctions should be removed.
> 

I agree, I removed this for the next version.

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



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

* RE: [RFC v2 3/7] cec: add new framework for cec support.
@ 2015-03-06 16:14       ` Kamil Debski
  0 siblings, 0 replies; 34+ messages in thread
From: Kamil Debski @ 2015-03-06 16:14 UTC (permalink / raw)
  To: 'Sean Young'
  Cc: 'Hans Verkuil',
	mchehab, dri-devel, kyungmin.park, thomas, linux-media,
	Marek Szyprowski

Hi Sean, Hans,

I am sorry to reply so late, I was busy with other work. I am preparing the
next version
of the CEC framework and I would like to discuss your comment.

From: Sean Young [mailto:sean@mess.org]
Sent: Friday, January 23, 2015 12:08 PM
> 
> On Thu, Jan 22, 2015 at 05:04:35PM +0100, Kamil Debski wrote:
> > Add the CEC framework.
> -snip-
> > +Remote control handling
> > +-----------------------
> > +
> > +The CEC framework provides two ways of handling the key messages of
> > +remote control. In the first case, the CEC framework will handle
> > +these messages and provide the keypressed via the RC framework. In
> > +the second case the messages related to the key down/up events are
> > +not parsed by the framework and are passed to the userspace as raw
> messages.
> > +
> > +Switching between these modes is done with a special ioctl.
> > +
> > +#define CEC_G_KEY_PASSTHROUGH	_IOR('a', 10, __u8)
> > +#define CEC_S_KEY_PASSTHROUGH	_IOW('a', 11, __u8)
> > +#define CEC_KEY_PASSTHROUGH_DISABLE	0
> > +#define CEC_KEY_PASSTHROUGH_ENABLE	1
> 
> This is ugly. This ioctl stops keypresses from going to rc-core. The
> cec device is still registered with rc-core but no keys will be passed
> to it.
> This could also be handled by loading an empty keymap; this way the
> input layer will still receive scancodes but no keypresses.

I see here a few options that can be done:

1) Remove the past through option altogether
I think I would opt for leaving it. There should be some mode that would
enable
raw access to the CEC bus. Maybe it should be something more like a
promiscuous mode
in Wi-Fi networks. What do you think? Sean, Hans?

2) Leave the pass through mode, but without disabling passing the keyup/down
events to
the RC framework. This way an application could capture all messages, but
the input device
would not be crippled in any way. The problem with this solution is that key
presses could
be accounted twice.

3) As you suggested - load an empty keymap whenever the pass through mode is
enabled.
I am not that familiar with the RC core. Is there a simple way to switch to
an empty map
from the kernel? There is the ir_setkeytable function, but it is static in
rc-main.c, so it
cannot be used in other kernel modules. Any hints, Sean?

4) Remove the input device whenever a pass through mode is enabled. This is
an alternative to
the solution number 3. I think it would not be great, because a
/dev/input/event* that appears
and disappears could be confusing.

> 
> > +static ssize_t cec_read(struct file *filp, char __user *buf,
> > +		size_t sz, loff_t *off)
> > +{
> > +	struct cec_devnode *cecdev = cec_devnode_data(filp);
> > +
> > +	if (!cec_devnode_is_registered(cecdev))
> > +		return -EIO;
> > +	return 0;
> > +}
> > +
> > +static ssize_t cec_write(struct file *filp, const char __user *buf,
> > +		size_t sz, loff_t *off)
> > +{
> > +	struct cec_devnode *cecdev = cec_devnode_data(filp);
> > +
> > +	if (!cec_devnode_is_registered(cecdev))
> > +		return -EIO;
> > +	return 0;
> > +}
> 
> Both read and write do nothing; they should either -ENOSYS or the
> fuctions should be removed.
> 

I agree, I removed this for the next version.

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


_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [RFC v2 3/7] cec: add new framework for cec support.
  2015-03-06 16:14       ` Kamil Debski
  (?)
@ 2015-03-08 10:44       ` Sean Young
  2015-03-09 16:21         ` Kamil Debski
  -1 siblings, 1 reply; 34+ messages in thread
From: Sean Young @ 2015-03-08 10:44 UTC (permalink / raw)
  To: Kamil Debski
  Cc: dri-devel, linux-media, Marek Szyprowski, mchehab, hverkuil,
	kyungmin.park, thomas, 'Hans Verkuil'

Hi Kamil,

On Fri, Mar 06, 2015 at 05:14:50PM +0100, Kamil Debski wrote:
> 3) As you suggested - load an empty keymap whenever the pass through mode is
> enabled.
> I am not that familiar with the RC core. Is there a simple way to switch to
> an empty map
> from the kernel? There is the ir_setkeytable function, but it is static in
> rc-main.c, so it
> cannot be used in other kernel modules. Any hints, Sean?

Why is it problematic if keypresses are passed to the input layer? 

You can only set the default keymap for an rc-device from kernel space; from
user space you can clear the table using input ioctl, see:

http://git.linuxtv.org/cgit.cgi/v4l-utils.git/tree/utils/keytable/keytable.c#n1277

You can select MAP_EMPTY as the default keymap if that is appropriate; using
ir-setkeytable(1) a different keymap can be selected.


Sean

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

* Re: [RFC v2 2/7] media: rc: Add cec protocol handling
  2015-01-22 16:04 ` [RFC v2 2/7] media: rc: Add cec protocol handling Kamil Debski
@ 2015-03-08 14:20     ` Mauro Carvalho Chehab
  0 siblings, 0 replies; 34+ messages in thread
From: Mauro Carvalho Chehab @ 2015-03-08 14:20 UTC (permalink / raw)
  To: Kamil Debski
  Cc: dri-devel, linux-media, m.szyprowski, hverkuil, kyungmin.park,
	thomas, sean, linux-input

Em Thu, 22 Jan 2015 17:04:34 +0100
Kamil Debski <k.debski@samsung.com> escreveu:

(c/c linux-input ML)

> Add cec protocol handling the RC framework.

I added some comments, that reflects my understanding from what's there at
the keymap definitions found at:
	http://xtreamerdev.googlecode.com/files/CEC_Specs.pdf


> 
> Signed-off-by: Kamil Debski <k.debski@samsung.com>
> ---
>  drivers/media/rc/keymaps/Makefile |    1 +
>  drivers/media/rc/keymaps/rc-cec.c |  133 +++++++++++++++++++++++++++++++++++++
>  drivers/media/rc/rc-main.c        |    1 +
>  include/media/rc-core.h           |    1 +
>  include/media/rc-map.h            |    5 +-
>  5 files changed, 140 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..f2826c5
> --- /dev/null
> +++ b/drivers/media/rc/keymaps/rc-cec.c
> @@ -0,0 +1,133 @@
> +/* 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_SELECT }, /* XXX CEC Spec: Select, should it be KEY_SELECT or KEY_OK? */

KEY_OK is better, IMHO.

> +	{ 0x01, KEY_UP },
> +	{ 0x02, KEY_DOWN },
> +	{ 0x03, KEY_LEFT },
> +	{ 0x04, KEY_RIGHT },
> +	/* XXX 0x05-0x08 CEC Spec: Right-Up, Right-Down, Left-Up, Left-Down */

I think you need to send a patch to linux-input, in order to add those
keycodes.

> +	{ 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_0 },
> +	{ 0x21, KEY_1 },
> +	{ 0x22, KEY_2 },
> +	{ 0x23, KEY_3 },
> +	{ 0x24, KEY_4 },
> +	{ 0x25, KEY_5 },
> +	{ 0x26, KEY_6 },
> +	{ 0x27, KEY_7 },
> +	{ 0x28, KEY_8 },
> +	{ 0x29, KEY_9 },

Better to use KEY_NUMERIC_* here, as this is not affected by the
shift state.

> +	{ 0x2a, KEY_DOT },
> +	{ 0x2b, KEY_ENTER },
> +	{ 0x2c, KEY_CLEAR },
> +	/* 0x2d-0x2e: Reserved */

> +	/* XXX 0x2f: CEC Spec: Next Favorite */
Again another addition to Linux keystroke codes.

> +	{ 0x30, KEY_CHANNELUP },
> +	{ 0x31, KEY_CHANNELDOWN },
> +	{ 0x32, KEY_PREVIOUS }, /* CEC Spec: Previous Channel */
> +	{ 0x33, KEY_SOUND }, /* CEC Spec: Sound Select */
> +	/* XXX 0x34: CEC Spec: Input Select */

Another key to be added. Yet, other keymaps have a key to select the
input source. Most use KEY_VIDEO, to select the video input source,
and KEY_AUDIO, to select the audio input source.

So, KEY_VIDEO is likely the best choice here.

> +	{ 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 }, /* XXX CEC Spec: Stop, what about KEY_STOPCD? */
> +	{ 0x46, KEY_PAUSE },/* XXX CEC Spec: Pause, what about KEY_PAUSECD? */

The CD variants are to control the CD player on multimedia keyboards I think.
only two IR maps use it. All the rest uses KEY_STOP/KEY_PAUSE.

> +	{ 0x47, KEY_RECORD },
> +	{ 0x48, KEY_REWIND },
> +	{ 0x49, KEY_FASTFORWARD },
> +	{ 0x4a, KEY_EJECTCD }, /* CEC Spec: Eject */
> +	{ 0x4b, KEY_FORWARD },

> +	{ 0x4c, }, /* XXX */

Hmm.. I guess it would be KEY_BACK for the backward keycode.
	
> +	{ 0x4d, KEY_STOP }, /* XXX CEC Spec: Stop-Record, what about KEY_STOPCD? */
> +	{ 0x4e, KEY_PAUSE }, /* XXX CEC Spec: Pause-Record, what about KEY_PAUSECD? */

Probably, we'll need to define two new keycodes here.

> +	/* 0x4f: Reserved */
> +	{ 0x50, KEY_ANGLE },
> +	{ 0x51, KEY_SUBTITLE }, /* XXX CEC Spec: Sub picture, should it be KEY_SUBTITLE or something else? */

KEY_SUBTITLE is for subtitle OSG data. Perhaps KEY_TV2?

Different maps do different things with the PIP key:

$ git grep -i pip drivers/media/rc/keymaps/
drivers/media/rc/keymaps/rc-alink-dtu-m.c:      { 0x0805, KEY_NEW },             /* symbol: PIP */
drivers/media/rc/keymaps/rc-avermedia-cardbus.c:        { 0x2b, KEY_VIDEO },            /* PIP (Picture-in-picture) */
drivers/media/rc/keymaps/rc-avermedia-m135a.c:  { 0x022b, KEY_TV2 },            /* TV2 or PIP */
drivers/media/rc/keymaps/rc-avermedia-m135a.c:  { 0x041a, KEY_TV2 },      /* PIP */
drivers/media/rc/keymaps/rc-avermedia-m733a-rm-k6.c:    { 0x041a, KEY_TV2 },      /* PIP */
drivers/media/rc/keymaps/rc-azurewave-ad-tu700.c:       { 0x0047, KEY_NEW },             /* PIP */
drivers/media/rc/keymaps/rc-dib0700-rc5.c:      { 0x064c, KEY_RESERVED }, /* PIP button*/
drivers/media/rc/keymaps/rc-digitalnow-tinytwin.c:      { 0x0053, KEY_NEW },             /* [symbol PIP?] */
drivers/media/rc/keymaps/rc-dntv-live-dvbt-pro.c:       { 0x47, KEY_TV2 },              /* pip */
drivers/media/rc/keymaps/rc-dvbsky.c:   { 0x000f, KEY_SUBTITLE }, /*PIP*/
drivers/media/rc/keymaps/rc-encore-enltv2.c:    { 0x71, KEY_TV2 },              /* PIP */
drivers/media/rc/keymaps/rc-evga-indtube.c:     { 0x16, KEY_TV2},       /* PIP */
drivers/media/rc/keymaps/rc-flydvb.c:   { 0x1a, KEY_TV2 },              /* PIP */
drivers/media/rc/keymaps/rc-terratec-slim.c:    { 0x02bd0b, KEY_NEW },             /* symbol: PIP */
drivers/media/rc/keymaps/rc-winfast-usbii-deluxe.c:     { 0x3a, KEY_NEW},               /* PIP */
drivers/media/rc/keymaps/rc-winfast.c:  { 0x2a, KEY_TV2 },              /* PIP (Picture in picture */

> +	{ 0x52, KEY_VIDEO }, /* XXX CEC Spec: Video on Demand / input.h: AL Movie Browser, maybe KEY_DIRECTORY? */

I would add a KEY_VOD for that.

> +	{ 0x53, KEY_EPG },
> +	{ 0x54, KEY_TIME }, /* XXX CEC Spec: Timer */
> +	{ 0x55, KEY_CONFIG },
> +	/* 0x56-0x5f: Reserved */

> +	{ 0x60, KEY_PLAY }, /* XXX CEC Spec: Play Function */
> +	{ 0x61, KEY_PLAYPAUSE }, /* XXX CEC Spec: Pause-Play Function */
> +	{ 0x62, KEY_RECORD }, /* XXX CEC Spec: Record Function */
> +	{ 0x63, KEY_PAUSE }, /* XXX CEC Spec: Pause-Record Function */
> +	{ 0x64, KEY_STOP }, /* XXX CEC Spec: Stop Function */
> +	{ 0x65, KEY_MUTE }, /* XXX CEC Spec: Mute Function */
> +	/* 0x66: CEC Spec: Restore Volume Function */
> +	{ 0x67, KEY_TUNER }, /* XXX CEC Spec: Tune Function */
> +	{ 0x68, KEY_MEDIA }, /* CEC Spec: Select Media Function */
> +	{ 0x69, KEY_SWITCHVIDEOMODE} /* XXX CEC Spec: Select A/V Input Function */,
> +	{ 0x6a, KEY_AUDIO} /* CEC Spec: Select Audio Input Function */,
> +	{ 0x6b, KEY_POWER} /* CEC Spec: Power Toggle Function */,
> +	{ 0x6c, KEY_SLEEP} /* XXX CEC Spec: Power Off Function */,
> +	{ 0x6d, KEY_WAKEUP} /* XXX CEC Spec: Power On Function */,

Those "function" keycodes look weird. What's the difference between those
and the pure non-function variants?

The spec (CEC 13.13.3) says that:

	"Unlike the other codes, which just pass remote control presses
	 to the target (often with manufacturer-specific results), 
	 the Functions are deterministic, ie they specify exactly the state
	 after executing these commands. Several of these also have further
	 operands, specifying the function in more detail, immediately
	 following the relevant [UI Command] operand."

Some codes are actually compund ones. For example, 0x60 has a "play mode"
operand. So, the actual mapping would be:

0x60 + 0x24 - "play forward"
0x61 + 0x20 - "play reverse"
...
(see CEC17 for operand descriptions)

So, IMHO, the mapping should be 

	{ 0x6024, KEY_PLAY },
	{ 0x6020, KEY_PLAY_REVERSE }, // to be created
	...


> +	/* 0x6e-0x70: Reserved */
> +	{ 0x71, KEY_BLUE }, /* XXX CEC Spec: F1 (Blue) */
> +	{ 0x72, KEY_RED }, /* XXX CEC Spec: F2 (Red) */
> +	{ 0x73, KEY_GREEN }, /* XXX CEC Spec: F3 (Green) */
> +	{ 0x74, KEY_YELLOW }, /* XXX CEC Spec: F4 (Yellow) */
> +	{ 0x75, KEY_F5 },
> +	{ 0x76, KEY_CONNECT }, /* XXX CEC Spec: Data - see Note 3 */
> +	/* Note 3: This is used, for example, to enter or leave a digital TV
> +	 * data broadcast application. */

perhaps a new keycode, like KEY_DVB? The spec is not actually too clear
about what that "Data" key means.

> +	/* 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"

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

* Re: [RFC v2 2/7] media: rc: Add cec protocol handling
@ 2015-03-08 14:20     ` Mauro Carvalho Chehab
  0 siblings, 0 replies; 34+ messages in thread
From: Mauro Carvalho Chehab @ 2015-03-08 14:20 UTC (permalink / raw)
  To: Kamil Debski
  Cc: dri-devel, linux-media, m.szyprowski, hverkuil, kyungmin.park,
	thomas, sean, linux-input

Em Thu, 22 Jan 2015 17:04:34 +0100
Kamil Debski <k.debski@samsung.com> escreveu:

(c/c linux-input ML)

> Add cec protocol handling the RC framework.

I added some comments, that reflects my understanding from what's there at
the keymap definitions found at:
	http://xtreamerdev.googlecode.com/files/CEC_Specs.pdf


> 
> Signed-off-by: Kamil Debski <k.debski@samsung.com>
> ---
>  drivers/media/rc/keymaps/Makefile |    1 +
>  drivers/media/rc/keymaps/rc-cec.c |  133 +++++++++++++++++++++++++++++++++++++
>  drivers/media/rc/rc-main.c        |    1 +
>  include/media/rc-core.h           |    1 +
>  include/media/rc-map.h            |    5 +-
>  5 files changed, 140 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..f2826c5
> --- /dev/null
> +++ b/drivers/media/rc/keymaps/rc-cec.c
> @@ -0,0 +1,133 @@
> +/* 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_SELECT }, /* XXX CEC Spec: Select, should it be KEY_SELECT or KEY_OK? */

KEY_OK is better, IMHO.

> +	{ 0x01, KEY_UP },
> +	{ 0x02, KEY_DOWN },
> +	{ 0x03, KEY_LEFT },
> +	{ 0x04, KEY_RIGHT },
> +	/* XXX 0x05-0x08 CEC Spec: Right-Up, Right-Down, Left-Up, Left-Down */

I think you need to send a patch to linux-input, in order to add those
keycodes.

> +	{ 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_0 },
> +	{ 0x21, KEY_1 },
> +	{ 0x22, KEY_2 },
> +	{ 0x23, KEY_3 },
> +	{ 0x24, KEY_4 },
> +	{ 0x25, KEY_5 },
> +	{ 0x26, KEY_6 },
> +	{ 0x27, KEY_7 },
> +	{ 0x28, KEY_8 },
> +	{ 0x29, KEY_9 },

Better to use KEY_NUMERIC_* here, as this is not affected by the
shift state.

> +	{ 0x2a, KEY_DOT },
> +	{ 0x2b, KEY_ENTER },
> +	{ 0x2c, KEY_CLEAR },
> +	/* 0x2d-0x2e: Reserved */

> +	/* XXX 0x2f: CEC Spec: Next Favorite */
Again another addition to Linux keystroke codes.

> +	{ 0x30, KEY_CHANNELUP },
> +	{ 0x31, KEY_CHANNELDOWN },
> +	{ 0x32, KEY_PREVIOUS }, /* CEC Spec: Previous Channel */
> +	{ 0x33, KEY_SOUND }, /* CEC Spec: Sound Select */
> +	/* XXX 0x34: CEC Spec: Input Select */

Another key to be added. Yet, other keymaps have a key to select the
input source. Most use KEY_VIDEO, to select the video input source,
and KEY_AUDIO, to select the audio input source.

So, KEY_VIDEO is likely the best choice here.

> +	{ 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 }, /* XXX CEC Spec: Stop, what about KEY_STOPCD? */
> +	{ 0x46, KEY_PAUSE },/* XXX CEC Spec: Pause, what about KEY_PAUSECD? */

The CD variants are to control the CD player on multimedia keyboards I think.
only two IR maps use it. All the rest uses KEY_STOP/KEY_PAUSE.

> +	{ 0x47, KEY_RECORD },
> +	{ 0x48, KEY_REWIND },
> +	{ 0x49, KEY_FASTFORWARD },
> +	{ 0x4a, KEY_EJECTCD }, /* CEC Spec: Eject */
> +	{ 0x4b, KEY_FORWARD },

> +	{ 0x4c, }, /* XXX */

Hmm.. I guess it would be KEY_BACK for the backward keycode.
	
> +	{ 0x4d, KEY_STOP }, /* XXX CEC Spec: Stop-Record, what about KEY_STOPCD? */
> +	{ 0x4e, KEY_PAUSE }, /* XXX CEC Spec: Pause-Record, what about KEY_PAUSECD? */

Probably, we'll need to define two new keycodes here.

> +	/* 0x4f: Reserved */
> +	{ 0x50, KEY_ANGLE },
> +	{ 0x51, KEY_SUBTITLE }, /* XXX CEC Spec: Sub picture, should it be KEY_SUBTITLE or something else? */

KEY_SUBTITLE is for subtitle OSG data. Perhaps KEY_TV2?

Different maps do different things with the PIP key:

$ git grep -i pip drivers/media/rc/keymaps/
drivers/media/rc/keymaps/rc-alink-dtu-m.c:      { 0x0805, KEY_NEW },             /* symbol: PIP */
drivers/media/rc/keymaps/rc-avermedia-cardbus.c:        { 0x2b, KEY_VIDEO },            /* PIP (Picture-in-picture) */
drivers/media/rc/keymaps/rc-avermedia-m135a.c:  { 0x022b, KEY_TV2 },            /* TV2 or PIP */
drivers/media/rc/keymaps/rc-avermedia-m135a.c:  { 0x041a, KEY_TV2 },      /* PIP */
drivers/media/rc/keymaps/rc-avermedia-m733a-rm-k6.c:    { 0x041a, KEY_TV2 },      /* PIP */
drivers/media/rc/keymaps/rc-azurewave-ad-tu700.c:       { 0x0047, KEY_NEW },             /* PIP */
drivers/media/rc/keymaps/rc-dib0700-rc5.c:      { 0x064c, KEY_RESERVED }, /* PIP button*/
drivers/media/rc/keymaps/rc-digitalnow-tinytwin.c:      { 0x0053, KEY_NEW },             /* [symbol PIP?] */
drivers/media/rc/keymaps/rc-dntv-live-dvbt-pro.c:       { 0x47, KEY_TV2 },              /* pip */
drivers/media/rc/keymaps/rc-dvbsky.c:   { 0x000f, KEY_SUBTITLE }, /*PIP*/
drivers/media/rc/keymaps/rc-encore-enltv2.c:    { 0x71, KEY_TV2 },              /* PIP */
drivers/media/rc/keymaps/rc-evga-indtube.c:     { 0x16, KEY_TV2},       /* PIP */
drivers/media/rc/keymaps/rc-flydvb.c:   { 0x1a, KEY_TV2 },              /* PIP */
drivers/media/rc/keymaps/rc-terratec-slim.c:    { 0x02bd0b, KEY_NEW },             /* symbol: PIP */
drivers/media/rc/keymaps/rc-winfast-usbii-deluxe.c:     { 0x3a, KEY_NEW},               /* PIP */
drivers/media/rc/keymaps/rc-winfast.c:  { 0x2a, KEY_TV2 },              /* PIP (Picture in picture */

> +	{ 0x52, KEY_VIDEO }, /* XXX CEC Spec: Video on Demand / input.h: AL Movie Browser, maybe KEY_DIRECTORY? */

I would add a KEY_VOD for that.

> +	{ 0x53, KEY_EPG },
> +	{ 0x54, KEY_TIME }, /* XXX CEC Spec: Timer */
> +	{ 0x55, KEY_CONFIG },
> +	/* 0x56-0x5f: Reserved */

> +	{ 0x60, KEY_PLAY }, /* XXX CEC Spec: Play Function */
> +	{ 0x61, KEY_PLAYPAUSE }, /* XXX CEC Spec: Pause-Play Function */
> +	{ 0x62, KEY_RECORD }, /* XXX CEC Spec: Record Function */
> +	{ 0x63, KEY_PAUSE }, /* XXX CEC Spec: Pause-Record Function */
> +	{ 0x64, KEY_STOP }, /* XXX CEC Spec: Stop Function */
> +	{ 0x65, KEY_MUTE }, /* XXX CEC Spec: Mute Function */
> +	/* 0x66: CEC Spec: Restore Volume Function */
> +	{ 0x67, KEY_TUNER }, /* XXX CEC Spec: Tune Function */
> +	{ 0x68, KEY_MEDIA }, /* CEC Spec: Select Media Function */
> +	{ 0x69, KEY_SWITCHVIDEOMODE} /* XXX CEC Spec: Select A/V Input Function */,
> +	{ 0x6a, KEY_AUDIO} /* CEC Spec: Select Audio Input Function */,
> +	{ 0x6b, KEY_POWER} /* CEC Spec: Power Toggle Function */,
> +	{ 0x6c, KEY_SLEEP} /* XXX CEC Spec: Power Off Function */,
> +	{ 0x6d, KEY_WAKEUP} /* XXX CEC Spec: Power On Function */,

Those "function" keycodes look weird. What's the difference between those
and the pure non-function variants?

The spec (CEC 13.13.3) says that:

	"Unlike the other codes, which just pass remote control presses
	 to the target (often with manufacturer-specific results), 
	 the Functions are deterministic, ie they specify exactly the state
	 after executing these commands. Several of these also have further
	 operands, specifying the function in more detail, immediately
	 following the relevant [UI Command] operand."

Some codes are actually compund ones. For example, 0x60 has a "play mode"
operand. So, the actual mapping would be:

0x60 + 0x24 - "play forward"
0x61 + 0x20 - "play reverse"
...
(see CEC17 for operand descriptions)

So, IMHO, the mapping should be 

	{ 0x6024, KEY_PLAY },
	{ 0x6020, KEY_PLAY_REVERSE }, // to be created
	...


> +	/* 0x6e-0x70: Reserved */
> +	{ 0x71, KEY_BLUE }, /* XXX CEC Spec: F1 (Blue) */
> +	{ 0x72, KEY_RED }, /* XXX CEC Spec: F2 (Red) */
> +	{ 0x73, KEY_GREEN }, /* XXX CEC Spec: F3 (Green) */
> +	{ 0x74, KEY_YELLOW }, /* XXX CEC Spec: F4 (Yellow) */
> +	{ 0x75, KEY_F5 },
> +	{ 0x76, KEY_CONNECT }, /* XXX CEC Spec: Data - see Note 3 */
> +	/* Note 3: This is used, for example, to enter or leave a digital TV
> +	 * data broadcast application. */

perhaps a new keycode, like KEY_DVB? The spec is not actually too clear
about what that "Data" key means.

> +	/* 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"
--
To unsubscribe from this list: send the line "unsubscribe linux-input" 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] 34+ messages in thread

* Re: [RFC v2 3/7] cec: add new framework for cec support.
  2015-03-06 16:14       ` Kamil Debski
  (?)
  (?)
@ 2015-03-08 15:41       ` Mauro Carvalho Chehab
  2015-03-09 16:22           ` Kamil Debski
  -1 siblings, 1 reply; 34+ messages in thread
From: Mauro Carvalho Chehab @ 2015-03-08 15:41 UTC (permalink / raw)
  To: Kamil Debski
  Cc: 'Sean Young',
	dri-devel, linux-media, Marek Szyprowski, hverkuil,
	kyungmin.park, thomas, 'Hans Verkuil'

Em Fri, 06 Mar 2015 17:14:50 +0100
Kamil Debski <k.debski@samsung.com> escreveu:

> Hi Sean, Hans,
> 
> I am sorry to reply so late, I was busy with other work. I am preparing the
> next version
> of the CEC framework and I would like to discuss your comment.

I'll do a deeper review of this patch when I have some time. For now,
let me add my comments about the pass-trough mode. See below.

> 
> From: Sean Young [mailto:sean@mess.org]
> Sent: Friday, January 23, 2015 12:08 PM
> > 
> > On Thu, Jan 22, 2015 at 05:04:35PM +0100, Kamil Debski wrote:
> > > Add the CEC framework.
> > -snip-
> > > +Remote control handling
> > > +-----------------------
> > > +
> > > +The CEC framework provides two ways of handling the key messages of
> > > +remote control. In the first case, the CEC framework will handle
> > > +these messages and provide the keypressed via the RC framework. In
> > > +the second case the messages related to the key down/up events are
> > > +not parsed by the framework and are passed to the userspace as raw
> > messages.
> > > +
> > > +Switching between these modes is done with a special ioctl.
> > > +
> > > +#define CEC_G_KEY_PASSTHROUGH	_IOR('a', 10, __u8)
> > > +#define CEC_S_KEY_PASSTHROUGH	_IOW('a', 11, __u8)
> > > +#define CEC_KEY_PASSTHROUGH_DISABLE	0
> > > +#define CEC_KEY_PASSTHROUGH_ENABLE	1
> > 
> > This is ugly. This ioctl stops keypresses from going to rc-core. The
> > cec device is still registered with rc-core but no keys will be passed
> > to it.
> > This could also be handled by loading an empty keymap; this way the
> > input layer will still receive scancodes but no keypresses.
> 
> I see here a few options that can be done:
> 
> 1) Remove the past through option altogether
> I think I would opt for leaving it. There should be some mode that would
> enable
> raw access to the CEC bus. Maybe it should be something more like a
> promiscuous mode
> in Wi-Fi networks. What do you think? Sean, Hans?
> 
> 2) Leave the pass through mode, but without disabling passing the keyup/down
> events to
> the RC framework. This way an application could capture all messages, but
> the input device
> would not be crippled in any way. The problem with this solution is that key
> presses could
> be accounted twice.
> 
> 3) As you suggested - load an empty keymap whenever the pass through mode is
> enabled.
> I am not that familiar with the RC core. Is there a simple way to switch to
> an empty map
> from the kernel? There is the ir_setkeytable function, but it is static in
> rc-main.c, so it
> cannot be used in other kernel modules. Any hints, Sean?
> 
> 4) Remove the input device whenever a pass through mode is enabled. This is
> an alternative to
> the solution number 3. I think it would not be great, because a
> /dev/input/event* that appears
> and disappears could be confusing.

(4) doesn't seem nice.

I don't think that the driver itself should cleanup the keymap. This is
something that the userspace app(s) should explicitly request.

With regards to the "raw" mode, the RC core currently has two ways to
send/receive raw data:

1) Via LIRC. This needs to be extended to pass scancodes, as, currently,
it sends/receive pulses. We need such extension for other usages, anyway,
so adding it makes sense.

2) The input layer actually provide several types of events on a key
press. One of such events carry on the scancode:

1425828993.018962: event type EV_KEY(0x01) key_down: KEY_VOLUMEDOWN(0x0001)
1425828993.018962: event type EV_SYN(0x00).
1425828993.131823: event type EV_KEY(0x01) key_up: KEY_VOLUMEDOWN(0x0001)
1425828993.131823: event type EV_MSC(0x04): scancode = 0x1e
1425828993.131823: event type EV_SYN(0x00).

The EV_KEY events has the Linux Keycode, plus the info if the key
was pressed or released, while the EV_MSC has the scancode. 

So, I'm not seeing much usage of a pass-through mode, as, even without
LIRC, the userspace could simply cleanup the key map, and listen to EV_MSC:

$ sudo ir-keytable -c -t
Old keytable cleared
Testing events. Please, press CTRL-C to abort.
1425829137.721737: event type EV_MSC(0x04): scancode = 0x1b
1425829137.721737: event type EV_SYN(0x00).
1425829139.318249: event type EV_MSC(0x04): scancode = 0x18
1425829139.318249: event type EV_SYN(0x00).
...

Yet, the best would be for the application is to setup the key map it
needs, and just use the standard Linux way: wait for EV_KEY events.

Regards,
Mauro

> 
> > 
> > > +static ssize_t cec_read(struct file *filp, char __user *buf,
> > > +		size_t sz, loff_t *off)
> > > +{
> > > +	struct cec_devnode *cecdev = cec_devnode_data(filp);
> > > +
> > > +	if (!cec_devnode_is_registered(cecdev))
> > > +		return -EIO;
> > > +	return 0;
> > > +}
> > > +
> > > +static ssize_t cec_write(struct file *filp, const char __user *buf,
> > > +		size_t sz, loff_t *off)
> > > +{
> > > +	struct cec_devnode *cecdev = cec_devnode_data(filp);
> > > +
> > > +	if (!cec_devnode_is_registered(cecdev))
> > > +		return -EIO;
> > > +	return 0;
> > > +}
> > 
> > Both read and write do nothing; they should either -ENOSYS or the
> > fuctions should be removed.
> > 
> 
> I agree, I removed this for the next version.
> 
> Best wishes,

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

* RE: [RFC v2 3/7] cec: add new framework for cec support.
  2015-03-08 10:44       ` Sean Young
@ 2015-03-09 16:21         ` Kamil Debski
  0 siblings, 0 replies; 34+ messages in thread
From: Kamil Debski @ 2015-03-09 16:21 UTC (permalink / raw)
  To: 'Sean Young'
  Cc: dri-devel, linux-media, Marek Szyprowski, mchehab, hverkuil,
	kyungmin.park, thomas, 'Hans Verkuil'

Hi Sean,

From: Sean Young [mailto:sean@mess.org]
Sent: Sunday, March 08, 2015 11:45 AM
> 
> Hi Kamil,
> 
> On Fri, Mar 06, 2015 at 05:14:50PM +0100, Kamil Debski wrote:
> > 3) As you suggested - load an empty keymap whenever the pass through
> > mode is enabled.
> > I am not that familiar with the RC core. Is there a simple way to
> > switch to an empty map from the kernel? There is the ir_setkeytable
> > function, but it is static in rc-main.c, so it cannot be used in
> other
> > kernel modules. Any hints, Sean?
> 
> Why is it problematic if keypresses are passed to the input layer?

I gave this a thought over the weekend and I think I agree that this
shouldn't be much of a problem. I had doubts that there could be an
application that could use both the input device and at the same time
parse the raw messages to get keycodes. In reality this should not
happen, as someone using the "raw"/"promiscuous" mode would be aware
of how it works - that the keycodes are still passed to the input device.

> 
> You can only set the default keymap for an rc-device from kernel space;
> from user space you can clear the table using input ioctl, see:
> 
> http://git.linuxtv.org/cgit.cgi/v4l-
> utils.git/tree/utils/keytable/keytable.c#n1277
> 
> You can select MAP_EMPTY as the default keymap if that is appropriate;
> using
> ir-setkeytable(1) a different keymap can be selected.
> 
> 
> Sean

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



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

* RE: [RFC v2 2/7] media: rc: Add cec protocol handling
  2015-03-08 14:20     ` Mauro Carvalho Chehab
@ 2015-03-09 16:22       ` Kamil Debski
  -1 siblings, 0 replies; 34+ messages in thread
From: Kamil Debski @ 2015-03-09 16:22 UTC (permalink / raw)
  To: 'Mauro Carvalho Chehab'
  Cc: dri-devel, linux-media, Marek Szyprowski, hverkuil,
	kyungmin.park, thomas, sean, linux-input

Hi Mauro, 

From: Mauro Carvalho Chehab [mailto:mchehab@osg.samsung.com]
Sent: Sunday, March 08, 2015 3:21 PM

> Em Thu, 22 Jan 2015 17:04:34 +0100
> Kamil Debski <k.debski@samsung.com> escreveu:
> 
> (c/c linux-input ML)
> 
> > Add cec protocol handling the RC framework.
> 
> I added some comments, that reflects my understanding from what's there
> at the keymap definitions found at:
> 	http://xtreamerdev.googlecode.com/files/CEC_Specs.pdf

Thank you very much for the review, Mauro. Your comments are very much appreciated.
 
> 
> >
> > Signed-off-by: Kamil Debski <k.debski@samsung.com>
> > ---
> >  drivers/media/rc/keymaps/Makefile |    1 +
> >  drivers/media/rc/keymaps/rc-cec.c |  133
> +++++++++++++++++++++++++++++++++++++
> >  drivers/media/rc/rc-main.c        |    1 +
> >  include/media/rc-core.h           |    1 +
> >  include/media/rc-map.h            |    5 +-
> >  5 files changed, 140 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..f2826c5
> > --- /dev/null
> > +++ b/drivers/media/rc/keymaps/rc-cec.c
> > @@ -0,0 +1,133 @@
> > +/* 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_SELECT }, /* XXX CEC Spec: Select, should it be
> > +KEY_SELECT or KEY_OK? */
> 
> KEY_OK is better, IMHO.
> 
> > +	{ 0x01, KEY_UP },
> > +	{ 0x02, KEY_DOWN },
> > +	{ 0x03, KEY_LEFT },
> > +	{ 0x04, KEY_RIGHT },
> > +	/* XXX 0x05-0x08 CEC Spec: Right-Up, Right-Down, Left-Up, Left-
> Down
> > +*/
> 
> I think you need to send a patch to linux-input, in order to add those
> keycodes.
> 
> > +	{ 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_0 },
> > +	{ 0x21, KEY_1 },
> > +	{ 0x22, KEY_2 },
> > +	{ 0x23, KEY_3 },
> > +	{ 0x24, KEY_4 },
> > +	{ 0x25, KEY_5 },
> > +	{ 0x26, KEY_6 },
> > +	{ 0x27, KEY_7 },
> > +	{ 0x28, KEY_8 },
> > +	{ 0x29, KEY_9 },
> 
> Better to use KEY_NUMERIC_* here, as this is not affected by the shift
> state.
> 
> > +	{ 0x2a, KEY_DOT },
> > +	{ 0x2b, KEY_ENTER },
> > +	{ 0x2c, KEY_CLEAR },
> > +	/* 0x2d-0x2e: Reserved */
> 
> > +	/* XXX 0x2f: CEC Spec: Next Favorite */
> Again another addition to Linux keystroke codes.
> 
> > +	{ 0x30, KEY_CHANNELUP },
> > +	{ 0x31, KEY_CHANNELDOWN },
> > +	{ 0x32, KEY_PREVIOUS }, /* CEC Spec: Previous Channel */
> > +	{ 0x33, KEY_SOUND }, /* CEC Spec: Sound Select */
> > +	/* XXX 0x34: CEC Spec: Input Select */
> 
> Another key to be added. Yet, other keymaps have a key to select the
> input source. Most use KEY_VIDEO, to select the video input source, and
> KEY_AUDIO, to select the audio input source.
> 
> So, KEY_VIDEO is likely the best choice here.
> 
> > +	{ 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 }, /* XXX CEC Spec: Stop, what about KEY_STOPCD?
> */
> > +	{ 0x46, KEY_PAUSE },/* XXX CEC Spec: Pause, what about
> KEY_PAUSECD?
> > +*/
> 
> The CD variants are to control the CD player on multimedia keyboards I
> think.
> only two IR maps use it. All the rest uses KEY_STOP/KEY_PAUSE.
> 
> > +	{ 0x47, KEY_RECORD },
> > +	{ 0x48, KEY_REWIND },
> > +	{ 0x49, KEY_FASTFORWARD },
> > +	{ 0x4a, KEY_EJECTCD }, /* CEC Spec: Eject */
> > +	{ 0x4b, KEY_FORWARD },
> 
> > +	{ 0x4c, }, /* XXX */
> 
> Hmm.. I guess it would be KEY_BACK for the backward keycode.
> 
> > +	{ 0x4d, KEY_STOP }, /* XXX CEC Spec: Stop-Record, what about
> KEY_STOPCD? */
> > +	{ 0x4e, KEY_PAUSE }, /* XXX CEC Spec: Pause-Record, what about
> > +KEY_PAUSECD? */
> 
> Probably, we'll need to define two new keycodes here.
> 
> > +	/* 0x4f: Reserved */
> > +	{ 0x50, KEY_ANGLE },
> > +	{ 0x51, KEY_SUBTITLE }, /* XXX CEC Spec: Sub picture, should it
> be
> > +KEY_SUBTITLE or something else? */
> 
> KEY_SUBTITLE is for subtitle OSG data. Perhaps KEY_TV2?
> 
> Different maps do different things with the PIP key:
> 
> $ git grep -i pip drivers/media/rc/keymaps/
> drivers/media/rc/keymaps/rc-alink-dtu-m.c:      { 0x0805, KEY_NEW },
> /* symbol: PIP */
> drivers/media/rc/keymaps/rc-avermedia-cardbus.c:        { 0x2b,
> KEY_VIDEO },            /* PIP (Picture-in-picture) */
> drivers/media/rc/keymaps/rc-avermedia-m135a.c:  { 0x022b, KEY_TV2 },
> /* TV2 or PIP */
> drivers/media/rc/keymaps/rc-avermedia-m135a.c:  { 0x041a, KEY_TV2 },
> /* PIP */
> drivers/media/rc/keymaps/rc-avermedia-m733a-rm-k6.c:    { 0x041a,
> KEY_TV2 },      /* PIP */
> drivers/media/rc/keymaps/rc-azurewave-ad-tu700.c:       { 0x0047,
> KEY_NEW },             /* PIP */
> drivers/media/rc/keymaps/rc-dib0700-rc5.c:      { 0x064c,
> KEY_RESERVED }, /* PIP button*/
> drivers/media/rc/keymaps/rc-digitalnow-tinytwin.c:      { 0x0053,
> KEY_NEW },             /* [symbol PIP?] */
> drivers/media/rc/keymaps/rc-dntv-live-dvbt-pro.c:       { 0x47,
> KEY_TV2 },              /* pip */
> drivers/media/rc/keymaps/rc-dvbsky.c:   { 0x000f, KEY_SUBTITLE },
> /*PIP*/
> drivers/media/rc/keymaps/rc-encore-enltv2.c:    { 0x71, KEY_TV2 },
> /* PIP */
> drivers/media/rc/keymaps/rc-evga-indtube.c:     { 0x16, KEY_TV2},
> /* PIP */
> drivers/media/rc/keymaps/rc-flydvb.c:   { 0x1a, KEY_TV2 },
> /* PIP */
> drivers/media/rc/keymaps/rc-terratec-slim.c:    { 0x02bd0b, KEY_NEW },
> /* symbol: PIP */
> drivers/media/rc/keymaps/rc-winfast-usbii-deluxe.c:     { 0x3a,
> KEY_NEW},               /* PIP */
> drivers/media/rc/keymaps/rc-winfast.c:  { 0x2a, KEY_TV2 },
> /* PIP (Picture in picture */
> 
> > +	{ 0x52, KEY_VIDEO }, /* XXX CEC Spec: Video on Demand / input.h:
> AL
> > +Movie Browser, maybe KEY_DIRECTORY? */
> 
> I would add a KEY_VOD for that.
> 
> > +	{ 0x53, KEY_EPG },
> > +	{ 0x54, KEY_TIME }, /* XXX CEC Spec: Timer */
> > +	{ 0x55, KEY_CONFIG },
> > +	/* 0x56-0x5f: Reserved */
> 
> > +	{ 0x60, KEY_PLAY }, /* XXX CEC Spec: Play Function */
> > +	{ 0x61, KEY_PLAYPAUSE }, /* XXX CEC Spec: Pause-Play Function */
> > +	{ 0x62, KEY_RECORD }, /* XXX CEC Spec: Record Function */
> > +	{ 0x63, KEY_PAUSE }, /* XXX CEC Spec: Pause-Record Function */
> > +	{ 0x64, KEY_STOP }, /* XXX CEC Spec: Stop Function */
> > +	{ 0x65, KEY_MUTE }, /* XXX CEC Spec: Mute Function */
> > +	/* 0x66: CEC Spec: Restore Volume Function */
> > +	{ 0x67, KEY_TUNER }, /* XXX CEC Spec: Tune Function */
> > +	{ 0x68, KEY_MEDIA }, /* CEC Spec: Select Media Function */
> > +	{ 0x69, KEY_SWITCHVIDEOMODE} /* XXX CEC Spec: Select A/V Input
> Function */,
> > +	{ 0x6a, KEY_AUDIO} /* CEC Spec: Select Audio Input Function */,
> > +	{ 0x6b, KEY_POWER} /* CEC Spec: Power Toggle Function */,
> > +	{ 0x6c, KEY_SLEEP} /* XXX CEC Spec: Power Off Function */,
> > +	{ 0x6d, KEY_WAKEUP} /* XXX CEC Spec: Power On Function */,
> 
> Those "function" keycodes look weird. What's the difference between
> those and the pure non-function variants?
> 
> The spec (CEC 13.13.3) says that:
> 
> 	"Unlike the other codes, which just pass remote control presses
> 	 to the target (often with manufacturer-specific results),
> 	 the Functions are deterministic, ie they specify exactly the
> state
> 	 after executing these commands. Several of these also have
> further
> 	 operands, specifying the function in more detail, immediately
> 	 following the relevant [UI Command] operand."
> 
> Some codes are actually compund ones. For example, 0x60 has a "play
> mode"
> operand. So, the actual mapping would be:
> 
> 0x60 + 0x24 - "play forward"
> 0x61 + 0x20 - "play reverse"
> ...
> (see CEC17 for operand descriptions)
> 
> So, IMHO, the mapping should be
> 
> 	{ 0x6024, KEY_PLAY },
> 	{ 0x6020, KEY_PLAY_REVERSE }, // to be created
> 	...
> 
> 
> > +	/* 0x6e-0x70: Reserved */
> > +	{ 0x71, KEY_BLUE }, /* XXX CEC Spec: F1 (Blue) */
> > +	{ 0x72, KEY_RED }, /* XXX CEC Spec: F2 (Red) */
> > +	{ 0x73, KEY_GREEN }, /* XXX CEC Spec: F3 (Green) */
> > +	{ 0x74, KEY_YELLOW }, /* XXX CEC Spec: F4 (Yellow) */
> > +	{ 0x75, KEY_F5 },
> > +	{ 0x76, KEY_CONNECT }, /* XXX CEC Spec: Data - see Note 3 */
> > +	/* Note 3: This is used, for example, to enter or leave a digital
> TV
> > +	 * data broadcast application. */
> 
> perhaps a new keycode, like KEY_DVB? The spec is not actually too clear
> about what that "Data" key means.
> 
> > +	/* 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"


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


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

* RE: [RFC v2 2/7] media: rc: Add cec protocol handling
@ 2015-03-09 16:22       ` Kamil Debski
  0 siblings, 0 replies; 34+ messages in thread
From: Kamil Debski @ 2015-03-09 16:22 UTC (permalink / raw)
  To: 'Mauro Carvalho Chehab'
  Cc: sean, dri-devel, kyungmin.park, thomas, linux-input, linux-media,
	Marek Szyprowski

Hi Mauro, 

From: Mauro Carvalho Chehab [mailto:mchehab@osg.samsung.com]
Sent: Sunday, March 08, 2015 3:21 PM

> Em Thu, 22 Jan 2015 17:04:34 +0100
> Kamil Debski <k.debski@samsung.com> escreveu:
> 
> (c/c linux-input ML)
> 
> > Add cec protocol handling the RC framework.
> 
> I added some comments, that reflects my understanding from what's there
> at the keymap definitions found at:
> 	http://xtreamerdev.googlecode.com/files/CEC_Specs.pdf

Thank you very much for the review, Mauro. Your comments are very much appreciated.
 
> 
> >
> > Signed-off-by: Kamil Debski <k.debski@samsung.com>
> > ---
> >  drivers/media/rc/keymaps/Makefile |    1 +
> >  drivers/media/rc/keymaps/rc-cec.c |  133
> +++++++++++++++++++++++++++++++++++++
> >  drivers/media/rc/rc-main.c        |    1 +
> >  include/media/rc-core.h           |    1 +
> >  include/media/rc-map.h            |    5 +-
> >  5 files changed, 140 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..f2826c5
> > --- /dev/null
> > +++ b/drivers/media/rc/keymaps/rc-cec.c
> > @@ -0,0 +1,133 @@
> > +/* 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_SELECT }, /* XXX CEC Spec: Select, should it be
> > +KEY_SELECT or KEY_OK? */
> 
> KEY_OK is better, IMHO.
> 
> > +	{ 0x01, KEY_UP },
> > +	{ 0x02, KEY_DOWN },
> > +	{ 0x03, KEY_LEFT },
> > +	{ 0x04, KEY_RIGHT },
> > +	/* XXX 0x05-0x08 CEC Spec: Right-Up, Right-Down, Left-Up, Left-
> Down
> > +*/
> 
> I think you need to send a patch to linux-input, in order to add those
> keycodes.
> 
> > +	{ 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_0 },
> > +	{ 0x21, KEY_1 },
> > +	{ 0x22, KEY_2 },
> > +	{ 0x23, KEY_3 },
> > +	{ 0x24, KEY_4 },
> > +	{ 0x25, KEY_5 },
> > +	{ 0x26, KEY_6 },
> > +	{ 0x27, KEY_7 },
> > +	{ 0x28, KEY_8 },
> > +	{ 0x29, KEY_9 },
> 
> Better to use KEY_NUMERIC_* here, as this is not affected by the shift
> state.
> 
> > +	{ 0x2a, KEY_DOT },
> > +	{ 0x2b, KEY_ENTER },
> > +	{ 0x2c, KEY_CLEAR },
> > +	/* 0x2d-0x2e: Reserved */
> 
> > +	/* XXX 0x2f: CEC Spec: Next Favorite */
> Again another addition to Linux keystroke codes.
> 
> > +	{ 0x30, KEY_CHANNELUP },
> > +	{ 0x31, KEY_CHANNELDOWN },
> > +	{ 0x32, KEY_PREVIOUS }, /* CEC Spec: Previous Channel */
> > +	{ 0x33, KEY_SOUND }, /* CEC Spec: Sound Select */
> > +	/* XXX 0x34: CEC Spec: Input Select */
> 
> Another key to be added. Yet, other keymaps have a key to select the
> input source. Most use KEY_VIDEO, to select the video input source, and
> KEY_AUDIO, to select the audio input source.
> 
> So, KEY_VIDEO is likely the best choice here.
> 
> > +	{ 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 }, /* XXX CEC Spec: Stop, what about KEY_STOPCD?
> */
> > +	{ 0x46, KEY_PAUSE },/* XXX CEC Spec: Pause, what about
> KEY_PAUSECD?
> > +*/
> 
> The CD variants are to control the CD player on multimedia keyboards I
> think.
> only two IR maps use it. All the rest uses KEY_STOP/KEY_PAUSE.
> 
> > +	{ 0x47, KEY_RECORD },
> > +	{ 0x48, KEY_REWIND },
> > +	{ 0x49, KEY_FASTFORWARD },
> > +	{ 0x4a, KEY_EJECTCD }, /* CEC Spec: Eject */
> > +	{ 0x4b, KEY_FORWARD },
> 
> > +	{ 0x4c, }, /* XXX */
> 
> Hmm.. I guess it would be KEY_BACK for the backward keycode.
> 
> > +	{ 0x4d, KEY_STOP }, /* XXX CEC Spec: Stop-Record, what about
> KEY_STOPCD? */
> > +	{ 0x4e, KEY_PAUSE }, /* XXX CEC Spec: Pause-Record, what about
> > +KEY_PAUSECD? */
> 
> Probably, we'll need to define two new keycodes here.
> 
> > +	/* 0x4f: Reserved */
> > +	{ 0x50, KEY_ANGLE },
> > +	{ 0x51, KEY_SUBTITLE }, /* XXX CEC Spec: Sub picture, should it
> be
> > +KEY_SUBTITLE or something else? */
> 
> KEY_SUBTITLE is for subtitle OSG data. Perhaps KEY_TV2?
> 
> Different maps do different things with the PIP key:
> 
> $ git grep -i pip drivers/media/rc/keymaps/
> drivers/media/rc/keymaps/rc-alink-dtu-m.c:      { 0x0805, KEY_NEW },
> /* symbol: PIP */
> drivers/media/rc/keymaps/rc-avermedia-cardbus.c:        { 0x2b,
> KEY_VIDEO },            /* PIP (Picture-in-picture) */
> drivers/media/rc/keymaps/rc-avermedia-m135a.c:  { 0x022b, KEY_TV2 },
> /* TV2 or PIP */
> drivers/media/rc/keymaps/rc-avermedia-m135a.c:  { 0x041a, KEY_TV2 },
> /* PIP */
> drivers/media/rc/keymaps/rc-avermedia-m733a-rm-k6.c:    { 0x041a,
> KEY_TV2 },      /* PIP */
> drivers/media/rc/keymaps/rc-azurewave-ad-tu700.c:       { 0x0047,
> KEY_NEW },             /* PIP */
> drivers/media/rc/keymaps/rc-dib0700-rc5.c:      { 0x064c,
> KEY_RESERVED }, /* PIP button*/
> drivers/media/rc/keymaps/rc-digitalnow-tinytwin.c:      { 0x0053,
> KEY_NEW },             /* [symbol PIP?] */
> drivers/media/rc/keymaps/rc-dntv-live-dvbt-pro.c:       { 0x47,
> KEY_TV2 },              /* pip */
> drivers/media/rc/keymaps/rc-dvbsky.c:   { 0x000f, KEY_SUBTITLE },
> /*PIP*/
> drivers/media/rc/keymaps/rc-encore-enltv2.c:    { 0x71, KEY_TV2 },
> /* PIP */
> drivers/media/rc/keymaps/rc-evga-indtube.c:     { 0x16, KEY_TV2},
> /* PIP */
> drivers/media/rc/keymaps/rc-flydvb.c:   { 0x1a, KEY_TV2 },
> /* PIP */
> drivers/media/rc/keymaps/rc-terratec-slim.c:    { 0x02bd0b, KEY_NEW },
> /* symbol: PIP */
> drivers/media/rc/keymaps/rc-winfast-usbii-deluxe.c:     { 0x3a,
> KEY_NEW},               /* PIP */
> drivers/media/rc/keymaps/rc-winfast.c:  { 0x2a, KEY_TV2 },
> /* PIP (Picture in picture */
> 
> > +	{ 0x52, KEY_VIDEO }, /* XXX CEC Spec: Video on Demand / input.h:
> AL
> > +Movie Browser, maybe KEY_DIRECTORY? */
> 
> I would add a KEY_VOD for that.
> 
> > +	{ 0x53, KEY_EPG },
> > +	{ 0x54, KEY_TIME }, /* XXX CEC Spec: Timer */
> > +	{ 0x55, KEY_CONFIG },
> > +	/* 0x56-0x5f: Reserved */
> 
> > +	{ 0x60, KEY_PLAY }, /* XXX CEC Spec: Play Function */
> > +	{ 0x61, KEY_PLAYPAUSE }, /* XXX CEC Spec: Pause-Play Function */
> > +	{ 0x62, KEY_RECORD }, /* XXX CEC Spec: Record Function */
> > +	{ 0x63, KEY_PAUSE }, /* XXX CEC Spec: Pause-Record Function */
> > +	{ 0x64, KEY_STOP }, /* XXX CEC Spec: Stop Function */
> > +	{ 0x65, KEY_MUTE }, /* XXX CEC Spec: Mute Function */
> > +	/* 0x66: CEC Spec: Restore Volume Function */
> > +	{ 0x67, KEY_TUNER }, /* XXX CEC Spec: Tune Function */
> > +	{ 0x68, KEY_MEDIA }, /* CEC Spec: Select Media Function */
> > +	{ 0x69, KEY_SWITCHVIDEOMODE} /* XXX CEC Spec: Select A/V Input
> Function */,
> > +	{ 0x6a, KEY_AUDIO} /* CEC Spec: Select Audio Input Function */,
> > +	{ 0x6b, KEY_POWER} /* CEC Spec: Power Toggle Function */,
> > +	{ 0x6c, KEY_SLEEP} /* XXX CEC Spec: Power Off Function */,
> > +	{ 0x6d, KEY_WAKEUP} /* XXX CEC Spec: Power On Function */,
> 
> Those "function" keycodes look weird. What's the difference between
> those and the pure non-function variants?
> 
> The spec (CEC 13.13.3) says that:
> 
> 	"Unlike the other codes, which just pass remote control presses
> 	 to the target (often with manufacturer-specific results),
> 	 the Functions are deterministic, ie they specify exactly the
> state
> 	 after executing these commands. Several of these also have
> further
> 	 operands, specifying the function in more detail, immediately
> 	 following the relevant [UI Command] operand."
> 
> Some codes are actually compund ones. For example, 0x60 has a "play
> mode"
> operand. So, the actual mapping would be:
> 
> 0x60 + 0x24 - "play forward"
> 0x61 + 0x20 - "play reverse"
> ...
> (see CEC17 for operand descriptions)
> 
> So, IMHO, the mapping should be
> 
> 	{ 0x6024, KEY_PLAY },
> 	{ 0x6020, KEY_PLAY_REVERSE }, // to be created
> 	...
> 
> 
> > +	/* 0x6e-0x70: Reserved */
> > +	{ 0x71, KEY_BLUE }, /* XXX CEC Spec: F1 (Blue) */
> > +	{ 0x72, KEY_RED }, /* XXX CEC Spec: F2 (Red) */
> > +	{ 0x73, KEY_GREEN }, /* XXX CEC Spec: F3 (Green) */
> > +	{ 0x74, KEY_YELLOW }, /* XXX CEC Spec: F4 (Yellow) */
> > +	{ 0x75, KEY_F5 },
> > +	{ 0x76, KEY_CONNECT }, /* XXX CEC Spec: Data - see Note 3 */
> > +	/* Note 3: This is used, for example, to enter or leave a digital
> TV
> > +	 * data broadcast application. */
> 
> perhaps a new keycode, like KEY_DVB? The spec is not actually too clear
> about what that "Data" key means.
> 
> > +	/* 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"


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

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* RE: [RFC v2 3/7] cec: add new framework for cec support.
  2015-03-08 15:41       ` Mauro Carvalho Chehab
@ 2015-03-09 16:22           ` Kamil Debski
  0 siblings, 0 replies; 34+ messages in thread
From: Kamil Debski @ 2015-03-09 16:22 UTC (permalink / raw)
  To: 'Mauro Carvalho Chehab'
  Cc: 'Sean Young',
	dri-devel, linux-media, Marek Szyprowski, hverkuil,
	kyungmin.park, thomas, 'Hans Verkuil'

Hi Mauro,

Thank you for your comments.

From: Mauro Carvalho Chehab [mailto:mchehab@osg.samsung.com]
Sent: Sunday, March 08, 2015 4:42 PM

> 
> Em Fri, 06 Mar 2015 17:14:50 +0100
> Kamil Debski <k.debski@samsung.com> escreveu:
> 
> > Hi Sean, Hans,
> >
> > I am sorry to reply so late, I was busy with other work. I am
> > preparing the next version of the CEC framework and I would like to
> > discuss your comment.
> 
> I'll do a deeper review of this patch when I have some time. For now,
> let me add my comments about the pass-trough mode. See below.

I think I might have confused you with the pass-through mode. I think it
would be good if I explained it in detail.

I guess my initial name choice wasn't fortunate. I prefer the name "raw"
over "pass through" as it is closer to what I meant by adding this feature. 
Maybe even "promiscuous" could be better.

The CEC framework does filtering on the messages it receives. It will
filter messages not directed to the device (different logical address)
and will do parsing of the keystrokes. The keystrokes are then reported by
the input framework to the userspace and won't be read by the CEC_RECEIVE
ioctl.

In the "raw"/"promiscuous" the messages on the CEC bus would not be
filtered and all of them should be passed to the userspace. This will
include messages not intended for the particular device and keystroke
messages. I think that this mode could be useful, e.g. for debugging and
maybe for devices that act as switches.

My original idea was that in the "raw" mode the CEC framework would stop
passing the keycodes from the CEC bus to the input device. I see that
this can be problematic, hence I think that suspending from passing the
keycodes to the input framework is not necessary. 

I think that this solution would be acceptable for you guys. Mauro, Sean,
Hans, tell me if I am wrong? To recap - the "raw"/"promiscuous" mode would
only disable filtering of messages and had no effect on passing keycodes
to the input device.

> >
> > From: Sean Young [mailto:sean@mess.org]
> > Sent: Friday, January 23, 2015 12:08 PM
> > >
> > > On Thu, Jan 22, 2015 at 05:04:35PM +0100, Kamil Debski wrote:
> > > > Add the CEC framework.
> > > -snip-
> > > > +Remote control handling
> > > > +-----------------------
> > > > +
> > > > +The CEC framework provides two ways of handling the key messages
> > > > +of remote control. In the first case, the CEC framework will
> > > > +handle these messages and provide the keypressed via the RC
> > > > +framework. In the second case the messages related to the key
> > > > +down/up events are not parsed by the framework and are passed to
> > > > +the userspace as raw
> > > messages.
> > > > +
> > > > +Switching between these modes is done with a special ioctl.
> > > > +
> > > > +#define CEC_G_KEY_PASSTHROUGH	_IOR('a', 10, __u8)
> > > > +#define CEC_S_KEY_PASSTHROUGH	_IOW('a', 11, __u8)
> > > > +#define CEC_KEY_PASSTHROUGH_DISABLE	0
> > > > +#define CEC_KEY_PASSTHROUGH_ENABLE	1
> > >
> > > This is ugly. This ioctl stops keypresses from going to rc-core.
> The
> > > cec device is still registered with rc-core but no keys will be
> > > passed to it.
> > > This could also be handled by loading an empty keymap; this way the
> > > input layer will still receive scancodes but no keypresses.
> >
> > I see here a few options that can be done:
> >
> > 1) Remove the past through option altogether I think I would opt for
> > leaving it. There should be some mode that would enable raw access to
> > the CEC bus. Maybe it should be something more like a promiscuous
> mode
> > in Wi-Fi networks. What do you think? Sean, Hans?
> >
> > 2) Leave the pass through mode, but without disabling passing the
> > keyup/down events to the RC framework. This way an application could
> > capture all messages, but the input device would not be crippled in
> > any way. The problem with this solution is that key presses could be
> > accounted twice.
> >
> > 3) As you suggested - load an empty keymap whenever the pass through
> > mode is enabled.
> > I am not that familiar with the RC core. Is there a simple way to
> > switch to an empty map from the kernel? There is the ir_setkeytable
> > function, but it is static in rc-main.c, so it cannot be used in
> other
> > kernel modules. Any hints, Sean?
> >
> > 4) Remove the input device whenever a pass through mode is enabled.
> > This is an alternative to the solution number 3. I think it would not
> > be great, because a
> > /dev/input/event* that appears
> > and disappears could be confusing.
> 
> (4) doesn't seem nice.
> 
> I don't think that the driver itself should cleanup the keymap. This is
> something that the userspace app(s) should explicitly request.

I agree.

> With regards to the "raw" mode, the RC core currently has two ways to
> send/receive raw data:
> 
> 1) Via LIRC. This needs to be extended to pass scancodes, as, currently,
> it sends/receive pulses. We need such extension for other usages,
> anyway, so adding it makes sense.

That is another thing I need to implement - send keycodes to other
devices.

> 
> 2) The input layer actually provide several types of events on a key
> press. One of such events carry on the scancode:
> 
> 1425828993.018962: event type EV_KEY(0x01) key_down:
> KEY_VOLUMEDOWN(0x0001)
> 1425828993.018962: event type EV_SYN(0x00).
> 1425828993.131823: event type EV_KEY(0x01) key_up:
> KEY_VOLUMEDOWN(0x0001)
> 1425828993.131823: event type EV_MSC(0x04): scancode = 0x1e
> 1425828993.131823: event type EV_SYN(0x00).
> 
> The EV_KEY events has the Linux Keycode, plus the info if the key was
> pressed or released, while the EV_MSC has the scancode.
> 
> So, I'm not seeing much usage of a pass-through mode, as, even without
> LIRC, the userspace could simply cleanup the key map, and listen to
> EV_MSC:

Maybe I made this confusing - the pass-through (raw/promiscuous) mode
would be useful for debugging and I think for switches that forward CEC
messages. 

> 
> $ sudo ir-keytable -c -t
> Old keytable cleared
> Testing events. Please, press CTRL-C to abort.
> 1425829137.721737: event type EV_MSC(0x04): scancode = 0x1b
> 1425829137.721737: event type EV_SYN(0x00).
> 1425829139.318249: event type EV_MSC(0x04): scancode = 0x18
> 1425829139.318249: event type EV_SYN(0x00).
> ...
> 
> Yet, the best would be for the application is to setup the key map it
> needs, and just use the standard Linux way: wait for EV_KEY events.
> 
> Regards,
> Mauro
> 
> >
> > >
> > > > +static ssize_t cec_read(struct file *filp, char __user *buf,
> > > > +		size_t sz, loff_t *off)
> > > > +{
> > > > +	struct cec_devnode *cecdev = cec_devnode_data(filp);
> > > > +
> > > > +	if (!cec_devnode_is_registered(cecdev))
> > > > +		return -EIO;
> > > > +	return 0;
> > > > +}
> > > > +
> > > > +static ssize_t cec_write(struct file *filp, const char __user
> *buf,
> > > > +		size_t sz, loff_t *off)
> > > > +{
> > > > +	struct cec_devnode *cecdev = cec_devnode_data(filp);
> > > > +
> > > > +	if (!cec_devnode_is_registered(cecdev))
> > > > +		return -EIO;
> > > > +	return 0;
> > > > +}
> > >
> > > Both read and write do nothing; they should either -ENOSYS or the
> > > fuctions should be removed.
> > >
> >
> > I agree, I removed this for the next version.
> >
> > Best wishes,

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


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

* RE: [RFC v2 3/7] cec: add new framework for cec support.
@ 2015-03-09 16:22           ` Kamil Debski
  0 siblings, 0 replies; 34+ messages in thread
From: Kamil Debski @ 2015-03-09 16:22 UTC (permalink / raw)
  To: 'Mauro Carvalho Chehab'
  Cc: 'Hans Verkuil', 'Sean Young',
	dri-devel, kyungmin.park, thomas, linux-media, Marek Szyprowski

Hi Mauro,

Thank you for your comments.

From: Mauro Carvalho Chehab [mailto:mchehab@osg.samsung.com]
Sent: Sunday, March 08, 2015 4:42 PM

> 
> Em Fri, 06 Mar 2015 17:14:50 +0100
> Kamil Debski <k.debski@samsung.com> escreveu:
> 
> > Hi Sean, Hans,
> >
> > I am sorry to reply so late, I was busy with other work. I am
> > preparing the next version of the CEC framework and I would like to
> > discuss your comment.
> 
> I'll do a deeper review of this patch when I have some time. For now,
> let me add my comments about the pass-trough mode. See below.

I think I might have confused you with the pass-through mode. I think it
would be good if I explained it in detail.

I guess my initial name choice wasn't fortunate. I prefer the name "raw"
over "pass through" as it is closer to what I meant by adding this feature. 
Maybe even "promiscuous" could be better.

The CEC framework does filtering on the messages it receives. It will
filter messages not directed to the device (different logical address)
and will do parsing of the keystrokes. The keystrokes are then reported by
the input framework to the userspace and won't be read by the CEC_RECEIVE
ioctl.

In the "raw"/"promiscuous" the messages on the CEC bus would not be
filtered and all of them should be passed to the userspace. This will
include messages not intended for the particular device and keystroke
messages. I think that this mode could be useful, e.g. for debugging and
maybe for devices that act as switches.

My original idea was that in the "raw" mode the CEC framework would stop
passing the keycodes from the CEC bus to the input device. I see that
this can be problematic, hence I think that suspending from passing the
keycodes to the input framework is not necessary. 

I think that this solution would be acceptable for you guys. Mauro, Sean,
Hans, tell me if I am wrong? To recap - the "raw"/"promiscuous" mode would
only disable filtering of messages and had no effect on passing keycodes
to the input device.

> >
> > From: Sean Young [mailto:sean@mess.org]
> > Sent: Friday, January 23, 2015 12:08 PM
> > >
> > > On Thu, Jan 22, 2015 at 05:04:35PM +0100, Kamil Debski wrote:
> > > > Add the CEC framework.
> > > -snip-
> > > > +Remote control handling
> > > > +-----------------------
> > > > +
> > > > +The CEC framework provides two ways of handling the key messages
> > > > +of remote control. In the first case, the CEC framework will
> > > > +handle these messages and provide the keypressed via the RC
> > > > +framework. In the second case the messages related to the key
> > > > +down/up events are not parsed by the framework and are passed to
> > > > +the userspace as raw
> > > messages.
> > > > +
> > > > +Switching between these modes is done with a special ioctl.
> > > > +
> > > > +#define CEC_G_KEY_PASSTHROUGH	_IOR('a', 10, __u8)
> > > > +#define CEC_S_KEY_PASSTHROUGH	_IOW('a', 11, __u8)
> > > > +#define CEC_KEY_PASSTHROUGH_DISABLE	0
> > > > +#define CEC_KEY_PASSTHROUGH_ENABLE	1
> > >
> > > This is ugly. This ioctl stops keypresses from going to rc-core.
> The
> > > cec device is still registered with rc-core but no keys will be
> > > passed to it.
> > > This could also be handled by loading an empty keymap; this way the
> > > input layer will still receive scancodes but no keypresses.
> >
> > I see here a few options that can be done:
> >
> > 1) Remove the past through option altogether I think I would opt for
> > leaving it. There should be some mode that would enable raw access to
> > the CEC bus. Maybe it should be something more like a promiscuous
> mode
> > in Wi-Fi networks. What do you think? Sean, Hans?
> >
> > 2) Leave the pass through mode, but without disabling passing the
> > keyup/down events to the RC framework. This way an application could
> > capture all messages, but the input device would not be crippled in
> > any way. The problem with this solution is that key presses could be
> > accounted twice.
> >
> > 3) As you suggested - load an empty keymap whenever the pass through
> > mode is enabled.
> > I am not that familiar with the RC core. Is there a simple way to
> > switch to an empty map from the kernel? There is the ir_setkeytable
> > function, but it is static in rc-main.c, so it cannot be used in
> other
> > kernel modules. Any hints, Sean?
> >
> > 4) Remove the input device whenever a pass through mode is enabled.
> > This is an alternative to the solution number 3. I think it would not
> > be great, because a
> > /dev/input/event* that appears
> > and disappears could be confusing.
> 
> (4) doesn't seem nice.
> 
> I don't think that the driver itself should cleanup the keymap. This is
> something that the userspace app(s) should explicitly request.

I agree.

> With regards to the "raw" mode, the RC core currently has two ways to
> send/receive raw data:
> 
> 1) Via LIRC. This needs to be extended to pass scancodes, as, currently,
> it sends/receive pulses. We need such extension for other usages,
> anyway, so adding it makes sense.

That is another thing I need to implement - send keycodes to other
devices.

> 
> 2) The input layer actually provide several types of events on a key
> press. One of such events carry on the scancode:
> 
> 1425828993.018962: event type EV_KEY(0x01) key_down:
> KEY_VOLUMEDOWN(0x0001)
> 1425828993.018962: event type EV_SYN(0x00).
> 1425828993.131823: event type EV_KEY(0x01) key_up:
> KEY_VOLUMEDOWN(0x0001)
> 1425828993.131823: event type EV_MSC(0x04): scancode = 0x1e
> 1425828993.131823: event type EV_SYN(0x00).
> 
> The EV_KEY events has the Linux Keycode, plus the info if the key was
> pressed or released, while the EV_MSC has the scancode.
> 
> So, I'm not seeing much usage of a pass-through mode, as, even without
> LIRC, the userspace could simply cleanup the key map, and listen to
> EV_MSC:

Maybe I made this confusing - the pass-through (raw/promiscuous) mode
would be useful for debugging and I think for switches that forward CEC
messages. 

> 
> $ sudo ir-keytable -c -t
> Old keytable cleared
> Testing events. Please, press CTRL-C to abort.
> 1425829137.721737: event type EV_MSC(0x04): scancode = 0x1b
> 1425829137.721737: event type EV_SYN(0x00).
> 1425829139.318249: event type EV_MSC(0x04): scancode = 0x18
> 1425829139.318249: event type EV_SYN(0x00).
> ...
> 
> Yet, the best would be for the application is to setup the key map it
> needs, and just use the standard Linux way: wait for EV_KEY events.
> 
> Regards,
> Mauro
> 
> >
> > >
> > > > +static ssize_t cec_read(struct file *filp, char __user *buf,
> > > > +		size_t sz, loff_t *off)
> > > > +{
> > > > +	struct cec_devnode *cecdev = cec_devnode_data(filp);
> > > > +
> > > > +	if (!cec_devnode_is_registered(cecdev))
> > > > +		return -EIO;
> > > > +	return 0;
> > > > +}
> > > > +
> > > > +static ssize_t cec_write(struct file *filp, const char __user
> *buf,
> > > > +		size_t sz, loff_t *off)
> > > > +{
> > > > +	struct cec_devnode *cecdev = cec_devnode_data(filp);
> > > > +
> > > > +	if (!cec_devnode_is_registered(cecdev))
> > > > +		return -EIO;
> > > > +	return 0;
> > > > +}
> > >
> > > Both read and write do nothing; they should either -ENOSYS or the
> > > fuctions should be removed.
> > >
> >
> > I agree, I removed this for the next version.
> >
> > Best wishes,

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

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [RFC v2 2/7] media: rc: Add cec protocol handling
  2015-03-09 16:22       ` Kamil Debski
  (?)
@ 2015-03-09 16:43       ` Bastien Nocera
  2015-03-10 12:02           ` Kamil Debski
  -1 siblings, 1 reply; 34+ messages in thread
From: Bastien Nocera @ 2015-03-09 16:43 UTC (permalink / raw)
  To: Kamil Debski
  Cc: 'Mauro Carvalho Chehab',
	dri-devel, linux-media, Marek Szyprowski, hverkuil,
	kyungmin.park, thomas, sean, linux-input

On Mon, 2015-03-09 at 17:22 +0100, Kamil Debski wrote:
> Hi Mauro,
> 
> From: Mauro Carvalho Chehab [mailto:mchehab@osg.samsung.com]
> Sent: Sunday, March 08, 2015 3:21 PM
> 
> > Em Thu, 22 Jan 2015 17:04:34 +0100
> > Kamil Debski <k.debski@samsung.com> escreveu:
> > 
> > (c/c linux-input ML)
> > 
> > > Add cec protocol handling the RC framework.
> > 
> > I added some comments, that reflects my understanding from what's 
> > there at the keymap definitions found at:
> >         http://xtreamerdev.googlecode.com/files/CEC_Specs.pdf
> 
> Thank you very much for the review, Mauro. Your comments are very 
> much appreciated.

How does one use this new support? If I plug in my laptop to my TV, 
will using the TV's remote automatically send those key events to the 
laptop?

Cheers

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

* RE: [RFC v2 2/7] media: rc: Add cec protocol handling
  2015-03-09 16:43       ` Bastien Nocera
@ 2015-03-10 12:02           ` Kamil Debski
  0 siblings, 0 replies; 34+ messages in thread
From: Kamil Debski @ 2015-03-10 12:02 UTC (permalink / raw)
  To: 'Bastien Nocera'
  Cc: 'Mauro Carvalho Chehab',
	dri-devel, linux-media, Marek Szyprowski, hverkuil,
	kyungmin.park, thomas, sean, linux-input

Hi Bastien,

From: Bastien Nocera [mailto:hadess@hadess.net]
Sent: Monday, March 09, 2015 5:44 PM
> 
> On Mon, 2015-03-09 at 17:22 +0100, Kamil Debski wrote:
> > Hi Mauro,
> >
> > From: Mauro Carvalho Chehab [mailto:mchehab@osg.samsung.com]
> > Sent: Sunday, March 08, 2015 3:21 PM
> >
> > > Em Thu, 22 Jan 2015 17:04:34 +0100
> > > Kamil Debski <k.debski@samsung.com> escreveu:
> > >
> > > (c/c linux-input ML)
> > >
> > > > Add cec protocol handling the RC framework.
> > >
> > > I added some comments, that reflects my understanding from what's
> > > there at the keymap definitions found at:
> > >         http://xtreamerdev.googlecode.com/files/CEC_Specs.pdf
> >
> > Thank you very much for the review, Mauro. Your comments are very
> much
> > appreciated.
> 
> How does one use this new support? If I plug in my laptop to my TV,
> will using the TV's remote automatically send those key events to the
> laptop?

It depends on the hardware that is used in your laptop to handle HDMI.
If there is hardware support for CEC then this framework can be used
to create a driver for the laptop's HDMI hardware. Then the laptop will
be able to communicate with the TV over CEC - this includes receiving
key events from the TV.

Currently there are some CEC devices (and drivers) that enable Linux to
use CEC, but there is no generic framework for CEC in the Linux kernel.
My goal is to introduce such a framework, such that userspace
application could work with different hardware using the same interface.

Getting back to your question - using this framework. There should be
some initialization done by a user space application:
- enabling CEC (if needed by the hardware/driver)
- configuring the connection (e.g. what kind of device should the
  laptop appear as, request the TV to pass remote control keys, etc.)
- the TV will also send other CEC messages to the laptop, hence the
  application should listen for such messages and act accordingly

How this should be done userspace? Definitely, it would be a good idea
to use a library. Maybe a deamon that does the steps mentioned above
would be a good idea? I am working on a simple library implementation
that would wrap the kernel ioctls and provide a more user friendly API.

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


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

* RE: [RFC v2 2/7] media: rc: Add cec protocol handling
@ 2015-03-10 12:02           ` Kamil Debski
  0 siblings, 0 replies; 34+ messages in thread
From: Kamil Debski @ 2015-03-10 12:02 UTC (permalink / raw)
  To: 'Bastien Nocera'
  Cc: sean, 'Mauro Carvalho Chehab',
	dri-devel, kyungmin.park, thomas, linux-input, linux-media,
	Marek Szyprowski

Hi Bastien,

From: Bastien Nocera [mailto:hadess@hadess.net]
Sent: Monday, March 09, 2015 5:44 PM
> 
> On Mon, 2015-03-09 at 17:22 +0100, Kamil Debski wrote:
> > Hi Mauro,
> >
> > From: Mauro Carvalho Chehab [mailto:mchehab@osg.samsung.com]
> > Sent: Sunday, March 08, 2015 3:21 PM
> >
> > > Em Thu, 22 Jan 2015 17:04:34 +0100
> > > Kamil Debski <k.debski@samsung.com> escreveu:
> > >
> > > (c/c linux-input ML)
> > >
> > > > Add cec protocol handling the RC framework.
> > >
> > > I added some comments, that reflects my understanding from what's
> > > there at the keymap definitions found at:
> > >         http://xtreamerdev.googlecode.com/files/CEC_Specs.pdf
> >
> > Thank you very much for the review, Mauro. Your comments are very
> much
> > appreciated.
> 
> How does one use this new support? If I plug in my laptop to my TV,
> will using the TV's remote automatically send those key events to the
> laptop?

It depends on the hardware that is used in your laptop to handle HDMI.
If there is hardware support for CEC then this framework can be used
to create a driver for the laptop's HDMI hardware. Then the laptop will
be able to communicate with the TV over CEC - this includes receiving
key events from the TV.

Currently there are some CEC devices (and drivers) that enable Linux to
use CEC, but there is no generic framework for CEC in the Linux kernel.
My goal is to introduce such a framework, such that userspace
application could work with different hardware using the same interface.

Getting back to your question - using this framework. There should be
some initialization done by a user space application:
- enabling CEC (if needed by the hardware/driver)
- configuring the connection (e.g. what kind of device should the
  laptop appear as, request the TV to pass remote control keys, etc.)
- the TV will also send other CEC messages to the laptop, hence the
  application should listen for such messages and act accordingly

How this should be done userspace? Definitely, it would be a good idea
to use a library. Maybe a deamon that does the steps mentioned above
would be a good idea? I am working on a simple library implementation
that would wrap the kernel ioctls and provide a more user friendly API.

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

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [RFC v2 2/7] media: rc: Add cec protocol handling
  2015-03-10 12:02           ` Kamil Debski
  (?)
@ 2015-03-10 14:13           ` Hans Verkuil
  -1 siblings, 0 replies; 34+ messages in thread
From: Hans Verkuil @ 2015-03-10 14:13 UTC (permalink / raw)
  To: Kamil Debski, 'Bastien Nocera'
  Cc: 'Mauro Carvalho Chehab',
	dri-devel, linux-media, Marek Szyprowski, kyungmin.park, thomas,
	sean, linux-input

On 03/10/2015 01:02 PM, Kamil Debski wrote:
> Hi Bastien,
> 
> From: Bastien Nocera [mailto:hadess@hadess.net]
> Sent: Monday, March 09, 2015 5:44 PM
>>
>> On Mon, 2015-03-09 at 17:22 +0100, Kamil Debski wrote:
>>> Hi Mauro,
>>>
>>> From: Mauro Carvalho Chehab [mailto:mchehab@osg.samsung.com]
>>> Sent: Sunday, March 08, 2015 3:21 PM
>>>
>>>> Em Thu, 22 Jan 2015 17:04:34 +0100
>>>> Kamil Debski <k.debski@samsung.com> escreveu:
>>>>
>>>> (c/c linux-input ML)
>>>>
>>>>> Add cec protocol handling the RC framework.
>>>>
>>>> I added some comments, that reflects my understanding from what's
>>>> there at the keymap definitions found at:
>>>>         http://xtreamerdev.googlecode.com/files/CEC_Specs.pdf
>>>
>>> Thank you very much for the review, Mauro. Your comments are very
>> much
>>> appreciated.
>>
>> How does one use this new support? If I plug in my laptop to my TV,
>> will using the TV's remote automatically send those key events to the
>> laptop?
> 
> It depends on the hardware that is used in your laptop to handle HDMI.
> If there is hardware support for CEC then this framework can be used
> to create a driver for the laptop's HDMI hardware. Then the laptop will
> be able to communicate with the TV over CEC - this includes receiving
> key events from the TV.
> 
> Currently there are some CEC devices (and drivers) that enable Linux to
> use CEC, but there is no generic framework for CEC in the Linux kernel.
> My goal is to introduce such a framework, such that userspace
> application could work with different hardware using the same interface.
> 
> Getting back to your question - using this framework. There should be
> some initialization done by a user space application:
> - enabling CEC (if needed by the hardware/driver)
> - configuring the connection (e.g. what kind of device should the
>   laptop appear as, request the TV to pass remote control keys, etc.)
> - the TV will also send other CEC messages to the laptop, hence the
>   application should listen for such messages and act accordingly
> 
> How this should be done userspace? Definitely, it would be a good idea
> to use a library. Maybe a deamon that does the steps mentioned above
> would be a good idea? I am working on a simple library implementation
> that would wrap the kernel ioctls and provide a more user friendly API.

Let me add to this as the original designer of this framework: first of
all the CEC protocol is a protocol from hell, very ad-hoc designed.

The problem with that is that it very much depends on the product or device
driver what - if anything - of the CEC protocol should be exposed to the
end-user. You can decide to keep all the CEC handling in the driver, or
do almost everything in userspace or anything in between. The hardware
itself can be an HDMI receiver, transmitter or repeater, or it can be a
USB dongle that controls the CEC bus between two HDMI devices. So even
the subsystem involved in the device can be all over the place (usb,
drm, v4l).

So this CEC framework keeps the core protocol handling inside the kernel,
and allows drivers to expose the CEC protocol to varying degrees to
userspace. The pure CEC core commands should be handled in the kernel so
no userspace components should be needed to get a valid working setup. A
USB dongle might be an exception to that rule, I haven't looked at that
in detail.

On the userspace side of the CEC framework we might need a simple library.
I'm not so sure about a daemon: that should definitely be optional.

A standard cec-ctl utility to help test and control the CEC bus would be
useful. I am also thinking that a cec-compliance test utility would be
extremely useful to verify that drivers (and userspace) implement the
CEC commands correctly. Since CEC is a bit of a disaster, such a tool
would help a lot. Time permitting this is something I might work on
myself.

Regards,

	Hans

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

* Re: [RFC v2 2/7] media: rc: Add cec protocol handling
  2015-03-10 12:02           ` Kamil Debski
  (?)
  (?)
@ 2015-03-10 14:14           ` Bastien Nocera
  2015-03-10 15:40               ` Kamil Debski
  -1 siblings, 1 reply; 34+ messages in thread
From: Bastien Nocera @ 2015-03-10 14:14 UTC (permalink / raw)
  To: Kamil Debski
  Cc: 'Mauro Carvalho Chehab',
	dri-devel, linux-media, Marek Szyprowski, hverkuil,
	kyungmin.park, thomas, sean, linux-input

On Tue, 2015-03-10 at 13:02 +0100, Kamil Debski wrote:
> Hi Bastien,
> 
> From: Bastien Nocera [mailto:hadess@hadess.net]
> Sent: Monday, March 09, 2015 5:44 PM
> > 
> > On Mon, 2015-03-09 at 17:22 +0100, Kamil Debski wrote:
> > > Hi Mauro,
> > > 
> > > From: Mauro Carvalho Chehab [mailto:mchehab@osg.samsung.com]
> > > Sent: Sunday, March 08, 2015 3:21 PM
> > > 
> > > > Em Thu, 22 Jan 2015 17:04:34 +0100
> > > > Kamil Debski <k.debski@samsung.com> escreveu:
> > > > 
> > > > (c/c linux-input ML)
> > > > 
> > > > > Add cec protocol handling the RC framework.
> > > > 
> > > > I added some comments, that reflects my understanding from 
> > > > what's there at the keymap definitions found at:
> > > >         http://xtreamerdev.googlecode.com/files/CEC_Specs.pdf
> > > 
> > > Thank you very much for the review, Mauro. Your comments are very
> > much
> > > appreciated.
> > 
> > How does one use this new support? If I plug in my laptop to my 
> > TV, will using the TV's remote automatically send those key events 
> > to the laptop?
> 
> It depends on the hardware that is used in your laptop to handle 
> HDMI. If there is hardware support for CEC then this framework can 
> be used to create a driver for the laptop's HDMI hardware. Then the 
> laptop will be able to communicate with the TV over CEC - this 
> includes receiving key events from the TV.
> 
> Currently there are some CEC devices (and drivers) that enable Linux 
> to use CEC, but there is no generic framework for CEC in the Linux 
> kernel. My goal is to introduce such a framework, such that 
> userspace application could work with different hardware using the 
> same interface.
> 
> Getting back to your question - using this framework. There should 
> be some initialization done by a user space application:
> - enabling CEC (if needed by the hardware/driver)

I have 2 machines that this could work on, a Intel Baytrail tablet, 
and a laptop with Intel Haswell. Is that part going to be covered by 
your library, or will there be a drm API for that?

> - configuring the connection (e.g. what kind of device should the
>   laptop appear as, request the TV to pass remote control keys, etc.)

That's done through the CEC API as well?

> - the TV will also send other CEC messages to the laptop, hence the
>   application should listen for such messages and act accordingly

That's easier to deal with :)

Something like LIRC can be used in the short-term.

> How this should be done userspace? Definitely, it would be a good 
> idea to use a library. Maybe a deamon that does the steps mentioned 
> above would be a good idea? I am working on a simple library 
> implementation that would wrap the kernel ioctls and provide a more 
> user friendly API.

Great. Do drop me a mail when you have something that I could test.

Cheers

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

* RE: [RFC v2 2/7] media: rc: Add cec protocol handling
  2015-03-10 14:14           ` Bastien Nocera
@ 2015-03-10 15:40               ` Kamil Debski
  0 siblings, 0 replies; 34+ messages in thread
From: Kamil Debski @ 2015-03-10 15:40 UTC (permalink / raw)
  To: 'Bastien Nocera'
  Cc: 'Mauro Carvalho Chehab',
	dri-devel, linux-media, Marek Szyprowski, hverkuil,
	kyungmin.park, thomas, sean, linux-input

From: Bastien Nocera [mailto:hadess@hadess.net]
Sent: Tuesday, March 10, 2015 3:15 PM
> 
> On Tue, 2015-03-10 at 13:02 +0100, Kamil Debski wrote:
> > Hi Bastien,
> >
> > From: Bastien Nocera [mailto:hadess@hadess.net]
> > Sent: Monday, March 09, 2015 5:44 PM
> > >
> > > On Mon, 2015-03-09 at 17:22 +0100, Kamil Debski wrote:
> > > > Hi Mauro,
> > > >
> > > > From: Mauro Carvalho Chehab [mailto:mchehab@osg.samsung.com]
> > > > Sent: Sunday, March 08, 2015 3:21 PM
> > > >
> > > > > Em Thu, 22 Jan 2015 17:04:34 +0100 Kamil Debski
> > > > > <k.debski@samsung.com> escreveu:
> > > > >
> > > > > (c/c linux-input ML)
> > > > >
> > > > > > Add cec protocol handling the RC framework.
> > > > >
> > > > > I added some comments, that reflects my understanding from
> > > > > what's there at the keymap definitions found at:
> > > > >         http://xtreamerdev.googlecode.com/files/CEC_Specs.pdf
> > > >
> > > > Thank you very much for the review, Mauro. Your comments are very
> > > much
> > > > appreciated.
> > >
> > > How does one use this new support? If I plug in my laptop to my TV,
> > > will using the TV's remote automatically send those key events to
> > > the laptop?
> >
> > It depends on the hardware that is used in your laptop to handle HDMI.
> > If there is hardware support for CEC then this framework can be used
> > to create a driver for the laptop's HDMI hardware. Then the laptop
> > will be able to communicate with the TV over CEC - this includes
> > receiving key events from the TV.
> >
> > Currently there are some CEC devices (and drivers) that enable Linux
> > to use CEC, but there is no generic framework for CEC in the Linux
> > kernel. My goal is to introduce such a framework, such that userspace
> > application could work with different hardware using the same
> > interface.
> >
> > Getting back to your question - using this framework. There should be
> > some initialization done by a user space application:
> > - enabling CEC (if needed by the hardware/driver)
> 
> I have 2 machines that this could work on, a Intel Baytrail tablet, and
> a laptop with Intel Haswell. Is that part going to be covered by your
> library, or will there be a drm API for that?

Enabling CEC is done by the CEC framework. The idea is to have it
independent of other frameworks (such as drm, or v4l2).

> 
> > - configuring the connection (e.g. what kind of device should the
> >   laptop appear as, request the TV to pass remote control keys, etc.)
> 
> That's done through the CEC API as well?

Yes.

> 
> > - the TV will also send other CEC messages to the laptop, hence the
> >   application should listen for such messages and act accordingly
> 
> That's easier to deal with :)
> 
> Something like LIRC can be used in the short-term.
> 
> > How this should be done userspace? Definitely, it would be a good
> idea
> > to use a library. Maybe a deamon that does the steps mentioned above
> > would be a good idea? I am working on a simple library implementation
> > that would wrap the kernel ioctls and provide a more user friendly
> > API.
> 
> Great. Do drop me a mail when you have something that I could test.

Will do.
 
> Cheers

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


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

* RE: [RFC v2 2/7] media: rc: Add cec protocol handling
@ 2015-03-10 15:40               ` Kamil Debski
  0 siblings, 0 replies; 34+ messages in thread
From: Kamil Debski @ 2015-03-10 15:40 UTC (permalink / raw)
  To: 'Bastien Nocera'
  Cc: sean, 'Mauro Carvalho Chehab',
	dri-devel, kyungmin.park, thomas, linux-input, linux-media,
	Marek Szyprowski

From: Bastien Nocera [mailto:hadess@hadess.net]
Sent: Tuesday, March 10, 2015 3:15 PM
> 
> On Tue, 2015-03-10 at 13:02 +0100, Kamil Debski wrote:
> > Hi Bastien,
> >
> > From: Bastien Nocera [mailto:hadess@hadess.net]
> > Sent: Monday, March 09, 2015 5:44 PM
> > >
> > > On Mon, 2015-03-09 at 17:22 +0100, Kamil Debski wrote:
> > > > Hi Mauro,
> > > >
> > > > From: Mauro Carvalho Chehab [mailto:mchehab@osg.samsung.com]
> > > > Sent: Sunday, March 08, 2015 3:21 PM
> > > >
> > > > > Em Thu, 22 Jan 2015 17:04:34 +0100 Kamil Debski
> > > > > <k.debski@samsung.com> escreveu:
> > > > >
> > > > > (c/c linux-input ML)
> > > > >
> > > > > > Add cec protocol handling the RC framework.
> > > > >
> > > > > I added some comments, that reflects my understanding from
> > > > > what's there at the keymap definitions found at:
> > > > >         http://xtreamerdev.googlecode.com/files/CEC_Specs.pdf
> > > >
> > > > Thank you very much for the review, Mauro. Your comments are very
> > > much
> > > > appreciated.
> > >
> > > How does one use this new support? If I plug in my laptop to my TV,
> > > will using the TV's remote automatically send those key events to
> > > the laptop?
> >
> > It depends on the hardware that is used in your laptop to handle HDMI.
> > If there is hardware support for CEC then this framework can be used
> > to create a driver for the laptop's HDMI hardware. Then the laptop
> > will be able to communicate with the TV over CEC - this includes
> > receiving key events from the TV.
> >
> > Currently there are some CEC devices (and drivers) that enable Linux
> > to use CEC, but there is no generic framework for CEC in the Linux
> > kernel. My goal is to introduce such a framework, such that userspace
> > application could work with different hardware using the same
> > interface.
> >
> > Getting back to your question - using this framework. There should be
> > some initialization done by a user space application:
> > - enabling CEC (if needed by the hardware/driver)
> 
> I have 2 machines that this could work on, a Intel Baytrail tablet, and
> a laptop with Intel Haswell. Is that part going to be covered by your
> library, or will there be a drm API for that?

Enabling CEC is done by the CEC framework. The idea is to have it
independent of other frameworks (such as drm, or v4l2).

> 
> > - configuring the connection (e.g. what kind of device should the
> >   laptop appear as, request the TV to pass remote control keys, etc.)
> 
> That's done through the CEC API as well?

Yes.

> 
> > - the TV will also send other CEC messages to the laptop, hence the
> >   application should listen for such messages and act accordingly
> 
> That's easier to deal with :)
> 
> Something like LIRC can be used in the short-term.
> 
> > How this should be done userspace? Definitely, it would be a good
> idea
> > to use a library. Maybe a deamon that does the steps mentioned above
> > would be a good idea? I am working on a simple library implementation
> > that would wrap the kernel ioctls and provide a more user friendly
> > API.
> 
> Great. Do drop me a mail when you have something that I could test.

Will do.
 
> Cheers

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

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* RE: [RFC v2 2/7] media: rc: Add cec protocol handling
  2015-03-08 14:20     ` Mauro Carvalho Chehab
@ 2015-03-11 11:24       ` Kamil Debski
  -1 siblings, 0 replies; 34+ messages in thread
From: Kamil Debski @ 2015-03-11 11:24 UTC (permalink / raw)
  To: 'Mauro Carvalho Chehab'
  Cc: dri-devel, linux-media, Marek Szyprowski, hverkuil,
	kyungmin.park, thomas, sean, linux-input

Hi Mauro,

I have some more comments/questions below.

From: Mauro Carvalho Chehab [mailto:mchehab@osg.samsung.com]
Sent: Sunday, March 08, 2015 3:21 PM
> 
> Em Thu, 22 Jan 2015 17:04:34 +0100
> Kamil Debski <k.debski@samsung.com> escreveu:
> 
> (c/c linux-input ML)
> 
> > Add cec protocol handling the RC framework.
> 
> I added some comments, that reflects my understanding from what's there
> at the keymap definitions found at:
> 	http://xtreamerdev.googlecode.com/files/CEC_Specs.pdf
> 
> 
> >
> > Signed-off-by: Kamil Debski <k.debski@samsung.com>
> > ---
> >  drivers/media/rc/keymaps/Makefile |    1 +
> >  drivers/media/rc/keymaps/rc-cec.c |  133
> +++++++++++++++++++++++++++++++++++++
> >  drivers/media/rc/rc-main.c        |    1 +
> >  include/media/rc-core.h           |    1 +
> >  include/media/rc-map.h            |    5 +-
> >  5 files changed, 140 insertions(+), 1 deletion(-)  create mode

[snip]

> 
> > +	{ 0x60, KEY_PLAY }, /* XXX CEC Spec: Play Function */
> > +	{ 0x61, KEY_PLAYPAUSE }, /* XXX CEC Spec: Pause-Play Function */
> > +	{ 0x62, KEY_RECORD }, /* XXX CEC Spec: Record Function */
> > +	{ 0x63, KEY_PAUSE }, /* XXX CEC Spec: Pause-Record Function */
> > +	{ 0x64, KEY_STOP }, /* XXX CEC Spec: Stop Function */
> > +	{ 0x65, KEY_MUTE }, /* XXX CEC Spec: Mute Function */
> > +	/* 0x66: CEC Spec: Restore Volume Function */
> > +	{ 0x67, KEY_TUNER }, /* XXX CEC Spec: Tune Function */
> > +	{ 0x68, KEY_MEDIA }, /* CEC Spec: Select Media Function */
> > +	{ 0x69, KEY_SWITCHVIDEOMODE} /* XXX CEC Spec: Select A/V Input
> Function */,
> > +	{ 0x6a, KEY_AUDIO} /* CEC Spec: Select Audio Input Function */,
> > +	{ 0x6b, KEY_POWER} /* CEC Spec: Power Toggle Function */,
> > +	{ 0x6c, KEY_SLEEP} /* XXX CEC Spec: Power Off Function */,
> > +	{ 0x6d, KEY_WAKEUP} /* XXX CEC Spec: Power On Function */,
> 
> Those "function" keycodes look weird. What's the difference between
> those and the pure non-function variants?

The note 2 applies to most of these function buttons. It says:
"2 During a recording or timed recording, a device may ask the user
for confirmation of this action before executing it."
 
> The spec (CEC 13.13.3) says that:
> 
> 	"Unlike the other codes, which just pass remote control presses
> 	 to the target (often with manufacturer-specific results),
> 	 the Functions are deterministic, ie they specify exactly the
> state
> 	 after executing these commands. Several of these also have
> further
> 	 operands, specifying the function in more detail, immediately
> 	 following the relevant [UI Command] operand."
> 
> Some codes are actually compund ones. For example, 0x60 has a "play
> mode"
> operand. So, the actual mapping would be:
> 
> 0x60 + 0x24 - "play forward"
> 0x61 + 0x20 - "play reverse"
> ...
> (see CEC17 for operand descriptions)
> 
> So, IMHO, the mapping should be
> 
> 	{ 0x6024, KEY_PLAY },
> 	{ 0x6020, KEY_PLAY_REVERSE }, // to be created

The note 1 says that they can be issued without the additional operand
specified:
"1 Functions with additional operands may also be used without the
additional operand: in this case the behavior is manufacturer-specific."

Will this do?
	{ 0x60, KEY_PLAY },
	{ 0x6024, KEY_PLAY },
 	{ 0x6020, KEY_PLAY_REVERSE }, // to be created
Or will the framework get confused that an incomplete key code was
received?

Another question I have is about the following operations:
0x67 Tune Function
0x68 Select Media Function
0x69 Select A/V Input Function
0x6a Select Audio Input Function
These operations take an additional operand that is large number.
1-255 for 0x68-0x6a or even a more complex operand such as the channel
number for 0x67.

Any suggestion on how to implement these correctly?

> 	...
> 
> 
> > +	/* 0x6e-0x70: Reserved */
> > +	{ 0x71, KEY_BLUE }, /* XXX CEC Spec: F1 (Blue) */
> > +	{ 0x72, KEY_RED }, /* XXX CEC Spec: F2 (Red) */
> > +	{ 0x73, KEY_GREEN }, /* XXX CEC Spec: F3 (Green) */
> > +	{ 0x74, KEY_YELLOW }, /* XXX CEC Spec: F4 (Yellow) */
> > +	{ 0x75, KEY_F5 },
> > +	{ 0x76, KEY_CONNECT }, /* XXX CEC Spec: Data - see Note 3 */
> > +	/* Note 3: This is used, for example, to enter or leave a digital
> TV
> > +	 * data broadcast application. */
> 

[snip]

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



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

* RE: [RFC v2 2/7] media: rc: Add cec protocol handling
@ 2015-03-11 11:24       ` Kamil Debski
  0 siblings, 0 replies; 34+ messages in thread
From: Kamil Debski @ 2015-03-11 11:24 UTC (permalink / raw)
  To: 'Mauro Carvalho Chehab'
  Cc: sean, dri-devel, kyungmin.park, thomas, linux-input, linux-media,
	Marek Szyprowski

Hi Mauro,

I have some more comments/questions below.

From: Mauro Carvalho Chehab [mailto:mchehab@osg.samsung.com]
Sent: Sunday, March 08, 2015 3:21 PM
> 
> Em Thu, 22 Jan 2015 17:04:34 +0100
> Kamil Debski <k.debski@samsung.com> escreveu:
> 
> (c/c linux-input ML)
> 
> > Add cec protocol handling the RC framework.
> 
> I added some comments, that reflects my understanding from what's there
> at the keymap definitions found at:
> 	http://xtreamerdev.googlecode.com/files/CEC_Specs.pdf
> 
> 
> >
> > Signed-off-by: Kamil Debski <k.debski@samsung.com>
> > ---
> >  drivers/media/rc/keymaps/Makefile |    1 +
> >  drivers/media/rc/keymaps/rc-cec.c |  133
> +++++++++++++++++++++++++++++++++++++
> >  drivers/media/rc/rc-main.c        |    1 +
> >  include/media/rc-core.h           |    1 +
> >  include/media/rc-map.h            |    5 +-
> >  5 files changed, 140 insertions(+), 1 deletion(-)  create mode

[snip]

> 
> > +	{ 0x60, KEY_PLAY }, /* XXX CEC Spec: Play Function */
> > +	{ 0x61, KEY_PLAYPAUSE }, /* XXX CEC Spec: Pause-Play Function */
> > +	{ 0x62, KEY_RECORD }, /* XXX CEC Spec: Record Function */
> > +	{ 0x63, KEY_PAUSE }, /* XXX CEC Spec: Pause-Record Function */
> > +	{ 0x64, KEY_STOP }, /* XXX CEC Spec: Stop Function */
> > +	{ 0x65, KEY_MUTE }, /* XXX CEC Spec: Mute Function */
> > +	/* 0x66: CEC Spec: Restore Volume Function */
> > +	{ 0x67, KEY_TUNER }, /* XXX CEC Spec: Tune Function */
> > +	{ 0x68, KEY_MEDIA }, /* CEC Spec: Select Media Function */
> > +	{ 0x69, KEY_SWITCHVIDEOMODE} /* XXX CEC Spec: Select A/V Input
> Function */,
> > +	{ 0x6a, KEY_AUDIO} /* CEC Spec: Select Audio Input Function */,
> > +	{ 0x6b, KEY_POWER} /* CEC Spec: Power Toggle Function */,
> > +	{ 0x6c, KEY_SLEEP} /* XXX CEC Spec: Power Off Function */,
> > +	{ 0x6d, KEY_WAKEUP} /* XXX CEC Spec: Power On Function */,
> 
> Those "function" keycodes look weird. What's the difference between
> those and the pure non-function variants?

The note 2 applies to most of these function buttons. It says:
"2 During a recording or timed recording, a device may ask the user
for confirmation of this action before executing it."
 
> The spec (CEC 13.13.3) says that:
> 
> 	"Unlike the other codes, which just pass remote control presses
> 	 to the target (often with manufacturer-specific results),
> 	 the Functions are deterministic, ie they specify exactly the
> state
> 	 after executing these commands. Several of these also have
> further
> 	 operands, specifying the function in more detail, immediately
> 	 following the relevant [UI Command] operand."
> 
> Some codes are actually compund ones. For example, 0x60 has a "play
> mode"
> operand. So, the actual mapping would be:
> 
> 0x60 + 0x24 - "play forward"
> 0x61 + 0x20 - "play reverse"
> ...
> (see CEC17 for operand descriptions)
> 
> So, IMHO, the mapping should be
> 
> 	{ 0x6024, KEY_PLAY },
> 	{ 0x6020, KEY_PLAY_REVERSE }, // to be created

The note 1 says that they can be issued without the additional operand
specified:
"1 Functions with additional operands may also be used without the
additional operand: in this case the behavior is manufacturer-specific."

Will this do?
	{ 0x60, KEY_PLAY },
	{ 0x6024, KEY_PLAY },
 	{ 0x6020, KEY_PLAY_REVERSE }, // to be created
Or will the framework get confused that an incomplete key code was
received?

Another question I have is about the following operations:
0x67 Tune Function
0x68 Select Media Function
0x69 Select A/V Input Function
0x6a Select Audio Input Function
These operations take an additional operand that is large number.
1-255 for 0x68-0x6a or even a more complex operand such as the channel
number for 0x67.

Any suggestion on how to implement these correctly?

> 	...
> 
> 
> > +	/* 0x6e-0x70: Reserved */
> > +	{ 0x71, KEY_BLUE }, /* XXX CEC Spec: F1 (Blue) */
> > +	{ 0x72, KEY_RED }, /* XXX CEC Spec: F2 (Red) */
> > +	{ 0x73, KEY_GREEN }, /* XXX CEC Spec: F3 (Green) */
> > +	{ 0x74, KEY_YELLOW }, /* XXX CEC Spec: F4 (Yellow) */
> > +	{ 0x75, KEY_F5 },
> > +	{ 0x76, KEY_CONNECT }, /* XXX CEC Spec: Data - see Note 3 */
> > +	/* Note 3: This is used, for example, to enter or leave a digital
> TV
> > +	 * data broadcast application. */
> 

[snip]

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


_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

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

* Re: [RFC v2 2/7] media: rc: Add cec protocol handling
  2015-03-11 11:24       ` Kamil Debski
  (?)
@ 2015-03-11 13:48       ` Mauro Carvalho Chehab
  -1 siblings, 0 replies; 34+ messages in thread
From: Mauro Carvalho Chehab @ 2015-03-11 13:48 UTC (permalink / raw)
  To: Kamil Debski, Dmitry Torokhov
  Cc: dri-devel, linux-media, Marek Szyprowski, hverkuil,
	kyungmin.park, thomas, sean, linux-input

Em Wed, 11 Mar 2015 12:24:53 +0100
Kamil Debski <k.debski@samsung.com> escreveu:

> Hi Mauro,
> 
> I have some more comments/questions below.
> 
> From: Mauro Carvalho Chehab [mailto:mchehab@osg.samsung.com]
> Sent: Sunday, March 08, 2015 3:21 PM
> > 
> > Em Thu, 22 Jan 2015 17:04:34 +0100
> > Kamil Debski <k.debski@samsung.com> escreveu:
> > 
> > (c/c linux-input ML)
> > 
> > > Add cec protocol handling the RC framework.
> > 
> > I added some comments, that reflects my understanding from what's there
> > at the keymap definitions found at:
> > 	http://xtreamerdev.googlecode.com/files/CEC_Specs.pdf
> > 
> > 
> > >
> > > Signed-off-by: Kamil Debski <k.debski@samsung.com>
> > > ---
> > >  drivers/media/rc/keymaps/Makefile |    1 +
> > >  drivers/media/rc/keymaps/rc-cec.c |  133
> > +++++++++++++++++++++++++++++++++++++
> > >  drivers/media/rc/rc-main.c        |    1 +
> > >  include/media/rc-core.h           |    1 +
> > >  include/media/rc-map.h            |    5 +-
> > >  5 files changed, 140 insertions(+), 1 deletion(-)  create mode
> 
> [snip]
> 
> > 
> > > +	{ 0x60, KEY_PLAY }, /* XXX CEC Spec: Play Function */
> > > +	{ 0x61, KEY_PLAYPAUSE }, /* XXX CEC Spec: Pause-Play Function */
> > > +	{ 0x62, KEY_RECORD }, /* XXX CEC Spec: Record Function */
> > > +	{ 0x63, KEY_PAUSE }, /* XXX CEC Spec: Pause-Record Function */
> > > +	{ 0x64, KEY_STOP }, /* XXX CEC Spec: Stop Function */
> > > +	{ 0x65, KEY_MUTE }, /* XXX CEC Spec: Mute Function */
> > > +	/* 0x66: CEC Spec: Restore Volume Function */
> > > +	{ 0x67, KEY_TUNER }, /* XXX CEC Spec: Tune Function */
> > > +	{ 0x68, KEY_MEDIA }, /* CEC Spec: Select Media Function */
> > > +	{ 0x69, KEY_SWITCHVIDEOMODE} /* XXX CEC Spec: Select A/V Input
> > Function */,
> > > +	{ 0x6a, KEY_AUDIO} /* CEC Spec: Select Audio Input Function */,
> > > +	{ 0x6b, KEY_POWER} /* CEC Spec: Power Toggle Function */,
> > > +	{ 0x6c, KEY_SLEEP} /* XXX CEC Spec: Power Off Function */,
> > > +	{ 0x6d, KEY_WAKEUP} /* XXX CEC Spec: Power On Function */,
> > 
> > Those "function" keycodes look weird. What's the difference between
> > those and the pure non-function variants?
> 
> The note 2 applies to most of these function buttons. It says:
> "2 During a recording or timed recording, a device may ask the user
> for confirmation of this action before executing it."

Ok. So, it seems that we need to add new keycodes for those function variants,
as they should be handled on a different way than the usual keycodes.
>  
> > The spec (CEC 13.13.3) says that:
> > 
> > 	"Unlike the other codes, which just pass remote control presses
> > 	 to the target (often with manufacturer-specific results),
> > 	 the Functions are deterministic, ie they specify exactly the
> > state
> > 	 after executing these commands. Several of these also have
> > further
> > 	 operands, specifying the function in more detail, immediately
> > 	 following the relevant [UI Command] operand."
> > 
> > Some codes are actually compund ones. For example, 0x60 has a "play
> > mode"
> > operand. So, the actual mapping would be:
> > 
> > 0x60 + 0x24 - "play forward"
> > 0x61 + 0x20 - "play reverse"
> > ...
> > (see CEC17 for operand descriptions)
> > 
> > So, IMHO, the mapping should be
> > 
> > 	{ 0x6024, KEY_PLAY },
> > 	{ 0x6020, KEY_PLAY_REVERSE }, // to be created
> 
> The note 1 says that they can be issued without the additional operand
> specified:
> "1 Functions with additional operands may also be used without the
> additional operand: in this case the behavior is manufacturer-specific."
> 
> Will this do?
> 	{ 0x60, KEY_PLAY },
> 	{ 0x6024, KEY_PLAY },
>  	{ 0x6020, KEY_PLAY_REVERSE }, // to be created
> Or will the framework get confused that an incomplete key code was
> received?

The above should work.

> Another question I have is about the following operations:
> 0x67 Tune Function
> 0x68 Select Media Function
> 0x69 Select A/V Input Function
> 0x6a Select Audio Input Function
> These operations take an additional operand that is large number.
> 1-255 for 0x68-0x6a or even a more complex operand such as the channel
> number for 0x67.
> 
> Any suggestion on how to implement these correctly?

Well, the scancode may have any size. The current rc core implementation
is limited to u64. The scancode seek uses binary search, so it should
be fast, even for a big 64 bits table.

So, supporting a big number is not an issue to the core.

For the channel number, however, I suspect that we need to think on a
better alternative, like sending a sequence of numeric keycodes.

Maybe Dmitry has a better suggestion.

> 
> > 	...
> > 
> > 
> > > +	/* 0x6e-0x70: Reserved */
> > > +	{ 0x71, KEY_BLUE }, /* XXX CEC Spec: F1 (Blue) */
> > > +	{ 0x72, KEY_RED }, /* XXX CEC Spec: F2 (Red) */
> > > +	{ 0x73, KEY_GREEN }, /* XXX CEC Spec: F3 (Green) */
> > > +	{ 0x74, KEY_YELLOW }, /* XXX CEC Spec: F4 (Yellow) */
> > > +	{ 0x75, KEY_F5 },
> > > +	{ 0x76, KEY_CONNECT }, /* XXX CEC Spec: Data - see Note 3 */
> > > +	/* Note 3: This is used, for example, to enter or leave a digital
> > TV
> > > +	 * data broadcast application. */
> > 
> 
> [snip]
> 
> Best wishes,


-- 

Cheers,
Mauro

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

end of thread, other threads:[~2015-03-11 13:49 UTC | newest]

Thread overview: 34+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-01-22 16:04 [RFC v2 0/7] HDMI CEC framework Kamil Debski
2015-01-22 16:04 ` Kamil Debski
2015-01-22 16:04 ` [RFC v2 1/7] ARM: dts: add hdmi cec driver to exynos4412-odroidu3 Kamil Debski
2015-01-22 16:04   ` Kamil Debski
2015-01-22 16:04 ` [RFC v2 2/7] media: rc: Add cec protocol handling Kamil Debski
2015-03-08 14:20   ` Mauro Carvalho Chehab
2015-03-08 14:20     ` Mauro Carvalho Chehab
2015-03-09 16:22     ` Kamil Debski
2015-03-09 16:22       ` Kamil Debski
2015-03-09 16:43       ` Bastien Nocera
2015-03-10 12:02         ` Kamil Debski
2015-03-10 12:02           ` Kamil Debski
2015-03-10 14:13           ` Hans Verkuil
2015-03-10 14:14           ` Bastien Nocera
2015-03-10 15:40             ` Kamil Debski
2015-03-10 15:40               ` Kamil Debski
2015-03-11 11:24     ` Kamil Debski
2015-03-11 11:24       ` Kamil Debski
2015-03-11 13:48       ` Mauro Carvalho Chehab
2015-01-22 16:04 ` [RFC v2 3/7] cec: add new framework for cec support Kamil Debski
2015-01-23 11:07   ` Sean Young
2015-01-26  8:41     ` Hans Verkuil
2015-03-06 16:14     ` Kamil Debski
2015-03-06 16:14       ` Kamil Debski
2015-03-08 10:44       ` Sean Young
2015-03-09 16:21         ` Kamil Debski
2015-03-08 15:41       ` Mauro Carvalho Chehab
2015-03-09 16:22         ` Kamil Debski
2015-03-09 16:22           ` Kamil Debski
2015-01-22 16:04 ` [RFC v2 4/7] v4l2-subdev: add cec ops Kamil Debski
2015-01-22 16:04 ` [RFC v2 5/7] adv7604: add cec support Kamil Debski
2015-01-22 16:04   ` Kamil Debski
2015-01-22 16:04 ` [RFC v2 6/7] adv7511: " Kamil Debski
2015-01-22 16:04 ` [RFC v2 7/7] s5p-cec: Add s5p-cec driver Kamil Debski

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.