at v4.15 54 kB view raw
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 */ 43static 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 52static 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 58static 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 64static 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 */ 72static 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 81static 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 87static 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 96static 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 106static 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 112static 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 127static 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 135static 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 144static 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 */ 152static 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 */ 160static 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 167struct cec_op_arib_data { 168 __u16 transport_id; 169 __u16 service_id; 170 __u16 orig_network_id; 171}; 172 173struct cec_op_atsc_data { 174 __u16 transport_id; 175 __u16 program_number; 176}; 177 178struct cec_op_dvb_data { 179 __u16 transport_id; 180 __u16 service_id; 181 __u16 orig_network_id; 182}; 183 184struct cec_op_channel_data { 185 __u8 channel_number_fmt; 186 __u16 major; 187 __u16 minor; 188}; 189 190struct 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 201struct 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 219static 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 256static 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 272static 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 279static 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 288static 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 302static 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 311static 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 321static 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 349static 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 375static 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 382static inline void cec_ops_record_status(const struct cec_msg *msg, 383 __u8 *rec_status) 384{ 385 *rec_status = msg->msg[2]; 386} 387 388static 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 */ 398static 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 421static 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 448static 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 456static 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 462static 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 492static 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 517static 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 542static 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 563static 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 593static 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 618static 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 648static 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 673static 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 698static 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 719static 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 749static 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 774static 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 786static 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 */ 798static 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 805static inline void cec_ops_cec_version(const struct cec_msg *msg, 806 __u8 *cec_version) 807{ 808 *cec_version = msg->msg[2]; 809} 810 811static 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 819static 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 830static 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 837static 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 845static 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 854static 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 861static 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 */ 877static 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 890static 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 911static 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 */ 920static 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 928static 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 934static 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 942static inline void cec_ops_deck_status(const struct cec_msg *msg, 943 __u8 *deck_info) 944{ 945 *deck_info = msg->msg[2]; 946} 947 948static 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 958static 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 964static 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 972static 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 */ 980struct 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 994static 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 1010static 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 1020static 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 1037static 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 1052static 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 1062static 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 1068static 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 1081static 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 1091static 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 1099static 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 1105static 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 1111static 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 */ 1119static 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 1129static 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 1135static 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 1143static 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 1153static 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 1164static 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 1178static 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 1190static 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 1201static 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 1212static 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 */ 1220static 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 1234static 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 */ 1249static 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 1260static 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 1271static 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 */ 1281static 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 1289static inline void cec_ops_menu_status(const struct cec_msg *msg, 1290 __u8 *menu_state) 1291{ 1292 *menu_state = msg->msg[2]; 1293} 1294 1295static 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 1305static inline void cec_ops_menu_request(const struct cec_msg *msg, 1306 __u8 *menu_req) 1307{ 1308 *menu_req = msg->msg[2]; 1309} 1310 1311struct 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 1325static 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 1355static 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 1384static 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 */ 1393static 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 1401static 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 1407static 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 */ 1416static 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 1425static 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 */ 1433static 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 1442static 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 */ 1450static 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 1459static 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 1467static 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 1475static 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 1483static 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 1489static 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 1501static 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 1510static 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 1518static 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 1524static 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 1532static 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 1549static 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 1564static 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 1582static 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 */ 1600static 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 1608static 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 */ 1616static 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 1622static 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 1630static 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 1638static 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 1644static 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 1652static 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 */ 1663static 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 1681static 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 1698static 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 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