Skip to content

Instantly share code, notes, and snippets.

@lainosantos
Last active February 18, 2025 21:01
Show Gist options
  • Save lainosantos/06d233f6c586305cde67489c2e4a764d to your computer and use it in GitHub Desktop.
Save lainosantos/06d233f6c586305cde67489c2e4a764d to your computer and use it in GitHub Desktop.
Basic commands for for KVM, PIP and PBP features for Dell Monitor U2723QE on Linux ddcutil
#!/usr/bin/env bash
if [ "$EUID" -ne 0 ] && groups | grep -qwv 'i2c' && getent group i2c &> /dev/null
then
echo "Insuficient permissions, run as root ou join $USER to i2c group."
exit 1
fi
case "$1" in
"switch")
# if hdmi is active, then go to usb
if ddcutil getvcp 60 | grep -q 'sl=0x11'; then
# usb-c
next_target="0x1b"
# if usb is active, then go to hdmi
elif ddcutil getvcp 60 | grep -q 'sl=0x1b'; then
# display port
next_target="0x0f"
# if hdmi is active, tehn go to usb
else
# hdmi
next_target="0x11"
fi
if [ "$2" = "usb-c" ]; then
next_target="0x1b"
elif [ "$2" = "dp" ]; then
next_target="0x0f"
elif [ "$2" = "hdmi" ]; then
next_target="0x11"
fi
ddcutil setvcp 60 "$next_target"
;;
"single_mode")
# exit from pip/pbp
ddcutil setvcp E9 0x0
;;
"switch_pip_size")
# switch between small and big pip window size
ddcutil setvcp E9 0x01
;;
"switch_pip_position")
# switch pip window position
ddcutil setvcp E9 0x2
;;
"pip_mode_small")
# enter on pip small window size
ddcutil setvcp E9 0x21
;;
"pip_mode_big")
# enter on pip big window size
ddcutil setvcp E9 0x1
;;
"pbp_mode")
# enter on pbp mode
ddcutil setvcp E9 0x24
;;
"switch_video")
# switch video sources on pip/pbp mode
ddcutil setvcp E5 0xF001
;;
"switch_usb")
# switch usb hub target on pip/pbp mode
ddcutil setvcp E7 0xFF00
;;
*)
echo "Invalid argument, use switch [usb-c, dp, hdmi], single_mode, switch_pip_size, switch_pip_position, pip_mode_small, pip_mode_big, pbp_mode, switch_video, switch_usb"
exit 1
;;
esac
@Kyklas
Copy link

Kyklas commented Mar 7, 2024

Thanks for the script, makes the workflow better on U3824DW.
How did you figure out the pip or pbp values ?

@lainosantos
Copy link
Author

Hi, you're welcome!!

I catch all them by reverse engenirring with this tool on a Windows OS (https://github.com/ScriptGod1337/kvm)

@margce
Copy link

margce commented Jul 18, 2024

Hi and thanks for script! I'm running Fedora 38 with a Dell U3824DW. The ddcutil detect command returns this info

Display 1
I2C bus: /dev/i2c-8
DRM connector: card1-DP-1
EDID synopsis:
Mfg id: DEL - Dell Inc.
Model: DELL U3824DW
Product code: 41484 (0xa20c)
Serial number: xxxxxx
Binary serial number: xxxxx
Manufacture year: 2023, Week: 23
VCP version: 2.1

When using the command to switch, although it works I get this message.

./dell_kvm.sh switch_usb
Setting value failed for feature e7, rc=DDCRC_NULL_RESPONSE(-3002): received DDC null response

Is this expected?

@emmenlau
Copy link

Thanks for this great script! I have slightly extended it, with only minor changes. For me on Ubuntu 24.04, it does not require root, and also not being in the i2c group. And it works unchanged also on Dell U2723QE

#!/usr/bin/env bash

#if test "$EUID" -ne 0  && groups | grep -qwv 'i2c' && getent group i2c &> /dev/null ; then
#    echo "Insufficient permissions. Run as root, our join $USER to the 'i2c' group."
#    exit 1
#fi


ARGUMENTS=("$@")
if test "${#ARGUMENTS[@]}" -lt 1 ; then
    echo "No arguments given, defaulting to 'switch'."
    ARGUMENTS=("switch")
fi || exit 1


case "${ARGUMENTS[0]}" in
    "switch")
      # if hdmi is active, then go to usb
      if ddcutil getvcp 60 | grep -q 'sl=0x11'; then
        # usb-c
        next_target="0x1b"
      # if usb is active, then go to hdmi
      elif ddcutil getvcp 60 | grep -q 'sl=0x1b'; then
        # display port
        next_target="0x0f"
      # if hdmi is active, tehn go to usb
      else
        # hdmi
        next_target="0x11"
      fi

      if test -n "${ARGUMENTS[1]}" ; then
          if test "${ARGUMENTS[1]}" == "usb-c" ; then
              next_target="0x1b"
          elif test "${ARGUMENTS[1]}" == "dp" ; then
              next_target="0x0f"
          elif test "${ARGUMENTS[1]}" == "hdmi" ; then
              next_target="0x11"
          else
              echo "Unknown/unsupported parameter '${ARGUMENTS[1]}' to argument 'switch'."
              exit 1
          fi || exit 1
      fi || exit 1

      ddcutil setvcp 60 "$next_target"
      ;;
    "single_mode")
      # exit from pip/pbp
      ddcutil setvcp E9 0x0
      ;;
    "switch_pip_size")
      # switch between small and big pip window size
      ddcutil setvcp E9 0x01
      ;;
    "switch_pip_position")
      # switch pip window position
      ddcutil setvcp E9 0x2
      ;;
    "pip_mode_small")
      # enter on pip small window size
      ddcutil setvcp E9 0x21
      ;;
    "pip_mode_big")
      # enter on pip big window size
      ddcutil setvcp E9 0x1
      ;;
    "pbp_mode")
      # enter on pbp mode
      ddcutil setvcp E9 0x24
      ;;
    "switch_video")
      # switch video sources on pip/pbp mode
      ddcutil setvcp E5 0xF001
      ;;
    "switch_usb")
      # switch usb hub target on pip/pbp mode
      ddcutil setvcp E7 0xFF00
      ;;
    *)
      echo "Invalid or unsupported argument '${ARGUMENTS[0]}'."
      echo "Use one of: switch [usb-c, dp, hdmi], single_mode, switch_pip_size, switch_pip_position, pip_mode_small, pip_mode_big, pbp_mode, switch_video, switch_usb"
      exit 1
      ;;
esac

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment