Index: /trunk/include/VBox/RemoteDesktop/VRDESCard.h
===================================================================
--- /trunk/include/VBox/RemoteDesktop/VRDESCard.h	(revision 41362)
+++ /trunk/include/VBox/RemoteDesktop/VRDESCard.h	(revision 41363)
@@ -150,7 +150,119 @@
 #define VRDE_SCARD_FN_SETATTRIB        16
 
-#define VRDESCARD_MAX_READERS 10
-#define VRDESCARD_MAX_ATR_LENGTH 36
-#define VRDESCARD_MAX_PCI_DATA 1024
+#define VRDE_SCARD_MAX_READERS 10
+#define VRDE_SCARD_MAX_ATR_LENGTH 36
+#define VRDE_SCARD_MAX_PCI_DATA 1024
+
+#define VRDE_SCARD_S_SUCCESS 0x00000000
+#define VRDE_SCARD_F_INTERNAL_ERROR 0x80100001
+#define VRDE_SCARD_E_CANCELLED 0x80100002
+#define VRDE_SCARD_E_INVALID_HANDLE 0x80100003
+#define VRDE_SCARD_E_INVALID_PARAMETER 0x80100004
+#define VRDE_SCARD_E_INVALID_TARGET 0x80100005
+#define VRDE_SCARD_E_NO_MEMORY 0x80100006
+#define VRDE_SCARD_F_WAITED_TOO_LONG 0x80100007
+#define VRDE_SCARD_E_INSUFFICIENT_BUFFER 0x80100008
+#define VRDE_SCARD_E_UNKNOWN_READER 0x80100009
+#define VRDE_SCARD_E_TIMEOUT 0x8010000A
+#define VRDE_SCARD_E_SHARING_VIOLATION 0x8010000B
+#define VRDE_SCARD_E_NO_SMARTCARD 0x8010000C
+#define VRDE_SCARD_E_UNKNOWN_CARD 0x8010000D
+#define VRDE_SCARD_E_CANT_DISPOSE 0x8010000E
+#define VRDE_SCARD_E_PROTO_MISMATCH 0x8010000F
+#define VRDE_SCARD_E_NOT_READY 0x80100010
+#define VRDE_SCARD_E_INVALID_VALUE 0x80100011
+#define VRDE_SCARD_E_SYSTEM_CANCELLED 0x80100012
+#define VRDE_SCARD_F_COMM_ERROR 0x80100013
+#define VRDE_SCARD_F_UNKNOWN_ERROR 0x80100014
+#define VRDE_SCARD_E_INVALID_ATR 0x80100015
+#define VRDE_SCARD_E_NOT_TRANSACTED 0x80100016
+#define VRDE_SCARD_E_READER_UNAVAILABLE 0x80100017
+#define VRDE_SCARD_P_SHUTDOWN 0x80100018
+#define VRDE_SCARD_E_PCI_TOO_SMALL 0x80100019
+#define VRDE_SCARD_E_ICC_INSTALLATION 0x80100020
+#define VRDE_SCARD_E_ICC_CREATEORDER 0x80100021
+#define VRDE_SCARD_E_UNSUPPORTED_FEATURE 0x80100022
+#define VRDE_SCARD_E_DIR_NOT_FOUND 0x80100023
+#define VRDE_SCARD_E_FILE_NOT_FOUND 0x80100024
+#define VRDE_SCARD_E_NO_DIR 0x80100025
+#define VRDE_SCARD_E_READER_UNSUPPORTED 0x8010001A
+#define VRDE_SCARD_E_DUPLICATE_READER 0x8010001B
+#define VRDE_SCARD_E_CARD_UNSUPPORTED 0x8010001C
+#define VRDE_SCARD_E_NO_SERVICE 0x8010001D
+#define VRDE_SCARD_E_SERVICE_STOPPED 0x8010001E
+#define VRDE_SCARD_E_UNEXPECTED 0x8010001F
+#define VRDE_SCARD_E_NO_FILE 0x80100026
+#define VRDE_SCARD_E_NO_ACCESS 0x80100027
+#define VRDE_SCARD_E_WRITE_TOO_MANY 0x80100028
+#define VRDE_SCARD_E_BAD_SEEK 0x80100029
+#define VRDE_SCARD_E_INVALID_CHV 0x8010002A
+#define VRDE_SCARD_E_UNKNOWN_RES_MSG 0x8010002B
+#define VRDE_SCARD_E_NO_SUCH_CERTIFICATE 0x8010002C
+#define VRDE_SCARD_E_CERTIFICATE_UNAVAILABLE 0x8010002D
+#define VRDE_SCARD_E_NO_READERS_AVAILABLE 0x8010002E
+#define VRDE_SCARD_E_COMM_DATA_LOST 0x8010002F
+#define VRDE_SCARD_E_NO_KEY_CONTAINER 0x80100030
+#define VRDE_SCARD_E_SERVER_TOO_BUSY 0x80100031
+#define VRDE_SCARD_E_PIN_CACHE_EXPIRED 0x80100032
+#define VRDE_SCARD_E_NO_PIN_CACHE 0x80100033
+#define VRDE_SCARD_E_READ_ONLY_CARD 0x80100034
+#define VRDE_SCARD_W_UNSUPPORTED_CARD 0x80100065
+#define VRDE_SCARD_W_UNRESPONSIVE_CARD 0x80100066
+#define VRDE_SCARD_W_UNPOWERED_CARD 0x80100067
+#define VRDE_SCARD_W_RESET_CARD 0x80100068
+#define VRDE_SCARD_W_REMOVED_CARD 0x80100069
+#define VRDE_SCARD_W_SECURITY_VIOLATION 0x8010006A
+#define VRDE_SCARD_W_WRONG_CHV 0x8010006B
+#define VRDE_SCARD_W_CHV_BLOCKED 0x8010006C
+#define VRDE_SCARD_W_EOF 0x8010006D
+#define VRDE_SCARD_W_CANCELLED_BY_USER 0x8010006E
+#define VRDE_SCARD_W_CARD_NOT_AUTHENTICATED 0x8010006F
+#define VRDE_SCARD_W_CACHE_ITEM_NOT_FOUND 0x80100070
+#define VRDE_SCARD_W_CACHE_ITEM_STALE 0x80100071
+#define VRDE_SCARD_W_CACHE_ITEM_TOO_BIG 0x80100072
+
+#define VRDE_SCARD_STATE_UNAWARE      0x0000
+#define VRDE_SCARD_STATE_IGNORE       0x0001
+#define VRDE_SCARD_STATE_CHANGED      0x0002
+#define VRDE_SCARD_STATE_UNKNOWN      0x0004
+#define VRDE_SCARD_STATE_UNAVAILABLE  0x0008
+#define VRDE_SCARD_STATE_EMPTY        0x0010
+#define VRDE_SCARD_STATE_PRESENT      0x0020
+#define VRDE_SCARD_STATE_ATRMATCH     0x0040
+#define VRDE_SCARD_STATE_EXCLUSIVE    0x0080
+#define VRDE_SCARD_STATE_INUSE        0x0100
+#define VRDE_SCARD_STATE_MUTE         0x0200
+#define VRDE_SCARD_STATE_UNPOWERED    0x0400
+#define VRDE_SCARD_STATE_MASK         UINT32_C(0x0000FFFF)
+#define VRDE_SCARD_STATE_COUNT_MASK   UINT32_C(0xFFFF0000)
+
+#define VRDE_SCARD_PROTOCOL_UNDEFINED 0x00000000
+#define VRDE_SCARD_PROTOCOL_T0 0x00000001
+#define VRDE_SCARD_PROTOCOL_T1 0x00000002
+#define VRDE_SCARD_PROTOCOL_Tx 0x00000003
+#define VRDE_SCARD_PROTOCOL_RAW 0x00010000
+
+#define VRDE_SCARD_PROTOCOL_DEFAULT 0x80000000
+#define VRDE_SCARD_PROTOCOL_OPTIMAL 0x00000000
+
+#define VRDE_SCARD_SHARE_EXCLUSIVE 0x00000001
+#define VRDE_SCARD_SHARE_SHARED 0x00000002
+#define VRDE_SCARD_SHARE_DIRECT 0x00000003
+
+/* u32Initialization, u32Disposition */
+#define VRDE_SCARD_LEAVE_CARD 0x00000000
+#define VRDE_SCARD_RESET_CARD 0x00000001
+#define VRDE_SCARD_UNPOWER_CARD 0x00000002
+#define VRDE_SCARD_EJECT_CARD 0x00000003
+
+/* VRDESCARDSTATUSRSP::u32State */
+#define VRDE_SCARD_UNKNOWN 0x00000000
+#define VRDE_SCARD_ABSENT 0x00000001
+#define VRDE_SCARD_PRESENT 0x00000002
+#define VRDE_SCARD_SWALLOWED 0x00000003
+#define VRDE_SCARD_POWERED 0x00000004
+#define VRDE_SCARD_NEGOTIABLE 0x00000005
+#define VRDE_SCARD_SPECIFICMODE 0x00000006
+
 
 /*
@@ -173,20 +285,20 @@
 {
     char *pszReader; /* UTF8 */
-    uint32_t u32CurrentState;
+    uint32_t u32CurrentState; /* VRDE_SCARD_STATE_* */
 } VRDESCARDREADERSTATECALL;
 
 typedef struct VRDESCARDREADERSTATERETURN
 {
-    uint32_t u32CurrentState;
-    uint32_t u32EventState;
+    uint32_t u32CurrentState; /* VRDE_SCARD_STATE_* */
+    uint32_t u32EventState; /* VRDE_SCARD_STATE_* */
     uint32_t u32AtrLength;
-    uint8_t au8Atr[VRDESCARD_MAX_ATR_LENGTH];
+    uint8_t au8Atr[VRDE_SCARD_MAX_ATR_LENGTH];
 } VRDESCARDREADERSTATERETURN;
 
 typedef struct VRDESCARDPCI
 {
-    uint32_t u32Protocol;
+    uint32_t u32Protocol; /* VRDE_SCARD_PROTOCOL_* */
     uint32_t u32PciLength; /* Includes u32Protocol and u32PciLength fields. 8 if no data in au8PciData. */
-    uint8_t au8PciData[VRDESCARD_MAX_PCI_DATA];
+    uint8_t au8PciData[VRDE_SCARD_MAX_PCI_DATA];
 } VRDESCARDPCI;
 
@@ -212,5 +324,5 @@
     uint32_t u32ReturnCode;
     uint32_t cReaders;
-    char *apszNames[VRDESCARD_MAX_READERS];  /* UTF8 */
+    char *apszNames[VRDE_SCARD_MAX_READERS];  /* UTF8 */
 } VRDESCARDLISTREADERSRSP;
 
@@ -228,7 +340,7 @@
 {
     VRDESCARDCONTEXT Context;
-    uint32_t u32Timeout;
+    uint32_t u32Timeout; /* Milliseconds. 0xFFFFFFFF = INFINITE */
     uint32_t cReaders;
-    VRDESCARDREADERSTATECALL aReaderStates[VRDESCARD_MAX_READERS];
+    VRDESCARDREADERSTATECALL aReaderStates[VRDE_SCARD_MAX_READERS];
 } VRDESCARDGETSTATUSCHANGEREQ;
 
@@ -237,5 +349,5 @@
     uint32_t u32ReturnCode;
     uint32_t cReaders;
-    VRDESCARDREADERSTATERETURN aReaderStates[VRDESCARD_MAX_READERS];
+    VRDESCARDREADERSTATERETURN aReaderStates[VRDE_SCARD_MAX_READERS];
 } VRDESCARDGETSTATUSCHANGERSP;
 
@@ -254,5 +366,5 @@
     VRDESCARDCONTEXT Context;
     char *pszReader; /* UTF8 */
-    uint32_t u32ShareMode;
+    uint32_t u32ShareMode; /* VRDE_SCARD_SHARE_* */
     uint32_t u32PreferredProtocols;
 } VRDESCARDCONNECTREQ;
@@ -323,5 +435,5 @@
     uint32_t u32Protocol;
     uint32_t u32AtrLength;
-    uint8_t au8Atr[VRDESCARD_MAX_ATR_LENGTH];
+    uint8_t au8Atr[VRDE_SCARD_MAX_ATR_LENGTH];
 } VRDESCARDSTATERSP;
 
@@ -338,5 +450,5 @@
     uint32_t u32Protocol;
     uint32_t u32AtrLength;
-    uint8_t au8Atr[VRDESCARD_MAX_ATR_LENGTH];
+    uint8_t au8Atr[VRDE_SCARD_MAX_ATR_LENGTH];
 } VRDESCARDSTATUSRSP;
 
Index: /trunk/include/VBox/vmm/pdmcardreaderinfs.h
===================================================================
--- /trunk/include/VBox/vmm/pdmcardreaderinfs.h	(revision 41363)
+++ /trunk/include/VBox/vmm/pdmcardreaderinfs.h	(revision 41363)
@@ -0,0 +1,116 @@
+/* $Id$ */
+
+/** @file
+ * cardreaderinfs - interface between Usb Card Reader device and its driver.
+ */
+
+/*
+ * 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.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef ___VBox_vmm_pdmcardreaderinfs_h
+# define ___VBox_vmm_pdmcardreaderinfs_h
+
+#include <VBox/types.h>
+
+#define PDMICARDREADERDOWN_IID  "78d65378-889c-4418-8bc2-7a89a5af2817"
+
+typedef struct PDMICARDREADER_IO_REQUEST
+{
+    uint32_t u32Protocol;  /* Protocol identifier */
+    uint32_t cbPciLength;  /* Protocol Control Information Length */
+    /* 'cbPciLength - 8' bytes of control info may follow. */
+} PDMICARDREADER_IO_REQUEST;
+
+typedef struct PDMICARDREADER_READERSTATE
+{
+    char *pszReaderName;
+    uint32_t u32CurrentState; /* Current state of reader at time of call. */
+    uint32_t u32EventState;   /* State of reader after state change */
+    uint32_t cbAtr;           /* Number of bytes in the returned ATR. */
+    uint8_t au8Atr[36];       /* Atr of inserted card, (extra alignment bytes) */
+} PDMICARDREADER_READERSTATE;
+
+
+typedef struct PDMICARDREADERDOWN PDMICARDREADERDOWN;
+typedef PDMICARDREADERDOWN *PPDMICARDREADERDOWN;
+struct PDMICARDREADERDOWN
+{
+    DECLR3CALLBACKMEMBER(int, pfnCardReaderDownEstablishContext,(PPDMICARDREADERDOWN pInterface));
+    DECLR3CALLBACKMEMBER(int, pfnCardReaderDownConnect,(PPDMICARDREADERDOWN pInterface, void *pvUser, const char *pszCardReaderName,
+                                                        uint32_t u32ShareMode, uint32_t u32PreferredProtocols));
+    DECLR3CALLBACKMEMBER(int, pfnCardReaderDownDisconnect,(PPDMICARDREADERDOWN pInterface, void *pvUser,
+                                                           uint32_t u32Disposition));
+    DECLR3CALLBACKMEMBER(int, pfnCardReaderDownStatus,(PPDMICARDREADERDOWN pInterface, void *pvUser,
+                                                       uint32_t cchReaderName, uint32_t cbAtrLen));
+    DECLR3CALLBACKMEMBER(int, pfnCardReaderDownReleaseContext,(PPDMICARDREADERDOWN pInterface, void *pvUser));
+    DECLR3CALLBACKMEMBER(int, pfnCardReaderDownGetStatusChange,(PPDMICARDREADERDOWN pInterface, void *pvUser,
+                                                                uint32_t u32Timeout, PDMICARDREADER_READERSTATE *paReaderStats, uint32_t cReaderStats));
+    DECLR3CALLBACKMEMBER(int, pfnCardReaderDownBeginTransaction,(PPDMICARDREADERDOWN pInterface, void *pvUser));
+    DECLR3CALLBACKMEMBER(int, pfnCardReaderDownEndTransaction,(PPDMICARDREADERDOWN pInterface, void *pvUser,
+                                                               uint32_t u32Disposition));
+    DECLR3CALLBACKMEMBER(int, pfnCardReaderDownTransmit,(PPDMICARDREADERDOWN pInterface, void *pvUser,
+                                                         const PDMICARDREADER_IO_REQUEST *pioSendRequest,
+                                                         const uint8_t *pu8SendBuffer, uint32_t cbSendBuffer, uint32_t cbRecvBuffer));
+    /**
+     * Up level provides pvInBuffer of cbInBuffer bytes to call SCardControl, also it specify bytes it expects to receive
+     * @note: device/driver implementation should copy buffers before execution in async mode, and both layers shouldn't
+     * expect permanent storage for the buffer.
+     */
+    DECLR3CALLBACKMEMBER(int, pfnCardReaderDownControl,(PPDMICARDREADERDOWN pInterface, void *pvUser,
+                                                        uint32_t u32ControlCode, const void *pvInBuffer, uint32_t cbInBuffer, uint32_t cbOutBuffer));
+    /**
+     * This function ask driver to provide attribute (dwAttribId) and provide limit (cbAttrib) of buffer size for attribute value,
+     * Callback UpGetAttrib returns buffer containing the value and altered size of the buffer.
+     */
+    DECLR3CALLBACKMEMBER(int, pfnCardReaderDownGetAttr,(PPDMICARDREADERDOWN pInterface, void *pvUser,
+                                                        uint32_t u32AttribId, uint32_t cbAttrib));
+    DECLR3CALLBACKMEMBER(int, pfnCardReaderDownSetAttr,(PPDMICARDREADERDOWN pInterface, void *pvUser,
+                                                        uint32_t u32AttribId, const void *pvAttrib, uint32_t cbAttrib));
+};
+
+#define PDMICARDREADERUP_IID    "c0d7498e-0635-48ca-aab1-b11b6a55cf7d"
+typedef struct PDMICARDREADERUP PDMICARDREADERUP;
+typedef PDMICARDREADERUP *PPDMICARDREADERUP;
+struct PDMICARDREADERUP
+{
+    DECLR3CALLBACKMEMBER(int, pfnCardReaderUpEstablishContext,(PPDMICARDREADERUP pInterface, int32_t lSCardRc));
+    DECLR3CALLBACKMEMBER(int, pfnCardReaderUpStatus,(PPDMICARDREADERUP pInterface, void *pvUser, int32_t lSCardRc,
+                                                     char *pszReaderName, uint32_t cchReaderName, uint32_t u32CardState,
+                                                     uint32_t u32Protocol, uint8_t *pu8Atr, uint32_t cbAtr));
+    DECLR3CALLBACKMEMBER(int, pfnCardReaderUpConnect,(PPDMICARDREADERUP pInterface, void *pvUser, int32_t lSCardRc,
+                                                      uint32_t u32ActiveProtocol));
+    DECLR3CALLBACKMEMBER(int, pfnCardReaderUpDisconnect,(PPDMICARDREADERUP pInterface, void *pvUser, int32_t lSCardRc));
+    DECLR3CALLBACKMEMBER(int, pfnCardReaderUpSetStatusChange,(PPDMICARDREADERUP pInterface, void *pvUser, int32_t lSCardRc,
+                                                              PDMICARDREADER_READERSTATE *paReaderStats, uint32_t cReaderStats));
+    DECLR3CALLBACKMEMBER(int, pfnCardReaderUpBeginTransaction,(PPDMICARDREADERUP pInterface, void *pvUser, int32_t lSCardRc));
+    DECLR3CALLBACKMEMBER(int, pfnCardReaderUpEndTransaction,(PPDMICARDREADERUP pInterface, void *pvUser, int32_t lSCardRc));
+    /* Note: pioRecvPci stack variable */
+    DECLR3CALLBACKMEMBER(int, pfnCardReaderUpTransmit,(PPDMICARDREADERUP pInterface, void *pvUser, int32_t lSCardRc,
+                                                       const PDMICARDREADER_IO_REQUEST *pioRecvPci, uint8_t *pu8RecvBuffer, uint32_t cbRecvBuffer));
+    DECLR3CALLBACKMEMBER(int, pfnCardReaderUpControl,(PPDMICARDREADERUP pInterface, void *pvUser, int32_t lSCardRc,
+                                                      uint32_t u32ControlCode, void *pvOutBuffer, uint32_t cbOutBuffer));
+    DECLR3CALLBACKMEMBER(int, pfnCardReaderUpGetAttrib,(PPDMICARDREADERUP pInterface, void *pvUser, int32_t lSCardRc,
+                                                        uint32_t u32AttribId, void *pvAttrib, uint32_t cbAttrib));
+    DECLR3CALLBACKMEMBER(int, pfnCardReaderUpSetAttrib,(PPDMICARDREADERUP pInterface, void *pvUser, int32_t lSCardRc,
+                                                        uint32_t u32AttribId));
+};
+
+#endif
Index: /trunk/src/VBox/Main/include/UsbCardReader.h
===================================================================
--- /trunk/src/VBox/Main/include/UsbCardReader.h	(revision 41363)
+++ /trunk/src/VBox/Main/include/UsbCardReader.h	(revision 41363)
@@ -0,0 +1,72 @@
+/* $Id$ */
+
+/** @file
+ * VirtualBox Driver interface to the virtual Usb Card Reader.
+ */
+
+/*
+ * 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.
+ */
+
+#ifndef ____H_USBCARDREADER
+#define ____H_USBCARDREADER
+
+#include <VBox/vmm/pdmcardreaderinfs.h>
+#include <VBox/vmm/pdmdrv.h>
+
+class Console;
+typedef struct USBCARDREADER USBCARDREADER;
+typedef struct UCRREMOTE UCRREMOTE;
+
+class UsbCardReader
+{
+    public:
+        UsbCardReader(Console *console);
+        virtual ~UsbCardReader();
+
+        static const PDMDRVREG DrvReg;
+        USBCARDREADER *mpDrv;
+
+        Console *getParent(void) { return mParent; }
+
+        int VRDENotify(uint32_t u32Id, void *pvData, uint32_t cbData);
+        int VRDEResponse(int rcRequest, void *pvUser, uint32_t u32Function, void *pvData, uint32_t cbData);
+
+        int EstablishContext(USBCARDREADER *pDrv);
+        int ReleaseContext(USBCARDREADER *pDrv);
+        int GetStatusChange(USBCARDREADER *pDrv, void *pvUser, uint32_t u32Timeout,
+                            PDMICARDREADER_READERSTATE *paReaderStats, uint32_t cReaderStats);
+        int Connect(USBCARDREADER *pDrv, void *pvUser, const char *pszReaderName,
+                    uint32_t u32ShareMode, uint32_t u32PreferredProtocols);
+        int Disconnect(USBCARDREADER *pDrv, void *pvUser, uint32_t u32Mode);
+        int Status(USBCARDREADER *pDrv, void *pvUser);
+        int Transmit(USBCARDREADER *pDrv, void *pvUser, PDMICARDREADER_IO_REQUEST *pioSendRequest,
+                     uint8_t *pu8SendBuffer, uint32_t cbSendBuffer, uint32_t cbRecvBuffer);
+        int Control(USBCARDREADER *pDrv, void *pvUser, uint32_t u32ControlCode,
+                    uint8_t *pu8InBuffer, uint32_t cbInBuffer, uint32_t cbOutBuffer);
+        int GetAttrib(USBCARDREADER *pDrv, void *pvUser, uint32_t u32AttrId, uint32_t cbAttrib);
+        int SetAttrib(USBCARDREADER *pDrv, void *pvUser, uint32_t u32AttrId,
+                      uint8_t *pu8Attrib, uint32_t cbAttrib);
+
+    private:
+        static DECLCALLBACK(void *) drvQueryInterface(PPDMIBASE pInterface, const char *pszIID);
+        static DECLCALLBACK(int)    drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags);
+        static DECLCALLBACK(void)   drvDestruct(PPDMDRVINS pDrvIns);
+
+        int vrdeSCardRequest(void *pvUser, uint32_t u32Function, const void *pvData, uint32_t cbData);
+
+        Console * const mParent;
+
+        UCRREMOTE *m_pRemote;
+};
+
+#endif /* !____H_USBCARDREADER */
+/* vi: set tabstop=4 shiftwidth=4 expandtab: */
Index: /trunk/src/VBox/Main/src-client/UsbCardReader.cpp
===================================================================
--- /trunk/src/VBox/Main/src-client/UsbCardReader.cpp	(revision 41363)
+++ /trunk/src/VBox/Main/src-client/UsbCardReader.cpp	(revision 41363)
@@ -0,0 +1,1965 @@
+/* $Id$ */
+
+/** @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>
+
+
+/*******************************************************************************
+*   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,
+                                                  const char *pcszCardReaderName,
+                                                  void *pvUser,
+                                                  uint32_t u32ShareMode,
+                                                  uint32_t u32PreferredProtocols)
+{
+    LogFlowFunc(("ENTER: pcszCardReaderName:%s, pvUser:%p, u32ShareMode:%RX32, u32PreferredProtocols:%RX32\n",
+                 pcszCardReaderName, pvUser, 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));
+            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));
+            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));
+            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));
+            VRDESCARDGETSTATUSCHANGERSP *pRsp = (VRDESCARDGETSTATUSCHANGERSP *)pvData;
+            UCRREQCTX *pCtx = (UCRREQCTX *)pvUser;
+
+            Assert(pCtx->u32Function == u32Function);
+
+            LogFlowFunc(("GETSTATUSCHANGE\n"));
+
+            uint32_t rcCard;
+            if (RT_FAILURE(rc))
+            {
+                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));
+            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));
+            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(rc))
+            {
+                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));
+            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));
+            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(rc))
+            {
+                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));
+            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));
+            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));
+            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));
+            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(rc))
+            {
+                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));
+            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(rc))
+            {
+                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));
+            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(rc))
+            {
+                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));
+            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(rc))
+            {
+                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));
+            VRDESCARDSETATTRIBRSP *pRsp = (VRDESCARDSETATTRIBRSP *)pvData;
+            UCRREQCTX *pCtx = (UCRREQCTX *)pvUser;
+
+            Assert(pCtx->u32Function == u32Function);
+
+            LogFlowFunc(("SETATTRIB\n"));
+
+            uint32_t rcCard;
+
+            if (RT_FAILURE(rc))
+            {
+                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,
+                                                           SCARD_PROTOCOL_T0);
+    }
+    else
+    {
+        UCRREQCTX *pCtx = (UCRREQCTX *)RTMemAlloc(sizeof(UCRREQCTX));
+        if (!pCtx)
+        {
+            rc = mpDrv->pICardReaderUp->pfnCardReaderUpConnect(mpDrv->pICardReaderUp,
+                                                               pvUser,
+                                                               VRDE_SCARD_E_NO_MEMORY,
+                                                               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: */
