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