* [PATCHv2 0/4] cec-ctl/compliance: new CEC utilities
@ 2015-08-18 8:36 Hans Verkuil
2015-08-18 8:36 ` [PATCHv2 1/4] Makefile.am: copy cec headers with make sync-with-kernel Hans Verkuil
` (4 more replies)
0 siblings, 5 replies; 7+ messages in thread
From: Hans Verkuil @ 2015-08-18 8:36 UTC (permalink / raw)
To: linux-media
Cc: dri-devel, m.szyprowski, linux-input, linux-samsung-soc, lars,
kamil, linux
This patch series adds two new utilities to the v4l-utils git repository
(http://git.linuxtv.org/cgit.cgi/v4l-utils.git/). It assumes that the new
CEC framework available in the kernel:
http://www.mail-archive.com/linux-media@vger.kernel.org/msg90085.html
The first patch adds the new cec headers to the 'sync-with-kernel' target,
the second syncs with the kernel and adds the new cec headers to v4l-utils,
the third adds the compliance utility and the last adds the cec-ctl utility.
The cec-compliance utility is by no means 100% coverage, in particular the
event API and non-blocking ioctls are untested. But it is a starting point,
and a complex protocol like CEC really needs a compliance tool.
The cec-ctl utility has almost full CEC message coverage: all generated from
the cec headers, so this is easy to keep up to date.
Regards,
Hans
Changes since v1:
- Added CEC message logging/monitoring to cec-ctl.
- Add support to clear the logical addresses.
Hans Verkuil (4):
Makefile.am: copy cec headers with make sync-with-kernel
sync-with-kernel
cec-compliance: add new CEC compliance utility
cec-ctl: CEC control utility
Makefile.am | 4 +
configure.ac | 2 +
contrib/freebsd/include/linux/input.h | 29 +
contrib/freebsd/include/linux/v4l2-controls.h | 4 +
include/linux/cec-funcs.h | 1771 +++++++++++++++++++++++++
include/linux/cec.h | 781 +++++++++++
include/linux/v4l2-controls.h | 4 +
utils/Makefile.am | 2 +
utils/cec-compliance/Makefile.am | 3 +
utils/cec-compliance/cec-compliance.cpp | 926 +++++++++++++
utils/cec-compliance/cec-compliance.h | 87 ++
utils/cec-ctl/Makefile.am | 8 +
utils/cec-ctl/cec-ctl.cpp | 1296 ++++++++++++++++++
utils/cec-ctl/msg2ctl.pl | 430 ++++++
utils/keytable/parse.h | 18 +
utils/keytable/rc_keymaps/lme2510 | 132 +-
utils/keytable/rc_maps.cfg | 1 +
17 files changed, 5432 insertions(+), 66 deletions(-)
create mode 100644 include/linux/cec-funcs.h
create mode 100644 include/linux/cec.h
create mode 100644 utils/cec-compliance/Makefile.am
create mode 100644 utils/cec-compliance/cec-compliance.cpp
create mode 100644 utils/cec-compliance/cec-compliance.h
create mode 100644 utils/cec-ctl/Makefile.am
create mode 100644 utils/cec-ctl/cec-ctl.cpp
create mode 100644 utils/cec-ctl/msg2ctl.pl
--
2.1.4
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCHv2 1/4] Makefile.am: copy cec headers with make sync-with-kernel
2015-08-18 8:36 [PATCHv2 0/4] cec-ctl/compliance: new CEC utilities Hans Verkuil
@ 2015-08-18 8:36 ` Hans Verkuil
2015-08-18 8:36 ` [PATCHv2 2/4] sync-with-kernel Hans Verkuil
` (3 subsequent siblings)
4 siblings, 0 replies; 7+ messages in thread
From: Hans Verkuil @ 2015-08-18 8:36 UTC (permalink / raw)
To: linux-media
Cc: dri-devel, m.szyprowski, linux-input, linux-samsung-soc, lars,
kamil, linux, Hans Verkuil
Copy the new cec headers.
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
---
Makefile.am | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/Makefile.am b/Makefile.am
index 1a61592..b8c450d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -21,6 +21,8 @@ sync-with-kernel:
! -f $(KERNEL_DIR)/usr/include/linux/v4l2-common.h -o \
! -f $(KERNEL_DIR)/usr/include/linux/v4l2-subdev.h -o \
! -f $(KERNEL_DIR)/usr/include/linux/v4l2-mediabus.h -o \
+ ! -f $(KERNEL_DIR)/usr/include/linux/cec.h -o \
+ ! -f $(KERNEL_DIR)/usr/include/linux/cec-funcs.h -o \
! -f $(KERNEL_DIR)/usr/include/linux/ivtv.h -o \
! -f $(KERNEL_DIR)/usr/include/linux/dvb/frontend.h -o \
! -f $(KERNEL_DIR)/usr/include/linux/dvb/dmx.h -o \
@@ -38,6 +40,8 @@ sync-with-kernel:
cp -a $(KERNEL_DIR)/usr/include/linux/v4l2-mediabus.h $(top_srcdir)/include/linux
cp -a $(KERNEL_DIR)/usr/include/linux/media-bus-format.h $(top_srcdir)/include/linux
cp -a $(KERNEL_DIR)/usr/include/linux/media.h $(top_srcdir)/include/linux
+ cp -a $(KERNEL_DIR)/usr/include/linux/cec.h $(top_srcdir)/include/linux
+ cp -a $(KERNEL_DIR)/usr/include/linux/cec-funcs.h $(top_srcdir)/include/linux
cp -a $(KERNEL_DIR)/usr/include/linux/ivtv.h $(top_srcdir)/include/linux
cp -a $(KERNEL_DIR)/usr/include/linux/dvb/frontend.h $(top_srcdir)/include/linux/dvb
cp -a $(KERNEL_DIR)/usr/include/linux/dvb/dmx.h $(top_srcdir)/include/linux/dvb
--
2.1.4
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCHv2 2/4] sync-with-kernel
2015-08-18 8:36 [PATCHv2 0/4] cec-ctl/compliance: new CEC utilities Hans Verkuil
2015-08-18 8:36 ` [PATCHv2 1/4] Makefile.am: copy cec headers with make sync-with-kernel Hans Verkuil
@ 2015-08-18 8:36 ` Hans Verkuil
2015-08-18 8:36 ` [PATCHv2 3/4] cec-compliance: add new CEC compliance utility Hans Verkuil
` (2 subsequent siblings)
4 siblings, 0 replies; 7+ messages in thread
From: Hans Verkuil @ 2015-08-18 8:36 UTC (permalink / raw)
To: linux-media
Cc: dri-devel, m.szyprowski, linux-input, linux-samsung-soc, lars,
kamil, linux, Hans Verkuil
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
---
contrib/freebsd/include/linux/input.h | 29 +
contrib/freebsd/include/linux/v4l2-controls.h | 4 +
include/linux/cec-funcs.h | 1771 +++++++++++++++++++++++++
include/linux/cec.h | 781 +++++++++++
include/linux/v4l2-controls.h | 4 +
utils/keytable/parse.h | 18 +
utils/keytable/rc_keymaps/lme2510 | 132 +-
utils/keytable/rc_maps.cfg | 1 +
8 files changed, 2674 insertions(+), 66 deletions(-)
create mode 100644 include/linux/cec-funcs.h
create mode 100644 include/linux/cec.h
diff --git a/contrib/freebsd/include/linux/input.h b/contrib/freebsd/include/linux/input.h
index 19345e1..1bc7241 100644
--- a/contrib/freebsd/include/linux/input.h
+++ b/contrib/freebsd/include/linux/input.h
@@ -786,6 +786,34 @@ struct input_keymap_entry {
#define KEY_KBDINPUTASSIST_ACCEPT 0x264
#define KEY_KBDINPUTASSIST_CANCEL 0x265
+#define KEY_RIGHT_UP 0x266
+#define KEY_RIGHT_DOWN 0x267
+#define KEY_LEFT_UP 0x268
+#define KEY_LEFT_DOWN 0x269
+#define KEY_ROOT_MENU 0x26a /* Show Device's Root Menu */
+#define KEY_MEDIA_TOP_MENU 0x26b /* Show Top Menu of the Media (e.g. DVD) */
+#define KEY_NUMERIC_11 0x26c
+#define KEY_NUMERIC_12 0x26d
+/*
+ * Toggle Audio Description: refers to an audio service that helps blind and
+ * visually impaired consumers understand the action in a program. Note: in
+ * some countries this is referred to as "Video Description".
+ */
+#define KEY_AUDIO_DESC 0x26e
+#define KEY_3D_MODE 0x26f
+#define KEY_NEXT_FAVORITE 0x270
+#define KEY_STOP_RECORD 0x271
+#define KEY_PAUSE_RECORD 0x272
+#define KEY_VOD 0x273 /* Video on Demand */
+#define KEY_UNMUTE 0x274
+#define KEY_FASTREVERSE 0x275
+#define KEY_SLOWREVERSE 0x276
+/*
+ * Control a data application associated with the currently viewed channel,
+ * e.g. teletext or data broadcast application (MHEG, MHP, HbbTV, etc.)
+ */
+#define KEY_DATA 0x275
+
#define BTN_TRIGGER_HAPPY 0x2c0
#define BTN_TRIGGER_HAPPY1 0x2c0
#define BTN_TRIGGER_HAPPY2 0x2c1
@@ -1006,6 +1034,7 @@ struct input_keymap_entry {
#define BUS_GSC 0x1A
#define BUS_ATARI 0x1B
#define BUS_SPI 0x1C
+#define BUS_CEC 0x1D
/*
* MT_TOOL types
diff --git a/contrib/freebsd/include/linux/v4l2-controls.h b/contrib/freebsd/include/linux/v4l2-controls.h
index 9f6e108..d448c53 100644
--- a/contrib/freebsd/include/linux/v4l2-controls.h
+++ b/contrib/freebsd/include/linux/v4l2-controls.h
@@ -174,6 +174,10 @@ enum v4l2_colorfx {
* We reserve 16 controls for this driver. */
#define V4L2_CID_USER_ADV7180_BASE (V4L2_CID_USER_BASE + 0x1070)
+/* The base for the tc358743 driver controls.
+ * We reserve 16 controls for this driver. */
+#define V4L2_CID_USER_TC358743_BASE (V4L2_CID_USER_BASE + 0x1080)
+
/* MPEG-class control IDs */
/* The MPEG controls are applicable to all codec controls
* and the 'MPEG' part of the define is historical */
diff --git a/include/linux/cec-funcs.h b/include/linux/cec-funcs.h
new file mode 100644
index 0000000..45fb7bd
--- /dev/null
+++ b/include/linux/cec-funcs.h
@@ -0,0 +1,1771 @@
+#ifndef _CEC_FUNCS_H
+#define _CEC_FUNCS_H
+
+#include <linux/cec.h>
+
+/* One Touch Play Feature */
+static __inline__ void cec_msg_active_source(struct cec_msg *msg, __u16 phys_addr)
+{
+ msg->len = 4;
+ msg->msg[0] |= 0xf; /* broadcast */
+ msg->msg[1] = CEC_MSG_ACTIVE_SOURCE;
+ msg->msg[2] = phys_addr >> 8;
+ msg->msg[3] = phys_addr & 0xff;
+}
+
+static __inline__ void cec_ops_active_source(const struct cec_msg *msg,
+ __u16 *phys_addr)
+{
+ *phys_addr = (msg->msg[2] << 8) | msg->msg[3];
+}
+
+static __inline__ void cec_msg_image_view_on(struct cec_msg *msg)
+{
+ msg->len = 2;
+ msg->msg[1] = CEC_MSG_IMAGE_VIEW_ON;
+}
+
+static __inline__ void cec_msg_text_view_on(struct cec_msg *msg)
+{
+ msg->len = 2;
+ msg->msg[1] = CEC_MSG_TEXT_VIEW_ON;
+}
+
+
+/* Routing Control Feature */
+static __inline__ void cec_msg_inactive_source(struct cec_msg *msg,
+ __u16 phys_addr)
+{
+ msg->len = 4;
+ msg->msg[1] = CEC_MSG_INACTIVE_SOURCE;
+ msg->msg[2] = phys_addr >> 8;
+ msg->msg[3] = phys_addr & 0xff;
+}
+
+static __inline__ void cec_ops_inactive_source(const struct cec_msg *msg,
+ __u16 *phys_addr)
+{
+ *phys_addr = (msg->msg[2] << 8) | msg->msg[3];
+}
+
+static __inline__ void cec_msg_request_active_source(struct cec_msg *msg,
+ bool reply)
+{
+ msg->len = 2;
+ msg->msg[0] |= 0xf; /* broadcast */
+ msg->msg[1] = CEC_MSG_REQUEST_ACTIVE_SOURCE;
+ msg->reply = reply ? CEC_MSG_ACTIVE_SOURCE : 0;
+}
+
+static __inline__ void cec_msg_routing_information(struct cec_msg *msg,
+ __u16 phys_addr)
+{
+ msg->len = 4;
+ msg->msg[0] |= 0xf; /* broadcast */
+ msg->msg[1] = CEC_MSG_ROUTING_INFORMATION;
+ msg->msg[2] = phys_addr >> 8;
+ msg->msg[3] = phys_addr & 0xff;
+}
+
+static __inline__ void cec_ops_routing_information(const struct cec_msg *msg,
+ __u16 *phys_addr)
+{
+ *phys_addr = (msg->msg[2] << 8) | msg->msg[3];
+}
+
+static __inline__ void cec_msg_routing_change(struct cec_msg *msg,
+ bool reply,
+ __u16 orig_phys_addr,
+ __u16 new_phys_addr)
+{
+ msg->len = 6;
+ msg->msg[0] |= 0xf; /* broadcast */
+ msg->msg[1] = CEC_MSG_ROUTING_CHANGE;
+ msg->msg[2] = orig_phys_addr >> 8;
+ msg->msg[3] = orig_phys_addr & 0xff;
+ msg->msg[4] = new_phys_addr >> 8;
+ msg->msg[5] = new_phys_addr & 0xff;
+ msg->reply = reply ? CEC_MSG_ROUTING_INFORMATION : 0;
+}
+
+static __inline__ void cec_ops_routing_change(const struct cec_msg *msg,
+ __u16 *orig_phys_addr,
+ __u16 *new_phys_addr)
+{
+ *orig_phys_addr = (msg->msg[2] << 8) | msg->msg[3];
+ *new_phys_addr = (msg->msg[4] << 8) | msg->msg[5];
+}
+
+static __inline__ void cec_msg_set_stream_path(struct cec_msg *msg, __u16 phys_addr)
+{
+ msg->len = 4;
+ msg->msg[0] |= 0xf; /* broadcast */
+ msg->msg[1] = CEC_MSG_SET_STREAM_PATH;
+ msg->msg[2] = phys_addr >> 8;
+ msg->msg[3] = phys_addr & 0xff;
+}
+
+static __inline__ void cec_ops_set_stream_path(const struct cec_msg *msg,
+ __u16 *phys_addr)
+{
+ *phys_addr = (msg->msg[2] << 8) | msg->msg[3];
+}
+
+
+/* Standby Feature */
+static __inline__ void cec_msg_standby(struct cec_msg *msg)
+{
+ msg->len = 2;
+ msg->msg[1] = CEC_MSG_STANDBY;
+}
+
+
+/* One Touch Record Feature */
+static __inline__ void cec_msg_record_off(struct cec_msg *msg)
+{
+ msg->len = 2;
+ msg->msg[1] = CEC_MSG_RECORD_OFF;
+}
+
+struct cec_op_arib_data {
+ __u16 transport_id;
+ __u16 service_id;
+ __u16 orig_network_id;
+};
+
+struct cec_op_atsc_data {
+ __u16 transport_id;
+ __u16 program_number;
+};
+
+struct cec_op_dvb_data {
+ __u16 transport_id;
+ __u16 service_id;
+ __u16 orig_network_id;
+};
+
+struct cec_op_channel_data {
+ __u8 channel_number_fmt;
+ __u16 major;
+ __u16 minor;
+};
+
+struct cec_op_digital_service_id {
+ __u8 service_id_method;
+ __u8 dig_bcast_system;
+ union {
+ struct cec_op_arib_data arib;
+ struct cec_op_atsc_data atsc;
+ struct cec_op_dvb_data dvb;
+ struct cec_op_channel_data channel;
+ };
+};
+
+struct cec_op_record_src {
+ __u8 type;
+ union {
+ struct cec_op_digital_service_id digital;
+ struct {
+ __u8 ana_bcast_type;
+ __u16 ana_freq;
+ __u8 bcast_system;
+ } analog;
+ struct {
+ __u8 plug;
+ } ext_plug;
+ struct {
+ __u16 phys_addr;
+ } ext_phys_addr;
+ };
+};
+
+static __inline__ void cec_set_digital_service_id(__u8 *msg,
+ const struct cec_op_digital_service_id *digital)
+{
+ *msg++ = (digital->service_id_method << 7) | digital->dig_bcast_system;
+ if (digital->service_id_method == CEC_OP_SERVICE_ID_METHOD_BY_CHANNEL) {
+ *msg++ = (digital->channel.channel_number_fmt << 2) |
+ (digital->channel.major >> 8);
+ *msg++ = digital->channel.major && 0xff;
+ *msg++ = digital->channel.minor >> 8;
+ *msg++ = digital->channel.minor & 0xff;
+ *msg++ = 0;
+ *msg++ = 0;
+ return;
+ }
+ switch (digital->dig_bcast_system) {
+ case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_GEN:
+ case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_CABLE:
+ case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_SAT:
+ case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_T:
+ *msg++ = digital->atsc.transport_id >> 8;
+ *msg++ = digital->atsc.transport_id & 0xff;
+ *msg++ = digital->atsc.program_number >> 8;
+ *msg++ = digital->atsc.program_number & 0xff;
+ *msg++ = 0;
+ *msg++ = 0;
+ break;
+ default:
+ *msg++ = digital->dvb.transport_id >> 8;
+ *msg++ = digital->dvb.transport_id & 0xff;
+ *msg++ = digital->dvb.service_id >> 8;
+ *msg++ = digital->dvb.service_id & 0xff;
+ *msg++ = digital->dvb.orig_network_id >> 8;
+ *msg++ = digital->dvb.orig_network_id & 0xff;
+ break;
+ }
+}
+
+static __inline__ void cec_get_digital_service_id(const __u8 *msg,
+ struct cec_op_digital_service_id *digital)
+{
+ digital->service_id_method = msg[0] >> 7;
+ digital->dig_bcast_system = msg[0] & 0x7f;
+ if (digital->service_id_method == CEC_OP_SERVICE_ID_METHOD_BY_CHANNEL) {
+ digital->channel.channel_number_fmt = msg[1] >> 2;
+ digital->channel.major = ((msg[1] & 3) << 6) | msg[2];
+ digital->channel.minor = (msg[3] << 8) | msg[4];
+ return;
+ }
+ digital->dvb.transport_id = (msg[1] << 8) | msg[2];
+ digital->dvb.service_id = (msg[3] << 8) | msg[4];
+ digital->dvb.orig_network_id = (msg[5] << 8) | msg[6];
+}
+
+static __inline__ void cec_msg_record_on_own(struct cec_msg *msg)
+{
+ msg->len = 3;
+ msg->msg[1] = CEC_MSG_RECORD_ON;
+ msg->msg[2] = CEC_OP_RECORD_SRC_OWN;
+}
+
+static __inline__ void cec_msg_record_on_digital(struct cec_msg *msg,
+ const struct cec_op_digital_service_id *digital)
+{
+ msg->len = 10;
+ msg->msg[1] = CEC_MSG_RECORD_ON;
+ msg->msg[2] = CEC_OP_RECORD_SRC_DIGITAL;
+ cec_set_digital_service_id(msg->msg + 3, digital);
+}
+
+static __inline__ void cec_msg_record_on_analog(struct cec_msg *msg,
+ __u8 ana_bcast_type,
+ __u16 ana_freq,
+ __u8 bcast_system)
+{
+ msg->len = 7;
+ msg->msg[1] = CEC_MSG_RECORD_ON;
+ msg->msg[2] = CEC_OP_RECORD_SRC_ANALOG;
+ msg->msg[3] = ana_bcast_type;
+ msg->msg[4] = ana_freq >> 8;
+ msg->msg[5] = ana_freq & 0xff;
+ msg->msg[6] = bcast_system;
+}
+
+static __inline__ void cec_msg_record_on_plug(struct cec_msg *msg,
+ __u8 plug)
+{
+ msg->len = 4;
+ msg->msg[1] = CEC_MSG_RECORD_ON;
+ msg->msg[2] = CEC_OP_RECORD_SRC_EXT_PLUG;
+ msg->msg[3] = plug;
+}
+
+static __inline__ void cec_msg_record_on_phys_addr(struct cec_msg *msg,
+ __u16 phys_addr)
+{
+ msg->len = 5;
+ msg->msg[1] = CEC_MSG_RECORD_ON;
+ msg->msg[2] = CEC_OP_RECORD_SRC_EXT_PHYS_ADDR;
+ msg->msg[3] = phys_addr >> 8;
+ msg->msg[4] = phys_addr & 0xff;
+}
+
+static __inline__ void cec_msg_record_on(struct cec_msg *msg,
+ const struct cec_op_record_src *rec_src)
+{
+ switch (rec_src->type) {
+ case CEC_OP_RECORD_SRC_OWN:
+ cec_msg_record_on_own(msg);
+ break;
+ case CEC_OP_RECORD_SRC_DIGITAL:
+ cec_msg_record_on_digital(msg, &rec_src->digital);
+ break;
+ case CEC_OP_RECORD_SRC_ANALOG:
+ cec_msg_record_on_analog(msg,
+ rec_src->analog.ana_bcast_type,
+ rec_src->analog.ana_freq,
+ rec_src->analog.bcast_system);
+ break;
+ case CEC_OP_RECORD_SRC_EXT_PLUG:
+ cec_msg_record_on_plug(msg, rec_src->ext_plug.plug);
+ break;
+ case CEC_OP_RECORD_SRC_EXT_PHYS_ADDR:
+ cec_msg_record_on_phys_addr(msg,
+ rec_src->ext_phys_addr.phys_addr);
+ break;
+ }
+}
+
+static __inline__ void cec_ops_record_on(const struct cec_msg *msg,
+ struct cec_op_record_src *rec_src)
+{
+ rec_src->type = msg->msg[2];
+ switch (rec_src->type) {
+ case CEC_OP_RECORD_SRC_OWN:
+ break;
+ case CEC_OP_RECORD_SRC_DIGITAL:
+ cec_get_digital_service_id(msg->msg + 3, &rec_src->digital);
+ break;
+ case CEC_OP_RECORD_SRC_ANALOG:
+ rec_src->analog.ana_bcast_type = msg->msg[3];
+ rec_src->analog.ana_freq =
+ (msg->msg[4] << 8) | msg->msg[5];
+ rec_src->analog.bcast_system = msg->msg[6];
+ break;
+ case CEC_OP_RECORD_SRC_EXT_PLUG:
+ rec_src->ext_plug.plug = msg->msg[3];
+ break;
+ case CEC_OP_RECORD_SRC_EXT_PHYS_ADDR:
+ rec_src->ext_phys_addr.phys_addr =
+ (msg->msg[3] << 8) | msg->msg[4];
+ break;
+ }
+}
+
+static __inline__ void cec_msg_record_status(struct cec_msg *msg, __u8 rec_status)
+{
+ msg->len = 3;
+ msg->msg[1] = CEC_MSG_RECORD_STATUS;
+ msg->msg[2] = rec_status;
+}
+
+static __inline__ void cec_ops_record_status(const struct cec_msg *msg,
+ __u8 *rec_status)
+{
+ *rec_status = msg->msg[2];
+}
+
+static __inline__ void cec_msg_record_tv_screen(struct cec_msg *msg,
+ bool reply)
+{
+ msg->len = 2;
+ msg->msg[1] = CEC_MSG_RECORD_TV_SCREEN;
+ msg->reply = reply ? CEC_MSG_RECORD_ON : 0;
+}
+
+
+/* Timer Programming Feature */
+static __inline__ void cec_msg_timer_status(struct cec_msg *msg,
+ __u8 timer_overlap_warning,
+ __u8 media_info,
+ __u8 prog_info,
+ __u8 prog_error,
+ __u8 duration_hr,
+ __u8 duration_min)
+{
+ msg->len = 3;
+ msg->msg[1] = CEC_MSG_TIMER_STATUS;
+ msg->msg[2] = (timer_overlap_warning << 7) |
+ (media_info << 5) |
+ (prog_info ? 0x10 : 0) |
+ (prog_info ? prog_info : prog_error);
+ if (prog_info == CEC_OP_PROG_INFO_NOT_ENOUGH_SPACE ||
+ prog_info == CEC_OP_PROG_INFO_MIGHT_NOT_BE_ENOUGH_SPACE ||
+ prog_error == CEC_OP_PROG_ERROR_DUPLICATE) {
+ msg->len += 2;
+ msg->msg[3] = ((duration_hr / 10) << 4) | (duration_hr % 10);
+ msg->msg[4] = ((duration_min / 10) << 4) | (duration_min % 10);
+ }
+}
+
+static __inline__ void cec_ops_timer_status(struct cec_msg *msg,
+ __u8 *timer_overlap_warning,
+ __u8 *media_info,
+ __u8 *prog_info,
+ __u8 *prog_error,
+ __u8 *duration_hr,
+ __u8 *duration_min)
+{
+ *timer_overlap_warning = msg->msg[2] >> 7;
+ *media_info = (msg->msg[2] >> 5) & 3;
+ if (msg->msg[2] & 0x10) {
+ *prog_info = msg->msg[2] & 0xf;
+ *prog_error = 0;
+ } else {
+ *prog_info = 0;
+ *prog_error = msg->msg[2] & 0xf;
+ }
+ if (*prog_info == CEC_OP_PROG_INFO_NOT_ENOUGH_SPACE ||
+ *prog_info == CEC_OP_PROG_INFO_MIGHT_NOT_BE_ENOUGH_SPACE ||
+ *prog_error == CEC_OP_PROG_ERROR_DUPLICATE) {
+ *duration_hr = (msg->msg[3] >> 4) * 10 + (msg->msg[3] & 0xf);
+ *duration_min = (msg->msg[4] >> 4) * 10 + (msg->msg[4] & 0xf);
+ } else {
+ *duration_hr = *duration_min = 0;
+ }
+}
+
+static __inline__ void cec_msg_timer_cleared_status(struct cec_msg *msg,
+ __u8 timer_cleared_status)
+{
+ msg->len = 3;
+ msg->msg[1] = CEC_MSG_TIMER_CLEARED_STATUS;
+ msg->msg[2] = timer_cleared_status;
+}
+
+static __inline__ void cec_ops_timer_cleared_status(struct cec_msg *msg,
+ __u8 *timer_cleared_status)
+{
+ *timer_cleared_status = msg->msg[2];
+}
+
+static __inline__ void cec_msg_clear_analogue_timer(struct cec_msg *msg,
+ bool reply,
+ __u8 day,
+ __u8 month,
+ __u8 start_hr,
+ __u8 start_min,
+ __u8 duration_hr,
+ __u8 duration_min,
+ __u8 recording_seq,
+ __u8 ana_bcast_type,
+ __u16 ana_freq,
+ __u8 bcast_system)
+{
+ msg->len = 13;
+ msg->msg[1] = CEC_MSG_CLEAR_ANALOGUE_TIMER;
+ msg->msg[2] = day;
+ msg->msg[3] = month;
+ /* Hours and minutes are in BCD format */
+ msg->msg[4] = ((start_hr / 10) << 4) | (start_hr % 10);
+ msg->msg[5] = ((start_min / 10) << 4) | (start_min % 10);
+ msg->msg[6] = ((duration_hr / 10) << 4) | (duration_hr % 10);
+ msg->msg[7] = ((duration_min / 10) << 4) | (duration_min % 10);
+ msg->msg[8] = recording_seq;
+ msg->msg[9] = ana_bcast_type;
+ msg->msg[10] = ana_freq >> 8;
+ msg->msg[11] = ana_freq & 0xff;
+ msg->msg[12] = bcast_system;
+ msg->reply = reply ? CEC_MSG_TIMER_CLEARED_STATUS : 0;
+}
+
+static __inline__ void cec_ops_clear_analogue_timer(struct cec_msg *msg,
+ __u8 *day,
+ __u8 *month,
+ __u8 *start_hr,
+ __u8 *start_min,
+ __u8 *duration_hr,
+ __u8 *duration_min,
+ __u8 *recording_seq,
+ __u8 *ana_bcast_type,
+ __u16 *ana_freq,
+ __u8 *bcast_system)
+{
+ *day = msg->msg[2];
+ *month = msg->msg[3];
+ /* Hours and minutes are in BCD format */
+ *start_hr = (msg->msg[4] >> 4) * 10 + (msg->msg[4] & 0xf);
+ *start_min = (msg->msg[5] >> 4) * 10 + (msg->msg[5] & 0xf);
+ *duration_hr = (msg->msg[6] >> 4) * 10 + (msg->msg[6] & 0xf);
+ *duration_min = (msg->msg[7] >> 4) * 10 + (msg->msg[7] & 0xf);
+ *recording_seq = msg->msg[8];
+ *ana_bcast_type = msg->msg[9];
+ *ana_freq = (msg->msg[10] << 8) | msg->msg[11];
+ *bcast_system = msg->msg[12];
+}
+
+static __inline__ void cec_msg_clear_digital_timer(struct cec_msg *msg,
+ bool reply,
+ __u8 day,
+ __u8 month,
+ __u8 start_hr,
+ __u8 start_min,
+ __u8 duration_hr,
+ __u8 duration_min,
+ __u8 recording_seq,
+ const struct cec_op_digital_service_id *digital)
+{
+ msg->len = 16;
+ msg->reply = reply ? CEC_MSG_TIMER_CLEARED_STATUS : 0;
+ msg->msg[1] = CEC_MSG_CLEAR_DIGITAL_TIMER;
+ msg->msg[2] = day;
+ msg->msg[3] = month;
+ /* Hours and minutes are in BCD format */
+ msg->msg[4] = ((start_hr / 10) << 4) | (start_hr % 10);
+ msg->msg[5] = ((start_min / 10) << 4) | (start_min % 10);
+ msg->msg[6] = ((duration_hr / 10) << 4) | (duration_hr % 10);
+ msg->msg[7] = ((duration_min / 10) << 4) | (duration_min % 10);
+ msg->msg[8] = recording_seq;
+ cec_set_digital_service_id(msg->msg + 9, digital);
+}
+
+static __inline__ void cec_ops_clear_digital_timer(struct cec_msg *msg,
+ __u8 *day,
+ __u8 *month,
+ __u8 *start_hr,
+ __u8 *start_min,
+ __u8 *duration_hr,
+ __u8 *duration_min,
+ __u8 *recording_seq,
+ struct cec_op_digital_service_id *digital)
+{
+ *day = msg->msg[2];
+ *month = msg->msg[3];
+ /* Hours and minutes are in BCD format */
+ *start_hr = (msg->msg[4] >> 4) * 10 + (msg->msg[4] & 0xf);
+ *start_min = (msg->msg[5] >> 4) * 10 + (msg->msg[5] & 0xf);
+ *duration_hr = (msg->msg[6] >> 4) * 10 + (msg->msg[6] & 0xf);
+ *duration_min = (msg->msg[7] >> 4) * 10 + (msg->msg[7] & 0xf);
+ *recording_seq = msg->msg[8];
+ cec_get_digital_service_id(msg->msg + 9, digital);
+}
+
+static __inline__ void cec_msg_clear_ext_timer(struct cec_msg *msg,
+ bool reply,
+ __u8 day,
+ __u8 month,
+ __u8 start_hr,
+ __u8 start_min,
+ __u8 duration_hr,
+ __u8 duration_min,
+ __u8 recording_seq,
+ __u8 ext_src_spec,
+ __u8 plug,
+ __u16 phys_addr)
+{
+ msg->len = 13;
+ msg->msg[1] = CEC_MSG_CLEAR_EXT_TIMER;
+ msg->msg[2] = day;
+ msg->msg[3] = month;
+ /* Hours and minutes are in BCD format */
+ msg->msg[4] = ((start_hr / 10) << 4) | (start_hr % 10);
+ msg->msg[5] = ((start_min / 10) << 4) | (start_min % 10);
+ msg->msg[6] = ((duration_hr / 10) << 4) | (duration_hr % 10);
+ msg->msg[7] = ((duration_min / 10) << 4) | (duration_min % 10);
+ msg->msg[8] = recording_seq;
+ msg->msg[9] = ext_src_spec;
+ msg->msg[10] = plug;
+ msg->msg[11] = phys_addr >> 8;
+ msg->msg[12] = phys_addr & 0xff;
+ msg->reply = reply ? CEC_MSG_TIMER_CLEARED_STATUS : 0;
+}
+
+static __inline__ void cec_ops_clear_ext_timer(struct cec_msg *msg,
+ __u8 *day,
+ __u8 *month,
+ __u8 *start_hr,
+ __u8 *start_min,
+ __u8 *duration_hr,
+ __u8 *duration_min,
+ __u8 *recording_seq,
+ __u8 *ext_src_spec,
+ __u8 *plug,
+ __u16 *phys_addr)
+{
+ *day = msg->msg[2];
+ *month = msg->msg[3];
+ /* Hours and minutes are in BCD format */
+ *start_hr = (msg->msg[4] >> 4) * 10 + (msg->msg[4] & 0xf);
+ *start_min = (msg->msg[5] >> 4) * 10 + (msg->msg[5] & 0xf);
+ *duration_hr = (msg->msg[6] >> 4) * 10 + (msg->msg[6] & 0xf);
+ *duration_min = (msg->msg[7] >> 4) * 10 + (msg->msg[7] & 0xf);
+ *recording_seq = msg->msg[8];
+ *ext_src_spec = msg->msg[9];
+ *plug = msg->msg[10];
+ *phys_addr = (msg->msg[11] << 8) | msg->msg[12];
+}
+
+static __inline__ void cec_msg_set_analogue_timer(struct cec_msg *msg,
+ bool reply,
+ __u8 day,
+ __u8 month,
+ __u8 start_hr,
+ __u8 start_min,
+ __u8 duration_hr,
+ __u8 duration_min,
+ __u8 recording_seq,
+ __u8 ana_bcast_type,
+ __u16 ana_freq,
+ __u8 bcast_system)
+{
+ msg->len = 13;
+ msg->msg[1] = CEC_MSG_SET_ANALOGUE_TIMER;
+ msg->msg[2] = day;
+ msg->msg[3] = month;
+ /* Hours and minutes are in BCD format */
+ msg->msg[4] = ((start_hr / 10) << 4) | (start_hr % 10);
+ msg->msg[5] = ((start_min / 10) << 4) | (start_min % 10);
+ msg->msg[6] = ((duration_hr / 10) << 4) | (duration_hr % 10);
+ msg->msg[7] = ((duration_min / 10) << 4) | (duration_min % 10);
+ msg->msg[8] = recording_seq;
+ msg->msg[9] = ana_bcast_type;
+ msg->msg[10] = ana_freq >> 8;
+ msg->msg[11] = ana_freq & 0xff;
+ msg->msg[12] = bcast_system;
+ msg->reply = reply ? CEC_MSG_TIMER_STATUS : 0;
+}
+
+static __inline__ void cec_ops_set_analogue_timer(struct cec_msg *msg,
+ __u8 *day,
+ __u8 *month,
+ __u8 *start_hr,
+ __u8 *start_min,
+ __u8 *duration_hr,
+ __u8 *duration_min,
+ __u8 *recording_seq,
+ __u8 *ana_bcast_type,
+ __u16 *ana_freq,
+ __u8 *bcast_system)
+{
+ *day = msg->msg[2];
+ *month = msg->msg[3];
+ /* Hours and minutes are in BCD format */
+ *start_hr = (msg->msg[4] >> 4) * 10 + (msg->msg[4] & 0xf);
+ *start_min = (msg->msg[5] >> 4) * 10 + (msg->msg[5] & 0xf);
+ *duration_hr = (msg->msg[6] >> 4) * 10 + (msg->msg[6] & 0xf);
+ *duration_min = (msg->msg[7] >> 4) * 10 + (msg->msg[7] & 0xf);
+ *recording_seq = msg->msg[8];
+ *ana_bcast_type = msg->msg[9];
+ *ana_freq = (msg->msg[10] << 8) | msg->msg[11];
+ *bcast_system = msg->msg[12];
+}
+
+static __inline__ void cec_msg_set_digital_timer(struct cec_msg *msg,
+ bool reply,
+ __u8 day,
+ __u8 month,
+ __u8 start_hr,
+ __u8 start_min,
+ __u8 duration_hr,
+ __u8 duration_min,
+ __u8 recording_seq,
+ const struct cec_op_digital_service_id *digital)
+{
+ msg->len = 16;
+ msg->reply = reply ? CEC_MSG_TIMER_STATUS : 0;
+ msg->msg[1] = CEC_MSG_SET_DIGITAL_TIMER;
+ msg->msg[2] = day;
+ msg->msg[3] = month;
+ /* Hours and minutes are in BCD format */
+ msg->msg[4] = ((start_hr / 10) << 4) | (start_hr % 10);
+ msg->msg[5] = ((start_min / 10) << 4) | (start_min % 10);
+ msg->msg[6] = ((duration_hr / 10) << 4) | (duration_hr % 10);
+ msg->msg[7] = ((duration_min / 10) << 4) | (duration_min % 10);
+ msg->msg[8] = recording_seq;
+ cec_set_digital_service_id(msg->msg + 9, digital);
+}
+
+static __inline__ void cec_ops_set_digital_timer(struct cec_msg *msg,
+ __u8 *day,
+ __u8 *month,
+ __u8 *start_hr,
+ __u8 *start_min,
+ __u8 *duration_hr,
+ __u8 *duration_min,
+ __u8 *recording_seq,
+ struct cec_op_digital_service_id *digital)
+{
+ *day = msg->msg[2];
+ *month = msg->msg[3];
+ /* Hours and minutes are in BCD format */
+ *start_hr = (msg->msg[4] >> 4) * 10 + (msg->msg[4] & 0xf);
+ *start_min = (msg->msg[5] >> 4) * 10 + (msg->msg[5] & 0xf);
+ *duration_hr = (msg->msg[6] >> 4) * 10 + (msg->msg[6] & 0xf);
+ *duration_min = (msg->msg[7] >> 4) * 10 + (msg->msg[7] & 0xf);
+ *recording_seq = msg->msg[8];
+ cec_get_digital_service_id(msg->msg + 9, digital);
+}
+
+static __inline__ void cec_msg_set_ext_timer(struct cec_msg *msg,
+ bool reply,
+ __u8 day,
+ __u8 month,
+ __u8 start_hr,
+ __u8 start_min,
+ __u8 duration_hr,
+ __u8 duration_min,
+ __u8 recording_seq,
+ __u8 ext_src_spec,
+ __u8 plug,
+ __u16 phys_addr)
+{
+ msg->len = 13;
+ msg->msg[1] = CEC_MSG_SET_EXT_TIMER;
+ msg->msg[2] = day;
+ msg->msg[3] = month;
+ /* Hours and minutes are in BCD format */
+ msg->msg[4] = ((start_hr / 10) << 4) | (start_hr % 10);
+ msg->msg[5] = ((start_min / 10) << 4) | (start_min % 10);
+ msg->msg[6] = ((duration_hr / 10) << 4) | (duration_hr % 10);
+ msg->msg[7] = ((duration_min / 10) << 4) | (duration_min % 10);
+ msg->msg[8] = recording_seq;
+ msg->msg[9] = ext_src_spec;
+ msg->msg[10] = plug;
+ msg->msg[11] = phys_addr >> 8;
+ msg->msg[12] = phys_addr & 0xff;
+ msg->reply = reply ? CEC_MSG_TIMER_STATUS : 0;
+}
+
+static __inline__ void cec_ops_set_ext_timer(struct cec_msg *msg,
+ __u8 *day,
+ __u8 *month,
+ __u8 *start_hr,
+ __u8 *start_min,
+ __u8 *duration_hr,
+ __u8 *duration_min,
+ __u8 *recording_seq,
+ __u8 *ext_src_spec,
+ __u8 *plug,
+ __u16 *phys_addr)
+{
+ *day = msg->msg[2];
+ *month = msg->msg[3];
+ /* Hours and minutes are in BCD format */
+ *start_hr = (msg->msg[4] >> 4) * 10 + (msg->msg[4] & 0xf);
+ *start_min = (msg->msg[5] >> 4) * 10 + (msg->msg[5] & 0xf);
+ *duration_hr = (msg->msg[6] >> 4) * 10 + (msg->msg[6] & 0xf);
+ *duration_min = (msg->msg[7] >> 4) * 10 + (msg->msg[7] & 0xf);
+ *recording_seq = msg->msg[8];
+ *ext_src_spec = msg->msg[9];
+ *plug = msg->msg[10];
+ *phys_addr = (msg->msg[11] << 8) | msg->msg[12];
+}
+
+static __inline__ void cec_msg_set_timer_program_title(struct cec_msg *msg,
+ const char *prog_title)
+{
+ unsigned len = strlen(prog_title);
+
+ if (len > 14)
+ len = 14;
+ msg->len = 2 + len;
+ msg->msg[1] = CEC_MSG_SET_TIMER_PROGRAM_TITLE;
+ memcpy(msg->msg + 2, prog_title, len);
+}
+
+static __inline__ void cec_ops_set_timer_program_title(const struct cec_msg *msg,
+ char *prog_title)
+{
+ unsigned len = msg->len - 2;
+
+ if (len > 14)
+ len = 14;
+ memcpy(prog_title, msg->msg + 2, len);
+ prog_title[len] = '\0';
+}
+
+/* System Information Feature */
+static __inline__ void cec_msg_cec_version(struct cec_msg *msg, __u8 cec_version)
+{
+ msg->len = 3;
+ msg->msg[1] = CEC_MSG_CEC_VERSION;
+ msg->msg[2] = cec_version;
+}
+
+static __inline__ void cec_ops_cec_version(const struct cec_msg *msg,
+ __u8 *cec_version)
+{
+ *cec_version = msg->msg[2];
+}
+
+static __inline__ void cec_msg_get_cec_version(struct cec_msg *msg,
+ bool reply)
+{
+ msg->len = 2;
+ msg->msg[1] = CEC_MSG_GET_CEC_VERSION;
+ msg->reply = reply ? CEC_MSG_CEC_VERSION : 0;
+}
+
+static __inline__ void cec_msg_report_physical_addr(struct cec_msg *msg,
+ __u16 phys_addr, __u8 prim_devtype)
+{
+ msg->len = 5;
+ msg->msg[0] |= 0xf; /* broadcast */
+ msg->msg[1] = CEC_MSG_REPORT_PHYSICAL_ADDR;
+ msg->msg[2] = phys_addr >> 8;
+ msg->msg[3] = phys_addr & 0xff;
+ msg->msg[4] = prim_devtype;
+}
+
+static __inline__ void cec_ops_report_physical_addr(const struct cec_msg *msg,
+ __u16 *phys_addr, __u8 *prim_devtype)
+{
+ *phys_addr = (msg->msg[2] << 8) | msg->msg[3];
+ *prim_devtype = msg->msg[4];
+}
+
+static __inline__ void cec_msg_give_physical_addr(struct cec_msg *msg,
+ bool reply)
+{
+ msg->len = 2;
+ msg->msg[1] = CEC_MSG_GIVE_PHYSICAL_ADDR;
+ msg->reply = reply ? CEC_MSG_REPORT_PHYSICAL_ADDR : 0;
+}
+
+static __inline__ void cec_msg_set_menu_language(struct cec_msg *msg,
+ const char *language)
+{
+ msg->len = 5;
+ msg->msg[0] |= 0xf; /* broadcast */
+ msg->msg[1] = CEC_MSG_SET_MENU_LANGUAGE;
+ memcpy(msg->msg + 2, language, 3);
+}
+
+static __inline__ void cec_ops_set_menu_language(struct cec_msg *msg,
+ char *language)
+{
+ memcpy(language, msg->msg + 2, 3);
+}
+
+static __inline__ void cec_msg_get_menu_language(struct cec_msg *msg,
+ bool reply)
+{
+ msg->len = 2;
+ msg->msg[1] = CEC_MSG_GET_MENU_LANGUAGE;
+ msg->reply = reply ? CEC_MSG_SET_MENU_LANGUAGE : 0;
+}
+
+/*
+ * Assumes a single RC Profile byte and a single Device Features byte,
+ * i.e. no extended features are supported by this helper function.
+ */
+static __inline__ void cec_msg_report_features(struct cec_msg *msg,
+ __u8 cec_version, __u8 all_device_types,
+ __u8 rc_profile, __u8 dev_features)
+{
+ msg->len = 6;
+ msg->msg[0] |= 0xf; /* broadcast */
+ msg->msg[1] = CEC_MSG_REPORT_FEATURES;
+ msg->msg[2] = cec_version;
+ msg->msg[3] = all_device_types;
+ msg->msg[4] = rc_profile;
+ msg->msg[5] = dev_features;
+}
+
+static __inline__ void cec_ops_report_features(const struct cec_msg *msg,
+ __u8 *cec_version, __u8 *all_device_types,
+ const __u8 **rc_profile, const __u8 **dev_features)
+{
+ const __u8 *p = &msg->msg[4];
+
+ *cec_version = msg->msg[2];
+ *all_device_types = msg->msg[3];
+ *rc_profile = p;
+ while (p < &msg->msg[14] && (*p & CEC_OP_FEAT_EXT))
+ p++;
+ if (!(*p & CEC_OP_FEAT_EXT)) {
+ *dev_features = p + 1;
+ while (p < &msg->msg[15] && (*p & CEC_OP_FEAT_EXT))
+ p++;
+ }
+ if (*p & CEC_OP_FEAT_EXT)
+ *rc_profile = *dev_features = NULL;
+}
+
+static __inline__ void cec_msg_give_features(struct cec_msg *msg,
+ bool reply)
+{
+ msg->len = 2;
+ msg->msg[1] = CEC_MSG_GIVE_FEATURES;
+ msg->reply = reply ? CEC_MSG_REPORT_FEATURES : 0;
+}
+
+/* Deck Control Feature */
+static __inline__ void cec_msg_deck_control(struct cec_msg *msg,
+ __u8 deck_control_mode)
+{
+ msg->len = 3;
+ msg->msg[1] = CEC_MSG_DECK_CONTROL;
+ msg->msg[2] = deck_control_mode;
+}
+
+static __inline__ void cec_ops_deck_control(struct cec_msg *msg,
+ __u8 *deck_control_mode)
+{
+ *deck_control_mode = msg->msg[2];
+}
+
+static __inline__ void cec_msg_deck_status(struct cec_msg *msg,
+ __u8 deck_info)
+{
+ msg->len = 3;
+ msg->msg[1] = CEC_MSG_DECK_STATUS;
+ msg->msg[2] = deck_info;
+}
+
+static __inline__ void cec_ops_deck_status(struct cec_msg *msg,
+ __u8 *deck_info)
+{
+ *deck_info = msg->msg[2];
+}
+
+static __inline__ void cec_msg_give_deck_status(struct cec_msg *msg,
+ bool reply,
+ __u8 status_req)
+{
+ msg->len = 3;
+ msg->msg[1] = CEC_MSG_GIVE_DECK_STATUS;
+ msg->msg[2] = status_req;
+ msg->reply = reply ? CEC_MSG_DECK_STATUS : 0;
+}
+
+static __inline__ void cec_ops_give_deck_status(struct cec_msg *msg,
+ __u8 *status_req)
+{
+ *status_req = msg->msg[2];
+}
+
+static __inline__ void cec_msg_play(struct cec_msg *msg,
+ __u8 play_mode)
+{
+ msg->len = 3;
+ msg->msg[1] = CEC_MSG_PLAY;
+ msg->msg[2] = play_mode;
+}
+
+static __inline__ void cec_ops_play(struct cec_msg *msg,
+ __u8 *play_mode)
+{
+ *play_mode = msg->msg[2];
+}
+
+
+/* Tuner Control Feature */
+struct cec_op_tuner_device_info {
+ __u8 rec_flag;
+ __u8 tuner_display_info;
+ bool is_analog;
+ union {
+ struct cec_op_digital_service_id digital;
+ struct {
+ __u8 ana_bcast_type;
+ __u16 ana_freq;
+ __u8 bcast_system;
+ } analog;
+ };
+};
+
+static __inline__ void cec_msg_tuner_device_status_analog(struct cec_msg *msg,
+ __u8 rec_flag,
+ __u8 tuner_display_info,
+ __u8 ana_bcast_type,
+ __u16 ana_freq,
+ __u8 bcast_system)
+{
+ msg->len = 7;
+ msg->msg[1] = CEC_MSG_TUNER_DEVICE_STATUS;
+ msg->msg[2] = (rec_flag << 7) | tuner_display_info;
+ msg->msg[3] = ana_bcast_type;
+ msg->msg[4] = ana_freq >> 8;
+ msg->msg[5] = ana_freq & 0xff;
+ msg->msg[6] = bcast_system;
+}
+
+static __inline__ void cec_msg_tuner_device_status_digital(struct cec_msg *msg,
+ __u8 rec_flag, __u8 tuner_display_info,
+ const struct cec_op_digital_service_id *digital)
+{
+ msg->len = 10;
+ msg->msg[1] = CEC_MSG_TUNER_DEVICE_STATUS;
+ msg->msg[2] = (rec_flag << 7) | tuner_display_info;
+ cec_set_digital_service_id(msg->msg + 3, digital);
+}
+
+static __inline__ void cec_msg_tuner_device_status(struct cec_msg *msg,
+ const struct cec_op_tuner_device_info *tuner_dev_info)
+{
+ if (tuner_dev_info->is_analog)
+ cec_msg_tuner_device_status_analog(msg,
+ tuner_dev_info->rec_flag,
+ tuner_dev_info->tuner_display_info,
+ tuner_dev_info->analog.ana_bcast_type,
+ tuner_dev_info->analog.ana_freq,
+ tuner_dev_info->analog.bcast_system);
+ else
+ cec_msg_tuner_device_status_digital(msg,
+ tuner_dev_info->rec_flag,
+ tuner_dev_info->tuner_display_info,
+ &tuner_dev_info->digital);
+}
+
+static __inline__ void cec_ops_tuner_device_status(struct cec_msg *msg,
+ struct cec_op_tuner_device_info *tuner_dev_info)
+{
+ tuner_dev_info->is_analog = msg->len < 10;
+ tuner_dev_info->rec_flag = msg->msg[2] >> 7;
+ tuner_dev_info->tuner_display_info = msg->msg[2] & 0x7f;
+ if (tuner_dev_info->is_analog) {
+ tuner_dev_info->analog.ana_bcast_type = msg->msg[3];
+ tuner_dev_info->analog.ana_freq = (msg->msg[4] << 8) | msg->msg[5];
+ tuner_dev_info->analog.bcast_system = msg->msg[6];
+ return;
+ }
+ cec_get_digital_service_id(msg->msg + 3, &tuner_dev_info->digital);
+}
+
+static __inline__ void cec_msg_give_tuner_device_status(struct cec_msg *msg,
+ bool reply,
+ __u8 status_req)
+{
+ msg->len = 3;
+ msg->msg[1] = CEC_MSG_GIVE_TUNER_DEVICE_STATUS;
+ msg->msg[2] = status_req;
+ msg->reply = reply ? CEC_MSG_TUNER_DEVICE_STATUS : 0;
+}
+
+static __inline__ void cec_ops_give_tuner_device_status(struct cec_msg *msg,
+ __u8 *status_req)
+{
+ *status_req = msg->msg[2];
+}
+
+static __inline__ void cec_msg_select_analogue_service(struct cec_msg *msg,
+ __u8 ana_bcast_type,
+ __u16 ana_freq,
+ __u8 bcast_system)
+{
+ msg->len = 6;
+ msg->msg[1] = CEC_MSG_SELECT_ANALOGUE_SERVICE;
+ msg->msg[2] = ana_bcast_type;
+ msg->msg[3] = ana_freq >> 8;
+ msg->msg[4] = ana_freq & 0xff;
+ msg->msg[5] = bcast_system;
+}
+
+static __inline__ void cec_ops_select_analogue_service(struct cec_msg *msg,
+ __u8 *ana_bcast_type,
+ __u16 *ana_freq,
+ __u8 *bcast_system)
+{
+ *ana_bcast_type = msg->msg[2];
+ *ana_freq = (msg->msg[3] << 8) | msg->msg[4];
+ *bcast_system = msg->msg[5];
+}
+
+static __inline__ void cec_msg_select_digital_service(struct cec_msg *msg,
+ const struct cec_op_digital_service_id *digital)
+{
+ msg->len = 9;
+ msg->msg[1] = CEC_MSG_SELECT_DIGITAL_SERVICE;
+ cec_set_digital_service_id(msg->msg + 2, digital);
+}
+
+static __inline__ void cec_ops_select_digital_service(struct cec_msg *msg,
+ struct cec_op_digital_service_id *digital)
+{
+ cec_get_digital_service_id(msg->msg + 2, digital);
+}
+
+static __inline__ void cec_msg_tuner_step_decrement(struct cec_msg *msg)
+{
+ msg->len = 2;
+ msg->msg[1] = CEC_MSG_TUNER_STEP_DECREMENT;
+}
+
+static __inline__ void cec_msg_tuner_step_increment(struct cec_msg *msg)
+{
+ msg->len = 2;
+ msg->msg[1] = CEC_MSG_TUNER_STEP_INCREMENT;
+}
+
+
+/* Vendor Specific Commands Feature */
+static __inline__ void cec_msg_device_vendor_id(struct cec_msg *msg, __u32 vendor_id)
+{
+ msg->len = 5;
+ msg->msg[0] |= 0xf; /* broadcast */
+ msg->msg[1] = CEC_MSG_DEVICE_VENDOR_ID;
+ msg->msg[2] = vendor_id >> 16;
+ msg->msg[3] = (vendor_id >> 8) & 0xff;
+ msg->msg[4] = vendor_id & 0xff;
+}
+
+static __inline__ void cec_ops_device_vendor_id(const struct cec_msg *msg,
+ __u32 *vendor_id)
+{
+ *vendor_id = (msg->msg[2] << 16) | (msg->msg[3] << 8) | msg->msg[4];
+}
+
+static __inline__ void cec_msg_give_device_vendor_id(struct cec_msg *msg,
+ bool reply)
+{
+ msg->len = 2;
+ msg->msg[1] = CEC_MSG_GIVE_DEVICE_VENDOR_ID;
+ msg->reply = reply ? CEC_MSG_DEVICE_VENDOR_ID : 0;
+}
+
+static __inline__ void cec_msg_vendor_remote_button_up(struct cec_msg *msg)
+{
+ msg->len = 2;
+ msg->msg[1] = CEC_MSG_VENDOR_REMOTE_BUTTON_UP;
+}
+
+
+/* OSD Display Feature */
+static __inline__ void cec_msg_set_osd_string(struct cec_msg *msg,
+ __u8 disp_ctl,
+ const char *osd)
+{
+ unsigned len = strlen(osd);
+
+ if (len > 13)
+ len = 13;
+ msg->len = 3 + len;
+ msg->msg[1] = CEC_MSG_SET_OSD_STRING;
+ msg->msg[2] = disp_ctl;
+ memcpy(msg->msg + 3, osd, len);
+}
+
+static __inline__ void cec_ops_set_osd_string(const struct cec_msg *msg,
+ __u8 *disp_ctl,
+ char *osd)
+{
+ unsigned len = msg->len - 3;
+
+ *disp_ctl = msg->msg[2];
+ if (len > 13)
+ len = 13;
+ memcpy(osd, msg->msg + 3, len);
+ osd[len] = '\0';
+}
+
+
+/* Device OSD Transfer Feature */
+static __inline__ void cec_msg_set_osd_name(struct cec_msg *msg, const char *name)
+{
+ unsigned len = strlen(name);
+
+ if (len > 14)
+ len = 14;
+ msg->len = 2 + len;
+ msg->msg[1] = CEC_MSG_SET_OSD_NAME;
+ memcpy(msg->msg + 2, name, len);
+}
+
+static __inline__ void cec_ops_set_osd_name(const struct cec_msg *msg,
+ char *name)
+{
+ unsigned len = msg->len - 2;
+
+ if (len > 14)
+ len = 14;
+ memcpy(name, msg->msg + 2, len);
+ name[len] = '\0';
+}
+
+static __inline__ void cec_msg_give_osd_name(struct cec_msg *msg,
+ bool reply)
+{
+ msg->len = 2;
+ msg->msg[1] = CEC_MSG_GIVE_OSD_NAME;
+ msg->reply = reply ? CEC_MSG_SET_OSD_NAME : 0;
+}
+
+
+/* Device Menu Control Feature */
+static __inline__ void cec_msg_menu_status(struct cec_msg *msg,
+ __u8 menu_state)
+{
+ msg->len = 3;
+ msg->msg[1] = CEC_MSG_MENU_STATUS;
+ msg->msg[2] = menu_state;
+}
+
+static __inline__ void cec_ops_menu_status(struct cec_msg *msg,
+ __u8 *menu_state)
+{
+ *menu_state = msg->msg[2];
+}
+
+static __inline__ void cec_msg_menu_request(struct cec_msg *msg,
+ bool reply,
+ __u8 menu_req)
+{
+ msg->len = 3;
+ msg->msg[1] = CEC_MSG_MENU_REQUEST;
+ msg->msg[2] = menu_req;
+ msg->reply = reply ? CEC_MSG_MENU_STATUS : 0;
+}
+
+static __inline__ void cec_ops_menu_request(struct cec_msg *msg,
+ __u8 *menu_req)
+{
+ *menu_req = msg->msg[2];
+}
+
+static __inline__ void cec_msg_user_control_pressed(struct cec_msg *msg,
+ __u8 ui_cmd)
+{
+ msg->len = 3;
+ msg->msg[1] = CEC_MSG_USER_CONTROL_PRESSED;
+ msg->msg[2] = ui_cmd;
+}
+
+static __inline__ void cec_ops_user_control_pressed(struct cec_msg *msg,
+ __u8 *ui_cmd)
+{
+ *ui_cmd = msg->msg[2];
+}
+
+static __inline__ void cec_msg_user_control_released(struct cec_msg *msg)
+{
+ msg->len = 2;
+ msg->msg[1] = CEC_MSG_USER_CONTROL_RELEASED;
+}
+
+/* Remote Control Passthrough Feature */
+
+/* Power Status Feature */
+static __inline__ void cec_msg_report_power_status(struct cec_msg *msg,
+ __u8 pwr_state)
+{
+ msg->len = 3;
+ msg->msg[1] = CEC_MSG_REPORT_POWER_STATUS;
+ msg->msg[2] = pwr_state;
+}
+
+static __inline__ void cec_ops_report_power_status(const struct cec_msg *msg,
+ __u8 *pwr_state)
+{
+ *pwr_state = msg->msg[2];
+}
+
+static __inline__ void cec_msg_give_device_power_status(struct cec_msg *msg,
+ bool reply)
+{
+ msg->len = 2;
+ msg->msg[1] = CEC_MSG_GIVE_DEVICE_POWER_STATUS;
+ msg->reply = reply ? CEC_MSG_REPORT_POWER_STATUS : 0;
+}
+
+/* General Protocol Messages */
+static __inline__ void cec_msg_feature_abort(struct cec_msg *msg,
+ __u8 abort_msg, __u8 reason)
+{
+ msg->len = 4;
+ msg->msg[1] = CEC_MSG_FEATURE_ABORT;
+ msg->msg[2] = abort_msg;
+ msg->msg[3] = reason;
+}
+
+static __inline__ void cec_ops_feature_abort(const struct cec_msg *msg,
+ __u8 *abort_msg, __u8 *reason)
+{
+ *abort_msg = msg->msg[2];
+ *reason = msg->msg[3];
+}
+
+/* This changes the current message into an abort message */
+static __inline__ void cec_msg_reply_abort(struct cec_msg *msg, __u8 reason)
+{
+ cec_msg_set_reply_to(msg, msg);
+ msg->len = 4;
+ msg->msg[2] = msg->msg[1];
+ msg->msg[3] = reason;
+ msg->msg[1] = CEC_MSG_FEATURE_ABORT;
+}
+
+static __inline__ void cec_msg_abort(struct cec_msg *msg)
+{
+ msg->len = 2;
+ msg->msg[1] = CEC_MSG_ABORT;
+}
+
+
+/* System Audio Control Feature */
+static __inline__ void cec_msg_report_audio_status(struct cec_msg *msg,
+ __u8 aud_mute_status,
+ __u8 aud_vol_status)
+{
+ msg->len = 3;
+ msg->msg[1] = CEC_MSG_REPORT_AUDIO_STATUS;
+ msg->msg[2] = (aud_mute_status << 7) | (aud_vol_status & 0x7f);
+}
+
+static __inline__ void cec_ops_report_audio_status(const struct cec_msg *msg,
+ __u8 *aud_mute_status,
+ __u8 *aud_vol_status)
+{
+ *aud_mute_status = msg->msg[2] >> 7;
+ *aud_vol_status = msg->msg[2] & 0x7f;
+}
+
+static __inline__ void cec_msg_give_audio_status(struct cec_msg *msg,
+ bool reply)
+{
+ msg->len = 2;
+ msg->msg[1] = CEC_MSG_GIVE_AUDIO_STATUS;
+ msg->reply = reply ? CEC_MSG_REPORT_AUDIO_STATUS : 0;
+}
+
+static __inline__ void cec_msg_set_system_audio_mode(struct cec_msg *msg,
+ __u8 sys_aud_status)
+{
+ msg->len = 3;
+ msg->msg[1] = CEC_MSG_SET_SYSTEM_AUDIO_MODE;
+ msg->msg[2] = sys_aud_status;
+}
+
+static __inline__ void cec_ops_set_system_audio_mode(const struct cec_msg *msg,
+ __u8 *sys_aud_status)
+{
+ *sys_aud_status = msg->msg[2];
+}
+
+static __inline__ void cec_msg_system_audio_mode_request(struct cec_msg *msg,
+ bool reply,
+ __u16 phys_addr)
+{
+ msg->len = phys_addr == 0xffff ? 2 : 4;
+ msg->msg[1] = CEC_MSG_SYSTEM_AUDIO_MODE_REQUEST;
+ msg->msg[2] = phys_addr >> 8;
+ msg->msg[3] = phys_addr & 0xff;
+ msg->reply = reply ? CEC_MSG_SET_SYSTEM_AUDIO_MODE : 0;
+
+}
+
+static __inline__ void cec_ops_system_audio_mode_request(const struct cec_msg *msg,
+ __u16 *phys_addr)
+{
+ if (msg->len < 4)
+ *phys_addr = 0xffff;
+ else
+ *phys_addr = (msg->msg[2] << 8) | msg->msg[3];
+}
+
+static __inline__ void cec_msg_system_audio_mode_status(struct cec_msg *msg,
+ __u8 sys_aud_status)
+{
+ msg->len = 3;
+ msg->msg[1] = CEC_MSG_SYSTEM_AUDIO_MODE_STATUS;
+ msg->msg[2] = sys_aud_status;
+}
+
+static __inline__ void cec_ops_system_audio_mode_status(const struct cec_msg *msg,
+ __u8 *sys_aud_status)
+{
+ *sys_aud_status = msg->msg[2];
+}
+
+static __inline__ void cec_msg_give_system_audio_mode_status(struct cec_msg *msg,
+ bool reply)
+{
+ msg->len = 2;
+ msg->msg[1] = CEC_MSG_GIVE_SYSTEM_AUDIO_MODE_STATUS;
+ msg->reply = reply ? CEC_MSG_SYSTEM_AUDIO_MODE_STATUS : 0;
+}
+
+static __inline__ void cec_msg_report_short_audio_descriptor(struct cec_msg *msg,
+ __u8 num_descriptors,
+ const __u32 *descriptors)
+{
+ unsigned i;
+
+ msg->len = 2 + num_descriptors * 3;
+ msg->msg[1] = CEC_MSG_REPORT_SHORT_AUDIO_DESCRIPTOR;
+ for (i = 0; i < num_descriptors; i++) {
+ msg->msg[2 + i * 3] = (descriptors[i] >> 16) & 0xff;
+ msg->msg[3 + i * 3] = (descriptors[i] >> 8) & 0xff;
+ msg->msg[4 + i * 3] = descriptors[i] & 0xff;
+ }
+}
+
+static __inline__ void cec_ops_report_short_audio_descriptor(const struct cec_msg *msg,
+ __u8 *num_descriptors,
+ __u32 *descriptors)
+{
+ unsigned i;
+
+ *num_descriptors = (msg->len - 2) / 3;
+ for (i = 0; i < *num_descriptors; i++)
+ descriptors[i] = (msg->msg[2 + i * 3] << 16) |
+ (msg->msg[3 + i * 3] << 8) |
+ msg->msg[4 + i * 3];
+}
+
+static __inline__ void cec_msg_request_short_audio_descriptor(struct cec_msg *msg,
+ __u8 audio_format_id,
+ __u8 audio_format_code)
+{
+ msg->len = 3;
+ msg->msg[1] = CEC_MSG_REQUEST_SHORT_AUDIO_DESCRIPTOR;
+ msg->msg[2] = (audio_format_id << 6) | (audio_format_code & 0x3f);
+}
+
+static __inline__ void cec_ops_request_short_audio_descriptor(const struct cec_msg *msg,
+ __u8 *audio_format_id,
+ __u8 *audio_format_code)
+{
+ *audio_format_id = msg->msg[2] >> 6;
+ *audio_format_code = msg->msg[2] & 0x3f;
+}
+
+
+/* Audio Rate Control Feature */
+static __inline__ void cec_msg_set_audio_rate(struct cec_msg *msg,
+ __u8 audio_rate)
+{
+ msg->len = 3;
+ msg->msg[1] = CEC_MSG_SET_AUDIO_RATE;
+ msg->msg[2] = audio_rate;
+}
+
+static __inline__ void cec_ops_set_audio_rate(const struct cec_msg *msg,
+ __u8 *audio_rate)
+{
+ *audio_rate = msg->msg[2];
+}
+
+
+/* Audio Return Channel Control Feature */
+static __inline__ void cec_msg_report_arc_initiated(struct cec_msg *msg)
+{
+ msg->len = 2;
+ msg->msg[1] = CEC_MSG_REPORT_ARC_INITIATED;
+}
+
+static __inline__ void cec_msg_initiate_arc(struct cec_msg *msg,
+ bool reply)
+{
+ msg->len = 2;
+ msg->msg[1] = CEC_MSG_INITIATE_ARC;
+ msg->reply = reply ? CEC_MSG_REPORT_ARC_INITIATED : 0;
+}
+
+static __inline__ void cec_msg_request_arc_initiation(struct cec_msg *msg,
+ bool reply)
+{
+ msg->len = 2;
+ msg->msg[1] = CEC_MSG_REQUEST_ARC_INITIATION;
+ msg->reply = reply ? CEC_MSG_INITIATE_ARC : 0;
+}
+
+static __inline__ void cec_msg_report_arc_terminated(struct cec_msg *msg)
+{
+ msg->len = 2;
+ msg->msg[1] = CEC_MSG_REPORT_ARC_TERMINATED;
+}
+
+static __inline__ void cec_msg_terminate_arc(struct cec_msg *msg,
+ bool reply)
+{
+ msg->len = 2;
+ msg->msg[1] = CEC_MSG_TERMINATE_ARC;
+ msg->reply = reply ? CEC_MSG_REPORT_ARC_TERMINATED : 0;
+}
+
+static __inline__ void cec_msg_request_arc_termination(struct cec_msg *msg,
+ bool reply)
+{
+ msg->len = 2;
+ msg->msg[1] = CEC_MSG_REQUEST_ARC_TERMINATION;
+ msg->reply = reply ? CEC_MSG_TERMINATE_ARC : 0;
+}
+
+
+/* Dynamic Audio Lipsync Feature */
+/* Only for CEC 2.0 and up */
+static __inline__ void cec_msg_report_current_latency(struct cec_msg *msg,
+ __u16 phys_addr,
+ __u8 video_latency,
+ __u8 low_latency_mode,
+ __u8 audio_out_compensated,
+ __u8 audio_out_delay)
+{
+ msg->len = 7;
+ msg->msg[1] = CEC_MSG_REPORT_CURRENT_LATENCY;
+ msg->msg[2] = phys_addr >> 8;
+ msg->msg[3] = phys_addr & 0xff;
+ msg->msg[4] = video_latency;
+ msg->msg[5] = (low_latency_mode << 2) | audio_out_compensated;
+ msg->msg[6] = audio_out_delay;
+}
+
+static __inline__ void cec_ops_report_current_latency(const struct cec_msg *msg,
+ __u16 *phys_addr,
+ __u8 *video_latency,
+ __u8 *low_latency_mode,
+ __u8 *audio_out_compensated,
+ __u8 *audio_out_delay)
+{
+ *phys_addr = (msg->msg[2] << 8) | msg->msg[3];
+ *video_latency = msg->msg[4];
+ *low_latency_mode = (msg->msg[5] >> 2) & 1;
+ *audio_out_compensated = msg->msg[5] & 3;
+ *audio_out_delay = msg->msg[6];
+}
+
+static __inline__ void cec_msg_request_current_latency(struct cec_msg *msg,
+ bool reply,
+ __u16 phys_addr)
+{
+ msg->len = 4;
+ msg->msg[1] = CEC_MSG_REQUEST_CURRENT_LATENCY;
+ msg->msg[2] = phys_addr >> 8;
+ msg->msg[3] = phys_addr & 0xff;
+ msg->reply = reply ? CEC_MSG_REPORT_CURRENT_LATENCY : 0;
+}
+
+static __inline__ void cec_ops_request_current_latency(const struct cec_msg *msg,
+ __u16 *phys_addr)
+{
+ *phys_addr = (msg->msg[2] << 8) | msg->msg[3];
+}
+
+
+/* Capability Discovery and Control Feature */
+static __inline__ void cec_msg_cdc_hec_inquire_state(struct cec_msg *msg,
+ __u16 phys_addr1,
+ __u16 phys_addr2)
+{
+ msg->len = 9;
+ msg->msg[0] |= 0xf; /* broadcast */
+ msg->msg[1] = CEC_MSG_CDC_MESSAGE;
+ /* msg[2] and msg[3] (phys_addr) are filled in by the CEC framework */
+ msg->msg[4] = CEC_MSG_CDC_HEC_INQUIRE_STATE;
+ msg->msg[5] = phys_addr1 >> 8;
+ msg->msg[6] = phys_addr1 & 0xff;
+ msg->msg[7] = phys_addr2 >> 8;
+ msg->msg[8] = phys_addr2 & 0xff;
+}
+
+static __inline__ void cec_ops_cdc_hec_inquire_state(const struct cec_msg *msg,
+ __u16 *phys_addr,
+ __u16 *phys_addr1,
+ __u16 *phys_addr2)
+{
+ *phys_addr = (msg->msg[2] << 8) | msg->msg[3];
+ *phys_addr1 = (msg->msg[5] << 8) | msg->msg[6];
+ *phys_addr2 = (msg->msg[7] << 8) | msg->msg[8];
+}
+
+static __inline__ void cec_msg_cdc_hec_report_state(struct cec_msg *msg,
+ __u16 target_phys_addr,
+ __u8 hec_func_state,
+ __u8 host_func_state,
+ __u8 enc_func_state,
+ __u8 cdc_errcode,
+ __u8 has_field,
+ __u16 hec_field)
+{
+ msg->len = has_field ? 10 : 8;
+ msg->msg[0] |= 0xf; /* broadcast */
+ msg->msg[1] = CEC_MSG_CDC_MESSAGE;
+ /* msg[2] and msg[3] (phys_addr) are filled in by the CEC framework */
+ msg->msg[4] = CEC_MSG_CDC_HEC_REPORT_STATE;
+ msg->msg[5] = target_phys_addr >> 8;
+ msg->msg[6] = target_phys_addr & 0xff;
+ msg->msg[7] = (hec_func_state << 6) |
+ (host_func_state << 4) |
+ (enc_func_state << 2) |
+ cdc_errcode;
+ if (has_field) {
+ msg->msg[8] = hec_field >> 8;
+ msg->msg[9] = hec_field & 0xff;
+ }
+}
+
+static __inline__ void cec_ops_cdc_hec_report_state(const struct cec_msg *msg,
+ __u16 *phys_addr,
+ __u16 *target_phys_addr,
+ __u8 *hec_func_state,
+ __u8 *host_func_state,
+ __u8 *enc_func_state,
+ __u8 *cdc_errcode,
+ __u8 *has_field,
+ __u16 *hec_field)
+{
+ *phys_addr = (msg->msg[2] << 8) | msg->msg[3];
+ *target_phys_addr = (msg->msg[5] << 8) | msg->msg[6];
+ *hec_func_state = msg->msg[7] >> 6;
+ *host_func_state = (msg->msg[7] >> 4) & 3;
+ *enc_func_state = (msg->msg[7] >> 4) & 3;
+ *cdc_errcode = msg->msg[7] & 3;
+ *has_field = msg->len >= 10;
+ *hec_field = *has_field ? ((msg->msg[8] << 8) | msg->msg[9]) : 0;
+}
+
+static __inline__ void cec_msg_cdc_hec_set_state(struct cec_msg *msg,
+ __u16 phys_addr1,
+ __u16 phys_addr2,
+ __u8 hec_set_state,
+ __u16 phys_addr3,
+ __u16 phys_addr4,
+ __u16 phys_addr5)
+{
+ msg->len = 10;
+ msg->msg[0] |= 0xf; /* broadcast */
+ msg->msg[1] = CEC_MSG_CDC_MESSAGE;
+ /* msg[2] and msg[3] (phys_addr) are filled in by the CEC framework */
+ msg->msg[4] = CEC_MSG_CDC_HEC_INQUIRE_STATE;
+ msg->msg[5] = phys_addr1 >> 8;
+ msg->msg[6] = phys_addr1 & 0xff;
+ msg->msg[7] = phys_addr2 >> 8;
+ msg->msg[8] = phys_addr2 & 0xff;
+ msg->msg[9] = hec_set_state;
+ if (phys_addr3 != CEC_PHYS_ADDR_INVALID) {
+ msg->msg[msg->len++] = phys_addr3 >> 8;
+ msg->msg[msg->len++] = phys_addr3 & 0xff;
+ if (phys_addr4 != CEC_PHYS_ADDR_INVALID) {
+ msg->msg[msg->len++] = phys_addr4 >> 8;
+ msg->msg[msg->len++] = phys_addr4 & 0xff;
+ if (phys_addr5 != CEC_PHYS_ADDR_INVALID) {
+ msg->msg[msg->len++] = phys_addr5 >> 8;
+ msg->msg[msg->len++] = phys_addr5 & 0xff;
+ }
+ }
+ }
+}
+
+static __inline__ void cec_ops_cdc_hec_set_state(const struct cec_msg *msg,
+ __u16 *phys_addr,
+ __u16 *phys_addr1,
+ __u16 *phys_addr2,
+ __u8 *hec_set_state,
+ __u16 *phys_addr3,
+ __u16 *phys_addr4,
+ __u16 *phys_addr5)
+{
+ *phys_addr = (msg->msg[2] << 8) | msg->msg[3];
+ *phys_addr1 = (msg->msg[5] << 8) | msg->msg[6];
+ *phys_addr2 = (msg->msg[7] << 8) | msg->msg[8];
+ *hec_set_state = msg->msg[9];
+ *phys_addr3 = *phys_addr4 = *phys_addr5 = CEC_PHYS_ADDR_INVALID;
+ if (msg->len >= 12)
+ *phys_addr3 = (msg->msg[10] << 8) | msg->msg[11];
+ if (msg->len >= 14)
+ *phys_addr4 = (msg->msg[12] << 8) | msg->msg[13];
+ if (msg->len >= 16)
+ *phys_addr5 = (msg->msg[14] << 8) | msg->msg[15];
+}
+
+static __inline__ void cec_msg_cdc_hec_set_state_adjacent(struct cec_msg *msg,
+ __u16 phys_addr1,
+ __u8 hec_set_state)
+{
+ msg->len = 8;
+ msg->msg[0] |= 0xf; /* broadcast */
+ msg->msg[1] = CEC_MSG_CDC_MESSAGE;
+ /* msg[2] and msg[3] (phys_addr) are filled in by the CEC framework */
+ msg->msg[4] = CEC_MSG_CDC_HEC_SET_STATE_ADJACENT;
+ msg->msg[5] = phys_addr1 >> 8;
+ msg->msg[6] = phys_addr1 & 0xff;
+ msg->msg[7] = hec_set_state;
+}
+
+static __inline__ void cec_ops_cdc_hec_set_state_adjacent(const struct cec_msg *msg,
+ __u16 *phys_addr,
+ __u16 *phys_addr1,
+ __u8 *hec_set_state)
+{
+ *phys_addr = (msg->msg[2] << 8) | msg->msg[3];
+ *phys_addr1 = (msg->msg[5] << 8) | msg->msg[6];
+ *hec_set_state = msg->msg[7];
+}
+
+static __inline__ void cec_msg_cdc_hec_request_deactivation(struct cec_msg *msg,
+ __u16 phys_addr1,
+ __u16 phys_addr2,
+ __u16 phys_addr3)
+{
+ msg->len = 11;
+ msg->msg[0] |= 0xf; /* broadcast */
+ msg->msg[1] = CEC_MSG_CDC_MESSAGE;
+ /* msg[2] and msg[3] (phys_addr) are filled in by the CEC framework */
+ msg->msg[4] = CEC_MSG_CDC_HEC_REQUEST_DEACTIVATION;
+ msg->msg[5] = phys_addr1 >> 8;
+ msg->msg[6] = phys_addr1 & 0xff;
+ msg->msg[7] = phys_addr2 >> 8;
+ msg->msg[8] = phys_addr2 & 0xff;
+ msg->msg[9] = phys_addr3 >> 8;
+ msg->msg[10] = phys_addr3 & 0xff;
+}
+
+static __inline__ void cec_ops_cdc_hec_request_deactivation(const struct cec_msg *msg,
+ __u16 *phys_addr,
+ __u16 *phys_addr1,
+ __u16 *phys_addr2,
+ __u16 *phys_addr3)
+{
+ *phys_addr = (msg->msg[2] << 8) | msg->msg[3];
+ *phys_addr1 = (msg->msg[5] << 8) | msg->msg[6];
+ *phys_addr2 = (msg->msg[7] << 8) | msg->msg[8];
+ *phys_addr3 = (msg->msg[9] << 8) | msg->msg[10];
+}
+
+static __inline__ void cec_msg_cdc_hec_notify_alive(struct cec_msg *msg)
+{
+ msg->len = 5;
+ msg->msg[0] |= 0xf; /* broadcast */
+ msg->msg[1] = CEC_MSG_CDC_MESSAGE;
+ /* msg[2] and msg[3] (phys_addr) are filled in by the CEC framework */
+ msg->msg[4] = CEC_MSG_CDC_HEC_NOTIFY_ALIVE;
+}
+
+static __inline__ void cec_ops_cdc_hec_notify_alive(const struct cec_msg *msg,
+ __u16 *phys_addr)
+{
+ *phys_addr = (msg->msg[2] << 8) | msg->msg[3];
+}
+
+static __inline__ void cec_msg_cdc_hec_discover(struct cec_msg *msg)
+{
+ msg->len = 5;
+ msg->msg[0] |= 0xf; /* broadcast */
+ msg->msg[1] = CEC_MSG_CDC_MESSAGE;
+ /* msg[2] and msg[3] (phys_addr) are filled in by the CEC framework */
+ msg->msg[4] = CEC_MSG_CDC_HEC_DISCOVER;
+}
+
+static __inline__ void cec_ops_cdc_hec_discover(const struct cec_msg *msg,
+ __u16 *phys_addr)
+{
+ *phys_addr = (msg->msg[2] << 8) | msg->msg[3];
+}
+
+static __inline__ void cec_msg_cdc_hpd_set_state(struct cec_msg *msg,
+ __u8 input_port,
+ __u8 hpd_state)
+{
+ msg->len = 6;
+ msg->msg[0] |= 0xf; /* broadcast */
+ msg->msg[1] = CEC_MSG_CDC_MESSAGE;
+ /* msg[2] and msg[3] (phys_addr) are filled in by the CEC framework */
+ msg->msg[4] = CEC_MSG_CDC_HPD_SET_STATE;
+ msg->msg[5] = (input_port << 4) | hpd_state;
+}
+
+static __inline__ void cec_ops_cdc_hpd_set_state(const struct cec_msg *msg,
+ __u16 *phys_addr,
+ __u8 *input_port,
+ __u8 *hpd_state)
+{
+ *phys_addr = (msg->msg[2] << 8) | msg->msg[3];
+ *input_port = msg->msg[5] >> 4;
+ *hpd_state = msg->msg[5] & 0xf;
+}
+
+static __inline__ void cec_msg_cdc_hpd_report_state(struct cec_msg *msg,
+ __u8 hpd_state,
+ __u8 hpd_error)
+{
+ msg->len = 6;
+ msg->msg[0] |= 0xf; /* broadcast */
+ msg->msg[1] = CEC_MSG_CDC_MESSAGE;
+ /* msg[2] and msg[3] (phys_addr) are filled in by the CEC framework */
+ msg->msg[4] = CEC_MSG_CDC_HPD_REPORT_STATE;
+ msg->msg[5] = (hpd_state << 4) | hpd_error;
+}
+
+static __inline__ void cec_ops_cdc_hpd_report_state(const struct cec_msg *msg,
+ __u16 *phys_addr,
+ __u8 *hpd_state,
+ __u8 *hpd_error)
+{
+ *phys_addr = (msg->msg[2] << 8) | msg->msg[3];
+ *hpd_state = msg->msg[5] >> 4;
+ *hpd_error = msg->msg[5] & 0xf;
+}
+
+#endif
diff --git a/include/linux/cec.h b/include/linux/cec.h
new file mode 100644
index 0000000..e02c21d
--- /dev/null
+++ b/include/linux/cec.h
@@ -0,0 +1,781 @@
+#ifndef _CEC_H
+#define _CEC_H
+
+#include <linux/types.h>
+
+struct cec_msg {
+ __u64 ts;
+ __u32 len;
+ __u32 status;
+ /*
+ * timeout (in ms) is used to timeout CEC_RECEIVE.
+ * Set to 0 if you want to wait forever.
+ */
+ __u32 timeout;
+ /*
+ * The framework assigns a sequence number to messages that are sent.
+ * This can be used to track replies to previously sent messages.
+ */
+ __u32 sequence;
+ __u8 msg[16];
+ /*
+ * 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;
+ __u8 reserved[35];
+};
+
+static __inline__ __u8 cec_msg_initiator(const struct cec_msg *msg)
+{
+ return msg->msg[0] >> 4;
+}
+
+static __inline__ __u8 cec_msg_destination(const struct cec_msg *msg)
+{
+ return msg->msg[0] & 0xf;
+}
+
+static __inline__ bool cec_msg_is_broadcast(const struct cec_msg *msg)
+{
+ return (msg->msg[0] & 0xf) == 0xf;
+}
+
+static __inline__ void cec_msg_init(struct cec_msg *msg,
+ __u8 initiator, __u8 destination)
+{
+ memset(msg, 0, sizeof(*msg));
+ msg->msg[0] = (initiator << 4) | destination;
+ msg->len = 1;
+}
+
+/*
+ * Set the msg destination to the orig initiator and the msg initiator to the
+ * orig destination. Note that msg and orig may be the same pointer, in which
+ * case the change is done in place.
+ */
+static __inline__ void cec_msg_set_reply_to(struct cec_msg *msg, struct cec_msg *orig)
+{
+ /* The destination becomes the initiator and vice versa */
+ msg->msg[0] = (cec_msg_destination(orig) << 4) | cec_msg_initiator(orig);
+}
+
+/* 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
+#define CEC_PHYS_ADDR_INVALID 0xffff
+
+/* 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 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.
+ * Processors should use SPECIFIC. */
+
+/*
+ * Use this if there is no vendor ID (CEC_G_VENDOR_ID) or if the vendor ID
+ * should be disabled (CEC_S_VENDOR_ID)
+ */
+#define CEC_VENDOR_ID_NONE 0xffffffff
+
+/* The CEC adapter state */
+#define CEC_ADAP_DISABLED 0
+#define CEC_ADAP_ENABLED 1
+
+/* The passthrough mode state */
+#define CEC_PASSTHROUGH_DISABLED 0
+#define CEC_PASSTHROUGH_ENABLED 1
+
+/* The monitor state */
+#define CEC_MONITOR_DISABLED 0
+#define CEC_MONITOR_ENABLED 1
+
+/* Userspace has to configure the adapter state (enable/disable) */
+#define CEC_CAP_STATE (1 << 0)
+/* Userspace has to configure the physical address */
+#define CEC_CAP_PHYS_ADDR (1 << 1)
+/* Userspace has to configure the logical addresses */
+#define CEC_CAP_LOG_ADDRS (1 << 2)
+/* Userspace can transmit and receive messages */
+#define CEC_CAP_IO (1 << 3)
+/* Userspace has to configure the vendor id */
+#define CEC_CAP_VENDOR_ID (1 << 4)
+/*
+ * Passthrough all messages instead of processing them.
+ * Note: ARC and CDC messages are always processed.
+ */
+#define CEC_CAP_PASSTHROUGH (1 << 5)
+/* Supports remote control */
+#define CEC_CAP_RC (1 << 6)
+/* Supports ARC */
+#define CEC_CAP_ARC (1 << 7)
+/* Supports CDC HPD */
+#define CEC_CAP_CDC_HPD (1 << 8)
+/* Is a source */
+#define CEC_CAP_IS_SOURCE (1 << 9)
+
+struct cec_caps {
+ __u32 available_log_addrs;
+ __u32 capabilities;
+ __u8 ninputs;
+ __u8 reserved[39];
+};
+
+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];
+ char osd_name[15];
+
+ /* CEC 2.0 */
+ __u8 all_device_types[CEC_MAX_LOG_ADDRS];
+ __u8 features[CEC_MAX_LOG_ADDRS][12];
+
+ __u8 reserved[63];
+};
+
+/* Events */
+
+/* Event that occurs when the adapter state changes */
+#define CEC_EVENT_STATE_CHANGE 1
+/* Event that occurs when inputs are connected/disconnected */
+#define CEC_EVENT_INPUTS_CHANGE 2
+/* This event is sent when messages are lost because the application
+ * didn't empty the message queue in time */
+#define CEC_EVENT_LOST_MSGS 3
+
+#define CEC_EVENT_STATE_DISABLED 0
+#define CEC_EVENT_STATE_UNCONFIGURED 1
+#define CEC_EVENT_STATE_CONFIGURING 2
+#define CEC_EVENT_STATE_CONFIGURED 3
+
+struct cec_event_state_change {
+ /* current CEC adapter state */
+ __u8 state;
+};
+
+struct cec_event_inputs_change {
+ /* bit 0 == input port 0, bit 15 == input port 15 */
+ /* currently connected input ports */
+ __u16 connected_inputs;
+ /* input ports that changed state since last event */
+ __u16 changed_inputs;
+};
+
+struct cec_event {
+ __u64 ts;
+ __u32 event;
+ __u32 reserved[7];
+ union {
+ struct cec_event_state_change state_change;
+ struct cec_event_inputs_change inputs_change;
+ __u32 raw[16];
+ };
+};
+
+/* ioctls */
+
+/* Adapter capabilities */
+#define CEC_ADAP_G_CAPS _IOWR('a', 0, struct cec_caps)
+
+/*
+ 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_ADAP_G_LOG_ADDRS _IOR ('a', 1, struct cec_log_addrs)
+#define CEC_ADAP_S_LOG_ADDRS _IOWR('a', 2, struct cec_log_addrs)
+
+/*
+ Enable/disable the adapter. The Set state ioctl may not
+ be available if that is handled internally.
+ */
+#define CEC_ADAP_G_STATE _IOR ('a', 3, __u32)
+#define CEC_ADAP_S_STATE _IOW ('a', 4, __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_ADAP_G_PHYS_ADDR _IOR ('a', 5, __u16)
+#define CEC_ADAP_S_PHYS_ADDR _IOW ('a', 6, __u16)
+
+/*
+ Read and set the vendor ID of the CEC adapter.
+ */
+#define CEC_ADAP_G_VENDOR_ID _IOR ('a', 7, __u32)
+#define CEC_ADAP_S_VENDOR_ID _IOW ('a', 8, __u32)
+
+/*
+ Read and set the monitor state of the filehandle.
+ */
+#define CEC_G_MONITOR _IOR ('a', 9, __u32)
+#define CEC_S_MONITOR _IOW ('a', 10, __u32)
+
+/*
+ Claim message handling and set passthrough mode,
+ release message handling and get passthrough mode for
+ this filehandle.
+ */
+#define CEC_CLAIM _IOW ('a', 11, __u32)
+#define CEC_RELEASE _IO ('a', 12)
+#define CEC_G_PASSTHROUGH _IOR ('a', 13, __u32)
+
+/* Transmit/receive a CEC command */
+#define CEC_TRANSMIT _IOWR('a', 14, struct cec_msg)
+#define CEC_RECEIVE _IOWR('a', 15, struct cec_msg)
+
+/* Dequeue CEC events */
+#define CEC_DQEVENT _IOWR('a', 16, struct cec_event)
+
+/* Commands */
+
+/* One Touch Play Feature */
+#define CEC_MSG_ACTIVE_SOURCE 0x82
+#define CEC_MSG_IMAGE_VIEW_ON 0x04
+#define CEC_MSG_TEXT_VIEW_ON 0x0d
+
+
+/* Routing Control Feature */
+
+/*
+ * Has also:
+ * CEC_MSG_ACTIVE_SOURCE
+ */
+
+#define CEC_MSG_INACTIVE_SOURCE 0x9d
+#define CEC_MSG_REQUEST_ACTIVE_SOURCE 0x85
+#define CEC_MSG_ROUTING_CHANGE 0x80
+#define CEC_MSG_ROUTING_INFORMATION 0x81
+#define CEC_MSG_SET_STREAM_PATH 0x86
+
+
+/* Standby Feature */
+#define CEC_MSG_STANDBY 0x36
+
+
+/* One Touch Record Feature */
+#define CEC_MSG_RECORD_OFF 0x0b
+#define CEC_MSG_RECORD_ON 0x09
+/* Record Source Type Operand (rec_src_type) */
+#define CEC_OP_RECORD_SRC_OWN 1
+#define CEC_OP_RECORD_SRC_DIGITAL 2
+#define CEC_OP_RECORD_SRC_ANALOG 3
+#define CEC_OP_RECORD_SRC_EXT_PLUG 4
+#define CEC_OP_RECORD_SRC_EXT_PHYS_ADDR 5
+/* Service Identification Method Operand (service_id_method) */
+#define CEC_OP_SERVICE_ID_METHOD_BY_DIG_ID 0
+#define CEC_OP_SERVICE_ID_METHOD_BY_CHANNEL 1
+/* Digital Service Broadcast System Operand (dig_bcast_system) */
+#define CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ARIB_GEN 0x00
+#define CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_GEN 0x01
+#define CEC_OP_DIG_SERVICE_BCAST_SYSTEM_DVB_GEN 0x02
+#define CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ARIB_BS 0x08
+#define CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ARIB_CS 0x09
+#define CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ARIB_T 0x0a
+#define CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_CABLE 0x10
+#define CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_SAT 0x11
+#define CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_T 0x12
+#define CEC_OP_DIG_SERVICE_BCAST_SYSTEM_DVB_C 0x18
+#define CEC_OP_DIG_SERVICE_BCAST_SYSTEM_DVB_S 0x19
+#define CEC_OP_DIG_SERVICE_BCAST_SYSTEM_DVB_S2 0x1a
+#define CEC_OP_DIG_SERVICE_BCAST_SYSTEM_DVB_T 0x1b
+/* Analogue Broadcast Type Operand (ana_bcast_type) */
+#define CEC_OP_ANA_BCAST_TYPE_CABLE 0
+#define CEC_OP_ANA_BCAST_TYPE_SATELLITE 1
+#define CEC_OP_ANA_BCAST_TYPE_TERRESTRIAL 2
+/* Broadcast System Operand (bcast_system) */
+#define CEC_OP_BCAST_SYSTEM_PAL_BG 0x00
+#define CEC_OP_BCAST_SYSTEM_SECAM_LQ 0x01 /* SECAM L' */
+#define CEC_OP_BCAST_SYSTEM_PAL_M 0x02
+#define CEC_OP_BCAST_SYSTEM_NTSC_M 0x03
+#define CEC_OP_BCAST_SYSTEM_PAL_I 0x04
+#define CEC_OP_BCAST_SYSTEM_SECAM_DK 0x05
+#define CEC_OP_BCAST_SYSTEM_SECAM_BG 0x06
+#define CEC_OP_BCAST_SYSTEM_SECAM_L 0x07
+#define CEC_OP_BCAST_SYSTEM_PAL_DK 0x08
+#define CEC_OP_BCAST_SYSTEM_OTHER 0x1f
+/* Channel Number Format Operand (channel_number_fmt) */
+#define CEC_OP_CHANNEL_NUMBER_FMT_1_PART 0x01
+#define CEC_OP_CHANNEL_NUMBER_FMT_2_PART 0x02
+
+#define CEC_MSG_RECORD_STATUS 0x0a
+/* Record Status Operand (rec_status) */
+#define CEC_OP_RECORD_STATUS_CUR_SRC 0x01
+#define CEC_OP_RECORD_STATUS_DIG_SERVICE 0x02
+#define CEC_OP_RECORD_STATUS_ANA_SERVICE 0x03
+#define CEC_OP_RECORD_STATUS_EXT_INPUT 0x04
+#define CEC_OP_RECORD_STATUS_NO_DIG_SERVICE 0x05
+#define CEC_OP_RECORD_STATUS_NO_ANA_SERVICE 0x06
+#define CEC_OP_RECORD_STATUS_NO_SERVICE 0x07
+#define CEC_OP_RECORD_STATUS_INVALID_EXT_PLUG 0x09
+#define CEC_OP_RECORD_STATUS_INVALID_EXT_PHYS_ADDR 0x0a
+#define CEC_OP_RECORD_STATUS_UNSUP_CA 0x0b
+#define CEC_OP_RECORD_STATUS_NO_CA_ENTITLEMENTS 0x0c
+#define CEC_OP_RECORD_STATUS_CANT_COPY_SRC 0x0d
+#define CEC_OP_RECORD_STATUS_NO_MORE_COPIES 0x0e
+#define CEC_OP_RECORD_STATUS_NO_MEDIA 0x10
+#define CEC_OP_RECORD_STATUS_PLAYING 0x11
+#define CEC_OP_RECORD_STATUS_ALREADY_RECORDING 0x12
+#define CEC_OP_RECORD_STATUS_MEDIA_PROT 0x13
+#define CEC_OP_RECORD_STATUS_NO_SIGNAL 0x14
+#define CEC_OP_RECORD_STATUS_MEDIA_PROBLEM 0x15
+#define CEC_OP_RECORD_STATUS_NO_SPACE 0x16
+#define CEC_OP_RECORD_STATUS_PARENTAL_LOCK 0x17
+#define CEC_OP_RECORD_STATUS_TERMINATED_OK 0x1a
+#define CEC_OP_RECORD_STATUS_ALREADY_TERM 0x1b
+#define CEC_OP_RECORD_STATUS_OTHER 0x1f
+
+#define CEC_MSG_RECORD_TV_SCREEN 0x0f
+
+
+/* Timer Programming Feature */
+#define CEC_MSG_CLEAR_ANALOGUE_TIMER 0x33
+/* Recording Sequence Operand (recording_seq) */
+#define CEC_OP_REC_SEQ_SUNDAY 0x01
+#define CEC_OP_REC_SEQ_MONDAY 0x02
+#define CEC_OP_REC_SEQ_TUESDAY 0x04
+#define CEC_OP_REC_SEQ_WEDNESDAY 0x08
+#define CEC_OP_REC_SEQ_THURSDAY 0x10
+#define CEC_OP_REC_SEQ_FRIDAY 0x20
+#define CEC_OP_REC_SEQ_SATERDAY 0x40
+#define CEC_OP_REC_SEQ_ONCE_ONLY 0x00
+
+#define CEC_MSG_CLEAR_DIGITAL_TIMER 0x99
+
+#define CEC_MSG_CLEAR_EXT_TIMER 0xa1
+/* External Source Specifier Operand (ext_src_spec) */
+#define CEC_OP_EXT_SRC_PLUG 0x04
+#define CEC_OP_EXT_SRC_PHYS_ADDR 0x05
+
+#define CEC_MSG_SET_ANALOGUE_TIMER 0x34
+#define CEC_MSG_SET_DIGITAL_TIMER 0x97
+#define CEC_MSG_SET_EXT_TIMER 0xa2
+
+#define CEC_MSG_SET_TIMER_PROGRAM_TITLE 0x67
+#define CEC_MSG_TIMER_CLEARED_STATUS 0x43
+/* Timer Cleared Status Data Operand (timer_cleared_status) */
+#define CEC_OP_TIMER_CLR_STAT_RECORDING 0x00
+#define CEC_OP_TIMER_CLR_STAT_NO_MATCHING 0x01
+#define CEC_OP_TIMER_CLR_STAT_NO_INFO 0x02
+#define CEC_OP_TIMER_CLR_STAT_CLEARED 0x80
+
+#define CEC_MSG_TIMER_STATUS 0x35
+/* Timer Overlap Warning Operand (timer_overlap_warning) */
+#define CEC_OP_TIMER_OVERLAP_WARNING_NO_OVERLAP 0
+#define CEC_OP_TIMER_OVERLAP_WARNING_OVERLAP 1
+/* Media Info Operand (media_info) */
+#define CEC_OP_MEDIA_INFO_UNPROT_MEDIA 0
+#define CEC_OP_MEDIA_INFO_PROT_MEDIA 1
+#define CEC_OP_MEDIA_INFO_NO_MEDIA 2
+/* Programmed Indicator Operand (prog_indicator) */
+#define CEC_OP_PROG_IND_NOT_PROGRAMMED 0
+#define CEC_OP_PROG_IND_PROGRAMMED 1
+/* Programmed Info Operand (prog_info) */
+#define CEC_OP_PROG_INFO_ENOUGH_SPACE 0x08
+#define CEC_OP_PROG_INFO_NOT_ENOUGH_SPACE 0x09
+#define CEC_OP_PROG_INFO_MIGHT_NOT_BE_ENOUGH_SPACE 0x0b
+#define CEC_OP_PROG_INFO_NONE_AVAILABLE 0x0a
+/* Not Programmed Error Info Operand (prog_error) */
+#define CEC_OP_PROG_ERROR_NO_FREE_TIMER 0x01
+#define CEC_OP_PROG_ERROR_DATE_OUT_OF_RANGE 0x02
+#define CEC_OP_PROG_ERROR_REC_SEQ_ERROR 0x03
+#define CEC_OP_PROG_ERROR_INV_EXT_PLUG 0x04
+#define CEC_OP_PROG_ERROR_INV_EXT_PHYS_ADDR 0x05
+#define CEC_OP_PROG_ERROR_CA_UNSUPP 0x06
+#define CEC_OP_PROG_ERROR_INSUF_CA_ENTITLEMENTS 0x07
+#define CEC_OP_PROG_ERROR_RESOLUTION_UNSUPP 0x08
+#define CEC_OP_PROG_ERROR_PARENTAL_LOCK 0x09
+#define CEC_OP_PROG_ERROR_CLOCK_FAILURE 0x0a
+#define CEC_OP_PROG_ERROR_DUPLICATE 0x0e
+
+
+/* System Information Feature */
+#define CEC_MSG_CEC_VERSION 0x9e
+/* CEC Version Operand (cec_version) */
+#define CEC_OP_CEC_VERSION_1_3A 4
+#define CEC_OP_CEC_VERSION_1_4 5
+#define CEC_OP_CEC_VERSION_2_0 6
+
+#define CEC_MSG_GET_CEC_VERSION 0x9f
+#define CEC_MSG_GIVE_PHYSICAL_ADDR 0x83
+#define CEC_MSG_GET_MENU_LANGUAGE 0x91
+#define CEC_MSG_REPORT_PHYSICAL_ADDR 0x84
+/* Primary Device Type Operand (prim_devtype) */
+#define CEC_OP_PRIM_DEVTYPE_TV 0
+#define CEC_OP_PRIM_DEVTYPE_RECORD 1
+#define CEC_OP_PRIM_DEVTYPE_TUNER 3
+#define CEC_OP_PRIM_DEVTYPE_PLAYBACK 4
+#define CEC_OP_PRIM_DEVTYPE_AUDIOSYSTEM 5
+#define CEC_OP_PRIM_DEVTYPE_SWITCH 6
+#define CEC_OP_PRIM_DEVTYPE_PROCESSOR 7
+
+#define CEC_MSG_SET_MENU_LANGUAGE 0x32
+#define CEC_MSG_REPORT_FEATURES 0xa6 /* HDMI 2.0 */
+/* All Device Types Operand (all_device_types) */
+#define CEC_OP_ALL_DEVTYPE_TV 0x80
+#define CEC_OP_ALL_DEVTYPE_RECORD 0x40
+#define CEC_OP_ALL_DEVTYPE_TUNER 0x20
+#define CEC_OP_ALL_DEVTYPE_PLAYBACK 0x10
+#define CEC_OP_ALL_DEVTYPE_AUDIOSYSTEM 0x08
+#define CEC_OP_ALL_DEVTYPE_SWITCH 0x04
+/* And if you wondering what happened to PROCESSOR devices: those should
+ * be mapped to a SWITCH. */
+
+/* Valid for RC Profile and Device Feature operands */
+#define CEC_OP_FEAT_EXT 0x80 /* Extension bit */
+/* RC Profile Operand (rc_profile) */
+#define CEC_OP_FEAT_RC_TV_PROFILE_NONE 0x00
+#define CEC_OP_FEAT_RC_TV_PROFILE_1 0x02
+#define CEC_OP_FEAT_RC_TV_PROFILE_2 0x06
+#define CEC_OP_FEAT_RC_TV_PROFILE_3 0x0a
+#define CEC_OP_FEAT_RC_TV_PROFILE_4 0x0e
+#define CEC_OP_FEAT_RC_SRC_HAS_DEV_ROOT_MENU 0x50
+#define CEC_OP_FEAT_RC_SRC_HAS_DEV_SETUP_MENU 0x48
+#define CEC_OP_FEAT_RC_SRC_HAS_CONTENTS_MENU 0x44
+#define CEC_OP_FEAT_RC_SRC_HAS_MEDIA_TOP_MENU 0x42
+#define CEC_OP_FEAT_RC_SRC_HAS_MEDIA_CONTEXT_MENU 0x41
+/* Device Feature Operand (dev_features) */
+#define CEC_OP_FEAT_DEV_HAS_RECORD_TV_SCREEN 0x40
+#define CEC_OP_FEAT_DEV_HAS_SET_OSD_STRING 0x20
+#define CEC_OP_FEAT_DEV_HAS_DECK_CONTROL 0x10
+#define CEC_OP_FEAT_DEV_HAS_SET_AUDIO_RATE 0x08
+#define CEC_OP_FEAT_DEV_SINK_HAS_ARC_TX 0x04
+#define CEC_OP_FEAT_DEV_SOURCE_HAS_ARC_RX 0x02
+
+#define CEC_MSG_GIVE_FEATURES 0xa5 /* HDMI 2.0 */
+
+
+/* Deck Control Feature */
+#define CEC_MSG_DECK_CONTROL 0x42
+/* Deck Control Mode Operand (deck_control_mode) */
+#define CEC_OP_DECK_CTL_MODE_SKIP_FWD 1
+#define CEC_OP_DECK_CTL_MODE_SKIP_REV 2
+#define CEC_OP_DECK_CTL_MODE_STOP 3
+#define CEC_OP_DECK_CTL_MODE_EJECT 4
+
+#define CEC_MSG_DECK_STATUS 0x1b
+/* Deck Info Operand (deck_info) */
+#define CEC_OP_DECK_INFO_PLAY 0x11
+#define CEC_OP_DECK_INFO_RECORD 0x12
+#define CEC_OP_DECK_INFO_PLAY_REV 0x13
+#define CEC_OP_DECK_INFO_STILL 0x14
+#define CEC_OP_DECK_INFO_SLOW 0x15
+#define CEC_OP_DECK_INFO_SLOW_REV 0x16
+#define CEC_OP_DECK_INFO_FAST_FWD 0x17
+#define CEC_OP_DECK_INFO_FAST_REV 0x18
+#define CEC_OP_DECK_INFO_NO_MEDIA 0x19
+#define CEC_OP_DECK_INFO_STOP 0x1a
+#define CEC_OP_DECK_INFO_SKIP_FWD 0x1b
+#define CEC_OP_DECK_INFO_SKIP_REV 0x1c
+#define CEC_OP_DECK_INFO_INDEX_SEARCH_FWD 0x1d
+#define CEC_OP_DECK_INFO_INDEX_SEARCH_REV 0x1e
+#define CEC_OP_DECK_INFO_OTHER 0x1f
+
+#define CEC_MSG_GIVE_DECK_STATUS 0x1a
+/* Status Request Operand (status_req) */
+#define CEC_OP_STATUS_REQ_ON 1
+#define CEC_OP_STATUS_REQ_OFF 2
+#define CEC_OP_STATUS_REQ_ONCE 3
+
+#define CEC_MSG_PLAY 0x41
+/* Play Mode Operand (play_mode) */
+#define CEC_OP_PLAY_MODE_PLAY_FWD 0x24
+#define CEC_OP_PLAY_MODE_PLAY_REV 0x20
+#define CEC_OP_PLAY_MODE_PLAY_STILL 0x25
+#define CEC_OP_PLAY_MODE_PLAY_FAST_FWD_MIN 0x05
+#define CEC_OP_PLAY_MODE_PLAY_FAST_FWD_MED 0x06
+#define CEC_OP_PLAY_MODE_PLAY_FAST_FWD_MAX 0x07
+#define CEC_OP_PLAY_MODE_PLAY_FAST_REV_MIN 0x09
+#define CEC_OP_PLAY_MODE_PLAY_FAST_REV_MED 0x0a
+#define CEC_OP_PLAY_MODE_PLAY_FAST_REV_MAX 0x0b
+#define CEC_OP_PLAY_MODE_PLAY_SLOW_FWD_MIN 0x15
+#define CEC_OP_PLAY_MODE_PLAY_SLOW_FWD_MED 0x16
+#define CEC_OP_PLAY_MODE_PLAY_SLOW_FWD_MAX 0x17
+#define CEC_OP_PLAY_MODE_PLAY_SLOW_REV_MIN 0x19
+#define CEC_OP_PLAY_MODE_PLAY_SLOW_REV_MED 0x1a
+#define CEC_OP_PLAY_MODE_PLAY_SLOW_REV_MAX 0x1b
+
+
+/* Tuner Control Feature */
+#define CEC_MSG_GIVE_TUNER_DEVICE_STATUS 0x08
+#define CEC_MSG_SELECT_ANALOGUE_SERVICE 0x92
+#define CEC_MSG_SELECT_DIGITAL_SERVICE 0x93
+#define CEC_MSG_TUNER_DEVICE_STATUS 0x07
+/* Recording Flag Operand (rec_flag) */
+#define CEC_OP_REC_FLAG_USED 0
+#define CEC_OP_REC_FLAG_NOT_USED 1
+/* Tuner Display Info Operand (tuner_display_info) */
+#define CEC_OP_TUNER_DISPLAY_INFO_DIGITAL 0
+#define CEC_OP_TUNER_DISPLAY_INFO_NONE 1
+#define CEC_OP_TUNER_DISPLAY_INFO_ANALOGUE 2
+
+#define CEC_MSG_TUNER_STEP_DECREMENT 0x06
+#define CEC_MSG_TUNER_STEP_INCREMENT 0x05
+
+
+/* Vendor Specific Commands Feature */
+
+/*
+ * Has also:
+ * CEC_MSG_CEC_VERSION
+ * CEC_MSG_GET_CEC_VERSION
+ */
+#define CEC_MSG_DEVICE_VENDOR_ID 0x87
+#define CEC_MSG_GIVE_DEVICE_VENDOR_ID 0x8c
+#define CEC_MSG_VENDOR_COMMAND 0x89
+#define CEC_MSG_VENDOR_COMMAND_WITH_ID 0xa0
+#define CEC_MSG_VENDOR_REMOTE_BUTTON_DOWN 0x8a
+#define CEC_MSG_VENDOR_REMOTE_BUTTON_UP 0x8b
+
+
+/* OSD Display Feature */
+#define CEC_MSG_SET_OSD_STRING 0x64
+/* Display Control Operand (disp_ctl) */
+#define CEC_OP_DISP_CTL_DEFAULT 0x00
+#define CEC_OP_DISP_CTL_UNTIL_CLEARED 0x40
+#define CEC_OP_DISP_CTL_CLEAR 0x80
+
+
+/* Device OSD Transfer Feature */
+#define CEC_MSG_GIVE_OSD_NAME 0x46
+#define CEC_MSG_SET_OSD_NAME 0x47
+
+
+/* Device Menu Control Feature */
+#define CEC_MSG_MENU_REQUEST 0x8d
+/* Menu Request Type Operand (menu_req) */
+#define CEC_OP_MENU_REQUEST_ACTIVATE 0x00
+#define CEC_OP_MENU_REQUEST_DEACTIVATE 0x01
+#define CEC_OP_MENU_REQUEST_QUERY 0x02
+
+#define CEC_MSG_MENU_STATUS 0x8e
+/* Menu State Operand (menu_state) */
+#define CEC_OP_MENU_STATE_ACTIVATED 0x00
+#define CEC_OP_MENU_STATE_DEACTIVATED 0x01
+
+#define CEC_MSG_USER_CONTROL_PRESSED 0x44
+/* UI Broadcast Type Operand (ui_bcast_type) */
+#define CEC_OP_UI_BCAST_TYPE_TOGGLE_ALL 0x00
+#define CEC_OP_UI_BCAST_TYPE_TOGGLE_DIG_ANA 0x01
+#define CEC_OP_UI_BCAST_TYPE_ANALOGUE 0x10
+#define CEC_OP_UI_BCAST_TYPE_ANALOGUE_T 0x20
+#define CEC_OP_UI_BCAST_TYPE_ANALOGUE_CABLE 0x30
+#define CEC_OP_UI_BCAST_TYPE_ANALOGUE_SAT 0x40
+#define CEC_OP_UI_BCAST_TYPE_DIGITAL 0x50
+#define CEC_OP_UI_BCAST_TYPE_DIGITAL_T 0x60
+#define CEC_OP_UI_BCAST_TYPE_DIGITAL_CABLE 0x70
+#define CEC_OP_UI_BCAST_TYPE_DIGITAL_SAT 0x80
+#define CEC_OP_UI_BCAST_TYPE_DIGITAL_COM_SAT 0x90
+#define CEC_OP_UI_BCAST_TYPE_DIGITAL_COM_SAT2 0x91
+#define CEC_OP_UI_BCAST_TYPE_IP 0xa0
+/* UI Sound Presentation Control Operand (ui_snd_pres_ctl) */
+#define CEC_OP_UI_SND_PRES_CTL_DUAL_MONO 0x10
+#define CEC_OP_UI_SND_PRES_CTL_KARAOKE 0x20
+#define CEC_OP_UI_SND_PRES_CTL_DOWNMIX 0x80
+#define CEC_OP_UI_SND_PRES_CTL_REVERB 0x90
+#define CEC_OP_UI_SND_PRES_CTL_EQUALIZER 0xa0
+#define CEC_OP_UI_SND_PRES_CTL_BASS_UP 0xb1
+#define CEC_OP_UI_SND_PRES_CTL_BASS_NEUTRAL 0xb2
+#define CEC_OP_UI_SND_PRES_CTL_BASS_DOWN 0xb3
+#define CEC_OP_UI_SND_PRES_CTL_TREBLE_UP 0xc1
+#define CEC_OP_UI_SND_PRES_CTL_TREBLE_NEUTRAL 0xc2
+#define CEC_OP_UI_SND_PRES_CTL_TREBLE_DOWN 0xc3
+
+#define CEC_MSG_USER_CONTROL_RELEASED 0x45
+
+
+/* Remote Control Passthrough Feature */
+
+/*
+ * Has also:
+ * CEC_MSG_USER_CONTROL_PRESSED
+ * CEC_MSG_USER_CONTROL_RELEASED
+ */
+
+
+/* Power Status Feature */
+#define CEC_MSG_GIVE_DEVICE_POWER_STATUS 0x8f
+#define CEC_MSG_REPORT_POWER_STATUS 0x90
+/* Power Status Operand (pwr_state) */
+#define CEC_OP_POWER_STATUS_ON 0
+#define CEC_OP_POWER_STATUS_STANDBY 1
+#define CEC_OP_POWER_STATUS_TO_ON 2
+#define CEC_OP_POWER_STATUS_TO_STANDBY 3
+
+
+/* General Protocol Messages */
+#define CEC_MSG_FEATURE_ABORT 0x00
+/* Abort Reason Operand (reason) */
+#define CEC_OP_ABORT_UNRECOGNIZED_OP 0
+#define CEC_OP_ABORT_INCORRECT_MODE 1
+#define CEC_OP_ABORT_NO_SOURCE 2
+#define CEC_OP_ABORT_INVALID_OP 3
+#define CEC_OP_ABORT_REFUSED 4
+#define CEC_OP_ABORT_UNDETERMINED 5
+
+#define CEC_MSG_ABORT 0xff
+
+
+/* System Audio Control Feature */
+
+/*
+ * Has also:
+ * CEC_MSG_USER_CONTROL_PRESSED
+ * CEC_MSG_USER_CONTROL_RELEASED
+ */
+#define CEC_MSG_GIVE_AUDIO_STATUS 0x71
+#define CEC_MSG_GIVE_SYSTEM_AUDIO_MODE_STATUS 0x7d
+#define CEC_MSG_REPORT_AUDIO_STATUS 0x7a
+/* Audio Mute Status Operand (aud_mute_status) */
+#define CEC_OP_AUD_MUTE_STATUS_OFF 0
+#define CEC_OP_AUD_MUTE_STATUS_ON 1
+
+#define CEC_MSG_REPORT_SHORT_AUDIO_DESCRIPTOR 0xa3
+#define CEC_MSG_REQUEST_SHORT_AUDIO_DESCRIPTOR 0xa4
+#define CEC_MSG_SET_SYSTEM_AUDIO_MODE 0x72
+/* System Audio Status Operand (sys_aud_status) */
+#define CEC_OP_SYS_AUD_STATUS_OFF 0
+#define CEC_OP_SYS_AUD_STATUS_ON 1
+
+#define CEC_MSG_SYSTEM_AUDIO_MODE_REQUEST 0x70
+#define CEC_MSG_SYSTEM_AUDIO_MODE_STATUS 0x7e
+/* Audio Format ID Operand (audio_format_id) */
+#define CEC_OP_AUD_FMT_ID_CEA861 0
+#define CEC_OP_AUD_FMT_ID_CEA861_CXT 1
+
+
+/* Audio Rate Control Feature */
+#define CEC_MSG_SET_AUDIO_RATE 0x9a
+/* Audio Rate Operand (audio_rate) */
+#define CEC_OP_AUD_RATE_OFF 0
+#define CEC_OP_AUD_RATE_WIDE_STD 1
+#define CEC_OP_AUD_RATE_WIDE_FAST 2
+#define CEC_OP_AUD_RATE_WIDE_SLOW 3
+#define CEC_OP_AUD_RATE_NARROW_STD 4
+#define CEC_OP_AUD_RATE_NARROW_FAST 5
+#define CEC_OP_AUD_RATE_NARROW_SLOW 6
+
+
+/* Audio Return Channel Control Feature */
+#define CEC_MSG_INITIATE_ARC 0xc0
+#define CEC_MSG_REPORT_ARC_INITIATED 0xc1
+#define CEC_MSG_REPORT_ARC_TERMINATED 0xc2
+#define CEC_MSG_REQUEST_ARC_INITIATION 0xc3
+#define CEC_MSG_REQUEST_ARC_TERMINATION 0xc4
+#define CEC_MSG_TERMINATE_ARC 0xc5
+
+
+/* Dynamic Audio Lipsync Feature */
+/* Only for CEC 2.0 and up */
+#define CEC_MSG_REQUEST_CURRENT_LATENCY 0xa7
+#define CEC_MSG_REPORT_CURRENT_LATENCY 0xa8
+/* Low Latency Mode Operand (low_latency_mode) */
+#define CEC_OP_LOW_LATENCY_MODE_OFF 0
+#define CEC_OP_LOW_LATENCY_MODE_ON 1
+/* Audio Output Compensated Operand (audio_out_compensated) */
+#define CEC_OP_AUD_OUT_COMPENSATED_NA 0
+#define CEC_OP_AUD_OUT_COMPENSATED_DELAY 1
+#define CEC_OP_AUD_OUT_COMPENSATED_NO_DELAY 2
+#define CEC_OP_AUD_OUT_COMPENSATED_PARTIAL_DELAY 3
+
+
+/* Capability Discovery and Control Feature */
+#define CEC_MSG_CDC_MESSAGE 0xf8
+/* Ethernet-over-HDMI: nobody ever does this... */
+#define CEC_MSG_CDC_HEC_INQUIRE_STATE 0x00
+#define CEC_MSG_CDC_HEC_REPORT_STATE 0x01
+/* HEC Functionality State Operand (hec_func_state) */
+#define CEC_OP_HEC_FUNC_STATE_NOT_SUPPORTED 0
+#define CEC_OP_HEC_FUNC_STATE_INACTIVE 1
+#define CEC_OP_HEC_FUNC_STATE_ACTIVE 2
+#define CEC_OP_HEC_FUNC_STATE_ACTIVATION_FIELD 3
+/* Host Functionality State Operand (host_func_state) */
+#define CEC_OP_HOST_FUNC_STATE_NOT_SUPPORTED 0
+#define CEC_OP_HOST_FUNC_STATE_INACTIVE 1
+#define CEC_OP_HOST_FUNC_STATE_ACTIVE 2
+/* ENC Functionality State Operand (enc_func_state) */
+#define CEC_OP_ENC_FUNC_STATE_EXT_CON_NOT_SUPPORTED 0
+#define CEC_OP_ENC_FUNC_STATE_EXT_CON_INACTIVE 1
+#define CEC_OP_ENC_FUNC_STATE_EXT_CON_ACTIVE 2
+/* CDC Error Code Operand (cdc_errcode) */
+#define CEC_OP_CDC_ERROR_CODE_NONE 0
+#define CEC_OP_CDC_ERROR_CODE_CAP_UNSUPPORTED 1
+#define CEC_OP_CDC_ERROR_CODE_WRONG_STATE 2
+#define CEC_OP_CDC_ERROR_CODE_OTHER 3
+/* HEC Support Operand (hec_support) */
+#define CEC_OP_HEC_SUPPORT_NO 0
+#define CEC_OP_HEC_SUPPORT_YES 1
+/* HEC Activation Operand (hec_activation) */
+#define CEC_OP_HEC_ACTIVATION_ON 0
+#define CEC_OP_HEC_ACTIVATION_OFF 1
+
+#define CEC_MSG_CDC_HEC_SET_STATE_ADJACENT 0x02
+#define CEC_MSG_CDC_HEC_SET_STATE 0x03
+/* HEC Set State Operand (hec_set_state) */
+#define CEC_OP_HEC_SET_STATE_DEACTIVATE 0
+#define CEC_OP_HEC_SET_STATE_ACTIVATE 1
+
+#define CEC_MSG_CDC_HEC_REQUEST_DEACTIVATION 0x04
+#define CEC_MSG_CDC_HEC_NOTIFY_ALIVE 0x05
+#define CEC_MSG_CDC_HEC_DISCOVER 0x06
+/* Hotplug Detect messages */
+#define CEC_MSG_CDC_HPD_SET_STATE 0x10
+/* HPD State Operand (hpd_state) */
+#define CEC_OP_HPD_STATE_CP_EDID_DISABLE 0
+#define CEC_OP_HPD_STATE_CP_EDID_ENABLE 1
+#define CEC_OP_HPD_STATE_CP_EDID_DISABLE_ENABLE 2
+#define CEC_OP_HPD_STATE_EDID_DISABLE 3
+#define CEC_OP_HPD_STATE_EDID_ENABLE 4
+#define CEC_OP_HPD_STATE_EDID_DISABLE_ENABLE 5
+#define CEC_MSG_CDC_HPD_REPORT_STATE 0x11
+/* HPD Error Code Operand (hpd_error) */
+#define CEC_OP_HPD_ERROR_NONE 0
+#define CEC_OP_HPD_ERROR_INITIATOR_NOT_CAPABLE 1
+#define CEC_OP_HPD_ERROR_INITIATOR_WRONG_STATE 2
+#define CEC_OP_HPD_ERROR_OTHER 3
+#define CEC_OP_HPD_ERROR_NONE_NO_VIDEO 4
+
+#endif
diff --git a/include/linux/v4l2-controls.h b/include/linux/v4l2-controls.h
index 9f6e108..d448c53 100644
--- a/include/linux/v4l2-controls.h
+++ b/include/linux/v4l2-controls.h
@@ -174,6 +174,10 @@ enum v4l2_colorfx {
* We reserve 16 controls for this driver. */
#define V4L2_CID_USER_ADV7180_BASE (V4L2_CID_USER_BASE + 0x1070)
+/* The base for the tc358743 driver controls.
+ * We reserve 16 controls for this driver. */
+#define V4L2_CID_USER_TC358743_BASE (V4L2_CID_USER_BASE + 0x1080)
+
/* MPEG-class control IDs */
/* The MPEG controls are applicable to all codec controls
* and the 'MPEG' part of the define is historical */
diff --git a/utils/keytable/parse.h b/utils/keytable/parse.h
index 6ada6e5..67eb1a6 100644
--- a/utils/keytable/parse.h
+++ b/utils/keytable/parse.h
@@ -518,6 +518,24 @@ struct parse_event key_events[] = {
{"KEY_KBDINPUTASSIST_NEXTGROUP", 0x263},
{"KEY_KBDINPUTASSIST_ACCEPT", 0x264},
{"KEY_KBDINPUTASSIST_CANCEL", 0x265},
+ {"KEY_RIGHT_UP", 0x266},
+ {"KEY_RIGHT_DOWN", 0x267},
+ {"KEY_LEFT_UP", 0x268},
+ {"KEY_LEFT_DOWN", 0x269},
+ {"KEY_ROOT_MENU", 0x26a},
+ {"KEY_MEDIA_TOP_MENU", 0x26b},
+ {"KEY_NUMERIC_11", 0x26c},
+ {"KEY_NUMERIC_12", 0x26d},
+ {"KEY_AUDIO_DESC", 0x26e},
+ {"KEY_3D_MODE", 0x26f},
+ {"KEY_NEXT_FAVORITE", 0x270},
+ {"KEY_STOP_RECORD", 0x271},
+ {"KEY_PAUSE_RECORD", 0x272},
+ {"KEY_VOD", 0x273},
+ {"KEY_UNMUTE", 0x274},
+ {"KEY_FASTREVERSE", 0x275},
+ {"KEY_SLOWREVERSE", 0x276},
+ {"KEY_DATA", 0x275},
{"BTN_TRIGGER_HAPPY", 0x2c0},
{"BTN_TRIGGER_HAPPY1", 0x2c0},
{"BTN_TRIGGER_HAPPY2", 0x2c1},
diff --git a/utils/keytable/rc_keymaps/lme2510 b/utils/keytable/rc_keymaps/lme2510
index 6d7b18e..1da95f8 100644
--- a/utils/keytable/rc_keymaps/lme2510
+++ b/utils/keytable/rc_keymaps/lme2510
@@ -1,67 +1,67 @@
# table lme2510, type: NEC
-0x10ed45 KEY_0
-0x10ed5f KEY_1
-0x10ed50 KEY_2
-0x10ed5d KEY_3
-0x10ed41 KEY_4
-0x10ed0a KEY_5
-0x10ed42 KEY_6
-0x10ed47 KEY_7
-0x10ed49 KEY_8
-0x10ed05 KEY_9
-0x10ed43 KEY_POWER
-0x10ed46 KEY_SUBTITLE
-0x10ed06 KEY_PAUSE
-0x10ed03 KEY_MEDIA_REPEAT
-0x10ed02 KEY_PAUSE
-0x10ed5e KEY_VOLUMEUP
-0x10ed5c KEY_VOLUMEDOWN
-0x10ed09 KEY_CHANNELUP
-0x10ed1a KEY_CHANNELDOWN
-0x10ed1e KEY_PLAY
-0x10ed1b KEY_ZOOM
-0x10ed59 KEY_MUTE
-0x10ed5a KEY_TV
-0x10ed18 KEY_RECORD
-0x10ed07 KEY_EPG
-0x10ed01 KEY_STOP
-0xbf15 KEY_0
-0xbf08 KEY_1
-0xbf09 KEY_2
-0xbf0a KEY_3
-0xbf0c KEY_4
-0xbf0d KEY_5
-0xbf0e KEY_6
-0xbf10 KEY_7
-0xbf11 KEY_8
-0xbf12 KEY_9
-0xbf00 KEY_POWER
-0xbf04 KEY_MEDIA_REPEAT
-0xbf1a KEY_PAUSE
-0xbf02 KEY_VOLUMEUP
-0xbf06 KEY_VOLUMEDOWN
-0xbf01 KEY_CHANNELUP
-0xbf05 KEY_CHANNELDOWN
-0xbf14 KEY_ZOOM
-0xbf18 KEY_RECORD
-0xbf16 KEY_STOP
-0x1c KEY_0
-0x07 KEY_1
-0x15 KEY_2
-0x09 KEY_3
-0x16 KEY_4
-0x19 KEY_5
-0x0d KEY_6
-0x0c KEY_7
-0x18 KEY_8
-0x5e KEY_9
-0x45 KEY_POWER
-0x44 KEY_MEDIA_REPEAT
-0x4a KEY_PAUSE
-0x47 KEY_VOLUMEUP
-0x43 KEY_VOLUMEDOWN
-0x46 KEY_CHANNELUP
-0x40 KEY_CHANNELDOWN
-0x08 KEY_ZOOM
-0x42 KEY_RECORD
-0x5a KEY_STOP
+0xef12ba45 KEY_0
+0xef12a05f KEY_1
+0xef12af50 KEY_2
+0xef12a25d KEY_3
+0xef12be41 KEY_4
+0xef12f50a KEY_5
+0xef12bd42 KEY_6
+0xef12b847 KEY_7
+0xef12b649 KEY_8
+0xef12fa05 KEY_9
+0xef12bc43 KEY_POWER
+0xef12b946 KEY_SUBTITLE
+0xef12f906 KEY_PAUSE
+0xef12fc03 KEY_MEDIA_REPEAT
+0xef12fd02 KEY_PAUSE
+0xef12a15e KEY_VOLUMEUP
+0xef12a35c KEY_VOLUMEDOWN
+0xef12f609 KEY_CHANNELUP
+0xef12e51a KEY_CHANNELDOWN
+0xef12e11e KEY_PLAY
+0xef12e41b KEY_ZOOM
+0xef12a659 KEY_MUTE
+0xef12a55a KEY_TV
+0xef12e718 KEY_RECORD
+0xef12f807 KEY_EPG
+0xef12fe01 KEY_STOP
+0xff40ea15 KEY_0
+0xff40f708 KEY_1
+0xff40f609 KEY_2
+0xff40f50a KEY_3
+0xff40f30c KEY_4
+0xff40f20d KEY_5
+0xff40f10e KEY_6
+0xff40ef10 KEY_7
+0xff40ee11 KEY_8
+0xff40ed12 KEY_9
+0xff40ff00 KEY_POWER
+0xff40fb04 KEY_MEDIA_REPEAT
+0xff40e51a KEY_PAUSE
+0xff40fd02 KEY_VOLUMEUP
+0xff40f906 KEY_VOLUMEDOWN
+0xff40fe01 KEY_CHANNELUP
+0xff40fa05 KEY_CHANNELDOWN
+0xff40eb14 KEY_ZOOM
+0xff40e718 KEY_RECORD
+0xff40e916 KEY_STOP
+0xff00e31c KEY_0
+0xff00f807 KEY_1
+0xff00ea15 KEY_2
+0xff00f609 KEY_3
+0xff00e916 KEY_4
+0xff00e619 KEY_5
+0xff00f20d KEY_6
+0xff00f30c KEY_7
+0xff00e718 KEY_8
+0xff00a15e KEY_9
+0xff00ba45 KEY_POWER
+0xff00bb44 KEY_MEDIA_REPEAT
+0xff00b54a KEY_PAUSE
+0xff00b847 KEY_VOLUMEUP
+0xff00bc43 KEY_VOLUMEDOWN
+0xff00b946 KEY_CHANNELUP
+0xff00bf40 KEY_CHANNELDOWN
+0xff00f708 KEY_ZOOM
+0xff00bd42 KEY_RECORD
+0xff00a55a KEY_STOP
diff --git a/utils/keytable/rc_maps.cfg b/utils/keytable/rc_maps.cfg
index e69fd6a..3bd7197 100644
--- a/utils/keytable/rc_maps.cfg
+++ b/utils/keytable/rc_maps.cfg
@@ -50,6 +50,7 @@
* rc-behold-columbus behold_columbus
* rc-behold behold
* rc-budget-ci-old budget_ci_old
+* rc-cec cec
* rc-cinergy-1400 cinergy_1400
* rc-cinergy cinergy
* rc-delock-61959 delock_61959
--
2.1.4
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCHv2 3/4] cec-compliance: add new CEC compliance utility
2015-08-18 8:36 [PATCHv2 0/4] cec-ctl/compliance: new CEC utilities Hans Verkuil
2015-08-18 8:36 ` [PATCHv2 1/4] Makefile.am: copy cec headers with make sync-with-kernel Hans Verkuil
2015-08-18 8:36 ` [PATCHv2 2/4] sync-with-kernel Hans Verkuil
@ 2015-08-18 8:36 ` Hans Verkuil
2015-08-18 8:36 ` [PATCHv2 4/4] cec-ctl: CEC control utility Hans Verkuil
2015-08-18 8:46 ` Hans Verkuil
4 siblings, 0 replies; 7+ messages in thread
From: Hans Verkuil @ 2015-08-18 8:36 UTC (permalink / raw)
To: linux-media
Cc: dri-devel, m.szyprowski, linux-input, linux-samsung-soc, lars,
kamil, linux, Hans Verkuil
This utility will attempt to test whether the CEC protocol was
implemented correctly.
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
---
configure.ac | 1 +
utils/Makefile.am | 1 +
utils/cec-compliance/Makefile.am | 3 +
utils/cec-compliance/cec-compliance.cpp | 926 ++++++++++++++++++++++++++++++++
utils/cec-compliance/cec-compliance.h | 87 +++
5 files changed, 1018 insertions(+)
create mode 100644 utils/cec-compliance/Makefile.am
create mode 100644 utils/cec-compliance/cec-compliance.cpp
create mode 100644 utils/cec-compliance/cec-compliance.h
diff --git a/configure.ac b/configure.ac
index d4e312c..12c2eb9 100644
--- a/configure.ac
+++ b/configure.ac
@@ -26,6 +26,7 @@ AC_CONFIG_FILES([Makefile
utils/keytable/Makefile
utils/media-ctl/Makefile
utils/rds/Makefile
+ utils/cec-compliance/Makefile
utils/v4l2-compliance/Makefile
utils/v4l2-ctl/Makefile
utils/v4l2-dbg/Makefile
diff --git a/utils/Makefile.am b/utils/Makefile.am
index 31b2979..c78e97b 100644
--- a/utils/Makefile.am
+++ b/utils/Makefile.am
@@ -5,6 +5,7 @@ SUBDIRS = \
decode_tm6000 \
keytable \
media-ctl \
+ cec-compliance \
v4l2-compliance \
v4l2-ctl \
v4l2-dbg \
diff --git a/utils/cec-compliance/Makefile.am b/utils/cec-compliance/Makefile.am
new file mode 100644
index 0000000..da4c0ef
--- /dev/null
+++ b/utils/cec-compliance/Makefile.am
@@ -0,0 +1,3 @@
+bin_PROGRAMS = cec-compliance
+
+cec_compliance_SOURCES = cec-compliance.cpp
diff --git a/utils/cec-compliance/cec-compliance.cpp b/utils/cec-compliance/cec-compliance.cpp
new file mode 100644
index 0000000..59db8ab
--- /dev/null
+++ b/utils/cec-compliance/cec-compliance.cpp
@@ -0,0 +1,926 @@
+/*
+ Copyright 2015 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ Author: Hans Verkuil <hans.verkuil@cisco.com>
+
+ 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 program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+#include <getopt.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <config.h>
+
+#include "cec-compliance.h"
+
+/* Short option list
+
+ Please keep in alphabetical order.
+ That makes it easier to see which short options are still free.
+
+ In general the lower case is used to set something and the upper
+ case is used to retrieve a setting. */
+enum Option {
+ OptPhysAddr = 'a',
+ OptSetDevice = 'd',
+ OptHelp = 'h',
+ OptNoWarnings = 'n',
+ OptTrace = 'T',
+ OptVerbose = 'v',
+ OptVendorID = 'V',
+
+ OptTV,
+ OptRecord,
+ OptTuner,
+ OptPlayback,
+ OptAudio,
+ OptProcessor,
+ OptSwitch,
+ OptCDCOnly,
+ OptUnregistered,
+ OptLast = 256
+};
+
+static char options[OptLast];
+
+static int app_result;
+static int tests_total, tests_ok;
+
+bool show_info;
+bool show_warnings = true;
+unsigned warnings;
+
+static struct option long_options[] = {
+ {"device", required_argument, 0, OptSetDevice},
+ {"help", no_argument, 0, OptHelp},
+ {"no-warnings", no_argument, 0, OptNoWarnings},
+ {"trace", no_argument, 0, OptTrace},
+ {"verbose", no_argument, 0, OptVerbose},
+ {"phys-addr", required_argument, 0, OptPhysAddr},
+ {"vendor-id", required_argument, 0, OptVendorID},
+
+ {"tv", no_argument, 0, OptTV},
+ {"record", no_argument, 0, OptRecord},
+ {"tuner", no_argument, 0, OptTuner},
+ {"playback", no_argument, 0, OptPlayback},
+ {"audio", no_argument, 0, OptAudio},
+ {"processor", no_argument, 0, OptProcessor},
+ {"switch", no_argument, 0, OptSwitch},
+ {"cdc-only", no_argument, 0, OptCDCOnly},
+ {"unregistered", no_argument, 0, OptUnregistered},
+ {0, 0, 0, 0}
+};
+
+static void usage(void)
+{
+ printf("Usage:\n"
+ " -d, --device=<dev> Use device <dev> instead of /dev/cec0\n"
+ " If <dev> starts with a digit, then /dev/cec<dev> is used.\n"
+ " -h, --help Display this help message\n"
+ " -n, --no-warnings Turn off warning messages.\n"
+ " -T, --trace Trace all called ioctls.\n"
+ " -v, --verbose Turn on verbose reporting.\n"
+ " -a, --phys-addr=<addr>\n"
+ " Use this physical address.\n"
+ " -V, --vendor-id=<id>\n"
+ " Use this vendor ID.\n"
+ " --tv This is a TV\n"
+ " --record This is a recording device\n"
+ " --tuner This is a tuner device\n"
+ " --playback This is a playback device\n"
+ " --audio This is an audio system device\n"
+ " --processor This is a processor device\n"
+ " --switch This is a pure CEC switch\n"
+ " --cdc-only This is a CDC-only device\n"
+ " --unregistered This is an unregistered device\n"
+ );
+}
+
+static std::string caps2s(unsigned caps)
+{
+ std::string s;
+
+ if (caps & CEC_CAP_STATE)
+ s += "\t\tState\n";
+ if (caps & CEC_CAP_PHYS_ADDR)
+ s += "\t\tPhysical Address\n";
+ if (caps & CEC_CAP_LOG_ADDRS)
+ s += "\t\tLogical Addresses\n";
+ if (caps & CEC_CAP_IO)
+ s += "\t\tI/O\n";
+ if (caps & CEC_CAP_VENDOR_ID)
+ s += "\t\tVendor ID\n";
+ if (caps & CEC_CAP_PASSTHROUGH)
+ s += "\t\tPassthrough\n";
+ if (caps & CEC_CAP_RC)
+ s += "\t\tRemote Control Support\n";
+ if (caps & CEC_CAP_ARC)
+ s += "\t\tAudio Return Channel\n";
+ if (caps & CEC_CAP_CDC_HPD)
+ s += "\t\tCapability Discovery and Control HPD\n";
+ if (caps & CEC_CAP_IS_SOURCE)
+ s += "\t\tIs Source\n";
+ return s;
+}
+
+static const char *version2s(unsigned version)
+{
+ switch (version) {
+ case CEC_OP_CEC_VERSION_1_3A:
+ return "1.3a";
+ case CEC_OP_CEC_VERSION_1_4:
+ return "1.4";
+ case CEC_OP_CEC_VERSION_2_0:
+ return "2.0";
+ default:
+ return "Unknown";
+ }
+}
+
+static const char *power_status2s(unsigned status)
+{
+ switch (status) {
+ case CEC_OP_POWER_STATUS_ON:
+ return "On";
+ case CEC_OP_POWER_STATUS_STANDBY:
+ return "Standby";
+ case CEC_OP_POWER_STATUS_TO_ON:
+ return "In Transition Standby to On";
+ case CEC_OP_POWER_STATUS_TO_STANDBY:
+ return "In Transition On to Standby";
+ default:
+ return "Unknown";
+ }
+}
+
+static const char *prim_type2s(unsigned type)
+{
+ switch (type) {
+ case CEC_OP_PRIM_DEVTYPE_TV:
+ return "TV";
+ case CEC_OP_PRIM_DEVTYPE_RECORD:
+ return "Record";
+ case CEC_OP_PRIM_DEVTYPE_TUNER:
+ return "Tuner";
+ case CEC_OP_PRIM_DEVTYPE_PLAYBACK:
+ return "Playback";
+ case CEC_OP_PRIM_DEVTYPE_AUDIOSYSTEM:
+ return "Audio System";
+ case CEC_OP_PRIM_DEVTYPE_SWITCH:
+ return "Switch";
+ case CEC_OP_PRIM_DEVTYPE_PROCESSOR:
+ return "Processor";
+ default:
+ return "Unknown";
+ }
+}
+
+static const char *la_type2s(unsigned type)
+{
+ switch (type) {
+ case CEC_LOG_ADDR_TYPE_TV:
+ return "TV";
+ case CEC_LOG_ADDR_TYPE_RECORD:
+ return "Record";
+ case CEC_LOG_ADDR_TYPE_TUNER:
+ return "Tuner";
+ case CEC_LOG_ADDR_TYPE_PLAYBACK:
+ return "Playback";
+ case CEC_LOG_ADDR_TYPE_AUDIOSYSTEM:
+ return "Audio System";
+ case CEC_LOG_ADDR_TYPE_SPECIFIC:
+ return "Specific";
+ case CEC_LOG_ADDR_TYPE_UNREGISTERED:
+ return "Unregistered";
+ default:
+ return "Unknown";
+ }
+}
+
+static const char *la2s(unsigned la)
+{
+ switch (la & 0xf) {
+ case 0:
+ return "TV";
+ case 1:
+ return "Recording Device 1";
+ case 2:
+ return "Recording Device 2";
+ case 3:
+ return "Tuner 1";
+ case 4:
+ return "Playback Device 1";
+ case 5:
+ return "Audio System";
+ case 6:
+ return "Tuner 2";
+ case 7:
+ return "Tuner 3";
+ case 8:
+ return "Playback Device 2";
+ case 9:
+ return "Playback Device 3";
+ case 10:
+ return "Tuner 4";
+ case 11:
+ return "Playback Device 3";
+ case 12:
+ return "Reserved 1";
+ case 13:
+ return "Reserved 2";
+ case 14:
+ return "Specific";
+ case 15:
+ default:
+ return "Unregistered";
+ }
+}
+
+static std::string status2s(unsigned stat)
+{
+ std::string s;
+
+ if (stat & CEC_TX_STATUS_ARB_LOST)
+ s += "ArbitrationLost ";
+ if (stat & CEC_TX_STATUS_REPLY_TIMEOUT)
+ s += "ReplyTimeout ";
+ if (stat & CEC_TX_STATUS_RETRY_TIMEOUT)
+ s += "RetryTimeout ";
+ if (stat & CEC_TX_STATUS_FEATURE_ABORT)
+ s += "FeatureAbort ";
+ return s;
+}
+
+static std::string all_dev_types2s(unsigned types)
+{
+ std::string s;
+
+ if (types & CEC_OP_ALL_DEVTYPE_TV)
+ s += "TV, ";
+ if (types & CEC_OP_ALL_DEVTYPE_RECORD)
+ s += "Record, ";
+ if (types & CEC_OP_ALL_DEVTYPE_TUNER)
+ s += "Tuner, ";
+ if (types & CEC_OP_ALL_DEVTYPE_PLAYBACK)
+ s += "Playback, ";
+ if (types & CEC_OP_ALL_DEVTYPE_AUDIOSYSTEM)
+ s += "Audio System, ";
+ if (types & CEC_OP_ALL_DEVTYPE_SWITCH)
+ s += "Switch, ";
+ return s.erase(s.length() - 2, 2);
+}
+
+static std::string rc_src_prof2s(unsigned prof)
+{
+ std::string s;
+
+ prof &= 0x1f;
+ if (prof == 0)
+ return "\t\tNone\n";
+ if (prof & CEC_OP_FEAT_RC_SRC_HAS_DEV_ROOT_MENU)
+ s += "\t\tSource Has Device Root Menu\n";
+ if (prof & CEC_OP_FEAT_RC_SRC_HAS_DEV_SETUP_MENU)
+ s += "\t\tSource Has Device Setup Menu\n";
+ if (prof & CEC_OP_FEAT_RC_SRC_HAS_MEDIA_CONTEXT_MENU)
+ s += "\t\tSource Has Contents Menu\n";
+ if (prof & CEC_OP_FEAT_RC_SRC_HAS_MEDIA_TOP_MENU)
+ s += "\t\tSource Has Media Top Menu\n";
+ if (prof & CEC_OP_FEAT_RC_SRC_HAS_MEDIA_CONTEXT_MENU)
+ s += "\t\tSource Has Media Context-Sensitive Menu\n";
+ return s;
+}
+
+static std::string dev_feat2s(unsigned feat)
+{
+ std::string s;
+
+ feat &= 0x3e;
+ if (feat == 0)
+ return "\t\tNone\n";
+ if (feat & CEC_OP_FEAT_DEV_HAS_RECORD_TV_SCREEN)
+ s += "\t\tTV Supports <Record TV Screen>\n";
+ if (feat & CEC_OP_FEAT_DEV_HAS_SET_OSD_STRING)
+ s += "\t\tTV Supports <Set OSD String>\n";
+ if (feat & CEC_OP_FEAT_DEV_HAS_DECK_CONTROL)
+ s += "\t\tSupports Deck Control\n";
+ if (feat & CEC_OP_FEAT_DEV_HAS_SET_AUDIO_RATE)
+ s += "\t\tSource Supports <Set Audio Rate>\n";
+ if (feat & CEC_OP_FEAT_DEV_SINK_HAS_ARC_TX)
+ s += "\t\tSink Supports ARC Tx\n";
+ if (feat & CEC_OP_FEAT_DEV_SOURCE_HAS_ARC_RX)
+ s += "\t\tSource Supports ARC Rx\n";
+ return s;
+}
+
+int cec_named_ioctl(int fd, const char *name,
+ unsigned long int request, void *parm)
+{
+ int retval = ioctl(fd, request, parm);
+ int e;
+
+ e = retval == 0 ? 0 : errno;
+ if (options[OptTrace])
+ printf("\t\t%s returned %d (%s)\n",
+ name, retval, strerror(e));
+
+ if (retval < 0)
+ app_result = -1;
+
+ return retval == -1 ? e : (retval ? -1 : 0);
+}
+
+const char *ok(int res)
+{
+ static char buf[100];
+
+ if (res == ENOTTY) {
+ strcpy(buf, "OK (Not Supported)");
+ res = 0;
+ } else {
+ strcpy(buf, "OK");
+ }
+ tests_total++;
+ if (res) {
+ app_result = res;
+ sprintf(buf, "FAIL");
+ } else {
+ tests_ok++;
+ }
+ return buf;
+}
+
+int check_0(const void *p, int len)
+{
+ const __u8 *q = (const __u8 *)p;
+
+ while (len--)
+ if (*q++)
+ return 1;
+ return 0;
+}
+
+static int testCap(struct node *node)
+{
+ struct cec_caps caps;
+
+ memset(&caps, 0xff, sizeof(caps));
+ // Must always be there
+ fail_on_test(doioctl(node, CEC_ADAP_G_CAPS, &caps));
+ fail_on_test(check_0(caps.reserved, sizeof(caps.reserved)));
+ fail_on_test(caps.available_log_addrs == 0 ||
+ caps.available_log_addrs > CEC_MAX_LOG_ADDRS);
+ fail_on_test((caps.capabilities & CEC_CAP_PASSTHROUGH) &&
+ !(caps.capabilities & CEC_CAP_IO));
+ return 0;
+}
+
+static int testAdapPhysAddr(struct node *node, __u16 set_phys_addr)
+{
+ __u16 pa = 0xefff;
+
+ fail_on_test(doioctl(node, CEC_ADAP_G_PHYS_ADDR, &pa));
+ fail_on_test(pa == 0xefff);
+ if (node->caps & CEC_CAP_PHYS_ADDR) {
+ fail_on_test(doioctl(node, CEC_ADAP_S_PHYS_ADDR, &set_phys_addr));
+ fail_on_test(doioctl(node, CEC_ADAP_G_PHYS_ADDR, &pa));
+ fail_on_test(pa != set_phys_addr);
+ } else {
+ fail_on_test(doioctl(node, CEC_ADAP_S_PHYS_ADDR, &pa) != ENOTTY);
+ }
+ return 0;
+}
+
+static int testVendorID(struct node *node, __u32 set_vendor_id)
+{
+ __u32 vendor_id = 0xeeeeeeee;
+
+ fail_on_test(doioctl(node, CEC_ADAP_G_VENDOR_ID, &vendor_id));
+ fail_on_test(vendor_id == 0xeeeeeeee);
+ fail_on_test(vendor_id != CEC_VENDOR_ID_NONE &&
+ (vendor_id & 0xff000000));
+ if (node->caps & CEC_CAP_VENDOR_ID) {
+ vendor_id = 0xeeeeeeee;
+ fail_on_test(doioctl(node, CEC_ADAP_S_VENDOR_ID, &vendor_id) != EINVAL);
+ fail_on_test(doioctl(node, CEC_ADAP_S_VENDOR_ID, &set_vendor_id));
+ fail_on_test(doioctl(node, CEC_ADAP_G_VENDOR_ID, &vendor_id));
+ fail_on_test(vendor_id != set_vendor_id);
+ } else {
+ fail_on_test(doioctl(node, CEC_ADAP_S_VENDOR_ID, &vendor_id) != ENOTTY);
+ }
+ return 0;
+}
+
+static int testAdapState(struct node *node)
+{
+ __u32 state = 0xffffffff;
+
+ fail_on_test(doioctl(node, CEC_ADAP_G_STATE, &state));
+ fail_on_test(state > CEC_ADAP_ENABLED);
+ if (node->caps & CEC_CAP_STATE) {
+ state = CEC_ADAP_DISABLED;
+ fail_on_test(doioctl(node, CEC_ADAP_S_STATE, &state));
+ fail_on_test(doioctl(node, CEC_ADAP_G_STATE, &state));
+ fail_on_test(state != CEC_ADAP_DISABLED);
+ state = CEC_ADAP_ENABLED;
+ fail_on_test(doioctl(node, CEC_ADAP_S_STATE, &state));
+ fail_on_test(doioctl(node, CEC_ADAP_G_STATE, &state));
+ fail_on_test(state != CEC_ADAP_ENABLED);
+
+ /*
+ * Do this again, thus guaranteeing that there is always
+ * a disabled -> enabled and an enabled -> disabled state
+ * transition tested.
+ */
+ state = CEC_ADAP_DISABLED;
+ fail_on_test(doioctl(node, CEC_ADAP_S_STATE, &state));
+ fail_on_test(doioctl(node, CEC_ADAP_G_STATE, &state));
+ fail_on_test(state != CEC_ADAP_DISABLED);
+ state = CEC_ADAP_ENABLED;
+ fail_on_test(doioctl(node, CEC_ADAP_S_STATE, &state));
+ fail_on_test(doioctl(node, CEC_ADAP_G_STATE, &state));
+ fail_on_test(state != CEC_ADAP_ENABLED);
+ } else {
+ fail_on_test(doioctl(node, CEC_ADAP_S_STATE, &state) != ENOTTY);
+ }
+ return 0;
+}
+
+static int testAdapLogAddrs(struct node *node, unsigned flags,
+ const char *osd_name)
+{
+ struct cec_log_addrs laddrs;
+
+ memset(&laddrs, 0xff, sizeof(laddrs));
+ fail_on_test(doioctl(node, CEC_ADAP_G_LOG_ADDRS, &laddrs));
+ fail_on_test(check_0(laddrs.reserved, sizeof(laddrs.reserved)));
+ fail_on_test(laddrs.cec_version != CEC_OP_CEC_VERSION_1_4 &&
+ laddrs.cec_version != CEC_OP_CEC_VERSION_2_0);
+ fail_on_test(laddrs.num_log_addrs > CEC_MAX_LOG_ADDRS);
+ if (node->caps & CEC_CAP_LOG_ADDRS) {
+ memset(&laddrs, 0, sizeof(laddrs));
+ fail_on_test(doioctl(node, CEC_ADAP_S_LOG_ADDRS, &laddrs));
+ fail_on_test(laddrs.num_log_addrs != 0);
+ fail_on_test(doioctl(node, CEC_ADAP_G_LOG_ADDRS, &laddrs));
+ fail_on_test(laddrs.num_log_addrs != 0);
+
+ memset(&laddrs, 0, sizeof(laddrs));
+ laddrs.cec_version = CEC_OP_CEC_VERSION_2_0;
+ strcpy(laddrs.osd_name, osd_name);
+ for (unsigned i = 0; i < 8; i++) {
+ unsigned la_type;
+ unsigned all_dev_type;
+
+ if (!(flags & (1 << i)))
+ continue;
+ fail_on_test(laddrs.num_log_addrs == node->available_log_addrs);
+ switch (i) {
+ case CEC_OP_PRIM_DEVTYPE_TV:
+ la_type = CEC_LOG_ADDR_TYPE_TV;
+ all_dev_type = CEC_OP_ALL_DEVTYPE_TV;
+ break;
+ case CEC_OP_PRIM_DEVTYPE_RECORD:
+ la_type = CEC_LOG_ADDR_TYPE_RECORD;
+ all_dev_type = CEC_OP_ALL_DEVTYPE_RECORD;
+ break;
+ case CEC_OP_PRIM_DEVTYPE_TUNER:
+ la_type = CEC_LOG_ADDR_TYPE_TUNER;
+ all_dev_type = CEC_OP_ALL_DEVTYPE_TUNER;
+ break;
+ case CEC_OP_PRIM_DEVTYPE_PLAYBACK:
+ la_type = CEC_LOG_ADDR_TYPE_PLAYBACK;
+ all_dev_type = CEC_OP_ALL_DEVTYPE_PLAYBACK;
+ break;
+ case CEC_OP_PRIM_DEVTYPE_AUDIOSYSTEM:
+ la_type = CEC_LOG_ADDR_TYPE_AUDIOSYSTEM;
+ all_dev_type = CEC_OP_ALL_DEVTYPE_AUDIOSYSTEM;
+ break;
+ case CEC_OP_PRIM_DEVTYPE_PROCESSOR:
+ la_type = CEC_LOG_ADDR_TYPE_SPECIFIC;
+ all_dev_type = CEC_OP_ALL_DEVTYPE_SWITCH;
+ break;
+ case CEC_OP_PRIM_DEVTYPE_SWITCH:
+ default:
+ la_type = CEC_LOG_ADDR_TYPE_UNREGISTERED;
+ all_dev_type = CEC_OP_ALL_DEVTYPE_SWITCH;
+ break;
+ }
+ laddrs.log_addr_type[laddrs.num_log_addrs] = la_type;
+ laddrs.all_device_types[laddrs.num_log_addrs] = all_dev_type;
+ laddrs.primary_device_type[laddrs.num_log_addrs++] = i;
+ }
+
+ fail_on_test(doioctl(node, CEC_ADAP_S_LOG_ADDRS, &laddrs));
+ fail_on_test(laddrs.num_log_addrs == 0 ||
+ laddrs.num_log_addrs > CEC_MAX_LOG_ADDRS);
+ node->num_log_addrs = laddrs.num_log_addrs;
+ memcpy(node->log_addr, laddrs.log_addr, laddrs.num_log_addrs);
+ fail_on_test(doioctl(node, CEC_ADAP_S_LOG_ADDRS, &laddrs) != EBUSY);
+ } else {
+ node->num_log_addrs = laddrs.num_log_addrs;
+ memcpy(node->log_addr, laddrs.log_addr, laddrs.num_log_addrs);
+ fail_on_test(doioctl(node, CEC_ADAP_S_LOG_ADDRS, &laddrs) != ENOTTY);
+ }
+ return 0;
+}
+
+static int testTopologyDevice(struct node *node, unsigned i, unsigned la)
+{
+ struct cec_msg msg = { };
+ char osd_name[15];
+
+ printf("\tSystem Information for device %d (%s) from device %d (%s):\n",
+ i, la2s(i), la, la2s(la));
+
+ cec_msg_init(&msg, la, i);
+ cec_msg_get_cec_version(&msg, true);
+ fail_on_test(doioctl(node, CEC_TRANSMIT, &msg));
+ printf("\t\tCEC Version : ");
+ if (msg.status)
+ warn("%s\n", status2s(msg.status).c_str());
+ else
+ printf("%s\n", version2s(msg.msg[2]));
+
+ cec_msg_init(&msg, la, i);
+ cec_msg_give_physical_addr(&msg, true);
+ doioctl(node, CEC_TRANSMIT, &msg);
+ printf("\t\tPhysical Address : ");
+ if (msg.status) {
+ warn("\n%s\n", status2s(msg.status).c_str());
+ } else {
+ __u16 phys_addr = (msg.msg[2] << 8) | msg.msg[3];
+
+ printf("%x.%x.%x.%x\n",
+ phys_addr >> 12, (phys_addr >> 8) & 0xf,
+ (phys_addr >> 4) & 0xf, phys_addr & 0xf);
+ printf("\t\tPrimary Device Type : %s\n",
+ prim_type2s(msg.msg[4]));
+ }
+
+ cec_msg_init(&msg, la, i);
+ cec_msg_give_device_vendor_id(&msg, true);
+ doioctl(node, CEC_TRANSMIT, &msg);
+ printf("\t\tVendor ID : ");
+ if (msg.status)
+ warn("\n%s\n", status2s(msg.status).c_str());
+ else
+ printf("0x%02x%02x%02x\n",
+ msg.msg[2], msg.msg[3], msg.msg[4]);
+
+ cec_msg_init(&msg, la, i);
+ cec_msg_give_device_power_status(&msg, true);
+ doioctl(node, CEC_TRANSMIT, &msg);
+ printf("\t\tPower Status : ");
+ if (msg.status)
+ warn("\n%s\n", status2s(msg.status).c_str());
+ else
+ printf("%s\n", power_status2s(msg.msg[2]));
+
+ cec_msg_init(&msg, la, i);
+ cec_msg_give_osd_name(&msg, true);
+ doioctl(node, CEC_TRANSMIT, &msg);
+ cec_ops_set_osd_name(&msg, osd_name);
+ printf("\t\tOSD Name : ");
+ if (msg.status)
+ warn("\n%s\n", status2s(msg.status).c_str());
+ else
+ printf("%s\n", osd_name);
+ return 0;
+}
+
+static int testTopology(struct node *node)
+{
+ struct cec_msg msg = { };
+ struct cec_log_addrs laddrs = { };
+
+ fail_on_test(doioctl(node, CEC_ADAP_G_LOG_ADDRS, &laddrs));
+
+ if (!(node->caps & CEC_CAP_IO)) {
+ cec_msg_init(&msg, 0xf, 0);
+ fail_on_test(doioctl(node, CEC_TRANSMIT, &msg) != ENOTTY);
+ return -ENOTTY;
+ }
+
+ for (unsigned i = 0; i < 15; i++) {
+ int ret;
+
+ cec_msg_init(&msg, 0xf, i);
+ ret = doioctl(node, CEC_TRANSMIT, &msg);
+
+ switch (msg.status) {
+ case CEC_TX_STATUS_OK:
+ fail_on_test(testTopologyDevice(node, i, laddrs.log_addr[0]));
+ break;
+ case CEC_TX_STATUS_ARB_LOST:
+ warn("tx arbitration lost for addr %d\n", i);
+ break;
+ case CEC_TX_STATUS_RETRY_TIMEOUT:
+ break;
+ default:
+ return fail("ret ? %d\n", ret);
+ }
+ }
+ return 0;
+}
+
+static int testARC(struct node *node)
+{
+ struct cec_msg msg = { };
+ struct cec_log_addrs laddrs = { };
+ unsigned la;
+ unsigned i;
+
+ fail_on_test(doioctl(node, CEC_ADAP_G_LOG_ADDRS, &laddrs));
+ la = laddrs.log_addr[0];
+
+ for (i = 0; i < 15; i++) {
+ if (i == la)
+ continue;
+ cec_msg_init(&msg, la, i);
+ cec_msg_initiate_arc(&msg, true);
+ fail_on_test(doioctl(node, CEC_TRANSMIT, &msg));
+ if (msg.status == 0) {
+ cec_msg_init(&msg, la, i);
+ cec_msg_terminate_arc(&msg, true);
+ msg.reply = CEC_MSG_REPORT_ARC_TERMINATED;
+ fail_on_test(doioctl(node, CEC_TRANSMIT, &msg));
+ fail_on_test(msg.status);
+ printf("logical address %d supports ARC\n", i);
+ } else {
+ printf("logical address %d doesn't support ARC\n", i);
+ }
+ }
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ const char *device = "/dev/cec0"; /* -d device */
+ char short_options[26 * 2 * 2 + 1];
+ __u32 vendor_id;
+ __u32 set_vendor_id = 0x000c03; /* HDMI LLC vendor ID */
+ __u16 phys_addr;
+ __u16 set_phys_addr = 0;
+ int idx = 0;
+ int fd = -1;
+ int ch;
+ int i;
+
+ for (i = 0; long_options[i].name; i++) {
+ if (!isalpha(long_options[i].val))
+ continue;
+ short_options[idx++] = long_options[i].val;
+ if (long_options[i].has_arg == required_argument)
+ short_options[idx++] = ':';
+ }
+ while (1) {
+ int option_index = 0;
+
+ short_options[idx] = 0;
+ ch = getopt_long(argc, argv, short_options,
+ long_options, &option_index);
+ if (ch == -1)
+ break;
+
+ options[(int)ch] = 1;
+ switch (ch) {
+ case OptHelp:
+ usage();
+ return 0;
+ case OptSetDevice:
+ device = optarg;
+ if (device[0] >= '0' && device[0] <= '9' && strlen(device) <= 3) {
+ static char newdev[20];
+
+ sprintf(newdev, "/dev/cec%s", device);
+ device = newdev;
+ }
+ break;
+ case OptNoWarnings:
+ show_warnings = false;
+ break;
+ case OptVerbose:
+ show_info = true;
+ break;
+ case OptPhysAddr:
+ set_phys_addr = strtoul(optarg, NULL, 0);
+ break;
+ case OptVendorID:
+ set_vendor_id = strtoul(optarg, NULL, 0) & 0x00ffffff;
+ break;
+ case OptSwitch:
+ if (options[OptCDCOnly] || options[OptUnregistered]) {
+ fprintf(stderr, "--switch cannot be combined with --cdc-only or --unregistered.\n");
+ usage();
+ return 1;
+ }
+ break;
+ case OptCDCOnly:
+ if (options[OptSwitch] || options[OptUnregistered]) {
+ fprintf(stderr, "--cdc-only cannot be combined with --switch or --unregistered.\n");
+ usage();
+ return 1;
+ }
+ break;
+ case OptUnregistered:
+ if (options[OptCDCOnly] || options[OptSwitch]) {
+ fprintf(stderr, "--unregistered cannot be combined with --cdc-only or --switch.\n");
+ usage();
+ return 1;
+ }
+ break;
+ case ':':
+ fprintf(stderr, "Option '%s' requires a value\n",
+ argv[optind]);
+ usage();
+ return 1;
+ case '?':
+ if (argv[optind])
+ fprintf(stderr, "Unknown argument '%s'\n", argv[optind]);
+ usage();
+ return 1;
+ }
+ }
+ if (optind < argc) {
+ printf("unknown arguments: ");
+ while (optind < argc)
+ printf("%s ", argv[optind++]);
+ printf("\n");
+ usage();
+ return 1;
+ }
+
+ if ((fd = open(device, O_RDWR)) < 0) {
+ fprintf(stderr, "Failed to open %s: %s\n", device,
+ strerror(errno));
+ exit(1);
+ }
+
+ struct node node;
+ struct cec_caps caps = { };
+
+ node.fd = fd;
+ node.device = device;
+ doioctl(&node, CEC_ADAP_G_CAPS, &caps);
+ node.caps = caps.capabilities;
+ node.available_log_addrs = caps.available_log_addrs;
+
+ unsigned flags = 0;
+ const char *osd_name;
+
+ if (options[OptTV])
+ osd_name = "TV";
+ else if (options[OptRecord])
+ osd_name = "Record";
+ else if (options[OptPlayback])
+ osd_name = "Playback";
+ else if (options[OptTuner])
+ osd_name = "Tuner";
+ else if (options[OptAudio])
+ osd_name = "Audio System";
+ else if (options[OptProcessor])
+ osd_name = "Processor";
+ else if (options[OptSwitch] || options[OptCDCOnly] || options[OptUnregistered])
+ osd_name = "";
+ else
+ osd_name = "TV";
+
+ if (options[OptTV])
+ flags |= 1 << CEC_OP_PRIM_DEVTYPE_TV;
+ if (options[OptRecord])
+ flags |= 1 << CEC_OP_PRIM_DEVTYPE_RECORD;
+ if (options[OptTuner])
+ flags |= 1 << CEC_OP_PRIM_DEVTYPE_TUNER;
+ if (options[OptPlayback])
+ flags |= 1 << CEC_OP_PRIM_DEVTYPE_PLAYBACK;
+ if (options[OptAudio])
+ flags |= 1 << CEC_OP_PRIM_DEVTYPE_AUDIOSYSTEM;
+ if (options[OptProcessor])
+ flags |= 1 << CEC_OP_PRIM_DEVTYPE_PROCESSOR;
+ if (options[OptSwitch] || options[OptCDCOnly] || options[OptUnregistered])
+ flags |= 1 << CEC_OP_PRIM_DEVTYPE_SWITCH;
+ if (flags == 0)
+ flags |= 1 << CEC_OP_PRIM_DEVTYPE_TV;
+
+ printf("Driver Info:\n");
+ printf("\tCapabilities : 0x%08x\n", caps.capabilities);
+ printf("%s", caps2s(caps.capabilities).c_str());
+ printf("\tInputs : %u\n", caps.ninputs);
+ printf("\tAvailable Logical Addresses: %u\n",
+ caps.available_log_addrs);
+
+ doioctl(&node, CEC_ADAP_G_PHYS_ADDR, &phys_addr);
+ printf("\tPhysical Address : %x.%x.%x.%x\n",
+ phys_addr >> 12, (phys_addr >> 8) & 0xf,
+ (phys_addr >> 4) & 0xf, phys_addr & 0xf);
+ if (!options[OptPhysAddr] && phys_addr == CEC_PHYS_ADDR_INVALID &&
+ (node.caps & CEC_CAP_PHYS_ADDR))
+ warn("Perhaps you should use option --phys-addr?\n");
+
+ doioctl(&node, CEC_ADAP_G_VENDOR_ID, &vendor_id);
+ if (vendor_id != CEC_VENDOR_ID_NONE)
+ printf("\tVendor ID : 0x%06x\n", vendor_id);
+
+ __u32 adap_state;
+ doioctl(&node, CEC_ADAP_G_STATE, &adap_state);
+ printf("\tAdapter State : %s\n", adap_state ? "Enabled" : "Disabled");
+
+ struct cec_log_addrs laddrs = { };
+ doioctl(&node, CEC_ADAP_G_LOG_ADDRS, &laddrs);
+ printf("\tCEC Version : %s\n", version2s(laddrs.cec_version));
+ printf("\tLogical Addresses : %u\n", laddrs.num_log_addrs);
+ for (unsigned i = 0; i < laddrs.num_log_addrs; i++) {
+ printf("\t Logical Address : %d\n",
+ laddrs.log_addr[i]);
+ printf("\t Primary Device Type : %s\n",
+ prim_type2s(laddrs.primary_device_type[i]));
+ printf("\t Logical Address Type : %s\n",
+ la_type2s(laddrs.log_addr_type[i]));
+ if (laddrs.cec_version < CEC_OP_CEC_VERSION_2_0)
+ continue;
+ printf("\t All Device Types : %s\n",
+ all_dev_types2s(laddrs.all_device_types[i]).c_str());
+
+ bool is_dev_feat = false;
+ for (unsigned idx = 0; idx < sizeof(laddrs.features[0]); idx++) {
+ __u8 byte = laddrs.features[i][idx];
+
+ if (!is_dev_feat) {
+ if (byte & 0x40) {
+ printf("\t RC Source Profile :\n%s\n",
+ rc_src_prof2s(byte).c_str());
+ } else {
+ const char *s = "Reserved";
+
+ switch (byte & 0xf) {
+ case 0:
+ s = "None";
+ break;
+ case 2:
+ s = "RC Profile 1";
+ break;
+ case 6:
+ s = "RC Profile 2";
+ break;
+ case 10:
+ s = "RC Profile 3";
+ break;
+ case 14:
+ s = "RC Profile 4";
+ break;
+ }
+ printf("\t RC TV Profile : %s\n", s);
+ }
+ } else {
+ printf("\t Device Features :\n%s\n",
+ dev_feat2s(byte).c_str());
+ }
+ if (byte & CEC_OP_FEAT_EXT)
+ continue;
+ if (!is_dev_feat)
+ is_dev_feat = true;
+ else
+ break;
+ }
+ }
+
+ printf("\nCompliance test for device %s:\n\n", device);
+
+ /* Required ioctls */
+
+ printf("Required ioctls:\n");
+ printf("\ttest CEC_ADAP_G_CAPS: %s\n", ok(testCap(&node)));
+ if (options[OptPhysAddr] || phys_addr == CEC_PHYS_ADDR_INVALID)
+ phys_addr = set_phys_addr;
+ printf("\ttest CEC_ADAP_G/S_PHYS_ADDR: %s\n", ok(testAdapPhysAddr(&node, phys_addr)));
+ if (options[OptVendorID] || vendor_id == CEC_VENDOR_ID_NONE)
+ vendor_id = set_vendor_id;
+ printf("\ttest CEC_ADAP_G/S_VENDOR_ID: %s\n", ok(testVendorID(&node, vendor_id)));
+ printf("\ttest CEC_ADAP_G/S_STATE: %s\n", ok(testAdapState(&node)));
+ printf("\ttest CEC_ADAP_G/S_LOG_ADDRS: %s\n", ok(testAdapLogAddrs(&node, flags, osd_name)));
+ printf("\ttest CEC topology discovery: %s\n", ok(testTopology(&node)));
+ printf("\ttest CEC ARC: %s\n", ok(testARC(&node)));
+ printf("\n");
+
+ /* Final test report */
+
+ close(fd);
+ printf("Total: %d, Succeeded: %d, Failed: %d, Warnings: %d\n",
+ tests_total, tests_ok, tests_total - tests_ok, warnings);
+ exit(app_result);
+}
diff --git a/utils/cec-compliance/cec-compliance.h b/utils/cec-compliance/cec-compliance.h
new file mode 100644
index 0000000..cd02c24
--- /dev/null
+++ b/utils/cec-compliance/cec-compliance.h
@@ -0,0 +1,87 @@
+/*
+ CEC API compliance test tool.
+
+ Copyright 2015 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ Author: Hans Verkuil <hans.verkuil@cisco.com>
+
+ 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 program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+ */
+
+#ifndef _CEC_COMPLIANCE_H_
+#define _CEC_COMPLIANCE_H_
+
+#include <stdarg.h>
+#include <cerrno>
+#include <string>
+#include <linux/cec-funcs.h>
+
+extern bool show_info;
+extern bool show_warnings;
+extern unsigned warnings;
+
+struct node {
+ int fd;
+ const char *device;
+ unsigned caps;
+ unsigned available_log_addrs;
+ unsigned num_log_addrs;
+ __u8 log_addr[CEC_MAX_LOG_ADDRS];
+};
+
+#define info(fmt, args...) \
+ do { \
+ if (show_info) \
+ printf("\t\tinfo: " fmt, ##args); \
+ } while (0)
+
+#define warn(fmt, args...) \
+ do { \
+ warnings++; \
+ if (show_warnings) \
+ printf("\t\twarn: %s(%d): " fmt, __FILE__, __LINE__, ##args); \
+ } while (0)
+
+#define warn_once(fmt, args...) \
+ do { \
+ static bool show; \
+ \
+ if (!show) { \
+ show = true; \
+ warnings++; \
+ if (show_warnings) \
+ printf("\t\twarn: %s(%d): " fmt, \
+ __FILE__, __LINE__, ##args); \
+ } \
+ } while (0)
+
+#define fail(fmt, args...) \
+({ \
+ printf("\t\tfail: %s(%d): " fmt, __FILE__, __LINE__, ##args); \
+ 1; \
+})
+
+#define fail_on_test(test) \
+ do { \
+ if (test) \
+ return fail("%s\n", #test); \
+ } while (0)
+
+int cec_named_ioctl(int fd, const char *name,
+ unsigned long int request, void *parm);
+
+#define doioctl(n, r, p) cec_named_ioctl((n)->fd, #r, r, p)
+
+const char *ok(int res);
+
+// CEC core tests
+int testCore(struct node *node);
+
+#endif
--
2.1.4
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCHv2 4/4] cec-ctl: CEC control utility
2015-08-18 8:36 [PATCHv2 0/4] cec-ctl/compliance: new CEC utilities Hans Verkuil
` (2 preceding siblings ...)
2015-08-18 8:36 ` [PATCHv2 3/4] cec-compliance: add new CEC compliance utility Hans Verkuil
@ 2015-08-18 8:36 ` Hans Verkuil
2015-08-18 8:46 ` Hans Verkuil
4 siblings, 0 replies; 7+ messages in thread
From: Hans Verkuil @ 2015-08-18 8:36 UTC (permalink / raw)
To: linux-media
Cc: dri-devel, m.szyprowski, linux-input, linux-samsung-soc, lars,
kamil, linux, Hans Verkuil
Generic CEC utility that can be used to send/receive/monitor CEC
messages.
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
---
configure.ac | 1 +
utils/Makefile.am | 1 +
utils/cec-ctl/Makefile.am | 8 +
utils/cec-ctl/cec-ctl.cpp | 1296 +++++++++++++++++++++++++++++++++++++++++++++
utils/cec-ctl/msg2ctl.pl | 430 +++++++++++++++
5 files changed, 1736 insertions(+)
create mode 100644 utils/cec-ctl/Makefile.am
create mode 100644 utils/cec-ctl/cec-ctl.cpp
create mode 100644 utils/cec-ctl/msg2ctl.pl
diff --git a/configure.ac b/configure.ac
index 12c2eb9..72d59bd 100644
--- a/configure.ac
+++ b/configure.ac
@@ -27,6 +27,7 @@ AC_CONFIG_FILES([Makefile
utils/media-ctl/Makefile
utils/rds/Makefile
utils/cec-compliance/Makefile
+ utils/cec-ctl/Makefile
utils/v4l2-compliance/Makefile
utils/v4l2-ctl/Makefile
utils/v4l2-dbg/Makefile
diff --git a/utils/Makefile.am b/utils/Makefile.am
index c78e97b..617abf1 100644
--- a/utils/Makefile.am
+++ b/utils/Makefile.am
@@ -6,6 +6,7 @@ SUBDIRS = \
keytable \
media-ctl \
cec-compliance \
+ cec-ctl \
v4l2-compliance \
v4l2-ctl \
v4l2-dbg \
diff --git a/utils/cec-ctl/Makefile.am b/utils/cec-ctl/Makefile.am
new file mode 100644
index 0000000..378d7db
--- /dev/null
+++ b/utils/cec-ctl/Makefile.am
@@ -0,0 +1,8 @@
+bin_PROGRAMS = cec-ctl
+
+cec_ctl_SOURCES = cec-ctl.cpp
+
+cec-ctl.cpp: cec-ctl-gen.h
+
+cec-ctl-gen.h: msg2ctl.pl ../../include/linux/cec.h ../../include/linux/cec-funcs.h
+ msg2ctl.pl ../../include/linux/cec.h ../../include/linux/cec-funcs.h >cec-ctl-gen.h
diff --git a/utils/cec-ctl/cec-ctl.cpp b/utils/cec-ctl/cec-ctl.cpp
new file mode 100644
index 0000000..6a1edb5
--- /dev/null
+++ b/utils/cec-ctl/cec-ctl.cpp
@@ -0,0 +1,1296 @@
+/*
+ Copyright 2015 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ Author: Hans Verkuil <hans.verkuil@cisco.com>
+
+ 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 program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <inttypes.h>
+#include <getopt.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <stdarg.h>
+#include <cerrno>
+#include <string>
+#include <vector>
+#include <linux/cec-funcs.h>
+#include <config.h>
+
+#define CEC_MAX_ARGS 16
+
+#define xstr(s) str(s)
+#define str(s) #s
+
+struct cec_enum_values {
+ const char *type_name;
+ __u8 value;
+};
+
+enum cec_types {
+ CEC_TYPE_U8,
+ CEC_TYPE_U16,
+ CEC_TYPE_U32,
+ CEC_TYPE_STRING,
+ CEC_TYPE_ENUM,
+};
+
+struct arg {
+ enum cec_types type;
+ __u8 num_enum_values;
+ const struct cec_enum_values *values;
+};
+
+static const struct arg arg_u8 = {
+ CEC_TYPE_U8,
+};
+
+static const struct arg arg_u16 = {
+ CEC_TYPE_U16,
+};
+
+static const struct arg arg_u32 = {
+ CEC_TYPE_U32,
+};
+
+static const struct arg arg_string = {
+ CEC_TYPE_STRING,
+};
+
+static const struct cec_enum_values type_ui_cmd[] = {
+ { "Select", 0x00 },
+ { "Up", 0x01 },
+ { "Down", 0x02 },
+ { "Left", 0x03 },
+ { "Right", 0x04 },
+ { "Right-Up", 0x05 },
+ { "Right-Down", 0x06 },
+ { "Left-Up", 0x07 },
+ { "Left-Down", 0x08 },
+ { "Device Root Menu", 0x09 },
+ { "Device Setup Menu", 0x0a },
+ { "Contents Menu", 0x0b },
+ { "Favorite Menu", 0x0c },
+ { "Back", 0x0d },
+ { "Media Top Menu", 0x10 },
+ { "Media Context-sensitive Menu", 0x11 },
+ { "Number Entry Mode", 0x1d },
+ { "Number 11", 0x1e },
+ { "Number 12", 0x1f },
+ { "Number 0 or Number 10", 0x20 },
+ { "Number 1", 0x21 },
+ { "Number 2", 0x22 },
+ { "Number 3", 0x23 },
+ { "Number 4", 0x24 },
+ { "Number 5", 0x25 },
+ { "Number 6", 0x26 },
+ { "Number 7", 0x27 },
+ { "Number 8", 0x28 },
+ { "Number 9", 0x29 },
+ { "Dot", 0x2a },
+ { "Enter", 0x2b },
+ { "Clear", 0x2c },
+ { "Next Favorite", 0x2f },
+ { "Channel Up", 0x30 },
+ { "Channel Down", 0x31 },
+ { "Previous Channel", 0x32 },
+ { "Sound Select", 0x33 },
+ { "Input Select", 0x34 },
+ { "Display Information", 0x35 },
+ { "Help", 0x36 },
+ { "Page Up", 0x37 },
+ { "Page Down", 0x38 },
+ { "Power", 0x40 },
+ { "Volume Up", 0x41 },
+ { "Volume Down", 0x42 },
+ { "Mute", 0x43 },
+ { "Play", 0x44 },
+ { "Stop", 0x45 },
+ { "Pause", 0x46 },
+ { "Record", 0x47 },
+ { "Rewind", 0x48 },
+ { "Fast forward", 0x49 },
+ { "Eject", 0x4a },
+ { "Skip Forward", 0x4b },
+ { "Skip Backward", 0x4c },
+ { "Stop-Record", 0x4d },
+ { "Pause-Record", 0x4e },
+ { "Angle", 0x50 },
+ { "Sub picture", 0x51 },
+ { "Video on Demand", 0x52 },
+ { "Electronic Program Guide", 0x53 },
+ { "Timer Programming", 0x54 },
+ { "Initial Configuration", 0x55 },
+ { "Select Broadcast Type", 0x56 },
+ { "Select Sound Presentation", 0x57 },
+ { "Audio Description", 0x58 },
+ { "Internet", 0x59 },
+ { "3D Mode", 0x5a },
+ { "Play Function", 0x60 },
+ { "Pause-Play Function", 0x61 },
+ { "Record Function", 0x62 },
+ { "Pause-Record Function", 0x63 },
+ { "Stop Function", 0x64 },
+ { "Mute Function", 0x65 },
+ { "Restore Volume Function", 0x66 },
+ { "Tune Function", 0x67 },
+ { "Select Media Function", 0x68 },
+ { "Select A/V Input Function", 0x69 },
+ { "Select Audio Input Function", 0x6a },
+ { "Power Toggle Function", 0x6b },
+ { "Power Off Function", 0x6c },
+ { "Power On Function", 0x6d },
+ { "F1 (Blue)", 0x71 },
+ { "F2 (Red)", 0x72 },
+ { "F3 (Green)", 0x73 },
+ { "F4 (Yellow)", 0x74 },
+ { "F5", 0x75 },
+ { "Data", 0x76 },
+};
+
+static const struct arg arg_rc_ui_cmd = {
+ CEC_TYPE_ENUM, sizeof(type_ui_cmd) / sizeof(type_ui_cmd[0]), type_ui_cmd
+};
+
+struct message {
+ __u8 msg;
+ unsigned option;
+ __u8 num_args;
+ const char *arg_names[CEC_MAX_ARGS+1];
+ const struct arg *args[CEC_MAX_ARGS];
+ const char *msg_name;
+};
+
+static struct cec_op_digital_service_id *args2digital_service_id(__u8 service_id_method,
+ __u8 dig_bcast_system,
+ __u16 transport_id,
+ __u16 service_id,
+ __u16 orig_network_id,
+ __u16 program_number,
+ __u8 channel_number_fmt,
+ __u16 major,
+ __u16 minor)
+{
+ static struct cec_op_digital_service_id dsid;
+
+ dsid.service_id_method = service_id_method;
+ dsid.dig_bcast_system = dig_bcast_system;
+ if (service_id_method == CEC_OP_SERVICE_ID_METHOD_BY_CHANNEL) {
+ dsid.channel.channel_number_fmt = channel_number_fmt;
+ dsid.channel.major = major;
+ dsid.channel.minor = minor;
+ return &dsid;
+ }
+ switch (dig_bcast_system) {
+ case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_GEN:
+ case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_CABLE:
+ case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_SAT:
+ case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_T:
+ dsid.atsc.transport_id = transport_id;
+ dsid.atsc.program_number = program_number;
+ break;
+ default:
+ dsid.dvb.transport_id = transport_id;
+ dsid.dvb.service_id = service_id;
+ dsid.dvb.orig_network_id = orig_network_id;
+ break;
+ }
+ return &dsid;
+}
+
+static int parse_subopt(char **subs, const char * const *subopts, char **value)
+{
+ int opt = getsubopt(subs, (char * const *)subopts, value);
+
+ if (opt == -1) {
+ fprintf(stderr, "Invalid suboptions specified\n");
+ return -1;
+ }
+ if (*value == NULL) {
+ fprintf(stderr, "No value given to suboption <%s>\n",
+ subopts[opt]);
+ return -1;
+ }
+ return opt;
+}
+
+static unsigned parse_enum(const char *value, const struct arg *a)
+{
+ if (isdigit(*value))
+ return strtoul(optarg, NULL, 0);
+ for (int i = 0; i < a->num_enum_values; i++) {
+ if (!strcmp(value, a->values[i].type_name))
+ return a->values[i].value;
+ }
+ return 0;
+}
+
+static char options[512];
+
+static std::string status2s(unsigned stat)
+{
+ std::string s;
+
+ if (stat & CEC_TX_STATUS_ARB_LOST)
+ s += "ArbitrationLost ";
+ if (stat & CEC_TX_STATUS_REPLY_TIMEOUT)
+ s += "ReplyTimeout ";
+ if (stat & CEC_TX_STATUS_RETRY_TIMEOUT)
+ s += "RetryTimeout ";
+ if (stat & CEC_TX_STATUS_FEATURE_ABORT)
+ s += "FeatureAbort ";
+ return s;
+}
+
+static void log_arg(const struct arg *arg, const char *arg_name, __u32 val)
+{
+ unsigned i;
+
+ switch (arg->type) {
+ case CEC_TYPE_ENUM:
+ for (i = 0; i < arg->num_enum_values; i++) {
+ if (arg->values[i].value == val) {
+ printf("\t%s: %s (0x%02x)\n", arg_name,
+ arg->values[i].type_name, val);
+ return;
+ }
+ }
+ /* fall through */
+ case CEC_TYPE_U8:
+ printf("\t%s: %u (0x%02x)\n", arg_name, val, val);
+ return;
+ case CEC_TYPE_U16:
+ if (strstr(arg_name, "phys-addr"))
+ printf("\t%s: %x.%x.%x.%x\n", arg_name,
+ val >> 12, (val >> 8) & 0xf, (val >> 4) & 0xf, val & 0xf);
+ else
+ printf("\t%s: %u (0x%04x)\n", arg_name, val, val);
+ return;
+ case CEC_TYPE_U32:
+ printf("\t%s: %u (0x%08x)\n", arg_name, val, val);
+ return;
+ default:
+ break;
+ }
+ printf("\t%s: unknown type\n", arg_name);
+}
+
+static void log_arg(const struct arg *arg, const char *arg_name,
+ const char *s)
+{
+ switch (arg->type) {
+ case CEC_TYPE_STRING:
+ printf("\t%s: %s\n", arg_name, s);
+ return;
+ default:
+ break;
+ }
+ printf("\t%s: unknown type\n", arg_name);
+}
+
+static const struct cec_enum_values type_rec_src_type[] = {
+ { "own", CEC_OP_RECORD_SRC_OWN },
+ { "digital", CEC_OP_RECORD_SRC_DIGITAL },
+ { "analog", CEC_OP_RECORD_SRC_ANALOG },
+ { "ext-plug", CEC_OP_RECORD_SRC_EXT_PLUG },
+ { "ext-phys-addr", CEC_OP_RECORD_SRC_EXT_PHYS_ADDR },
+};
+
+static const struct arg arg_rec_src_type = {
+ CEC_TYPE_ENUM, 5, type_rec_src_type
+};
+
+static void log_digital(const char *arg_name, const struct cec_op_digital_service_id *digital);
+static void log_rec_src(const char *arg_name, const struct cec_op_record_src *rec_src);
+static void log_tuner_dev_info(const char *arg_name, const struct cec_op_tuner_device_info *tuner_dev_info);
+static void log_features(const struct arg *arg, const char *arg_name, const __u8 *p);
+
+#include "cec-ctl-gen.h"
+
+static void log_digital(const char *arg_name, const struct cec_op_digital_service_id *digital)
+{
+ log_arg(&arg_service_id_method, "service-id-method", digital->service_id_method);
+ log_arg(&arg_dig_bcast_system, "dig-bcast-system", digital->dig_bcast_system);
+ if (digital->service_id_method == CEC_OP_SERVICE_ID_METHOD_BY_CHANNEL) {
+ log_arg(&arg_channel_number_fmt, "channel-number-fmt", digital->channel.channel_number_fmt);
+ log_arg(&arg_u16, "major", digital->channel.major);
+ log_arg(&arg_u16, "minor", digital->channel.minor);
+ return;
+ }
+
+ switch (digital->dig_bcast_system) {
+ case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_GEN:
+ case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_CABLE:
+ case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_SAT:
+ case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_T:
+ log_arg(&arg_u16, "transport-id", digital->atsc.transport_id);
+ log_arg(&arg_u16, "program-number", digital->atsc.program_number);
+ break;
+ default:
+ log_arg(&arg_u16, "transport-id", digital->dvb.transport_id);
+ log_arg(&arg_u16, "service-id", digital->dvb.service_id);
+ log_arg(&arg_u16, "orig-network-id", digital->dvb.orig_network_id);
+ break;
+ }
+}
+
+static void log_rec_src(const char *arg_name, const struct cec_op_record_src *rec_src)
+{
+ log_arg(&arg_rec_src_type, "rec-src-type", rec_src->type);
+ switch (rec_src->type) {
+ case CEC_OP_RECORD_SRC_OWN:
+ default:
+ break;
+ case CEC_OP_RECORD_SRC_DIGITAL:
+ log_digital(arg_name, &rec_src->digital);
+ break;
+ case CEC_OP_RECORD_SRC_ANALOG:
+ log_arg(&arg_ana_bcast_type, "ana-bcast-type", rec_src->analog.ana_bcast_type);
+ log_arg(&arg_u16, "ana-freq", rec_src->analog.ana_freq);
+ log_arg(&arg_bcast_system, "bcast-system", rec_src->analog.bcast_system);
+ break;
+ case CEC_OP_RECORD_SRC_EXT_PLUG:
+ log_arg(&arg_u8, "plug", rec_src->ext_plug.plug);
+ break;
+ case CEC_OP_RECORD_SRC_EXT_PHYS_ADDR:
+ log_arg(&arg_u16, "phys-addr", rec_src->ext_phys_addr.phys_addr);
+ break;
+ }
+}
+
+static void log_tuner_dev_info(const char *arg_name, const struct cec_op_tuner_device_info *tuner_dev_info)
+{
+ log_arg(&arg_rec_flag, "rec-flag", tuner_dev_info->rec_flag);
+ log_arg(&arg_tuner_display_info, "tuner-display-info", tuner_dev_info->tuner_display_info);
+ if (tuner_dev_info->is_analog) {
+ log_arg(&arg_ana_bcast_type, "ana-bcast-type", tuner_dev_info->analog.ana_bcast_type);
+ log_arg(&arg_u16, "ana-freq", tuner_dev_info->analog.ana_freq);
+ log_arg(&arg_bcast_system, "bcast-system", tuner_dev_info->analog.bcast_system);
+ } else {
+ log_digital(arg_name, &tuner_dev_info->digital);
+ }
+}
+
+static void log_features(const struct arg *arg,
+ const char *arg_name, const __u8 *p)
+{
+ do {
+ log_arg(arg, arg_name, (__u32)((*p) & ~CEC_OP_FEAT_EXT));
+ } while ((*p++) & CEC_OP_FEAT_EXT);
+}
+
+/* Short option list
+
+ Please keep in alphabetical order.
+ That makes it easier to see which short options are still free.
+
+ In general the lower case is used to set something and the upper
+ case is used to retrieve a setting. */
+enum Option {
+ OptPhysAddr = 'a',
+ OptClear = 'C',
+ OptSetDevice = 'd',
+ OptAdapDisable = 'D',
+ OptAdapEnable = 'E',
+ OptFrom = 'f',
+ OptHelp = 'h',
+ OptMonitor = 'm',
+ OptNoReply = 'n',
+ OptShowTopology = 'S',
+ OptTo = 't',
+ OptTrace = 'T',
+ OptVerbose = 'v',
+ OptVendorID = 'V',
+
+ OptTV = 128,
+ OptRecord,
+ OptTuner,
+ OptPlayback,
+ OptAudio,
+ OptProcessor,
+ OptSwitch,
+ OptCDCOnly,
+ OptUnregistered,
+ OptCECVersion1_4,
+ CEC_FEATURE_OPTIONS
+};
+
+struct node {
+ int fd;
+ const char *device;
+ unsigned caps;
+ unsigned available_log_addrs;
+ unsigned num_log_addrs;
+ __u8 log_addr[CEC_MAX_LOG_ADDRS];
+};
+
+#define doioctl(n, r, p) cec_named_ioctl((n)->fd, #r, r, p)
+
+bool show_info;
+
+typedef std::vector<cec_msg> msg_vec;
+
+static const struct message *opt2message[OptLast - OptMessages];
+
+static void init_messages()
+{
+ for (unsigned i = 0; messages[i].msg_name; i++)
+ opt2message[messages[i].option - OptMessages] = &messages[i];
+}
+
+static struct option long_options[] = {
+ { "device", required_argument, 0, OptSetDevice },
+ { "help", no_argument, 0, OptHelp },
+ { "trace", no_argument, 0, OptTrace },
+ { "verbose", no_argument, 0, OptVerbose },
+ { "phys-addr", required_argument, 0, OptPhysAddr },
+ { "vendor-id", required_argument, 0, OptVendorID },
+ { "cec-version-1.4", no_argument, 0, OptCECVersion1_4 },
+ { "enable", no_argument, 0, OptAdapEnable },
+ { "disable", no_argument, 0, OptAdapDisable },
+ { "clear", no_argument, 0, OptClear },
+ { "monitor", no_argument, 0, OptMonitor },
+ { "no-reply", no_argument, 0, OptNoReply },
+ { "to", required_argument, 0, OptTo },
+ { "from", required_argument, 0, OptFrom },
+ { "show-topology", no_argument, 0, OptShowTopology },
+
+ { "tv", no_argument, 0, OptTV },
+ { "record", no_argument, 0, OptRecord },
+ { "tuner", no_argument, 0, OptTuner },
+ { "playback", no_argument, 0, OptPlayback },
+ { "audio", no_argument, 0, OptAudio },
+ { "processor", no_argument, 0, OptProcessor },
+ { "switch", no_argument, 0, OptSwitch },
+ { "cdc-only", no_argument, 0, OptCDCOnly },
+ { "unregistered", no_argument, 0, OptUnregistered },
+ { "help-all", no_argument, 0, OptHelpAll },
+
+ CEC_LONG_OPTS
+
+ { 0, 0, 0, 0 }
+};
+
+static void usage(void)
+{
+ printf("Usage:\n"
+ " -d, --device=<dev> Use device <dev> instead of /dev/cec0\n"
+ " If <dev> starts with a digit, then /dev/cec<dev> is used.\n"
+ " -h, --help Display this help message\n"
+ " -T, --trace Trace all called ioctls.\n"
+ " -v, --verbose Turn on verbose reporting.\n"
+ " -a, --phys-addr=<addr>\n"
+ " Use this physical address.\n"
+ " -D, --disable Disable CEC adapter.\n"
+ " -E, --enable Enable CEC adapter.\n"
+ " -C, --clear Clear all logical addresses.\n"
+ " -m, --monitor Monitor CEC traffic.\n"
+ " -V, --vendor-id=<id>\n"
+ " Use this vendor ID.\n"
+ " -n, --no-reply Don't wait for a reply.\n"
+ " -S, --show-topology Show the CEC topology.\n"
+ " -t, --to=<la> Send message to the given logical address.\n"
+ " -f, --from=<la> Send message from the given logical address.\n"
+ " By default use the first assigned logical address.\n"
+ " --cec-version-1.4 Use CEC Version 1.4 instead of 2.0\n"
+ " --tv This is a TV\n"
+ " --record This is a recording device\n"
+ " --tuner This is a tuner device\n"
+ " --playback This is a playback device\n"
+ " --audio This is an audio system device\n"
+ " --processor This is a processor device\n"
+ " --switch This is a pure CEC switch\n"
+ " --cdc-only This is a CDC-only device\n"
+ " --unregistered This is an unregistered device\n"
+ "\n"
+ " --help-all Show all messages\n"
+ CEC_USAGE
+ );
+}
+
+static std::string caps2s(unsigned caps)
+{
+ std::string s;
+
+ if (caps & CEC_CAP_STATE)
+ s += "\t\tState\n";
+ if (caps & CEC_CAP_PHYS_ADDR)
+ s += "\t\tPhysical Address\n";
+ if (caps & CEC_CAP_LOG_ADDRS)
+ s += "\t\tLogical Addresses\n";
+ if (caps & CEC_CAP_IO)
+ s += "\t\tI/O\n";
+ if (caps & CEC_CAP_VENDOR_ID)
+ s += "\t\tVendor ID\n";
+ if (caps & CEC_CAP_PASSTHROUGH)
+ s += "\t\tPassthrough\n";
+ if (caps & CEC_CAP_RC)
+ s += "\t\tRemote Control Support\n";
+ if (caps & CEC_CAP_ARC)
+ s += "\t\tAudio Return Channel\n";
+ if (caps & CEC_CAP_CDC_HPD)
+ s += "\t\tCapability Discovery and Control HPD\n";
+ if (caps & CEC_CAP_IS_SOURCE)
+ s += "\t\tIs Source\n";
+ return s;
+}
+
+static const char *version2s(unsigned version)
+{
+ switch (version) {
+ case CEC_OP_CEC_VERSION_1_3A:
+ return "1.3a";
+ case CEC_OP_CEC_VERSION_1_4:
+ return "1.4";
+ case CEC_OP_CEC_VERSION_2_0:
+ return "2.0";
+ default:
+ return "Unknown";
+ }
+}
+
+static const char *power_status2s(unsigned status)
+{
+ switch (status) {
+ case CEC_OP_POWER_STATUS_ON:
+ return "On";
+ case CEC_OP_POWER_STATUS_STANDBY:
+ return "Standby";
+ case CEC_OP_POWER_STATUS_TO_ON:
+ return "In Transition Standby to On";
+ case CEC_OP_POWER_STATUS_TO_STANDBY:
+ return "In Transition On to Standby";
+ default:
+ return "Unknown";
+ }
+}
+
+static const char *prim_type2s(unsigned type)
+{
+ switch (type) {
+ case CEC_OP_PRIM_DEVTYPE_TV:
+ return "TV";
+ case CEC_OP_PRIM_DEVTYPE_RECORD:
+ return "Record";
+ case CEC_OP_PRIM_DEVTYPE_TUNER:
+ return "Tuner";
+ case CEC_OP_PRIM_DEVTYPE_PLAYBACK:
+ return "Playback";
+ case CEC_OP_PRIM_DEVTYPE_AUDIOSYSTEM:
+ return "Audio System";
+ case CEC_OP_PRIM_DEVTYPE_SWITCH:
+ return "Switch";
+ case CEC_OP_PRIM_DEVTYPE_PROCESSOR:
+ return "Processor";
+ default:
+ return "Unknown";
+ }
+}
+
+static const char *la_type2s(unsigned type)
+{
+ switch (type) {
+ case CEC_LOG_ADDR_TYPE_TV:
+ return "TV";
+ case CEC_LOG_ADDR_TYPE_RECORD:
+ return "Record";
+ case CEC_LOG_ADDR_TYPE_TUNER:
+ return "Tuner";
+ case CEC_LOG_ADDR_TYPE_PLAYBACK:
+ return "Playback";
+ case CEC_LOG_ADDR_TYPE_AUDIOSYSTEM:
+ return "Audio System";
+ case CEC_LOG_ADDR_TYPE_SPECIFIC:
+ return "Specific";
+ case CEC_LOG_ADDR_TYPE_UNREGISTERED:
+ return "Unregistered";
+ default:
+ return "Unknown";
+ }
+}
+
+static const char *la2s(unsigned la)
+{
+ switch (la & 0xf) {
+ case 0:
+ return "TV";
+ case 1:
+ return "Recording Device 1";
+ case 2:
+ return "Recording Device 2";
+ case 3:
+ return "Tuner 1";
+ case 4:
+ return "Playback Device 1";
+ case 5:
+ return "Audio System";
+ case 6:
+ return "Tuner 2";
+ case 7:
+ return "Tuner 3";
+ case 8:
+ return "Playback Device 2";
+ case 9:
+ return "Playback Device 3";
+ case 10:
+ return "Tuner 4";
+ case 11:
+ return "Playback Device 3";
+ case 12:
+ return "Reserved 1";
+ case 13:
+ return "Reserved 2";
+ case 14:
+ return "Specific";
+ case 15:
+ default:
+ return "Unregistered";
+ }
+}
+
+static std::string all_dev_types2s(unsigned types)
+{
+ std::string s;
+
+ if (types & CEC_OP_ALL_DEVTYPE_TV)
+ s += "TV, ";
+ if (types & CEC_OP_ALL_DEVTYPE_RECORD)
+ s += "Record, ";
+ if (types & CEC_OP_ALL_DEVTYPE_TUNER)
+ s += "Tuner, ";
+ if (types & CEC_OP_ALL_DEVTYPE_PLAYBACK)
+ s += "Playback, ";
+ if (types & CEC_OP_ALL_DEVTYPE_AUDIOSYSTEM)
+ s += "Audio System, ";
+ if (types & CEC_OP_ALL_DEVTYPE_SWITCH)
+ s += "Switch, ";
+ if (s.length())
+ return s.erase(s.length() - 2, 2);
+ return s;
+}
+
+static std::string rc_src_prof2s(unsigned prof)
+{
+ std::string s;
+
+ prof &= 0x1f;
+ if (prof == 0)
+ return "\t\tNone\n";
+ if (prof & CEC_OP_FEAT_RC_SRC_HAS_DEV_ROOT_MENU)
+ s += "\t\tSource Has Device Root Menu\n";
+ if (prof & CEC_OP_FEAT_RC_SRC_HAS_DEV_SETUP_MENU)
+ s += "\t\tSource Has Device Setup Menu\n";
+ if (prof & CEC_OP_FEAT_RC_SRC_HAS_MEDIA_CONTEXT_MENU)
+ s += "\t\tSource Has Contents Menu\n";
+ if (prof & CEC_OP_FEAT_RC_SRC_HAS_MEDIA_TOP_MENU)
+ s += "\t\tSource Has Media Top Menu\n";
+ if (prof & CEC_OP_FEAT_RC_SRC_HAS_MEDIA_CONTEXT_MENU)
+ s += "\t\tSource Has Media Context-Sensitive Menu\n";
+ return s;
+}
+
+static std::string dev_feat2s(unsigned feat)
+{
+ std::string s;
+
+ feat &= 0x3e;
+ if (feat == 0)
+ return "\t\tNone\n";
+ if (feat & CEC_OP_FEAT_DEV_HAS_RECORD_TV_SCREEN)
+ s += "\t\tTV Supports <Record TV Screen>\n";
+ if (feat & CEC_OP_FEAT_DEV_HAS_SET_OSD_STRING)
+ s += "\t\tTV Supports <Set OSD String>\n";
+ if (feat & CEC_OP_FEAT_DEV_HAS_DECK_CONTROL)
+ s += "\t\tSupports Deck Control\n";
+ if (feat & CEC_OP_FEAT_DEV_HAS_SET_AUDIO_RATE)
+ s += "\t\tSource Supports <Set Audio Rate>\n";
+ if (feat & CEC_OP_FEAT_DEV_SINK_HAS_ARC_TX)
+ s += "\t\tSink Supports ARC Tx\n";
+ if (feat & CEC_OP_FEAT_DEV_SOURCE_HAS_ARC_RX)
+ s += "\t\tSource Supports ARC Rx\n";
+ return s;
+}
+
+static const char *event_state2s(__u8 state)
+{
+ switch (state) {
+ case CEC_EVENT_STATE_DISABLED:
+ return "Disabled";
+ case CEC_EVENT_STATE_UNCONFIGURED:
+ return "Unconfigured";
+ case CEC_EVENT_STATE_CONFIGURING:
+ return "Configuring";
+ case CEC_EVENT_STATE_CONFIGURED:
+ return "Configured";
+ default:
+ return "Unknown";
+ }
+}
+
+int cec_named_ioctl(int fd, const char *name,
+ unsigned long int request, void *parm)
+{
+ int retval = ioctl(fd, request, parm);
+ int e;
+
+ e = retval == 0 ? 0 : errno;
+ if (options[OptTrace])
+ printf("\t\t%s returned %d (%s)\n",
+ name, retval, strerror(e));
+
+ return retval == -1 ? e : (retval ? -1 : 0);
+}
+
+static void log_event(struct cec_event &ev)
+{
+ switch (ev.event) {
+ case CEC_EVENT_STATE_CHANGE:
+ printf("Event: State Change: %s\n",
+ event_state2s(ev.state_change.state));
+ break;
+ case CEC_EVENT_INPUTS_CHANGE:
+ printf("Event: Inputs Change: Connected: 0x%04x Changed: 0x%04x\n",
+ ev.inputs_change.connected_inputs,
+ ev.inputs_change.changed_inputs);
+ break;
+ case CEC_EVENT_LOST_MSGS:
+ printf("Event: Lost Messages\n");
+ break;
+ default:
+ printf("Event: Unknown (0x%x)\n", ev.event);
+ break;
+ }
+ printf("\tTimestamp: %llu.%09llus\n", ev.ts / 1000000000, ev.ts % 1000000000);
+}
+
+static int showTopologyDevice(struct node *node, unsigned i, unsigned la)
+{
+ struct cec_msg msg;
+ char osd_name[15];
+
+ printf("\tSystem Information for device %d (%s) from device %d (%s):\n",
+ i, la2s(i), la, la2s(la));
+
+ cec_msg_init(&msg, la, i);
+ cec_msg_get_cec_version(&msg, true);
+ doioctl(node, CEC_TRANSMIT, &msg);
+ printf("\t\tCEC Version : %s\n",
+ msg.status ? status2s(msg.status).c_str() : version2s(msg.msg[2]));
+
+ cec_msg_init(&msg, la, i);
+ cec_msg_give_physical_addr(&msg, true);
+ doioctl(node, CEC_TRANSMIT, &msg);
+ printf("\t\tPhysical Address : ");
+ if (msg.status) {
+ printf("%s\n", status2s(msg.status).c_str());
+ } else {
+ __u16 phys_addr = (msg.msg[2] << 8) | msg.msg[3];
+
+ printf("%x.%x.%x.%x\n",
+ phys_addr >> 12, (phys_addr >> 8) & 0xf,
+ (phys_addr >> 4) & 0xf, phys_addr & 0xf);
+ printf("\t\tPrimary Device Type : %s\n",
+ prim_type2s(msg.msg[4]));
+ }
+
+ cec_msg_init(&msg, la, i);
+ cec_msg_give_device_vendor_id(&msg, true);
+ doioctl(node, CEC_TRANSMIT, &msg);
+ printf("\t\tVendor ID : ");
+ if (msg.status)
+ printf("%s\n", status2s(msg.status).c_str());
+ else
+ printf("0x%02x%02x%02x\n",
+ msg.msg[2], msg.msg[3], msg.msg[4]);
+
+ cec_msg_init(&msg, la, i);
+ cec_msg_give_device_power_status(&msg, true);
+ doioctl(node, CEC_TRANSMIT, &msg);
+ printf("\t\tPower Status : %s\n",
+ msg.status ? status2s(msg.status).c_str() : power_status2s(msg.msg[2]));
+
+ cec_msg_init(&msg, la, i);
+ cec_msg_give_osd_name(&msg, true);
+ doioctl(node, CEC_TRANSMIT, &msg);
+ cec_ops_set_osd_name(&msg, osd_name);
+ printf("\t\tOSD Name : %s\n",
+ msg.status ? status2s(msg.status).c_str() : osd_name);
+ return 0;
+}
+
+static int showTopology(struct node *node)
+{
+ struct cec_msg msg = { };
+ struct cec_log_addrs laddrs = { };
+
+ if (!(node->caps & CEC_CAP_IO))
+ return -ENOTTY;
+
+ doioctl(node, CEC_ADAP_G_LOG_ADDRS, &laddrs);
+
+ for (unsigned i = 0; i < 15; i++) {
+ int ret;
+
+ cec_msg_init(&msg, 0xf, i);
+ ret = doioctl(node, CEC_TRANSMIT, &msg);
+
+ switch (msg.status) {
+ case CEC_TX_STATUS_OK:
+ showTopologyDevice(node, i, laddrs.log_addr[0]);
+ break;
+ case CEC_TX_STATUS_ARB_LOST:
+ if (show_info)
+ printf("\t\ttx arbitration lost for addr %d\n", i);
+ break;
+ case CEC_TX_STATUS_RETRY_TIMEOUT:
+ break;
+ default:
+ if (show_info)
+ printf("\t\tunknown status %d\n", ret);
+ break;
+ }
+ }
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ const char *device = "/dev/cec0"; /* -d device */
+ const message *opt;
+ msg_vec msgs;
+ char short_options[26 * 2 * 2 + 1];
+ __u32 vendor_id;
+ __u32 adap_state;
+ __u16 phys_addr;
+ __u8 from = 0, to = 0;
+ bool reply = true;
+ int idx = 0;
+ int fd = -1;
+ int ch;
+ int i;
+
+ init_messages();
+
+ for (i = 0; long_options[i].name; i++) {
+ if (!isalpha(long_options[i].val))
+ continue;
+ short_options[idx++] = long_options[i].val;
+ if (long_options[i].has_arg == required_argument)
+ short_options[idx++] = ':';
+ }
+ while (1) {
+ int option_index = 0;
+ struct cec_msg msg;
+
+ short_options[idx] = 0;
+ ch = getopt_long(argc, argv, short_options,
+ long_options, &option_index);
+ if (ch == -1)
+ break;
+
+ if (ch > OptMessages)
+ cec_msg_init(&msg, 0, 0);
+ options[(int)ch] = 1;
+
+ switch (ch) {
+ case OptHelp:
+ usage();
+ return 0;
+ case OptSetDevice:
+ device = optarg;
+ if (device[0] >= '0' && device[0] <= '9' && strlen(device) <= 3) {
+ static char newdev[20];
+
+ sprintf(newdev, "/dev/cec%s", device);
+ device = newdev;
+ }
+ break;
+ case OptVerbose:
+ show_info = true;
+ break;
+ case OptFrom:
+ from = strtoul(optarg, NULL, 0) & 0xf;
+ break;
+ case OptTo:
+ to = strtoul(optarg, NULL, 0) & 0xf;
+ break;
+ case OptNoReply:
+ reply = false;
+ break;
+ case OptPhysAddr:
+ phys_addr = strtoul(optarg, NULL, 0);
+ break;
+ case OptVendorID:
+ vendor_id = strtoul(optarg, NULL, 0) & 0x00ffffff;
+ break;
+ case OptAdapDisable:
+ adap_state = CEC_ADAP_DISABLED;
+ break;
+ case OptAdapEnable:
+ adap_state = CEC_ADAP_ENABLED;
+ break;
+ case OptSwitch:
+ if (options[OptCDCOnly] || options[OptUnregistered]) {
+ fprintf(stderr, "--switch cannot be combined with --cdc-only or --unregistered.\n");
+ usage();
+ return 1;
+ }
+ break;
+ case OptCDCOnly:
+ if (options[OptSwitch] || options[OptUnregistered]) {
+ fprintf(stderr, "--cdc-only cannot be combined with --switch or --unregistered.\n");
+ usage();
+ return 1;
+ }
+ break;
+ case OptUnregistered:
+ if (options[OptCDCOnly] || options[OptSwitch]) {
+ fprintf(stderr, "--unregistered cannot be combined with --cdc-only or --switch.\n");
+ usage();
+ return 1;
+ }
+ break;
+ case ':':
+ fprintf(stderr, "Option '%s' requires a value\n",
+ argv[optind]);
+ usage();
+ return 1;
+ case '?':
+ if (argv[optind])
+ fprintf(stderr, "Unknown argument '%s'\n", argv[optind]);
+ usage();
+ return 1;
+ default:
+ if (ch >= OptHelpAll) {
+ usage_options(ch);
+ exit(0);
+ }
+ if (ch < OptMessages)
+ break;
+ opt = opt2message[ch - OptMessages];
+ parse_msg_args(msg, reply, opt, ch);
+ msgs.push_back(msg);
+ break;
+ }
+ }
+ if (optind < argc) {
+ printf("unknown arguments: ");
+ while (optind < argc)
+ printf("%s ", argv[optind++]);
+ printf("\n");
+ usage();
+ return 1;
+ }
+
+ if ((fd = open(device, O_RDWR)) < 0) {
+ fprintf(stderr, "Failed to open %s: %s\n", device,
+ strerror(errno));
+ exit(1);
+ }
+
+ struct node node;
+ struct cec_caps caps = { };
+
+ node.fd = fd;
+ node.device = device;
+ doioctl(&node, CEC_ADAP_G_CAPS, &caps);
+ node.caps = caps.capabilities;
+ node.available_log_addrs = caps.available_log_addrs;
+
+ unsigned flags = 0;
+ const char *osd_name;
+
+ if (options[OptTV])
+ osd_name = "TV";
+ else if (options[OptRecord])
+ osd_name = "Record";
+ else if (options[OptPlayback])
+ osd_name = "Playback";
+ else if (options[OptTuner])
+ osd_name = "Tuner";
+ else if (options[OptAudio])
+ osd_name = "Audio System";
+ else if (options[OptProcessor])
+ osd_name = "Processor";
+ else if (options[OptSwitch] || options[OptCDCOnly] || options[OptUnregistered])
+ osd_name = "";
+ else
+ osd_name = "TV";
+
+ if (options[OptTV])
+ flags |= 1 << CEC_OP_PRIM_DEVTYPE_TV;
+ if (options[OptRecord])
+ flags |= 1 << CEC_OP_PRIM_DEVTYPE_RECORD;
+ if (options[OptTuner])
+ flags |= 1 << CEC_OP_PRIM_DEVTYPE_TUNER;
+ if (options[OptPlayback])
+ flags |= 1 << CEC_OP_PRIM_DEVTYPE_PLAYBACK;
+ if (options[OptAudio])
+ flags |= 1 << CEC_OP_PRIM_DEVTYPE_AUDIOSYSTEM;
+ if (options[OptProcessor])
+ flags |= 1 << CEC_OP_PRIM_DEVTYPE_PROCESSOR;
+ if (options[OptSwitch] || options[OptCDCOnly] || options[OptUnregistered])
+ flags |= 1 << CEC_OP_PRIM_DEVTYPE_SWITCH;
+
+ printf("Driver Info:\n");
+ printf("\tCapabilities : 0x%08x\n", caps.capabilities);
+ printf("%s", caps2s(caps.capabilities).c_str());
+ printf("\tInputs : %u\n", caps.ninputs);
+ printf("\tAvailable Logical Addresses: %u\n",
+ caps.available_log_addrs);
+
+ if ((node.caps & CEC_CAP_LOG_ADDRS) && options[OptClear]) {
+ struct cec_log_addrs laddrs = { };
+
+ doioctl(&node, CEC_ADAP_S_LOG_ADDRS, &laddrs);
+ }
+
+ if ((node.caps & CEC_CAP_PHYS_ADDR) && options[OptPhysAddr])
+ doioctl(&node, CEC_ADAP_S_PHYS_ADDR, &phys_addr);
+ doioctl(&node, CEC_ADAP_G_PHYS_ADDR, &phys_addr);
+ printf("\tPhysical Address : %x.%x.%x.%x\n",
+ phys_addr >> 12, (phys_addr >> 8) & 0xf,
+ (phys_addr >> 4) & 0xf, phys_addr & 0xf);
+ if (!options[OptPhysAddr] && phys_addr == 0xffff &&
+ (node.caps & CEC_CAP_PHYS_ADDR))
+ printf("Perhaps you should use option --phys-addr?\n");
+
+ if (node.caps & CEC_CAP_VENDOR_ID) {
+ if (!options[OptVendorID]) {
+ doioctl(&node, CEC_ADAP_G_VENDOR_ID, &vendor_id);
+ if (vendor_id == CEC_VENDOR_ID_NONE)
+ vendor_id = 0x000c03; /* HDMI LLC vendor ID */
+ }
+ doioctl(&node, CEC_ADAP_S_VENDOR_ID, &vendor_id);
+ }
+ doioctl(&node, CEC_ADAP_G_VENDOR_ID, &vendor_id);
+ if (vendor_id != CEC_VENDOR_ID_NONE)
+ printf("\tVendor ID : 0x%06x\n", vendor_id);
+
+ if ((node.caps & CEC_CAP_STATE) &&
+ (options[OptAdapEnable] || options[OptAdapDisable]))
+ doioctl(&node, CEC_ADAP_S_STATE, &adap_state);
+ doioctl(&node, CEC_ADAP_G_STATE, &adap_state);
+ printf("\tAdapter State : %s\n", adap_state ? "Enabled" : "Disabled");
+ if (adap_state == CEC_ADAP_DISABLED)
+ return 0;
+
+ if ((node.caps & CEC_CAP_LOG_ADDRS) && flags) {
+ struct cec_log_addrs laddrs;
+
+ memset(&laddrs, 0, sizeof(laddrs));
+ doioctl(&node, CEC_ADAP_S_LOG_ADDRS, &laddrs);
+ memset(&laddrs, 0, sizeof(laddrs));
+
+ laddrs.cec_version = options[OptCECVersion1_4] ?
+ CEC_OP_CEC_VERSION_1_4 : CEC_OP_CEC_VERSION_2_0;
+ strcpy(laddrs.osd_name, osd_name);
+
+ for (unsigned i = 0; i < 8; i++) {
+ unsigned la_type;
+ unsigned all_dev_type;
+
+ if (!(flags & (1 << i)))
+ continue;
+ if (laddrs.num_log_addrs == node.available_log_addrs) {
+ fprintf(stderr, "Attempt to define too many logical addresses\n");
+ exit(-1);
+ }
+ switch (i) {
+ case CEC_OP_PRIM_DEVTYPE_TV:
+ la_type = CEC_LOG_ADDR_TYPE_TV;
+ all_dev_type = CEC_OP_ALL_DEVTYPE_TV;
+ break;
+ case CEC_OP_PRIM_DEVTYPE_RECORD:
+ la_type = CEC_LOG_ADDR_TYPE_RECORD;
+ all_dev_type = CEC_OP_ALL_DEVTYPE_RECORD;
+ break;
+ case CEC_OP_PRIM_DEVTYPE_TUNER:
+ la_type = CEC_LOG_ADDR_TYPE_TUNER;
+ all_dev_type = CEC_OP_ALL_DEVTYPE_TUNER;
+ break;
+ case CEC_OP_PRIM_DEVTYPE_PLAYBACK:
+ la_type = CEC_LOG_ADDR_TYPE_PLAYBACK;
+ all_dev_type = CEC_OP_ALL_DEVTYPE_PLAYBACK;
+ break;
+ case CEC_OP_PRIM_DEVTYPE_AUDIOSYSTEM:
+ la_type = CEC_LOG_ADDR_TYPE_AUDIOSYSTEM;
+ all_dev_type = CEC_OP_ALL_DEVTYPE_AUDIOSYSTEM;
+ break;
+ case CEC_OP_PRIM_DEVTYPE_PROCESSOR:
+ la_type = CEC_LOG_ADDR_TYPE_SPECIFIC;
+ all_dev_type = CEC_OP_ALL_DEVTYPE_SWITCH;
+ break;
+ case CEC_OP_PRIM_DEVTYPE_SWITCH:
+ default:
+ la_type = CEC_LOG_ADDR_TYPE_UNREGISTERED;
+ all_dev_type = CEC_OP_ALL_DEVTYPE_SWITCH;
+ break;
+ }
+ laddrs.log_addr_type[laddrs.num_log_addrs] = la_type;
+ laddrs.all_device_types[laddrs.num_log_addrs] = all_dev_type;
+ laddrs.primary_device_type[laddrs.num_log_addrs++] = i;
+ }
+
+ doioctl(&node, CEC_ADAP_S_LOG_ADDRS, &laddrs);
+ }
+
+ struct cec_log_addrs laddrs = { };
+ doioctl(&node, CEC_ADAP_G_LOG_ADDRS, &laddrs);
+ node.num_log_addrs = laddrs.num_log_addrs;
+ printf("\tCEC Version : %s\n", version2s(laddrs.cec_version));
+ printf("\tLogical Addresses : %u\n", laddrs.num_log_addrs);
+ for (unsigned i = 0; i < laddrs.num_log_addrs; i++) {
+ printf("\n\t Logical Address : %d (%s)\n",
+ laddrs.log_addr[i], la2s(laddrs.log_addr[i]));
+ printf("\t Primary Device Type : %s\n",
+ prim_type2s(laddrs.primary_device_type[i]));
+ printf("\t Logical Address Type : %s\n",
+ la_type2s(laddrs.log_addr_type[i]));
+ if (laddrs.cec_version < CEC_OP_CEC_VERSION_2_0)
+ continue;
+ printf("\t All Device Types : %s\n",
+ all_dev_types2s(laddrs.all_device_types[i]).c_str());
+
+ bool is_dev_feat = false;
+ for (unsigned idx = 0; idx < sizeof(laddrs.features[0]); idx++) {
+ __u8 byte = laddrs.features[i][idx];
+
+ if (!is_dev_feat) {
+ if (byte & 0x40) {
+ printf("\t RC Source Profile :\n%s\n",
+ rc_src_prof2s(byte).c_str());
+ } else {
+ const char *s = "Reserved";
+
+ switch (byte & 0xf) {
+ case 0:
+ s = "None";
+ break;
+ case 2:
+ s = "RC Profile 1";
+ break;
+ case 6:
+ s = "RC Profile 2";
+ break;
+ case 10:
+ s = "RC Profile 3";
+ break;
+ case 14:
+ s = "RC Profile 4";
+ break;
+ }
+ printf("\t RC TV Profile : %s\n", s);
+ }
+ } else {
+ printf("\t Device Features :\n%s",
+ dev_feat2s(byte).c_str());
+ }
+ if (byte & CEC_OP_FEAT_EXT)
+ continue;
+ if (!is_dev_feat)
+ is_dev_feat = true;
+ else
+ break;
+ }
+ }
+ if (node.num_log_addrs == 0) {
+ if (options[OptMonitor])
+ goto monitor;
+ return 0;
+ }
+ printf("\n");
+
+ if (!options[OptFrom])
+ from = laddrs.log_addr[0];
+
+ if (options[OptShowTopology])
+ showTopology(&node);
+
+ for (msg_vec::iterator iter = msgs.begin(); iter != msgs.end(); ++iter) {
+ if (!options[OptTo]) {
+ fprintf(stderr, "attempting to send message without --to\n");
+ exit(1);
+ }
+ struct cec_msg msg = *iter;
+ bool has_reply = msg.reply;
+
+ printf("\nTransmit from %s to %s (%d to %d):\n",
+ la2s(from), to == 0xf ? "all" : la2s(to), from, to);
+ msg.msg[0] |= (from << 4) | to;
+ log_msg(msg);
+ if (doioctl(&node, CEC_TRANSMIT, &msg))
+ continue;
+ if (has_reply) {
+ printf("Received from %s (%d):\n", la2s(cec_msg_initiator(&msg)),
+ cec_msg_initiator(&msg));
+ log_msg(msg);
+ } else {
+ printf("\t%s\n", status2s(msg.status).c_str());
+ }
+ printf("\tTimestamp: %llu.%09llus\n", msg.ts / 1000000000, msg.ts % 1000000000);
+ }
+
+monitor:
+ if (options[OptMonitor]) {
+ __u32 monitor = CEC_MONITOR_ENABLED;
+ fd_set rd_fds;
+ fd_set ex_fds;
+ int fd = node.fd;
+
+ printf("\n");
+ doioctl(&node, CEC_S_MONITOR, &monitor);
+
+ fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
+ while (1) {
+ int res;
+
+ FD_ZERO(&rd_fds);
+ FD_ZERO(&ex_fds);
+ FD_SET(fd, &rd_fds);
+ FD_SET(fd, &ex_fds);
+ res = select(fd + 1, &rd_fds, NULL, &ex_fds, NULL);
+ if (res <= 0)
+ break;
+ if (FD_ISSET(fd, &rd_fds)) {
+ struct cec_msg msg = { };
+ __u8 from, to;
+
+ if (doioctl(&node, CEC_RECEIVE, &msg))
+ continue;
+
+ from = cec_msg_initiator(&msg);
+ to = cec_msg_destination(&msg);
+ printf("\nReceived from %s to %s (%d to %d):\n",
+ la2s(from), to == 0xf ? "all" : la2s(to), from, to);
+ log_msg(msg);
+ printf("\tTimestamp: %llu.%09llus\n", msg.ts / 1000000000, msg.ts % 1000000000);
+ }
+ if (FD_ISSET(fd, &ex_fds)) {
+ struct cec_event ev;
+
+ if (doioctl(&node, CEC_DQEVENT, &ev))
+ continue;
+ log_event(ev);
+ }
+ }
+ }
+
+ close(fd);
+ return 0;
+}
diff --git a/utils/cec-ctl/msg2ctl.pl b/utils/cec-ctl/msg2ctl.pl
new file mode 100644
index 0000000..af42905
--- /dev/null
+++ b/utils/cec-ctl/msg2ctl.pl
@@ -0,0 +1,430 @@
+#!/usr/bin/perl
+
+sub maxprefix {
+ my $p = shift(@_);
+ for (@_) {
+ chop $p until /^\Q$p/;
+ }
+ $p =~ s/_[^_]*$/_/;
+ $p = "CEC_OP_CEC_" if ($p =~ /CEC_OP_CEC_VERSION_/);
+ return $p;
+}
+
+sub process_func
+{
+ my $feature = shift;
+ my $func = shift;
+ my $func_args = $func;
+ $func =~ s/\(.*//;
+ my $msg = $func;
+ $msg =~ s/([a-z])/\U\1/g;
+ $func =~ s/cec_msg//;
+ my $opt = $func;
+ $opt =~ s/_([a-z])/\U\1/g;
+ $func_args =~ s/.*\((.*)\).*/\1/;
+ my $has_reply = $func_args =~ /^bool reply/;
+ $func_args =~ s/^bool reply,? ?//;
+ my $arg_names;
+ my $arg_ptrs;
+ my $name, $type, $size;
+ my $msg_dash_name, $msg_lc_name;
+ my @enum, $val;
+ my $usage;
+ my $has_digital = $func_args =~ /cec_op_digital_service_id/;
+
+ my @ops_args = split(/, */, $func_args);
+ if ($has_digital) {
+ $func_args =~ s/const struct cec_op_digital_service_id \*digital/__u8 service_id_method, __u8 dig_bcast_system, __u16 transport_id, __u16 service_id, __u16 orig_network_id, __u16 program_number, __u8 channel_number_fmt, __u16 major, __u16 minor/;
+ }
+ my @args = split(/, */, $func_args);
+ my $has_struct = $func_args =~ /struct/;
+ return if ($func_args =~ /__u\d+\s*\*/);
+
+ my $cec_msg = $msg;
+ while ($cec_msg ne "" && !exists($msgs{$cec_msg})) {
+ $cec_msg =~ s/_[^_]*$//;
+ }
+ return if ($cec_msg eq "");
+
+ my $msg_name = $cec_msg;
+ $msg_name =~ s/CEC_MSG_//;
+ $msg_dash_name = $msg;
+ $msg_dash_name =~ s/CEC_MSG_//;
+ $msg_dash_name =~ s/([A-Z])/\l\1/g;
+ $msg_dash_name =~ s/_/-/g;
+ $msg_lc_name = $msg;
+ $msg_lc_name =~ s/([A-Z])/\l\1/g;
+
+ if ($cec_msg eq $msg) {
+ if ($cec_msg =~ /_CDC_/ && !$cdc_case) {
+ $cdc_case = 1;
+ $logswitch .= "\tcase CEC_MSG_CDC_MESSAGE:\n";
+ $logswitch .= "\tswitch (msg.msg[4]) {\n";
+ }
+ if (@args == 0) {
+ $logswitch .= "\tcase $cec_msg:\n";
+ $logswitch .= "\t\tprintf(\"$cec_msg:\\n\");\n";
+ $logswitch .= "\t\tbreak;\n\n";
+ } else {
+ $logswitch .= "\tcase $cec_msg: {\n";
+ foreach (@ops_args) {
+ ($type, $name) = /(.*?) ?([a-zA-Z_]\w+)$/;
+ if ($type =~ /struct .*\*/) {
+ $type =~ s/ \*//;
+ $type =~ s/const //;
+ }
+ if ($name eq "rc_profile" || $name eq "dev_features") {
+ $logswitch .= "\t\tconst __u8 *$name = NULL;\n";
+ } elsif ($type eq "const char *") {
+ $logswitch .= "\t\tchar $name\[16\];\n";
+ } else {
+ $logswitch .= "\t\t$type $name;\n";
+ }
+ }
+ if ($cdc_case) {
+ $logswitch .= "\t\t__u16 phys_addr;\n";
+ }
+ my $ops_lc_name = $msg_lc_name;
+ $ops_lc_name =~ s/^cec_msg/cec_ops/;
+ $logswitch .= "\n\t\t$ops_lc_name(&msg";
+ if ($cdc_case) {
+ $logswitch .= ", &phys_addr";
+ }
+ foreach (@ops_args) {
+ ($type, $name) = /(.*?) ?([a-zA-Z_]\w+)$/;
+ if ($type eq "const char *") {
+ $logswitch .= ", $name";
+ } else {
+ $logswitch .= ", &$name";
+ }
+ }
+ $logswitch .= ");\n";
+ $logswitch .= "\t\tprintf(\"$cec_msg:\\n\");\n";
+ if ($cdc_case) {
+ $logswitch .= "\t\tlog_arg(&arg_phys_addr, \"phys-addr\", phys_addr);\n";
+ }
+ foreach (@ops_args) {
+ ($type, $name) = /(.*?) ?([a-zA-Z_]\w+)$/;
+ my $dash_name = $name;
+ $dash_name =~ s/_/-/g;
+ if ($name eq "rc_profile" || $name eq "dev_features") {
+ $logswitch .= "\t\tlog_features(&arg_$name, \"$dash_name\", $name);\n";
+ } elsif ($name eq "digital") {
+ $logswitch .= "\t\tlog_digital(\"$dash_name\", &$name);\n";
+ } elsif ($name eq "rec_src") {
+ $logswitch .= "\t\tlog_rec_src(\"$dash_name\", &$name);\n";
+ } elsif ($name eq "tuner_dev_info") {
+ $logswitch .= "\t\tlog_tuner_dev_info(\"$dash_name\", &$name);\n";
+ } elsif ($name eq "ui_cmd") {
+ $logswitch .= "\t\tlog_arg(&arg_rc_$name, \"$dash_name\", $name);\n";
+ } else {
+ $logswitch .= "\t\tlog_arg(&arg_$name, \"$dash_name\", $name);\n";
+ }
+ }
+ $logswitch .= "\t\tbreak;\n\t}\n";
+ }
+ }
+ return if $has_struct;
+
+ $options .= "\tOpt$opt,\n";
+ $messages .= "\t\t$cec_msg,\n";
+ $messages .= "\t\tOpt$opt,\n";
+ if (@args == 0) {
+ $messages .= "\t\t0, { }, { },\n";
+ $long_opts .= "\t{ \"$msg_dash_name\", no_argument, 0, Opt$opt }, \\\n";
+ $usage .= "\t\" --" . sprintf("%-30s", $msg_dash_name) . "Send $msg_name message (\" xstr($cec_msg) \")\\n\"\n";
+ $usage_msg{$msg} = $usage;
+ $switch .= "\tcase Opt$opt: {\n";
+ $switch .= "\t\t$msg_lc_name(&msg";
+ $switch .= ", reply" if $has_reply;
+ $switch .= ");\n\t\tbreak;\n\t}\n\n";
+ } else {
+ $long_opts .= "\t{ \"$msg_dash_name\", required_argument, 0, Opt$opt }, \\\n";
+ $usage .= "\t\" --$msg_dash_name";
+ my $prefix = "\t\" " . sprintf("%-30s", " ");
+ my $sep = "=";
+ foreach (@args) {
+ ($type, $name) = /(.*?) ?([a-zA-Z_]\w+)$/;
+ $name =~ s/_/-/g;
+ $usage .= "$sep$name=<val>";
+ $sep = ",";
+ }
+ $usage .= "\\n\"\n";
+ foreach (@args) {
+ ($type, $name) = /(.*?) ?([a-zA-Z_]\w+)$/;
+ @enum = @{$types{$name}};
+ next if !scalar(@enum);
+ $name =~ s/_/-/g;
+ $usage .= $prefix . "'$name' can have these values:\\n\"\n";
+ my $common_prefix = maxprefix(@enum);
+ foreach (@enum) {
+ my $e = $_;
+ s/^$common_prefix//;
+ s/([A-Z])/\l\1/g;
+ s/_/-/g;
+ $usage .= $prefix . " $_ (\" xstr($e) \")\\n\"\n";
+ }
+ }
+ $usage .= $prefix . "Send $msg_name message (\" xstr($cec_msg) \")\\n\"\n";
+ $usage_msg{$msg} = $usage;
+ $switch .= "\tcase Opt$opt: {\n";
+ foreach (@args) {
+ ($type, $name) = /(.*?) ?([a-zA-Z_]\w+)$/;
+ if ($type =~ /char/) {
+ $switch .= "\t\tconst char *$name = \"\";\n";
+ } else {
+ $switch .= "\t\t$type $name = 0;\n";
+ }
+ }
+ $switch .= "\n\t\twhile (*subs != '\\0') {\n";
+ $switch .= "\t\t\tswitch (parse_subopt(&subs, opt->arg_names, &value)) {\n";
+ my $cnt = 0;
+ foreach (@args) {
+ ($type, $name) = /(.*?) ?([a-zA-Z_]\w+)$/;
+ @enum = @{$types{$name}};
+ $switch .= "\t\t\tcase $cnt:\n";
+ $cnt++;
+ if ($type =~ /char/) {
+ $switch .= "\t\t\t\t$name = value;\n";
+ } elsif (scalar(@enum)) {
+ $switch .= "\t\t\t\t$name = parse_enum(value, opt->args\[1\]);\n";
+ } else {
+ $switch .= "\t\t\t\t$name = strtol(value, 0L, 0);\n";
+ }
+ $switch .= "\t\t\t\tbreak;\n";
+ }
+ $switch .= "\t\t\tdefault:\n";
+ $switch .= "\t\t\t\texit(1);\n";
+ $switch .= "\t\t\t}\n\t\t}\n";
+ $switch .= "\t\t$msg_lc_name(&msg";
+ $switch .= ", reply" if $has_reply;
+ foreach (@args) {
+ ($type, $name) = /(.*?) ?([a-zA-Z_]\w+)$/;
+ $switch .= ", $name";
+ }
+ $switch .= ");\n\t\tbreak;\n\t}\n\n";
+
+ foreach (@args) {
+ ($type, $name) = /(.*?) ?([a-zA-Z_]\w+)$/;
+ if ($arg_names ne "") {
+ $arg_names .= ", ";
+ $arg_ptrs .= ", ";
+ }
+ $arg_ptrs .= "&arg_$name";
+ $name =~ s/_/-/g;
+ $arg_names .= '"' . $name . '"';
+ }
+ $size = $#args + 1;
+ $messages .= "\t\t$size, { $arg_names },\n";
+ $messages .= "\t\t{ $arg_ptrs },\n";
+ foreach (@args) {
+ ($type, $name) = /(.*?) ?([a-zA-Z_]\w+)$/;
+ @enum = @{$types{$name}};
+ $size = scalar(@enum);
+
+ if ($size && !defined($created_enum{$name})) {
+ $created_enum{$name} = 1;
+ $enums .= "static const struct cec_enum_values type_$name\[\] = {\n";
+ my $common_prefix = maxprefix(@enum);
+ foreach (@enum) {
+ $val = $_;
+ s/^$common_prefix//;
+ s/([A-Z])/\l\1/g;
+ s/_/-/g;
+ $enums .= "\t{ \"$_\", $val },\n";
+ }
+ $enums .= "};\n\n";
+ }
+ if (!defined($created_arg{$name})) {
+ $created_arg{$name} = 1;
+ if ($type eq "__u8" && $size) {
+ $arg_structs .= "static const struct arg arg_$name = {\n";
+ $arg_structs .= "\tCEC_TYPE_ENUM, $size, type_$name\n};\n\n";
+ } elsif ($type eq "__u8") {
+ $arg_structs .= "#define arg_$name arg_u8\n";
+ } elsif ($type eq "__u16") {
+ $arg_structs .= "#define arg_$name arg_u16\n";
+ } elsif ($type eq "__u32") {
+ $arg_structs .= "#define arg_$name arg_u32\n";
+ } elsif ($type eq "const char *") {
+ $arg_structs .= "#define arg_$name arg_string\n";
+ }
+ }
+ }
+ }
+ $messages .= "\t\t\"$msg_name\"\n";
+ $messages .= "\t}, {\n";
+ $feature_usage{$feature} .= $usage;
+}
+
+while (<>) {
+ last if /\/\* Commands \*\//;
+}
+
+$comment = 0;
+$has_also = 0;
+$operand_name = "";
+$feature = "";
+
+while (<>) {
+ chomp;
+ last if /_CEC_FUNCS_H/;
+ if (/^\/\*.*Feature \*\/$/) {
+ ($feature) = /^\/\* (.*) Feature/;
+ }
+ if ($operand_name ne "" && !/^#define/) {
+ @{$types{$operand_name}} = @ops;
+ undef @ops;
+ $operand_name = "";
+ }
+ if (/\/\*.*Operand \((.*)\)/) {
+ $operand_name = $1;
+ next;
+ }
+ s/\/\*.*\*\///;
+ if ($comment) {
+ if ($has_also) {
+ if (/CEC_MSG/) {
+ ($also_msg) = /(CEC_MSG\S+)/;
+ push @{$feature_also{$feature}}, $also_msg;
+ }
+ } elsif (/^ \* Has also:$/) {
+ $has_also = 1;
+ }
+ $has_also = 0 if (/\*\//);
+ next unless /\*\//;
+ $comment = 0;
+ s/^.*\*\///;
+ }
+ if (/\/\*/) {
+ $comment = 1;
+ $has_also = 0;
+ next;
+ }
+ next if /^\s*$/;
+ if (/^\#define/) {
+ ($name, $val) = /define (\S+)\s+(\S+)/;
+ if ($name =~ /^CEC_MSG/) {
+ $msgs{$name} = 1;
+ } elsif ($operand_name ne "" && $name =~ /^CEC_OP/) {
+ push @ops, $name;
+ }
+ next;
+ }
+}
+
+while (<>) {
+ chomp;
+ if (/^\/\*.*Feature \*\/$/) {
+ ($feature) = /^\/\* (.*) Feature/;
+ }
+ s/\/\*.*\*\///;
+ if ($comment) {
+ next unless /\*\//;
+ $comment = 0;
+ s/^.*\*\///;
+ }
+ if (/\/\*/) {
+ $comment = 1;
+ next;
+ }
+ next if /^\s*$/;
+ next if /cec_msg_reply_abort/;
+ if (/^static __inline__ void cec_msg.*\(.*\)/) {
+ s/static\s__inline__\svoid\s//;
+ s/struct cec_msg \*msg, //;
+ s/struct cec_msg \*msg//;
+ process_func($feature, $_);
+ next;
+ }
+ if (/^static __inline__ void cec_msg/) {
+ $func = $_;
+ next;
+ }
+ if ($func ne "") {
+ $func .= $_;
+ next unless /\)$/;
+ $func =~ s/\s+/ /g;
+ $func =~ s/static\s__inline__\svoid\s//;
+ $func =~ s/struct cec_msg \*msg, //;
+ $func =~ s/struct cec_msg \*msg//;
+ process_func($feature, $func);
+ $func = "";
+ }
+}
+
+$options .= "\tOptHelpAll,\n";
+
+foreach (sort keys %feature_usage) {
+ $name = $_;
+ s/ /_/g;
+ s/([A-Z])/\l\1/g;
+ $usage_var = $_ . "_usage";
+ printf "static const char *$usage_var =\n";
+ $usage = $feature_usage{$name};
+ foreach (@{$feature_also{$name}}) {
+ $usage .= $feature_usage{$_};
+ }
+ chop $usage;
+ printf "%s;\n\n", $usage;
+ s/_/-/g;
+ $help_features .= sprintf("\t\" --help-%-28s Show messages for the $name feature\\n\" \\\n", $_);
+ $opt = "OptHelp" . $name;
+ $opt =~ s/ //g;
+ $help .= "\tif (options[OptHelpAll] || options\[$opt\]) {\n";
+ $help .= "\t\tprintf(\"$name Feature:\\n\");\n";
+ $help .= "\t\tprintf(\"\%s\\n\", $usage_var);\n\t}\n";
+ $options .= "\t$opt,\n";
+ $long_opts .= "\t{ \"help-$_\", no_argument, 0, $opt }, \\\n";
+}
+
+print "enum {\n\tOptMessages = 255,\n";
+printf "%s\n\tOptLast = 512\n};\n\n", $options;
+
+printf "#define CEC_LONG_OPTS \\\n%s\n\n", $long_opts;
+printf "#define CEC_OPT_FEATURES \\\n%s\n\n", $opt_features;
+printf "#define CEC_USAGE \\\n%s\n\n", $help_features;
+printf "%s%s\n", $enums, $arg_structs;
+printf "static const struct message messages[] = {\n\t{\n";
+printf "%s\t}\n};\n\n", $messages;
+printf "static void usage_options(int ch)\n{\n";
+printf "%s}\n\n", $help;
+printf "static void parse_msg_args(struct cec_msg &msg, bool reply, const message *opt, int ch)\n{\n";
+printf "\tchar *value, *subs = optarg;\n\n";
+printf "\tswitch (ch) {\n";
+$switch =~ s/service_id_method, dig_bcast_system, transport_id, service_id, orig_network_id, program_number, channel_number_fmt, major, minor/args2digital_service_id(service_id_method, dig_bcast_system, transport_id, service_id, orig_network_id, program_number, channel_number_fmt, major, minor)/g;
+printf "%s", $switch;
+printf "\t}\n};\n\n";
+
+print <<'EOF';
+static void log_msg(struct cec_msg &msg)
+{
+ if (msg.len == 1)
+ printf("CEC_MSG_POLL:\n");
+ if (msg.status && msg.status != CEC_TX_STATUS_FEATURE_ABORT) {
+ printf("\t%s\n", status2s(msg.status).c_str());
+ return;
+ }
+ if (msg.len == 1)
+ return;
+
+ switch (msg.msg[1]) {
+EOF
+printf "%s", $logswitch;
+print <<'EOF';
+ default: {
+ __u16 phys_addr = (msg.msg[2] << 8) | msg.msg[3];
+
+ printf("CDC MSG 0x%02x, %d bytes payload\n", msg.msg[4], msg.len - 5);
+ log_arg(&arg_u16, "phys-addr", phys_addr);
+ break;
+ }
+ }
+ break;
+
+ default:
+ printf("MSG %02x, %d bytes payload\n", msg.msg[1], msg.len - 2);
+ break;
+ }
+}
+EOF
--
2.1.4
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCHv2 0/4] cec-ctl/compliance: new CEC utilities
2015-08-18 8:36 [PATCHv2 0/4] cec-ctl/compliance: new CEC utilities Hans Verkuil
@ 2015-08-18 8:46 ` Hans Verkuil
2015-08-18 8:36 ` [PATCHv2 2/4] sync-with-kernel Hans Verkuil
` (3 subsequent siblings)
4 siblings, 0 replies; 7+ messages in thread
From: Hans Verkuil @ 2015-08-18 8:46 UTC (permalink / raw)
To: Hans Verkuil, linux-media
Cc: dri-devel, m.szyprowski, linux-input, linux-samsung-soc, lars,
kamil, linux
Oops, this cover letter is incomplete, here is the full cover letter:
This patch series adds two new utilities to the v4l-utils git repository
(http://git.linuxtv.org/cgit.cgi/v4l-utils.git/). It assumes that the new
CEC framework (v8) is available in the kernel:
http://www.mail-archive.com/linux-media@vger.kernel.org/msg91285.html
The first patch adds the new cec headers to the 'sync-with-kernel' target,
the second syncs with the kernel and adds the new cec headers to v4l-utils,
the third adds the compliance utility and the last adds the cec-ctl utility.
The cec-compliance utility is by no means 100% coverage, in particular the
event API and non-blocking ioctls are untested. But it is a starting point,
and a complex protocol like CEC really needs a compliance tool.
The cec-ctl utility has almost full CEC message coverage: all generated from
the cec headers, so this is easy to keep up to date.
Regards,
Hans
Changes since v1:
- cec-ctl: added CEC message logging/monitoring.
- cec-ctl: add support to clear the logical addresses.
- cec-ctl: log events.
On 08/18/15 10:36, Hans Verkuil wrote:
> Hans Verkuil (4):
> Makefile.am: copy cec headers with make sync-with-kernel
> sync-with-kernel
> cec-compliance: add new CEC compliance utility
> cec-ctl: CEC control utility
>
> Makefile.am | 4 +
> configure.ac | 2 +
> contrib/freebsd/include/linux/input.h | 29 +
> contrib/freebsd/include/linux/v4l2-controls.h | 4 +
> include/linux/cec-funcs.h | 1771 +++++++++++++++++++++++++
> include/linux/cec.h | 781 +++++++++++
> include/linux/v4l2-controls.h | 4 +
> utils/Makefile.am | 2 +
> utils/cec-compliance/Makefile.am | 3 +
> utils/cec-compliance/cec-compliance.cpp | 926 +++++++++++++
> utils/cec-compliance/cec-compliance.h | 87 ++
> utils/cec-ctl/Makefile.am | 8 +
> utils/cec-ctl/cec-ctl.cpp | 1296 ++++++++++++++++++
> utils/cec-ctl/msg2ctl.pl | 430 ++++++
> utils/keytable/parse.h | 18 +
> utils/keytable/rc_keymaps/lme2510 | 132 +-
> utils/keytable/rc_maps.cfg | 1 +
> 17 files changed, 5432 insertions(+), 66 deletions(-)
> create mode 100644 include/linux/cec-funcs.h
> create mode 100644 include/linux/cec.h
> create mode 100644 utils/cec-compliance/Makefile.am
> create mode 100644 utils/cec-compliance/cec-compliance.cpp
> create mode 100644 utils/cec-compliance/cec-compliance.h
> create mode 100644 utils/cec-ctl/Makefile.am
> create mode 100644 utils/cec-ctl/cec-ctl.cpp
> create mode 100644 utils/cec-ctl/msg2ctl.pl
>
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCHv2 0/4] cec-ctl/compliance: new CEC utilities
@ 2015-08-18 8:46 ` Hans Verkuil
0 siblings, 0 replies; 7+ messages in thread
From: Hans Verkuil @ 2015-08-18 8:46 UTC (permalink / raw)
To: Hans Verkuil, linux-media
Cc: linux-samsung-soc, linux, kamil, dri-devel, lars, linux-input,
m.szyprowski
Oops, this cover letter is incomplete, here is the full cover letter:
This patch series adds two new utilities to the v4l-utils git repository
(http://git.linuxtv.org/cgit.cgi/v4l-utils.git/). It assumes that the new
CEC framework (v8) is available in the kernel:
http://www.mail-archive.com/linux-media@vger.kernel.org/msg91285.html
The first patch adds the new cec headers to the 'sync-with-kernel' target,
the second syncs with the kernel and adds the new cec headers to v4l-utils,
the third adds the compliance utility and the last adds the cec-ctl utility.
The cec-compliance utility is by no means 100% coverage, in particular the
event API and non-blocking ioctls are untested. But it is a starting point,
and a complex protocol like CEC really needs a compliance tool.
The cec-ctl utility has almost full CEC message coverage: all generated from
the cec headers, so this is easy to keep up to date.
Regards,
Hans
Changes since v1:
- cec-ctl: added CEC message logging/monitoring.
- cec-ctl: add support to clear the logical addresses.
- cec-ctl: log events.
On 08/18/15 10:36, Hans Verkuil wrote:
> Hans Verkuil (4):
> Makefile.am: copy cec headers with make sync-with-kernel
> sync-with-kernel
> cec-compliance: add new CEC compliance utility
> cec-ctl: CEC control utility
>
> Makefile.am | 4 +
> configure.ac | 2 +
> contrib/freebsd/include/linux/input.h | 29 +
> contrib/freebsd/include/linux/v4l2-controls.h | 4 +
> include/linux/cec-funcs.h | 1771 +++++++++++++++++++++++++
> include/linux/cec.h | 781 +++++++++++
> include/linux/v4l2-controls.h | 4 +
> utils/Makefile.am | 2 +
> utils/cec-compliance/Makefile.am | 3 +
> utils/cec-compliance/cec-compliance.cpp | 926 +++++++++++++
> utils/cec-compliance/cec-compliance.h | 87 ++
> utils/cec-ctl/Makefile.am | 8 +
> utils/cec-ctl/cec-ctl.cpp | 1296 ++++++++++++++++++
> utils/cec-ctl/msg2ctl.pl | 430 ++++++
> utils/keytable/parse.h | 18 +
> utils/keytable/rc_keymaps/lme2510 | 132 +-
> utils/keytable/rc_maps.cfg | 1 +
> 17 files changed, 5432 insertions(+), 66 deletions(-)
> create mode 100644 include/linux/cec-funcs.h
> create mode 100644 include/linux/cec.h
> create mode 100644 utils/cec-compliance/Makefile.am
> create mode 100644 utils/cec-compliance/cec-compliance.cpp
> create mode 100644 utils/cec-compliance/cec-compliance.h
> create mode 100644 utils/cec-ctl/Makefile.am
> create mode 100644 utils/cec-ctl/cec-ctl.cpp
> create mode 100644 utils/cec-ctl/msg2ctl.pl
>
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2015-08-18 8:56 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-08-18 8:36 [PATCHv2 0/4] cec-ctl/compliance: new CEC utilities Hans Verkuil
2015-08-18 8:36 ` [PATCHv2 1/4] Makefile.am: copy cec headers with make sync-with-kernel Hans Verkuil
2015-08-18 8:36 ` [PATCHv2 2/4] sync-with-kernel Hans Verkuil
2015-08-18 8:36 ` [PATCHv2 3/4] cec-compliance: add new CEC compliance utility Hans Verkuil
2015-08-18 8:36 ` [PATCHv2 4/4] cec-ctl: CEC control utility Hans Verkuil
2015-08-18 8:46 ` [PATCHv2 0/4] cec-ctl/compliance: new CEC utilities Hans Verkuil
2015-08-18 8:46 ` Hans Verkuil
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.