## [2.2.7] 2025-05-08

#### EACCES Errors

Calling open() on a /dev/i2c device for which the user has RW permission
sometimes (rarely) fails with Linux error EACCES. This elusive problem has most
frequently been reported on Framework computers and Arch based distributions.

Reverting to using group i2c instead of udev token uaccess to grant permission
appears to resolve the problem, but this is not certain.

The problem commonly occurs after a resume from sleep. The best (but not certain)
explanation for these events is as follows. The userid, group id, and mode bits are
permanent attributes of the device inode.  They survive suspend/resume intact. 
On the other hand, udev rule TAG+="uaccess" works by having systemd-logind set a 
POSIX ACL on the device node for the current seat user. After resume, the kernel 
driver re-registers the device, which can trigger a new add uevent. Logind needs
to process that event, creating a window during with an EACCES error is possible. 
In short, it is a race condition.

To address this problem, pauses are inserted at several points, including before 
opening a /dev/i2c device, if the call occurs immediately after a resume from sleep.  

In addition, if an open() call fails with errno EACCES, the ACL API is used to 
recheck device permissions. If the API reports that the /dev/i2c device does have
the proper permissions, the open() call is retried for an extended period of time 
on the presumption that it will eventually succeed.  If the ACL API does not
report that the /dev/i2c device has proper permissions, the open() is nonetheless 
retried once. 

The behavior of open() calls and watching for display connection/disconnection has
been parameterized in several ways. For many parameters, there is a tension: if 
the delay time is too large, true EACCES errors can flood the system, making the 
UI unresponsive; if the delay time is too small not enough time may be given for 
the permissions to resolve.

File src/base/parms.h contains the default values of several of these parameters.
The following options have been added for those most likely to be adjusted: 

- ***~~pause-after-resume-ms***  The number of milliseconds libddcutil may pause 
  after dbus reports a resume from sleep.  The default is 500, set by 
  DEFAULT_AFTER_RESUME_MS in parms.h.
- ***-max-eacces_retry-ms*** Limits the number of milliseconds for retrying open() 
  calls when it appears likely, having checked the ACL, that the open() call will 
  succeed eventually. The default is 3000, set by DEFAULT_EACCES_RETRY_MS in parms.h. 
- ***--enable/disable-early-permission-checks***  Perform basic permission checks
  before performing operations that might generate a flurry of EACCES errors.  
  The drawback of this option is that the basic permission might be performed too
  soon, generating permission failures that might otherwise resolve by the time
  the open() calls are actually needed.  The default is enable, set by 
  ENABLE_EARLY_PERMISSION_CHECKS in parms.h

In addition, many parameters can be adjusted using utility options (***--fN***,
***--iN***, etc.). The current definitions of the utility options are reported by
command **ddcutil noop --settings**. These options exist to simplify testing; 
there is no guarantee that their effect will be the same from one release to the next.

#### Added 

- Extensive diagnostics are written to the system log if opening a /dev/i2c
  device fails with errno EACCES.
- Implemented a basic segfault handler.  It writes the traced function stack
  of the current thread to the system log, then invokes the prior handler. 
- Option ***max-eacces-retry-ms***. (See above.)  

#### Changed

- Re-enable reporting of laptop display connection/disconnection. 
  Do not check DDC operation for the laptop /dev/i2c bus or for any
  bus unresponsive on slave address x37.
- When watching for display connection/disconnection using watch-mode UDEV: 
  - watch for UDEV notifications for subsystem i2c-dev as well as drm.
  - write udev event detail to the system log
- **dw_hotplug_change_handler()**: write additonal messages to the system log
  when a /dev/i2c device unexpectedly no longer exists
- Option ***--skip-ddc-checks***: valid only for command line **ddcutil**, not 
  shared library **libddcutil**. If specified in config file ddcutilrc, it must
  now be in the [ddcutil] section, not the [global] section.
- The installed udev rules file, 60-ddcutil-i2c.rules now sets group i2c and 
  mode 0660 as well as using token uaccess to assign /dev/i2c permissions. 
  Users encountering the transient EACCES errors may need to use the old group
  permissions method. 

#### Fixed

- **ddca_redetect_displays()**: Recover from an unexpected system state that
  previously triggered assert() failures. Diagnostics are written to the system
  log. If display watch is not running on entry to the function, it is not 
  restarted at the end. 
  Addresses issue #595, (powerdevil crashes with assertion failure in libddcutil
  after resume from sleep/hibernate) and KDE bug 517571 (KDE Power Management 
  Crash in DDCutilPrivateSingleton::redetect after letting laptop sleep).
- In **dw_create_display_status_event()**, the test for event type
  DDCA_EVENT_DDC_DISABLED incorrectly used flag DDCA_DISPLAY_EVENT_DDC_WORKING.
- man page ddcutil: Replace example "getvcp supported" by "getvcp all". 
  Group "supported" was replaced long ago by "all". Issue #579.
- segfault in diagnose_open_failure_to_syslog(). Issue #596
- Error parsing option ***--maxtries***.
- Attempting to run command line programs lsof, getfacl (which can occur whan 
  analyzing unexpected behaviour or as part command **environment**) 
  caused a segfault when those programs are not found on the user's system.
  Addresses segfault reported in issue #590.
- In syslog messages, the reported thread id might actually be the process id. 
- Change the sample rules file in data/etc/udev/rules.d/60-ddcutil-i2c.rules, 
  which is normally installed in /usr/share/ddcutil/data/60-ddcutil.rules, to
  conform to the file normally installed in 
  /usr/lib/udev/rules.d/60-ddcutil-i2c.rules. Both files now Loosen the video
  display adapter test to look at only the first byte of the adapter class, 
  which must be x03. Pull request #597.
- Fix incorrect ioctl call in **hiddev_get_report()**, used for monitors using
  USB rather that I2C for communication with their Virtual Control Panel.
- When reading the EDID bytewise using **get_edid_bytes_directly_using_fileio()**
  (currently done only for test purposes), only every other byte was saved.
- Incorrect call to i2c-dev set address ioctl.
- General source cleanup using Claude Code
  - Fix a large number of typos and other errors in messages, mostly trace and 
    syslog messages.
  - Update Doxygen documentaion.
  - Consistenly make **#include "config.h"** the first include.
  - Consistenly set AM_CFLAGS = $(AM_CLAGS_STD) in the Makefile.am in each of
    the subdirectories of src
- Avoid a possible buffer overflow when printing an EDID field such as 
  serial number that contains invalid ASCII characters
- Write error message during **getvcp --brief*** regarding sysfs drm connector 
  not found to stderr, not stdout.  Issue #598.   
- More consistent formatting of syslog output.
- Use atomic variables to fix time of use to time of check (TOCTOU) race 
  conditions identified by Claude Code.

### Building

- Add autoconf **config** option ***--enable-dbus***/***--disable-dbus***. 
  The default is enabled.  Needed to watch for sleep events.
- File src/base/parms.h: Define QUIESCE operation constants: 
  QUIESCE_POLL_MAX_MILLISEC, QUIESCE_POLL_INTERVAL_MILLISEC

### Shared Library

The shared library **libddcutil** is backwardly compatible with the one in 
ddcutil 2.2.1. The SONAME is unchanged as libddcutil.so.5. The released library
file is libddcutil.so.5.5.1.

#### Added

- Added a thread that watches for dbus PrepareForSleep messages, in order to 
  calculate the time since the most recent return from sleep.  If opening a 
  /dev/i2c device fails with errno EACCES shortly after returning from sleep, 
  the open is retried.
- Option ***~~pause-after-resume-ms*** (See above.)
- Option ***--enable/disable-early-permission-checks*** (See above.)

## [2.2.6] 2026-03-11

Release 2.2.6 replaces release 2.2.5, which was reported to hang KDE Plasma
at login.

### General

#### Changed

- Use up to date macros in Autotools configuration file configure.ac: 
  AC_SYSTEM_EXTENSIONS, AC_PROG_CC conditionally replaces AC_PROG_C99.
- Allow VCP feature numbers to be specified as a single hex digit, 
  e.g. "getvcp 2".

#### Fixed

- Ignore case when processing options ***--mfg***, ***--model***, and ***--sn***.
- Changes for glib 2.43, which is stricter about preserving const-ness of 
  function string arguments.
- Command **traceable-functions** failed if a non-traceable function was 
  specified on the command line or in the ddcutil configuration file. 

### Shared Library

The shared library **libddcutil** is backwardly compatible with the one in 
ddcutil 2.2.1. The SONAME is unchanged as libddcutil.so.5. The released library
file is libddcutil.so.5.5.0.

#### Added

- Added API function **ddca_get_non_table_vcp_value2()**. Unlike 
  **ddca_get_non_table_vcp_value()**, which is now deprecated, the new function
  never performs verification. 

#### Changed 

- Ignore laptop displays when processing display connection and disconnection.
- Add "AMDGPU DM i2c OEM bus" to list of names of I2C buses to be ignored. 
  These buses are used to control display controller features like RGB lighting.  
- Eliminate use in libddcutil of linux api function **access()** to check if 
  the user has RW access to a /dev/i2c device. Bug reports suggest this 
  function may not always respect UDEV token UACCESS.
- More extensive syslog trace messages. Needed to aid in remote debugging, 
  particularly for KDE PowerDevil.
- Functions in the call trees from **ddca_get_...vcp_value()** and 
  **ddca_set_...vcp_value()** consistenty return Error_Info structs instead of
  status codes to improve diagnostic messages written to the system log and 
  information returned by **ddca_get_error_detail()**. 
 
#### Fixed

- Issue #581 "ddcutil 2.2.5 causes KDE Plasma freeze due to excessive 
  permission checks".  For some undetermined reason, despite the logged on user
  having RW access to /dev/i2c-devices, attempting to open these devices sometimes 
  fails with Linux error EACCES. Functions **ddca_init2()** and **ddca_init()**
  now fail with status code EACCESS if the logged on user does not have RW 
  permission for all /dev/i2c devices that might possibly be used for DDC 
  communication.  As the cause of the permission loss is unclear, function 
  **ddca_start_watch_displays()** similarly checks if the logged on user has 
  RW access, and returns DDCRC_INVALID_OPERATION in case of failure.  Callers
  should check for failure of these functions and not repeatedly call them to
  avoid a flood of permission failures. 
- Issue #585, "Displays with I2C bus name DPMST not detected". It was possible
  that the video adapter for a /dev/i2c devices was not located, causing MST
  connected displays to not be detected.(Fix based on diagnosis by Diego Nunes.) 
- Issue #587, "Assert failure in ddc_packet_io.c", due to an inconsistent
  data structure in ddc_open_display(). The inconsistency was apparently caused 
  by a race condition in display change detection. Added mutex. Also addresses 
  issue #586.
- Clear the display locks table during **ddca_redetect_displays()**.


## [2.2.5] 2026-01-26 

Release 2.2.5 replaces release 2.2.4, which failed to build on aarch64.

### General

#### Fixed

- Compilation failure in function xvrpt_vstring() when building on aarch64. 
  Issue $574.

### Shared Library

#### Changed

- **ddca_start_watch_displays()**: issue warning if displays exist for which 
  the EDID is readable using sysfs but not I2C.
- API functions that write a feature value (**ddca_set_non_table_vcp_value()** etc.) 
  return DDCRC_DISCONNECTED if called before libddcutil has been notified by 
  UDEV that the display has been removed.
- **ddca_report_display_info()**, **ddca_report_display_info2()**: do not include the
  display number in the report as this is meaningless for shared library clients.

## [2.2.4] 2026-01-21

### General

Display selection has been reworked to be more flexible while also simpler internally. 
Previously, options ***--display***, ***--bus***, ***--edid***, etc. were regarded as 
identifiers that uniquely picked a display.  Generally speaking, only one identifier
could be given, with special handling for the combination of ***--mfg***, ***--model***,
and ***-sn***.  

With this change identifiers are now treated as selection criteria. More than one
can be specified.  To be chosen, the display must satisfy all the criteria given.  
As before if no selection options are specified, ***--display 1*** is assumed.

#### Added

- Option ***--edp-ambiguous***. Normally, if the DRM connector name contains the string 
  "eDP", it reliably indicates that the connected display, typically a laptop display, 
  does not implement DDC/CI, and no further checking is needed.  Owing to a bug in the 
  amdgpu driver, there have been instances where "eDP" is in the DRM connector name for 
  an external display that does support DDC/CI. There will be no fix for this bug, which
  occurs only when the BIOS is operating in CSM mode, not EFI mode. If this option is 
  given, the contents of the EDID are also checked when "eDP" is in the connector name
  to confirm that display really is a laptop display. This test is imperfect, so 
  ***--edp-ambiguous*** should only be used as a workaround for the amdgpu bug.
- Option ***--ignore bus*** takes as its argument the /dev/i2c bus number for I2C bus 
  that should be completely ignored. This option can be specified multiple times.  
  It provides a workaround for obscure bugs.

#### Changed

- Option ***--edid***: If the value given starts with "...", the remainder of the value 
  is some number of hex digits, which are compared against the final bytes of the EDID
  for display selection.
- For commands that require a monitor, if no monitors implementing DDC/CI exist,
  the error message is "No displays implementing DDC/CI found" instead of "Display not 
  found". Suggested in issue #540. 
- Command **detect**:  Insert the word "correctly" into the phrase "Monitor correctly
  uses unsupported feature flag" to make clear that this is not an error.
- Command **capabilities**: Change message "Read cached capabilities string from ..."
  to "Obtained cached capabilities string from ..." so as to be clear that the 
  string was read from a file, not that it possibly will be.

#### Fixed 

- "eDP" in a DRM connector name once again always implies a laptop or other display 
  that does not implement DDC/CI. This test was relaxed in release 2.2.1 (commit 
  8580c3d...) as a workaround for issue #384 caused by a bug in the amdgpu driver. 
  Unfortunately, the workaround caused some laptop displays to be treated as if 
  they implemented DDC/CI, with resulting errors.  Addresses issue #559.
  For handling the extremely rare case of "eDP" in the DRM connector name for an
  external monitor, option ***--edp-ambiguous*** has been added.
- Command **detect**: For laptop displays, do not output a monitor-model-id and UDF 
  file name as these are meaningless.
- Segfault in function xvrpt_vstring() caused by an extermely log capabilities string.
  Addresses issue #568.
- If ddc_write_read() fails, only call ddc_check_open_bus_alive() when executing in
  libdcutil. The test is not meaningful when executing in command line ddcutil.
  In the case where a display's EDID was obtained from sysfs but is not readable
  using I2C, ddc_write_read_with_retry() repeatedly calls i2c_check_open_bus_alive(), 
  which fails with multiple waits, markedly slowing command **detect**. As a result, 
  GNOME extensions were seen to hang the user interface.  Addresses issue #559.
- Build failure on aarch64

### Shared Library

The shared library **libddcutil** is backwardly compatible with the one in 
ddcutil 2.2.1. The SONAME is unchanged as libddcutil.so.5. The released library
file is libddcutil.so.5.4.1. 

#### Fixed

- Segfault in dw_start_watch_displays() when Wayland-X11 bridge is not running.
  Change based on pull request #563. 
- Race condition failure in ddca_open_display2() triggered by disconnecting and 
  connecting display in KDE PowerDevil.  Make setting Display_Ref flag 
  DREF_DISCONNECTED and Display_Ref variable detail=NULL an atomic operation. 
  Fixes the problem identified in issue #556.
- Option ***--ignore-hiddev*** was not being processed for libdcutil.


## [2.2.2] 2025-11-13

### General

#### Added

- Option ***--trcback***: report call stack that led to specified function
  (initial implementation). Requires ***--enable-traced-function-stack***.
- Option ***--trace-to_syslog***: Direct trace output to the system log, without 
  disabling other destinations.

#### Changed

- Option ***--enable-traced-function-stack*** is now the default.
- Additional messages reporting configuration file errors. In particular, 
  section names and the names of keys within each section are validated.
  Section names other than [global], [ddcutil], and [libddcutil] are flagged
  as errors.
- If possible, obtain list of PNP ids from /usr/share/hwdata/pnp.ids instead
  of using hardcoded list.
- Reword the parser explanation of options ***--verify*** and ***--noverify***
  for clarity.

#### Fixed

- Command **setvcp --verify** and API function **ddca_set_non_table_vcp_value()**: 
  were not performing verification,
- Command **getvcp --verbose**: output was partially in a format intended for syslog
- **ddca_display_ref_from_handle()**: was not converting internal to external display 
  reference, causing a segfault. Issue #528.
- Relax the check of the device class when determining if a device is a video 
  controller.   Look only at the first byte in sysfs device attribute class.  
  An AMD Ryzen AI 9 365 based system was seen to report 0x038000, not 0x030000.  
  Addresses issue #530.
- Build failed with an undefined reference error when configure option ***--disable-drm***
  was specified. API function **ddca_redetect_displays()** now returns 
  DDCRC_INVALID_OPERATION if ddcutil was built with ***--disable-drm***.  
  (An alternative code path through **ddca_redetect_displays()** is possible for
  the ***--disable-drm*** case, but is non-trivial and so not implemented for now.)
  Also option ***--disable-drm*** forces ***--disable-watch-displays***. 
  Addresses issue #506
- man page ddcutil: correct typo in hyperlink. Patch #535
- man page ddcutil: document that **loadvcp** uses the display identifier on the 
  command line if one was specified, and ensures it identifies the same display as
  the one identified by the data in the file being loaded.  Noted in issue #552.
- Command **environment --verbose**: 
  - Permission denied errors corrupted output of the find command used to scan for 
    DisplayLink devices.
  - Incorrectly formed path name for examining /sys/class/drm
- Fix invalid hyperlink in README.md. Pull Request #558

#### Building

- Fix out-of-tree build reference to generated file /src/base/build_details.h. Pull request #544

### Shared library

The shared library **libddcutil** is backwardly compatible with the one in 
ddcutil 2.2.1. The SONAME is unchanged as libddcutil.so.5. The released library
file is libddcutil.so.5.4.0. 

#### Added

- Option ***--watch-mode udev***
  Uses libudev to watch for display connection and disconnection. This is now 
  the default watch mode when executing on wayland if ddcutil was built to use 
  libudev, which is normally the case (configure option ***--enable-udev***). 
  Xevent continues to be the default watch mode when executing on X11. A specific
  watch mode can be forced using ***--watch-mode udev***, ***--watch-mode xevent***, 
  or ***--watch-mode poll***.  Addresses issues in [KDE-Plasma Powerdevil merge request 542]
  (https://invent.kde.org/plasma/powerdevil/-/merge_requests/542)
- Define bit **DDCA_NOVERIFY** in **DDCA_Version_Feature_Flags**. 

#### Fixed

- **ddca_open_display2()**: Return DDCRC_INTERNAL_ERROR instead of terminating 
  with assert() failure in certain ill-defined situations.  Addresses issue #556
  reported by PowerDevil.
- **ddca_redetect_displays()**: Set the **DREF_REMOVED** bit in all entries
  in the table of published display references, i.e. references that have been 
  reported to the client program, instead of emptying the table.


## [2.2.1] 2025-07-07

### General

#### Added

- Do not perform permission checks if running with effective user root, i.e. when 
  running with setuid bit set. Partially addresses issue #509

#### Changed

- Command **environment**: report if running as root, with sudo, or setuid bit set
- Command **environment --verbose**: eliminate some unneeded edid read tests
- Command **setvcp**: Emit more more useful messages when the cause of a 
  DDCRC_RETRIES error is itself a DDCRC_RETRIES error.
- Add option ***--disable-traced-function-stack***
  The default traced-function-stack option value (disabled) is set in parms.h. 

#### Fixed

- Avoid segfault if invalid feature code specified
- Maximum wait time on function lock_display() not respected, possible infinte
  loop.  Addresses issue #511
- Fix --verify/--noverify parsing.  Addresses issue #512.
- ddca_close_display(): do not respect quiesce, allowing the display lock
  record to be released, avoiding possible deadlock
- Fix the spelling of company name HON HAI PRECISION" (obtained from UEFI), 
  avoiding a lintian message. Addresses issue #500
- Fix errors reported by clang 19: unused variable, expression which evaluates
  to 0 treated as null pointer. Addresses issue #502.
- Command **getvcp --terse**: Eliminate irrelevant messages regarding VCP version not set.
- Make test for missing DRM card-connector directories more robust. Issue #507.
- DDC communication not detected with old (340 series) Nvidia proprietary driver. Issue #507
- Function end_capture(): call close() in case of fflush() error, ensuring that 
  messages are always sent to the terminal after message capture complete
- Functions **ddca_find_display_ref()** and **ddca_get_display_ref()** were 
  returning a pointer to the internal Display_Ref struct rather than an external 
  integer DDCA_Display_Ref, causing segfault or return code DDCRC_INVALID_DISPLAY
  on a subsequent api call such as **ddca_open_display2()**.  Addresses issue #528.
- Several API functions were not recognized as arguments to ***--trcfunc*** and ***--trcfrom***. 
  These included **ddca_find_display_ref()**, **ddca_get_display_ref()**, **report_parsed_capabilities()** 
- Option ***--stats*** was not reporting data 
- **ddc_open_display()**: return DDCRC_DISCONNECTED instead of an assert failure if 
  bus_info == NULL.  Addresses KDE Powerdevil issue #504861 (powerdevil crash from 
  libddcutil, no restart happens)
- Macro TRACED_ASSERT() calls **__assert_fail()** instead of exit(1). 
  Addresses Powerdevil issue #504861.
- Fix troff formatting in ddcutil man page. Pull request #531.

### Building

- **configure** option ***--enable-watch-displays***/***--disable-watch-displays***
  controls whether display watch functionaliity is built.  The default is 
  ***--enable-watch-displays***.
  - If built with ***--disable-watch-displays***, API functions related 
    to display change detection return DDCRC_UNIMPLEMENTED
- If **configure** option ***--disable-x11*** is specified, the only watch-mode 
  is POLL. watch-mode XEVENT does not exist.

#### Shared Library

### Added

- Struct DDCA_Display_Info2 is an extended version of DDCA_Display_Info that 
  adds fields for the display's sysfs card-connector directory, how that 
  directory was determined (precisely using I2C bus number or heristically
  using EDID), and the DRM connector id. API functions have been added to 
  use this struct: **ddca_get_display_info2()**, **ddca_free_display_info2()**, 
  and **ddca_report_display_info2()**.  Addresses issue #518.

### Changed

- By default, watching for display connection and disconnection by default uses
  watch-mode **XEVENT** if X11 is the display manager, watch-mode **UDEV**
  otherwise.
- Callback function handling made more bulletproof
  - Close any unlock displays left open by user callback function
  - Write syslog messages (with log level NOTICE) before and after executing
    the callback function

### Fixed

- **ddca_redetect_displays()**: block if called with callback threads active or 
  if already executing
- **ddca_close_display()**: allow execution even if libddcutil is quiesced.
  Avoids a possible deadlock due to an internal display lock not being released.
- **ddca_stop_watch_displays()** did not release the X11/Wayland connection 
  obtained by **ddca_start_watch_displays()**.  This also occured with each 
  **ddca_redetect_displays()** call. As a result KDE PowerDevil eventually 
  exhausted X11 connections of a very long running system with repeated
  display connections and disconnections.  Pull request #519.
- KDE powerdevil was terminating with status success instead of failure if
  libddcutil terminated with a traced assertion, causing the powerdevil 
  service to not restart automatically. Macro TRACE_ASSERT() is modified to
  use **__assert_fail()** instead of **exit()** for termination. 

## [2.2.0] 2025-02-10

### General

#### Added

- Support DisplayLink devices
- Add command **noop**, which allows for executing options such as 
  ***--settings*** without having to execute a real command.
- As an aid to development, the build date and time are normally embedded in
  the ddcutil and libddcutil executables.  This is reported using command
  **ddcutil --version --verbose".  **libddcutil** reports this to the system
  log. If reproducible builds are required, use **configure** option 
  ***--disable-build-timestamp***. (For reproducible builds, building typically
  is performed using a script or build system, so it's not inconvenient to 
  specify ***--disable-build-timestamp*** in this situation.)
- Add ***--enable-flock*** and ***--disable-flock*** as aliases for 
  ***--enable-cross-instance-locks*** and ***--disable-cross-instance-locks***
- Add option ***--ignore-mmid*** to ignore problematic monitor models.
  Takes a Monitor Model Id, e.g. SAM-U32H75x-3587 as an argument. 
  Indicates that DDC/CI communication is disabled for monitors with this id.  
  Typically, this will be added to the [libddcutil] section of configuration 
  file ddcutilrc. It can also be included in the options string passed in the
  opts argument to ddca_init2(). Addresses issue #446.
- Maintain a stack of traced functions for debugging. Turned on by option 
  ***--enable-traced-function-stack***

#### Changed

- User Defined Features: 
  - Add XNC (Extended Non-Continous) like simple NC, but the SH byte is
    also reported.
  - Allow SNC (Simple Non-Continuous) as alternative name for NC.
  - Report user defined features as part of parsed capabilities.
  - Commands recognizing user defined features now fail if there's an error
    loading a user defined feature file.  These are **capabilities**, 
    **setvcp**, **dumpvcp**, and **probe**.
- /usr/lib/udev/rules.d/60-ddcutil-i2c-rules:
  - Give logged on user r/w access to /dev/dri/cardN, needed
    to allow logged on user to probe connectors using DRM.
- Do not install /usr/lib/udev/rules.d/60-ddcutil-usb.rules, delete it
  if previously installed. Addresses issues #405, #428, #437
- Command **ddcutil chkusbmon**:  
  - Skip processing and always return 1 (failure) if option ***--disable-usb***
    is in effect.
- Command **detect**: 
  - Only show communication error detail if --verbose
  - Provide a clearer message if slave address x37 is inactive: 
     - "Monitor does not support DDC" instead of generic "DDC_commnication failed"
     - If option ***--verbose*** is in effect, emit an additional message to
       check the monitor's OSD.
- Parser changes:
  - Add alternative option names for symmetry with other options: 
    - ***--discard-capabilities-cache*** is an alias for ***--discard-cache capabilities***
    - ***--discard-sleep-cache*** is an alias for ***--discard cache dsa***
    - ***--discard-dsa-cache*** is an alias for ***--discard cache dsa***
  - Eliminate --enable-dsa-cache as alias for --enable-dynamic-sleep-cache
  - Improve handling of --verify/--noverify, error if both specified
- File .gitignore:
  - Add: *.tar.gz, docs/ddcutil-c-api
- Commands **interrogate** and **environment --verbose**:
  - Force settings --disable-cross-instance-locking, --disable-dynamic-sleep (VERIFY)
  - Forced settings apply to **environment --verbose** as well as **interrogate**
  - When probing DRM, recognize bus types DRM_BUS_PLATFORM, DRM_BUS_HOST1X, 
    report as "platform", "host1x"
- Change the system log message level when sleep time is adjusted from WARNING
  to VERBOSE. Addresses issue #427: Adjusting multiplier message fills system
  log when libddcutil used by clightd
- Configuration file ddcutilrc: If there is a pound sign "#" on a line, 
  the remainder of the line is treated as a comment.
- Add -Wformat-security to compiler options.  Addresses issue #458.
- If option --bus specified, only check accessability for that bus, avoiding
  irrelevant warning messages regarding other buses.  Addresses issue #461.
- Return DDCRC_CONFIG_ERROR instead of DDCRC_BAD_DATA for User Defined Feature File
  errors.
- Report the Monitor Model Id in the ***--verbose*** output to **ddcutil detect**.
- Command **setvcp**: Do not report "Interpretation may not be accurate.", which
  is irrelevant for this command. Partially addresses issue #454.
- rpt...() functions can redirect output to syslog, making lines coming from 
  multiple threads more coherent
- Enable additional compiler warnings to tighten the code.
- Additional trace groups SYSFS, CONN

#### Fixed

- Rework laptop detection. A non-laptop display can have an eDP connector.
  This is an i915 video driver bug that will not be fixed. See freedesktop.org 
  issue "DRM connector for external monitor has name card1-eDP-1" 
  https://gitlab.freedesktop.org/drm/i915/kernel/-/issues/10389
- When processing environment variable user $XDG_DATA_DIRS, or $XDG_CONFIG_DIRS,  
  the final directory in the list was ignored.  Issue #438
- When processing a user defined feature file, recognize any whitespace character
  (e.g. tab), not just space.
- Fix core dump on ddcutil getvcp. Issue #407 
- Commands **interrogate** and **environment --verbose**
   - Simple getvcp test was not reporting the bytes of the response packet.
   - If no device with class x03 was found, the user's home directory
     was dumped. Issue #413.
   - Remove "-i" option on get-edid command. Does not exist on some versions.
- Fix display not found on Raspberry Pi. Do not rely on /sys/class/drm to read 
  EDID, which is not valid for some drivers.  Addresses issue #403
- Fix DDC communication failed on Raspberry Pi. Do not rely on sysfs attributes
  that do not exist for ARM devices. Resolves issue #413.
- User Define Features file: fix error msg when nothing follow VALUE
- Convert CRLF line endings to LF
- Use printf() formats %jd and %zd to portably print variables of type ssize_t, 
  time_t, so as to build  unchanged on architectures such as armel, armhf.
- Avoid compiler warning possible depending on compiler configuration when
  a switch() construct is used. Replaced with if/else if/else. Resolves issue #458.
- Do not use function strerrrorname_np(). Requires glibc >= 2.32.
- Miscellaneous changes to allow for building on raspbian (debian bullseye).
- Replace function sysfs_find_adapter().  Fixes display detection problem aspect
  of issue #465.
- Dump information to syslog instead of asserting failure if unable to get flock
  on /dev/i2c device.
- Option ***--skip-ddc-checks*** set vcp version in Display_Ref to DDCA_VSPEC_UNKNOWN
  to avoid possible assert failure.
- Prepend thread id to most syslog messages.
- Make syslog messages more consistent in form. 
- Memory leaks.

### Building 

- Re-enable autoconf/configure option --enable-x11/--disable-x11.
  X11 specific code is used in display change and sleep state detection.
  The default is --enable-x11.   
- Add autoconf/configure option ***--enable-static-functions-visible***. 
  If set, storage class specifier "static" is removed from many functions so
  that their names appear in backtrace reports from valgrind, asan, and glibc 
  function backtrace().

### Shared Library

The shared library **libddcutil** is backwardly compatible with the one in 
ddcutil 2.1.x. The SONAME is unchanged as libddcutil.so.5. The released library
file is libddcutil.so.5.2.0. 

#### Added

- Option ***--disable-api*** completely disables the API. Most API calls, including
  those performing DDC communications, will fail. This can be useful for testing 
  whether **libddcutil** is the source of a system error in the case of client
  applications, e.g. KDE PowerDevil, that will not build without the shared library.
- Add libddcutil only option ***--disable-watch-displays***, which unconditionally
  blocks **ddca_start_watch_displays()** from starting the thread that watches
  for display changes. Workaround for issue #470.
- **ddca_get_display_watch_settings()**, **ddca_set_display_watch_settings()**

#### Changed

- **ddca_start_watch_displays()**: 
  - The only event class that can currently be enabled is DDCA_EVENT_CLASS_DISPLAY_CONNECTION. 
    Watching for sleep state changes is not currently supported.  
  - Regards DDCA_EVENT_CLASS_ALL as same as DDCA_EVENT_CLASS_DISPLAY_CONNECTION
  - Error if either DDCA_EVENT_CLASS_DPMS or DDCA_EVENT_CLASS_NONE are specified.
- Status code DDCRC_INVALID_CONFIG_FILE renamed to more general DDCRC_CONFIG_ERROR. 
  DDCRC_INVALID_CONFIG_FILE is a valid alias.
- Write build date and time to system log when starting libddcutil.
- Rework libdccutil output to avoid duplicate msgs in system log when all terminal 
  output is directed to the log, as with KDE Plasma
- Most API functions that specify a display reference now return status code 
  DDCRC_DISCONNECTED if the display reference is no longer valid.
- Quiesce the API during **ddca_redetect_displays()**.  Operations that access
  display state are not permitted, and return DDCRC_QUIESCED.
- Add DDCA_STATS_API to enum DDCA_Stats_Type, for reporting API specific stats.
- Compile using option -Wformat-security. Issue #458.
- Opaque pointer DDCA_Display_Ref now contains a display reference id instead
  of an actual pointer. It's type continues to be void* so client program use
  of this type is unchanged.
- **libddcutil** maintains a table of DDCA_Display_Refs that have been
  "published" by the API, for validating DDCA_Display_Ref args on API 
  function calls.
- The opaque value in DDCA_Display_Ref is now an integer id number instead of 
  pointer into the libddcutil data structures, making it slightly more opaque.
  The type of DDCA_Display_Ref remains "void*", so no client changes are needed
- syslog output is generally prefixed with date and thread id

#### Fixed

- Whan a display is connected, the display number assigned to its display 
  reference is one greater than the highest already assigned, instead of 99.  
- **ddca_start_watch_displays()**: 
  Fixed segfault that occured with driver nvidia when checking if all video
  adapters implement drm. Issue #390. 
- Ignore phantom displays when searching for a display reference. Issue #412. 
- **ddca_get_display_refs()**, **ddca_get_display_info_list2()** always
  return 0, even if an error occured when examining a particular monitor. 
  Addresses issue #417. 
  - Errors that occur opening individual displays or reading their EDIDs are
    are still reported using **ddca_get_error_detail()**. In addition, error
    messages are written to the terminal and, depending on the current
    syslog level, to the system log.
- **ddca_get_display_refs()** and **ddac_get_display_info_list2()** do not 
  include display references for displays that are no longer connected.
- **ddca_get_display_info()** succeeds even if DDC communication is not working.  
    Addresses issue #???.
- Display reference validation: Do not use dref->drm_connector, which may be 
  invalid after hotplug. Addresses issue #418.
- **ddca_dref_repr()**: Do not check that the display reference is still valid.
  It is meaningful to create a string representation of a display reference even
  if it is no longer usable. Addresses ddcui issue #55.
- Protect hash table of open monitors to avoid a possible race condition.
- Recover instead of abort when more than one non-removed display refs exist 
  for the same display.
- Do not call ddca_stop_watch_displays() at library termination if client has
  already called it. 
- Use mutexes to control access to corruptable data structures.
- Memory leaks.

#### Display Change Detection

- Alternative algorithms for detecting display changes, specified by option 
  ***--watch-mode***
  - watch mode XEVENT
    - Scans for changes only when a X11 change notification occurs. 
      (Uses X11 API extension RANDR, which is also implemented on Wayland.)
  - watch mode POLL
    - doesn't use X11 
    - doesn't rely on /sys 
    - reads EDIDs in polling loop
    - can consume a significant amount of CPU time on older machines
  - watch mode DYNAMIC (the default)
    - resolves to XEVENT on X11 or Wayland, otherwise to POLL
- Extensively reworked display change detection
  - use /sys to get EDID if possible
  - handle MST hub devices if driver/device allow
    - not all drivers work
  - only perform stabilization for removed display
  - not checking for asleep
- Named options affecting display change detection:
  - --watch-mode POLL, XEVENT, DYNAMIC
  - --enable/disable-try-get-edid-from-sysfs (default is --enable-try-get-edid-from-sysfs)
- options ***--xevent-watch-loop-millisec*** ***--poll-watch-loop-millisec***
- Added **ddca_get_display_watch_settings()**, **ddca_set_display_watch_settings()**
- Use constants in parms.h to specify retry intevals and counts
- Handle possible delay between time that EDID can be read and DDC becomes functional
- Added **flags** field in unused secton of DDCA_Display_Status Event, with bit DDCA_DISPLAY_EVENT_DDC_WORKING.
  Normally, this bit is set on display connection events.  In case DDC is not immediately available after 
  EDID detection, this bit is not set.  If DDC subsequently becomes enabled, and event of type DDCA_EVENT_DDC_ENABLED occurs. 

- It's possible that there's a delay between the time a monitor is turned on 
  (and X11/Wayland generate a display change event) and the time that DDC 
  becomes enabled. There's a newly added flags field in DDCA_Display_Status_Event,
  with one bit defined, DDCA_DISPLAY_EVENT_DDC_WORKING.  Normally, this bit is 
  set in the emitted DDCA_Display_Status_Event. However, if DDC is not immediately
  enabled the bit is not set, and the display reference goes onto a recheck queue 
  to be processed by a separate thread. An event of type DDCA_EVENT_DDC_ENABLED
  will be emitted if and when the recheck thread determines that DDC is working.
- There's a tension in display change detection between minimizing the time between
  when X11/Wayland detects a monitor having been turned on and libddcutil issuing
  an event of type DDCA_DISPLAY_EVENT_CONNECTED versus checking and rechecking 
  failed states (e.g. DDC not working).  In many caes, the frequency and wait 
  intervals are controlled by settings in file src/base/parms.h.



## [2.1.4] 2024-02-17

### Shared Library

- Reinstall previously deprecated and removed **ddca_create_display_ref()**, 
  allowing existing clients to build unchanged.


## [2.1.3] 2024-02-07

### Changed

- Option ***--settings*** reports build options.

### Fixed

- Memory leaks

### Shared Library

The shared library **libddcutil** is backwardly compatible with the one in 
ddcutil 2.1.0. The SONAME is unchanged as libddcutil.so.5. The released library
file is libddcutil.so.5.2.0.

### Fixed

- Due to overly aggressive DDCA_Display_Ref validation, ddca_get_display_info()
  returned status DDCRC_ARG when obtaining information about an invalid display 
  (i.e. one for which the EDID is detected but DDC communication fails). This
  fixes ddcui issue #55, which reported an abort if a display was invalid.
- Checking for whether the video adapter supports DRM was consolidated.
  This fixes a case where all displays were reported to support DRM when that
  was not the case, causing incorrect display status change monitoring.
  
## [2.1.2] 2024-01-27

### General

### Added

- Option ***--vstats*** reports minimum, maximum, and average successful
  sleep multiplier

### Changed

- Make hidden option ***--min-dynamic-multiplier*** non-hidden
- Revert **ddca_get/set_sleep_multiplier()** to 2.0.0 semantics
- Allow for the fact that the proprietary Nvidia driver always reports
  the value of /sys/class/drm/<connector name>/enabled as "disabled"

### Fixed

- Invalid assert when checking how monitor reports unsupported features. 
  (Issue #371)
- Segfault in environment command when examining procfs if compiled using clang
  option -flto (Issue #354)
- Bring man page up to date (Issue #364)

### Shared Library

The shared library **libddcutil** is backwardly compatible with the one in 
ddcutil 2.1.0. The SONAME is unchanged as libddcutil.so.5. The released library
file is libddcutil.so.5.1.1.

### Changed

- **ddca_start_watch_displays()** requires that all video drivers support DRM. 
  If the API call fails, detailed error information is available using 
  **ddca_get_error_detail()**.
- Additional syslog messages

### Fixed

- SIGABRT in API calls that have a display reference or handle argument if 
  **ddca_init2()** (or **ddca_init()**) had not been called.  This caused
  KDE PowerDevil to repeatedly crash and restart. 
- Fix the check of whether all video drivers implement DRM, required for
  display hotplug detection.


## [2.1.0] 2024-01-16

### General

#### Added
- Option ***--skip-ddc-checks***
  - Skips initialization checks to confirm that DDC communication is working
    and the monitor properly uses the unsupported feature bit in Get Feature 
    Reply packets, thereby improving initialization time.
- Cross-instance locking (experimental). Uses flock() to coordinate I2C bus
  access to /dev/i2c devices when multiple instances of ddcutil or libddcutil
  are executing. Enabled by option ***--enable-cross-instance-locks***.
- Option ***--min-dynamic-multiplier*** Specifies a floor to how low dynamic
  sleep adjustment sets the sleep multiplier. (experimental)

#### Changed
- Multiple "Options:" lines in an ini file segment are combined
- Option ***--help***: 
  - Only show extended information when ***--verbose*** specified
- Option ***--version***: 
  - Show only the version, without prefix if ***--brief*** specified
  - Include detailed build information if ***--verbose** specified 
- I2C bus examination during initialization can be parallelized, improving performance
  (This is distinct from the ddc protocol checking.) This is an experimental
  feature.  It can be enabled by using a low value as an argument to option 
  ***--i2c-init-async-min***, e.g. ***--i2c-init-async-min 4***.
  THIS OPTION IS DISABLED BY DEFAULT AS IT OCCASIONALLY TRIGGERS A BUG IN
  DRIVER amdgpu THAT CAN CAUSE THE MOUSE AND KEYBOARD TO BECOME UNRESPONSIVE.
  See freedesktop.org bug report "lockup in dce_i2c_submit_command_hw" at
  https://gitlab.freedesktop.org/drm/amd/-/issues.
- Command detect: better messages when laptop display detected
  - do not report "DDC communication failed"
  - report "Is laptop display" instead of "Is eDP device" or "Is LVDS device"
- Better accomodate the variation in use of sysfs by different drivers
- Turned off unconditional message that reported an elusive Nvidia/i2c-dev
  driver compatibility error.  The incompatibility has been full diagnosed 
  as being caused by use of a legacy proprietary Nvidia driver. A message
  is still written to the system log.
- Make more extensive use of the system log.
- Options ***--enable-displays-cache***, ***--disable-displays-cache*** are marked
  hidden since displays caching is not a released feature.
- Deprecate vaguely named option ***--force***.  Replace its single use with  
  option ***--permit-unknown-feature***.
- Deprecate vaguely named option ***--async***. Use ***--ddc-checks-async-min***
- Deprecate vaguely named option ***--ddc***. Use option ***--ddcdata***, which more
  clearly indicates that it causes DDC data errors to be reported.
- **configure** option ***--enable-asan*** causes libasan to be linked into binaries 
- **configure** option ***--enable-x11*** is deprecated. The X11 API is no longer used.

#### Fixed
- Better handling of DDC Null Message recognition and adjustments
- Dynamic sleep: make it easier to reduce time - once high didn't come down
- Command detect: ensure output of model name, serial number, and extra display descriptor 
  use only ASCII character in the range 0..127.
- Some USB-only code was not iftested out when **configure** option ***--disable-usb*** was set. (Issue 355)
- Always set sleep multiplier to at least 1.0 for commands **setvcp** and **scs**. Addresses reports
  that aggressive optimization caused setvcp to fail.
- Cross-thread locking handles situtations where a display ref does not yet exist, e.g. reading EDID.
- Memory leaks.

### Shared library

The shared library **libddcutil** is backwardly compatible with the one in 
ddcutil 2.0.0. The SONAME is unchanged as libddcutil.so.5. The released library
file is libddcutil.so.5.1.0.

#### Added
- Implemented display hotplug event detection
  - Requires DRM video drivers (e.g. amdgpu, i915)
  - Can detect physical connection/disconnection and DPMS sleep status chanes,
    but the effect of turning a monitor on or off is monitor dependant and 
    cannot reliably be detected.
  - Enabled by libddcutil option ***--enable-watch-displays***, or
    API call **ddca_enable_start_watch_displays()**
  - API uses callbacks to report report status changes to client
  - new status codes possible for many current API functions: 
    DDCRC_DISCONNECTED, DDCRC_DPMS_ASLEEP
  - When a display connection event is reported, the client should call 
    **ddca_redetect_displays()**
- **ddca_validate_display_ref()**: Exposes the validation that occurs on any
    API call that has a DDCA_Display_Ref argument.  Can be used to check 
    whether a monitor asleep, disconnected, etc.
- New functions for sleep multiplier control:
  - **ddca_enable_dynamic_sleep() 
  - **ddca_disable_dynamic_sleep() 
  - **ddca_get_current_sleep_multiplier() 
  - **ddca_set_display_sleep_multiplier() 
- **ddca_init2()** replaces **ddca_init()**, which is deprecated: 
  Has an additional argument for collecting informational msgs. Allows for not
  issuing information messages regarding the assembly of options and parsing directly
  from libddcutil to the terminal (now enabled by setting flag DDCA_INIT_OPTIONS_ENABLE_INIT_MSGS),
  but instead gives client complete control as to what to do with the messages.

#### Changed
- Functions that depend on initialization and that return a status code now 
  return DDCRC_UNINITIALIZED if ddca_init() failed.
- Revert **ddca_get_sleep_multiplier()**, **ddca_set_sleep_multiplier()** to 
  their pre 2.0 semantics changing the multiplier on the current thread.
  However, these functions are marked as deprecated.

#### Fixed
- Argument passing on **ddca_get_any_vcp_value_using_implicit_type()**
- Fixed cause of assert() failure in **ddca_init()** when the libopts string
  argument has a value and the configuration file is enabled but no options 
  are obtained from the configuation file.
- Contents of the libopts arg were added twice to the string passed to the
  libddcutil parser.

## [2.0.0] 2023-09-25

Release 2.0.0 contains extensive changes.  Shared library libddcutil is not 
backwards compatible.  

#### Added
- Install /usr/lib/modules-load.d/ddcutil.conf. Ensures that driver i2c-dev
  is loaded.
- Install file /usr/share/udev/rules.d/60-ddcutil-i2c.rules, autmatically granting
  the logged on user read/write access to /dev/i2c devices for video displays.
  For most configurations, use of group i2c is no longer necessary.
- Command options not of interest to general users are now hidden when help is 
  requested.  Option ***--hh*** exposes them, and implies option ***--help***.
- Option ***--noconfig***. Do not process the configuration file.
- Option ***--verbose***.  If specified on the command line, the options obtained
  from the configuration file are reported.
- Added utility options --f7, --f8, --i2, --s1, --s2, --s3, --s4, --fl1, --fl2
  These options are for temporary use during development. The current use of 
  the utility options is reported by option ***--settings***. 
- Added utility command C1 for temporary use during development.
- Added option ***--enable-mock-data*** for testing
- Option ***--trcfrom***. Traces the call stack starting with the specified 
  function.  This option applies only to functions for which tracing has been enabled.
- API performance profiling
- Added options ***--ignore-hiddev*** and ***--ignore-usb-vid-pid***
- Added: Sample file nvidia-i2c.conf that can be installed in directory 
  /etc/modprobe.d to set options sometimes needed by the proprieatry NVidia 
  video driver.
- Added option ***--discard-cache*** to discard cached data at the start of 
  program execution.  Valid arguments are ***capabilities***, ***dsa***, and ***all***.
- Command **discard [capabilites|dsa|all] cache(s)** discards cached data.
- Option ***--pid*** (alt ***--process-id***) prepends the process id to trace messages.
- Command **traceable-functions*** lists functions that can be traced by name, 
  i.e. ones that can be specified as a ***--trcfunc*** argument.
- If using X11, terminate immediately if a DPMS sleep mode is active.

#### Changed
- The dynamic sleep algorithm has been completely rewritten to both dynamically
  increase the sleep-multiplier factor (as needed) and decrease the sleep 
  multiplier factor (insofar as possible).  Data is maintained across program 
  executions in file $HOME/.cache/ddcutil/stats. Option ***-dsa***, or one of 
  its variants such as ***--enable-dsa*** turn it on.
- Option ***--sleep-multiplier***:  0 is now allowed as an argument. Some 
  DisplayPort monitors have been observed to work with this value. 
- Writing to the system log has been generalized. 
  Option ***--syslog <level>*** controls what is written to the system log.
  Recognized levels are NEVER, ERROR, WARN, INFO, and DEBUG.  This option 
  replaces ***--enable-syslog***, ***--disable-syslog***, and ***--trace-to-syslog***. 
- **environment --verbose**: Option ***--quickenv*** skips some slow tests such as 
  use of program i2cdetect.
