blob: aa7031369791583515f8b2e879aed13967ac818b [file] [log] [blame]
// SPDX-License-Identifier: (LGPL-2.1-only OR BSD-3-Clause)
/*
* Copyright 2019 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
*/
#include <cctype>
#include <cstring>
#include <string>
#include <unistd.h>
#include <linux/cec-funcs.h>
#include <v4l-getsubopt.h>
#include "cec-htng-funcs.h"
#include "cec-log.h"
#include "cec-parse.h"
#define xstr(s) str(s)
#define str(s) #s
static struct cec_op_digital_service_id *args2digital_service_id(__u8 service_id_method,
__u8 dig_bcast_system,
__u16 transport_id,
__u16 service_id,
__u16 orig_network_id,
__u16 program_number,
__u8 channel_number_fmt,
__u16 major,
__u16 minor)
{
static struct cec_op_digital_service_id dsid;
dsid.service_id_method = service_id_method;
dsid.dig_bcast_system = dig_bcast_system;
if (service_id_method == CEC_OP_SERVICE_ID_METHOD_BY_CHANNEL) {
dsid.channel.channel_number_fmt = channel_number_fmt;
dsid.channel.major = major;
dsid.channel.minor = minor;
return &dsid;
}
switch (dig_bcast_system) {
case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_GEN:
case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_CABLE:
case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_SAT:
case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_T:
dsid.atsc.transport_id = transport_id;
dsid.atsc.program_number = program_number;
break;
default:
dsid.dvb.transport_id = transport_id;
dsid.dvb.service_id = service_id;
dsid.dvb.orig_network_id = orig_network_id;
break;
}
return &dsid;
}
static struct cec_op_ui_command *args2ui_command(__u8 ui_cmd,
__u8 has_opt_arg,
__u8 play_mode,
__u8 ui_function_media,
__u8 ui_function_select_av_input,
__u8 ui_function_select_audio_input,
__u8 ui_bcast_type,
__u8 ui_snd_pres_ctl,
__u8 channel_number_fmt,
__u16 major,
__u16 minor)
{
static struct cec_op_ui_command ui_command;
ui_command.ui_cmd = ui_cmd;
ui_command.has_opt_arg = has_opt_arg;
if (!has_opt_arg)
return &ui_command;
switch (ui_cmd) {
case CEC_OP_UI_CMD_SELECT_BROADCAST_TYPE:
ui_command.ui_broadcast_type = ui_bcast_type;
break;
case CEC_OP_UI_CMD_SELECT_SOUND_PRESENTATION:
ui_command.ui_sound_presentation_control = ui_snd_pres_ctl;
break;
case CEC_OP_UI_CMD_PLAY_FUNCTION:
ui_command.play_mode = play_mode;
break;
case CEC_OP_UI_CMD_TUNE_FUNCTION:
ui_command.channel_identifier.channel_number_fmt = channel_number_fmt;
ui_command.channel_identifier.major = major;
ui_command.channel_identifier.minor = minor;
break;
case CEC_OP_UI_CMD_SELECT_MEDIA_FUNCTION:
ui_command.ui_function_media = ui_function_media;
break;
case CEC_OP_UI_CMD_SELECT_AV_INPUT_FUNCTION:
ui_command.ui_function_select_av_input = ui_function_select_av_input;
break;
case CEC_OP_UI_CMD_SELECT_AUDIO_INPUT_FUNCTION:
ui_command.ui_function_select_audio_input = ui_function_select_audio_input;
break;
default:
ui_command.has_opt_arg = false;
break;
}
return &ui_command;
}
static __u32 *args2short_descrs(__u32 descriptor1,
__u32 descriptor2,
__u32 descriptor3,
__u32 descriptor4)
{
static __u32 descriptors[4];
descriptors[0] = descriptor1;
descriptors[1] = descriptor2;
descriptors[2] = descriptor3;
descriptors[3] = descriptor4;
return descriptors;
}
static __u8 *args2short_aud_fmt_ids(__u8 audio_format_id1,
__u8 audio_format_id2,
__u8 audio_format_id3,
__u8 audio_format_id4)
{
static __u8 audio_format_ids[4];
audio_format_ids[0] = audio_format_id1;
audio_format_ids[1] = audio_format_id2;
audio_format_ids[2] = audio_format_id3;
audio_format_ids[3] = audio_format_id4;
return audio_format_ids;
}
static __u8 *args2short_aud_fmt_codes(__u8 audio_format_code1,
__u8 audio_format_code2,
__u8 audio_format_code3,
__u8 audio_format_code4)
{
static __u8 audio_format_codes[4];
audio_format_codes[0] = audio_format_code1;
audio_format_codes[1] = audio_format_code2;
audio_format_codes[2] = audio_format_code3;
audio_format_codes[3] = audio_format_code4;
return audio_format_codes;
}
int cec_parse_subopt(char **subs, const char * const *subopts, char **value)
{
int opt = v4l_getsubopt(subs, const_cast<char * const *>(subopts), value);
if (opt == -1) {
fprintf(stderr, "Invalid suboptions specified\n");
return -1;
}
if (*value == nullptr) {
fprintf(stderr, "No value given to suboption <%s>\n",
subopts[opt]);
return -1;
}
return opt;
}
static unsigned parse_enum(const char *value, const struct cec_arg *a)
{
if (isdigit(*value))
return strtoul(value, nullptr, 0);
for (int i = 0; i < a->num_enum_values; i++) {
if (!strcmp(value, a->values[i].type_name))
return a->values[i].value;
}
return 0;
}
unsigned cec_parse_phys_addr(const char *value)
{
unsigned p1, p2, p3, p4;
if (!std::strchr(value, '.'))
return strtoul(value, nullptr, 0);
if (sscanf(value, "%x.%x.%x.%x", &p1, &p2, &p3, &p4) != 4) {
fprintf(stderr, "Expected a physical address of the form x.x.x.x\n");
return 0;
}
if (p1 > 0xf || p2 > 0xf || p3 > 0xf || p4 > 0xf) {
fprintf(stderr, "Physical address components should never be larger than 0xf\n");
return 0;
}
return (p1 << 12) | (p2 << 8) | (p3 << 4) | p4;
}
static unsigned parse_latency(const char *value)
{
char *end;
unsigned delay = strtoul(value, &end, 0);
if (!memcmp(end, "ms", 2))
delay = (delay / 2) + 1;
if (delay < 1)
delay = 1;
else if (delay > 251)
delay = 251;
return delay;
}
#define VENDOR_EXTRA \
" --vendor-command payload=<byte>[:<byte>]*\n" \
" Send VENDOR_COMMAND message (" xstr(CEC_MSG_VENDOR_COMMAND) ")\n" \
" --vendor-command-with-id vendor-id=<val>,cmd=<byte>[:<byte>]*\n" \
" Send VENDOR_COMMAND_WITH_ID message (" xstr(CEC_MSG_VENDOR_COMMAND_WITH_ID) ")\n" \
" --vendor-remote-button-down rc-code=<byte>[:<byte>]*\n" \
" Send VENDOR_REMOTE_BUTTON_DOWN message (" xstr(CEC_MSG_VENDOR_REMOTE_BUTTON_DOWN) ")\n"
#include "cec-parse-src-gen.h"