UsbCardReader.cpp revision f4c45a1ca8a0bbdb88cf32e34c29474850ab0ee8
/* $Id$ */
/** @file
* UsbCardReader - Driver Interface to USB Smart Card Reader emulation.
*/
/*
* Copyright (C) 2011-2014 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->pfnSetStatusChange(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->pfnEstablishContext(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->pfnStatus(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->pfnConnect(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->pfnDisconnect(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->pfnTransmit(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->pfnGetAttrib(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->pfnSetAttrib(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->pfnControl(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->i_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->pfnSetStatusChange(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->pfnConnect(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->pfnDisconnect(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 = (uint32_t)strlen(pRsp->szReader) + 1;
u32CardState = pRsp->u32State;
u32Protocol = pRsp->u32Protocol;
u32AtrLength = pRsp->u32AtrLength;
pbAtr = &pRsp->au8Atr[0];
}
}
mpDrv->pICardReaderUp->pfnStatus(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->pfnTransmit(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->pfnControl(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->pfnGetAttrib(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->pfnSetAttrib(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->pfnEstablishContext(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->pfnSetStatusChange(mpDrv->pICardReaderUp,
pvUser,
VRDE_SCARD_E_NO_SMARTCARD,
paReaderStats,
cReaderStats);
}
else
{
UCRREQCTX *pCtx = (UCRREQCTX *)RTMemAlloc(sizeof(UCRREQCTX));
if (!pCtx)
{
rc = mpDrv->pICardReaderUp->pfnSetStatusChange(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->pfnConnect(mpDrv->pICardReaderUp,
pvUser,
VRDE_SCARD_E_NO_SMARTCARD,
VRDE_SCARD_PROTOCOL_T0);
}
else
{
UCRREQCTX *pCtx = (UCRREQCTX *)RTMemAlloc(sizeof(UCRREQCTX));
if (!pCtx)
{
rc = mpDrv->pICardReaderUp->pfnConnect(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->pfnDisconnect(mpDrv->pICardReaderUp,
pvUser,
VRDE_SCARD_E_NO_SMARTCARD);
}
else
{
UCRREQCTX *pCtx = (UCRREQCTX *)RTMemAlloc(sizeof(UCRREQCTX));
if (!pCtx)
{
rc = mpDrv->pICardReaderUp->pfnDisconnect(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->pfnStatus(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->pfnStatus(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->pfnTransmit(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->pfnControl(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->pfnGetAttrib(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->pfnSetAttrib(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;
}
/*
* PDMDRVINS
*/
/* 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(void) UsbCardReader::drvDestruct(PPDMDRVINS pDrvIns)
{
PDMDRV_CHECK_VERSIONS_RETURN_VOID(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;
}
/** @todo r=bird: why doesn't this set pThis->pUsbCardReader->mpDrv to NULL like
* everyone else? */
pThis->pUsbCardReader = NULL;
LogFlowFuncLeave();
}
/* static */ DECLCALLBACK(int) UsbCardReader::drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
{
PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
LogFlowFunc(("iInstance/%d, pCfg:%p, fFlags:%x\n", pDrvIns->iInstance, pCfg, fFlags));
PUSBCARDREADER pThis = PDMINS_2_DATA(pDrvIns, PUSBCARDREADER);
pThis->hReqQCardReaderCmd = NIL_RTREQQUEUE;
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.pfnEstablishContext = drvCardReaderDownEstablishContext;
pThis->ICardReaderDown.pfnReleaseContext = drvCardReaderDownReleaseContext;
pThis->ICardReaderDown.pfnConnect = drvCardReaderDownConnect;
pThis->ICardReaderDown.pfnDisconnect = drvCardReaderDownDisconnect;
pThis->ICardReaderDown.pfnStatus = drvCardReaderDownStatus;
pThis->ICardReaderDown.pfnGetStatusChange = drvCardReaderDownGetStatusChange;
pThis->ICardReaderDown.pfnBeginTransaction = drvCardReaderDownBeginTransaction;
pThis->ICardReaderDown.pfnEndTransaction = drvCardReaderDownEndTransaction;
pThis->ICardReaderDown.pfnTransmit = drvCardReaderDownTransmit;
pThis->ICardReaderDown.pfnGetAttr = drvCardReaderDownGetAttr;
pThis->ICardReaderDown.pfnSetAttr = drvCardReaderDownSetAttr;
pThis->ICardReaderDown.pfnControl = 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 */ 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: */