Add support for specifying UDC that HID gadget will connect to

Currently, HID gadget always connects to the USB virtual hub port
under /sys/bus/platform/devices/1e6a0000.usb-vhub, which only works
on ASPEED platform.

This commit adds support for specifying UDC that HID gadget will
connect to, it could be useful for non-ASPEED platform. Although there
are still some other ASPEED-specific behaviors need to be addressed,
but this commit is the first step for non-ASPEED platform.

Tested:
Specify UDC by '-u' parameter and HID gadget will connect to it. Otherwise,
HID gadget will connect to the USB virtual hub port.

Signed-off-by: Marvin Lin <milkfafa@gmail.com>
Change-Id: Ie24ed9d32cb4f7483e8d4c8b51cc5e1bb5fa94de
diff --git a/ikvm_args.cpp b/ikvm_args.cpp
index f9401ac..4887870 100644
--- a/ikvm_args.cpp
+++ b/ikvm_args.cpp
@@ -12,12 +12,16 @@
     frameRate(30), subsampling(0), calcFrameCRC{false}, commandLine(argc, argv)
 {
     int option;
-    const char* opts = "f:s:h:k:p:v:c";
-    struct option lopts[] = {
-        {"frameRate", 1, 0, 'f'}, {"subsampling", 1, 0, 's'},
-        {"help", 0, 0, 'h'},      {"keyboard", 1, 0, 'k'},
-        {"mouse", 1, 0, 'p'},     {"videoDevice", 1, 0, 'v'},
-        {"calcCRC", 0, 0, 'c'},   {0, 0, 0, 0}};
+    const char* opts = "f:s:h:k:p:u:v:c";
+    struct option lopts[] = {{"frameRate", 1, 0, 'f'},
+                             {"subsampling", 1, 0, 's'},
+                             {"help", 0, 0, 'h'},
+                             {"keyboard", 1, 0, 'k'},
+                             {"mouse", 1, 0, 'p'},
+                             {"udcName", 1, 0, 'u'},
+                             {"videoDevice", 1, 0, 'v'},
+                             {"calcCRC", 0, 0, 'c'},
+                             {0, 0, 0, 0}};
 
     while ((option = getopt_long(argc, argv, opts, lopts, NULL)) != -1)
     {
@@ -42,6 +46,9 @@
             case 'p':
                 pointerPath = std::string(optarg);
                 break;
+            case 'u':
+                udcName = std::string(optarg);
+                break;
             case 'v':
                 videoPath = std::string(optarg);
                 break;
@@ -62,6 +69,8 @@
     fprintf(stderr, "-h, --help             show this message and exit\n");
     fprintf(stderr, "-k device              HID keyboard gadget device\n");
     fprintf(stderr, "-p device              HID mouse gadget device\n");
+    fprintf(stderr,
+            "-u udc name            UDC that HID gadget will connect to\n");
     fprintf(stderr, "-v device              V4L2 device\n");
     fprintf(
         stderr,
diff --git a/ikvm_args.hpp b/ikvm_args.hpp
index 565d9c0..cb3d3ad 100644
--- a/ikvm_args.hpp
+++ b/ikvm_args.hpp
@@ -101,6 +101,16 @@
     }
 
     /*
+     * @brief Get the name of UDC
+     *
+     * @return Reference to the string storing the name of UDC
+     */
+    inline const std::string& getUdcName() const
+    {
+        return udcName;
+    }
+
+    /*
      * @brief Get the path to the V4L2 video device
      *
      * @return Reference to the string storing the path to the video device
@@ -135,6 +145,8 @@
     std::string keyboardPath;
     /* @brief Path to the USB mouse device */
     std::string pointerPath;
+    /* @brief Name of UDC */
+    std::string udcName;
     /* @brief Path to the V4L2 video device */
     std::string videoPath;
     /* @brief Identical frames detection */
diff --git a/ikvm_input.cpp b/ikvm_input.cpp
index e9bd151..107756b 100644
--- a/ikvm_input.cpp
+++ b/ikvm_input.cpp
@@ -23,9 +23,11 @@
 using namespace phosphor::logging;
 using namespace sdbusplus::xyz::openbmc_project::Common::File::Error;
 
-Input::Input(const std::string& kbdPath, const std::string& ptrPath) :
-    keyboardFd(-1), pointerFd(-1), keyboardReport{0}, pointerReport{0},
-    keyboardPath(kbdPath), pointerPath(ptrPath)
+Input::Input(const std::string& kbdPath, const std::string& ptrPath,
+             const std::string& udc) :
+    keyboardFd(-1),
+    pointerFd(-1), keyboardReport{0}, pointerReport{0}, keyboardPath(kbdPath),
+    pointerPath(ptrPath), udcName(udc)
 {
     hidUdcStream.exceptions(std::ofstream::failbit | std::ofstream::badbit);
     hidUdcStream.open(hidUdcPath, std::ios::out | std::ios::app);
@@ -51,16 +53,23 @@
 {
     try
     {
-        for (const auto& port : fs::directory_iterator(usbVirtualHubPath))
+        if (udcName.empty())
         {
-            if (fs::is_directory(port) && !fs::is_symlink(port) &&
-                !fs::exists(port.path() / "gadget/suspended"))
+            for (const auto& port : fs::directory_iterator(usbVirtualHubPath))
             {
-                const std::string portId = port.path().filename();
-                hidUdcStream << portId << std::endl;
-                break;
+                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;
+                }
             }
         }
+        else // If UDC has been specified by '-u' parameter, connect to it.
+        {
+            hidUdcStream << udcName << std::endl;
+        }
     }
     catch (fs::filesystem_error& e)
     {
diff --git a/ikvm_input.hpp b/ikvm_input.hpp
index 295fb12..83e4071 100644
--- a/ikvm_input.hpp
+++ b/ikvm_input.hpp
@@ -24,8 +24,10 @@
      *
      * @param[in] kbdPath - Path to the USB keyboard device
      * @param[in] ptrPath - Path to the USB mouse device
+     * @param[in] udc - Name of UDC
      */
-    Input(const std::string& kbdPath, const std::string& ptrPath);
+    Input(const std::string& kbdPath, const std::string& ptrPath,
+          const std::string& udc);
     ~Input();
     Input(const Input&) = default;
     Input& operator=(const Input&) = default;
@@ -113,6 +115,8 @@
     std::string keyboardPath;
     /* @brief Path to the USB mouse device */
     std::string pointerPath;
+    /* @brief Name of UDC */
+    std::string udcName;
     /*
      * @brief Mapping of RFB key code to report data index to keep track
      *        of which keys are down
diff --git a/ikvm_manager.cpp b/ikvm_manager.cpp
index 11afcb7..93fd1ce 100644
--- a/ikvm_manager.cpp
+++ b/ikvm_manager.cpp
@@ -7,7 +7,7 @@
 
 Manager::Manager(const Args& args) :
     continueExecuting(true), serverDone(false), videoDone(true),
-    input(args.getKeyboardPath(), args.getPointerPath()),
+    input(args.getKeyboardPath(), args.getPointerPath(), args.getUdcName()),
     video(args.getVideoPath(), input, args.getFrameRate(),
           args.getSubsampling()),
     server(args, input, video)