Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Display not found with LG UltraFine 27MD5KL #123

Closed
andrejpodzimek opened this issue May 27, 2020 · 25 comments
Closed

Display not found with LG UltraFine 27MD5KL #123

andrejpodzimek opened this issue May 27, 2020 · 25 comments
Labels
bug lg monitor specific problems with particular monitors USB

Comments

@andrejpodzimek
Copy link

While the 5k resolution works fine and looks awesome (thanks to this latest fix), I haven't found a way to make backlight controls work. I tried lots of combinations, both as root and as a regular user:

ddcutil getvcp 10 --hiddev 3
ddcutil getvcp 10 --usb 7.5
ddcutil probe --hiddev 3
ddcutil probe --usb 7.5
ddcutil detect
ddcutil usbenv  # <<< This does something!

I always get No displays found from detect and Display not found from the (more) monitor-specific commands. Only ddcutil usbenv seems to identify the monitor somehow:

Device /dev/usb/hiddev3, devnum.busnum: 7.5, vid:pid: 043e:9a70 - LG Electronics Inc. LG UltraFine Display Controls
   Identifies as a USB HID monitor

Initially I tried a few LG-specific brightness control tools, but they didn't work for me, likely because they assume i2c over DisplayPort or the like, whereas this monitor is Thunderbolt-only and may not have an i2c bus relayed through Thunderbolt. I do have i2c_hid loaded, but no i2c devices pop up in /dev.

Full ddcutil usbenv output

In particular, this piece of data looks like “something backlight-related”:

/sys/kernel/debug/hid/0003:043E:9A70.0014/rdesc:
   05 80 09 01 a1 01 06 82 00 09 10 15 04 26 1c 02 67 e1 00 00 01 55 0e 75 20 95 01 b1 42 06 82 00 09 10 67 e1 00 00 01 55 0e 75 20 95 01 81 02 05 0f 09 50 15 00 26 20 4e 66 10 01 55 0d 75 10 95 01 b1 42 c0

     INPUT[INPUT]
       Field(0)
         Application(0080.0001)
         Usage(1)
           0082.0010
         Logical Minimum(4)
         Logical Maximum(540)
         Unit Exponent(-2)
         Unit(SI Linear : Centimeter^-2*Candela)
         Report Size(32)
         Report Count(1)
         Report Offset(0)
         Flags( Variable Absolute )
     FEATURE[FEATURE]
       Field(0)
         Application(0080.0001)
         Usage(1)
           0082.0010
         Logical Minimum(4)
         Logical Maximum(540)
         Unit Exponent(-2)
         Unit(SI Linear : Centimeter^-2*Candela)
         Report Size(32)
         Report Count(1)
         Report Offset(0)
         Flags( Variable Absolute NullState )
       Field(1)
         Application(0080.0001)
         Usage(1)
           PhysicalInterfaceDevice.0050
         Logical Minimum(0)
         Logical Maximum(20000)
         Unit Exponent(-3)
         Unit(None : None*None)
         Report Size(16)
         Report Count(1)
         Report Offset(32)
         Flags( Variable Absolute NullState )

   0082.0010 ---> Sync.Report

System configuration

@andrejpodzimek
Copy link
Author

I've just retried it without the dock (with the monitor directly in the laptop's Thunderbolt port), but results were almost identical; no display found.

@rockowitz
Copy link
Owner

rockowitz commented May 27, 2020 via email

@andrejpodzimek
Copy link
Author

Alright, here's a workaround. Brightness can be controlled using this tool, loosely based on acdcontrol:

// This code has been shamelessly extracted from acdcontrol:
// https://www.dionysopoulos.me/apple-display-brightness-controls-in-ubuntu-desktop/

# define _POSIX_C_SOURCE 200809L
#include <fcntl.h>
#include <inttypes.h>
#include <linux/hiddev.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

static const uint32_t USAGE_CODE = 0x820010;  // Magic!
static const size_t MAX_INT32_DIGITS = 10;
static const char HID_DEVICE[] = "/dev/usb/hiddev";

int main(int argc, const char* const* argv) {
  if (argc != 3) {
    if (argc)
      dprintf(STDERR_FILENO, "Usage: %s <HID device> <brightness>\n", argv[0]);
    return EXIT_FAILURE;
  }
  bool error = false;
  char *endptr;
  const uint32_t device = strtoul(argv[1], &endptr, 10);
  if (!argv[1] || *endptr) {
    dprintf(STDERR_FILENO, "Malformed device number '%s'\n", argv[1]);
    error = true;
  }
  char device_name[sizeof(HID_DEVICE) + MAX_INT32_DIGITS];
  sprintf(device_name, "%s%" PRIu32, HID_DEVICE, device);
  const int32_t brightness = strtoul(argv[2], &endptr, 10);
  if (!argv[2] || *endptr) {
    dprintf(STDERR_FILENO, "Malformed brightness value '%s'\n", argv[2]);
    error = true;
  }
  if (error) return EXIT_FAILURE;
  const int fd = open(device_name, O_RDWR);
  if (fd < 0) {
    perror("HID open() failed");
    return EXIT_FAILURE;
  }
  const struct hiddev_usage_ref usage_ref = {
    .report_type = HID_REPORT_TYPE_FEATURE,
    .report_id = HID_REPORT_ID_FIRST,  // This is for LG; Apple may use 16
    .field_index = 0,
    .usage_index = 0,
    .usage_code = USAGE_CODE,
    .value = brightness,  // For LG 27MD5KL, this is 400 to 54000.
  };
  if (ioctl(fd, HIDIOCSUSAGE, &usage_ref) < 0) {
    perror("HIDIOCSUSAGE failed");
    return EXIT_FAILURE;
  }
  const struct hiddev_report_info report_info = {
    .report_type = HID_REPORT_TYPE_FEATURE,
    .report_id = HID_REPORT_ID_FIRST,  // This is for LG; Apple may use 16
    .num_fields = 1,
  };
  if (ioctl(fd, HIDIOCSREPORT, &report_info) < 0) {
    perror("HIDIOCSREPORT failed");
    return EXIT_FAILURE;
  }
  if (close(fd) < 0) {
    perror("HID close() failed");
    return EXIT_FAILURE;
  }
  return EXIT_SUCCESS;
}

Example for /dev/usb/hiddev3:

clang -std=c11 -Wall -Wextra -pedantic -march=native -O3 brightness.c -o brightness
./brightness 3 400  # minimum
./brightness 3 54000  # maximum
./brightness 3 36000  # my usual choice

@andrejpodzimek
Copy link
Author

@rockowitz Here's the output:

The C example above shows what ioctl() commands work for brightness on this monitor. (I haven't tried to figure out what that other FEATURE (and also the INPUT) means.)

@rockowitz
Copy link
Owner

rockowitz commented May 27, 2020 via email

@rockowitz
Copy link
Owner

rockowitz commented May 27, 2020 via email

@andrejpodzimek
Copy link
Author

Oh, now I see that all of this has been just my mistake + ignorance. I had i2c_hid loaded and thought that was all (and no i2c devices showed up). In fact what I should have had was i2c_dev, but I didn’t have it due to a strange glitch. (I'm jusing a -rc kernel to get 5k working on this monitor (with i915) and i2c_dev just didn’t load.) After some trial and error (and i2c_dev at last), I got this:

# ddcutil detect
Invalid display
   I2C bus:             /dev/i2c-5
   EDID synopsis:
      Mfg id:           BOE
      Model:
      Serial number:
      Manufacture year: 2018
      EDID version:     1.4
   DDC communication failed
   This is an eDP laptop display. Laptop displays do not support DDC/CI.

Display 1
   I2C bus:             /dev/i2c-6
   EDID synopsis:
      Mfg id:           GSM
      Model:            LG UltraFine
      Serial number:    003NTTQ58945
      Manufacture year: 2020
      EDID version:     1.4
   VCP version:         Detection failed

Display 2
   I2C bus:             /dev/i2c-7
   EDID synopsis:
      Mfg id:           GSM
      Model:            LG UltraFine
      Serial number:    003NTTQ58945
      Manufacture year: 2020
      EDID version:     1.4
   VCP version:         Detection failed

Brightness control works (setvcp 10 ...) for both --display 1 and --display 2.

Thanks a lot for looking into this and sorry for all the noise.

@rockowitz
Copy link
Owner

rockowitz commented May 28, 2020 via email

@andrejpodzimek
Copy link
Author

  • Two /i2c-dev devices for the same monitor. I've seen this for
    DisplayPort devices. Normally, DDC works only over one of the /dev/i2c
    devices, and detection should filter out the crippled duplicate.
    Apparently that is not happening in your case.

Well, at least brightness can be set using any of the two devices. It takes effect over the entire monitor, presumably; the backlight (fortunately) doesn't have two tiles.

  • Have you hacked the EDID so that identical monitors have the same
    serial number?

Nope, the monitor is in a pristine factory state and I didn't attempt to override the EDID in software anywhere else.

  • The monitor looks like it should support the USB Monitor Control Class
    spec, but detection doesn't find it.

That's weird. Well, at least the HID trick above still works for brightness. (Not sure what the other FEATURE or the INPUT is.) Maybe one of these mysterious devices is an entry point to the functionality you mentioned?

$ lsusb | grep LG
Bus 006 Device 004: ID 043e:9a68 LG Electronics USA, Inc.
Bus 006 Device 003: ID 043e:9a71 LG Electronics USA, Inc.
Bus 006 Device 002: ID 043e:9a60 LG Electronics USA, Inc. USB3.1 Hub
Bus 005 Device 005: ID 043e:9a70 LG Electronics USA, Inc. USB2.1 Hub
Bus 005 Device 004: ID 043e:9a66 LG Electronics USA, Inc.
Bus 005 Device 003: ID 043e:9a73 LG Electronics USA, Inc.
Bus 005 Device 002: ID 043e:9a61 LG Electronics USA, Inc. USB2.1 Hub

Please run the following commands (n.b. as root) and send the output as
attachments:

@rockowitz
Copy link
Owner

rockowitz commented May 31, 2020 via email

@andrejpodzimek
Copy link
Author

@rockowitz
Copy link
Owner

rockowitz commented Jun 2, 2020 via email

@andrejpodzimek
Copy link
Author

@rockowitz
Copy link
Owner

rockowitz commented Jun 6, 2020 via email

@andrejpodzimek
Copy link
Author

  • ddcutil detect --verbose --trace usb

    First this couldn't open any of the /dev/i2c-* devices. So I added myself to the i2c group. (Which is already wrong; this should be managed by systemd using ACLs to grant permissions dynamically based on logins and seats (just like sound cards and input devices are managed). Unfortunately, I couldn't find a suitable udev + systemd configuration example on the web that would manage /dev/i2c-* properly.) Even with my i2c membership, it still complains about /dev/usb/hiddev*. But those devices have root:root ownership and 600 permissions by default, so no quick'n'dirty membership hack is available.

    Open failed for /dev/usb/hiddev0: errno=EACCES(13): Permission denied
    Open failed for /dev/usb/hiddev2: errno=EACCES(13): Permission denied
    Open failed for /dev/usb/hiddev3: errno=EACCES(13): Permission denied
    Open failed for /dev/usb/hiddev4: errno=EACCES(13): Permission denied
    

    I guess the only proper and root-avoiding solution would be to have seat-based ACLs managed by udev + systemd. Which sounds like quite a big undertaking involving lots of USB IDs of monitors and lots of configuration. 😱

  • sudo ddcutil detect --verbose --trace usb

    I haven't mentioned it before, but this rants a bit on stderr when it sees eDP1, the laptop display:

    Monitor on device /dev/usb/hiddev3 reports no EDID or has invalid EDID. Ignoring.
    
  • sudo ddcutil usbenvironment

@rockowitz
Copy link
Owner

rockowitz commented Jun 13, 2020 via email

@andrejpodzimek
Copy link
Author

Thanks for the details. My entire point about the ACLs was the little + that appears (mostly unnoticed) when you look at (e.g.) sound cards:

$ ls -l /dev/snd
...
crw-rw----+ 1 root audio 116, 15 Jun 12 17:34 controlC0
crw-rw----+ 1 root audio 116,  3 Jun 12 17:34 controlC1
...
crw-rw----+ 1 root audio 116, 14 Jun 12 17:34 hwC0D0
crw-rw----+ 1 root audio 116, 13 Jun 12 17:34 hwC0D2
crw-rw----+ 1 root audio 116,  7 Jun 14 07:23 pcmC0D0c
crw-rw----+ 1 root audio 116,  6 Jun 14 07:24 pcmC0D0p
...
crw-rw----+ 1 root audio 116,  1 Jun 12 17:34 seq
crw-rw----+ 1 root audio 116, 33 Jun 12 17:34 timer

getfacl for any of the devices with + shows myself in that temporary ACL, because the seat I've logged in from happens to be associated with the sound card.

Presumably, I'm not in the audio group and there's no need for that membership; it would only be necessary for special purposes (e.g. playing sound without logging in from a seat, over SSH or the like).

Just like sound cards (or even more so), monitors should be associated with a particular login seat. (There's no point in allowing a user logged in over SSH or from an unrelated seat to adjust backlight brightness.)

However, as you pointed out, this should be done in a separate project (using ddcutil as a tool) rather than in ddcutil (the package, the repository) itself.

@andrejpodzimek
Copy link
Author

As for the (numerous) monitor capabilities listed but not really “exposed”, this is something that I also find puzzling. One of my goals was to set a cooler color tone on the monitor, but the corresponding capabilities don't seem to be actually working. Admittedly, I haven't tried too many wannabe-clever tricks to poke around and skip some of the checks, simply because I don't really want to brick the monitor. But since my laptop has a much cooler tone than the monitor and since I prefer white at 6000 K anyway, I thought it would be awesome to configure this on the monitor as well.

@rockowitz
Copy link
Owner

rockowitz commented Jun 16, 2020 via email

@rockowitz
Copy link
Owner

rockowitz commented Jun 16, 2020 via email

@andrejpodzimek
Copy link
Author

If you send me the output of "ddcutil probe --trcfunc ddc_write_read"…

Is there a button to turn it on?

No, the monitor has exactly zero buttons. It doesn't show any signs of an OSD, controlled or automatic. (Older monitors sometimes show a message for a few seconds when they detect inputs or lose signal, but this one doesn't.)

If you can connect the monitor to a Windows system…
So if you have access to a Mac you might try that.

I don't have any of that.

Interesting possibilities are feature x04 (Restore Factory Defaults) and x05 (Restore Factory Brightness/Contrast).

I tried ddcutil --display 1 setvcp x05 1. But it didn't have any noticeable effect. A subsequent getvcp on value 10 returned the same brightness I had set before. The command terminates successfully though. I wasn't sure what the argument should be (and tried just 0 and 1). The feature x05 is not readable, so I had no reference point.

@rockowitz
Copy link
Owner

rockowitz commented Jul 4, 2020 via email

@rockowitz rockowitz added bug monitor specific problems with particular monitors USB labels Jul 6, 2020
@rockowitz rockowitz added the lg label Nov 30, 2021
@24fpsDaVinci
Copy link

24fpsDaVinci commented Jun 10, 2022

sorry to bump this closed thread, i just want to point out this Andre's C program (#123 (comment)) works with the newly released Apply studio display 5k.

@rockowitz
Copy link
Owner

It's not clear to me what "this script" in your message refers to. The "123 (comment)" link is to Andre's C program derived from acdconttrol.

Are you communicating with the monitor using I2C or USB?

@24fpsDaVinci
Copy link

24fpsDaVinci commented Jun 10, 2022

It's not clear to me what "this script" in your message refers to. The "123 (comment)" link is to Andre's C program derived from acdconttrol.

Are you communicating with the monitor using I2C or USB?

the new apple studio display is brightness over usb only, no ddc support as far as I can tell. I edited my last comment to be more clear.

output from ddcutil usbenv command for those interested.

  /sys/kernel/debug/hid/0003:05AC:1114.000B/rdesc:
     05 80 09 01 a1 01 85 01 06 82 00 09 10 16 90 01 27 60 ea 00 00 67 e1 00 00 01 55 0e 75 20 95 01 b1 42 05 0f 09 50 15 00 26 20 4e 66 10 01 55 0d 75 10 b1 42 06 82 00 09 10 16 90 01 27 60 ea 00 00 67 e1 00 00 01 55 0e 75 20 95 01 81 02 c0
     
       INPUT(1)[INPUT]
         Field(0)
           Application(0080.0001)
           Usage(1)
             0082.0010
           Logical Minimum(400)
           Logical Maximum(60000)
           Unit Exponent(-2)
           Unit(SI Linear : Centimeter^-2*Candela)
           Report Size(32)
           Report Count(1)
           Report Offset(0)
           Flags( Variable Absolute )
       FEATURE(1)[FEATURE]
         Field(0)
           Application(0080.0001)
           Usage(1)
             0082.0010
           Logical Minimum(400)
           Logical Maximum(60000)
           Unit Exponent(-2)
           Unit(SI Linear : Centimeter^-2*Candela)
           Report Size(32)
           Report Count(1)
           Report Offset(0)
           Flags( Variable Absolute NullState )
         Field(1)
           Application(0080.0001)
           Usage(1)
             PhysicalInterfaceDevice.0050
           Logical Minimum(0)
           Logical Maximum(20000)
           Unit Exponent(-3)
           Unit(None : None*None)
           Report Size(16)
           Report Count(1)
           Report Offset(32)
           Flags( Variable Absolute NullState )
     
     0082.0010 ---> Sync.Report

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug lg monitor specific problems with particular monitors USB
Projects
None yet
Development

No branches or pull requests

3 participants