/* $Id: UsbCardReader.cpp $ */

/** @file
 * UsbCardReader - Driver Interface to USB Smart Card Reader emulation.
 */

/*
 * Copyright (C) 2011-2012 Oracle Corporation
 *
 * This file is part of VirtualBox Open Source Edition (OSE), as
 * available from http://www.virtualbox.org. This file is free software;
 * you can redistribute it and/or modify it under the terms of the GNU
 * General Public License (GPL) as published by the Free Software
 * Foundation, in version 2 as it comes in the "COPYING" file of the
 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
 */


/*******************************************************************************
*   Header Files                                                               *
*******************************************************************************/
#define LOG_GROUP LOG_GROUP_USB_CARDREADER
#include "UsbCardReader.h"
#include "ConsoleImpl.h"
#include "ConsoleVRDPServer.h"

#include <VBox/vmm/pdm.h>
#include <VBox/vmm/pdmcardreaderinfs.h>

#include <iprt/req.h>

#define NIL_RTREQQUEUE ((RTREQQUEUE *)0)
#define RTReqQueueCallEx RTReqCallEx
#define RTReqQueueProcess RTReqProcess
#define RTReqQueueCall RTReqCall
#define RTReqQueueCreate RTReqCreateQueue
#define RTReqQueueDestroy RTReqDestroyQueue
#define RTReqRelease RTReqFree


/*******************************************************************************
*   Structures and Typedefs                                                    *
*******************************************************************************/
typedef struct USBCARDREADER USBCARDREADER;
typedef struct USBCARDREADER *PUSBCARDREADER;

struct USBCARDREADER
{
    UsbCardReader *pUsbCardReader;

    PPDMDRVINS pDrvIns;

    PDMICARDREADERDOWN ICardReaderDown;
    PPDMICARDREADERUP  pICardReaderUp;

    /* Thread handling Cmd to card reader */
    PPDMTHREAD          pThrCardReaderCmd;
    /* Queue handling requests to cardreader */
    RTREQQUEUE          *hReqQCardReaderCmd;
};


/*
 * Command queue's callbacks.
 */

static DECLCALLBACK(void) drvCardReaderCmdStatusChange(PUSBCARDREADER pThis,
                                                       void *pvUser,
                                                       uint32_t u32Timeout,
                                                       PDMICARDREADER_READERSTATE *paReaderStats,
                                                       uint32_t cReaderStats)
{
    LogFlowFunc(("ENTER: pvUser:%p, u32Timeout:%d\n",
                 pvUser, u32Timeout));

    UsbCardReader *pUsbCardReader = pThis->pUsbCardReader;
    if (!pUsbCardReader)
    {
        pThis->pICardReaderUp->pfnCardReaderUpSetStatusChange(pThis->pICardReaderUp,
                                                              pvUser, VRDE_SCARD_E_NO_SMARTCARD,
                                                              paReaderStats, cReaderStats);
    }
    else
    {
        pUsbCardReader->GetStatusChange(pThis, pvUser, u32Timeout,
                                        paReaderStats, cReaderStats);
    }

    LogFlowFuncLeave();
}


static DECLCALLBACK(void) drvCardReaderCmdEstablishContext(PUSBCARDREADER pThis)
{
    LogFlowFunc(("\n"));

    UsbCardReader *pUsbCardReader = pThis->pUsbCardReader;
    if (!pUsbCardReader)
    {
        pThis->pICardReaderUp->pfnCardReaderUpEstablishContext(pThis->pICardReaderUp,
                                                               VRDE_SCARD_E_NO_SMARTCARD);
    }
    else
    {
        pUsbCardReader->EstablishContext(pThis);
    }

    LogFlowFuncLeave();
}

static DECLCALLBACK(void) drvCardReaderCmdReleaseContext(PUSBCARDREADER pThis,
                                                         void *pvUser)
{
    LogFlowFunc(("ENTER: pvUser:%p\n",
                 pvUser));
    NOREF(pvUser);

    UsbCardReader *pUsbCardReader = pThis->pUsbCardReader;
    if (!pUsbCardReader)
    {
        /* Do nothing. */
    }
    else
    {
        pUsbCardReader->ReleaseContext(pThis);
    }

    LogFlowFuncLeave();
}

static DECLCALLBACK(void) drvCardReaderCmdStatus(PUSBCARDREADER pThis,
                                                 void *pvUser)
{
    LogFlowFunc(("ENTER: pvUser:%p\n",
                 pvUser));

    UsbCardReader *pUsbCardReader = pThis->pUsbCardReader;
    if (!pUsbCardReader)
    {
        pThis->pICardReaderUp->pfnCardReaderUpStatus(pThis->pICardReaderUp,
                                                     pvUser,
                                                     VRDE_SCARD_E_NO_SMARTCARD,
                                                     /* pszReaderName */ NULL,
                                                     /* cchReaderName */ 0,
                                                     /* u32CardState */ 0,
                                                     /* u32Protocol */ 0,
                                                     /* pu8Atr */ 0,
                                                     /* cbAtr */ 0);
    }
    else
    {
        pUsbCardReader->Status(pThis, pvUser);
    }

    LogFlowFuncLeave();
}

static DECLCALLBACK(void) drvCardReaderCmdConnect(PUSBCARDREADER pThis,
                                                  void *pvUser,
                                                  const char *pcszCardReaderName,
                                                  uint32_t u32ShareMode,
                                                  uint32_t u32PreferredProtocols)
{
    LogFlowFunc(("ENTER: pvUser:%p, pcszCardReaderName:%s, u32ShareMode:%RX32, u32PreferredProtocols:%RX32\n",
                 pvUser, pcszCardReaderName, u32ShareMode, u32PreferredProtocols));

    UsbCardReader *pUsbCardReader = pThis->pUsbCardReader;
    if (!pUsbCardReader)
    {
        pThis->pICardReaderUp->pfnCardReaderUpConnect(pThis->pICardReaderUp,
                                                      pvUser,
                                                      VRDE_SCARD_E_NO_SMARTCARD,
                                                      0);
    }
    else
    {
        pUsbCardReader->Connect(pThis, pvUser, pcszCardReaderName,
                                u32ShareMode, u32PreferredProtocols);
    }

    LogFlowFuncLeave();
}

static DECLCALLBACK(void) drvCardReaderCmdDisconnect(PUSBCARDREADER pThis,
                                                     void *pvUser,
                                                     uint32_t u32Disposition)
{
    LogFlowFunc(("ENTER: pvUser:%p, u32Disposition:%RX32\n",
                 pvUser, u32Disposition));

    UsbCardReader *pUsbCardReader = pThis->pUsbCardReader;
    if (!pUsbCardReader)
    {
        pThis->pICardReaderUp->pfnCardReaderUpDisconnect(pThis->pICardReaderUp,
                                                         pvUser,
                                                         VRDE_SCARD_E_NO_SMARTCARD);
    }
    else
    {
        pUsbCardReader->Disconnect(pThis, pvUser, u32Disposition);
    }

    LogFlowFuncLeave();
}

static DECLCALLBACK(void) drvCardReaderCmdTransmit(PUSBCARDREADER pThis,
                                                   void *pvUser,
                                                   PDMICARDREADER_IO_REQUEST *pioSendRequest,
                                                   uint8_t *pu8SendBuffer,
                                                   uint32_t cbSendBuffer,
                                                   uint32_t cbRecvBuffer)
{
    LogFlowFunc(("ENTER: pvUser:%p, pioSendRequest:%p, pu8SendBuffer:%p, cbSendBuffer:%d, cbRecvBuffer:%d\n",
                 pvUser, pioSendRequest, pu8SendBuffer, cbSendBuffer, cbRecvBuffer));

    UsbCardReader *pUsbCardReader = pThis->pUsbCardReader;
    if (!pUsbCardReader)
    {
        pThis->pICardReaderUp->pfnCardReaderUpTransmit(pThis->pICardReaderUp,
                                                       pvUser,
                                                       VRDE_SCARD_E_NO_SMARTCARD,
                                                       /* pioRecvPci */ NULL,
                                                       /* pu8RecvBuffer */ NULL,
                                                       /* cbRecvBuffer*/ 0);
    }
    else
    {
        pUsbCardReader->Transmit(pThis, pvUser, pioSendRequest,
                                 pu8SendBuffer, cbSendBuffer, cbRecvBuffer);
    }

    /* Clean up buffers allocated by driver */
    RTMemFree(pioSendRequest);
    RTMemFree(pu8SendBuffer);

    LogFlowFuncLeave();
}

static DECLCALLBACK(void) drvCardReaderCmdGetAttr(PUSBCARDREADER pThis,
                                                  void *pvUser,
                                                  uint32_t u32AttrId,
                                                  uint32_t cbAttrib)
{
    LogFlowFunc(("ENTER: pvUser:%p, u32AttrId:%RX32, cbAttrib:%d\n",
                pvUser, u32AttrId, cbAttrib));

    UsbCardReader *pUsbCardReader = pThis->pUsbCardReader;
    if (!pUsbCardReader)
    {
        pThis->pICardReaderUp->pfnCardReaderUpGetAttrib(pThis->pICardReaderUp,
                                                        pvUser,
                                                        VRDE_SCARD_E_NO_SMARTCARD,
                                                        u32AttrId,
                                                        /* pvAttrib */ NULL,
                                                        /* cbAttrib */ 0);
    }
    else
    {
        pUsbCardReader->GetAttrib(pThis, pvUser, u32AttrId, cbAttrib);
    }

    LogFlowFuncLeave();
}

static DECLCALLBACK(void) drvCardReaderCmdSetAttr(PUSBCARDREADER pThis,
                                                  void *pvUser,
                                                  uint32_t u32AttrId,
                                                  void *pvAttrib,
                                                  uint32_t cbAttrib)
{
    LogFlowFunc(("ENTER: pvUser:%p, u32AttrId:%RX32, pvAttrib:%p, cbAttrib:%d\n",
                 pvUser, u32AttrId, pvAttrib, cbAttrib));

    UsbCardReader *pUsbCardReader = pThis->pUsbCardReader;
    if (!pUsbCardReader)
    {
        pThis->pICardReaderUp->pfnCardReaderUpSetAttrib(pThis->pICardReaderUp,
                                                        pvUser,
                                                        VRDE_SCARD_E_NO_SMARTCARD,
                                                        u32AttrId);
    }
    else
    {
        pUsbCardReader->SetAttrib(pThis, pvUser, u32AttrId, (uint8_t *)pvAttrib, cbAttrib);
    }

    /* Clean up buffers allocated by driver */
    RTMemFree(pvAttrib);

    LogFlowFuncLeave();
}

static DECLCALLBACK(void) drvCardReaderCmdControl(PUSBCARDREADER pThis,
                                                  void *pvUser,
                                                  uint32_t u32ControlCode,
                                                  void *pvInBuffer,
                                                  uint32_t cbInBuffer,
                                                  uint32_t cbOutBuffer)
{
    LogFlowFunc(("ENTER: pvUser:%p, u32ControlCode:%RX32, pvInBuffer:%p, cbInBuffer:%d, cbOutBuffer:%d\n",
                 pvUser, u32ControlCode, pvInBuffer, cbInBuffer, cbOutBuffer));

    UsbCardReader *pUsbCardReader = pThis->pUsbCardReader;
    if (!pUsbCardReader)
    {
        pThis->pICardReaderUp->pfnCardReaderUpControl(pThis->pICardReaderUp,
                                                      pvUser,
                                                      VRDE_SCARD_E_NO_SMARTCARD,
                                                      u32ControlCode,
                                                      /* pvOutBuffer */ NULL,
                                                      /* cbOutBuffer */ 0);
    }
    else
    {
        pUsbCardReader->Control(pThis, pvUser, u32ControlCode,
                                (uint8_t *)pvInBuffer, cbInBuffer, cbOutBuffer);
    }

    /* Clean up buffers allocated by driver */
    RTMemFree(pvInBuffer);

    LogFlowFuncLeave();
}


/*
 * PDMICARDREADERDOWN - interface
 */

static DECLCALLBACK(int) drvCardReaderDownConnect(PPDMICARDREADERDOWN pInterface,
                                                  void *pvUser,
                                                  const char *pcszCardReaderName,
                                                  uint32_t u32ShareMode,
                                                  uint32_t u32PreferredProtocols)
{
    AssertPtrReturn(pInterface, VERR_INVALID_PARAMETER);
    LogFlowFunc(("ENTER: pcszCardReaderName:%s, pvUser:%p, u32ShareMode:%RX32, u32PreferredProtocols:%RX32\n",
                 pcszCardReaderName, pvUser, u32ShareMode, u32PreferredProtocols));
    PUSBCARDREADER pThis = RT_FROM_MEMBER(pInterface, USBCARDREADER, ICardReaderDown);
    int rc = RTReqQueueCallEx(pThis->hReqQCardReaderCmd, NULL, 0, RTREQFLAGS_VOID | RTREQFLAGS_NO_WAIT,
                              (PFNRT)drvCardReaderCmdConnect, 5,
                              pThis, pvUser, pcszCardReaderName, u32ShareMode, u32PreferredProtocols);
    AssertRC(rc);
    LogFlowFunc(("LEAVE: %Rrc\n", rc));
    return rc;
}

static DECLCALLBACK(int)drvCardReaderDownDisconnect(PPDMICARDREADERDOWN pInterface,
                                                    void *pvUser,
                                                    uint32_t u32Disposition)
{
    AssertPtrReturn(pInterface, VERR_INVALID_PARAMETER);
    LogFlowFunc(("ENTER: pvUser:%p, u32Disposition:%RX32\n",
                 pvUser, u32Disposition));
    PUSBCARDREADER pThis = RT_FROM_MEMBER(pInterface, USBCARDREADER, ICardReaderDown);
    int rc = RTReqQueueCallEx(pThis->hReqQCardReaderCmd, NULL, 0, RTREQFLAGS_VOID | RTREQFLAGS_NO_WAIT,
                              (PFNRT)drvCardReaderCmdDisconnect, 3,
                              pThis, pvUser, u32Disposition);
    AssertRC(rc);
    LogFlowFunc(("LEAVE: %Rrc\n", rc));
    return rc;
}

static DECLCALLBACK(int) drvCardReaderDownEstablishContext(PPDMICARDREADERDOWN pInterface)
{
    AssertPtrReturn(pInterface, VERR_INVALID_PARAMETER);
    LogFlowFunc(("ENTER:\n"));
    PUSBCARDREADER pThis = RT_FROM_MEMBER(pInterface, USBCARDREADER, ICardReaderDown);
    int rc = RTReqQueueCallEx(pThis->hReqQCardReaderCmd, NULL, 0, RTREQFLAGS_VOID | RTREQFLAGS_NO_WAIT,
                              (PFNRT)drvCardReaderCmdEstablishContext, 1,
                              pThis);
    AssertRC(rc);
    LogFlowFunc(("LEAVE: %Rrc\n", rc));
    return rc;
}

static DECLCALLBACK(int) drvCardReaderDownReleaseContext(PPDMICARDREADERDOWN pInterface,
                                                         void *pvUser)
{
    AssertPtrReturn(pInterface, VERR_INVALID_PARAMETER);
    LogFlowFunc(("ENTER: pvUser:%p\n",
                 pvUser));
    PUSBCARDREADER pThis = RT_FROM_MEMBER(pInterface, USBCARDREADER, ICardReaderDown);
    /* @todo Device calls this when the driver already destroyed. */
    if (pThis->hReqQCardReaderCmd == NIL_RTREQQUEUE)
    {
        LogFlowFunc(("LEAVE: device already deleted.\n"));
        return VINF_SUCCESS;
    }

    int rc = RTReqQueueCallEx(pThis->hReqQCardReaderCmd, NULL, 0, RTREQFLAGS_VOID | RTREQFLAGS_NO_WAIT,
                              (PFNRT)drvCardReaderCmdReleaseContext, 2,
                              pThis, pvUser);
    AssertRC(rc);
    LogFlowFunc(("LEAVE: %Rrc\n", rc));
    return rc;
}

static DECLCALLBACK(int)drvCardReaderDownStatus(PPDMICARDREADERDOWN pInterface,
                                                void *pvUser,
                                                uint32_t cchReaderName,
                                                uint32_t cbAtrLen)
{
    AssertPtrReturn(pInterface, VERR_INVALID_PARAMETER);
    LogFlowFunc(("ENTER: pvUser:%p, cchReaderName:%d, cbAtrLen:%d\n",
                 pvUser, cchReaderName, cbAtrLen));
    NOREF(cchReaderName);
    NOREF(cbAtrLen);
    PUSBCARDREADER pThis = RT_FROM_MEMBER(pInterface, USBCARDREADER, ICardReaderDown);
    int rc = RTReqQueueCallEx(pThis->hReqQCardReaderCmd, NULL, 0, RTREQFLAGS_VOID | RTREQFLAGS_NO_WAIT,
                             (PFNRT)drvCardReaderCmdStatus, 2,
                             pThis, pvUser);
    AssertRC(rc);
    LogFlowFunc(("LEAVE: %Rrc\n", rc));
    return rc;
}

static DECLCALLBACK(int) drvCardReaderDownGetStatusChange(PPDMICARDREADERDOWN pInterface,
                                                          void *pvUser,
                                                          uint32_t u32Timeout,
                                                          PDMICARDREADER_READERSTATE *paReaderStats,
                                                          uint32_t cReaderStats)
{
    AssertPtrReturn(pInterface, VERR_INVALID_PARAMETER);
    LogFlowFunc(("ENTER: pvUser:%p, u32Timeout:%d, cReaderStats:%d\n",
                 pvUser, u32Timeout, cReaderStats));
    PUSBCARDREADER pThis = RT_FROM_MEMBER(pInterface, USBCARDREADER, ICardReaderDown);
    int rc = RTReqQueueCallEx(pThis->hReqQCardReaderCmd, NULL, 0, RTREQFLAGS_VOID | RTREQFLAGS_NO_WAIT,
                              (PFNRT)drvCardReaderCmdStatusChange, 5,
                              pThis, pvUser, u32Timeout, paReaderStats, cReaderStats);
    AssertRC(rc);
    LogFlowFunc(("LEAVE: %Rrc\n", rc));
    return rc;
}

static DECLCALLBACK(int) drvCardReaderDownBeginTransaction(PPDMICARDREADERDOWN pInterface,
                                                           void *pvUser)
{
    AssertPtrReturn(pInterface, VERR_INVALID_PARAMETER);
    LogFlowFunc(("ENTER: pvUser:%p\n",
                 pvUser));
    PUSBCARDREADER pThis = RT_FROM_MEMBER(pInterface, USBCARDREADER, ICardReaderDown);
    int rc = VERR_NOT_SUPPORTED;
    AssertRC(rc);
    LogFlowFunc(("LEAVE: %Rrc\n", rc));
    return rc;
}

static DECLCALLBACK(int) drvCardReaderDownEndTransaction(PPDMICARDREADERDOWN pInterface,
                                                         void *pvUser,
                                                         uint32_t u32Disposition)
{
    AssertPtrReturn(pInterface, VERR_INVALID_PARAMETER);
    LogFlowFunc(("ENTER: pvUser:%p, u32Disposition:%RX32\n",
                 pvUser, u32Disposition));
    PUSBCARDREADER pThis = RT_FROM_MEMBER(pInterface, USBCARDREADER, ICardReaderDown);
    int rc = VERR_NOT_SUPPORTED;
    AssertRC(rc);
    LogFlowFunc(("LEAVE: %Rrc\n", rc));
    return rc;
}

static DECLCALLBACK(int) drvCardReaderDownTransmit(PPDMICARDREADERDOWN pInterface,
                                                   void *pvUser,
                                                   const PDMICARDREADER_IO_REQUEST *pioSendRequest,
                                                   const uint8_t *pu8SendBuffer,
                                                   uint32_t cbSendBuffer,
                                                   uint32_t cbRecvBuffer)
{
    AssertPtrReturn(pInterface, VERR_INVALID_PARAMETER);
    LogFlowFunc(("ENTER: pvUser:%p, pioSendRequest:%p, pu8SendBuffer:%p, cbSendBuffer:%d, cbRecvBuffer:%d\n",
                 pvUser, pioSendRequest, pu8SendBuffer, cbSendBuffer, cbRecvBuffer));
    PUSBCARDREADER pThis = RT_FROM_MEMBER(pInterface, USBCARDREADER, ICardReaderDown);
    uint8_t *pu8SendBufferCopy = NULL;
    if (   pu8SendBuffer
        && cbSendBuffer)
    {
        pu8SendBufferCopy = (uint8_t *)RTMemDup(pu8SendBuffer, cbSendBuffer);
        if (!pu8SendBufferCopy)
        {
            return VERR_NO_MEMORY;
        }
    }
    PDMICARDREADER_IO_REQUEST *pioSendRequestCopy = NULL;
    if (pioSendRequest)
    {
        pioSendRequestCopy = (PDMICARDREADER_IO_REQUEST *)RTMemDup(pioSendRequest, pioSendRequest->cbPciLength);
        if (!pioSendRequestCopy)
        {
            RTMemFree(pu8SendBufferCopy);
            return VERR_NO_MEMORY;
        }
    }
    int rc = RTReqQueueCallEx(pThis->hReqQCardReaderCmd, NULL, 0,RTREQFLAGS_VOID | RTREQFLAGS_NO_WAIT,
                              (PFNRT)drvCardReaderCmdTransmit, 6,
                              pThis, pvUser, pioSendRequestCopy, pu8SendBufferCopy, cbSendBuffer, cbRecvBuffer);
    AssertRC(rc);
    LogFlowFunc(("LEAVE: %Rrc\n", rc));
    return rc;
}

static DECLCALLBACK(int) drvCardReaderDownGetAttr(PPDMICARDREADERDOWN pInterface,
                                                  void *pvUser,
                                                  uint32_t u32AttribId,
                                                  uint32_t cbAttrib)
{
    AssertPtrReturn(pInterface, VERR_INVALID_PARAMETER);
    LogFlowFunc(("ENTER: pvUser:%p, u32AttribId:%RX32, cbAttrib:%d\n",
                 pvUser, u32AttribId, cbAttrib));
    PUSBCARDREADER pThis = RT_FROM_MEMBER(pInterface, USBCARDREADER, ICardReaderDown);
    int rc = RTReqQueueCallEx(pThis->hReqQCardReaderCmd, NULL, 0, RTREQFLAGS_VOID | RTREQFLAGS_NO_WAIT,
                              (PFNRT)drvCardReaderCmdGetAttr, 4,
                              pThis, pvUser, u32AttribId, cbAttrib);
    AssertRC(rc);
    LogFlowFunc(("LEAVE: %Rrc\n", rc));
    return rc;
}

static DECLCALLBACK(int) drvCardReaderDownSetAttr(PPDMICARDREADERDOWN pInterface,
                                                  void *pvUser,
                                                  uint32_t u32AttribId,
                                                  const void *pvAttrib,
                                                  uint32_t cbAttrib)
{
    AssertPtrReturn(pInterface, VERR_INVALID_PARAMETER);
    LogFlowFunc(("ENTER: pvUser:%p, u32AttribId:%RX32, pvAttrib:%p, cbAttrib:%d\n",
                 pvUser, u32AttribId, pvAttrib, cbAttrib));
    PUSBCARDREADER pThis = RT_FROM_MEMBER(pInterface, USBCARDREADER, ICardReaderDown);
    void *pvAttribCopy = NULL;
    if (   pvAttrib
        && cbAttrib)
    {
        pvAttribCopy = RTMemDup(pvAttrib, cbAttrib);
        AssertPtrReturn(pvAttribCopy, VERR_NO_MEMORY);
    }
    int rc = RTReqQueueCallEx(pThis->hReqQCardReaderCmd, NULL, 0, RTREQFLAGS_VOID | RTREQFLAGS_NO_WAIT,
                              (PFNRT)drvCardReaderCmdSetAttr, 5,
                              pThis, pvUser, u32AttribId, pvAttribCopy, cbAttrib);
    AssertRC(rc);
    LogFlowFunc(("LEAVE: %Rrc\n", rc));
    return rc;
}

static DECLCALLBACK(int) drvCardReaderDownControl(PPDMICARDREADERDOWN pInterface,
                                                  void *pvUser,
                                                  uint32_t u32ControlCode,
                                                  const void *pvInBuffer,
                                                  uint32_t cbInBuffer,
                                                  uint32_t cbOutBuffer)
{
    AssertPtrReturn(pInterface, VERR_INVALID_PARAMETER);
    LogFlowFunc(("ENTER: pvUser:%p, u32ControlCode:%RX32 pvInBuffer:%p, cbInBuffer:%d, cbOutBuffer:%d\n",
                 pvUser, u32ControlCode, pvInBuffer, cbInBuffer, cbOutBuffer));
    PUSBCARDREADER pThis = RT_FROM_MEMBER(pInterface, USBCARDREADER, ICardReaderDown);
    void *pvInBufferCopy = NULL;
    if (   pvInBuffer
        && cbInBuffer)
    {
        pvInBufferCopy = RTMemDup(pvInBuffer, cbInBuffer);
        AssertPtrReturn(pvInBufferCopy, VERR_NO_MEMORY);
    }
    int rc = RTReqQueueCallEx(pThis->hReqQCardReaderCmd, NULL, 0, RTREQFLAGS_VOID | RTREQFLAGS_NO_WAIT,
                              (PFNRT)drvCardReaderCmdControl, 6,
                              pThis, pvUser, u32ControlCode, pvInBufferCopy, cbInBuffer, cbOutBuffer);
    AssertRC(rc);
    LogFlowFunc(("LEAVE: %Rrc\n", rc));
    return rc;
}


/*
 * Cardreader driver thread routines
 */
static DECLCALLBACK(int) drvCardReaderThreadCmd(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
{
    int rc = VINF_SUCCESS;
    PUSBCARDREADER pThis = PDMINS_2_DATA(pDrvIns, PUSBCARDREADER);

    LogFlowFunc(("ENTER: pDrvIns:%d, state %d\n", pDrvIns->iInstance, pThread->enmState));

    if (pThread->enmState == PDMTHREADSTATE_INITIALIZING)
    {
        LogFlowFunc(("LEAVE: INITIALIZING: VINF_SUCCESS\n"));
        return VINF_SUCCESS;
    }

    while (pThread->enmState == PDMTHREADSTATE_RUNNING)
    {
        rc = RTReqQueueProcess(pThis->hReqQCardReaderCmd, RT_INDEFINITE_WAIT);

        AssertMsg(rc == VWRN_STATE_CHANGED,
                  ("Left RTReqProcess and error code is not VWRN_STATE_CHANGED rc=%Rrc\n",
                   rc));
    }

    LogFlowFunc(("LEAVE: %Rrc\n", rc));
    return rc;
}

static int drvCardReaderWakeupFunc(PUSBCARDREADER pThis)
{
    NOREF(pThis);
    /* Returning a VINF_* will cause RTReqQueueProcess return. */
    return VWRN_STATE_CHANGED;
}

static DECLCALLBACK(int) drvCardReaderThreadCmdWakeup(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)
{
    LogFlowFunc(("ENTER: pDrvIns:%i\n", pDrvIns->iInstance));

    PUSBCARDREADER pThis = PDMINS_2_DATA(pDrvIns, PUSBCARDREADER);

    AssertReturn(pThis->hReqQCardReaderCmd != NIL_RTREQQUEUE, VERR_INVALID_STATE);

    PRTREQ pReq;
    int rc = RTReqQueueCall(pThis->hReqQCardReaderCmd, &pReq, 10000, (PFNRT)drvCardReaderWakeupFunc, 1, pThis);
    AssertMsgRC(rc, ("Inserting request into queue failed rc=%Rrc\n"));

    if (RT_SUCCESS(rc))
        RTReqRelease(pReq);
    /* @todo handle VERR_TIMEOUT */

    return rc;
}


/*
 * USB Card reader driver implementation.
 */

UsbCardReader::UsbCardReader(Console *console)
    :
    mpDrv(NULL),
    mParent(console),
    m_pRemote(NULL)
{
    LogFlowFunc(("\n"));
}

UsbCardReader::~UsbCardReader()
{
    LogFlowFunc(("mpDrv %p\n", mpDrv));
    if (mpDrv)
    {
        mpDrv->pUsbCardReader = NULL;
        mpDrv = NULL;
    }
}

typedef struct UCRREMOTEREADER
{
    bool fAvailable;
    char szReaderName[1024];

    bool fHandle;
    VRDESCARDHANDLE hCard;
} UCRREMOTEREADER;

struct UCRREMOTE
{
    UsbCardReader *pUsbCardReader;

    /* The remote identifiers. */
    uint32_t u32ClientId;
    uint32_t u32DeviceId;

    bool fContext;
    VRDESCARDCONTEXT context;

    /* Possible a few readers. Currently only one. */
    UCRREMOTEREADER reader;
};

typedef struct UCRREQCTX
{
    UCRREMOTE *pRemote;
    uint32_t u32Function;
    void *pvUser;
    union
    {
        struct
        {
            PDMICARDREADER_READERSTATE *paReaderStats;
            uint32_t cReaderStats;
        } GetStatusChange;
        struct
        {
            uint32_t u32AttrId;
        } GetAttrib;
        struct
        {
            uint32_t u32AttrId;
        } SetAttrib;
        struct
        {
            uint32_t u32ControlCode;
        } Control;
    } u;
} UCRREQCTX;

int UsbCardReader::vrdeSCardRequest(void *pvUser, uint32_t u32Function, const void *pvData, uint32_t cbData)
{
    int rc = mParent->consoleVRDPServer()->SCardRequest(pvUser, u32Function, pvData, cbData);
    LogFlowFunc(("%d %Rrc\n", u32Function, rc));
    return rc;
}

int UsbCardReader::VRDENotify(uint32_t u32Id, void *pvData, uint32_t cbData)
{
    int rc = VINF_SUCCESS;

    switch (u32Id)
    {
        case VRDE_SCARD_NOTIFY_ATTACH:
        {
            VRDESCARDNOTIFYATTACH *p = (VRDESCARDNOTIFYATTACH *)pvData;
            Assert(cbData == sizeof(VRDESCARDNOTIFYATTACH));

            LogFlowFunc(("[%d,%d]\n", p->u32ClientId, p->u32DeviceId));

            /* Add this remote instance, which allow access to card readers attached to the client, to the list.
             * @todo currently only one device is allowed.
             */
            if (m_pRemote)
            {
                AssertFailed();
                rc = VERR_NOT_SUPPORTED;
                break;
            }
            UCRREMOTE *pRemote = (UCRREMOTE *)RTMemAllocZ(sizeof(UCRREMOTE));
            if (pRemote == NULL)
            {
                rc = VERR_NO_MEMORY;
                break;
            }

            pRemote->pUsbCardReader = this;
            pRemote->u32ClientId = p->u32ClientId;
            pRemote->u32DeviceId = p->u32DeviceId;

            m_pRemote = pRemote;

            /* Try to establish a context. */
            VRDESCARDESTABLISHCONTEXTREQ req;
            req.u32ClientId = m_pRemote->u32ClientId;
            req.u32DeviceId = m_pRemote->u32DeviceId;

            rc = vrdeSCardRequest(m_pRemote, VRDE_SCARD_FN_ESTABLISHCONTEXT, &req, sizeof(req));

            LogFlowFunc(("sent ESTABLISHCONTEXT\n"));
        } break;

        case VRDE_SCARD_NOTIFY_DETACH:
        {
            VRDESCARDNOTIFYDETACH *p = (VRDESCARDNOTIFYDETACH *)pvData;
            Assert(cbData == sizeof(VRDESCARDNOTIFYDETACH));

            /* @todo Just free. There should be no pending requests, because VRDP cancels them. */
            RTMemFree(m_pRemote);
            m_pRemote = NULL;
        } break;

        default:
            rc = VERR_INVALID_PARAMETER;
            AssertFailed();
            break;
    }

    return rc;
}

int UsbCardReader::VRDEResponse(int rcRequest, void *pvUser, uint32_t u32Function, void *pvData, uint32_t cbData)
{
    int rc = VINF_SUCCESS;

    LogFlowFunc(("%Rrc %p %u %p %u\n",
                 rcRequest, pvUser, u32Function, pvData, cbData));

    switch (u32Function)
    {
        case VRDE_SCARD_FN_ESTABLISHCONTEXT:
        {
            Assert(cbData == sizeof(VRDESCARDESTABLISHCONTEXTRSP) || RT_FAILURE(rcRequest));
            VRDESCARDESTABLISHCONTEXTRSP *pRsp = (VRDESCARDESTABLISHCONTEXTRSP *)pvData;
            UCRREMOTE *pRemote = (UCRREMOTE *)pvUser;

            /* Check if the context was created. */
            Assert(!pRemote->fContext);
            if (   RT_SUCCESS(rcRequest)
                && pRsp->u32ReturnCode == VRDE_SCARD_S_SUCCESS)
            {
                pRemote->fContext = true;
                pRemote->context = pRsp->Context;

                LogFlowFunc(("ESTABLISHCONTEXT success\n"));

                /* Now list readers attached to the remote client. */
                VRDESCARDLISTREADERSREQ req;
                req.Context = pRemote->context;

                rc = vrdeSCardRequest(pRemote, VRDE_SCARD_FN_LISTREADERS, &req, sizeof(req));
            }
        } break;

        case VRDE_SCARD_FN_LISTREADERS:
        {
            Assert(cbData == sizeof(VRDESCARDLISTREADERSRSP) || RT_FAILURE(rcRequest));
            VRDESCARDLISTREADERSRSP *pRsp = (VRDESCARDLISTREADERSRSP *)pvData;
            UCRREMOTE *pRemote = (UCRREMOTE *)pvUser;

            Assert(pRemote->fContext);
            if (   RT_SUCCESS(rcRequest)
                && pRsp->u32ReturnCode == VRDE_SCARD_S_SUCCESS
                && pRemote->fContext)
            {
                LogFlowFunc(("LISTREADERS: cReaders %d\n",
                             pRsp->cReaders));

                uint32_t i;
                for (i = 0; i < pRsp->cReaders; i++)
                {
                    LogFlowFunc(("LISTREADERS: [%d] [%s]\n",
                                 i, pRsp->apszNames[i]));

                    /* @todo only the first reader is supported. */
                    if (i != 0)
                    {
                        continue;
                    }

                    RTStrCopy(pRemote->reader.szReaderName, sizeof(pRemote->reader.szReaderName), pRsp->apszNames[i]);
                    pRemote->reader.fHandle = false;
                    pRemote->reader.fAvailable = true;
                }
            }
        } break;

        case VRDE_SCARD_FN_RELEASECONTEXT:
        {
            Assert(cbData == sizeof(VRDESCARDRELEASECONTEXTRSP) || RT_FAILURE(rcRequest));
            VRDESCARDRELEASECONTEXTRSP *pRsp = (VRDESCARDRELEASECONTEXTRSP *)pvData;
            UCRREQCTX *pCtx = (UCRREQCTX *)pvUser;

            Assert(pCtx->u32Function == u32Function);

            LogFlowFunc(("RELEASECONTEXT completed\n"));

            /* No notification is expected here by the caller. */
            Assert(!m_pRemote->fContext);
        } break;

        case VRDE_SCARD_FN_GETSTATUSCHANGE:
        {
            Assert(cbData == sizeof(VRDESCARDGETSTATUSCHANGERSP) || RT_FAILURE(rcRequest));
            VRDESCARDGETSTATUSCHANGERSP *pRsp = (VRDESCARDGETSTATUSCHANGERSP *)pvData;
            UCRREQCTX *pCtx = (UCRREQCTX *)pvUser;

            Assert(pCtx->u32Function == u32Function);

            LogFlowFunc(("GETSTATUSCHANGE\n"));

            uint32_t rcCard;
            if (RT_FAILURE(rcRequest))
            {
                rcCard = VRDE_SCARD_E_NO_SMARTCARD;
            }
            else
            {
                rcCard = pRsp->u32ReturnCode;

                if (pRsp->u32ReturnCode == VRDE_SCARD_S_SUCCESS)
                {
                    uint32_t i;
                    for (i = 0; i < pRsp->cReaders; i++)
                    {
                        LogFlowFunc(("GETSTATUSCHANGE: [%d] %RX32\n",
                                     i, pRsp->aReaderStates[i].u32EventState));

                        /* @todo only the first reader is supported. */
                        if (i != 0)
                        {
                            continue;
                        }

                        if (i >= pCtx->u.GetStatusChange.cReaderStats)
                        {
                            continue;
                        }

                        pCtx->u.GetStatusChange.paReaderStats[i].u32EventState = pRsp->aReaderStates[i].u32EventState;
                        pCtx->u.GetStatusChange.paReaderStats[i].cbAtr = pRsp->aReaderStates[i].u32AtrLength > 36?
                                                                             36:
                                                                             pRsp->aReaderStates[i].u32AtrLength;
                        memcpy(pCtx->u.GetStatusChange.paReaderStats[i].au8Atr,
                               pRsp->aReaderStates[i].au8Atr,
                               pCtx->u.GetStatusChange.paReaderStats[i].cbAtr);
                    }
                }
            }

            mpDrv->pICardReaderUp->pfnCardReaderUpSetStatusChange(mpDrv->pICardReaderUp,
                                                                  pCtx->pvUser,
                                                                  rcCard,
                                                                  pCtx->u.GetStatusChange.paReaderStats,
                                                                  pCtx->u.GetStatusChange.cReaderStats);

            RTMemFree(pCtx);
        } break;

        case VRDE_SCARD_FN_CANCEL:
        {
            Assert(cbData == sizeof(VRDESCARDCANCELRSP) || RT_FAILURE(rcRequest));
            VRDESCARDCANCELRSP *pRsp = (VRDESCARDCANCELRSP *)pvData;
            UCRREQCTX *pCtx = (UCRREQCTX *)pvUser;

            Assert(pCtx->u32Function == u32Function);

            LogFlowFunc(("CANCEL\n"));
        } break;

        case VRDE_SCARD_FN_CONNECT:
        {
            Assert(cbData == sizeof(VRDESCARDCONNECTRSP) || RT_FAILURE(rcRequest));
            VRDESCARDCONNECTRSP *pRsp = (VRDESCARDCONNECTRSP *)pvData;
            UCRREQCTX *pCtx = (UCRREQCTX *)pvUser;

            Assert(pCtx->u32Function == u32Function);

            LogFlowFunc(("CONNECT\n"));

            uint32_t u32ActiveProtocol = 0;
            uint32_t rcCard;

            if (RT_FAILURE(rcRequest))
            {
                rcCard = VRDE_SCARD_E_NO_SMARTCARD;
            }
            else
            {
                rcCard = pRsp->u32ReturnCode;

                if (pRsp->u32ReturnCode == VRDE_SCARD_S_SUCCESS)
                {
                    u32ActiveProtocol = pRsp->u32ActiveProtocol;

                    Assert(!m_pRemote->reader.fHandle);
                    m_pRemote->reader.hCard = pRsp->hCard;
                    m_pRemote->reader.fHandle = true;
                }
            }

            mpDrv->pICardReaderUp->pfnCardReaderUpConnect(mpDrv->pICardReaderUp,
                                                          pCtx->pvUser,
                                                          rcCard,
                                                          u32ActiveProtocol);

            RTMemFree(pCtx);
        } break;

        case VRDE_SCARD_FN_RECONNECT:
        {
            Assert(cbData == sizeof(VRDESCARDRECONNECTRSP) || RT_FAILURE(rcRequest));
            VRDESCARDRECONNECTRSP *pRsp = (VRDESCARDRECONNECTRSP *)pvData;
            UCRREQCTX *pCtx = (UCRREQCTX *)pvUser;

            Assert(pCtx->u32Function == u32Function);

            LogFlowFunc(("RECONNECT\n"));
        } break;

        case VRDE_SCARD_FN_DISCONNECT:
        {
            Assert(cbData == sizeof(VRDESCARDDISCONNECTRSP) || RT_FAILURE(rcRequest));
            VRDESCARDDISCONNECTRSP *pRsp = (VRDESCARDDISCONNECTRSP *)pvData;
            UCRREQCTX *pCtx = (UCRREQCTX *)pvUser;

            Assert(pCtx->u32Function == u32Function);

            LogFlowFunc(("DISCONNECT\n"));

            Assert(!pCtx->pRemote->reader.fHandle);

            uint32_t rcCard;

            if (RT_FAILURE(rcRequest))
            {
                rcCard = VRDE_SCARD_E_NO_SMARTCARD;
            }
            else
            {
                rcCard = pRsp->u32ReturnCode;
            }

            mpDrv->pICardReaderUp->pfnCardReaderUpDisconnect(mpDrv->pICardReaderUp,
                                                             pCtx->pvUser,
                                                             rcCard);

            RTMemFree(pCtx);
        } break;

        case VRDE_SCARD_FN_BEGINTRANSACTION:
        {
            Assert(cbData == sizeof(VRDESCARDBEGINTRANSACTIONRSP) || RT_FAILURE(rcRequest));
            VRDESCARDBEGINTRANSACTIONRSP *pRsp = (VRDESCARDBEGINTRANSACTIONRSP *)pvData;
            UCRREQCTX *pCtx = (UCRREQCTX *)pvUser;

            Assert(pCtx->u32Function == u32Function);

            LogFlowFunc(("BEGINTRANSACTION\n"));
        } break;

        case VRDE_SCARD_FN_ENDTRANSACTION:
        {
            Assert(cbData == sizeof(VRDESCARDENDTRANSACTIONRSP) || RT_FAILURE(rcRequest));
            VRDESCARDENDTRANSACTIONRSP *pRsp = (VRDESCARDENDTRANSACTIONRSP *)pvData;
            UCRREQCTX *pCtx = (UCRREQCTX *)pvUser;

            Assert(pCtx->u32Function == u32Function);

            LogFlowFunc(("ENDTRANSACTION\n"));
        } break;

        case VRDE_SCARD_FN_STATE:
        {
            Assert(cbData == sizeof(VRDESCARDSTATERSP) || RT_FAILURE(rcRequest));
            VRDESCARDSTATERSP *pRsp = (VRDESCARDSTATERSP *)pvData;
            UCRREQCTX *pCtx = (UCRREQCTX *)pvUser;

            Assert(pCtx->u32Function == u32Function);

            LogFlowFunc(("STATE\n"));
        } break;

        case VRDE_SCARD_FN_STATUS:
        {
            Assert(cbData == sizeof(VRDESCARDSTATUSRSP) || RT_FAILURE(rcRequest));
            VRDESCARDSTATUSRSP *pRsp = (VRDESCARDSTATUSRSP *)pvData;
            UCRREQCTX *pCtx = (UCRREQCTX *)pvUser;

            Assert(pCtx->u32Function == u32Function);

            LogFlowFunc(("STATUS\n"));

            char *pszReaderName = NULL;
            uint32_t cchReaderName = 0;
            uint32_t u32CardState = 0;
            uint32_t u32Protocol = 0;
            uint32_t u32AtrLength = 0;
            uint8_t *pbAtr = NULL;

            uint32_t rcCard;

            if (RT_FAILURE(rcRequest))
            {
                rcCard = VRDE_SCARD_E_NO_SMARTCARD;
            }
            else
            {
                rcCard = pRsp->u32ReturnCode;

                if (pRsp->u32ReturnCode == VRDE_SCARD_S_SUCCESS)
                {
                    pszReaderName = pRsp->szReader;
                    cchReaderName = strlen(pRsp->szReader) + 1;
                    u32CardState = pRsp->u32State;
                    u32Protocol = pRsp->u32Protocol;
                    u32AtrLength = pRsp->u32AtrLength;
                    pbAtr = &pRsp->au8Atr[0];
                }
            }

            mpDrv->pICardReaderUp->pfnCardReaderUpStatus(mpDrv->pICardReaderUp,
                                                         pCtx->pvUser,
                                                         rcCard,
                                                         pszReaderName,
                                                         cchReaderName,
                                                         u32CardState,
                                                         u32Protocol,
                                                         pbAtr,
                                                         u32AtrLength);

            RTMemFree(pCtx);
        } break;

        case VRDE_SCARD_FN_TRANSMIT:
        {
            Assert(cbData == sizeof(VRDESCARDTRANSMITRSP) || RT_FAILURE(rcRequest));
            VRDESCARDTRANSMITRSP *pRsp = (VRDESCARDTRANSMITRSP *)pvData;
            UCRREQCTX *pCtx = (UCRREQCTX *)pvUser;

            Assert(pCtx->u32Function == u32Function);

            LogFlowFunc(("TRANSMIT\n"));

            PDMICARDREADER_IO_REQUEST *pioRecvPci = NULL;
            uint8_t *pu8RecvBuffer = NULL;
            uint32_t cbRecvBuffer = 0;

            uint32_t rcCard;

            if (RT_FAILURE(rcRequest))
            {
                rcCard = VRDE_SCARD_E_NO_SMARTCARD;
            }
            else
            {
                rcCard = pRsp->u32ReturnCode;

                if (pRsp->u32ReturnCode == VRDE_SCARD_S_SUCCESS)
                {
                    pu8RecvBuffer = pRsp->pu8RecvBuffer;
                    cbRecvBuffer = pRsp->u32RecvLength;
                    /* @todo pioRecvPci */
                }
            }

            mpDrv->pICardReaderUp->pfnCardReaderUpTransmit(mpDrv->pICardReaderUp,
                                                           pCtx->pvUser,
                                                           rcCard,
                                                           pioRecvPci,
                                                           pu8RecvBuffer,
                                                           cbRecvBuffer);

            RTMemFree(pioRecvPci);

            RTMemFree(pCtx);
        } break;

        case VRDE_SCARD_FN_CONTROL:
        {
            Assert(cbData == sizeof(VRDESCARDCONTROLRSP) || RT_FAILURE(rcRequest));
            VRDESCARDCONTROLRSP *pRsp = (VRDESCARDCONTROLRSP *)pvData;
            UCRREQCTX *pCtx = (UCRREQCTX *)pvUser;

            Assert(pCtx->u32Function == u32Function);

            LogFlowFunc(("CONTROL\n"));

            uint8_t *pu8OutBuffer = NULL;
            uint32_t cbOutBuffer = 0;

            uint32_t rcCard;

            if (RT_FAILURE(rcRequest))
            {
                rcCard = VRDE_SCARD_E_NO_SMARTCARD;
            }
            else
            {
                rcCard = pRsp->u32ReturnCode;

                if (pRsp->u32ReturnCode == VRDE_SCARD_S_SUCCESS)
                {
                    pu8OutBuffer = pRsp->pu8OutBuffer;
                    cbOutBuffer = pRsp->u32OutBufferSize;
                }
            }

            mpDrv->pICardReaderUp->pfnCardReaderUpControl(mpDrv->pICardReaderUp,
                                                           pCtx->pvUser,
                                                           rcCard,
                                                           pCtx->u.Control.u32ControlCode,
                                                           pu8OutBuffer,
                                                           cbOutBuffer);

            RTMemFree(pCtx);
        } break;

        case VRDE_SCARD_FN_GETATTRIB:
        {
            Assert(cbData == sizeof(VRDESCARDGETATTRIBRSP) || RT_FAILURE(rcRequest));
            VRDESCARDGETATTRIBRSP *pRsp = (VRDESCARDGETATTRIBRSP *)pvData;
            UCRREQCTX *pCtx = (UCRREQCTX *)pvUser;

            Assert(pCtx->u32Function == u32Function);

            LogFlowFunc(("GETATTRIB\n"));

            uint8_t *pu8Attrib = NULL;
            uint32_t cbAttrib = 0;

            uint32_t rcCard;

            if (RT_FAILURE(rcRequest))
            {
                rcCard = VRDE_SCARD_E_NO_SMARTCARD;
            }
            else
            {
                rcCard = pRsp->u32ReturnCode;

                if (pRsp->u32ReturnCode == VRDE_SCARD_S_SUCCESS)
                {
                    pu8Attrib = pRsp->pu8Attr;
                    cbAttrib = pRsp->u32AttrLength;
                }
            }

            mpDrv->pICardReaderUp->pfnCardReaderUpGetAttrib(mpDrv->pICardReaderUp,
                                                            pCtx->pvUser,
                                                            rcCard,
                                                            pCtx->u.GetAttrib.u32AttrId,
                                                            pu8Attrib,
                                                            cbAttrib);

            RTMemFree(pCtx);
        } break;

        case VRDE_SCARD_FN_SETATTRIB:
        {
            Assert(cbData == sizeof(VRDESCARDSETATTRIBRSP) || RT_FAILURE(rcRequest));
            VRDESCARDSETATTRIBRSP *pRsp = (VRDESCARDSETATTRIBRSP *)pvData;
            UCRREQCTX *pCtx = (UCRREQCTX *)pvUser;

            Assert(pCtx->u32Function == u32Function);

            LogFlowFunc(("SETATTRIB\n"));

            uint32_t rcCard;

            if (RT_FAILURE(rcRequest))
            {
                rcCard = VRDE_SCARD_E_NO_SMARTCARD;
            }
            else
            {
                rcCard = pRsp->u32ReturnCode;
            }

            mpDrv->pICardReaderUp->pfnCardReaderUpSetAttrib(mpDrv->pICardReaderUp,
                                                            pCtx->pvUser,
                                                            rcCard,
                                                            pCtx->u.SetAttrib.u32AttrId);

            RTMemFree(pCtx);
        } break;

        default:
            AssertFailed();
            rc = VERR_INVALID_PARAMETER;
            break;
    }

    return rc;
}

int UsbCardReader::EstablishContext(struct USBCARDREADER *pDrv)
{
    AssertReturn(pDrv == mpDrv, VERR_NOT_SUPPORTED);

    /* The context here is a not a real device context.
     * The device can be detached at the moment, for example the VRDP client did not connect yet.
     */

    return mpDrv->pICardReaderUp->pfnCardReaderUpEstablishContext(mpDrv->pICardReaderUp,
                                                                  VRDE_SCARD_S_SUCCESS);
}

int UsbCardReader::ReleaseContext(struct USBCARDREADER *pDrv)
{
    AssertReturn(pDrv == mpDrv, VERR_NOT_SUPPORTED);

    int rc = VINF_SUCCESS;

    if (   !m_pRemote
        || !m_pRemote->fContext)
    {
        /* Do nothing. */
    }
    else
    {
        UCRREQCTX *pCtx = (UCRREQCTX *)RTMemAlloc(sizeof(UCRREQCTX));
        if (!pCtx)
        {
            /* Do nothing. */
        }
        else
        {
            pCtx->pRemote = m_pRemote;
            pCtx->u32Function = VRDE_SCARD_FN_RELEASECONTEXT;
            pCtx->pvUser = NULL;

            VRDESCARDRELEASECONTEXTREQ req;
            req.Context = m_pRemote->context;

            rc = vrdeSCardRequest(pCtx, VRDE_SCARD_FN_RELEASECONTEXT, &req, sizeof(req));

            if (RT_FAILURE(rc))
            {
                RTMemFree(pCtx);
            }
            else
            {
                m_pRemote->fContext = false;
            }
        }
    }

    return rc;
}

int UsbCardReader::GetStatusChange(struct USBCARDREADER *pDrv,
                                   void *pvUser,
                                   uint32_t u32Timeout,
                                   PDMICARDREADER_READERSTATE *paReaderStats,
                                   uint32_t cReaderStats)
{
    AssertReturn(pDrv == mpDrv, VERR_NOT_SUPPORTED);

    int rc = VINF_SUCCESS;

    if (   !m_pRemote
        || !m_pRemote->fContext
        || !m_pRemote->reader.fAvailable)
    {
        rc = mpDrv->pICardReaderUp->pfnCardReaderUpSetStatusChange(mpDrv->pICardReaderUp,
                                                                   pvUser,
                                                                   VRDE_SCARD_E_NO_SMARTCARD,
                                                                   paReaderStats,
                                                                   cReaderStats);
    }
    else
    {
        UCRREQCTX *pCtx = (UCRREQCTX *)RTMemAlloc(sizeof(UCRREQCTX));
        if (!pCtx)
        {
            rc = mpDrv->pICardReaderUp->pfnCardReaderUpSetStatusChange(mpDrv->pICardReaderUp,
                                                                       pvUser,
                                                                       VRDE_SCARD_E_NO_MEMORY,
                                                                       paReaderStats,
                                                                       cReaderStats);
        }
        else
        {
            pCtx->pRemote = m_pRemote;
            pCtx->u32Function = VRDE_SCARD_FN_GETSTATUSCHANGE;
            pCtx->pvUser = pvUser;
            pCtx->u.GetStatusChange.paReaderStats = paReaderStats;
            pCtx->u.GetStatusChange.cReaderStats = cReaderStats;

            VRDESCARDGETSTATUSCHANGEREQ req;
            req.Context = m_pRemote->context;
            req.u32Timeout = u32Timeout;
            req.cReaders = 1;
            req.aReaderStates[0].pszReader = &m_pRemote->reader.szReaderName[0];
            req.aReaderStates[0].u32CurrentState = paReaderStats[0].u32CurrentState;

            rc = vrdeSCardRequest(pCtx, VRDE_SCARD_FN_GETSTATUSCHANGE, &req, sizeof(req));

            if (RT_FAILURE(rc))
            {
                RTMemFree(pCtx);
            }
        }
    }

    return rc;
}

int UsbCardReader::Connect(struct USBCARDREADER *pDrv,
                           void *pvUser,
                           const char *pszReaderName,
                           uint32_t u32ShareMode,
                           uint32_t u32PreferredProtocols)
{
    AssertReturn(pDrv == mpDrv, VERR_NOT_SUPPORTED);

    int rc = VINF_SUCCESS;

    if (   !m_pRemote
        || !m_pRemote->fContext
        || !m_pRemote->reader.fAvailable)
    {
        rc = mpDrv->pICardReaderUp->pfnCardReaderUpConnect(mpDrv->pICardReaderUp,
                                                           pvUser,
                                                           VRDE_SCARD_E_NO_SMARTCARD,
                                                           VRDE_SCARD_PROTOCOL_T0);
    }
    else
    {
        UCRREQCTX *pCtx = (UCRREQCTX *)RTMemAlloc(sizeof(UCRREQCTX));
        if (!pCtx)
        {
            rc = mpDrv->pICardReaderUp->pfnCardReaderUpConnect(mpDrv->pICardReaderUp,
                                                               pvUser,
                                                               VRDE_SCARD_E_NO_MEMORY,
                                                               VRDE_SCARD_PROTOCOL_T0);
        }
        else
        {
            pCtx->pRemote = m_pRemote;
            pCtx->u32Function = VRDE_SCARD_FN_CONNECT;
            pCtx->pvUser = pvUser;

            VRDESCARDCONNECTREQ req;
            req.Context = m_pRemote->context;
            req.pszReader = &m_pRemote->reader.szReaderName[0];
            req.u32ShareMode = u32ShareMode;
            req.u32PreferredProtocols = u32PreferredProtocols;

            rc = vrdeSCardRequest(pCtx, VRDE_SCARD_FN_CONNECT, &req, sizeof(req));

            if (RT_FAILURE(rc))
            {
                RTMemFree(pCtx);
            }
        }
    }

    return rc;
}

int UsbCardReader::Disconnect(struct USBCARDREADER *pDrv,
                              void *pvUser,
                              uint32_t u32Mode)
{
    AssertReturn(pDrv == mpDrv, VERR_NOT_SUPPORTED);

    int rc = VINF_SUCCESS;

    if (   !m_pRemote
        || !m_pRemote->fContext
        || !m_pRemote->reader.fAvailable
        || !m_pRemote->reader.fHandle)
    {
        rc = mpDrv->pICardReaderUp->pfnCardReaderUpDisconnect(mpDrv->pICardReaderUp,
                                                              pvUser,
                                                              VRDE_SCARD_E_NO_SMARTCARD);
    }
    else
    {
        UCRREQCTX *pCtx = (UCRREQCTX *)RTMemAlloc(sizeof(UCRREQCTX));
        if (!pCtx)
        {
            rc = mpDrv->pICardReaderUp->pfnCardReaderUpDisconnect(mpDrv->pICardReaderUp,
                                                                  pvUser,
                                                                  VRDE_SCARD_E_NO_MEMORY);
        }
        else
        {
            pCtx->pRemote = m_pRemote;
            pCtx->u32Function = VRDE_SCARD_FN_DISCONNECT;
            pCtx->pvUser = pvUser;

            VRDESCARDDISCONNECTREQ req;
            req.hCard = m_pRemote->reader.hCard;
            req.u32Disposition = u32Mode;

            rc = vrdeSCardRequest(pCtx, VRDE_SCARD_FN_DISCONNECT, &req, sizeof(req));

            if (RT_FAILURE(rc))
            {
                RTMemFree(pCtx);
            }
            else
            {
                m_pRemote->reader.fHandle = false;
            }
        }
    }

    return rc;
}

int UsbCardReader::Status(struct USBCARDREADER *pDrv,
                          void *pvUser)
{
    AssertReturn(pDrv == mpDrv, VERR_NOT_SUPPORTED);

    int rc = VINF_SUCCESS;

    if (   !m_pRemote
        || !m_pRemote->fContext
        || !m_pRemote->reader.fAvailable
        || !m_pRemote->reader.fHandle)
    {
        rc = mpDrv->pICardReaderUp->pfnCardReaderUpStatus(mpDrv->pICardReaderUp,
                                                          pvUser,
                                                          VRDE_SCARD_E_NO_SMARTCARD,
                                                          /* pszReaderName */ NULL,
                                                          /* cchReaderName */ 0,
                                                          /* u32CardState */ 0,
                                                          /* u32Protocol */ 0,
                                                          /* pu8Atr */ 0,
                                                          /* cbAtr */ 0);
    }
    else
    {
        UCRREQCTX *pCtx = (UCRREQCTX *)RTMemAlloc(sizeof(UCRREQCTX));
        if (!pCtx)
        {
            rc = mpDrv->pICardReaderUp->pfnCardReaderUpStatus(mpDrv->pICardReaderUp,
                                                              pvUser,
                                                              VRDE_SCARD_E_NO_MEMORY,
                                                              /* pszReaderName */ NULL,
                                                              /* cchReaderName */ 0,
                                                              /* u32CardState */ 0,
                                                              /* u32Protocol */ 0,
                                                              /* pu8Atr */ 0,
                                                              /* cbAtr */ 0);
        }
        else
        {
            pCtx->pRemote = m_pRemote;
            pCtx->u32Function = VRDE_SCARD_FN_STATUS;
            pCtx->pvUser = pvUser;

            VRDESCARDSTATUSREQ req;
            req.hCard = m_pRemote->reader.hCard;

            rc = vrdeSCardRequest(pCtx, VRDE_SCARD_FN_STATUS, &req, sizeof(req));

            if (RT_FAILURE(rc))
            {
                RTMemFree(pCtx);
            }
        }
    }

    return rc;
}

int UsbCardReader::Transmit(struct USBCARDREADER *pDrv,
                            void *pvUser,
                            PDMICARDREADER_IO_REQUEST *pioSendRequest,
                            uint8_t *pu8SendBuffer,
                            uint32_t cbSendBuffer,
                            uint32_t cbRecvBuffer)
{
    AssertReturn(pDrv == mpDrv, VERR_NOT_SUPPORTED);

    int rc = VINF_SUCCESS;

    UCRREQCTX *pCtx = NULL;
    uint32_t rcSCard = VRDE_SCARD_S_SUCCESS;

    if (   !m_pRemote
        || !m_pRemote->fContext
        || !m_pRemote->reader.fAvailable
        || !m_pRemote->reader.fHandle)
    {
        rcSCard = VRDE_SCARD_E_NO_SMARTCARD;
    }

    if (rcSCard == VRDE_SCARD_S_SUCCESS)
    {
        if (   !pioSendRequest
            || (   pioSendRequest->cbPciLength < 2 *  sizeof(uint32_t)
                || pioSendRequest->cbPciLength > 2 *  sizeof(uint32_t) + VRDE_SCARD_MAX_PCI_DATA)
           )
        {
            AssertFailed();
            rcSCard = VRDE_SCARD_E_INVALID_PARAMETER;
        }
    }

    if (rcSCard == VRDE_SCARD_S_SUCCESS)
    {
        pCtx = (UCRREQCTX *)RTMemAlloc(sizeof(UCRREQCTX));
        if (!pCtx)
        {
            rcSCard = VRDE_SCARD_E_NO_MEMORY;
        }
    }

    if (rcSCard != VRDE_SCARD_S_SUCCESS)
    {
        Assert(pCtx == NULL);

        rc = pDrv->pICardReaderUp->pfnCardReaderUpTransmit(pDrv->pICardReaderUp,
                                                           pvUser,
                                                           rcSCard,
                                                           /* pioRecvPci */ NULL,
                                                           /* pu8RecvBuffer */ NULL,
                                                           /* cbRecvBuffer*/ 0);
    }
    else
    {
        pCtx->pRemote = m_pRemote;
        pCtx->u32Function = VRDE_SCARD_FN_TRANSMIT;
        pCtx->pvUser = pvUser;

        VRDESCARDTRANSMITREQ req;
        req.hCard = m_pRemote->reader.hCard;

        req.ioSendPci.u32Protocol = pioSendRequest->u32Protocol;
        req.ioSendPci.u32PciLength = pioSendRequest->cbPciLength < 2 * sizeof(uint32_t)?
                                         2 * sizeof(uint32_t):
                                         pioSendRequest->cbPciLength;
        Assert(pioSendRequest->cbPciLength <= VRDE_SCARD_MAX_PCI_DATA + 2 * sizeof(uint32_t));
        memcpy(req.ioSendPci.au8PciData,
               (uint8_t *)pioSendRequest + 2 * sizeof(uint32_t),
               req.ioSendPci.u32PciLength - 2 * sizeof(uint32_t));

        req.u32SendLength = cbSendBuffer;
        req.pu8SendBuffer = pu8SendBuffer;
        req.u32RecvLength = cbRecvBuffer;

        rc = vrdeSCardRequest(pCtx, VRDE_SCARD_FN_TRANSMIT, &req, sizeof(req));

        if (RT_FAILURE(rc))
        {
            RTMemFree(pCtx);
        }
    }

    return rc;
}

int UsbCardReader::Control(struct USBCARDREADER *pDrv,
                           void *pvUser,
                           uint32_t u32ControlCode,
                           uint8_t *pu8InBuffer,
                           uint32_t cbInBuffer,
                           uint32_t cbOutBuffer)
{
    AssertReturn(pDrv == mpDrv, VERR_NOT_SUPPORTED);

    int rc = VINF_SUCCESS;

    UCRREQCTX *pCtx = NULL;
    uint32_t rcSCard = VRDE_SCARD_S_SUCCESS;

    if (   !m_pRemote
        || !m_pRemote->fContext
        || !m_pRemote->reader.fAvailable
        || !m_pRemote->reader.fHandle)
    {
        rcSCard = VRDE_SCARD_E_NO_SMARTCARD;
    }

    if (rcSCard == VRDE_SCARD_S_SUCCESS)
    {
        if (   cbInBuffer > _128K
            || cbOutBuffer > _128K)
        {
            AssertFailed();
            rcSCard = VRDE_SCARD_E_INVALID_PARAMETER;
        }
    }

    if (rcSCard == VRDE_SCARD_S_SUCCESS)
    {
        pCtx = (UCRREQCTX *)RTMemAlloc(sizeof(UCRREQCTX));
        if (!pCtx)
        {
            rcSCard = VRDE_SCARD_E_NO_MEMORY;
        }
    }

    if (rcSCard != VRDE_SCARD_S_SUCCESS)
    {
        Assert(pCtx == NULL);

        rc = pDrv->pICardReaderUp->pfnCardReaderUpControl(pDrv->pICardReaderUp,
                                                          pvUser,
                                                          rcSCard,
                                                          u32ControlCode,
                                                          /* pvOutBuffer */ NULL,
                                                          /* cbOutBuffer*/ 0);
    }
    else
    {
        pCtx->pRemote = m_pRemote;
        pCtx->u32Function = VRDE_SCARD_FN_CONTROL;
        pCtx->pvUser = pvUser;
        pCtx->u.Control.u32ControlCode = u32ControlCode;

        VRDESCARDCONTROLREQ req;
        req.hCard = m_pRemote->reader.hCard;
        req.u32ControlCode = u32ControlCode;
        req.u32InBufferSize = cbInBuffer;
        req.pu8InBuffer = pu8InBuffer;
        req.u32OutBufferSize = cbOutBuffer;

        rc = vrdeSCardRequest(pCtx, VRDE_SCARD_FN_CONTROL, &req, sizeof(req));

        if (RT_FAILURE(rc))
        {
            RTMemFree(pCtx);
        }
    }

    return rc;
}

int UsbCardReader::GetAttrib(struct USBCARDREADER *pDrv,
                             void *pvUser,
                             uint32_t u32AttrId,
                             uint32_t cbAttrib)
{
    AssertReturn(pDrv == mpDrv, VERR_NOT_SUPPORTED);

    int rc = VINF_SUCCESS;

    UCRREQCTX *pCtx = NULL;
    uint32_t rcSCard = VRDE_SCARD_S_SUCCESS;

    if (   !m_pRemote
        || !m_pRemote->fContext
        || !m_pRemote->reader.fAvailable
        || !m_pRemote->reader.fHandle)
    {
        rcSCard = VRDE_SCARD_E_NO_SMARTCARD;
    }

    if (rcSCard == VRDE_SCARD_S_SUCCESS)
    {
        if (cbAttrib > _128K)
        {
            AssertFailed();
            rcSCard = VRDE_SCARD_E_INVALID_PARAMETER;
        }
    }

    if (rcSCard == VRDE_SCARD_S_SUCCESS)
    {
        pCtx = (UCRREQCTX *)RTMemAlloc(sizeof(UCRREQCTX));
        if (!pCtx)
        {
            rcSCard = VRDE_SCARD_E_NO_MEMORY;
        }
    }

    if (rcSCard != VRDE_SCARD_S_SUCCESS)
    {
        Assert(pCtx == NULL);

        pDrv->pICardReaderUp->pfnCardReaderUpGetAttrib(pDrv->pICardReaderUp,
                                                       pvUser,
                                                       rcSCard,
                                                       u32AttrId,
                                                       /* pvAttrib */ NULL,
                                                       /* cbAttrib */ 0);
    }
    else
    {
        pCtx->pRemote = m_pRemote;
        pCtx->u32Function = VRDE_SCARD_FN_GETATTRIB;
        pCtx->pvUser = pvUser;
        pCtx->u.GetAttrib.u32AttrId = u32AttrId;

        VRDESCARDGETATTRIBREQ req;
        req.hCard = m_pRemote->reader.hCard;
        req.u32AttrId = u32AttrId;
        req.u32AttrLen = cbAttrib;

        rc = vrdeSCardRequest(pCtx, VRDE_SCARD_FN_GETATTRIB, &req, sizeof(req));

        if (RT_FAILURE(rc))
        {
            RTMemFree(pCtx);
        }
    }

    return rc;
}

int UsbCardReader::SetAttrib(struct USBCARDREADER *pDrv,
                             void *pvUser,
                             uint32_t u32AttrId,
                             uint8_t *pu8Attrib,
                             uint32_t cbAttrib)
{
    AssertReturn(pDrv == mpDrv, VERR_NOT_SUPPORTED);

    int rc = VINF_SUCCESS;

    UCRREQCTX *pCtx = NULL;
    uint32_t rcSCard = VRDE_SCARD_S_SUCCESS;

    if (   !m_pRemote
        || !m_pRemote->fContext
        || !m_pRemote->reader.fAvailable
        || !m_pRemote->reader.fHandle)
    {
        rcSCard = VRDE_SCARD_E_NO_SMARTCARD;
    }

    if (rcSCard == VRDE_SCARD_S_SUCCESS)
    {
        if (cbAttrib > _128K)
        {
            AssertFailed();
            rcSCard = VRDE_SCARD_E_INVALID_PARAMETER;
        }
    }

    if (rcSCard == VRDE_SCARD_S_SUCCESS)
    {
        pCtx = (UCRREQCTX *)RTMemAlloc(sizeof(UCRREQCTX));
        if (!pCtx)
        {
            rcSCard = VRDE_SCARD_E_NO_MEMORY;
        }
    }

    if (rcSCard != VRDE_SCARD_S_SUCCESS)
    {
        Assert(pCtx == NULL);

        pDrv->pICardReaderUp->pfnCardReaderUpSetAttrib(pDrv->pICardReaderUp,
                                                       pvUser,
                                                       rcSCard,
                                                       u32AttrId);
    }
    else
    {
        pCtx->pRemote = m_pRemote;
        pCtx->u32Function = VRDE_SCARD_FN_SETATTRIB;
        pCtx->pvUser = pvUser;
        pCtx->u.SetAttrib.u32AttrId = u32AttrId;

        VRDESCARDSETATTRIBREQ req;
        req.hCard = m_pRemote->reader.hCard;
        req.u32AttrId = u32AttrId;
        req.u32AttrLen = cbAttrib;
        req.pu8Attr = pu8Attrib;

        rc = vrdeSCardRequest(pCtx, VRDE_SCARD_FN_SETATTRIB, &req, sizeof(req));

        if (RT_FAILURE(rc))
        {
            RTMemFree(pCtx);
        }
    }

    return rc;
}


/*
 * PDM
 */

/* static */ DECLCALLBACK(void *)UsbCardReader::drvQueryInterface(PPDMIBASE pInterface, const char *pszIID)
{
    LogFlowFunc(("pInterface:%p, pszIID:%s\n", pInterface, pszIID));
    PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
    PUSBCARDREADER pThis = PDMINS_2_DATA(pDrvIns, PUSBCARDREADER);

    PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
    PDMIBASE_RETURN_INTERFACE(pszIID, PDMICARDREADERDOWN, &pThis->ICardReaderDown);
    return NULL;
}

/* static */ DECLCALLBACK(int) UsbCardReader::drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
{
    LogFlowFunc(("iInstance/%d, pCfg:%p, fFlags:%x\n", pDrvIns->iInstance, pCfg, fFlags));
    PUSBCARDREADER pThis = PDMINS_2_DATA(pDrvIns, PUSBCARDREADER);

    if (!CFGMR3AreValuesValid(pCfg, "Object\0"))
        return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;
    AssertMsgReturn(PDMDrvHlpNoAttach(pDrvIns) == VERR_PDM_NO_ATTACHED_DRIVER,
                    ("Configuration error: Not possible to attach anything to this driver!\n"),
                    VERR_PDM_DRVINS_NO_ATTACH);

    void *pv;
    int rc = CFGMR3QueryPtr(pCfg, "Object", &pv);
    AssertMsgRCReturn(rc, ("Configuration error: No/bad \"Object\" value! rc=%Rrc\n", rc), rc);

    pThis->pUsbCardReader = (UsbCardReader *)pv;
    pThis->pUsbCardReader->mpDrv = pThis;
    pThis->pDrvIns = pDrvIns;

    pDrvIns->IBase.pfnQueryInterface = UsbCardReader::drvQueryInterface;

    pThis->ICardReaderDown.pfnCardReaderDownEstablishContext = drvCardReaderDownEstablishContext;
    pThis->ICardReaderDown.pfnCardReaderDownReleaseContext = drvCardReaderDownReleaseContext;
    pThis->ICardReaderDown.pfnCardReaderDownConnect = drvCardReaderDownConnect;
    pThis->ICardReaderDown.pfnCardReaderDownDisconnect = drvCardReaderDownDisconnect;
    pThis->ICardReaderDown.pfnCardReaderDownStatus = drvCardReaderDownStatus;
    pThis->ICardReaderDown.pfnCardReaderDownGetStatusChange = drvCardReaderDownGetStatusChange;
    pThis->ICardReaderDown.pfnCardReaderDownBeginTransaction = drvCardReaderDownBeginTransaction;
    pThis->ICardReaderDown.pfnCardReaderDownEndTransaction = drvCardReaderDownEndTransaction;
    pThis->ICardReaderDown.pfnCardReaderDownTransmit = drvCardReaderDownTransmit;
    pThis->ICardReaderDown.pfnCardReaderDownGetAttr = drvCardReaderDownGetAttr;
    pThis->ICardReaderDown.pfnCardReaderDownSetAttr = drvCardReaderDownSetAttr;
    pThis->ICardReaderDown.pfnCardReaderDownControl = drvCardReaderDownControl;

    pThis->pICardReaderUp = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMICARDREADERUP);
    AssertReturn(pThis->pICardReaderUp, VERR_PDM_MISSING_INTERFACE);

    /* Command Thread Synchronization primitives */
    rc = RTReqQueueCreate(&pThis->hReqQCardReaderCmd);
    AssertLogRelRCReturn(rc, rc);

    rc = PDMDrvHlpThreadCreate(pDrvIns,
                               &pThis->pThrCardReaderCmd,
                               pThis,
                               drvCardReaderThreadCmd /* worker routine */,
                               drvCardReaderThreadCmdWakeup /* wakeup routine */,
                               128 * _1K, RTTHREADTYPE_IO, "UCRCMD");
    if (RT_FAILURE(rc))
    {
        RTReqQueueDestroy(pThis->hReqQCardReaderCmd);
        pThis->hReqQCardReaderCmd = NIL_RTREQQUEUE;
    }

    LogFlowFunc(("LEAVE: %Rrc\n", rc));
    return rc;
}

/* static */ DECLCALLBACK(void) UsbCardReader::drvDestruct(PPDMDRVINS pDrvIns)
{
    LogFlowFunc(("iInstance/%d\n",pDrvIns->iInstance));
    PUSBCARDREADER pThis = PDMINS_2_DATA(pDrvIns, PUSBCARDREADER);

    /* @todo The driver is destroyed before the device.
     * So device calls ReleaseContext when there is no more driver.
     * Notify the device here so it can do cleanup or
     * do a cleanup now in the driver.
     */
    if (pThis->hReqQCardReaderCmd != NIL_RTREQQUEUE)
    {
        int rc = RTReqQueueDestroy(pThis->hReqQCardReaderCmd);
        AssertRC(rc);
        pThis->hReqQCardReaderCmd = NIL_RTREQQUEUE;
    }

    pThis->pUsbCardReader = NULL;
    LogFlowFuncLeave();
}

/* static */ const PDMDRVREG UsbCardReader::DrvReg =
{
    /* u32Version */
    PDM_DRVREG_VERSION,
    /* szName[32] */
    "UsbCardReader",
    /* szRCMod[32] */
    "",
    /* szR0Mod[32] */
    "",
    /* pszDescription */
    "Main Driver communicating with VRDE",
    /* fFlags */
    PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
    /* fClass */
    PDM_DRVREG_CLASS_USB,
    /* cMaxInstances */
    1,
    /* cbInstance */
    sizeof(USBCARDREADER),
    /* pfnConstruct */
    UsbCardReader::drvConstruct,
    /* pfnDestruct */
    UsbCardReader::drvDestruct,
    /* pfnRelocate */
    NULL,
    /* pfnIOCtl */
    NULL,
    /* pfnPowerOn */
    NULL,
    /* pfnReset */
    NULL,
    /* pfnSuspend */
    NULL,
    /* pfnResume */
    NULL,
    /* pfnAttach */
    NULL,
    /* pfnDetach */
    NULL,
    /* pfnPowerOff */
    NULL,
    /* pfnSoftReset */
    NULL,
    /* u32VersionEnd */
    PDM_DRVREG_VERSION
};
/* vi: set tabstop=4 shiftwidth=4 expandtab: */
