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