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