14e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park/** @addtogroup MCD_IMPL_LIB
24e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park * @{
34e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park * @file
44e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park *
54e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park * Client library device management.
64e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park *
74e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park * Device and Trustlet Session management Funtions.
84e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park *
94e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park * <!-- Copyright Giesecke & Devrient GmbH 2009 - 2012 -->
109081ca65cb7959b6a06ba44823f84a6afa8bca2fJihyun Kim *
114e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park * Redistribution and use in source and binary forms, with or without
124e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park * modification, are permitted provided that the following conditions
134e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park * are met:
144e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park * 1. Redistributions of source code must retain the above copyright
154e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park *    notice, this list of conditions and the following disclaimer.
164e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park * 2. Redistributions in binary form must reproduce the above copyright
174e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park *    notice, this list of conditions and the following disclaimer in the
184e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park *    documentation and/or other materials provided with the distribution.
194e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park * 3. The name of the author may not be used to endorse or promote
204e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park *    products derived from this software without specific prior
214e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park *    written permission.
224e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park *
234e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
244e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
254e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
264e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
274e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
284e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
294e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
304e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
314e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
324e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
334e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
344e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park */
354e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park#include <stdint.h>
364e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park#include <vector>
374e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park
389081ca65cb7959b6a06ba44823f84a6afa8bca2fJihyun Kim#include "mc_linux.h"
394e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park#include "Device.h"
404e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park
414e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park#include "log.h"
427b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim#include <assert.h>
434e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park
444e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park
454e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park//------------------------------------------------------------------------------
469081ca65cb7959b6a06ba44823f84a6afa8bca2fJihyun KimDevice::Device(uint32_t deviceId, Connection *connection)
479081ca65cb7959b6a06ba44823f84a6afa8bca2fJihyun Kim{
487b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    this->deviceId = deviceId;
497b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    this->connection = connection;
504e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park
517b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    pMcKMod = new CMcKMod();
524e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park}
534e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park
544e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park
554e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park//------------------------------------------------------------------------------
569081ca65cb7959b6a06ba44823f84a6afa8bca2fJihyun KimDevice::~Device(void)
579081ca65cb7959b6a06ba44823f84a6afa8bca2fJihyun Kim{
587b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    /* Delete all session objects. Usually this should not be needed as closeDevice()
597b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim     * requires that all sessions have been closed before.
607b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim     */
617b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    sessionIterator_t  sessionIterator = sessionList.begin();
627b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    while (sessionIterator != sessionList.end()) {
637b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        delete (*sessionIterator);
647b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        sessionIterator = sessionList.erase(sessionIterator);
657b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    }
667b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim
677b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    // Free all allocated WSM descriptors
687b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    wsmIterator_t  wsmIterator = wsmL2List.begin();
697b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    while (wsmIterator != wsmL2List.end()) {
707b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        CWsm_ptr pWsm = *wsmIterator;
717b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim
727b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        // ignore return code
737b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        pMcKMod->free(pWsm->handle, pWsm->virtAddr, pWsm->len);
747b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim
757b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        delete (*wsmIterator);
767b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        wsmIterator = wsmL2List.erase(wsmIterator);
777b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    }
787b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    delete connection;
797b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    delete pMcKMod;
804e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park}
814e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park
824e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park
834e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park//------------------------------------------------------------------------------
847b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kimbool Device::open(const char *deviceName)
859081ca65cb7959b6a06ba44823f84a6afa8bca2fJihyun Kim{
867b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    return pMcKMod->open(deviceName);
874e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park}
884e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park
894e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park
904e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park//------------------------------------------------------------------------------
919081ca65cb7959b6a06ba44823f84a6afa8bca2fJihyun Kimvoid Device::close(void)
929081ca65cb7959b6a06ba44823f84a6afa8bca2fJihyun Kim{
937b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    pMcKMod->close();
944e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park}
954e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park
964e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park
974e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park//------------------------------------------------------------------------------
989081ca65cb7959b6a06ba44823f84a6afa8bca2fJihyun Kimbool Device::hasSessions(void)
999081ca65cb7959b6a06ba44823f84a6afa8bca2fJihyun Kim{
1007b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    return sessionList.size() > 0;
1014e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park}
1024e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park
1034e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park
1044e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park//------------------------------------------------------------------------------
1059081ca65cb7959b6a06ba44823f84a6afa8bca2fJihyun Kimvoid Device::createNewSession(uint32_t sessionId, Connection  *connection)
1069081ca65cb7959b6a06ba44823f84a6afa8bca2fJihyun Kim{
1077b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    Session *session = new Session(sessionId, pMcKMod, connection);
1087b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    sessionList.push_back(session);
1094e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park}
1104e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park
1114e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park
1124e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park//------------------------------------------------------------------------------
1139081ca65cb7959b6a06ba44823f84a6afa8bca2fJihyun Kimbool Device::removeSession(uint32_t sessionId)
1149081ca65cb7959b6a06ba44823f84a6afa8bca2fJihyun Kim{
1157b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    bool ret = false;
1167b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim
1177b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    sessionIterator_t interator = sessionList.begin();
1187b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    while (interator != sessionList.end()) {
1197b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        if ((*interator)->sessionId == sessionId) {
1207b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim            delete (*interator);
1217b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim            interator = sessionList.erase(interator);
1227b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim            ret = true;
1237b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim            break;
1247b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        } else {
1257b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim            interator++;
1267b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        }
1277b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    }
1287b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    return ret;
1294e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park}
1304e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park
1314e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park
1324e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park//------------------------------------------------------------------------------
1339081ca65cb7959b6a06ba44823f84a6afa8bca2fJihyun KimSession *Device::resolveSessionId(uint32_t sessionId)
1349081ca65cb7959b6a06ba44823f84a6afa8bca2fJihyun Kim{
1357b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    Session  *ret = NULL;
1367b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim
1377b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    // Get Session for sessionId
1387b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    for ( sessionIterator_t interator = sessionList.begin();
1397b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim            interator != sessionList.end();
1407b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim            ++interator) {
1417b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        if ((*interator)->sessionId == sessionId) {
1427b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim            ret = (*interator);
1437b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim            break;
1447b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        }
1457b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    }
1467b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    return ret;
1474e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park}
1484e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park
1494e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park
1504e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park//------------------------------------------------------------------------------
1517b143edf281bed18c8ebd0733465f3af5af327ebJungtae KimmcResult_t Device::allocateContiguousWsm(uint32_t len, CWsm **wsm)
1529081ca65cb7959b6a06ba44823f84a6afa8bca2fJihyun Kim{
1537b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    // Allocate shared memory
1547b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    addr_t    virtAddr;
1557b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    uint32_t  handle;
1567b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    addr_t    physAddr;
1577b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    mcResult_t  ret;
1589081ca65cb7959b6a06ba44823f84a6afa8bca2fJihyun Kim
1597b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    assert(wsm != NULL);
1604e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park
1617b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    if (!len) {
1627b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        return MC_DRV_ERR_INVALID_LENGTH;
1637b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    }
1644e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park
1657b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    ret = pMcKMod->mapWsm(len, &handle, &virtAddr, &physAddr);
1667b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    if (ret) {
1677b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        return ret;
1687b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    }
1699081ca65cb7959b6a06ba44823f84a6afa8bca2fJihyun Kim
1707b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    LOG_I(" mapped handle %d to %p, phys=%p ", handle, virtAddr, physAddr);
1719081ca65cb7959b6a06ba44823f84a6afa8bca2fJihyun Kim
1727b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    // Register (vaddr,paddr) with device
1737b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    *wsm = new CWsm(virtAddr, len, handle, physAddr);
1744e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park
1757b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    wsmL2List.push_back(*wsm);
1767b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim
1777b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    // Return pointer to the allocated memory
1787b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    return MC_DRV_OK;
1794e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park}
1804e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park
1814e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park
1824e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park//------------------------------------------------------------------------------
1837b143edf281bed18c8ebd0733465f3af5af327ebJungtae KimmcResult_t Device::freeContiguousWsm(CWsm_ptr  pWsm)
1849081ca65cb7959b6a06ba44823f84a6afa8bca2fJihyun Kim{
1857b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    mcResult_t ret = MC_DRV_ERR_WSM_NOT_FOUND;
1867b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    wsmIterator_t iterator;
1877b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim
1887b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    for (iterator = wsmL2List.begin(); iterator != wsmL2List.end(); ++iterator) {
1897b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        if (pWsm == *iterator) {
1907b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim            ret = MC_DRV_OK;
1917b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim            break;
1927b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        }
1937b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    }
1947b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    // We just looked this up using findContiguousWsm
1957b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    assert(ret == MC_DRV_OK);
1967b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim
1977b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    LOG_I(" unmapping handle %d from %p, phys=%p",
1987b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim          pWsm->handle, pWsm->virtAddr, pWsm->physAddr);
1997b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim
2007b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    ret = pMcKMod->free(pWsm->handle, pWsm->virtAddr, pWsm->len);
2017b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    if (ret != MC_DRV_OK) {
2027b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        // developer forgot to free all references of this memory, we do not remove the reference here
2037b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        return ret;
2047b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    }
2057b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim
2067b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    iterator = wsmL2List.erase(iterator);
2077b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    delete pWsm;
2087b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim
2097b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    return ret;
2104e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park}
2114e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park
2124e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park
2134e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park//------------------------------------------------------------------------------
2149081ca65cb7959b6a06ba44823f84a6afa8bca2fJihyun KimCWsm_ptr Device::findContiguousWsm(addr_t  virtAddr)
2159081ca65cb7959b6a06ba44823f84a6afa8bca2fJihyun Kim{
2167b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    CWsm_ptr pWsm = NULL;
2177b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim
2187b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    for ( wsmIterator_t iterator = wsmL2List.begin();
2197b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim            iterator != wsmL2List.end();
2207b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim            ++iterator) {
2217b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        CWsm_ptr pTmpWsm = *iterator;
2227b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        if (virtAddr == pTmpWsm->virtAddr) {
2237b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim            pWsm = pTmpWsm;
2247b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim            break;
2257b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim        }
2267b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    }
2277b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim
2287b143edf281bed18c8ebd0733465f3af5af327ebJungtae Kim    return pWsm;
2294e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park}
2304e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park
2314e9e8c9c0169b40318386436d762c3d73cf4c328DongJin Park/** @} */
232