VirtualBox

Ignore:
Timestamp:
Apr 8, 2016 11:07:37 AM (9 years ago)
Author:
vboxsync
Message:

ValidationKit/usb/UsbTestServices: Updates, use configfs to create a USB test device (works only on Linux), untested

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/ValidationKit/utils/usb/UsbTestServiceGadgetClassTest.cpp

    r60376 r60394  
    3131#include <iprt/process.h>
    3232#include <iprt/string.h>
     33#include <iprt/symlink.h>
    3334#include <iprt/types.h>
    3435
     
    4647#define UTS_GADGET_TEMPLATE_NAME "gadget_test"
    4748
     49/** Default vendor ID which is recognized by the usbtest driver. */
    4850#define UTS_GADGET_TEST_VENDOR_ID_DEF    UINT16_C(0x0525)
     51/** Default product ID which is recognized by the usbtest driver. */
    4952#define UTS_GADGET_TEST_PRODUCT_ID_DEF   UINT16_C(0xa4a0)
     53/** Default device class. */
    5054#define UTS_GADGET_TEST_DEVICE_CLASS_DEF UINT8_C(0xff)
    51 
     55/** Default serial number string. */
     56#define UTS_GADGET_TEST_SERIALNUMBER_DEF "0123456789"
     57/** Default manufacturer string. */
     58#define UTS_GADGET_TEST_MANUFACTURER_DEF "Oracle Inc."
     59/** Default product string. */
     60#define UTS_GADGET_TEST_PRODUCT_DEF      "USB test device"
    5261
    5362/**
     
    6877
    6978/*********************************************************************************************************************************
     79*   Global Variables                                                                                                             *
     80*********************************************************************************************************************************/
     81
     82/** Number of already created gadgets, used for the template name. */
     83static volatile uint32_t g_cGadgets = 0;
     84
     85
     86/*********************************************************************************************************************************
    7087*   Internal Functions                                                                                                           *
    7188*********************************************************************************************************************************/
    7289
     90/**
     91 * Creates a new directory pointed to by the given format string.
     92 *
     93 * @returns IPRT status code.
     94 * @param   pszFormat         The format string.
     95 * @param   va                The arguments.
     96 */
     97static int utsGadgetClassTestDirCreateV(const char *pszFormat, va_list va)
     98{
     99    int rc = VINF_SUCCESS;
     100    char aszPath[RTPATH_MAX + 1];
     101
     102    size_t cbStr = RTStrPrintfV(&aszPath[0], sizeof(aszPath), pszFormat, va);
     103    if (cbStr <= sizeof(aszPath) - 1)
     104        rc = RTDirCreateFullPath(aszPath, 0700);
     105    else
     106        rc = VERR_BUFFER_OVERFLOW;
     107
     108    return rc;
     109}
     110
     111
     112/**
     113 * Creates a new directory pointed to by the given format string.
     114 *
     115 * @returns IPRT status code.
     116 * @param   pszFormat         The format string.
     117 * @param   ...               The arguments.
     118 */
     119static int utsGadgetClassTestDirCreate(const char *pszFormat, ...)
     120{
     121    va_list va;
     122    va_start(va, pszFormat);
     123    int rc = utsGadgetClassTestDirCreateV(pszFormat, va);
     124    va_end(va);
     125    return rc;
     126}
     127
     128
     129/**
     130 * Removes a directory pointed to by the given format string.
     131 *
     132 * @returns IPRT status code.
     133 * @param   pszFormat         The format string.
     134 * @param   va                The arguments.
     135 */
     136static int utsGadgetClassTestDirRemoveV(const char *pszFormat, va_list va)
     137{
     138    int rc = VINF_SUCCESS;
     139    char aszPath[RTPATH_MAX + 1];
     140
     141    size_t cbStr = RTStrPrintfV(&aszPath[0], sizeof(aszPath), pszFormat, va);
     142    if (cbStr <= sizeof(aszPath) - 1)
     143        rc = RTDirRemove(aszPath);
     144    else
     145        rc = VERR_BUFFER_OVERFLOW;
     146
     147    return rc;
     148}
     149
     150
     151/**
     152 * Removes a directory pointed to by the given format string.
     153 *
     154 * @returns IPRT status code.
     155 * @param   pszFormat         The format string.
     156 * @param   ...               The arguments.
     157 */
     158static int utsGadgetClassTestDirRemove(const char *pszFormat, ...)
     159{
     160    va_list va;
     161    va_start(va, pszFormat);
     162    int rc = utsGadgetClassTestDirRemoveV(pszFormat, va);
     163    va_end(va);
     164    return rc;
     165}
     166
     167
     168/**
     169 * Links the given function to the given config.
     170 *
     171 * @returns IPRT status code.
     172 * @param   pClass            The gadget class instance data.
     173 * @param   pszFunc           The function to link.
     174 * @param   pszCfg            The configuration which the function will be part of.
     175 */
     176static int utsGadgetClassTestLinkFuncToCfg(PUTSGADGETCLASSINT pClass, const char *pszFunc, const char *pszCfg)
     177{
     178    int rc = VINF_SUCCESS;
     179    char aszPathFunc[RTPATH_MAX + 1];
     180    char aszPathCfg[RTPATH_MAX + 1];
     181
     182    size_t cbStr = RTStrPrintf(&aszPathFunc[0], sizeof(aszPathFunc), "%s/functions/%s",
     183                               pClass->pszGadgetPath, pszFunc);
     184    if (cbStr <= sizeof(aszPathFunc) - 1)
     185    {
     186        cbStr = RTStrPrintf(&aszPathCfg[0], sizeof(aszPathCfg), "%s/configs/%s",
     187                            pClass->pszGadgetPath, pszCfg);
     188        if (cbStr <= sizeof(aszPathCfg) - 1)
     189            rc = RTSymlinkCreate(&aszPathCfg[0], &aszPathFunc[0], RTSYMLINKTYPE_DIR, 0);
     190        else
     191            rc = VERR_BUFFER_OVERFLOW;
     192    }
     193    else
     194        rc = VERR_BUFFER_OVERFLOW;
     195
     196    return rc;
     197}
     198
     199
     200/**
     201 * Unlinks the given function from the given configuration.
     202 *
     203 * @returns IPRT status code.
     204 * @param   pClass            The gadget class instance data.
     205 * @param   pszFunc           The function to unlink.
     206 * @param   pszCfg            The configuration which the function is currently part of.
     207 */
     208static int utsGadgetClassTestUnlinkFuncFromCfg(PUTSGADGETCLASSINT pClass, const char *pszFunc, const char *pszCfg)
     209{
     210    int rc = VINF_SUCCESS;
     211    char aszPath[RTPATH_MAX + 1];
     212    size_t cbStr = RTStrPrintf(&aszPath[0], sizeof(aszPath), "%s/configs/%s/%s",
     213                               pClass->pszGadgetPath, pszCfg, pszFunc);
     214    if (cbStr <= sizeof(aszPath) - 1)
     215        rc = RTSymlinkDelete(&aszPath[0], 0);
     216    else
     217        rc = VERR_BUFFER_OVERFLOW;
     218
     219    return rc;
     220}
     221
     222
     223/**
     224 * Cleans up any leftover configurations from the gadget class.
     225 *
     226 * @returns nothing.
     227 * @param   pClass            The gadget class instance data.
     228 */
     229static void utsGadgetClassTestCleanup(PUTSGADGETCLASSINT pClass)
     230{
     231    /* Unbind the gadget from the currently assigned UDC first. */
     232    int rc = RTLinuxSysFsWriteStrFile("", 0, NULL, "%s/UDC", pClass->pszGadgetPath);
     233    AssertRC(rc);
     234
     235    /* Delete the symlinks, ignore any errors. */
     236    utsGadgetClassTestUnlinkFuncFromCfg(pClass, "Loopback.0", "c.2");
     237    utsGadgetClassTestUnlinkFuncFromCfg(pClass, "SourceSink.0", "c.1");
     238
     239    /* Delete configuration strings and then the configuration directories. */
     240    utsGadgetClassTestDirRemove("%s/configs/c.2/strings/0x409", pClass->pszGadgetPath);
     241    utsGadgetClassTestDirRemove("%s/configs/c.1/strings/0x409", pClass->pszGadgetPath);
     242
     243    utsGadgetClassTestDirRemove("%s/configs/c.2", pClass->pszGadgetPath);
     244    utsGadgetClassTestDirRemove("%s/configs/c.1", pClass->pszGadgetPath);
     245
     246    /* Delete the functions. */
     247    utsGadgetClassTestDirRemove("%s/functions/Loopback.0", pClass->pszGadgetPath);
     248    utsGadgetClassTestDirRemove("%s/functions/SourceSink.0", pClass->pszGadgetPath);
     249
     250    /* Delete the english strings. */
     251    utsGadgetClassTestDirRemove("%s/strings/0x409", pClass->pszGadgetPath);
     252
     253    /* Finally delete the gadget template. */
     254    utsGadgetClassTestDirRemove(pClass->pszGadgetPath);
     255}
    73256
    74257/**
     
    82265    {
    83266        /* Create the gadget template */
    84         unsigned idx = 0;
    85         char aszPath[RTPATH_MAX];
    86 
    87         do
    88         {
    89             RTStrPrintf(&aszPath[0], RT_ELEMENTS(aszPath), "%s/%s%u",
    90                         UTS_GADGET_CLASS_CONFIGFS_MNT_DEF, UTS_GADGET_TEMPLATE_NAME,
    91                         idx);
    92             rc = RTDirCreateFullPath(aszPath, 0700);
    93             if (RT_SUCCESS(rc))
    94                 break;
    95             idx++;
    96         } while (idx < 100);
    97 
     267        unsigned idx = ASMAtomicIncU32(&g_cGadgets);
     268
     269        int rcStr = RTStrAPrintf(&pClass->pszGadgetPath, "%s/%s%u", UTS_GADGET_CLASS_CONFIGFS_MNT_DEF,
     270                                 UTS_GADGET_TEMPLATE_NAME, idx);
     271        if (rcStr == -1)
     272            return VERR_NO_STR_MEMORY;
     273
     274        rc = utsGadgetClassTestDirCreate(pClass->pszGadgetPath);
    98275        if (RT_SUCCESS(rc))
    99276        {
    100             pClass->pszGadgetPath = RTStrDup(aszPath);
    101 
    102277            uint16_t idVendor = 0;
    103278            uint16_t idProduct = 0;
    104279            uint8_t  bDeviceClass = 0;
    105             rc = utsGadgetCfgQueryU16Def(paCfg, "Gadget/idVendor", &idVendor, UTS_GADGET_TEST_VENDOR_ID_DEF);
    106             if (RT_SUCCESS(rc))
    107                 rc = utsGadgetCfgQueryU16Def(paCfg, "Gadget/idProduct", &idProduct, UTS_GADGET_TEST_PRODUCT_ID_DEF);
    108             if (RT_SUCCESS(rc))
    109                 rc = utsGadgetCfgQueryU8Def(paCfg, "Gadget/bDeviceClass", &bDeviceClass, UTS_GADGET_TEST_DEVICE_CLASS_DEF);
     280            char *pszSerial = NULL;
     281            char *pszManufacturer = NULL;
     282            char *pszProduct = NULL;
     283
     284            /* Get basic device config. */
     285            rc = utsGadgetCfgQueryU16Def(paCfg,        "Gadget/idVendor",     &idVendor,        UTS_GADGET_TEST_VENDOR_ID_DEF);
     286            if (RT_SUCCESS(rc))
     287                rc = utsGadgetCfgQueryU16Def(paCfg,    "Gadget/idProduct",    &idProduct,       UTS_GADGET_TEST_PRODUCT_ID_DEF);
     288            if (RT_SUCCESS(rc))
     289                rc = utsGadgetCfgQueryU8Def(paCfg,     "Gadget/bDeviceClass", &bDeviceClass,    UTS_GADGET_TEST_DEVICE_CLASS_DEF);
     290            if (RT_SUCCESS(rc))
     291                rc = utsGadgetCfgQueryStringDef(paCfg, "Gadget/SerialNumber", &pszSerial,       UTS_GADGET_TEST_SERIALNUMBER_DEF);
     292            if (RT_SUCCESS(rc))
     293                rc = utsGadgetCfgQueryStringDef(paCfg, "Gadget/Manufacturer", &pszManufacturer, UTS_GADGET_TEST_MANUFACTURER_DEF);
     294            if (RT_SUCCESS(rc))
     295                rc = utsGadgetCfgQueryStringDef(paCfg, "Gadget/Product",      &pszProduct,      UTS_GADGET_TEST_PRODUCT_DEF);
     296
     297            if (RT_SUCCESS(rc))
     298            {
     299                /* Write basic attributes. */
     300                rc = RTLinuxSysFsWriteU16File(16, idVendor, "%s/idVendor", pClass->pszGadgetPath);
     301                if (RT_SUCCESS(rc))
     302                    rc = RTLinuxSysFsWriteU16File(16, idProduct, "%s/idProduct", pClass->pszGadgetPath);
     303                if (RT_SUCCESS(rc))
     304                    rc = RTLinuxSysFsWriteU16File(16, bDeviceClass, "%s/bDeviceClass", pClass->pszGadgetPath);
     305
     306                /* Create english language strings. */
     307                if (RT_SUCCESS(rc))
     308                    rc = utsGadgetClassTestDirCreate("%s/strings/0x409", pClass->pszGadgetPath);
     309                if (RT_SUCCESS(rc))
     310                    rc = RTLinuxSysFsWriteStrFile(pszSerial, 0, NULL, "%s/strings/0x409/serialnumber", pClass->pszGadgetPath);
     311                if (RT_SUCCESS(rc))
     312                    rc = RTLinuxSysFsWriteStrFile(pszManufacturer, 0, NULL, "%s/strings/0x409/manufacturer", pClass->pszGadgetPath);
     313                if (RT_SUCCESS(rc))
     314                    rc = RTLinuxSysFsWriteStrFile(pszProduct, 0, NULL, "%s/strings/0x409/product", pClass->pszGadgetPath);
     315
     316                /* Create the gadget functions. */
     317                if (RT_SUCCESS(rc))
     318                    rc = utsGadgetClassTestDirCreate("%s/functions/SourceSink.0", pClass->pszGadgetPath);
     319                if (RT_SUCCESS(rc))
     320                    rc = utsGadgetClassTestDirCreate("%s/functions/Loopback.0", pClass->pszGadgetPath);
     321
     322                /* Create the device configs. */
     323                if (RT_SUCCESS(rc))
     324                    rc = utsGadgetClassTestDirCreate("%s/configs/c.1", pClass->pszGadgetPath);
     325                if (RT_SUCCESS(rc))
     326                    rc = utsGadgetClassTestDirCreate("%s/configs/c.2", pClass->pszGadgetPath);
     327
     328                /* Write configuration strings. */
     329                if (RT_SUCCESS(rc))
     330                    rc = utsGadgetClassTestDirCreate("%s/configs/c.1/strings/0x409", pClass->pszGadgetPath);
     331                if (RT_SUCCESS(rc))
     332                    rc = utsGadgetClassTestDirCreate("%s/configs/c.2/strings/0x409", pClass->pszGadgetPath);
     333                if (RT_SUCCESS(rc))
     334                    rc = RTLinuxSysFsWriteStrFile("source and sink data", 0, NULL, "%s/configs/c.1/strings/0x409/configuration", pClass->pszGadgetPath);
     335                if (RT_SUCCESS(rc))
     336                    rc = RTLinuxSysFsWriteStrFile("loop input to output", 0, NULL, "%s/configs/c.2/strings/0x409/configuration", pClass->pszGadgetPath);
     337
     338                /* Link the functions into the configurations. */
     339                if (RT_SUCCESS(rc))
     340                    rc = utsGadgetClassTestLinkFuncToCfg(pClass, "SourceSink.0", "c.1");
     341                if (RT_SUCCESS(rc))
     342                    rc = utsGadgetClassTestLinkFuncToCfg(pClass, "Loopback.0", "c.2");
     343
     344                /* Finally enable the gadget by attaching it to a UDC. */
     345                /** @todo: Figure out a free UDC dynamically. */
     346                if (RT_SUCCESS(rc))
     347                    rc = RTLinuxSysFsWriteStrFile("dummy_udc.0", 0, NULL, "%s/UDC", pClass->pszGadgetPath);
     348            }
     349
     350            if (pszSerial)
     351                RTStrFree(pszSerial);
     352            if (pszManufacturer)
     353                RTStrFree(pszManufacturer);
     354            if (pszProduct)
     355                RTStrFree(pszProduct);
    110356        }
    111357    }
     
    113359        rc = VERR_NOT_FOUND;
    114360
     361    if (RT_FAILURE(rc))
     362        utsGadgetClassTestCleanup(pClass);
     363
    115364    return rc;
    116365}
     
    122371static DECLCALLBACK(void) utsGadgetClassTestTerm(PUTSGADGETCLASSINT pClass)
    123372{
    124 
     373    utsGadgetClassTestCleanup(pClass);
     374
     375    if (pClass->pszGadgetPath)
     376        RTStrFree(pClass->pszGadgetPath);
    125377}
    126378
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette