cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

cec-funcs.h (53453B)


      1/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Clause) */
      2/*
      3 * cec - HDMI Consumer Electronics Control message functions
      4 *
      5 * Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
      6 */
      7
      8#ifndef _CEC_UAPI_FUNCS_H
      9#define _CEC_UAPI_FUNCS_H
     10
     11#include <linux/cec.h>
     12
     13/* One Touch Play Feature */
     14static inline void cec_msg_active_source(struct cec_msg *msg, __u16 phys_addr)
     15{
     16	msg->len = 4;
     17	msg->msg[0] |= 0xf; /* broadcast */
     18	msg->msg[1] = CEC_MSG_ACTIVE_SOURCE;
     19	msg->msg[2] = phys_addr >> 8;
     20	msg->msg[3] = phys_addr & 0xff;
     21}
     22
     23static inline void cec_ops_active_source(const struct cec_msg *msg,
     24					 __u16 *phys_addr)
     25{
     26	*phys_addr = (msg->msg[2] << 8) | msg->msg[3];
     27}
     28
     29static inline void cec_msg_image_view_on(struct cec_msg *msg)
     30{
     31	msg->len = 2;
     32	msg->msg[1] = CEC_MSG_IMAGE_VIEW_ON;
     33}
     34
     35static inline void cec_msg_text_view_on(struct cec_msg *msg)
     36{
     37	msg->len = 2;
     38	msg->msg[1] = CEC_MSG_TEXT_VIEW_ON;
     39}
     40
     41
     42/* Routing Control Feature */
     43static inline void cec_msg_inactive_source(struct cec_msg *msg,
     44					   __u16 phys_addr)
     45{
     46	msg->len = 4;
     47	msg->msg[1] = CEC_MSG_INACTIVE_SOURCE;
     48	msg->msg[2] = phys_addr >> 8;
     49	msg->msg[3] = phys_addr & 0xff;
     50}
     51
     52static inline void cec_ops_inactive_source(const struct cec_msg *msg,
     53					   __u16 *phys_addr)
     54{
     55	*phys_addr = (msg->msg[2] << 8) | msg->msg[3];
     56}
     57
     58static inline void cec_msg_request_active_source(struct cec_msg *msg,
     59						 int reply)
     60{
     61	msg->len = 2;
     62	msg->msg[0] |= 0xf; /* broadcast */
     63	msg->msg[1] = CEC_MSG_REQUEST_ACTIVE_SOURCE;
     64	msg->reply = reply ? CEC_MSG_ACTIVE_SOURCE : 0;
     65}
     66
     67static inline void cec_msg_routing_information(struct cec_msg *msg,
     68					       __u16 phys_addr)
     69{
     70	msg->len = 4;
     71	msg->msg[0] |= 0xf; /* broadcast */
     72	msg->msg[1] = CEC_MSG_ROUTING_INFORMATION;
     73	msg->msg[2] = phys_addr >> 8;
     74	msg->msg[3] = phys_addr & 0xff;
     75}
     76
     77static inline void cec_ops_routing_information(const struct cec_msg *msg,
     78					       __u16 *phys_addr)
     79{
     80	*phys_addr = (msg->msg[2] << 8) | msg->msg[3];
     81}
     82
     83static inline void cec_msg_routing_change(struct cec_msg *msg,
     84					  int reply,
     85					  __u16 orig_phys_addr,
     86					  __u16 new_phys_addr)
     87{
     88	msg->len = 6;
     89	msg->msg[0] |= 0xf; /* broadcast */
     90	msg->msg[1] = CEC_MSG_ROUTING_CHANGE;
     91	msg->msg[2] = orig_phys_addr >> 8;
     92	msg->msg[3] = orig_phys_addr & 0xff;
     93	msg->msg[4] = new_phys_addr >> 8;
     94	msg->msg[5] = new_phys_addr & 0xff;
     95	msg->reply = reply ? CEC_MSG_ROUTING_INFORMATION : 0;
     96}
     97
     98static inline void cec_ops_routing_change(const struct cec_msg *msg,
     99					  __u16 *orig_phys_addr,
    100					  __u16 *new_phys_addr)
    101{
    102	*orig_phys_addr = (msg->msg[2] << 8) | msg->msg[3];
    103	*new_phys_addr = (msg->msg[4] << 8) | msg->msg[5];
    104}
    105
    106static inline void cec_msg_set_stream_path(struct cec_msg *msg, __u16 phys_addr)
    107{
    108	msg->len = 4;
    109	msg->msg[0] |= 0xf; /* broadcast */
    110	msg->msg[1] = CEC_MSG_SET_STREAM_PATH;
    111	msg->msg[2] = phys_addr >> 8;
    112	msg->msg[3] = phys_addr & 0xff;
    113}
    114
    115static inline void cec_ops_set_stream_path(const struct cec_msg *msg,
    116					   __u16 *phys_addr)
    117{
    118	*phys_addr = (msg->msg[2] << 8) | msg->msg[3];
    119}
    120
    121
    122/* Standby Feature */
    123static inline void cec_msg_standby(struct cec_msg *msg)
    124{
    125	msg->len = 2;
    126	msg->msg[1] = CEC_MSG_STANDBY;
    127}
    128
    129
    130/* One Touch Record Feature */
    131static inline void cec_msg_record_off(struct cec_msg *msg, int reply)
    132{
    133	msg->len = 2;
    134	msg->msg[1] = CEC_MSG_RECORD_OFF;
    135	msg->reply = reply ? CEC_MSG_RECORD_STATUS : 0;
    136}
    137
    138struct cec_op_arib_data {
    139	__u16 transport_id;
    140	__u16 service_id;
    141	__u16 orig_network_id;
    142};
    143
    144struct cec_op_atsc_data {
    145	__u16 transport_id;
    146	__u16 program_number;
    147};
    148
    149struct cec_op_dvb_data {
    150	__u16 transport_id;
    151	__u16 service_id;
    152	__u16 orig_network_id;
    153};
    154
    155struct cec_op_channel_data {
    156	__u8 channel_number_fmt;
    157	__u16 major;
    158	__u16 minor;
    159};
    160
    161struct cec_op_digital_service_id {
    162	__u8 service_id_method;
    163	__u8 dig_bcast_system;
    164	union {
    165		struct cec_op_arib_data arib;
    166		struct cec_op_atsc_data atsc;
    167		struct cec_op_dvb_data dvb;
    168		struct cec_op_channel_data channel;
    169	};
    170};
    171
    172struct cec_op_record_src {
    173	__u8 type;
    174	union {
    175		struct cec_op_digital_service_id digital;
    176		struct {
    177			__u8 ana_bcast_type;
    178			__u16 ana_freq;
    179			__u8 bcast_system;
    180		} analog;
    181		struct {
    182			__u8 plug;
    183		} ext_plug;
    184		struct {
    185			__u16 phys_addr;
    186		} ext_phys_addr;
    187	};
    188};
    189
    190static inline void cec_set_digital_service_id(__u8 *msg,
    191	      const struct cec_op_digital_service_id *digital)
    192{
    193	*msg++ = (digital->service_id_method << 7) | digital->dig_bcast_system;
    194	if (digital->service_id_method == CEC_OP_SERVICE_ID_METHOD_BY_CHANNEL) {
    195		*msg++ = (digital->channel.channel_number_fmt << 2) |
    196			 (digital->channel.major >> 8);
    197		*msg++ = digital->channel.major & 0xff;
    198		*msg++ = digital->channel.minor >> 8;
    199		*msg++ = digital->channel.minor & 0xff;
    200		*msg++ = 0;
    201		*msg++ = 0;
    202		return;
    203	}
    204	switch (digital->dig_bcast_system) {
    205	case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_GEN:
    206	case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_CABLE:
    207	case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_SAT:
    208	case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_T:
    209		*msg++ = digital->atsc.transport_id >> 8;
    210		*msg++ = digital->atsc.transport_id & 0xff;
    211		*msg++ = digital->atsc.program_number >> 8;
    212		*msg++ = digital->atsc.program_number & 0xff;
    213		*msg++ = 0;
    214		*msg++ = 0;
    215		break;
    216	default:
    217		*msg++ = digital->dvb.transport_id >> 8;
    218		*msg++ = digital->dvb.transport_id & 0xff;
    219		*msg++ = digital->dvb.service_id >> 8;
    220		*msg++ = digital->dvb.service_id & 0xff;
    221		*msg++ = digital->dvb.orig_network_id >> 8;
    222		*msg++ = digital->dvb.orig_network_id & 0xff;
    223		break;
    224	}
    225}
    226
    227static inline void cec_get_digital_service_id(const __u8 *msg,
    228	      struct cec_op_digital_service_id *digital)
    229{
    230	digital->service_id_method = msg[0] >> 7;
    231	digital->dig_bcast_system = msg[0] & 0x7f;
    232	if (digital->service_id_method == CEC_OP_SERVICE_ID_METHOD_BY_CHANNEL) {
    233		digital->channel.channel_number_fmt = msg[1] >> 2;
    234		digital->channel.major = ((msg[1] & 3) << 6) | msg[2];
    235		digital->channel.minor = (msg[3] << 8) | msg[4];
    236		return;
    237	}
    238	digital->dvb.transport_id = (msg[1] << 8) | msg[2];
    239	digital->dvb.service_id = (msg[3] << 8) | msg[4];
    240	digital->dvb.orig_network_id = (msg[5] << 8) | msg[6];
    241}
    242
    243static inline void cec_msg_record_on_own(struct cec_msg *msg)
    244{
    245	msg->len = 3;
    246	msg->msg[1] = CEC_MSG_RECORD_ON;
    247	msg->msg[2] = CEC_OP_RECORD_SRC_OWN;
    248}
    249
    250static inline void cec_msg_record_on_digital(struct cec_msg *msg,
    251			     const struct cec_op_digital_service_id *digital)
    252{
    253	msg->len = 10;
    254	msg->msg[1] = CEC_MSG_RECORD_ON;
    255	msg->msg[2] = CEC_OP_RECORD_SRC_DIGITAL;
    256	cec_set_digital_service_id(msg->msg + 3, digital);
    257}
    258
    259static inline void cec_msg_record_on_analog(struct cec_msg *msg,
    260					    __u8 ana_bcast_type,
    261					    __u16 ana_freq,
    262					    __u8 bcast_system)
    263{
    264	msg->len = 7;
    265	msg->msg[1] = CEC_MSG_RECORD_ON;
    266	msg->msg[2] = CEC_OP_RECORD_SRC_ANALOG;
    267	msg->msg[3] = ana_bcast_type;
    268	msg->msg[4] = ana_freq >> 8;
    269	msg->msg[5] = ana_freq & 0xff;
    270	msg->msg[6] = bcast_system;
    271}
    272
    273static inline void cec_msg_record_on_plug(struct cec_msg *msg,
    274					  __u8 plug)
    275{
    276	msg->len = 4;
    277	msg->msg[1] = CEC_MSG_RECORD_ON;
    278	msg->msg[2] = CEC_OP_RECORD_SRC_EXT_PLUG;
    279	msg->msg[3] = plug;
    280}
    281
    282static inline void cec_msg_record_on_phys_addr(struct cec_msg *msg,
    283					       __u16 phys_addr)
    284{
    285	msg->len = 5;
    286	msg->msg[1] = CEC_MSG_RECORD_ON;
    287	msg->msg[2] = CEC_OP_RECORD_SRC_EXT_PHYS_ADDR;
    288	msg->msg[3] = phys_addr >> 8;
    289	msg->msg[4] = phys_addr & 0xff;
    290}
    291
    292static inline void cec_msg_record_on(struct cec_msg *msg,
    293				     int reply,
    294				     const struct cec_op_record_src *rec_src)
    295{
    296	switch (rec_src->type) {
    297	case CEC_OP_RECORD_SRC_OWN:
    298		cec_msg_record_on_own(msg);
    299		break;
    300	case CEC_OP_RECORD_SRC_DIGITAL:
    301		cec_msg_record_on_digital(msg, &rec_src->digital);
    302		break;
    303	case CEC_OP_RECORD_SRC_ANALOG:
    304		cec_msg_record_on_analog(msg,
    305					 rec_src->analog.ana_bcast_type,
    306					 rec_src->analog.ana_freq,
    307					 rec_src->analog.bcast_system);
    308		break;
    309	case CEC_OP_RECORD_SRC_EXT_PLUG:
    310		cec_msg_record_on_plug(msg, rec_src->ext_plug.plug);
    311		break;
    312	case CEC_OP_RECORD_SRC_EXT_PHYS_ADDR:
    313		cec_msg_record_on_phys_addr(msg,
    314					    rec_src->ext_phys_addr.phys_addr);
    315		break;
    316	}
    317	msg->reply = reply ? CEC_MSG_RECORD_STATUS : 0;
    318}
    319
    320static inline void cec_ops_record_on(const struct cec_msg *msg,
    321				     struct cec_op_record_src *rec_src)
    322{
    323	rec_src->type = msg->msg[2];
    324	switch (rec_src->type) {
    325	case CEC_OP_RECORD_SRC_OWN:
    326		break;
    327	case CEC_OP_RECORD_SRC_DIGITAL:
    328		cec_get_digital_service_id(msg->msg + 3, &rec_src->digital);
    329		break;
    330	case CEC_OP_RECORD_SRC_ANALOG:
    331		rec_src->analog.ana_bcast_type = msg->msg[3];
    332		rec_src->analog.ana_freq =
    333			(msg->msg[4] << 8) | msg->msg[5];
    334		rec_src->analog.bcast_system = msg->msg[6];
    335		break;
    336	case CEC_OP_RECORD_SRC_EXT_PLUG:
    337		rec_src->ext_plug.plug = msg->msg[3];
    338		break;
    339	case CEC_OP_RECORD_SRC_EXT_PHYS_ADDR:
    340		rec_src->ext_phys_addr.phys_addr =
    341			(msg->msg[3] << 8) | msg->msg[4];
    342		break;
    343	}
    344}
    345
    346static inline void cec_msg_record_status(struct cec_msg *msg, __u8 rec_status)
    347{
    348	msg->len = 3;
    349	msg->msg[1] = CEC_MSG_RECORD_STATUS;
    350	msg->msg[2] = rec_status;
    351}
    352
    353static inline void cec_ops_record_status(const struct cec_msg *msg,
    354					 __u8 *rec_status)
    355{
    356	*rec_status = msg->msg[2];
    357}
    358
    359static inline void cec_msg_record_tv_screen(struct cec_msg *msg,
    360					    int reply)
    361{
    362	msg->len = 2;
    363	msg->msg[1] = CEC_MSG_RECORD_TV_SCREEN;
    364	msg->reply = reply ? CEC_MSG_RECORD_ON : 0;
    365}
    366
    367
    368/* Timer Programming Feature */
    369static inline void cec_msg_timer_status(struct cec_msg *msg,
    370					__u8 timer_overlap_warning,
    371					__u8 media_info,
    372					__u8 prog_info,
    373					__u8 prog_error,
    374					__u8 duration_hr,
    375					__u8 duration_min)
    376{
    377	msg->len = 3;
    378	msg->msg[1] = CEC_MSG_TIMER_STATUS;
    379	msg->msg[2] = (timer_overlap_warning << 7) |
    380		(media_info << 5) |
    381		(prog_info ? 0x10 : 0) |
    382		(prog_info ? prog_info : prog_error);
    383	if (prog_info == CEC_OP_PROG_INFO_NOT_ENOUGH_SPACE ||
    384	    prog_info == CEC_OP_PROG_INFO_MIGHT_NOT_BE_ENOUGH_SPACE ||
    385	    prog_error == CEC_OP_PROG_ERROR_DUPLICATE) {
    386		msg->len += 2;
    387		msg->msg[3] = ((duration_hr / 10) << 4) | (duration_hr % 10);
    388		msg->msg[4] = ((duration_min / 10) << 4) | (duration_min % 10);
    389	}
    390}
    391
    392static inline void cec_ops_timer_status(const struct cec_msg *msg,
    393					__u8 *timer_overlap_warning,
    394					__u8 *media_info,
    395					__u8 *prog_info,
    396					__u8 *prog_error,
    397					__u8 *duration_hr,
    398					__u8 *duration_min)
    399{
    400	*timer_overlap_warning = msg->msg[2] >> 7;
    401	*media_info = (msg->msg[2] >> 5) & 3;
    402	if (msg->msg[2] & 0x10) {
    403		*prog_info = msg->msg[2] & 0xf;
    404		*prog_error = 0;
    405	} else {
    406		*prog_info = 0;
    407		*prog_error = msg->msg[2] & 0xf;
    408	}
    409	if (*prog_info == CEC_OP_PROG_INFO_NOT_ENOUGH_SPACE ||
    410	    *prog_info == CEC_OP_PROG_INFO_MIGHT_NOT_BE_ENOUGH_SPACE ||
    411	    *prog_error == CEC_OP_PROG_ERROR_DUPLICATE) {
    412		*duration_hr = (msg->msg[3] >> 4) * 10 + (msg->msg[3] & 0xf);
    413		*duration_min = (msg->msg[4] >> 4) * 10 + (msg->msg[4] & 0xf);
    414	} else {
    415		*duration_hr = *duration_min = 0;
    416	}
    417}
    418
    419static inline void cec_msg_timer_cleared_status(struct cec_msg *msg,
    420						__u8 timer_cleared_status)
    421{
    422	msg->len = 3;
    423	msg->msg[1] = CEC_MSG_TIMER_CLEARED_STATUS;
    424	msg->msg[2] = timer_cleared_status;
    425}
    426
    427static inline void cec_ops_timer_cleared_status(const struct cec_msg *msg,
    428						__u8 *timer_cleared_status)
    429{
    430	*timer_cleared_status = msg->msg[2];
    431}
    432
    433static inline void cec_msg_clear_analogue_timer(struct cec_msg *msg,
    434						int reply,
    435						__u8 day,
    436						__u8 month,
    437						__u8 start_hr,
    438						__u8 start_min,
    439						__u8 duration_hr,
    440						__u8 duration_min,
    441						__u8 recording_seq,
    442						__u8 ana_bcast_type,
    443						__u16 ana_freq,
    444						__u8 bcast_system)
    445{
    446	msg->len = 13;
    447	msg->msg[1] = CEC_MSG_CLEAR_ANALOGUE_TIMER;
    448	msg->msg[2] = day;
    449	msg->msg[3] = month;
    450	/* Hours and minutes are in BCD format */
    451	msg->msg[4] = ((start_hr / 10) << 4) | (start_hr % 10);
    452	msg->msg[5] = ((start_min / 10) << 4) | (start_min % 10);
    453	msg->msg[6] = ((duration_hr / 10) << 4) | (duration_hr % 10);
    454	msg->msg[7] = ((duration_min / 10) << 4) | (duration_min % 10);
    455	msg->msg[8] = recording_seq;
    456	msg->msg[9] = ana_bcast_type;
    457	msg->msg[10] = ana_freq >> 8;
    458	msg->msg[11] = ana_freq & 0xff;
    459	msg->msg[12] = bcast_system;
    460	msg->reply = reply ? CEC_MSG_TIMER_CLEARED_STATUS : 0;
    461}
    462
    463static inline void cec_ops_clear_analogue_timer(const struct cec_msg *msg,
    464						__u8 *day,
    465						__u8 *month,
    466						__u8 *start_hr,
    467						__u8 *start_min,
    468						__u8 *duration_hr,
    469						__u8 *duration_min,
    470						__u8 *recording_seq,
    471						__u8 *ana_bcast_type,
    472						__u16 *ana_freq,
    473						__u8 *bcast_system)
    474{
    475	*day = msg->msg[2];
    476	*month = msg->msg[3];
    477	/* Hours and minutes are in BCD format */
    478	*start_hr = (msg->msg[4] >> 4) * 10 + (msg->msg[4] & 0xf);
    479	*start_min = (msg->msg[5] >> 4) * 10 + (msg->msg[5] & 0xf);
    480	*duration_hr = (msg->msg[6] >> 4) * 10 + (msg->msg[6] & 0xf);
    481	*duration_min = (msg->msg[7] >> 4) * 10 + (msg->msg[7] & 0xf);
    482	*recording_seq = msg->msg[8];
    483	*ana_bcast_type = msg->msg[9];
    484	*ana_freq = (msg->msg[10] << 8) | msg->msg[11];
    485	*bcast_system = msg->msg[12];
    486}
    487
    488static inline void cec_msg_clear_digital_timer(struct cec_msg *msg,
    489				int reply,
    490				__u8 day,
    491				__u8 month,
    492				__u8 start_hr,
    493				__u8 start_min,
    494				__u8 duration_hr,
    495				__u8 duration_min,
    496				__u8 recording_seq,
    497				const struct cec_op_digital_service_id *digital)
    498{
    499	msg->len = 16;
    500	msg->reply = reply ? CEC_MSG_TIMER_CLEARED_STATUS : 0;
    501	msg->msg[1] = CEC_MSG_CLEAR_DIGITAL_TIMER;
    502	msg->msg[2] = day;
    503	msg->msg[3] = month;
    504	/* Hours and minutes are in BCD format */
    505	msg->msg[4] = ((start_hr / 10) << 4) | (start_hr % 10);
    506	msg->msg[5] = ((start_min / 10) << 4) | (start_min % 10);
    507	msg->msg[6] = ((duration_hr / 10) << 4) | (duration_hr % 10);
    508	msg->msg[7] = ((duration_min / 10) << 4) | (duration_min % 10);
    509	msg->msg[8] = recording_seq;
    510	cec_set_digital_service_id(msg->msg + 9, digital);
    511}
    512
    513static inline void cec_ops_clear_digital_timer(const struct cec_msg *msg,
    514				__u8 *day,
    515				__u8 *month,
    516				__u8 *start_hr,
    517				__u8 *start_min,
    518				__u8 *duration_hr,
    519				__u8 *duration_min,
    520				__u8 *recording_seq,
    521				struct cec_op_digital_service_id *digital)
    522{
    523	*day = msg->msg[2];
    524	*month = msg->msg[3];
    525	/* Hours and minutes are in BCD format */
    526	*start_hr = (msg->msg[4] >> 4) * 10 + (msg->msg[4] & 0xf);
    527	*start_min = (msg->msg[5] >> 4) * 10 + (msg->msg[5] & 0xf);
    528	*duration_hr = (msg->msg[6] >> 4) * 10 + (msg->msg[6] & 0xf);
    529	*duration_min = (msg->msg[7] >> 4) * 10 + (msg->msg[7] & 0xf);
    530	*recording_seq = msg->msg[8];
    531	cec_get_digital_service_id(msg->msg + 9, digital);
    532}
    533
    534static inline void cec_msg_clear_ext_timer(struct cec_msg *msg,
    535					   int reply,
    536					   __u8 day,
    537					   __u8 month,
    538					   __u8 start_hr,
    539					   __u8 start_min,
    540					   __u8 duration_hr,
    541					   __u8 duration_min,
    542					   __u8 recording_seq,
    543					   __u8 ext_src_spec,
    544					   __u8 plug,
    545					   __u16 phys_addr)
    546{
    547	msg->len = 13;
    548	msg->msg[1] = CEC_MSG_CLEAR_EXT_TIMER;
    549	msg->msg[2] = day;
    550	msg->msg[3] = month;
    551	/* Hours and minutes are in BCD format */
    552	msg->msg[4] = ((start_hr / 10) << 4) | (start_hr % 10);
    553	msg->msg[5] = ((start_min / 10) << 4) | (start_min % 10);
    554	msg->msg[6] = ((duration_hr / 10) << 4) | (duration_hr % 10);
    555	msg->msg[7] = ((duration_min / 10) << 4) | (duration_min % 10);
    556	msg->msg[8] = recording_seq;
    557	msg->msg[9] = ext_src_spec;
    558	msg->msg[10] = plug;
    559	msg->msg[11] = phys_addr >> 8;
    560	msg->msg[12] = phys_addr & 0xff;
    561	msg->reply = reply ? CEC_MSG_TIMER_CLEARED_STATUS : 0;
    562}
    563
    564static inline void cec_ops_clear_ext_timer(const struct cec_msg *msg,
    565					   __u8 *day,
    566					   __u8 *month,
    567					   __u8 *start_hr,
    568					   __u8 *start_min,
    569					   __u8 *duration_hr,
    570					   __u8 *duration_min,
    571					   __u8 *recording_seq,
    572					   __u8 *ext_src_spec,
    573					   __u8 *plug,
    574					   __u16 *phys_addr)
    575{
    576	*day = msg->msg[2];
    577	*month = msg->msg[3];
    578	/* Hours and minutes are in BCD format */
    579	*start_hr = (msg->msg[4] >> 4) * 10 + (msg->msg[4] & 0xf);
    580	*start_min = (msg->msg[5] >> 4) * 10 + (msg->msg[5] & 0xf);
    581	*duration_hr = (msg->msg[6] >> 4) * 10 + (msg->msg[6] & 0xf);
    582	*duration_min = (msg->msg[7] >> 4) * 10 + (msg->msg[7] & 0xf);
    583	*recording_seq = msg->msg[8];
    584	*ext_src_spec = msg->msg[9];
    585	*plug = msg->msg[10];
    586	*phys_addr = (msg->msg[11] << 8) | msg->msg[12];
    587}
    588
    589static inline void cec_msg_set_analogue_timer(struct cec_msg *msg,
    590					      int reply,
    591					      __u8 day,
    592					      __u8 month,
    593					      __u8 start_hr,
    594					      __u8 start_min,
    595					      __u8 duration_hr,
    596					      __u8 duration_min,
    597					      __u8 recording_seq,
    598					      __u8 ana_bcast_type,
    599					      __u16 ana_freq,
    600					      __u8 bcast_system)
    601{
    602	msg->len = 13;
    603	msg->msg[1] = CEC_MSG_SET_ANALOGUE_TIMER;
    604	msg->msg[2] = day;
    605	msg->msg[3] = month;
    606	/* Hours and minutes are in BCD format */
    607	msg->msg[4] = ((start_hr / 10) << 4) | (start_hr % 10);
    608	msg->msg[5] = ((start_min / 10) << 4) | (start_min % 10);
    609	msg->msg[6] = ((duration_hr / 10) << 4) | (duration_hr % 10);
    610	msg->msg[7] = ((duration_min / 10) << 4) | (duration_min % 10);
    611	msg->msg[8] = recording_seq;
    612	msg->msg[9] = ana_bcast_type;
    613	msg->msg[10] = ana_freq >> 8;
    614	msg->msg[11] = ana_freq & 0xff;
    615	msg->msg[12] = bcast_system;
    616	msg->reply = reply ? CEC_MSG_TIMER_STATUS : 0;
    617}
    618
    619static inline void cec_ops_set_analogue_timer(const struct cec_msg *msg,
    620					      __u8 *day,
    621					      __u8 *month,
    622					      __u8 *start_hr,
    623					      __u8 *start_min,
    624					      __u8 *duration_hr,
    625					      __u8 *duration_min,
    626					      __u8 *recording_seq,
    627					      __u8 *ana_bcast_type,
    628					      __u16 *ana_freq,
    629					      __u8 *bcast_system)
    630{
    631	*day = msg->msg[2];
    632	*month = msg->msg[3];
    633	/* Hours and minutes are in BCD format */
    634	*start_hr = (msg->msg[4] >> 4) * 10 + (msg->msg[4] & 0xf);
    635	*start_min = (msg->msg[5] >> 4) * 10 + (msg->msg[5] & 0xf);
    636	*duration_hr = (msg->msg[6] >> 4) * 10 + (msg->msg[6] & 0xf);
    637	*duration_min = (msg->msg[7] >> 4) * 10 + (msg->msg[7] & 0xf);
    638	*recording_seq = msg->msg[8];
    639	*ana_bcast_type = msg->msg[9];
    640	*ana_freq = (msg->msg[10] << 8) | msg->msg[11];
    641	*bcast_system = msg->msg[12];
    642}
    643
    644static inline void cec_msg_set_digital_timer(struct cec_msg *msg,
    645			int reply,
    646			__u8 day,
    647			__u8 month,
    648			__u8 start_hr,
    649			__u8 start_min,
    650			__u8 duration_hr,
    651			__u8 duration_min,
    652			__u8 recording_seq,
    653			const struct cec_op_digital_service_id *digital)
    654{
    655	msg->len = 16;
    656	msg->reply = reply ? CEC_MSG_TIMER_STATUS : 0;
    657	msg->msg[1] = CEC_MSG_SET_DIGITAL_TIMER;
    658	msg->msg[2] = day;
    659	msg->msg[3] = month;
    660	/* Hours and minutes are in BCD format */
    661	msg->msg[4] = ((start_hr / 10) << 4) | (start_hr % 10);
    662	msg->msg[5] = ((start_min / 10) << 4) | (start_min % 10);
    663	msg->msg[6] = ((duration_hr / 10) << 4) | (duration_hr % 10);
    664	msg->msg[7] = ((duration_min / 10) << 4) | (duration_min % 10);
    665	msg->msg[8] = recording_seq;
    666	cec_set_digital_service_id(msg->msg + 9, digital);
    667}
    668
    669static inline void cec_ops_set_digital_timer(const struct cec_msg *msg,
    670			__u8 *day,
    671			__u8 *month,
    672			__u8 *start_hr,
    673			__u8 *start_min,
    674			__u8 *duration_hr,
    675			__u8 *duration_min,
    676			__u8 *recording_seq,
    677			struct cec_op_digital_service_id *digital)
    678{
    679	*day = msg->msg[2];
    680	*month = msg->msg[3];
    681	/* Hours and minutes are in BCD format */
    682	*start_hr = (msg->msg[4] >> 4) * 10 + (msg->msg[4] & 0xf);
    683	*start_min = (msg->msg[5] >> 4) * 10 + (msg->msg[5] & 0xf);
    684	*duration_hr = (msg->msg[6] >> 4) * 10 + (msg->msg[6] & 0xf);
    685	*duration_min = (msg->msg[7] >> 4) * 10 + (msg->msg[7] & 0xf);
    686	*recording_seq = msg->msg[8];
    687	cec_get_digital_service_id(msg->msg + 9, digital);
    688}
    689
    690static inline void cec_msg_set_ext_timer(struct cec_msg *msg,
    691					 int reply,
    692					 __u8 day,
    693					 __u8 month,
    694					 __u8 start_hr,
    695					 __u8 start_min,
    696					 __u8 duration_hr,
    697					 __u8 duration_min,
    698					 __u8 recording_seq,
    699					 __u8 ext_src_spec,
    700					 __u8 plug,
    701					 __u16 phys_addr)
    702{
    703	msg->len = 13;
    704	msg->msg[1] = CEC_MSG_SET_EXT_TIMER;
    705	msg->msg[2] = day;
    706	msg->msg[3] = month;
    707	/* Hours and minutes are in BCD format */
    708	msg->msg[4] = ((start_hr / 10) << 4) | (start_hr % 10);
    709	msg->msg[5] = ((start_min / 10) << 4) | (start_min % 10);
    710	msg->msg[6] = ((duration_hr / 10) << 4) | (duration_hr % 10);
    711	msg->msg[7] = ((duration_min / 10) << 4) | (duration_min % 10);
    712	msg->msg[8] = recording_seq;
    713	msg->msg[9] = ext_src_spec;
    714	msg->msg[10] = plug;
    715	msg->msg[11] = phys_addr >> 8;
    716	msg->msg[12] = phys_addr & 0xff;
    717	msg->reply = reply ? CEC_MSG_TIMER_STATUS : 0;
    718}
    719
    720static inline void cec_ops_set_ext_timer(const struct cec_msg *msg,
    721					 __u8 *day,
    722					 __u8 *month,
    723					 __u8 *start_hr,
    724					 __u8 *start_min,
    725					 __u8 *duration_hr,
    726					 __u8 *duration_min,
    727					 __u8 *recording_seq,
    728					 __u8 *ext_src_spec,
    729					 __u8 *plug,
    730					 __u16 *phys_addr)
    731{
    732	*day = msg->msg[2];
    733	*month = msg->msg[3];
    734	/* Hours and minutes are in BCD format */
    735	*start_hr = (msg->msg[4] >> 4) * 10 + (msg->msg[4] & 0xf);
    736	*start_min = (msg->msg[5] >> 4) * 10 + (msg->msg[5] & 0xf);
    737	*duration_hr = (msg->msg[6] >> 4) * 10 + (msg->msg[6] & 0xf);
    738	*duration_min = (msg->msg[7] >> 4) * 10 + (msg->msg[7] & 0xf);
    739	*recording_seq = msg->msg[8];
    740	*ext_src_spec = msg->msg[9];
    741	*plug = msg->msg[10];
    742	*phys_addr = (msg->msg[11] << 8) | msg->msg[12];
    743}
    744
    745static inline void cec_msg_set_timer_program_title(struct cec_msg *msg,
    746						   const char *prog_title)
    747{
    748	unsigned int len = strlen(prog_title);
    749
    750	if (len > 14)
    751		len = 14;
    752	msg->len = 2 + len;
    753	msg->msg[1] = CEC_MSG_SET_TIMER_PROGRAM_TITLE;
    754	memcpy(msg->msg + 2, prog_title, len);
    755}
    756
    757static inline void cec_ops_set_timer_program_title(const struct cec_msg *msg,
    758						   char *prog_title)
    759{
    760	unsigned int len = msg->len > 2 ? msg->len - 2 : 0;
    761
    762	if (len > 14)
    763		len = 14;
    764	memcpy(prog_title, msg->msg + 2, len);
    765	prog_title[len] = '\0';
    766}
    767
    768/* System Information Feature */
    769static inline void cec_msg_cec_version(struct cec_msg *msg, __u8 cec_version)
    770{
    771	msg->len = 3;
    772	msg->msg[1] = CEC_MSG_CEC_VERSION;
    773	msg->msg[2] = cec_version;
    774}
    775
    776static inline void cec_ops_cec_version(const struct cec_msg *msg,
    777				       __u8 *cec_version)
    778{
    779	*cec_version = msg->msg[2];
    780}
    781
    782static inline void cec_msg_get_cec_version(struct cec_msg *msg,
    783					   int reply)
    784{
    785	msg->len = 2;
    786	msg->msg[1] = CEC_MSG_GET_CEC_VERSION;
    787	msg->reply = reply ? CEC_MSG_CEC_VERSION : 0;
    788}
    789
    790static inline void cec_msg_report_physical_addr(struct cec_msg *msg,
    791					__u16 phys_addr, __u8 prim_devtype)
    792{
    793	msg->len = 5;
    794	msg->msg[0] |= 0xf; /* broadcast */
    795	msg->msg[1] = CEC_MSG_REPORT_PHYSICAL_ADDR;
    796	msg->msg[2] = phys_addr >> 8;
    797	msg->msg[3] = phys_addr & 0xff;
    798	msg->msg[4] = prim_devtype;
    799}
    800
    801static inline void cec_ops_report_physical_addr(const struct cec_msg *msg,
    802					__u16 *phys_addr, __u8 *prim_devtype)
    803{
    804	*phys_addr = (msg->msg[2] << 8) | msg->msg[3];
    805	*prim_devtype = msg->msg[4];
    806}
    807
    808static inline void cec_msg_give_physical_addr(struct cec_msg *msg,
    809					      int reply)
    810{
    811	msg->len = 2;
    812	msg->msg[1] = CEC_MSG_GIVE_PHYSICAL_ADDR;
    813	msg->reply = reply ? CEC_MSG_REPORT_PHYSICAL_ADDR : 0;
    814}
    815
    816static inline void cec_msg_set_menu_language(struct cec_msg *msg,
    817					     const char *language)
    818{
    819	msg->len = 5;
    820	msg->msg[0] |= 0xf; /* broadcast */
    821	msg->msg[1] = CEC_MSG_SET_MENU_LANGUAGE;
    822	memcpy(msg->msg + 2, language, 3);
    823}
    824
    825static inline void cec_ops_set_menu_language(const struct cec_msg *msg,
    826					     char *language)
    827{
    828	memcpy(language, msg->msg + 2, 3);
    829	language[3] = '\0';
    830}
    831
    832static inline void cec_msg_get_menu_language(struct cec_msg *msg,
    833					     int reply)
    834{
    835	msg->len = 2;
    836	msg->msg[1] = CEC_MSG_GET_MENU_LANGUAGE;
    837	msg->reply = reply ? CEC_MSG_SET_MENU_LANGUAGE : 0;
    838}
    839
    840/*
    841 * Assumes a single RC Profile byte and a single Device Features byte,
    842 * i.e. no extended features are supported by this helper function.
    843 *
    844 * As of CEC 2.0 no extended features are defined, should those be added
    845 * in the future, then this function needs to be adapted or a new function
    846 * should be added.
    847 */
    848static inline void cec_msg_report_features(struct cec_msg *msg,
    849				__u8 cec_version, __u8 all_device_types,
    850				__u8 rc_profile, __u8 dev_features)
    851{
    852	msg->len = 6;
    853	msg->msg[0] |= 0xf; /* broadcast */
    854	msg->msg[1] = CEC_MSG_REPORT_FEATURES;
    855	msg->msg[2] = cec_version;
    856	msg->msg[3] = all_device_types;
    857	msg->msg[4] = rc_profile;
    858	msg->msg[5] = dev_features;
    859}
    860
    861static inline void cec_ops_report_features(const struct cec_msg *msg,
    862			__u8 *cec_version, __u8 *all_device_types,
    863			const __u8 **rc_profile, const __u8 **dev_features)
    864{
    865	const __u8 *p = &msg->msg[4];
    866
    867	*cec_version = msg->msg[2];
    868	*all_device_types = msg->msg[3];
    869	*rc_profile = p;
    870	*dev_features = NULL;
    871	while (p < &msg->msg[14] && (*p & CEC_OP_FEAT_EXT))
    872		p++;
    873	if (!(*p & CEC_OP_FEAT_EXT)) {
    874		*dev_features = p + 1;
    875		while (p < &msg->msg[15] && (*p & CEC_OP_FEAT_EXT))
    876			p++;
    877	}
    878	if (*p & CEC_OP_FEAT_EXT)
    879		*rc_profile = *dev_features = NULL;
    880}
    881
    882static inline void cec_msg_give_features(struct cec_msg *msg,
    883					 int reply)
    884{
    885	msg->len = 2;
    886	msg->msg[1] = CEC_MSG_GIVE_FEATURES;
    887	msg->reply = reply ? CEC_MSG_REPORT_FEATURES : 0;
    888}
    889
    890/* Deck Control Feature */
    891static inline void cec_msg_deck_control(struct cec_msg *msg,
    892					__u8 deck_control_mode)
    893{
    894	msg->len = 3;
    895	msg->msg[1] = CEC_MSG_DECK_CONTROL;
    896	msg->msg[2] = deck_control_mode;
    897}
    898
    899static inline void cec_ops_deck_control(const struct cec_msg *msg,
    900					__u8 *deck_control_mode)
    901{
    902	*deck_control_mode = msg->msg[2];
    903}
    904
    905static inline void cec_msg_deck_status(struct cec_msg *msg,
    906				       __u8 deck_info)
    907{
    908	msg->len = 3;
    909	msg->msg[1] = CEC_MSG_DECK_STATUS;
    910	msg->msg[2] = deck_info;
    911}
    912
    913static inline void cec_ops_deck_status(const struct cec_msg *msg,
    914				       __u8 *deck_info)
    915{
    916	*deck_info = msg->msg[2];
    917}
    918
    919static inline void cec_msg_give_deck_status(struct cec_msg *msg,
    920					    int reply,
    921					    __u8 status_req)
    922{
    923	msg->len = 3;
    924	msg->msg[1] = CEC_MSG_GIVE_DECK_STATUS;
    925	msg->msg[2] = status_req;
    926	msg->reply = (reply && status_req != CEC_OP_STATUS_REQ_OFF) ?
    927				CEC_MSG_DECK_STATUS : 0;
    928}
    929
    930static inline void cec_ops_give_deck_status(const struct cec_msg *msg,
    931					    __u8 *status_req)
    932{
    933	*status_req = msg->msg[2];
    934}
    935
    936static inline void cec_msg_play(struct cec_msg *msg,
    937				__u8 play_mode)
    938{
    939	msg->len = 3;
    940	msg->msg[1] = CEC_MSG_PLAY;
    941	msg->msg[2] = play_mode;
    942}
    943
    944static inline void cec_ops_play(const struct cec_msg *msg,
    945				__u8 *play_mode)
    946{
    947	*play_mode = msg->msg[2];
    948}
    949
    950
    951/* Tuner Control Feature */
    952struct cec_op_tuner_device_info {
    953	__u8 rec_flag;
    954	__u8 tuner_display_info;
    955	__u8 is_analog;
    956	union {
    957		struct cec_op_digital_service_id digital;
    958		struct {
    959			__u8 ana_bcast_type;
    960			__u16 ana_freq;
    961			__u8 bcast_system;
    962		} analog;
    963	};
    964};
    965
    966static inline void cec_msg_tuner_device_status_analog(struct cec_msg *msg,
    967						      __u8 rec_flag,
    968						      __u8 tuner_display_info,
    969						      __u8 ana_bcast_type,
    970						      __u16 ana_freq,
    971						      __u8 bcast_system)
    972{
    973	msg->len = 7;
    974	msg->msg[1] = CEC_MSG_TUNER_DEVICE_STATUS;
    975	msg->msg[2] = (rec_flag << 7) | tuner_display_info;
    976	msg->msg[3] = ana_bcast_type;
    977	msg->msg[4] = ana_freq >> 8;
    978	msg->msg[5] = ana_freq & 0xff;
    979	msg->msg[6] = bcast_system;
    980}
    981
    982static inline void cec_msg_tuner_device_status_digital(struct cec_msg *msg,
    983		   __u8 rec_flag, __u8 tuner_display_info,
    984		   const struct cec_op_digital_service_id *digital)
    985{
    986	msg->len = 10;
    987	msg->msg[1] = CEC_MSG_TUNER_DEVICE_STATUS;
    988	msg->msg[2] = (rec_flag << 7) | tuner_display_info;
    989	cec_set_digital_service_id(msg->msg + 3, digital);
    990}
    991
    992static inline void cec_msg_tuner_device_status(struct cec_msg *msg,
    993			const struct cec_op_tuner_device_info *tuner_dev_info)
    994{
    995	if (tuner_dev_info->is_analog)
    996		cec_msg_tuner_device_status_analog(msg,
    997			tuner_dev_info->rec_flag,
    998			tuner_dev_info->tuner_display_info,
    999			tuner_dev_info->analog.ana_bcast_type,
   1000			tuner_dev_info->analog.ana_freq,
   1001			tuner_dev_info->analog.bcast_system);
   1002	else
   1003		cec_msg_tuner_device_status_digital(msg,
   1004			tuner_dev_info->rec_flag,
   1005			tuner_dev_info->tuner_display_info,
   1006			&tuner_dev_info->digital);
   1007}
   1008
   1009static inline void cec_ops_tuner_device_status(const struct cec_msg *msg,
   1010				struct cec_op_tuner_device_info *tuner_dev_info)
   1011{
   1012	tuner_dev_info->is_analog = msg->len < 10;
   1013	tuner_dev_info->rec_flag = msg->msg[2] >> 7;
   1014	tuner_dev_info->tuner_display_info = msg->msg[2] & 0x7f;
   1015	if (tuner_dev_info->is_analog) {
   1016		tuner_dev_info->analog.ana_bcast_type = msg->msg[3];
   1017		tuner_dev_info->analog.ana_freq = (msg->msg[4] << 8) | msg->msg[5];
   1018		tuner_dev_info->analog.bcast_system = msg->msg[6];
   1019		return;
   1020	}
   1021	cec_get_digital_service_id(msg->msg + 3, &tuner_dev_info->digital);
   1022}
   1023
   1024static inline void cec_msg_give_tuner_device_status(struct cec_msg *msg,
   1025						    int reply,
   1026						    __u8 status_req)
   1027{
   1028	msg->len = 3;
   1029	msg->msg[1] = CEC_MSG_GIVE_TUNER_DEVICE_STATUS;
   1030	msg->msg[2] = status_req;
   1031	msg->reply = (reply && status_req != CEC_OP_STATUS_REQ_OFF) ?
   1032				CEC_MSG_TUNER_DEVICE_STATUS : 0;
   1033}
   1034
   1035static inline void cec_ops_give_tuner_device_status(const struct cec_msg *msg,
   1036						    __u8 *status_req)
   1037{
   1038	*status_req = msg->msg[2];
   1039}
   1040
   1041static inline void cec_msg_select_analogue_service(struct cec_msg *msg,
   1042						   __u8 ana_bcast_type,
   1043						   __u16 ana_freq,
   1044						   __u8 bcast_system)
   1045{
   1046	msg->len = 6;
   1047	msg->msg[1] = CEC_MSG_SELECT_ANALOGUE_SERVICE;
   1048	msg->msg[2] = ana_bcast_type;
   1049	msg->msg[3] = ana_freq >> 8;
   1050	msg->msg[4] = ana_freq & 0xff;
   1051	msg->msg[5] = bcast_system;
   1052}
   1053
   1054static inline void cec_ops_select_analogue_service(const struct cec_msg *msg,
   1055						   __u8 *ana_bcast_type,
   1056						   __u16 *ana_freq,
   1057						   __u8 *bcast_system)
   1058{
   1059	*ana_bcast_type = msg->msg[2];
   1060	*ana_freq = (msg->msg[3] << 8) | msg->msg[4];
   1061	*bcast_system = msg->msg[5];
   1062}
   1063
   1064static inline void cec_msg_select_digital_service(struct cec_msg *msg,
   1065				const struct cec_op_digital_service_id *digital)
   1066{
   1067	msg->len = 9;
   1068	msg->msg[1] = CEC_MSG_SELECT_DIGITAL_SERVICE;
   1069	cec_set_digital_service_id(msg->msg + 2, digital);
   1070}
   1071
   1072static inline void cec_ops_select_digital_service(const struct cec_msg *msg,
   1073				struct cec_op_digital_service_id *digital)
   1074{
   1075	cec_get_digital_service_id(msg->msg + 2, digital);
   1076}
   1077
   1078static inline void cec_msg_tuner_step_decrement(struct cec_msg *msg)
   1079{
   1080	msg->len = 2;
   1081	msg->msg[1] = CEC_MSG_TUNER_STEP_DECREMENT;
   1082}
   1083
   1084static inline void cec_msg_tuner_step_increment(struct cec_msg *msg)
   1085{
   1086	msg->len = 2;
   1087	msg->msg[1] = CEC_MSG_TUNER_STEP_INCREMENT;
   1088}
   1089
   1090
   1091/* Vendor Specific Commands Feature */
   1092static inline void cec_msg_device_vendor_id(struct cec_msg *msg, __u32 vendor_id)
   1093{
   1094	msg->len = 5;
   1095	msg->msg[0] |= 0xf; /* broadcast */
   1096	msg->msg[1] = CEC_MSG_DEVICE_VENDOR_ID;
   1097	msg->msg[2] = vendor_id >> 16;
   1098	msg->msg[3] = (vendor_id >> 8) & 0xff;
   1099	msg->msg[4] = vendor_id & 0xff;
   1100}
   1101
   1102static inline void cec_ops_device_vendor_id(const struct cec_msg *msg,
   1103					    __u32 *vendor_id)
   1104{
   1105	*vendor_id = (msg->msg[2] << 16) | (msg->msg[3] << 8) | msg->msg[4];
   1106}
   1107
   1108static inline void cec_msg_give_device_vendor_id(struct cec_msg *msg,
   1109						 int reply)
   1110{
   1111	msg->len = 2;
   1112	msg->msg[1] = CEC_MSG_GIVE_DEVICE_VENDOR_ID;
   1113	msg->reply = reply ? CEC_MSG_DEVICE_VENDOR_ID : 0;
   1114}
   1115
   1116static inline void cec_msg_vendor_command(struct cec_msg *msg,
   1117					  __u8 size, const __u8 *vendor_cmd)
   1118{
   1119	if (size > 14)
   1120		size = 14;
   1121	msg->len = 2 + size;
   1122	msg->msg[1] = CEC_MSG_VENDOR_COMMAND;
   1123	memcpy(msg->msg + 2, vendor_cmd, size);
   1124}
   1125
   1126static inline void cec_ops_vendor_command(const struct cec_msg *msg,
   1127					  __u8 *size,
   1128					  const __u8 **vendor_cmd)
   1129{
   1130	*size = msg->len - 2;
   1131
   1132	if (*size > 14)
   1133		*size = 14;
   1134	*vendor_cmd = msg->msg + 2;
   1135}
   1136
   1137static inline void cec_msg_vendor_command_with_id(struct cec_msg *msg,
   1138						  __u32 vendor_id, __u8 size,
   1139						  const __u8 *vendor_cmd)
   1140{
   1141	if (size > 11)
   1142		size = 11;
   1143	msg->len = 5 + size;
   1144	msg->msg[1] = CEC_MSG_VENDOR_COMMAND_WITH_ID;
   1145	msg->msg[2] = vendor_id >> 16;
   1146	msg->msg[3] = (vendor_id >> 8) & 0xff;
   1147	msg->msg[4] = vendor_id & 0xff;
   1148	memcpy(msg->msg + 5, vendor_cmd, size);
   1149}
   1150
   1151static inline void cec_ops_vendor_command_with_id(const struct cec_msg *msg,
   1152						  __u32 *vendor_id,  __u8 *size,
   1153						  const __u8 **vendor_cmd)
   1154{
   1155	*size = msg->len - 5;
   1156
   1157	if (*size > 11)
   1158		*size = 11;
   1159	*vendor_id = (msg->msg[2] << 16) | (msg->msg[3] << 8) | msg->msg[4];
   1160	*vendor_cmd = msg->msg + 5;
   1161}
   1162
   1163static inline void cec_msg_vendor_remote_button_down(struct cec_msg *msg,
   1164						     __u8 size,
   1165						     const __u8 *rc_code)
   1166{
   1167	if (size > 14)
   1168		size = 14;
   1169	msg->len = 2 + size;
   1170	msg->msg[1] = CEC_MSG_VENDOR_REMOTE_BUTTON_DOWN;
   1171	memcpy(msg->msg + 2, rc_code, size);
   1172}
   1173
   1174static inline void cec_ops_vendor_remote_button_down(const struct cec_msg *msg,
   1175						     __u8 *size,
   1176						     const __u8 **rc_code)
   1177{
   1178	*size = msg->len - 2;
   1179
   1180	if (*size > 14)
   1181		*size = 14;
   1182	*rc_code = msg->msg + 2;
   1183}
   1184
   1185static inline void cec_msg_vendor_remote_button_up(struct cec_msg *msg)
   1186{
   1187	msg->len = 2;
   1188	msg->msg[1] = CEC_MSG_VENDOR_REMOTE_BUTTON_UP;
   1189}
   1190
   1191
   1192/* OSD Display Feature */
   1193static inline void cec_msg_set_osd_string(struct cec_msg *msg,
   1194					  __u8 disp_ctl,
   1195					  const char *osd)
   1196{
   1197	unsigned int len = strlen(osd);
   1198
   1199	if (len > 13)
   1200		len = 13;
   1201	msg->len = 3 + len;
   1202	msg->msg[1] = CEC_MSG_SET_OSD_STRING;
   1203	msg->msg[2] = disp_ctl;
   1204	memcpy(msg->msg + 3, osd, len);
   1205}
   1206
   1207static inline void cec_ops_set_osd_string(const struct cec_msg *msg,
   1208					  __u8 *disp_ctl,
   1209					  char *osd)
   1210{
   1211	unsigned int len = msg->len > 3 ? msg->len - 3 : 0;
   1212
   1213	*disp_ctl = msg->msg[2];
   1214	if (len > 13)
   1215		len = 13;
   1216	memcpy(osd, msg->msg + 3, len);
   1217	osd[len] = '\0';
   1218}
   1219
   1220
   1221/* Device OSD Transfer Feature */
   1222static inline void cec_msg_set_osd_name(struct cec_msg *msg, const char *name)
   1223{
   1224	unsigned int len = strlen(name);
   1225
   1226	if (len > 14)
   1227		len = 14;
   1228	msg->len = 2 + len;
   1229	msg->msg[1] = CEC_MSG_SET_OSD_NAME;
   1230	memcpy(msg->msg + 2, name, len);
   1231}
   1232
   1233static inline void cec_ops_set_osd_name(const struct cec_msg *msg,
   1234					char *name)
   1235{
   1236	unsigned int len = msg->len > 2 ? msg->len - 2 : 0;
   1237
   1238	if (len > 14)
   1239		len = 14;
   1240	memcpy(name, msg->msg + 2, len);
   1241	name[len] = '\0';
   1242}
   1243
   1244static inline void cec_msg_give_osd_name(struct cec_msg *msg,
   1245					 int reply)
   1246{
   1247	msg->len = 2;
   1248	msg->msg[1] = CEC_MSG_GIVE_OSD_NAME;
   1249	msg->reply = reply ? CEC_MSG_SET_OSD_NAME : 0;
   1250}
   1251
   1252
   1253/* Device Menu Control Feature */
   1254static inline void cec_msg_menu_status(struct cec_msg *msg,
   1255				       __u8 menu_state)
   1256{
   1257	msg->len = 3;
   1258	msg->msg[1] = CEC_MSG_MENU_STATUS;
   1259	msg->msg[2] = menu_state;
   1260}
   1261
   1262static inline void cec_ops_menu_status(const struct cec_msg *msg,
   1263				       __u8 *menu_state)
   1264{
   1265	*menu_state = msg->msg[2];
   1266}
   1267
   1268static inline void cec_msg_menu_request(struct cec_msg *msg,
   1269					int reply,
   1270					__u8 menu_req)
   1271{
   1272	msg->len = 3;
   1273	msg->msg[1] = CEC_MSG_MENU_REQUEST;
   1274	msg->msg[2] = menu_req;
   1275	msg->reply = reply ? CEC_MSG_MENU_STATUS : 0;
   1276}
   1277
   1278static inline void cec_ops_menu_request(const struct cec_msg *msg,
   1279					__u8 *menu_req)
   1280{
   1281	*menu_req = msg->msg[2];
   1282}
   1283
   1284struct cec_op_ui_command {
   1285	__u8 ui_cmd;
   1286	__u8 has_opt_arg;
   1287	union {
   1288		struct cec_op_channel_data channel_identifier;
   1289		__u8 ui_broadcast_type;
   1290		__u8 ui_sound_presentation_control;
   1291		__u8 play_mode;
   1292		__u8 ui_function_media;
   1293		__u8 ui_function_select_av_input;
   1294		__u8 ui_function_select_audio_input;
   1295	};
   1296};
   1297
   1298static inline void cec_msg_user_control_pressed(struct cec_msg *msg,
   1299					const struct cec_op_ui_command *ui_cmd)
   1300{
   1301	msg->len = 3;
   1302	msg->msg[1] = CEC_MSG_USER_CONTROL_PRESSED;
   1303	msg->msg[2] = ui_cmd->ui_cmd;
   1304	if (!ui_cmd->has_opt_arg)
   1305		return;
   1306	switch (ui_cmd->ui_cmd) {
   1307	case CEC_OP_UI_CMD_SELECT_BROADCAST_TYPE:
   1308	case CEC_OP_UI_CMD_SELECT_SOUND_PRESENTATION:
   1309	case CEC_OP_UI_CMD_PLAY_FUNCTION:
   1310	case CEC_OP_UI_CMD_SELECT_MEDIA_FUNCTION:
   1311	case CEC_OP_UI_CMD_SELECT_AV_INPUT_FUNCTION:
   1312	case CEC_OP_UI_CMD_SELECT_AUDIO_INPUT_FUNCTION:
   1313		/* The optional operand is one byte for all these ui commands */
   1314		msg->len++;
   1315		msg->msg[3] = ui_cmd->play_mode;
   1316		break;
   1317	case CEC_OP_UI_CMD_TUNE_FUNCTION:
   1318		msg->len += 4;
   1319		msg->msg[3] = (ui_cmd->channel_identifier.channel_number_fmt << 2) |
   1320			      (ui_cmd->channel_identifier.major >> 8);
   1321		msg->msg[4] = ui_cmd->channel_identifier.major & 0xff;
   1322		msg->msg[5] = ui_cmd->channel_identifier.minor >> 8;
   1323		msg->msg[6] = ui_cmd->channel_identifier.minor & 0xff;
   1324		break;
   1325	}
   1326}
   1327
   1328static inline void cec_ops_user_control_pressed(const struct cec_msg *msg,
   1329						struct cec_op_ui_command *ui_cmd)
   1330{
   1331	ui_cmd->ui_cmd = msg->msg[2];
   1332	ui_cmd->has_opt_arg = 0;
   1333	if (msg->len == 3)
   1334		return;
   1335	switch (ui_cmd->ui_cmd) {
   1336	case CEC_OP_UI_CMD_SELECT_BROADCAST_TYPE:
   1337	case CEC_OP_UI_CMD_SELECT_SOUND_PRESENTATION:
   1338	case CEC_OP_UI_CMD_PLAY_FUNCTION:
   1339	case CEC_OP_UI_CMD_SELECT_MEDIA_FUNCTION:
   1340	case CEC_OP_UI_CMD_SELECT_AV_INPUT_FUNCTION:
   1341	case CEC_OP_UI_CMD_SELECT_AUDIO_INPUT_FUNCTION:
   1342		/* The optional operand is one byte for all these ui commands */
   1343		ui_cmd->play_mode = msg->msg[3];
   1344		ui_cmd->has_opt_arg = 1;
   1345		break;
   1346	case CEC_OP_UI_CMD_TUNE_FUNCTION:
   1347		if (msg->len < 7)
   1348			break;
   1349		ui_cmd->has_opt_arg = 1;
   1350		ui_cmd->channel_identifier.channel_number_fmt = msg->msg[3] >> 2;
   1351		ui_cmd->channel_identifier.major = ((msg->msg[3] & 3) << 6) | msg->msg[4];
   1352		ui_cmd->channel_identifier.minor = (msg->msg[5] << 8) | msg->msg[6];
   1353		break;
   1354	}
   1355}
   1356
   1357static inline void cec_msg_user_control_released(struct cec_msg *msg)
   1358{
   1359	msg->len = 2;
   1360	msg->msg[1] = CEC_MSG_USER_CONTROL_RELEASED;
   1361}
   1362
   1363/* Remote Control Passthrough Feature */
   1364
   1365/* Power Status Feature */
   1366static inline void cec_msg_report_power_status(struct cec_msg *msg,
   1367					       __u8 pwr_state)
   1368{
   1369	msg->len = 3;
   1370	msg->msg[1] = CEC_MSG_REPORT_POWER_STATUS;
   1371	msg->msg[2] = pwr_state;
   1372}
   1373
   1374static inline void cec_ops_report_power_status(const struct cec_msg *msg,
   1375					       __u8 *pwr_state)
   1376{
   1377	*pwr_state = msg->msg[2];
   1378}
   1379
   1380static inline void cec_msg_give_device_power_status(struct cec_msg *msg,
   1381						    int reply)
   1382{
   1383	msg->len = 2;
   1384	msg->msg[1] = CEC_MSG_GIVE_DEVICE_POWER_STATUS;
   1385	msg->reply = reply ? CEC_MSG_REPORT_POWER_STATUS : 0;
   1386}
   1387
   1388/* General Protocol Messages */
   1389static inline void cec_msg_feature_abort(struct cec_msg *msg,
   1390					 __u8 abort_msg, __u8 reason)
   1391{
   1392	msg->len = 4;
   1393	msg->msg[1] = CEC_MSG_FEATURE_ABORT;
   1394	msg->msg[2] = abort_msg;
   1395	msg->msg[3] = reason;
   1396}
   1397
   1398static inline void cec_ops_feature_abort(const struct cec_msg *msg,
   1399					 __u8 *abort_msg, __u8 *reason)
   1400{
   1401	*abort_msg = msg->msg[2];
   1402	*reason = msg->msg[3];
   1403}
   1404
   1405/* This changes the current message into a feature abort message */
   1406static inline void cec_msg_reply_feature_abort(struct cec_msg *msg, __u8 reason)
   1407{
   1408	cec_msg_set_reply_to(msg, msg);
   1409	msg->len = 4;
   1410	msg->msg[2] = msg->msg[1];
   1411	msg->msg[3] = reason;
   1412	msg->msg[1] = CEC_MSG_FEATURE_ABORT;
   1413}
   1414
   1415static inline void cec_msg_abort(struct cec_msg *msg)
   1416{
   1417	msg->len = 2;
   1418	msg->msg[1] = CEC_MSG_ABORT;
   1419}
   1420
   1421
   1422/* System Audio Control Feature */
   1423static inline void cec_msg_report_audio_status(struct cec_msg *msg,
   1424					       __u8 aud_mute_status,
   1425					       __u8 aud_vol_status)
   1426{
   1427	msg->len = 3;
   1428	msg->msg[1] = CEC_MSG_REPORT_AUDIO_STATUS;
   1429	msg->msg[2] = (aud_mute_status << 7) | (aud_vol_status & 0x7f);
   1430}
   1431
   1432static inline void cec_ops_report_audio_status(const struct cec_msg *msg,
   1433					       __u8 *aud_mute_status,
   1434					       __u8 *aud_vol_status)
   1435{
   1436	*aud_mute_status = msg->msg[2] >> 7;
   1437	*aud_vol_status = msg->msg[2] & 0x7f;
   1438}
   1439
   1440static inline void cec_msg_give_audio_status(struct cec_msg *msg,
   1441					     int reply)
   1442{
   1443	msg->len = 2;
   1444	msg->msg[1] = CEC_MSG_GIVE_AUDIO_STATUS;
   1445	msg->reply = reply ? CEC_MSG_REPORT_AUDIO_STATUS : 0;
   1446}
   1447
   1448static inline void cec_msg_set_system_audio_mode(struct cec_msg *msg,
   1449						 __u8 sys_aud_status)
   1450{
   1451	msg->len = 3;
   1452	msg->msg[1] = CEC_MSG_SET_SYSTEM_AUDIO_MODE;
   1453	msg->msg[2] = sys_aud_status;
   1454}
   1455
   1456static inline void cec_ops_set_system_audio_mode(const struct cec_msg *msg,
   1457						 __u8 *sys_aud_status)
   1458{
   1459	*sys_aud_status = msg->msg[2];
   1460}
   1461
   1462static inline void cec_msg_system_audio_mode_request(struct cec_msg *msg,
   1463						     int reply,
   1464						     __u16 phys_addr)
   1465{
   1466	msg->len = phys_addr == 0xffff ? 2 : 4;
   1467	msg->msg[1] = CEC_MSG_SYSTEM_AUDIO_MODE_REQUEST;
   1468	msg->msg[2] = phys_addr >> 8;
   1469	msg->msg[3] = phys_addr & 0xff;
   1470	msg->reply = reply ? CEC_MSG_SET_SYSTEM_AUDIO_MODE : 0;
   1471
   1472}
   1473
   1474static inline void cec_ops_system_audio_mode_request(const struct cec_msg *msg,
   1475						     __u16 *phys_addr)
   1476{
   1477	if (msg->len < 4)
   1478		*phys_addr = 0xffff;
   1479	else
   1480		*phys_addr = (msg->msg[2] << 8) | msg->msg[3];
   1481}
   1482
   1483static inline void cec_msg_system_audio_mode_status(struct cec_msg *msg,
   1484						    __u8 sys_aud_status)
   1485{
   1486	msg->len = 3;
   1487	msg->msg[1] = CEC_MSG_SYSTEM_AUDIO_MODE_STATUS;
   1488	msg->msg[2] = sys_aud_status;
   1489}
   1490
   1491static inline void cec_ops_system_audio_mode_status(const struct cec_msg *msg,
   1492						    __u8 *sys_aud_status)
   1493{
   1494	*sys_aud_status = msg->msg[2];
   1495}
   1496
   1497static inline void cec_msg_give_system_audio_mode_status(struct cec_msg *msg,
   1498							 int reply)
   1499{
   1500	msg->len = 2;
   1501	msg->msg[1] = CEC_MSG_GIVE_SYSTEM_AUDIO_MODE_STATUS;
   1502	msg->reply = reply ? CEC_MSG_SYSTEM_AUDIO_MODE_STATUS : 0;
   1503}
   1504
   1505static inline void cec_msg_report_short_audio_descriptor(struct cec_msg *msg,
   1506					__u8 num_descriptors,
   1507					const __u32 *descriptors)
   1508{
   1509	unsigned int i;
   1510
   1511	if (num_descriptors > 4)
   1512		num_descriptors = 4;
   1513	msg->len = 2 + num_descriptors * 3;
   1514	msg->msg[1] = CEC_MSG_REPORT_SHORT_AUDIO_DESCRIPTOR;
   1515	for (i = 0; i < num_descriptors; i++) {
   1516		msg->msg[2 + i * 3] = (descriptors[i] >> 16) & 0xff;
   1517		msg->msg[3 + i * 3] = (descriptors[i] >> 8) & 0xff;
   1518		msg->msg[4 + i * 3] = descriptors[i] & 0xff;
   1519	}
   1520}
   1521
   1522static inline void cec_ops_report_short_audio_descriptor(const struct cec_msg *msg,
   1523							 __u8 *num_descriptors,
   1524							 __u32 *descriptors)
   1525{
   1526	unsigned int i;
   1527
   1528	*num_descriptors = (msg->len - 2) / 3;
   1529	if (*num_descriptors > 4)
   1530		*num_descriptors = 4;
   1531	for (i = 0; i < *num_descriptors; i++)
   1532		descriptors[i] = (msg->msg[2 + i * 3] << 16) |
   1533			(msg->msg[3 + i * 3] << 8) |
   1534			msg->msg[4 + i * 3];
   1535}
   1536
   1537static inline void cec_msg_request_short_audio_descriptor(struct cec_msg *msg,
   1538					int reply,
   1539					__u8 num_descriptors,
   1540					const __u8 *audio_format_id,
   1541					const __u8 *audio_format_code)
   1542{
   1543	unsigned int i;
   1544
   1545	if (num_descriptors > 4)
   1546		num_descriptors = 4;
   1547	msg->len = 2 + num_descriptors;
   1548	msg->msg[1] = CEC_MSG_REQUEST_SHORT_AUDIO_DESCRIPTOR;
   1549	msg->reply = reply ? CEC_MSG_REPORT_SHORT_AUDIO_DESCRIPTOR : 0;
   1550	for (i = 0; i < num_descriptors; i++)
   1551		msg->msg[2 + i] = (audio_format_id[i] << 6) |
   1552				  (audio_format_code[i] & 0x3f);
   1553}
   1554
   1555static inline void cec_ops_request_short_audio_descriptor(const struct cec_msg *msg,
   1556					__u8 *num_descriptors,
   1557					__u8 *audio_format_id,
   1558					__u8 *audio_format_code)
   1559{
   1560	unsigned int i;
   1561
   1562	*num_descriptors = msg->len - 2;
   1563	if (*num_descriptors > 4)
   1564		*num_descriptors = 4;
   1565	for (i = 0; i < *num_descriptors; i++) {
   1566		audio_format_id[i] = msg->msg[2 + i] >> 6;
   1567		audio_format_code[i] = msg->msg[2 + i] & 0x3f;
   1568	}
   1569}
   1570
   1571
   1572/* Audio Rate Control Feature */
   1573static inline void cec_msg_set_audio_rate(struct cec_msg *msg,
   1574					  __u8 audio_rate)
   1575{
   1576	msg->len = 3;
   1577	msg->msg[1] = CEC_MSG_SET_AUDIO_RATE;
   1578	msg->msg[2] = audio_rate;
   1579}
   1580
   1581static inline void cec_ops_set_audio_rate(const struct cec_msg *msg,
   1582					  __u8 *audio_rate)
   1583{
   1584	*audio_rate = msg->msg[2];
   1585}
   1586
   1587
   1588/* Audio Return Channel Control Feature */
   1589static inline void cec_msg_report_arc_initiated(struct cec_msg *msg)
   1590{
   1591	msg->len = 2;
   1592	msg->msg[1] = CEC_MSG_REPORT_ARC_INITIATED;
   1593}
   1594
   1595static inline void cec_msg_initiate_arc(struct cec_msg *msg,
   1596					int reply)
   1597{
   1598	msg->len = 2;
   1599	msg->msg[1] = CEC_MSG_INITIATE_ARC;
   1600	msg->reply = reply ? CEC_MSG_REPORT_ARC_INITIATED : 0;
   1601}
   1602
   1603static inline void cec_msg_request_arc_initiation(struct cec_msg *msg,
   1604						  int reply)
   1605{
   1606	msg->len = 2;
   1607	msg->msg[1] = CEC_MSG_REQUEST_ARC_INITIATION;
   1608	msg->reply = reply ? CEC_MSG_INITIATE_ARC : 0;
   1609}
   1610
   1611static inline void cec_msg_report_arc_terminated(struct cec_msg *msg)
   1612{
   1613	msg->len = 2;
   1614	msg->msg[1] = CEC_MSG_REPORT_ARC_TERMINATED;
   1615}
   1616
   1617static inline void cec_msg_terminate_arc(struct cec_msg *msg,
   1618					 int reply)
   1619{
   1620	msg->len = 2;
   1621	msg->msg[1] = CEC_MSG_TERMINATE_ARC;
   1622	msg->reply = reply ? CEC_MSG_REPORT_ARC_TERMINATED : 0;
   1623}
   1624
   1625static inline void cec_msg_request_arc_termination(struct cec_msg *msg,
   1626						   int reply)
   1627{
   1628	msg->len = 2;
   1629	msg->msg[1] = CEC_MSG_REQUEST_ARC_TERMINATION;
   1630	msg->reply = reply ? CEC_MSG_TERMINATE_ARC : 0;
   1631}
   1632
   1633
   1634/* Dynamic Audio Lipsync Feature */
   1635/* Only for CEC 2.0 and up */
   1636static inline void cec_msg_report_current_latency(struct cec_msg *msg,
   1637						  __u16 phys_addr,
   1638						  __u8 video_latency,
   1639						  __u8 low_latency_mode,
   1640						  __u8 audio_out_compensated,
   1641						  __u8 audio_out_delay)
   1642{
   1643	msg->len = 6;
   1644	msg->msg[0] |= 0xf; /* broadcast */
   1645	msg->msg[1] = CEC_MSG_REPORT_CURRENT_LATENCY;
   1646	msg->msg[2] = phys_addr >> 8;
   1647	msg->msg[3] = phys_addr & 0xff;
   1648	msg->msg[4] = video_latency;
   1649	msg->msg[5] = (low_latency_mode << 2) | audio_out_compensated;
   1650	if (audio_out_compensated == 3)
   1651		msg->msg[msg->len++] = audio_out_delay;
   1652}
   1653
   1654static inline void cec_ops_report_current_latency(const struct cec_msg *msg,
   1655						  __u16 *phys_addr,
   1656						  __u8 *video_latency,
   1657						  __u8 *low_latency_mode,
   1658						  __u8 *audio_out_compensated,
   1659						  __u8 *audio_out_delay)
   1660{
   1661	*phys_addr = (msg->msg[2] << 8) | msg->msg[3];
   1662	*video_latency = msg->msg[4];
   1663	*low_latency_mode = (msg->msg[5] >> 2) & 1;
   1664	*audio_out_compensated = msg->msg[5] & 3;
   1665	if (*audio_out_compensated == 3 && msg->len >= 7)
   1666		*audio_out_delay = msg->msg[6];
   1667	else
   1668		*audio_out_delay = 1;
   1669}
   1670
   1671static inline void cec_msg_request_current_latency(struct cec_msg *msg,
   1672						   int reply,
   1673						   __u16 phys_addr)
   1674{
   1675	msg->len = 4;
   1676	msg->msg[0] |= 0xf; /* broadcast */
   1677	msg->msg[1] = CEC_MSG_REQUEST_CURRENT_LATENCY;
   1678	msg->msg[2] = phys_addr >> 8;
   1679	msg->msg[3] = phys_addr & 0xff;
   1680	msg->reply = reply ? CEC_MSG_REPORT_CURRENT_LATENCY : 0;
   1681}
   1682
   1683static inline void cec_ops_request_current_latency(const struct cec_msg *msg,
   1684						   __u16 *phys_addr)
   1685{
   1686	*phys_addr = (msg->msg[2] << 8) | msg->msg[3];
   1687}
   1688
   1689
   1690/* Capability Discovery and Control Feature */
   1691static inline void cec_msg_cdc_hec_inquire_state(struct cec_msg *msg,
   1692						 __u16 phys_addr1,
   1693						 __u16 phys_addr2)
   1694{
   1695	msg->len = 9;
   1696	msg->msg[0] |= 0xf; /* broadcast */
   1697	msg->msg[1] = CEC_MSG_CDC_MESSAGE;
   1698	/* msg[2] and msg[3] (phys_addr) are filled in by the CEC framework */
   1699	msg->msg[4] = CEC_MSG_CDC_HEC_INQUIRE_STATE;
   1700	msg->msg[5] = phys_addr1 >> 8;
   1701	msg->msg[6] = phys_addr1 & 0xff;
   1702	msg->msg[7] = phys_addr2 >> 8;
   1703	msg->msg[8] = phys_addr2 & 0xff;
   1704}
   1705
   1706static inline void cec_ops_cdc_hec_inquire_state(const struct cec_msg *msg,
   1707						 __u16 *phys_addr,
   1708						 __u16 *phys_addr1,
   1709						 __u16 *phys_addr2)
   1710{
   1711	*phys_addr = (msg->msg[2] << 8) | msg->msg[3];
   1712	*phys_addr1 = (msg->msg[5] << 8) | msg->msg[6];
   1713	*phys_addr2 = (msg->msg[7] << 8) | msg->msg[8];
   1714}
   1715
   1716static inline void cec_msg_cdc_hec_report_state(struct cec_msg *msg,
   1717						__u16 target_phys_addr,
   1718						__u8 hec_func_state,
   1719						__u8 host_func_state,
   1720						__u8 enc_func_state,
   1721						__u8 cdc_errcode,
   1722						__u8 has_field,
   1723						__u16 hec_field)
   1724{
   1725	msg->len = has_field ? 10 : 8;
   1726	msg->msg[0] |= 0xf; /* broadcast */
   1727	msg->msg[1] = CEC_MSG_CDC_MESSAGE;
   1728	/* msg[2] and msg[3] (phys_addr) are filled in by the CEC framework */
   1729	msg->msg[4] = CEC_MSG_CDC_HEC_REPORT_STATE;
   1730	msg->msg[5] = target_phys_addr >> 8;
   1731	msg->msg[6] = target_phys_addr & 0xff;
   1732	msg->msg[7] = (hec_func_state << 6) |
   1733		      (host_func_state << 4) |
   1734		      (enc_func_state << 2) |
   1735		      cdc_errcode;
   1736	if (has_field) {
   1737		msg->msg[8] = hec_field >> 8;
   1738		msg->msg[9] = hec_field & 0xff;
   1739	}
   1740}
   1741
   1742static inline void cec_ops_cdc_hec_report_state(const struct cec_msg *msg,
   1743						__u16 *phys_addr,
   1744						__u16 *target_phys_addr,
   1745						__u8 *hec_func_state,
   1746						__u8 *host_func_state,
   1747						__u8 *enc_func_state,
   1748						__u8 *cdc_errcode,
   1749						__u8 *has_field,
   1750						__u16 *hec_field)
   1751{
   1752	*phys_addr = (msg->msg[2] << 8) | msg->msg[3];
   1753	*target_phys_addr = (msg->msg[5] << 8) | msg->msg[6];
   1754	*hec_func_state = msg->msg[7] >> 6;
   1755	*host_func_state = (msg->msg[7] >> 4) & 3;
   1756	*enc_func_state = (msg->msg[7] >> 4) & 3;
   1757	*cdc_errcode = msg->msg[7] & 3;
   1758	*has_field = msg->len >= 10;
   1759	*hec_field = *has_field ? ((msg->msg[8] << 8) | msg->msg[9]) : 0;
   1760}
   1761
   1762static inline void cec_msg_cdc_hec_set_state(struct cec_msg *msg,
   1763					     __u16 phys_addr1,
   1764					     __u16 phys_addr2,
   1765					     __u8 hec_set_state,
   1766					     __u16 phys_addr3,
   1767					     __u16 phys_addr4,
   1768					     __u16 phys_addr5)
   1769{
   1770	msg->len = 10;
   1771	msg->msg[0] |= 0xf; /* broadcast */
   1772	msg->msg[1] = CEC_MSG_CDC_MESSAGE;
   1773	/* msg[2] and msg[3] (phys_addr) are filled in by the CEC framework */
   1774	msg->msg[4] = CEC_MSG_CDC_HEC_INQUIRE_STATE;
   1775	msg->msg[5] = phys_addr1 >> 8;
   1776	msg->msg[6] = phys_addr1 & 0xff;
   1777	msg->msg[7] = phys_addr2 >> 8;
   1778	msg->msg[8] = phys_addr2 & 0xff;
   1779	msg->msg[9] = hec_set_state;
   1780	if (phys_addr3 != CEC_PHYS_ADDR_INVALID) {
   1781		msg->msg[msg->len++] = phys_addr3 >> 8;
   1782		msg->msg[msg->len++] = phys_addr3 & 0xff;
   1783		if (phys_addr4 != CEC_PHYS_ADDR_INVALID) {
   1784			msg->msg[msg->len++] = phys_addr4 >> 8;
   1785			msg->msg[msg->len++] = phys_addr4 & 0xff;
   1786			if (phys_addr5 != CEC_PHYS_ADDR_INVALID) {
   1787				msg->msg[msg->len++] = phys_addr5 >> 8;
   1788				msg->msg[msg->len++] = phys_addr5 & 0xff;
   1789			}
   1790		}
   1791	}
   1792}
   1793
   1794static inline void cec_ops_cdc_hec_set_state(const struct cec_msg *msg,
   1795					     __u16 *phys_addr,
   1796					     __u16 *phys_addr1,
   1797					     __u16 *phys_addr2,
   1798					     __u8 *hec_set_state,
   1799					     __u16 *phys_addr3,
   1800					     __u16 *phys_addr4,
   1801					     __u16 *phys_addr5)
   1802{
   1803	*phys_addr = (msg->msg[2] << 8) | msg->msg[3];
   1804	*phys_addr1 = (msg->msg[5] << 8) | msg->msg[6];
   1805	*phys_addr2 = (msg->msg[7] << 8) | msg->msg[8];
   1806	*hec_set_state = msg->msg[9];
   1807	*phys_addr3 = *phys_addr4 = *phys_addr5 = CEC_PHYS_ADDR_INVALID;
   1808	if (msg->len >= 12)
   1809		*phys_addr3 = (msg->msg[10] << 8) | msg->msg[11];
   1810	if (msg->len >= 14)
   1811		*phys_addr4 = (msg->msg[12] << 8) | msg->msg[13];
   1812	if (msg->len >= 16)
   1813		*phys_addr5 = (msg->msg[14] << 8) | msg->msg[15];
   1814}
   1815
   1816static inline void cec_msg_cdc_hec_set_state_adjacent(struct cec_msg *msg,
   1817						      __u16 phys_addr1,
   1818						      __u8 hec_set_state)
   1819{
   1820	msg->len = 8;
   1821	msg->msg[0] |= 0xf; /* broadcast */
   1822	msg->msg[1] = CEC_MSG_CDC_MESSAGE;
   1823	/* msg[2] and msg[3] (phys_addr) are filled in by the CEC framework */
   1824	msg->msg[4] = CEC_MSG_CDC_HEC_SET_STATE_ADJACENT;
   1825	msg->msg[5] = phys_addr1 >> 8;
   1826	msg->msg[6] = phys_addr1 & 0xff;
   1827	msg->msg[7] = hec_set_state;
   1828}
   1829
   1830static inline void cec_ops_cdc_hec_set_state_adjacent(const struct cec_msg *msg,
   1831						      __u16 *phys_addr,
   1832						      __u16 *phys_addr1,
   1833						      __u8 *hec_set_state)
   1834{
   1835	*phys_addr = (msg->msg[2] << 8) | msg->msg[3];
   1836	*phys_addr1 = (msg->msg[5] << 8) | msg->msg[6];
   1837	*hec_set_state = msg->msg[7];
   1838}
   1839
   1840static inline void cec_msg_cdc_hec_request_deactivation(struct cec_msg *msg,
   1841							__u16 phys_addr1,
   1842							__u16 phys_addr2,
   1843							__u16 phys_addr3)
   1844{
   1845	msg->len = 11;
   1846	msg->msg[0] |= 0xf; /* broadcast */
   1847	msg->msg[1] = CEC_MSG_CDC_MESSAGE;
   1848	/* msg[2] and msg[3] (phys_addr) are filled in by the CEC framework */
   1849	msg->msg[4] = CEC_MSG_CDC_HEC_REQUEST_DEACTIVATION;
   1850	msg->msg[5] = phys_addr1 >> 8;
   1851	msg->msg[6] = phys_addr1 & 0xff;
   1852	msg->msg[7] = phys_addr2 >> 8;
   1853	msg->msg[8] = phys_addr2 & 0xff;
   1854	msg->msg[9] = phys_addr3 >> 8;
   1855	msg->msg[10] = phys_addr3 & 0xff;
   1856}
   1857
   1858static inline void cec_ops_cdc_hec_request_deactivation(const struct cec_msg *msg,
   1859							__u16 *phys_addr,
   1860							__u16 *phys_addr1,
   1861							__u16 *phys_addr2,
   1862							__u16 *phys_addr3)
   1863{
   1864	*phys_addr = (msg->msg[2] << 8) | msg->msg[3];
   1865	*phys_addr1 = (msg->msg[5] << 8) | msg->msg[6];
   1866	*phys_addr2 = (msg->msg[7] << 8) | msg->msg[8];
   1867	*phys_addr3 = (msg->msg[9] << 8) | msg->msg[10];
   1868}
   1869
   1870static inline void cec_msg_cdc_hec_notify_alive(struct cec_msg *msg)
   1871{
   1872	msg->len = 5;
   1873	msg->msg[0] |= 0xf; /* broadcast */
   1874	msg->msg[1] = CEC_MSG_CDC_MESSAGE;
   1875	/* msg[2] and msg[3] (phys_addr) are filled in by the CEC framework */
   1876	msg->msg[4] = CEC_MSG_CDC_HEC_NOTIFY_ALIVE;
   1877}
   1878
   1879static inline void cec_ops_cdc_hec_notify_alive(const struct cec_msg *msg,
   1880						__u16 *phys_addr)
   1881{
   1882	*phys_addr = (msg->msg[2] << 8) | msg->msg[3];
   1883}
   1884
   1885static inline void cec_msg_cdc_hec_discover(struct cec_msg *msg)
   1886{
   1887	msg->len = 5;
   1888	msg->msg[0] |= 0xf; /* broadcast */
   1889	msg->msg[1] = CEC_MSG_CDC_MESSAGE;
   1890	/* msg[2] and msg[3] (phys_addr) are filled in by the CEC framework */
   1891	msg->msg[4] = CEC_MSG_CDC_HEC_DISCOVER;
   1892}
   1893
   1894static inline void cec_ops_cdc_hec_discover(const struct cec_msg *msg,
   1895					    __u16 *phys_addr)
   1896{
   1897	*phys_addr = (msg->msg[2] << 8) | msg->msg[3];
   1898}
   1899
   1900static inline void cec_msg_cdc_hpd_set_state(struct cec_msg *msg,
   1901					     __u8 input_port,
   1902					     __u8 hpd_state)
   1903{
   1904	msg->len = 6;
   1905	msg->msg[0] |= 0xf; /* broadcast */
   1906	msg->msg[1] = CEC_MSG_CDC_MESSAGE;
   1907	/* msg[2] and msg[3] (phys_addr) are filled in by the CEC framework */
   1908	msg->msg[4] = CEC_MSG_CDC_HPD_SET_STATE;
   1909	msg->msg[5] = (input_port << 4) | hpd_state;
   1910}
   1911
   1912static inline void cec_ops_cdc_hpd_set_state(const struct cec_msg *msg,
   1913					    __u16 *phys_addr,
   1914					    __u8 *input_port,
   1915					    __u8 *hpd_state)
   1916{
   1917	*phys_addr = (msg->msg[2] << 8) | msg->msg[3];
   1918	*input_port = msg->msg[5] >> 4;
   1919	*hpd_state = msg->msg[5] & 0xf;
   1920}
   1921
   1922static inline void cec_msg_cdc_hpd_report_state(struct cec_msg *msg,
   1923						__u8 hpd_state,
   1924						__u8 hpd_error)
   1925{
   1926	msg->len = 6;
   1927	msg->msg[0] |= 0xf; /* broadcast */
   1928	msg->msg[1] = CEC_MSG_CDC_MESSAGE;
   1929	/* msg[2] and msg[3] (phys_addr) are filled in by the CEC framework */
   1930	msg->msg[4] = CEC_MSG_CDC_HPD_REPORT_STATE;
   1931	msg->msg[5] = (hpd_state << 4) | hpd_error;
   1932}
   1933
   1934static inline void cec_ops_cdc_hpd_report_state(const struct cec_msg *msg,
   1935						__u16 *phys_addr,
   1936						__u8 *hpd_state,
   1937						__u8 *hpd_error)
   1938{
   1939	*phys_addr = (msg->msg[2] << 8) | msg->msg[3];
   1940	*hpd_state = msg->msg[5] >> 4;
   1941	*hpd_error = msg->msg[5] & 0xf;
   1942}
   1943
   1944#endif