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 ? CEC_MSG_DECK_STATUS : 0;
 927}
 928
 929static inline void cec_ops_give_deck_status(const struct cec_msg *msg,
 930                                            __u8 *status_req)
 931{
 932        *status_req = msg->msg[2];
 933}
 934
 935static inline void cec_msg_play(struct cec_msg *msg,
 936                                __u8 play_mode)
 937{
 938        msg->len = 3;
 939        msg->msg[1] = CEC_MSG_PLAY;
 940        msg->msg[2] = play_mode;
 941}
 942
 943static inline void cec_ops_play(const struct cec_msg *msg,
 944                                __u8 *play_mode)
 945{
 946        *play_mode = msg->msg[2];
 947}
 948
 949
 950/* Tuner Control Feature */
 951struct cec_op_tuner_device_info {
 952        __u8 rec_flag;
 953        __u8 tuner_display_info;
 954        __u8 is_analog;
 955        union {
 956                struct cec_op_digital_service_id digital;
 957                struct {
 958                        __u8 ana_bcast_type;
 959                        __u16 ana_freq;
 960                        __u8 bcast_system;
 961                } analog;
 962        };
 963};
 964
 965static inline void cec_msg_tuner_device_status_analog(struct cec_msg *msg,
 966                                                      __u8 rec_flag,
 967                                                      __u8 tuner_display_info,
 968                                                      __u8 ana_bcast_type,
 969                                                      __u16 ana_freq,
 970                                                      __u8 bcast_system)
 971{
 972        msg->len = 7;
 973        msg->msg[1] = CEC_MSG_TUNER_DEVICE_STATUS;
 974        msg->msg[2] = (rec_flag << 7) | tuner_display_info;
 975        msg->msg[3] = ana_bcast_type;
 976        msg->msg[4] = ana_freq >> 8;
 977        msg->msg[5] = ana_freq & 0xff;
 978        msg->msg[6] = bcast_system;
 979}
 980
 981static inline void cec_msg_tuner_device_status_digital(struct cec_msg *msg,
 982                   __u8 rec_flag, __u8 tuner_display_info,
 983                   const struct cec_op_digital_service_id *digital)
 984{
 985        msg->len = 10;
 986        msg->msg[1] = CEC_MSG_TUNER_DEVICE_STATUS;
 987        msg->msg[2] = (rec_flag << 7) | tuner_display_info;
 988        cec_set_digital_service_id(msg->msg + 3, digital);
 989}
 990
 991static inline void cec_msg_tuner_device_status(struct cec_msg *msg,
 992                        const struct cec_op_tuner_device_info *tuner_dev_info)
 993{
 994        if (tuner_dev_info->is_analog)
 995                cec_msg_tuner_device_status_analog(msg,
 996                        tuner_dev_info->rec_flag,
 997                        tuner_dev_info->tuner_display_info,
 998                        tuner_dev_info->analog.ana_bcast_type,
 999                        tuner_dev_info->analog.ana_freq,
1000                        tuner_dev_info->analog.bcast_system);
1001        else
1002                cec_msg_tuner_device_status_digital(msg,
1003                        tuner_dev_info->rec_flag,
1004                        tuner_dev_info->tuner_display_info,
1005                        &tuner_dev_info->digital);
1006}
1007
1008static inline void cec_ops_tuner_device_status(const struct cec_msg *msg,
1009                                struct cec_op_tuner_device_info *tuner_dev_info)
1010{
1011        tuner_dev_info->is_analog = msg->len < 10;
1012        tuner_dev_info->rec_flag = msg->msg[2] >> 7;
1013        tuner_dev_info->tuner_display_info = msg->msg[2] & 0x7f;
1014        if (tuner_dev_info->is_analog) {
1015                tuner_dev_info->analog.ana_bcast_type = msg->msg[3];
1016                tuner_dev_info->analog.ana_freq = (msg->msg[4] << 8) | msg->msg[5];
1017                tuner_dev_info->analog.bcast_system = msg->msg[6];
1018                return;
1019        }
1020        cec_get_digital_service_id(msg->msg + 3, &tuner_dev_info->digital);
1021}
1022
1023static inline void cec_msg_give_tuner_device_status(struct cec_msg *msg,
1024                                                    int reply,
1025                                                    __u8 status_req)
1026{
1027        msg->len = 3;
1028        msg->msg[1] = CEC_MSG_GIVE_TUNER_DEVICE_STATUS;
1029        msg->msg[2] = status_req;
1030        msg->reply = reply ? CEC_MSG_TUNER_DEVICE_STATUS : 0;
1031}
1032
1033static inline void cec_ops_give_tuner_device_status(const struct cec_msg *msg,
1034                                                    __u8 *status_req)
1035{
1036        *status_req = msg->msg[2];
1037}
1038
1039static inline void cec_msg_select_analogue_service(struct cec_msg *msg,
1040                                                   __u8 ana_bcast_type,
1041                                                   __u16 ana_freq,
1042                                                   __u8 bcast_system)
1043{
1044        msg->len = 6;
1045        msg->msg[1] = CEC_MSG_SELECT_ANALOGUE_SERVICE;
1046        msg->msg[2] = ana_bcast_type;
1047        msg->msg[3] = ana_freq >> 8;
1048        msg->msg[4] = ana_freq & 0xff;
1049        msg->msg[5] = bcast_system;
1050}
1051
1052static inline void cec_ops_select_analogue_service(const struct cec_msg *msg,
1053                                                   __u8 *ana_bcast_type,
1054                                                   __u16 *ana_freq,
1055                                                   __u8 *bcast_system)
1056{
1057        *ana_bcast_type = msg->msg[2];
1058        *ana_freq = (msg->msg[3] << 8) | msg->msg[4];
1059        *bcast_system = msg->msg[5];
1060}
1061
1062static inline void cec_msg_select_digital_service(struct cec_msg *msg,
1063                                const struct cec_op_digital_service_id *digital)
1064{
1065        msg->len = 9;
1066        msg->msg[1] = CEC_MSG_SELECT_DIGITAL_SERVICE;
1067        cec_set_digital_service_id(msg->msg + 2, digital);
1068}
1069
1070static inline void cec_ops_select_digital_service(const struct cec_msg *msg,
1071                                struct cec_op_digital_service_id *digital)
1072{
1073        cec_get_digital_service_id(msg->msg + 2, digital);
1074}
1075
1076static inline void cec_msg_tuner_step_decrement(struct cec_msg *msg)
1077{
1078        msg->len = 2;
1079        msg->msg[1] = CEC_MSG_TUNER_STEP_DECREMENT;
1080}
1081
1082static inline void cec_msg_tuner_step_increment(struct cec_msg *msg)
1083{
1084        msg->len = 2;
1085        msg->msg[1] = CEC_MSG_TUNER_STEP_INCREMENT;
1086}
1087
1088
1089/* Vendor Specific Commands Feature */
1090static inline void cec_msg_device_vendor_id(struct cec_msg *msg, __u32 vendor_id)
1091{
1092        msg->len = 5;
1093        msg->msg[0] |= 0xf; /* broadcast */
1094        msg->msg[1] = CEC_MSG_DEVICE_VENDOR_ID;
1095        msg->msg[2] = vendor_id >> 16;
1096        msg->msg[3] = (vendor_id >> 8) & 0xff;
1097        msg->msg[4] = vendor_id & 0xff;
1098}
1099
1100static inline void cec_ops_device_vendor_id(const struct cec_msg *msg,
1101                                            __u32 *vendor_id)
1102{
1103        *vendor_id = (msg->msg[2] << 16) | (msg->msg[3] << 8) | msg->msg[4];
1104}
1105
1106static inline void cec_msg_give_device_vendor_id(struct cec_msg *msg,
1107                                                 int reply)
1108{
1109        msg->len = 2;
1110        msg->msg[1] = CEC_MSG_GIVE_DEVICE_VENDOR_ID;
1111        msg->reply = reply ? CEC_MSG_DEVICE_VENDOR_ID : 0;
1112}
1113
1114static inline void cec_msg_vendor_command(struct cec_msg *msg,
1115                                          __u8 size, const __u8 *vendor_cmd)
1116{
1117        if (size > 14)
1118                size = 14;
1119        msg->len = 2 + size;
1120        msg->msg[1] = CEC_MSG_VENDOR_COMMAND;
1121        memcpy(msg->msg + 2, vendor_cmd, size);
1122}
1123
1124static inline void cec_ops_vendor_command(const struct cec_msg *msg,
1125                                          __u8 *size,
1126                                          const __u8 **vendor_cmd)
1127{
1128        *size = msg->len - 2;
1129
1130        if (*size > 14)
1131                *size = 14;
1132        *vendor_cmd = msg->msg + 2;
1133}
1134
1135static inline void cec_msg_vendor_command_with_id(struct cec_msg *msg,
1136                                                  __u32 vendor_id, __u8 size,
1137                                                  const __u8 *vendor_cmd)
1138{
1139        if (size > 11)
1140                size = 11;
1141        msg->len = 5 + size;
1142        msg->msg[1] = CEC_MSG_VENDOR_COMMAND_WITH_ID;
1143        msg->msg[2] = vendor_id >> 16;
1144        msg->msg[3] = (vendor_id >> 8) & 0xff;
1145        msg->msg[4] = vendor_id & 0xff;
1146        memcpy(msg->msg + 5, vendor_cmd, size);
1147}
1148
1149static inline void cec_ops_vendor_command_with_id(const struct cec_msg *msg,
1150                                                  __u32 *vendor_id,  __u8 *size,
1151                                                  const __u8 **vendor_cmd)
1152{
1153        *size = msg->len - 5;
1154
1155        if (*size > 11)
1156                *size = 11;
1157        *vendor_id = (msg->msg[2] << 16) | (msg->msg[3] << 8) | msg->msg[4];
1158        *vendor_cmd = msg->msg + 5;
1159}
1160
1161static inline void cec_msg_vendor_remote_button_down(struct cec_msg *msg,
1162                                                     __u8 size,
1163                                                     const __u8 *rc_code)
1164{
1165        if (size > 14)
1166                size = 14;
1167        msg->len = 2 + size;
1168        msg->msg[1] = CEC_MSG_VENDOR_REMOTE_BUTTON_DOWN;
1169        memcpy(msg->msg + 2, rc_code, size);
1170}
1171
1172static inline void cec_ops_vendor_remote_button_down(const struct cec_msg *msg,
1173                                                     __u8 *size,
1174                                                     const __u8 **rc_code)
1175{
1176        *size = msg->len - 2;
1177
1178        if (*size > 14)
1179                *size = 14;
1180        *rc_code = msg->msg + 2;
1181}
1182
1183static inline void cec_msg_vendor_remote_button_up(struct cec_msg *msg)
1184{
1185        msg->len = 2;
1186        msg->msg[1] = CEC_MSG_VENDOR_REMOTE_BUTTON_UP;
1187}
1188
1189
1190/* OSD Display Feature */
1191static inline void cec_msg_set_osd_string(struct cec_msg *msg,
1192                                          __u8 disp_ctl,
1193                                          const char *osd)
1194{
1195        unsigned int len = strlen(osd);
1196
1197        if (len > 13)
1198                len = 13;
1199        msg->len = 3 + len;
1200        msg->msg[1] = CEC_MSG_SET_OSD_STRING;
1201        msg->msg[2] = disp_ctl;
1202        memcpy(msg->msg + 3, osd, len);
1203}
1204
1205static inline void cec_ops_set_osd_string(const struct cec_msg *msg,
1206                                          __u8 *disp_ctl,
1207                                          char *osd)
1208{
1209        unsigned int len = msg->len > 3 ? msg->len - 3 : 0;
1210
1211        *disp_ctl = msg->msg[2];
1212        if (len > 13)
1213                len = 13;
1214        memcpy(osd, msg->msg + 3, len);
1215        osd[len] = '\0';
1216}
1217
1218
1219/* Device OSD Transfer Feature */
1220static inline void cec_msg_set_osd_name(struct cec_msg *msg, const char *name)
1221{
1222        unsigned int len = strlen(name);
1223
1224        if (len > 14)
1225                len = 14;
1226        msg->len = 2 + len;
1227        msg->msg[1] = CEC_MSG_SET_OSD_NAME;
1228        memcpy(msg->msg + 2, name, len);
1229}
1230
1231static inline void cec_ops_set_osd_name(const struct cec_msg *msg,
1232                                        char *name)
1233{
1234        unsigned int len = msg->len > 2 ? msg->len - 2 : 0;
1235
1236        if (len > 14)
1237                len = 14;
1238        memcpy(name, msg->msg + 2, len);
1239        name[len] = '\0';
1240}
1241
1242static inline void cec_msg_give_osd_name(struct cec_msg *msg,
1243                                         int reply)
1244{
1245        msg->len = 2;
1246        msg->msg[1] = CEC_MSG_GIVE_OSD_NAME;
1247        msg->reply = reply ? CEC_MSG_SET_OSD_NAME : 0;
1248}
1249
1250
1251/* Device Menu Control Feature */
1252static inline void cec_msg_menu_status(struct cec_msg *msg,
1253                                       __u8 menu_state)
1254{
1255        msg->len = 3;
1256        msg->msg[1] = CEC_MSG_MENU_STATUS;
1257        msg->msg[2] = menu_state;
1258}
1259
1260static inline void cec_ops_menu_status(const struct cec_msg *msg,
1261                                       __u8 *menu_state)
1262{
1263        *menu_state = msg->msg[2];
1264}
1265
1266static inline void cec_msg_menu_request(struct cec_msg *msg,
1267                                        int reply,
1268                                        __u8 menu_req)
1269{
1270        msg->len = 3;
1271        msg->msg[1] = CEC_MSG_MENU_REQUEST;
1272        msg->msg[2] = menu_req;
1273        msg->reply = reply ? CEC_MSG_MENU_STATUS : 0;
1274}
1275
1276static inline void cec_ops_menu_request(const struct cec_msg *msg,
1277                                        __u8 *menu_req)
1278{
1279        *menu_req = msg->msg[2];
1280}
1281
1282struct cec_op_ui_command {
1283        __u8 ui_cmd;
1284        __u8 has_opt_arg;
1285        union {
1286                struct cec_op_channel_data channel_identifier;
1287                __u8 ui_broadcast_type;
1288                __u8 ui_sound_presentation_control;
1289                __u8 play_mode;
1290                __u8 ui_function_media;
1291                __u8 ui_function_select_av_input;
1292                __u8 ui_function_select_audio_input;
1293        };
1294};
1295
1296static inline void cec_msg_user_control_pressed(struct cec_msg *msg,
1297                                        const struct cec_op_ui_command *ui_cmd)
1298{
1299        msg->len = 3;
1300        msg->msg[1] = CEC_MSG_USER_CONTROL_PRESSED;
1301        msg->msg[2] = ui_cmd->ui_cmd;
1302        if (!ui_cmd->has_opt_arg)
1303                return;
1304        switch (ui_cmd->ui_cmd) {
1305        case 0x56:
1306        case 0x57:
1307        case 0x60:
1308        case 0x68:
1309        case 0x69:
1310        case 0x6a:
1311                /* The optional operand is one byte for all these ui commands */
1312                msg->len++;
1313                msg->msg[3] = ui_cmd->play_mode;
1314                break;
1315        case 0x67:
1316                msg->len += 4;
1317                msg->msg[3] = (ui_cmd->channel_identifier.channel_number_fmt << 2) |
1318                              (ui_cmd->channel_identifier.major >> 8);
1319                msg->msg[4] = ui_cmd->channel_identifier.major & 0xff;
1320                msg->msg[5] = ui_cmd->channel_identifier.minor >> 8;
1321                msg->msg[6] = ui_cmd->channel_identifier.minor & 0xff;
1322                break;
1323        }
1324}
1325
1326static inline void cec_ops_user_control_pressed(const struct cec_msg *msg,
1327                                                struct cec_op_ui_command *ui_cmd)
1328{
1329        ui_cmd->ui_cmd = msg->msg[2];
1330        ui_cmd->has_opt_arg = 0;
1331        if (msg->len == 3)
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                ui_cmd->play_mode = msg->msg[3];
1342                ui_cmd->has_opt_arg = 1;
1343                break;
1344        case 0x67:
1345                if (msg->len < 7)
1346                        break;
1347                ui_cmd->has_opt_arg = 1;
1348                ui_cmd->channel_identifier.channel_number_fmt = msg->msg[3] >> 2;
1349                ui_cmd->channel_identifier.major = ((msg->msg[3] & 3) << 6) | msg->msg[4];
1350                ui_cmd->channel_identifier.minor = (msg->msg[5] << 8) | msg->msg[6];
1351                break;
1352        }
1353}
1354
1355static inline void cec_msg_user_control_released(struct cec_msg *msg)
1356{
1357        msg->len = 2;
1358        msg->msg[1] = CEC_MSG_USER_CONTROL_RELEASED;
1359}
1360
1361/* Remote Control Passthrough Feature */
1362
1363/* Power Status Feature */
1364static inline void cec_msg_report_power_status(struct cec_msg *msg,
1365                                               __u8 pwr_state)
1366{
1367        msg->len = 3;
1368        msg->msg[1] = CEC_MSG_REPORT_POWER_STATUS;
1369        msg->msg[2] = pwr_state;
1370}
1371
1372static inline void cec_ops_report_power_status(const struct cec_msg *msg,
1373                                               __u8 *pwr_state)
1374{
1375        *pwr_state = msg->msg[2];
1376}
1377
1378static inline void cec_msg_give_device_power_status(struct cec_msg *msg,
1379                                                    int reply)
1380{
1381        msg->len = 2;
1382        msg->msg[1] = CEC_MSG_GIVE_DEVICE_POWER_STATUS;
1383        msg->reply = reply ? CEC_MSG_REPORT_POWER_STATUS : 0;
1384}
1385
1386/* General Protocol Messages */
1387static inline void cec_msg_feature_abort(struct cec_msg *msg,
1388                                         __u8 abort_msg, __u8 reason)
1389{
1390        msg->len = 4;
1391        msg->msg[1] = CEC_MSG_FEATURE_ABORT;
1392        msg->msg[2] = abort_msg;
1393        msg->msg[3] = reason;
1394}
1395
1396static inline void cec_ops_feature_abort(const struct cec_msg *msg,
1397                                         __u8 *abort_msg, __u8 *reason)
1398{
1399        *abort_msg = msg->msg[2];
1400        *reason = msg->msg[3];
1401}
1402
1403/* This changes the current message into a feature abort message */
1404static inline void cec_msg_reply_feature_abort(struct cec_msg *msg, __u8 reason)
1405{
1406        cec_msg_set_reply_to(msg, msg);
1407        msg->len = 4;
1408        msg->msg[2] = msg->msg[1];
1409        msg->msg[3] = reason;
1410        msg->msg[1] = CEC_MSG_FEATURE_ABORT;
1411}
1412
1413static inline void cec_msg_abort(struct cec_msg *msg)
1414{
1415        msg->len = 2;
1416        msg->msg[1] = CEC_MSG_ABORT;
1417}
1418
1419
1420/* System Audio Control Feature */
1421static inline void cec_msg_report_audio_status(struct cec_msg *msg,
1422                                               __u8 aud_mute_status,
1423                                               __u8 aud_vol_status)
1424{
1425        msg->len = 3;
1426        msg->msg[1] = CEC_MSG_REPORT_AUDIO_STATUS;
1427        msg->msg[2] = (aud_mute_status << 7) | (aud_vol_status & 0x7f);
1428}
1429
1430static inline void cec_ops_report_audio_status(const struct cec_msg *msg,
1431                                               __u8 *aud_mute_status,
1432                                               __u8 *aud_vol_status)
1433{
1434        *aud_mute_status = msg->msg[2] >> 7;
1435        *aud_vol_status = msg->msg[2] & 0x7f;
1436}
1437
1438static inline void cec_msg_give_audio_status(struct cec_msg *msg,
1439                                             int reply)
1440{
1441        msg->len = 2;
1442        msg->msg[1] = CEC_MSG_GIVE_AUDIO_STATUS;
1443        msg->reply = reply ? CEC_MSG_REPORT_AUDIO_STATUS : 0;
1444}
1445
1446static inline void cec_msg_set_system_audio_mode(struct cec_msg *msg,
1447                                                 __u8 sys_aud_status)
1448{
1449        msg->len = 3;
1450        msg->msg[1] = CEC_MSG_SET_SYSTEM_AUDIO_MODE;
1451        msg->msg[2] = sys_aud_status;
1452}
1453
1454static inline void cec_ops_set_system_audio_mode(const struct cec_msg *msg,
1455                                                 __u8 *sys_aud_status)
1456{
1457        *sys_aud_status = msg->msg[2];
1458}
1459
1460static inline void cec_msg_system_audio_mode_request(struct cec_msg *msg,
1461                                                     int reply,
1462                                                     __u16 phys_addr)
1463{
1464        msg->len = phys_addr == 0xffff ? 2 : 4;
1465        msg->msg[1] = CEC_MSG_SYSTEM_AUDIO_MODE_REQUEST;
1466        msg->msg[2] = phys_addr >> 8;
1467        msg->msg[3] = phys_addr & 0xff;
1468        msg->reply = reply ? CEC_MSG_SET_SYSTEM_AUDIO_MODE : 0;
1469
1470}
1471
1472static inline void cec_ops_system_audio_mode_request(const struct cec_msg *msg,
1473                                                     __u16 *phys_addr)
1474{
1475        if (msg->len < 4)
1476                *phys_addr = 0xffff;
1477        else
1478                *phys_addr = (msg->msg[2] << 8) | msg->msg[3];
1479}
1480
1481static inline void cec_msg_system_audio_mode_status(struct cec_msg *msg,
1482                                                    __u8 sys_aud_status)
1483{
1484        msg->len = 3;
1485        msg->msg[1] = CEC_MSG_SYSTEM_AUDIO_MODE_STATUS;
1486        msg->msg[2] = sys_aud_status;
1487}
1488
1489static inline void cec_ops_system_audio_mode_status(const struct cec_msg *msg,
1490                                                    __u8 *sys_aud_status)
1491{
1492        *sys_aud_status = msg->msg[2];
1493}
1494
1495static inline void cec_msg_give_system_audio_mode_status(struct cec_msg *msg,
1496                                                         int reply)
1497{
1498        msg->len = 2;
1499        msg->msg[1] = CEC_MSG_GIVE_SYSTEM_AUDIO_MODE_STATUS;
1500        msg->reply = reply ? CEC_MSG_SYSTEM_AUDIO_MODE_STATUS : 0;
1501}
1502
1503static inline void cec_msg_report_short_audio_descriptor(struct cec_msg *msg,
1504                                        __u8 num_descriptors,
1505                                        const __u32 *descriptors)
1506{
1507        unsigned int i;
1508
1509        if (num_descriptors > 4)
1510                num_descriptors = 4;
1511        msg->len = 2 + num_descriptors * 3;
1512        msg->msg[1] = CEC_MSG_REPORT_SHORT_AUDIO_DESCRIPTOR;
1513        for (i = 0; i < num_descriptors; i++) {
1514                msg->msg[2 + i * 3] = (descriptors[i] >> 16) & 0xff;
1515                msg->msg[3 + i * 3] = (descriptors[i] >> 8) & 0xff;
1516                msg->msg[4 + i * 3] = descriptors[i] & 0xff;
1517        }
1518}
1519
1520static inline void cec_ops_report_short_audio_descriptor(const struct cec_msg *msg,
1521                                                         __u8 *num_descriptors,
1522                                                         __u32 *descriptors)
1523{
1524        unsigned int i;
1525
1526        *num_descriptors = (msg->len - 2) / 3;
1527        if (*num_descriptors > 4)
1528                *num_descriptors = 4;
1529        for (i = 0; i < *num_descriptors; i++)
1530                descriptors[i] = (msg->msg[2 + i * 3] << 16) |
1531                        (msg->msg[3 + i * 3] << 8) |
1532                        msg->msg[4 + i * 3];
1533}
1534
1535static inline void cec_msg_request_short_audio_descriptor(struct cec_msg *msg,
1536                                        int reply,
1537                                        __u8 num_descriptors,
1538                                        const __u8 *audio_format_id,
1539                                        const __u8 *audio_format_code)
1540{
1541        unsigned int i;
1542
1543        if (num_descriptors > 4)
1544                num_descriptors = 4;
1545        msg->len = 2 + num_descriptors;
1546        msg->msg[1] = CEC_MSG_REQUEST_SHORT_AUDIO_DESCRIPTOR;
1547        msg->reply = reply ? CEC_MSG_REPORT_SHORT_AUDIO_DESCRIPTOR : 0;
1548        for (i = 0; i < num_descriptors; i++)
1549                msg->msg[2 + i] = (audio_format_id[i] << 6) |
1550                                  (audio_format_code[i] & 0x3f);
1551}
1552
1553static inline void cec_ops_request_short_audio_descriptor(const struct cec_msg *msg,
1554                                        __u8 *num_descriptors,
1555                                        __u8 *audio_format_id,
1556                                        __u8 *audio_format_code)
1557{
1558        unsigned int i;
1559
1560        *num_descriptors = msg->len - 2;
1561        if (*num_descriptors > 4)
1562                *num_descriptors = 4;
1563        for (i = 0; i < *num_descriptors; i++) {
1564                audio_format_id[i] = msg->msg[2 + i] >> 6;
1565                audio_format_code[i] = msg->msg[2 + i] & 0x3f;
1566        }
1567}
1568
1569
1570/* Audio Rate Control Feature */
1571static inline void cec_msg_set_audio_rate(struct cec_msg *msg,
1572                                          __u8 audio_rate)
1573{
1574        msg->len = 3;
1575        msg->msg[1] = CEC_MSG_SET_AUDIO_RATE;
1576        msg->msg[2] = audio_rate;
1577}
1578
1579static inline void cec_ops_set_audio_rate(const struct cec_msg *msg,
1580                                          __u8 *audio_rate)
1581{
1582        *audio_rate = msg->msg[2];
1583}
1584
1585
1586/* Audio Return Channel Control Feature */
1587static inline void cec_msg_report_arc_initiated(struct cec_msg *msg)
1588{
1589        msg->len = 2;
1590        msg->msg[1] = CEC_MSG_REPORT_ARC_INITIATED;
1591}
1592
1593static inline void cec_msg_initiate_arc(struct cec_msg *msg,
1594                                        int reply)
1595{
1596        msg->len = 2;
1597        msg->msg[1] = CEC_MSG_INITIATE_ARC;
1598        msg->reply = reply ? CEC_MSG_REPORT_ARC_INITIATED : 0;
1599}
1600
1601static inline void cec_msg_request_arc_initiation(struct cec_msg *msg,
1602                                                  int reply)
1603{
1604        msg->len = 2;
1605        msg->msg[1] = CEC_MSG_REQUEST_ARC_INITIATION;
1606        msg->reply = reply ? CEC_MSG_INITIATE_ARC : 0;
1607}
1608
1609static inline void cec_msg_report_arc_terminated(struct cec_msg *msg)
1610{
1611        msg->len = 2;
1612        msg->msg[1] = CEC_MSG_REPORT_ARC_TERMINATED;
1613}
1614
1615static inline void cec_msg_terminate_arc(struct cec_msg *msg,
1616                                         int reply)
1617{
1618        msg->len = 2;
1619        msg->msg[1] = CEC_MSG_TERMINATE_ARC;
1620        msg->reply = reply ? CEC_MSG_REPORT_ARC_TERMINATED : 0;
1621}
1622
1623static inline void cec_msg_request_arc_termination(struct cec_msg *msg,
1624                                                   int reply)
1625{
1626        msg->len = 2;
1627        msg->msg[1] = CEC_MSG_REQUEST_ARC_TERMINATION;
1628        msg->reply = reply ? CEC_MSG_TERMINATE_ARC : 0;
1629}
1630
1631
1632/* Dynamic Audio Lipsync Feature */
1633/* Only for CEC 2.0 and up */
1634static inline void cec_msg_report_current_latency(struct cec_msg *msg,
1635                                                  __u16 phys_addr,
1636                                                  __u8 video_latency,
1637                                                  __u8 low_latency_mode,
1638                                                  __u8 audio_out_compensated,
1639                                                  __u8 audio_out_delay)
1640{
1641        msg->len = 6;
1642        msg->msg[0] |= 0xf; /* broadcast */
1643        msg->msg[1] = CEC_MSG_REPORT_CURRENT_LATENCY;
1644        msg->msg[2] = phys_addr >> 8;
1645        msg->msg[3] = phys_addr & 0xff;
1646        msg->msg[4] = video_latency;
1647        msg->msg[5] = (low_latency_mode << 2) | audio_out_compensated;
1648        if (audio_out_compensated == 3)
1649                msg->msg[msg->len++] = audio_out_delay;
1650}
1651
1652static inline void cec_ops_report_current_latency(const struct cec_msg *msg,
1653                                                  __u16 *phys_addr,
1654                                                  __u8 *video_latency,
1655                                                  __u8 *low_latency_mode,
1656                                                  __u8 *audio_out_compensated,
1657                                                  __u8 *audio_out_delay)
1658{
1659        *phys_addr = (msg->msg[2] << 8) | msg->msg[3];
1660        *video_latency = msg->msg[4];
1661        *low_latency_mode = (msg->msg[5] >> 2) & 1;
1662        *audio_out_compensated = msg->msg[5] & 3;
1663        if (*audio_out_compensated == 3 && msg->len >= 7)
1664                *audio_out_delay = msg->msg[6];
1665        else
1666                *audio_out_delay = 0;
1667}
1668
1669static inline void cec_msg_request_current_latency(struct cec_msg *msg,
1670                                                   int reply,
1671                                                   __u16 phys_addr)
1672{
1673        msg->len = 4;
1674        msg->msg[0] |= 0xf; /* broadcast */
1675        msg->msg[1] = CEC_MSG_REQUEST_CURRENT_LATENCY;
1676        msg->msg[2] = phys_addr >> 8;
1677        msg->msg[3] = phys_addr & 0xff;
1678        msg->reply = reply ? CEC_MSG_REPORT_CURRENT_LATENCY : 0;
1679}
1680
1681static inline void cec_ops_request_current_latency(const struct cec_msg *msg,
1682                                                   __u16 *phys_addr)
1683{
1684        *phys_addr = (msg->msg[2] << 8) | msg->msg[3];
1685}
1686
1687
1688/* Capability Discovery and Control Feature */
1689static inline void cec_msg_cdc_hec_inquire_state(struct cec_msg *msg,
1690                                                 __u16 phys_addr1,
1691                                                 __u16 phys_addr2)
1692{
1693        msg->len = 9;
1694        msg->msg[0] |= 0xf; /* broadcast */
1695        msg->msg[1] = CEC_MSG_CDC_MESSAGE;
1696        /* msg[2] and msg[3] (phys_addr) are filled in by the CEC framework */
1697        msg->msg[4] = CEC_MSG_CDC_HEC_INQUIRE_STATE;
1698        msg->msg[5] = phys_addr1 >> 8;
1699        msg->msg[6] = phys_addr1 & 0xff;
1700        msg->msg[7] = phys_addr2 >> 8;
1701        msg->msg[8] = phys_addr2 & 0xff;
1702}
1703
1704static inline void cec_ops_cdc_hec_inquire_state(const struct cec_msg *msg,
1705                                                 __u16 *phys_addr,
1706                                                 __u16 *phys_addr1,
1707                                                 __u16 *phys_addr2)
1708{
1709        *phys_addr = (msg->msg[2] << 8) | msg->msg[3];
1710        *phys_addr1 = (msg->msg[5] << 8) | msg->msg[6];
1711        *phys_addr2 = (msg->msg[7] << 8) | msg->msg[8];
1712}
1713
1714static inline void cec_msg_cdc_hec_report_state(struct cec_msg *msg,
1715                                                __u16 target_phys_addr,
1716                                                __u8 hec_func_state,
1717                                                __u8 host_func_state,
1718                                                __u8 enc_func_state,
1719                                                __u8 cdc_errcode,
1720                                                __u8 has_field,
1721                                                __u16 hec_field)
1722{
1723        msg->len = has_field ? 10 : 8;
1724        msg->msg[0] |= 0xf; /* broadcast */
1725        msg->msg[1] = CEC_MSG_CDC_MESSAGE;
1726        /* msg[2] and msg[3] (phys_addr) are filled in by the CEC framework */
1727        msg->msg[4] = CEC_MSG_CDC_HEC_REPORT_STATE;
1728        msg->msg[5] = target_phys_addr >> 8;
1729        msg->msg[6] = target_phys_addr & 0xff;
1730        msg->msg[7] = (hec_func_state << 6) |
1731                      (host_func_state << 4) |
1732                      (enc_func_state << 2) |
1733                      cdc_errcode;
1734        if (has_field) {
1735                msg->msg[8] = hec_field >> 8;
1736                msg->msg[9] = hec_field & 0xff;
1737        }
1738}
1739
1740static inline void cec_ops_cdc_hec_report_state(const struct cec_msg *msg,
1741                                                __u16 *phys_addr,
1742                                                __u16 *target_phys_addr,
1743                                                __u8 *hec_func_state,
1744                                                __u8 *host_func_state,
1745                                                __u8 *enc_func_state,
1746                                                __u8 *cdc_errcode,
1747                                                __u8 *has_field,
1748                                                __u16 *hec_field)
1749{
1750        *phys_addr = (msg->msg[2] << 8) | msg->msg[3];
1751        *target_phys_addr = (msg->msg[5] << 8) | msg->msg[6];
1752        *hec_func_state = msg->msg[7] >> 6;
1753        *host_func_state = (msg->msg[7] >> 4) & 3;
1754        *enc_func_state = (msg->msg[7] >> 4) & 3;
1755        *cdc_errcode = msg->msg[7] & 3;
1756        *has_field = msg->len >= 10;
1757        *hec_field = *has_field ? ((msg->msg[8] << 8) | msg->msg[9]) : 0;
1758}
1759
1760static inline void cec_msg_cdc_hec_set_state(struct cec_msg *msg,
1761                                             __u16 phys_addr1,
1762                                             __u16 phys_addr2,
1763                                             __u8 hec_set_state,
1764                                             __u16 phys_addr3,
1765                                             __u16 phys_addr4,
1766                                             __u16 phys_addr5)
1767{
1768        msg->len = 10;
1769        msg->msg[0] |= 0xf; /* broadcast */
1770        msg->msg[1] = CEC_MSG_CDC_MESSAGE;
1771        /* msg[2] and msg[3] (phys_addr) are filled in by the CEC framework */
1772        msg->msg[4] = CEC_MSG_CDC_HEC_INQUIRE_STATE;
1773        msg->msg[5] = phys_addr1 >> 8;
1774        msg->msg[6] = phys_addr1 & 0xff;
1775        msg->msg[7] = phys_addr2 >> 8;
1776        msg->msg[8] = phys_addr2 & 0xff;
1777        msg->msg[9] = hec_set_state;
1778        if (phys_addr3 != CEC_PHYS_ADDR_INVALID) {
1779                msg->msg[msg->len++] = phys_addr3 >> 8;
1780                msg->msg[msg->len++] = phys_addr3 & 0xff;
1781                if (phys_addr4 != CEC_PHYS_ADDR_INVALID) {
1782                        msg->msg[msg->len++] = phys_addr4 >> 8;
1783                        msg->msg[msg->len++] = phys_addr4 & 0xff;
1784                        if (phys_addr5 != CEC_PHYS_ADDR_INVALID) {
1785                                msg->msg[msg->len++] = phys_addr5 >> 8;
1786                                msg->msg[msg->len++] = phys_addr5 & 0xff;
1787                        }
1788                }
1789        }
1790}
1791
1792static inline void cec_ops_cdc_hec_set_state(const struct cec_msg *msg,
1793                                             __u16 *phys_addr,
1794                                             __u16 *phys_addr1,
1795                                             __u16 *phys_addr2,
1796                                             __u8 *hec_set_state,
1797                                             __u16 *phys_addr3,
1798                                             __u16 *phys_addr4,
1799                                             __u16 *phys_addr5)
1800{
1801        *phys_addr = (msg->msg[2] << 8) | msg->msg[3];
1802        *phys_addr1 = (msg->msg[5] << 8) | msg->msg[6];
1803        *phys_addr2 = (msg->msg[7] << 8) | msg->msg[8];
1804        *hec_set_state = msg->msg[9];
1805        *phys_addr3 = *phys_addr4 = *phys_addr5 = CEC_PHYS_ADDR_INVALID;
1806        if (msg->len >= 12)
1807                *phys_addr3 = (msg->msg[10] << 8) | msg->msg[11];
1808        if (msg->len >= 14)
1809                *phys_addr4 = (msg->msg[12] << 8) | msg->msg[13];
1810        if (msg->len >= 16)
1811                *phys_addr5 = (msg->msg[14] << 8) | msg->msg[15];
1812}
1813
1814static inline void cec_msg_cdc_hec_set_state_adjacent(struct cec_msg *msg,
1815                                                      __u16 phys_addr1,
1816                                                      __u8 hec_set_state)
1817{
1818        msg->len = 8;
1819        msg->msg[0] |= 0xf; /* broadcast */
1820        msg->msg[1] = CEC_MSG_CDC_MESSAGE;
1821        /* msg[2] and msg[3] (phys_addr) are filled in by the CEC framework */
1822        msg->msg[4] = CEC_MSG_CDC_HEC_SET_STATE_ADJACENT;
1823        msg->msg[5] = phys_addr1 >> 8;
1824        msg->msg[6] = phys_addr1 & 0xff;
1825        msg->msg[7] = hec_set_state;
1826}
1827
1828static inline void cec_ops_cdc_hec_set_state_adjacent(const struct cec_msg *msg,
1829                                                      __u16 *phys_addr,
1830                                                      __u16 *phys_addr1,
1831                                                      __u8 *hec_set_state)
1832{
1833        *phys_addr = (msg->msg[2] << 8) | msg->msg[3];
1834        *phys_addr1 = (msg->msg[5] << 8) | msg->msg[6];
1835        *hec_set_state = msg->msg[7];
1836}
1837
1838static inline void cec_msg_cdc_hec_request_deactivation(struct cec_msg *msg,
1839                                                        __u16 phys_addr1,
1840                                                        __u16 phys_addr2,
1841                                                        __u16 phys_addr3)
1842{
1843        msg->len = 11;
1844        msg->msg[0] |= 0xf; /* broadcast */
1845        msg->msg[1] = CEC_MSG_CDC_MESSAGE;
1846        /* msg[2] and msg[3] (phys_addr) are filled in by the CEC framework */
1847        msg->msg[4] = CEC_MSG_CDC_HEC_REQUEST_DEACTIVATION;
1848        msg->msg[5] = phys_addr1 >> 8;
1849        msg->msg[6] = phys_addr1 & 0xff;
1850        msg->msg[7] = phys_addr2 >> 8;
1851        msg->msg[8] = phys_addr2 & 0xff;
1852        msg->msg[9] = phys_addr3 >> 8;
1853        msg->msg[10] = phys_addr3 & 0xff;
1854}
1855
1856static inline void cec_ops_cdc_hec_request_deactivation(const struct cec_msg *msg,
1857                                                        __u16 *phys_addr,
1858                                                        __u16 *phys_addr1,
1859                                                        __u16 *phys_addr2,
1860                                                        __u16 *phys_addr3)
1861{
1862        *phys_addr = (msg->msg[2] << 8) | msg->msg[3];
1863        *phys_addr1 = (msg->msg[5] << 8) | msg->msg[6];
1864        *phys_addr2 = (msg->msg[7] << 8) | msg->msg[8];
1865        *phys_addr3 = (msg->msg[9] << 8) | msg->msg[10];
1866}
1867
1868static inline void cec_msg_cdc_hec_notify_alive(struct cec_msg *msg)
1869{
1870        msg->len = 5;
1871        msg->msg[0] |= 0xf; /* broadcast */
1872        msg->msg[1] = CEC_MSG_CDC_MESSAGE;
1873        /* msg[2] and msg[3] (phys_addr) are filled in by the CEC framework */
1874        msg->msg[4] = CEC_MSG_CDC_HEC_NOTIFY_ALIVE;
1875}
1876
1877static inline void cec_ops_cdc_hec_notify_alive(const struct cec_msg *msg,
1878                                                __u16 *phys_addr)
1879{
1880        *phys_addr = (msg->msg[2] << 8) | msg->msg[3];
1881}
1882
1883static inline void cec_msg_cdc_hec_discover(struct cec_msg *msg)
1884{
1885        msg->len = 5;
1886        msg->msg[0] |= 0xf; /* broadcast */
1887        msg->msg[1] = CEC_MSG_CDC_MESSAGE;
1888        /* msg[2] and msg[3] (phys_addr) are filled in by the CEC framework */
1889        msg->msg[4] = CEC_MSG_CDC_HEC_DISCOVER;
1890}
1891
1892static inline void cec_ops_cdc_hec_discover(const struct cec_msg *msg,
1893                                            __u16 *phys_addr)
1894{
1895        *phys_addr = (msg->msg[2] << 8) | msg->msg[3];
1896}
1897
1898static inline void cec_msg_cdc_hpd_set_state(struct cec_msg *msg,
1899                                             __u8 input_port,
1900                                             __u8 hpd_state)
1901{
1902        msg->len = 6;
1903        msg->msg[0] |= 0xf; /* broadcast */
1904        msg->msg[1] = CEC_MSG_CDC_MESSAGE;
1905        /* msg[2] and msg[3] (phys_addr) are filled in by the CEC framework */
1906        msg->msg[4] = CEC_MSG_CDC_HPD_SET_STATE;
1907        msg->msg[5] = (input_port << 4) | hpd_state;
1908}
1909
1910static inline void cec_ops_cdc_hpd_set_state(const struct cec_msg *msg,
1911                                            __u16 *phys_addr,
1912                                            __u8 *input_port,
1913                                            __u8 *hpd_state)
1914{
1915        *phys_addr = (msg->msg[2] << 8) | msg->msg[3];
1916        *input_port = msg->msg[5] >> 4;
1917        *hpd_state = msg->msg[5] & 0xf;
1918}
1919
1920static inline void cec_msg_cdc_hpd_report_state(struct cec_msg *msg,
1921                                                __u8 hpd_state,
1922                                                __u8 hpd_error)
1923{
1924        msg->len = 6;
1925        msg->msg[0] |= 0xf; /* broadcast */
1926        msg->msg[1] = CEC_MSG_CDC_MESSAGE;
1927        /* msg[2] and msg[3] (phys_addr) are filled in by the CEC framework */
1928        msg->msg[4] = CEC_MSG_CDC_HPD_REPORT_STATE;
1929        msg->msg[5] = (hpd_state << 4) | hpd_error;
1930}
1931
1932static inline void cec_ops_cdc_hpd_report_state(const struct cec_msg *msg,
1933                                                __u16 *phys_addr,
1934                                                __u8 *hpd_state,
1935                                                __u8 *hpd_error)
1936{
1937        *phys_addr = (msg->msg[2] << 8) | msg->msg[3];
1938        *hpd_state = msg->msg[5] >> 4;
1939        *hpd_error = msg->msg[5] & 0xf;
1940}
1941
1942#endif
1943