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