/** @file ddcutil_types.h * @brief File ddcutil_types.h contains type declarations for the C API. * * API function declarations are specified in a separate file, ddcutil_c_api.h. * The reason for this split is that the type declarations are used throughout the * **ddcutil** implementation, whereas the function declarations are only referenced * within the code that implements the API. */ // Copyright (C) 2014-2024 Sanford Rockowitz // SPDX-License-Identifier: GPL-2.0-or-later #ifndef DDCUTIL_TYPES_H_ #define DDCUTIL_TYPES_H_ #ifdef __cplusplus extern "C" { #endif /** @cond */ #include #include // for uint8_t, unit16_t /** @endcond */ // // Status Code // /** * **ddcutil** Status Code * * Most public **ddcutil** functions return a status code. * These status codes have 3 sources: * - Linux * - ADL (AMD Display Library) (no longer used) * - **ddcutil** itself * * These multiple status code sources are consolidated by "modulating" * the raw values into non-overlapping ranges. * - Linux errno values are returned as negative numbers (e.g. -EIO) * - ADL values are modulated by 2000 (i.e., 2000 subtracted from negative ADL status codes, * or added to positive ADL status codes) (no longer used) * - ddcutil errors are always in the -3000 range * * In summary: * - 0 always indicates a normal successful status * - Positive values (possible with ADL) represent qualified success of some sort (no longer used) * - Negative values indicate an error condition. */ typedef int DDCA_Status; // // Build Information // //! ddcutil version //! typedef struct { uint8_t major; ///< Major release number uint8_t minor; ///< Minor release number uint8_t micro; ///< Micro release number } DDCA_Ddcutil_Version_Spec; //! Build option flags, as returned by #ddca_build_options() //! The enum values are defined as 1,2,4 etc so that they can be or'd. typedef enum { DDCA_BUILT_WITH_NONE = 0x00, /** @brief ddcutil was built with support for USB connected monitors */ DDCA_BUILT_WITH_USB = 0x02, /** @brief ddcutil was built with support for failure simulation */ DDCA_BUILT_WITH_FAILSIM = 0x04 } DDCA_Build_Option_Flags; // // Error Reporting // #define DDCA_ERROR_DETAIL_MARKER "EDTL" //! Detailed error report typedef struct ddca_error_detail { char marker[4]; ///< Always "EDTL" DDCA_Status status_code; ///< Error code char * detail; ///< Optional explanation string uint16_t cause_ct; ///< Number of sub-errors struct ddca_error_detail * causes[]; ///< Variable length array of contributing errors } DDCA_Error_Detail; // // Initialization // //! Options passed to #ddca_init() typedef enum { DDCA_INIT_OPTIONS_NONE = 0, DDCA_INIT_OPTIONS_DISABLE_CONFIG_FILE = 1, ///< Do not process configuration file DDCA_INIT_OPTIONS_CLIENT_OPENED_SYSLOG = 2, ///< Client has already opened syslog DDCA_INIT_OPTIONS_ENABLE_INIT_MSGS = 4 ///< Emit msgs re how config file and passed options merged } DDCA_Init_Options; // // Message Control // //! Output Level //! //! Values assigned to constants allow them to be or'd in bit flags. //! //! Values are ascending in order of verbosity typedef enum { DDCA_OL_TERSE =0x04, /**< Brief output */ DDCA_OL_NORMAL =0x08, /**< Normal output */ DDCA_OL_VERBOSE=0x10, /**< Verbose output */ DDCA_OL_VV =0x20 /**< Very verbose output */ } DDCA_Output_Level; // // Tracing // //! ddcutil message severity maps to syslog() severity. //! //! Gaps in values allow for further refinement typedef enum { DDCA_SYSLOG_NOT_SET = -1, DDCA_SYSLOG_NEVER = 0, DDCA_SYSLOG_ERROR = 3, DDCA_SYSLOG_WARNING = 6, DDCA_SYSLOG_NOTICE = 9, DDCA_SYSLOG_INFO = 12, DDCA_SYSLOG_VERBOSE = 15, DDCA_SYSLOG_DEBUG = 18, } DDCA_Syslog_Level; // // Performance statistics // //! Used as values to specify a single statistics type, and as //! bitflags to select statistics types. typedef enum { DDCA_STATS_NONE = 0x00, ///< no statistics DDCA_STATS_TRIES = 0x01, ///< retry statistics DDCA_STATS_ERRORS = 0x02, ///< error statistics DDCA_STATS_CALLS = 0x04, ///< system calls DDCA_STATS_ELAPSED = 0x08, ///< total elapsed time DDCA_STATS_ALL = 0xFF ///< indicates all statistics types } DDCA_Stats_Type; // // Miscellaneous types // typedef double DDCA_Sleep_Multiplier; // // Output capture // //! Capture option flags, used by #ddca_start_capture() //! //! The enum values are defined as 1,2,4 etc so that they can be or'd. //! //! @since 0.9.0 typedef enum { DDCA_CAPTURE_NOOPTS = 0, ///< @brief no options specified DDCA_CAPTURE_STDERR = 1 ///< @brief capture **stderr** as well as **stdout** } DDCA_Capture_Option_Flags; // // Display Specification // /** @defgroup api_display_spec API Display Specification */ /** Opaque display identifier * * A **DDCA_Display_Identifier** holds the criteria for selecting a monitor, * typically as specified by the user. * * It can take several forms: * - the display number assigned by **dccutil** * - an I2C bus number * - an ADL (adapter index, display index) pair (deprecated) * - a USB (bus number, device number) pair or USB device number * - an EDID * - manufacturer, model, and serial number strings * * @ingroup api_display_spec * */ typedef void * DDCA_Display_Identifier; /** Opaque display reference. * * A #DDCA_Display_Ref describes a monitor. It contains 3 kinds of information: * - Assigned ddcutil display number * - The operating system path to the monitor, which is an I2C bus number or * a USB device number. * - Accumulated information about the monitor, such as the EDID or capabilities string. * * @remark * When libddcutil is started, it detects all connected monitors and creates * a persistent #DDCA_DisplayRef for each. * @remark * A #DDCA_Display_Ref can be obtained in 2 ways: * - From the DDCA_Display_List returned by #ddca_get_display_info_list2() * - Searching based on #DDCA_Display_Identifier using #ddca_get_display_ref() * * @ingroup api_display_spec */ typedef void * DDCA_Display_Ref; /** Opaque display handle * * A **DDCA_Display_Handle** represents an "open" display on which actions can be * performed. This is required for communicating with a display. It is obtained by * calling #ddca_open_display2(). * * For I2C and USB connected displays, an operating system open is performed by * # ddca_open_display2(). #DDCA_Display_Handle then contains the file handle * returned by the operating system. * * @ingroup api_display_spec */ typedef void * DDCA_Display_Handle; ///@} // // VCP Feature Information // /** MCCS Version in binary form */ typedef struct { uint8_t major; /**< major version number */ uint8_t minor; /*** minor version number */ } DDCA_MCCS_Version_Spec; extern const DDCA_MCCS_Version_Spec DDCA_VSPEC_V10; ///< MCCS version 1.0 extern const DDCA_MCCS_Version_Spec DDCA_VSPEC_V20; ///< MCCS version 2.0 extern const DDCA_MCCS_Version_Spec DDCA_VSPEC_V21; ///< MCCS version 2.1 extern const DDCA_MCCS_Version_Spec DDCA_VSPEC_V30; ///< MCCS version 3.0 extern const DDCA_MCCS_Version_Spec DDCA_VSPEC_V22; ///< MCCS version 2.2 extern const DDCA_MCCS_Version_Spec DDCA_VSPEC_ANY; ///< used as query specifier extern const DDCA_MCCS_Version_Spec DDCA_VSPEC_UNKNOWN; ///< value for monitor has been queried unsuccessfully extern const DDCA_MCCS_Version_Spec DDCA_VSPEC_UNQUERIED; ///< indicates version not queried /** MCCS VCP Feature Id */ typedef uint8_t DDCA_Vcp_Feature_Code; /** Bitfield specifying a collection of VCP feature codes * * @remark * This struct might be more appropriately named DDCA_Feature_Set, but * that results in confusing function names such as ddca_feature_set_set() */ typedef struct { uint8_t bytes[32]; } DDCA_Feature_List; extern const DDCA_Feature_List DDCA_EMPTY_FEATURE_LIST; /** Identifiers for publicly useful VCP feature subsets * * @remark * These subset identifiers represent a subset of the much * larger collection of subset ids used internally. */ typedef enum { DDCA_SUBSET_UNSET = 0, ///< No subset selected DDCA_SUBSET_KNOWN, ///< All features defined in a MCCS spec DDCA_SUBSET_COLOR, ///< Color related features DDCA_SUBSET_PROFILE, ///< Features saved and restored by loadvcp/setvcp DDCA_SUBSET_MFG, ///< Feature codes reserved for manufacturer use (0x0e..0xff) DDCA_SUBSET_CAPABILITIES, ///< Feature codes specified in capabilities string DDCA_SUBSET_SCAN, ///< All feature codes other than known write-only or table DDCA_SUBSET_CUSTOM } DDCA_Feature_Subset_Id; // // Display Information // /** Indicates how MCCS communication is performed */ typedef enum { DDCA_IO_I2C, /**< Use DDC to communicate with a /dev/i2c-n device */ DDCA_IO_USB /**< Use USB reports for a USB connected monitor */ } DDCA_IO_Mode; /** Describes a display's physical access mode and the location identifiers for that mode */ typedef struct { DDCA_IO_Mode io_mode; ///< physical access mode union { int i2c_busno; ///< I2C bus number int hiddev_devno; ///* USB hiddev device number } path; } DDCA_IO_Path; // Maximum length of strings extracted from EDID, plus 1 for trailing NULL #define DDCA_EDID_MFG_ID_FIELD_SIZE 4 #define DDCA_EDID_MODEL_NAME_FIELD_SIZE 14 #define DDCA_EDID_SN_ASCII_FIELD_SIZE 14 #define DDCA_DISPLAY_INFO_MARKER "DDIN" /** Describes one monitor detected by ddcutil. * * This struct is copied to the caller and can simply be freed. */ typedef struct { char marker[4]; ///< always "DDIN" int dispno; ///< ddcutil assigned display number DDCA_IO_Path path; ///< physical access path to display int usb_bus; ///< USB bus number, if USB connection int usb_device; ///< USB device number, if USB connection char mfg_id[ DDCA_EDID_MFG_ID_FIELD_SIZE ]; ///< 3 character mfg id from EDID char model_name[DDCA_EDID_MODEL_NAME_FIELD_SIZE]; ///< model name from EDID, 13 char max char sn[ DDCA_EDID_SN_ASCII_FIELD_SIZE ]; ///< "serial number" from EDID, 13 char max uint16_t product_code; ///< model product number uint8_t edid_bytes[128]; ///< first 128 bytes of EDID DDCA_MCCS_Version_Spec vcp_version; ///< VCP version as pair of numbers DDCA_Display_Ref dref; ///< opaque display reference } DDCA_Display_Info; /** Collection of #DDCA_Display_Info */ typedef struct { int ct; ///< number of records DDCA_Display_Info info[]; ///< array whose size is determined by ct } DDCA_Display_Info_List; /** @name Version Feature Flags * * #DDCA_Version_Feature_Flags is a byte of flags describing attributes of a * VCP feature that can vary by MCCS version. * * @remark * Exactly 1 of #DDCA_RO, #DDCA_WO, #DDCA_RW is set. * @remark * Flags #DDCA_STD_CONT, #DDCA_COMPLEX_CONT, #DDCA_SIMPLE_NC, #DDCA_COMPLEX_NC, * #DDCA_WO_NC, #DDCA_NORMAL_TABLE, #DDCA_WO_TABLE refine the C/NC/TABLE categorization * of the VESA MCCS specification. Exactly 1 of these bits is set. */ ///@{ /** Flags specifying VCP feature attributes, which can be VCP version dependent. */ typedef uint16_t DDCA_Version_Feature_Flags; // Bits in DDCA_Version_Feature_Flags: // Exactly 1 of DDCA_RO, DDCA_WO, DDCA_RW is set #define DDCA_RO 0x0400 /**< Read only feature */ #define DDCA_WO 0x0200 /**< Write only feature */ #define DDCA_RW 0x0100 /**< Feature is both readable and writable */ #define DDCA_READABLE (DDCA_RO | DDCA_RW) /**< Feature is either RW or RO */ #define DDCA_WRITABLE (DDCA_WO | DDCA_RW) /**< Feature is either RW or WO */ // Further refine the C/NC/TABLE categorization of the MCCS spec // Exactly 1 of the following 8 bits is set #define DDCA_STD_CONT 0x0080 /**< Normal continuous feature */ #define DDCA_COMPLEX_CONT 0x0040 /**< Continuous feature with special interpretation */ #define DDCA_SIMPLE_NC 0x0020 /**< Non-continuous feature, having a defined list of values in byte SL */ #define DDCA_COMPLEX_NC 0x0010 /**< Non-continuous feature, having a complex interpretation using one or more of SL, SH, ML, MH */ #define DDCA_NC_CONT 0x0800 /**< NC feature combining reserved values with continuous range */ // For WO NC features. There's no interpretation function or lookup table // Used to mark that the feature is defined for a version #define DDCA_WO_NC 0x0008 /**< Used internally for write-only non-continuous features */ #define DDCA_NORMAL_TABLE 0x0004 /**< Normal RW table type feature */ #define DDCA_WO_TABLE 0x0002 /**< Write only table feature */ #define DDCA_CONT (DDCA_STD_CONT|DDCA_COMPLEX_CONT) /**< Continuous feature, of any subtype */ #define DDCA_NC (DDCA_SIMPLE_NC|DDCA_COMPLEX_NC|DDCA_WO_NC|DDCA_NC_CONT) /**< Non-continuous feature of any subtype */ #define DDCA_NON_TABLE (DDCA_CONT | DDCA_NC) /**< Non-table feature of any type */ #define DDCA_TABLE (DDCA_NORMAL_TABLE | DDCA_WO_TABLE) /**< Table type feature, of any subtype */ // #define DDCA_KNOWN (DDCA_CONT | DDCA_NC | DDCA_TABLE) // *** unused *** // Additional bits: #define DDCA_DEPRECATED 0x0001 /**< Feature is deprecated in the specified VCP version */ ///@} typedef uint16_t DDCA_Global_Feature_Flags; // Bits in DDCA_Global_Feature_Flags: // Lifecycle: #define DDCA_SYNTHETIC_VCP_FEATURE_TABLE_ENTRY 0x8000 /**< Used internally to indicate a temporary VCP_Feature_Table_Entry */ #define DDCA_PERSISTENT_METADATA 0x1000 /**< Part of internal feature tables, do not free */ // Describe Provenance: #define DDCA_USER_DEFINED 0x4000 /**< User provided feature definition */ #define DDCA_SYNTHETIC 0x2000 /**< Generated feature definition */ typedef uint16_t DDCA_Feature_Flags; // union (DDCA_Version_Feature_Flags, DDCA_Global_Feature_Flags) /** One entry in array listing defined simple NC values. * * An entry of {0x00,NULL} terminates the list. */ typedef struct { uint8_t value_code; char * value_name; } DDCA_Feature_Value_Entry; // Makes reference to feature value table less implementation specific // deprecated // typedef DDCA_Feature_Value_Entry * DDCA_Feature_Value_Table; #define DDCA_FEATURE_METADATA_MARKER "FMET" /** Describes a VCP feature code, tailored for a specific monitor. * Feature metadata can vary by VCP version and user defined features */ typedef struct { char marker[4]; /**< always "FMET" */ DDCA_Vcp_Feature_Code feature_code; /**< VCP feature code */ DDCA_MCCS_Version_Spec vcp_version; /**< MCCS version */ DDCA_Feature_Flags feature_flags; /**< feature type description */ DDCA_Feature_Value_Entry * sl_values; /**< valid when DDCA_SIMPLE_NC set */ void * unused; /** no longer used, was latest_sl_values */ char * feature_name; /**< feature name */ char * feature_desc; /**< feature description */ // possibly add pointers to formatting functions } DDCA_Feature_Metadata; // // Represent the Capabilities string returned by a monitor // #define DDCA_CAP_VCP_MARKER "DCVP" /** Represents one feature code in the vcp() section of the capabilities string. */ typedef struct { char marker[4]; /**< Always DDCA_CAP_VCP_MARKER */ DDCA_Vcp_Feature_Code feature_code; /**< VCP feature code */ int value_ct; /**< number of values declared */ uint8_t * values; /**< array of declared values */ } DDCA_Cap_Vcp; #define DDCA_CAPABILITIES_MARKER "DCAP" /** Represents a monitor capabilities string */ typedef struct { char marker[4]; /**< always DDCA_CAPABILITIES_MARKER */ char * unparsed_string; /**< unparsed capabilities string */ DDCA_MCCS_Version_Spec version_spec; /**< parsed mccs_ver() field */ int cmd_ct; /**< number of command codes */ uint8_t * cmd_codes; /**< array of command codes */ int vcp_code_ct; /**< number of features in vcp() field */ DDCA_Cap_Vcp * vcp_codes; /**< array of pointers to structs describing each vcp code */ int msg_ct; char ** messages; } DDCA_Capabilities; // // Get and set VCP feature values // /** Indicates the physical data type. At the DDC level, continuous (C) and * non-continuous (NC) features are treated identically. They share the same * DDC commands (Get VCP Feature and VCP Feature Reply) and data structure. * Table (T) features use DDC commands Table Write and Table Read, which take * different data structures. */ typedef enum { DDCA_NON_TABLE_VCP_VALUE = 1, /**< Continuous (C) or Non-Continuous (NC) value */ DDCA_TABLE_VCP_VALUE = 2, /**< Table (T) value */ } DDCA_Vcp_Value_Type; typedef struct { uint8_t mh; uint8_t ml; uint8_t sh; uint8_t sl; } DDCA_Non_Table_Vcp_Value; /** Represents a single table VCP value. Consists of a count, and a pointer to the bytes */ typedef struct { uint16_t bytect; /**< Number of bytes in value */ uint8_t* bytes; /**< Bytes of the value */ } DDCA_Table_Vcp_Value; /** Stores a VCP feature value of any type */ typedef struct { DDCA_Vcp_Feature_Code opcode; /**< VCP feature code */ DDCA_Vcp_Value_Type value_type; // probably a different type would be better union { struct { uint8_t * bytes; /**< pointer to bytes of table value */ uint16_t bytect; /**< number of bytes in table value */ } t; /**< table value */ struct { uint8_t mh; uint8_t ml; uint8_t sh; uint8_t sl; } c_nc; /**< continuous non-continuous, i.e. non-table, value */ } val; } DDCA_Any_Vcp_Value; #define VALREC_CUR_VAL(valrec) ( valrec->val.c_nc.sh << 8 | valrec->val.c_nc.sl ) #define VALREC_MAX_VAL(valrec) ( valrec->val.c_nc.mh << 8 | valrec->val.c_nc.ml ) // // For reporting display status changes to client // //! Type of event being reported //! //! @since 2.1.0 typedef enum { DDCA_EVENT_DPMS_AWAKE, DDCA_EVENT_DPMS_ASLEEP, DDCA_EVENT_DISPLAY_CONNECTED, DDCA_EVENT_DISPLAY_DISCONNECTED, DDCA_EVENT_UNUSED1, DDCA_EVENT_UNUSED2, } DDCA_Display_Event_Type; //! Specifies groups of Display_Status_Event_Type to watch for //! //! The enum values are defined as 1,2,4 etc so that they can be or'd. //! //! @since 2.1.0 typedef enum { DDCA_EVENT_CLASS_NONE = 0, DDCA_EVENT_CLASS_DPMS = 1, DDCA_EVENT_CLASS_DISPLAY_CONNECTION = 2, DDCA_EVENT_CLASS_UNUSED1 = 4, } DDCA_Display_Event_Class; #define DDCA_EVENT_CLASS_ALL (DDCA_EVENT_CLASS_DPMS | DDCA_EVENT_CLASS_DISPLAY_CONNECTION) /** Event record passed by a display status callback function. * * @remark * Strictly speaking, connector names can have a maximum length of 32 characters. * In practice, no connector names longer than 16 characters have ever been * seen. Therefore, it should be safe for connector_name to allow for a * maximum of 31 printable characters and a termination byte. * * @remark * The DDCA_Display_Status_Event is defined with two unused fields to allow * for future extension without breaking the ABI. * * @since 2.1.0 */ typedef struct { uint64_t timestamp_nanos; DDCA_Display_Event_Type event_type; DDCA_IO_Path io_path; char connector_name[32]; DDCA_Display_Ref dref; void * unused[2]; } DDCA_Display_Status_Event; /** Signature of a function to be invoked by the shared library notifying the * client that a change in connected displays has been detected. * * The client program should call #ddca_redetect_displays() and then * #ddca_get_display_refs() to get the currently valid display references. * * @remark * The DDCA_Display_Status_Event is passed on the stack, not allocated on * the heap. Callback invocation is extremely infrequent, the struct size is * not large, and passing the event on the stack relieves clients of * responsibility for memory management. * * @since 2.1.0 */ typedef void (*DDCA_Display_Status_Callback_Func)(DDCA_Display_Status_Event event); #ifdef __cplusplus } #endif #endif /* DDCUTIL_TYPES_H_ */