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