summaryrefslogtreecommitdiff
path: root/meta-openbmc-mods/meta-common/recipes-graphics
diff options
context:
space:
mode:
Diffstat (limited to 'meta-openbmc-mods/meta-common/recipes-graphics')
-rw-r--r--meta-openbmc-mods/meta-common/recipes-graphics/libvncserver/libvncserver_%.bbappend5
-rw-r--r--meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/0003-Fix-keyboard-and-mouse-input-events-dropping-issue.patch162
-rw-r--r--meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/0004-Connect-HID-gadget-device-dynamically.patch494
-rw-r--r--meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/0005-Refine-HID-report-writing-logic.patch295
-rw-r--r--meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm_%.bbappend10
5 files changed, 966 insertions, 0 deletions
diff --git a/meta-openbmc-mods/meta-common/recipes-graphics/libvncserver/libvncserver_%.bbappend b/meta-openbmc-mods/meta-common/recipes-graphics/libvncserver/libvncserver_%.bbappend
new file mode 100644
index 000000000..f42119baa
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-graphics/libvncserver/libvncserver_%.bbappend
@@ -0,0 +1,5 @@
+FILESEXTRAPATHS_append := ":${THISDIR}/${PN}"
+
+# Use the latest to support obmc-ikvm properly
+SRC_URI = "git://github.com/LibVNC/libvncserver"
+SRCREV = "2b6d595e3ea89597b3bebbf545eb7d3c0a1224a8"
diff --git a/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/0003-Fix-keyboard-and-mouse-input-events-dropping-issue.patch b/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/0003-Fix-keyboard-and-mouse-input-events-dropping-issue.patch
new file mode 100644
index 000000000..43600ac8a
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/0003-Fix-keyboard-and-mouse-input-events-dropping-issue.patch
@@ -0,0 +1,162 @@
+From 0c0b7b5da551c99161bda98820a529ba29cbaac1 Mon Sep 17 00:00:00 2001
+From: Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>
+Date: Wed, 21 Aug 2019 16:52:30 -0700
+Subject: [PATCH] Fix keyboard and mouse input events dropping issue
+
+Restarting of HID input devices causes input events dropping issue
+which is critical for BMC KVM uses. For an example, user can't enter
+to BIOS by doing keep pressing 'F2' or 'Del' key because of this issue.
+
+To fix the issue, this commit removes the input device restarting
+logic and refines error log journaling logic using errno checking.
+
+Tested:
+ 1. Open BMCweb -> Server control -> KVM.
+ 2. Make a host reset and keep pressing 'F2' key.
+ 3. Was able to enter to BIOS using the key press.
+
+Change-Id: Iec1bfad1d9e5825858844cab658bbfa3e6bc24f6
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>
+---
+ ikvm_input.cpp | 58 +++++++---------------------------------------------------
+ ikvm_input.hpp | 4 ----
+ ikvm_video.cpp | 3 +--
+ 3 files changed, 8 insertions(+), 57 deletions(-)
+
+diff --git a/ikvm_input.cpp b/ikvm_input.cpp
+index d95e6313f62c..df12f2715585 100644
+--- a/ikvm_input.cpp
++++ b/ikvm_input.cpp
+@@ -23,9 +23,9 @@ using namespace phosphor::logging;
+ using namespace sdbusplus::xyz::openbmc_project::Common::File::Error;
+
+ Input::Input(const std::string& kbdPath, const std::string& ptrPath) :
+- pointerError(false), sendKeyboard(false), sendPointer(false),
+- keyboardFd(-1), pointerFd(-1), keyboardReport{0}, pointerReport{0},
+- keyboardPath(kbdPath), pointerPath(ptrPath)
++ sendKeyboard(false), sendPointer(false), keyboardFd(-1), pointerFd(-1),
++ keyboardReport{0}, pointerReport{0}, keyboardPath(kbdPath),
++ pointerPath(ptrPath)
+ {
+ if (!keyboardPath.empty())
+ {
+@@ -156,36 +156,6 @@ void Input::pointerEvent(int buttonMask, int x, int y, rfbClientPtr cl)
+ rfbDefaultPtrAddEvent(buttonMask, x, y, cl);
+ }
+
+-void Input::restart()
+-{
+- if (!keyboardPath.empty() && keyboardFd < 0)
+- {
+- keyboardFd = open(keyboardPath.c_str(), O_RDWR | O_CLOEXEC);
+- if (keyboardFd < 0)
+- {
+- log<level::ERR>("Failed to open input device",
+- entry("PATH=%s", keyboardPath.c_str()),
+- entry("ERROR=%s", strerror(errno)));
+- }
+-
+- sendKeyboard = false;
+- }
+-
+- if (!pointerPath.empty() && pointerFd < 0)
+- {
+- pointerFd = open(pointerPath.c_str(), O_RDWR | O_CLOEXEC | O_NONBLOCK);
+- if (pointerFd < 0)
+- {
+- log<level::ERR>("Failed to open input device",
+- entry("PATH=%s", pointerPath.c_str()),
+- entry("ERROR=%s", strerror(errno)));
+- }
+-
+- pointerError = false;
+- sendPointer = false;
+- }
+-}
+-
+ void Input::sendWakeupPacket()
+ {
+ uint8_t wakeupReport[KEY_REPORT_LENGTH] = {0};
+@@ -459,13 +429,10 @@ bool Input::writeKeyboard(const uint8_t *report)
+ {
+ if (write(keyboardFd, report, KEY_REPORT_LENGTH) != KEY_REPORT_LENGTH)
+ {
+- log<level::ERR>("Failed to write keyboard report",
+- entry("ERROR=%s", strerror(errno)));
+-
+- if (errno == ESHUTDOWN)
++ if (errno != ESHUTDOWN && errno != EAGAIN)
+ {
+- close(keyboardFd);
+- keyboardFd = -1;
++ log<level::ERR>("Failed to write keyboard report",
++ entry("ERROR=%s", strerror(errno)));
+ }
+
+ return false;
+@@ -478,23 +445,12 @@ void Input::writePointer(const uint8_t *report)
+ {
+ if (write(pointerFd, report, PTR_REPORT_LENGTH) != PTR_REPORT_LENGTH)
+ {
+- if (!pointerError)
++ if (errno != ESHUTDOWN && errno != EAGAIN)
+ {
+ log<level::ERR>("Failed to write pointer report",
+ entry("ERROR=%s", strerror(errno)));
+- pointerError = true;
+- }
+-
+- if (errno == ESHUTDOWN)
+- {
+- close(pointerFd);
+- pointerFd = -1;
+ }
+ }
+- else
+- {
+- pointerError = false;
+- }
+ }
+
+ } // namespace ikvm
+diff --git a/ikvm_input.hpp b/ikvm_input.hpp
+index 953333263e2d..2adc7c106755 100644
+--- a/ikvm_input.hpp
++++ b/ikvm_input.hpp
+@@ -48,8 +48,6 @@ class Input
+ */
+ static void pointerEvent(int buttonMask, int x, int y, rfbClientPtr cl);
+
+- /* @brief Re-opens USB device in case the endpoint shutdown */
+- void restart();
+ /* @brief Sends a wakeup data packet to the USB input device */
+ void sendWakeupPacket();
+ /* @brief Sends an HID report to the USB input device */
+@@ -90,8 +88,6 @@ class Input
+ bool writeKeyboard(const uint8_t *report);
+ void writePointer(const uint8_t *report);
+
+- /* @brief Indicates whether or not a pointer report error has occurred */
+- bool pointerError;
+ /* @brief Indicates whether or not to send a keyboard report */
+ bool sendKeyboard;
+ /* @brief Indicates whether or not to send a pointer report */
+diff --git a/ikvm_video.cpp b/ikvm_video.cpp
+index 6a5aa6c10927..7bd4b4eb6c98 100644
+--- a/ikvm_video.cpp
++++ b/ikvm_video.cpp
+@@ -163,10 +163,9 @@ bool Video::needsResize()
+ restart();
+ return false;
+ }
+- else if (timingsError)
++ else
+ {
+ timingsError = false;
+- input.restart();
+ }
+
+ if (timings.bt.width != width || timings.bt.height != height)
+--
+2.7.4
+
diff --git a/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/0004-Connect-HID-gadget-device-dynamically.patch b/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/0004-Connect-HID-gadget-device-dynamically.patch
new file mode 100644
index 000000000..0fe93c604
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/0004-Connect-HID-gadget-device-dynamically.patch
@@ -0,0 +1,494 @@
+From 9a0f78ab773b33fd0445b23358097ddcd175a58f Mon Sep 17 00:00:00 2001
+From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+Date: Wed, 22 Jul 2020 23:39:18 -0700
+Subject: [PATCH] Connect HID gadget device dynamically
+
+Connecting HID gadget device statically from the beginning of this
+service causes an issue on WHLK test. To prevent the issue, this
+commit changes the HID gadget device handling as dynamic so that
+the HID gadget device can be connected when this service has at
+least one KVM client.
+
+Tested: /dev/hidg0 and /dev/hidg1 created only when at least one
+KVM client is connected.
+
+Change-Id: I5f6596b9e4e297fb6b507000499fc041460659f7
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+---
+ create_usbhid.sh | 278 ++++++++++++++++++++++++--------------------
+ ikvm_input.cpp | 64 +++++++++-
+ ikvm_input.hpp | 14 +++
+ ikvm_server.cpp | 2 +
+ start-ipkvm.service | 2 +-
+ 5 files changed, 230 insertions(+), 130 deletions(-)
+
+diff --git a/create_usbhid.sh b/create_usbhid.sh
+index 656299102d7f..d1fa4e036bbe 100644
+--- a/create_usbhid.sh
++++ b/create_usbhid.sh
+@@ -1,135 +1,157 @@
+ #!/bin/sh
+
+-new_directory="/sys/kernel/config/usb_gadget/obmc_hid"
++hid_conf_directory="/sys/kernel/config/usb_gadget/obmc_hid"
++dev_name="1e6a0000.usb-vhub"
+
+-if [ -e "${new_directory}" ]; then
+- exit 0
+-fi
++create_hid() {
++ # create gadget
++ mkdir "${hid_conf_directory}"
++ cd "${hid_conf_directory}"
++
++ # add basic information
++ echo 0x0100 > bcdDevice
++ echo 0x0200 > bcdUSB
++ echo 0x0104 > idProduct # Multifunction Composite Gadget
++ echo 0x1d6b > idVendor # Linux Foundation
++
++ # create English locale
++ mkdir strings/0x409
++
++ echo "OpenBMC" > strings/0x409/manufacturer
++ echo "virtual_input" > strings/0x409/product
++ echo "OBMC0001" > strings/0x409/serialnumber
++
++ # Create HID keyboard function
++ mkdir functions/hid.0
++
++ echo 1 > functions/hid.0/protocol # 1: keyboard
++ echo 8 > functions/hid.0/report_length
++ echo 1 > functions/hid.0/subclass
++
++ # Binary HID keyboard descriptor
++ # 0x05, 0x01, // USAGE_PAGE (Generic Desktop)
++ # 0x09, 0x06, // USAGE (Keyboard)
++ # 0xa1, 0x01, // COLLECTION (Application)
++ # 0x05, 0x07, // USAGE_PAGE (Keyboard)
++ # 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl)
++ # 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI)
++ # 0x15, 0x00, // LOGICAL_MINIMUM (0)
++ # 0x25, 0x01, // LOGICAL_MAXIMUM (1)
++ # 0x75, 0x01, // REPORT_SIZE (1)
++ # 0x95, 0x08, // REPORT_COUNT (8)
++ # 0x81, 0x02, // INPUT (Data,Var,Abs)
++ # 0x95, 0x01, // REPORT_COUNT (1)
++ # 0x75, 0x08, // REPORT_SIZE (8)
++ # 0x81, 0x03, // INPUT (Data,Var,Abs)
++ # 0x95, 0x05, // REPORT_COUNT (5)
++ # 0x75, 0x01, // REPORT_SIZE (1)
++ # 0x05, 0x08, // USAGE_PAGE (LEDs)
++ # 0x19, 0x01, // USAGE_MINIMUM (Num Lock)
++ # 0x29, 0x05, // USAGE_MAXIMUM (Kana)
++ # 0x91, 0x02, // OUTPUT (Data,Var,Abs)
++ # 0x95, 0x01, // REPORT_COUNT (1)
++ # 0x75, 0x03, // REPORT_SIZE (3)
++ # 0x91, 0x03, // OUTPUT (Cnst,Var,Abs)
++ # 0x95, 0x06, // REPORT_COUNT (6)
++ # 0x75, 0x08, // REPORT_SIZE (8)
++ # 0x15, 0x00, // LOGICAL_MINIMUM (0)
++ # 0x25, 0x65, // LOGICAL_MAXIMUM (101)
++ # 0x05, 0x07, // USAGE_PAGE (Keyboard)
++ # 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated))
++ # 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application)
++ # 0x81, 0x00, // INPUT (Data,Ary,Abs)
++ # 0xc0 // END_COLLECTION
++ echo -ne '\x05\x01\x09\x06\xa1\x01\x05\x07\x19\xe0\x29\xe7\x15\x00\x25\x01\x75\x01\x95\x08\x81\x02\x95\x01\x75\x08\x81\x03\x95\x05\x75\x01\x05\x08\x19\x01\x29\x05\x91\x02\x95\x01\x75\x03\x91\x03\x95\x06\x75\x08\x15\x00\x25\x65\x05\x07\x19\x00\x29\x65\x81\x00\xc0' > functions/hid.0/report_desc
++
++ # Create HID mouse function
++ mkdir functions/hid.1
++
++ echo 2 > functions/hid.1/protocol # 2: mouse
++ echo 5 > functions/hid.1/report_length
++ echo 1 > functions/hid.1/subclass
++
++ # Binary HID mouse descriptor (absolute coordinate)
++ # 0x05, 0x01, // USAGE_PAGE (Generic Desktop)
++ # 0x09, 0x02, // USAGE (Mouse)
++ # 0xa1, 0x01, // COLLECTION (Application)
++ # 0x09, 0x01, // USAGE (Pointer)
++ # 0xa1, 0x00, // COLLECTION (Physical)
++ # 0x05, 0x09, // USAGE_PAGE (Button)
++ # 0x19, 0x01, // USAGE_MINIMUM (Button 1)
++ # 0x29, 0x03, // USAGE_MAXIMUM (Button 3)
++ # 0x15, 0x00, // LOGICAL_MINIMUM (0)
++ # 0x25, 0x01, // LOGICAL_MAXIMUM (1)
++ # 0x95, 0x03, // REPORT_COUNT (3)
++ # 0x75, 0x01, // REPORT_SIZE (1)
++ # 0x81, 0x02, // INPUT (Data,Var,Abs)
++ # 0x95, 0x01, // REPORT_COUNT (1)
++ # 0x75, 0x05, // REPORT_SIZE (5)
++ # 0x81, 0x03, // INPUT (Cnst,Var,Abs)
++ # 0x05, 0x01, // USAGE_PAGE (Generic Desktop)
++ # 0x09, 0x30, // USAGE (X)
++ # 0x09, 0x31, // USAGE (Y)
++ # 0x35, 0x00, // PHYSICAL_MINIMUM (0)
++ # 0x46, 0xff, 0x7f, // PHYSICAL_MAXIMUM (32767)
++ # 0x15, 0x00, // LOGICAL_MINIMUM (0)
++ # 0x26, 0xff, 0x7f, // LOGICAL_MAXIMUM (32767)
++ # 0x65, 0x11, // UNIT (SI Lin:Distance)
++ # 0x55, 0x00, // UNIT_EXPONENT (0)
++ # 0x75, 0x10, // REPORT_SIZE (16)
++ # 0x95, 0x02, // REPORT_COUNT (2)
++ # 0x81, 0x02, // INPUT (Data,Var,Abs)
++ # 0xc0, // END_COLLECTION
++ # 0xc0 // END_COLLECTION
++ echo -ne '\x05\x01\x09\x02\xa1\x01\x09\x01\xa1\x00\x05\x09\x19\x01\x29\x03\x15\x00\x25\x01\x95\x03\x75\x01\x81\x02\x95\x01\x75\x05\x81\x03\x05\x01\x09\x30\x09\x31\x35\x00\x46\xff\x7f\x15\x00\x26\xff\x7f\x65\x11\x55\x00\x75\x10\x95\x02\x81\x02\xc0\xc0' > functions/hid.1/report_desc
++
++ # Create configuration
++ mkdir configs/c.1
++ mkdir configs/c.1/strings/0x409
++
++ echo 0x80 > configs/c.1/bmAttributes
++ echo 200 > configs/c.1/MaxPower
++ echo "" > configs/c.1/strings/0x409/configuration
++
++ # Link HID functions to configuration
++ ln -s functions/hid.0 configs/c.1
++ ln -s functions/hid.1 configs/c.1
++}
++
++connect_hid() {
++ if ! [[ `cat UDC` =~ "${dev_name}:p" ]]; then
++ i=0
++ num_ports=5
++ base_usb_dir="/sys/bus/platform/devices/${dev_name}/${dev_name}:p"
++ while [ $i -lt $num_ports ]; do
++ port=$(($i + 1))
++ i=$port
++ if [ ! -e "${base_usb_dir}${port}/gadget/suspended" ]; then
++ break
++ fi
++ done
++ echo "${dev_name}:p${port}" > UDC
++ fi
++}
++
++disconnect_hid() {
++ if [[ `cat UDC` =~ "${dev_name}:p" ]]; then
++ echo "" > UDC
++ fi
++}
+
+-# create gadget
+ original_directory="$(pwd)"
+-mkdir "${new_directory}"
+-cd "${new_directory}"
+-
+-# add basic information
+-echo 0x0100 > bcdDevice
+-echo 0x0200 > bcdUSB
+-echo 0x0104 > idProduct # Multifunction Composite Gadget
+-echo 0x1d6b > idVendor # Linux Foundation
+-
+-# create English locale
+-mkdir strings/0x409
+-
+-echo "OpenBMC" > strings/0x409/manufacturer
+-echo "virtual_input" > strings/0x409/product
+-echo "OBMC0001" > strings/0x409/serialnumber
+-
+-# Create HID keyboard function
+-mkdir functions/hid.0
+-
+-echo 1 > functions/hid.0/protocol # 1: keyboard
+-echo 8 > functions/hid.0/report_length
+-echo 1 > functions/hid.0/subclass
+-
+-# Binary HID keyboard descriptor
+-# 0x05, 0x01, // USAGE_PAGE (Generic Desktop)
+-# 0x09, 0x06, // USAGE (Keyboard)
+-# 0xa1, 0x01, // COLLECTION (Application)
+-# 0x05, 0x07, // USAGE_PAGE (Keyboard)
+-# 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl)
+-# 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI)
+-# 0x15, 0x00, // LOGICAL_MINIMUM (0)
+-# 0x25, 0x01, // LOGICAL_MAXIMUM (1)
+-# 0x75, 0x01, // REPORT_SIZE (1)
+-# 0x95, 0x08, // REPORT_COUNT (8)
+-# 0x81, 0x02, // INPUT (Data,Var,Abs)
+-# 0x95, 0x01, // REPORT_COUNT (1)
+-# 0x75, 0x08, // REPORT_SIZE (8)
+-# 0x81, 0x03, // INPUT (Data,Var,Abs)
+-# 0x95, 0x05, // REPORT_COUNT (5)
+-# 0x75, 0x01, // REPORT_SIZE (1)
+-# 0x05, 0x08, // USAGE_PAGE (LEDs)
+-# 0x19, 0x01, // USAGE_MINIMUM (Num Lock)
+-# 0x29, 0x05, // USAGE_MAXIMUM (Kana)
+-# 0x91, 0x02, // OUTPUT (Data,Var,Abs)
+-# 0x95, 0x01, // REPORT_COUNT (1)
+-# 0x75, 0x03, // REPORT_SIZE (3)
+-# 0x91, 0x03, // OUTPUT (Cnst,Var,Abs)
+-# 0x95, 0x06, // REPORT_COUNT (6)
+-# 0x75, 0x08, // REPORT_SIZE (8)
+-# 0x15, 0x00, // LOGICAL_MINIMUM (0)
+-# 0x25, 0x65, // LOGICAL_MAXIMUM (101)
+-# 0x05, 0x07, // USAGE_PAGE (Keyboard)
+-# 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated))
+-# 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application)
+-# 0x81, 0x00, // INPUT (Data,Ary,Abs)
+-# 0xc0 // END_COLLECTION
+-echo -ne '\x05\x01\x09\x06\xa1\x01\x05\x07\x19\xe0\x29\xe7\x15\x00\x25\x01\x75\x01\x95\x08\x81\x02\x95\x01\x75\x08\x81\x03\x95\x05\x75\x01\x05\x08\x19\x01\x29\x05\x91\x02\x95\x01\x75\x03\x91\x03\x95\x06\x75\x08\x15\x00\x25\x65\x05\x07\x19\x00\x29\x65\x81\x00\xc0' > functions/hid.0/report_desc
+-
+-# Create HID mouse function
+-mkdir functions/hid.1
+-
+-echo 2 > functions/hid.1/protocol # 2: mouse
+-echo 5 > functions/hid.1/report_length
+-echo 1 > functions/hid.1/subclass
+-
+-# Binary HID mouse descriptor (absolute coordinate)
+-# 0x05, 0x01, // USAGE_PAGE (Generic Desktop)
+-# 0x09, 0x02, // USAGE (Mouse)
+-# 0xa1, 0x01, // COLLECTION (Application)
+-# 0x09, 0x01, // USAGE (Pointer)
+-# 0xa1, 0x00, // COLLECTION (Physical)
+-# 0x05, 0x09, // USAGE_PAGE (Button)
+-# 0x19, 0x01, // USAGE_MINIMUM (Button 1)
+-# 0x29, 0x03, // USAGE_MAXIMUM (Button 3)
+-# 0x15, 0x00, // LOGICAL_MINIMUM (0)
+-# 0x25, 0x01, // LOGICAL_MAXIMUM (1)
+-# 0x95, 0x03, // REPORT_COUNT (3)
+-# 0x75, 0x01, // REPORT_SIZE (1)
+-# 0x81, 0x02, // INPUT (Data,Var,Abs)
+-# 0x95, 0x01, // REPORT_COUNT (1)
+-# 0x75, 0x05, // REPORT_SIZE (5)
+-# 0x81, 0x03, // INPUT (Cnst,Var,Abs)
+-# 0x05, 0x01, // USAGE_PAGE (Generic Desktop)
+-# 0x09, 0x30, // USAGE (X)
+-# 0x09, 0x31, // USAGE (Y)
+-# 0x35, 0x00, // PHYSICAL_MINIMUM (0)
+-# 0x46, 0xff, 0x7f, // PHYSICAL_MAXIMUM (32767)
+-# 0x15, 0x00, // LOGICAL_MINIMUM (0)
+-# 0x26, 0xff, 0x7f, // LOGICAL_MAXIMUM (32767)
+-# 0x65, 0x11, // UNIT (SI Lin:Distance)
+-# 0x55, 0x00, // UNIT_EXPONENT (0)
+-# 0x75, 0x10, // REPORT_SIZE (16)
+-# 0x95, 0x02, // REPORT_COUNT (2)
+-# 0x81, 0x02, // INPUT (Data,Var,Abs)
+-# 0xc0, // END_COLLECTION
+-# 0xc0 // END_COLLECTION
+-echo -ne '\x05\x01\x09\x02\xa1\x01\x09\x01\xa1\x00\x05\x09\x19\x01\x29\x03\x15\x00\x25\x01\x95\x03\x75\x01\x81\x02\x95\x01\x75\x05\x81\x03\x05\x01\x09\x30\x09\x31\x35\x00\x46\xff\x7f\x15\x00\x26\xff\x7f\x65\x11\x55\x00\x75\x10\x95\x02\x81\x02\xc0\xc0' > functions/hid.1/report_desc
+-
+-# Create configuration
+-mkdir configs/c.1
+-mkdir configs/c.1/strings/0x409
+-
+-echo 0x80 > configs/c.1/bmAttributes
+-echo 200 > configs/c.1/MaxPower
+-echo "" > configs/c.1/strings/0x409/configuration
+-
+-# Link HID functions to configuration
+-ln -s functions/hid.0 configs/c.1
+-ln -s functions/hid.1 configs/c.1
+-
+-# Enable gadget
+-dev_name="1e6a0000.usb-vhub"
+-i=0
+-num_ports=5
+-base_usb_dir="/sys/bus/platform/devices/${dev_name}/${dev_name}:p"
+-while [ $i -lt $num_ports ]; do
+- port=$(($i + 1))
+- i=$port
+- if [ ! -e "${base_usb_dir}${port}/gadget/suspended" ]; then
+- break
+- fi
+-done
+-echo "${dev_name}:p${port}" > UDC
++
++if [ ! -e "${hid_conf_directory}" ]; then
++ create_hid
++else
++ cd "${hid_conf_directory}"
++fi
++
++if [ "$1" = "connect" ]; then
++ connect_hid
++elif [ "$1" = "disconnect" ]; then
++ disconnect_hid
++else
++ echo "Invalid option: $1. Use 'connect' or 'disconnect'."
++fi
+
+ cd "${original_directory}"
+diff --git a/ikvm_input.cpp b/ikvm_input.cpp
+index df12f2715585..c4cce5088461 100644
+--- a/ikvm_input.cpp
++++ b/ikvm_input.cpp
+@@ -16,6 +16,8 @@
+
+ #include "scancodes.hpp"
+
++namespace fs = std::filesystem;
++
+ namespace ikvm
+ {
+
+@@ -27,6 +29,54 @@ Input::Input(const std::string& kbdPath, const std::string& ptrPath) :
+ keyboardReport{0}, pointerReport{0}, keyboardPath(kbdPath),
+ pointerPath(ptrPath)
+ {
++ hidUdcStream.exceptions(std::ofstream::failbit | std::ofstream::badbit);
++ hidUdcStream.open(hidUdcPath, std::ios::out | std::ios::app);
++}
++
++Input::~Input()
++{
++ if (keyboardFd >= 0)
++ {
++ close(keyboardFd);
++ }
++
++ if (pointerFd >= 0)
++ {
++ close(pointerFd);
++ }
++
++ disconnect();
++ hidUdcStream.close();
++}
++
++void Input::connect()
++{
++ try
++ {
++ for (const auto& port : fs::directory_iterator(usbVirtualHubPath))
++ {
++ if (fs::is_directory(port) && !fs::is_symlink(port) &&
++ !fs::exists(port.path() / "gadget/suspended"))
++ {
++ const std::string portId = port.path().filename();
++ hidUdcStream << portId << std::endl;
++ break;
++ }
++ }
++ }
++ catch (fs::filesystem_error& e)
++ {
++ log<level::ERR>("Failed to search USB virtual hub port",
++ entry("ERROR=%s", e.what()));
++ return;
++ }
++ catch (std::ofstream::failure& e)
++ {
++ log<level::ERR>("Failed to connect HID gadget",
++ entry("ERROR=%s", e.what()));
++ return;
++ }
++
+ if (!keyboardPath.empty())
+ {
+ keyboardFd = open(keyboardPath.c_str(), O_RDWR | O_CLOEXEC);
+@@ -56,16 +106,28 @@ Input::Input(const std::string& kbdPath, const std::string& ptrPath) :
+ }
+ }
+
+-Input::~Input()
++void Input::disconnect()
+ {
+ if (keyboardFd >= 0)
+ {
+ close(keyboardFd);
++ keyboardFd = -1;
+ }
+
+ if (pointerFd >= 0)
+ {
+ close(pointerFd);
++ pointerFd = -1;
++ }
++
++ try
++ {
++ hidUdcStream << "" << std::endl;
++ }
++ catch (std::ofstream::failure& e)
++ {
++ log<level::ERR>("Failed to disconnect HID gadget",
++ entry("ERROR=%s", e.what()));
+ }
+ }
+
+diff --git a/ikvm_input.hpp b/ikvm_input.hpp
+index 2adc7c106755..aae7cefbef6e 100644
+--- a/ikvm_input.hpp
++++ b/ikvm_input.hpp
+@@ -2,6 +2,8 @@
+
+ #include <rfb/rfb.h>
+
++#include <filesystem>
++#include <fstream>
+ #include <map>
+ #include <string>
+
+@@ -29,6 +31,10 @@ class Input
+ Input(Input&&) = default;
+ Input& operator=(Input&&) = default;
+
++ /* @brief Connects HID gadget to host */
++ void connect();
++ /* @brief Disconnects HID gadget from host */
++ void disconnect();
+ /*
+ * @brief RFB client key event handler
+ *
+@@ -72,6 +78,12 @@ class Input
+ 0x04, // left alt
+ 0x40 // right alt
+ };
++ /* @brief Path to the HID gadget UDC */
++ static constexpr const char* hidUdcPath =
++ "/sys/kernel/config/usb_gadget/obmc_hid/UDC";
++ /* @brief Path to the USB virtual hub */
++ static constexpr const char* usbVirtualHubPath =
++ "/sys/bus/platform/devices/1e6a0000.usb-vhub";
+ /*
+ * @brief Translates a RFB-specific key code to HID modifier bit
+ *
+@@ -109,6 +121,8 @@ class Input
+ * of which keys are down
+ */
+ std::map<int, int> keysDown;
++ /* @brief Handle of the HID gadget UDC */
++ std::ofstream hidUdcStream;
+ };
+
+ } // namespace ikvm
+diff --git a/ikvm_server.cpp b/ikvm_server.cpp
+index ebeaef049d04..1c2e981b7a72 100644
+--- a/ikvm_server.cpp
++++ b/ikvm_server.cpp
+@@ -178,6 +178,7 @@ void Server::clientGone(rfbClientPtr cl)
+
+ if (server->numClients-- == 1)
+ {
++ server->input.disconnect();
+ rfbMarkRectAsModified(server->server, 0, 0, server->video.getWidth(),
+ server->video.getHeight());
+ }
+@@ -193,6 +194,7 @@ enum rfbNewClientAction Server::newClient(rfbClientPtr cl)
+ cl->clientFramebufferUpdateRequestHook = clientFramebufferUpdateRequest;
+ if (!server->numClients++)
+ {
++ server->input.connect();
+ server->pendingResize = false;
+ server->frameCounter = 0;
+ }
+diff --git a/start-ipkvm.service b/start-ipkvm.service
+index 5f945b329a26..60234b231da3 100644
+--- a/start-ipkvm.service
++++ b/start-ipkvm.service
+@@ -4,7 +4,7 @@ ConditionPathIsMountPoint=/sys/kernel/config
+
+ [Service]
+ Restart=always
+-ExecStartPre=/usr/bin/create_usbhid.sh
++ExecStartPre=/usr/bin/create_usbhid.sh disconnect
+ ExecStart=/usr/bin/obmc-ikvm -v /dev/video0 -k /dev/hidg0 -p /dev/hidg1
+
+ [Install]
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/0005-Refine-HID-report-writing-logic.patch b/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/0005-Refine-HID-report-writing-logic.patch
new file mode 100644
index 000000000..5293f3f27
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm/0005-Refine-HID-report-writing-logic.patch
@@ -0,0 +1,295 @@
+From 68885eb4d056b8343c567c48ece7e875feb28fc0 Mon Sep 17 00:00:00 2001
+From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+Date: Thu, 30 Jul 2020 00:29:19 -0700
+Subject: [PATCH] Refine HID report writing logic
+
+Blocking write on the keyboard HID device causes screen freezing
+during turning off the host power. To fix this issue, this commit
+refines the logic using non-blocking write. As a side effect,
+non-blocking write introduces event dropping when kernel HID driver
+returns -EAGAIN when the driver is in busy state so this commit also
+adds retry logic to cover the case.
+
+Tested: Didn't see the screen freezing issue.
+
+Change-Id: Ibd95f567c49f448cd053948c14c006de17c52420
+Signed-off-by: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
+---
+ ikvm_input.cpp | 106 ++++++++++++++++++++++++++++++++----------------
+ ikvm_input.hpp | 13 +++---
+ ikvm_server.cpp | 2 -
+ 3 files changed, 79 insertions(+), 42 deletions(-)
+
+diff --git a/ikvm_input.cpp b/ikvm_input.cpp
+index c4cce5088461..480db3c094bc 100644
+--- a/ikvm_input.cpp
++++ b/ikvm_input.cpp
+@@ -25,9 +25,8 @@ using namespace phosphor::logging;
+ using namespace sdbusplus::xyz::openbmc_project::Common::File::Error;
+
+ Input::Input(const std::string& kbdPath, const std::string& ptrPath) :
+- sendKeyboard(false), sendPointer(false), keyboardFd(-1), pointerFd(-1),
+- keyboardReport{0}, pointerReport{0}, keyboardPath(kbdPath),
+- pointerPath(ptrPath)
++ keyboardFd(-1), pointerFd(-1), keyboardReport{0}, pointerReport{0},
++ keyboardPath(kbdPath), pointerPath(ptrPath)
+ {
+ hidUdcStream.exceptions(std::ofstream::failbit | std::ofstream::badbit);
+ hidUdcStream.open(hidUdcPath, std::ios::out | std::ios::app);
+@@ -79,7 +78,8 @@ void Input::connect()
+
+ if (!keyboardPath.empty())
+ {
+- keyboardFd = open(keyboardPath.c_str(), O_RDWR | O_CLOEXEC);
++ keyboardFd = open(keyboardPath.c_str(),
++ O_RDWR | O_CLOEXEC | O_NONBLOCK);
+ if (keyboardFd < 0)
+ {
+ log<level::ERR>("Failed to open input device",
+@@ -135,6 +135,12 @@ void Input::keyEvent(rfbBool down, rfbKeySym key, rfbClientPtr cl)
+ {
+ Server::ClientData* cd = (Server::ClientData*)cl->clientData;
+ Input* input = cd->input;
++ bool sendKeyboard = false;
++
++ if (input->keyboardFd < 0)
++ {
++ return;
++ }
+
+ if (down)
+ {
+@@ -150,7 +156,7 @@ void Input::keyEvent(rfbBool down, rfbKeySym key, rfbClientPtr cl)
+ {
+ input->keyboardReport[i] = sc;
+ input->keysDown.insert(std::make_pair(key, i));
+- input->sendKeyboard = true;
++ sendKeyboard = true;
+ break;
+ }
+ }
+@@ -163,7 +169,7 @@ void Input::keyEvent(rfbBool down, rfbKeySym key, rfbClientPtr cl)
+ if (mod)
+ {
+ input->keyboardReport[0] |= mod;
+- input->sendKeyboard = true;
++ sendKeyboard = true;
+ }
+ }
+ }
+@@ -175,7 +181,7 @@ void Input::keyEvent(rfbBool down, rfbKeySym key, rfbClientPtr cl)
+ {
+ input->keyboardReport[it->second] = 0;
+ input->keysDown.erase(it);
+- input->sendKeyboard = true;
++ sendKeyboard = true;
+ }
+ else
+ {
+@@ -184,10 +190,15 @@ void Input::keyEvent(rfbBool down, rfbKeySym key, rfbClientPtr cl)
+ if (mod)
+ {
+ input->keyboardReport[0] &= ~mod;
+- input->sendKeyboard = true;
++ sendKeyboard = true;
+ }
+ }
+ }
++
++ if (sendKeyboard)
++ {
++ input->writeKeyboard(input->keyboardReport);
++ }
+ }
+
+ void Input::pointerEvent(int buttonMask, int x, int y, rfbClientPtr cl)
+@@ -197,6 +208,11 @@ void Input::pointerEvent(int buttonMask, int x, int y, rfbClientPtr cl)
+ Server* server = (Server*)cl->screen->screenData;
+ const Video& video = server->getVideo();
+
++ if (input->pointerFd < 0)
++ {
++ return;
++ }
++
+ input->pointerReport[0] = ((buttonMask & 0x4) >> 1) |
+ ((buttonMask & 0x2) << 1) | (buttonMask & 0x1);
+
+@@ -214,8 +230,8 @@ void Input::pointerEvent(int buttonMask, int x, int y, rfbClientPtr cl)
+ memcpy(&input->pointerReport[3], &yy, 2);
+ }
+
+- input->sendPointer = true;
+ rfbDefaultPtrAddEvent(buttonMask, x, y, cl);
++ input->writePointer(input->pointerReport);
+ }
+
+ void Input::sendWakeupPacket()
+@@ -249,23 +265,6 @@ void Input::sendWakeupPacket()
+ }
+ }
+
+-void Input::sendReport()
+-{
+- if (sendKeyboard && keyboardFd >= 0)
+- {
+- writeKeyboard(keyboardReport);
+-
+- sendKeyboard = false;
+- }
+-
+- if (sendPointer && pointerFd >= 0)
+- {
+- writePointer(pointerReport);
+-
+- sendPointer = false;
+- }
+-}
+-
+ uint8_t Input::keyToMod(rfbKeySym key)
+ {
+ uint8_t mod = 0;
+@@ -489,14 +488,35 @@ uint8_t Input::keyToScancode(rfbKeySym key)
+
+ bool Input::writeKeyboard(const uint8_t *report)
+ {
+- if (write(keyboardFd, report, KEY_REPORT_LENGTH) != KEY_REPORT_LENGTH)
++ std::unique_lock<std::mutex> lk(keyMutex);
++ uint retryCount = HID_REPORT_RETRY_MAX;
++
++ while (retryCount > 0)
+ {
+- if (errno != ESHUTDOWN && errno != EAGAIN)
++ if (write(keyboardFd, report, KEY_REPORT_LENGTH) == KEY_REPORT_LENGTH)
+ {
+- log<level::ERR>("Failed to write keyboard report",
+- entry("ERROR=%s", strerror(errno)));
++ break;
++ }
++
++ if (errno != EAGAIN)
++ {
++ if (errno != ESHUTDOWN)
++ {
++ log<level::ERR>("Failed to write keyboard report",
++ entry("ERROR=%s", strerror(errno)));
++ }
++
++ break;
+ }
+
++ lk.unlock();
++ std::this_thread::sleep_for(std::chrono::milliseconds(10));
++ lk.lock();
++ retryCount--;
++ }
++
++ if (!retryCount || errno)
++ {
+ return false;
+ }
+
+@@ -505,13 +525,31 @@ bool Input::writeKeyboard(const uint8_t *report)
+
+ void Input::writePointer(const uint8_t *report)
+ {
+- if (write(pointerFd, report, PTR_REPORT_LENGTH) != PTR_REPORT_LENGTH)
++ std::unique_lock<std::mutex> lk(ptrMutex);
++ uint retryCount = HID_REPORT_RETRY_MAX;
++
++ while (retryCount > 0)
+ {
+- if (errno != ESHUTDOWN && errno != EAGAIN)
++ if (write(pointerFd, report, PTR_REPORT_LENGTH) == PTR_REPORT_LENGTH)
+ {
+- log<level::ERR>("Failed to write pointer report",
+- entry("ERROR=%s", strerror(errno)));
++ break;
++ }
++
++ if (errno != EAGAIN)
++ {
++ if (errno != ESHUTDOWN)
++ {
++ log<level::ERR>("Failed to write pointer report",
++ entry("ERROR=%s", strerror(errno)));
++ }
++
++ break;
+ }
++
++ lk.unlock();
++ std::this_thread::sleep_for(std::chrono::milliseconds(10));
++ lk.lock();
++ retryCount--;
+ }
+ }
+
+diff --git a/ikvm_input.hpp b/ikvm_input.hpp
+index aae7cefbef6e..558251d673cc 100644
+--- a/ikvm_input.hpp
++++ b/ikvm_input.hpp
+@@ -5,6 +5,7 @@
+ #include <filesystem>
+ #include <fstream>
+ #include <map>
++#include <mutex>
+ #include <string>
+
+ namespace ikvm
+@@ -56,8 +57,6 @@ class Input
+
+ /* @brief Sends a wakeup data packet to the USB input device */
+ void sendWakeupPacket();
+- /* @brief Sends an HID report to the USB input device */
+- void sendReport();
+
+ private:
+ static constexpr int NUM_MODIFIER_BITS = 4;
+@@ -84,6 +83,8 @@ class Input
+ /* @brief Path to the USB virtual hub */
+ static constexpr const char* usbVirtualHubPath =
+ "/sys/bus/platform/devices/1e6a0000.usb-vhub";
++ /* @brief Retry limit for writing an HID report */
++ static constexpr int HID_REPORT_RETRY_MAX = 5;
+ /*
+ * @brief Translates a RFB-specific key code to HID modifier bit
+ *
+@@ -100,10 +101,6 @@ class Input
+ bool writeKeyboard(const uint8_t *report);
+ void writePointer(const uint8_t *report);
+
+- /* @brief Indicates whether or not to send a keyboard report */
+- bool sendKeyboard;
+- /* @brief Indicates whether or not to send a pointer report */
+- bool sendPointer;
+ /* @brief File descriptor for the USB keyboard device */
+ int keyboardFd;
+ /* @brief File descriptor for the USB mouse device */
+@@ -123,6 +120,10 @@ class Input
+ std::map<int, int> keysDown;
+ /* @brief Handle of the HID gadget UDC */
+ std::ofstream hidUdcStream;
++ /* @brief Mutex for sending keyboard reports */
++ std::mutex keyMutex;
++ /* @brief Mutex for sending pointer reports */
++ std::mutex ptrMutex;
+ };
+
+ } // namespace ikvm
+diff --git a/ikvm_server.cpp b/ikvm_server.cpp
+index 0736d1f55f73..7be99e4379d1 100644
+--- a/ikvm_server.cpp
++++ b/ikvm_server.cpp
+@@ -79,8 +79,6 @@ void Server::run()
+
+ if (server->clientHead)
+ {
+- input.sendReport();
+-
+ frameCounter++;
+ if (pendingResize && frameCounter > video.getFrameRate())
+ {
+--
+2.17.1
+
diff --git a/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm_%.bbappend b/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm_%.bbappend
new file mode 100644
index 000000000..9ea9e1a4e
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm/obmc-ikvm_%.bbappend
@@ -0,0 +1,10 @@
+FILESEXTRAPATHS_append := ":${THISDIR}/${PN}"
+
+#SRC_URI = "git://github.com/openbmc/obmc-ikvm"
+SRCREV = "861337e8ec92767c4c88237ec5db494a2a67fa8d"
+
+SRC_URI += " \
+ file://0003-Fix-keyboard-and-mouse-input-events-dropping-issue.patch \
+ file://0004-Connect-HID-gadget-device-dynamically.patch \
+ file://0005-Refine-HID-report-writing-logic.patch \
+ "