diff --git a/src/ccid.c b/src/ccid.c index a1c3b215..c2c37894 100644 --- a/src/ccid.c +++ b/src/ccid.c @@ -80,6 +80,15 @@ int ccid_open_hack_pre(unsigned int reader_index) /* The SCM SCL011 reader needs 350 ms to answer */ ccid_descriptor->readTimeout = DEFAULT_COM_READ_TIMEOUT * 4; break; + + case VMWARE_CCID: + /* This is not an actual reader, it's an emulated reader that + * acts as a proxy to the reader present on the host machine. + * Anounced dwFeatures are wrong, override them here. */ + ccid_descriptor->dwFeatures = 0x0002047E; + /* It also doesn't have any pinpad */ + ccid_descriptor->bPINSupport = 0; + break; } /* CCID */ diff --git a/src/ccid.h b/src/ccid.h index da0fd752..a8561b44 100644 --- a/src/ccid.h +++ b/src/ccid.h @@ -213,6 +213,7 @@ typedef struct #define ElatecTWN4 0x09D80427 #define SCM_SCL011 0x04E65293 #define HID_AVIATOR 0x076B3A21 +#define VMWARE_CCID 0x0E0F0004 #define VENDOR_GEMALTO 0x08E6 #define GET_VENDOR(readerID) ((readerID >> 16) & 0xFFFF) diff --git a/src/commands.c b/src/commands.c index 0dea0385..714337be 100644 --- a/src/commands.c +++ b/src/commands.c @@ -1121,8 +1121,10 @@ RESPONSECODE CmdGetSlotStatus(unsigned int reader_index, unsigned char buffer[]) unsigned char cmd[10]; status_t res; unsigned int length; + int retries = 2; RESPONSECODE return_value = IFD_SUCCESS; _ccid_descriptor *ccid_descriptor = get_ccid_descriptor(reader_index); + int saved_timeout = ccid_descriptor->readTimeout; #ifndef TWIN_SERIAL if (PROTOCOL_ICCD_A == ccid_descriptor->bInterfaceProtocol) @@ -1211,11 +1213,24 @@ RESPONSECODE CmdGetSlotStatus(unsigned int reader_index, unsigned char buffer[]) cmd[6] = (*ccid_descriptor->pbSeq)++; cmd[7] = cmd[8] = cmd[9] = 0; /* RFU */ + /* There is a bug when the reader sometimes ignores the first request + * and we get a timeout from libusb. Since we expect it let's reduce + * the timeout here to come back from it quickly. We'll restore the + * timeout on the retry */ + if (ccid_descriptor->readerID == VMWARE_CCID) + ccid_descriptor->readTimeout = 150; +again: res = WritePort(reader_index, sizeof(cmd), cmd); CHECK_STATUS(res) length = SIZE_GET_SLOT_STATUS; res = ReadPort(reader_index, &length, buffer); + if (ccid_descriptor->readerID == VMWARE_CCID && + res != STATUS_SUCCESS && retries > 0) { + retries--; + ccid_descriptor->readTimeout = saved_timeout; + goto again; + } CHECK_STATUS(res) if (length < STATUS_OFFSET+1)