diff options
Diffstat (limited to 'meta-openbmc-mods/meta-common/recipes-graphics/obmc-ikvm')
4 files changed, 961 insertions, 0 deletions
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 \ + " |