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