Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1315 lines
34 KiB

#include "gemcore.h"
#include "iopack.h"
#pragma PAGEDCODE
NTSTATUS CGemCore::read(CIoPacket* Irp)
{
NTSTATUS status;
ULONG ReplyLength;
ReplyLength = Irp->getReadLength();
TRACE("GemCore read requested...\n");
status = readAndWait((PUCHAR)Irp->getBuffer(),Irp->getReadLength(),(PUCHAR)Irp->getBuffer(),&ReplyLength);
if(!NT_SUCCESS(status)) ReplyLength = 0;
Irp->setInformation(ReplyLength);
TRACE("GemCore read response:\n");
//TRACE_BUFFER(Irp->getBuffer(),ReplyLength);
return status;
}
#pragma PAGEDCODE
NTSTATUS CGemCore::write(CIoPacket* Irp)
{
NTSTATUS status;
ULONG ReplyLength;
ReplyLength = Irp->getWriteLength();
TRACE("GemCore write requested...\n");
//TRACE_BUFFER(Irp->getBuffer(),Irp->getWriteLength());
status = writeAndWait((PUCHAR)Irp->getBuffer(),Irp->getReadLength(),(PUCHAR)Irp->getBuffer(),&ReplyLength);
if(!NT_SUCCESS(status)) ReplyLength = 0;
Irp->setInformation(ReplyLength);
TRACE("GemCore write response:\n");
//TRACE_BUFFER(Irp->getBuffer(),ReplyLength);
return status;
}
#pragma PAGEDCODE
// Reader interface functions...
NTSTATUS CGemCore::readAndWait(BYTE * pRequest,ULONG RequestLength,BYTE * pReply,ULONG* pReplyLength)
{
ULONG length;
ULONG BufferLength;
BOOL extendedCommand;
ULONG replyLength;
ULONG expectedReplyLength;
ULONG replyBufferPosition = 0;
if(!RequestLength || !pRequest || !pReply || !pReplyLength || RequestLength<5)
return STATUS_INVALID_PARAMETER;
length = pRequest[4];
if (!length || (length > READER_DATA_BUFFER_SIZE - 3))
{
// If the length is lower or equal to 252 (255 - (<IFD Status> + <SW1> + <SW2>))
// (standard OROS cmds)
extendedCommand = TRUE;
TRACE("******** EXTENDED COMMAND REQUESTED! ");
TRACE_BUFFER(pRequest,RequestLength);
if(!length) length = 256;
expectedReplyLength = length;
}
else extendedCommand = FALSE;
pOutputBuffer[0] = GEMCORE_CARD_READ;
memory->copy(pOutputBuffer+1,pRequest,5);
length = 6;
BufferLength = InputBufferLength;
NTSTATUS status = protocol->writeAndWait(pOutputBuffer,length,pInputBuffer,&BufferLength);
if(!NT_SUCCESS(status) || !BufferLength)
{
*pReplyLength = 0;
return status;
}
status = translateStatus(pInputBuffer[0],0);
if(!NT_SUCCESS(status))
{
*pReplyLength = 0;
return status;
}
// Extended command valid only if card reports 0 status!
if(pInputBuffer[0]!=0)
{
extendedCommand = FALSE;
}
// ISV: If card finish Xfer, do not send send second part of the command!
// This will fix CyberFlex card problem...
if(extendedCommand && BufferLength==3)
{
TRACE("******** EXTENDED COMMAND CANCELLED BY CARD REPLY!\n");
extendedCommand = FALSE;
}
// Skip status byte
replyLength = BufferLength - 1;
if(extendedCommand)
{
// Copy first part of the reply to the output buffer...
// Skip status byte.
if(*pReplyLength<(replyBufferPosition + replyLength))
{
*pReplyLength = 0;
return STATUS_INVALID_BUFFER_SIZE;
}
memory->copy(pReply,pInputBuffer+1, replyLength);
replyBufferPosition = replyLength;
// Read second block of data...
pOutputBuffer[0] = GEMCORE_CARD_READ;
memory->copy(pOutputBuffer+1,"\xFF\xFF\xFF\xFF", 4);
pOutputBuffer[5] = (BYTE ) (expectedReplyLength - replyLength);
length = 6;
BufferLength = InputBufferLength;
status = protocol->writeAndWait(pOutputBuffer,length,pInputBuffer,&BufferLength);
if(!NT_SUCCESS(status) || !BufferLength)
{
*pReplyLength = 0;
return status;
}
status = translateStatus(pInputBuffer[0],0);
if(!NT_SUCCESS(status))
{
*pReplyLength = 0;
return status;
}
// Skip status byte.
replyLength = BufferLength - 1;
}
if(*pReplyLength<(replyBufferPosition + replyLength))
{
TRACE("Gemcore: INVALID BUFFER LENGTH - buffer length %d, reply length %d\n",*pReplyLength,(replyBufferPosition + replyLength));
*pReplyLength = 0;
return STATUS_INVALID_BUFFER_SIZE;
}
// Skip status byte.
if(replyLength) memory->copy(pReply+replyBufferPosition,pInputBuffer+1, replyLength);
*pReplyLength = replyBufferPosition + replyLength;
TRACE("GemCore readAndWait() response with Length %d \n",*pReplyLength);
//TRACE_BUFFER(pReply,*pReplyLength);
return status;
}
#pragma PAGEDCODE
NTSTATUS CGemCore::writeAndWait(BYTE * pRequest,ULONG RequestLength,BYTE * pReply,ULONG* pReplyLength)
{
ULONG length;
ULONG BufferLength;
NTSTATUS status;
TRACE("\nGEMCORE WRITE:\n");
//TRACE_BUFFER(pRequest,RequestLength);
if(!RequestLength || !pRequest || RequestLength<5)
{
TRACE("\nGEMCORE WRITE: INVALID IN PARAMETERS...\n");
return STATUS_INVALID_PARAMETER;
}
length = pRequest[4];
if(RequestLength<length+5)
{
TRACE("\nGEMCORE WRITE: INVALID REQUESTED LENGTH...\n");
return STATUS_INVALID_PARAMETER;
}
if (length > READER_DATA_BUFFER_SIZE - 7)
{
// If the length is lower or equal than the extended available space (255)
// Prepare and send the first part of the extended ISO In command:
// The five command bytes are added in cmd buffer: 0xFF,0xFF,0xFF,0xFF,LN-248
// Read second block of data...
pOutputBuffer[0] = GEMCORE_CARD_WRITE;
memory->copy(pOutputBuffer+1,"\xFF\xFF\xFF\xFF", 4);
length = length - (READER_DATA_BUFFER_SIZE - 7);
pOutputBuffer[5] = (BYTE )length;
memory->copy(pOutputBuffer+6,pRequest + 5 + 248, length);
// Add size of header...
length += 6;
BufferLength = InputBufferLength;
status = protocol->writeAndWait(pOutputBuffer,length,pInputBuffer,&BufferLength);
if(!NT_SUCCESS(status) || !BufferLength)
{
return status;
}
if(!NT_SUCCESS(status))
{
return status;
}
// NOW prepare and send the Second part of the extended ISO In command:
// The five command bytes are added in cmd buffer.
// The data field is added (248 bytes).
// The command is sent to IFD.
// Now set length to first block of data...
length = 248;
}
pOutputBuffer[0] = GEMCORE_CARD_WRITE;
memory->copy(pOutputBuffer+1,pRequest,4);
pOutputBuffer[5] = pRequest[4]; // Warning you must specified full APDU length
memory->copy(pOutputBuffer+6,pRequest+5, length);
// Add size of header...
length += 6;
BufferLength = InputBufferLength;
status = protocol->writeAndWait(pOutputBuffer,length,pInputBuffer,&BufferLength);
if(!NT_SUCCESS(status) || !BufferLength)
{
*pReplyLength = 0;
return status;
}
status = translateStatus(pInputBuffer[0],0);
if(!NT_SUCCESS(status))
{
*pReplyLength = 0;
return status;
}
// Skip status byte.
length = BufferLength - 1;
if(*pReplyLength<length)
{
*pReplyLength = 0;
return STATUS_INVALID_BUFFER_SIZE;
}
// Skip status byte.
if(length) memory->copy(pReply,pInputBuffer+1, length);
*pReplyLength = length;
TRACE("GemCore writeAndWait() response\n");
//TRACE_BUFFER(pReply,*pReplyLength);
return status;
}
#pragma PAGEDCODE
ReaderConfig CGemCore::getConfiguration()
{
return configuration;
}
#pragma PAGEDCODE
NTSTATUS CGemCore::setConfiguration(ReaderConfig configuration)
{
this->configuration = configuration;
return STATUS_SUCCESS;
}
#pragma PAGEDCODE
NTSTATUS CGemCore::ioctl(ULONG ControlCode,BYTE* pRequest,ULONG RequestLength,BYTE* pReply,ULONG* pReplyLength)
{
ULONG length;
ULONG BufferLength;
NTSTATUS status;
TRACE("\nGEMCORE VendorIOCTL:\n");
//TRACE_BUFFER(pRequest,RequestLength);
if(!RequestLength || !pRequest)
{
TRACE("\nGEMCORE IOCTL: INVALID IN PARAMETERS...\n");
*pReplyLength = 0;
return STATUS_INVALID_PARAMETER;
}
memory->copy(pOutputBuffer,pRequest, RequestLength);
// Send direct gemcore command
BufferLength = InputBufferLength;
status = protocol->writeAndWait(pOutputBuffer,RequestLength,pInputBuffer,&BufferLength);
if(!NT_SUCCESS(status) || !BufferLength)
{
*pReplyLength = 0;
return status;
}
// NOTE: DO NOT TRANSLATE REPLY, USER REQUIRED TO GET THIS INFORMATION
// SO, keep status byte.
length = BufferLength;
if(*pReplyLength<length)
{
*pReplyLength = 0;
return STATUS_BUFFER_TOO_SMALL;
}
// Skip status byte.
if(length) memory->copy(pReply, pInputBuffer, length);
*pReplyLength = length;
TRACE("GemCore VendorIOCTL() response\n");
//TRACE_BUFFER(pReply,*pReplyLength);
return status;
}
#pragma PAGEDCODE
NTSTATUS CGemCore::SwitchSpeed(ULONG ControlCode,BYTE* pRequest,ULONG RequestLength,BYTE* pReply,ULONG* pReplyLength)
{
ULONG length;
ULONG BufferLength;
NTSTATUS status;
BYTE NewTA1;
TRACE("\nGEMCORE SwitchSpeed:\n");
//TRACE_BUFFER(pRequest,RequestLength);
if(!RequestLength || !pRequest)
{
TRACE("\nGEMCORE SwitchSpeed: INVALID IN PARAMETERS...\n");
*pReplyLength = 0;
return STATUS_INVALID_PARAMETER;
}
NewTA1 = pRequest[0];
// Modify speed value in reader's memory.
length = 6;
pOutputBuffer[0] = 0x23; // Write memory command
pOutputBuffer[1] = 0x01; // The type of memory is iData.
pOutputBuffer[2] = 0x00; // Address high byte.
pOutputBuffer[3] = 0x89; // Address low byte.
pOutputBuffer[4] = 0x01; // Number of byte to write
// New speed.
pOutputBuffer[5] = NewTA1;
// Send direct gemcore command
BufferLength = InputBufferLength;
status = protocol->writeAndWait(pOutputBuffer,length,pInputBuffer,&BufferLength);
if(!NT_SUCCESS(status) || !BufferLength)
{
*pReplyLength = 0;
return status;
}
length = BufferLength;
if(*pReplyLength<length)
{
*pReplyLength = 0;
return STATUS_BUFFER_TOO_SMALL;
}
// Copy the full reply
if(length) memory->copy(pReply, pInputBuffer, length);
*pReplyLength = length;
TRACE("GemCore SwitchSpeed() response\n");
//TRACE_BUFFER(pReply,*pReplyLength);
return status;
}
// TODO:
// ??????????????????
// It is specific to device not Gemcore
// I would suggest to move it into the specific reader object!
#pragma PAGEDCODE
NTSTATUS CGemCore::VendorAttribute(ULONG ControlCode,BYTE* pRequest,ULONG RequestLength,BYTE* pReply,ULONG* pReplyLength)
{
NTSTATUS status;
ULONG TagValue;
TRACE("\nGEMCORE VendorAttibute:\n");
//TRACE_BUFFER(pRequest,RequestLength);
if(!RequestLength || !pRequest)
{
TRACE("\nGEMCORE VendorAttibute: INVALID IN PARAMETERS...\n");
*pReplyLength = 0;
return STATUS_INVALID_PARAMETER;
}
if (RequestLength < sizeof(TagValue))
{
*pReplyLength = 0;
return STATUS_BUFFER_TOO_SMALL;
}
TagValue = (ULONG) *((PULONG)pRequest);
switch(ControlCode)
{
// Get an attribute
case IOCTL_SMARTCARD_VENDOR_GET_ATTRIBUTE:
switch (TagValue)
{
// Power Timeout (SCARD_ATTR_SPEC_POWER_TIMEOUT)
case SCARD_ATTR_SPEC_POWER_TIMEOUT:
if (*pReplyLength < (ULONG) sizeof(configuration.PowerTimeOut))
{
*pReplyLength = 0;
return STATUS_BUFFER_TOO_SMALL;
}
// Copy the value of PowerTimeout in the reply buffer
memory->copy(
pReply,
&configuration.PowerTimeOut,
sizeof(configuration.PowerTimeOut));
*pReplyLength = (ULONG)sizeof(configuration.PowerTimeOut);
status = STATUS_SUCCESS;
break;
case SCARD_ATTR_MANUFACTURER_NAME:
if (*pReplyLength < ATTR_LENGTH)
{
*pReplyLength = 0;
return STATUS_BUFFER_TOO_SMALL;
}
// Copy the value of PowerTimeout in the reply buffer
memory->copy(
pReply,
ATTR_MANUFACTURER_NAME,
sizeof(ATTR_MANUFACTURER_NAME));
*pReplyLength = (ULONG)sizeof(ATTR_MANUFACTURER_NAME);
status = STATUS_SUCCESS;
break;
case SCARD_ATTR_ORIGINAL_FILENAME:
if (*pReplyLength < ATTR_LENGTH)
{
*pReplyLength = 0;
return STATUS_BUFFER_TOO_SMALL;
}
// Copy the value of PowerTimeout in the reply buffer
memory->copy(
pReply,
ATTR_ORIGINAL_FILENAME,
sizeof(ATTR_ORIGINAL_FILENAME));
*pReplyLength = (ULONG)sizeof(ATTR_ORIGINAL_FILENAME);
status = STATUS_SUCCESS;
break;
// Unknown tag, we return STATUS_NOT_SUPPORTED
default:
*pReplyLength = 0;
status = STATUS_NOT_SUPPORTED;
}
break;
// Set the value of one tag (IOCTL_SMARTCARD_VENDOR_SET_ATTRIBUTE)
case IOCTL_SMARTCARD_VENDOR_SET_ATTRIBUTE:
switch (TagValue)
{
// Power Timeout (SCARD_ATTR_SPEC_POWER_TIMEOUT)
case SCARD_ATTR_SPEC_POWER_TIMEOUT:
if (RequestLength <(ULONG) (sizeof(configuration.PowerTimeOut) + sizeof(TagValue)))
{
*pReplyLength = 0;
return STATUS_BUFFER_TOO_SMALL;
}
memory->copy(
&configuration.PowerTimeOut,
pRequest + sizeof(TagValue),
sizeof(configuration.PowerTimeOut));
*pReplyLength = 0;
status = STATUS_SUCCESS;
break;
// Unknown tag, we return STATUS_NOT_SUPPORTED
default:
*pReplyLength = 0;
status = STATUS_NOT_SUPPORTED;
}
break;
default:
*pReplyLength = 0;
status = STATUS_NOT_SUPPORTED;
break;
}
TRACE("GemCore VendorAttibute() response\n");
//TRACE_BUFFER(pReply,*pReplyLength);
return status;
}
#pragma PAGEDCODE
NTSTATUS CGemCore::powerUp(BYTE* pReply,ULONG* pReplyLength)
{
BYTE CFG = 0,PCK;
ULONG length,i;
ULONG BufferLength;
NTSTATUS status;
switch(configuration.Voltage)
{
case CARD_VOLTAGE_3V: CFG = 0x02;break;
case CARD_VOLTAGE_5V: CFG = 0x01;break;
default: CFG = 0x00;break;
}
switch(configuration.PTSMode)
{
case PTS_MODE_DISABLED: CFG |= 0x10;break;
case PTS_MODE_OPTIMAL: CFG |= 0x20;break;
case PTS_MODE_MANUALLY: CFG |= 0x10;break;
case PTS_MODE_DEFAULT: CFG = 0x00;break; // do not add cfg field
default: CFG = 0x00;break; // same
}
length = 0;
pOutputBuffer[length++] = GEMCORE_CARD_POWER_UP;
// YN: if CFG = 0 that means we just need to do a power without CFG
// This append in the case with a card in specific mode (presence of TA2)
if(CFG) pOutputBuffer[length++] = CFG;
BufferLength = InputBufferLength;
protocol->set_WTR_Delay(protocol->get_Power_WTR_Delay());
status = protocol->writeAndWait(pOutputBuffer,length,pInputBuffer,&BufferLength);
protocol->set_Default_WTR_Delay();
if (NT_SUCCESS(status))
{
if(BufferLength)
{
BufferLength--;
TRACE("GemCore status %x\n",pInputBuffer[0]);
status = translateStatus(pInputBuffer[0],GEMCORE_CARD_POWER);
if(!NT_SUCCESS(status))
{
TRACE("GemCore FAILED TO POWER UP CARD! Status %x\n", status);
*pReplyLength = 0;
return status;
}
TRACE("GemCore power() ATR");
TRACE_BUFFER(pInputBuffer+1,BufferLength);
// Skip status byte and copy ATR
if(pInputBuffer[1]==0x3B || pInputBuffer[1]==0x3F)
{
memory->copy(pReply,pInputBuffer+1,BufferLength);
*pReplyLength = BufferLength;
}
else
{
*pReplyLength = 0;
return STATUS_UNSUCCESSFUL;
}
//return status; //YN: do not return now
}
else
{
*pReplyLength = 0;
return STATUS_UNSUCCESSFUL;
}
// YN: add PTS capabilities
if (pInputBuffer[0] == 0x00)
{
if(configuration.PTSMode == PTS_MODE_MANUALLY)
{
length = 0;
pOutputBuffer[length++] = GEMCORE_CARD_POWER_UP;
CFG |= 0xF0; //Manual PPS and 3V or 5V module
pOutputBuffer[length++] = CFG;
pOutputBuffer[length++] = configuration.PTS0;
if ((configuration.PTS0 & PTS_NEGOTIATE_PTS1) != 0) pOutputBuffer[length++] = configuration.PTS1;
if ((configuration.PTS0 & PTS_NEGOTIATE_PTS2) != 0) pOutputBuffer[length++] = configuration.PTS2;
if ((configuration.PTS0 & PTS_NEGOTIATE_PTS3) != 0) pOutputBuffer[length++] = configuration.PTS3;
// computes the exclusive-oring of all characters from CFG to PTS3
PCK = 0xFF;
for (i=2; i<length; i++) { PCK ^= pOutputBuffer[i];}
pOutputBuffer[length++] = PCK;
BufferLength = InputBufferLength;
protocol->set_WTR_Delay(protocol->get_Power_WTR_Delay());
status = protocol->writeAndWait(pOutputBuffer,length,pInputBuffer,&BufferLength);
protocol->set_Default_WTR_Delay();
// Copy into buffer only when it fail.
if (!NT_SUCCESS(status) || (BufferLength != 1) || (pInputBuffer[0] != 0x00))
{
*pReplyLength = BufferLength;
if (BufferLength > 1)
{
memory->copy(pReply,pInputBuffer,BufferLength);
}
}
return status;
}
}
}
else
{
*pReplyLength = 0;
}
return status;
}
#pragma PAGEDCODE
NTSTATUS CGemCore::power(ULONG ControlCode,BYTE* pReply,ULONG* pReplyLength, BOOLEAN Specific)
{
ULONG length;
ULONG BufferLength;
ULONG PreviousState;
NTSTATUS status;
switch(ControlCode)
{
case SCARD_COLD_RESET:
//ISV: First treat any card as ISO card on cold reset!
// Defines the type of the card (ISOCARD) and set the card presence
RestoreISOsetting();
length = 2;
BufferLength = InputBufferLength;
pOutputBuffer[0] = GEMCORE_DEFINE_CARD_TYPE;
pOutputBuffer[1] = (UCHAR)configuration.Type;
status = protocol->writeAndWait(pOutputBuffer,length,pInputBuffer,&BufferLength);
if(NT_SUCCESS(status))
{
if(BufferLength) status = translateStatus(pInputBuffer[0],GEMCORE_CARD_POWER);
}
if (!NT_SUCCESS(status))
{
return status;
}
if(Specific == FALSE)
{
//
// Just define card default values
//
RestoreISOsetting();
}
PreviousState = protocol->getCardState();
// Power down first for a cold reset
// YN : verify power state of card first
length = 0;
pOutputBuffer[length++] = GEMCORE_CARD_POWER_DOWN;
BufferLength = InputBufferLength;
status = protocol->writeAndWait(pOutputBuffer,length,pInputBuffer,&BufferLength);
if(NT_SUCCESS(status))
{
if(BufferLength) status = translateStatus(pInputBuffer[0],GEMCORE_CARD_POWER);
}
TRACE("GemCore powerDown() response\n");
//TRACE_BUFFER(pInputBuffer,BufferLength);
*pReplyLength = 0;
if(status != STATUS_SUCCESS)
{
return status;
}
// YN this is PowerTimeout must be a
if ((PreviousState & SCARD_POWERED) && (configuration.PowerTimeOut))
{
// Waits for the Power Timeout to be elapsed.
// before doing reset.
TRACE("GEMCORE power, ColdReset timeout %d ms\n", configuration.PowerTimeOut);
DELAY(configuration.PowerTimeOut);
}
case SCARD_WARM_RESET:
// If card have a Specific mode let Gemcore negociate properly with this card.
if(Specific)
{
// keep configuration of the reader.
configuration.PTSMode = PTS_MODE_DEFAULT;
status = powerUp(pReply, pReplyLength);
}
else if(configuration.Type == TRANSPARENT_MODE_CARD)
{
// ISV: Command 12 will fail in transparant mode...
// Let's set reader in ISO mode first!
TRACE(" WARM RESET for Transparent mode requested...\n");
RestoreISOsetting();
length = 2;
BufferLength = InputBufferLength;
pOutputBuffer[0] = GEMCORE_DEFINE_CARD_TYPE;
pOutputBuffer[1] = (UCHAR)configuration.Type;
status = protocol->writeAndWait(pOutputBuffer,length,pInputBuffer,&BufferLength);
if(NT_SUCCESS(status))
{
if(BufferLength) status = translateStatus(pInputBuffer[0],GEMCORE_CARD_POWER);
}
if (!NT_SUCCESS(status))
{
return status;
}
// do not lost transparent config on warm reset
// keep configuration of the reader.
status = powerUp(pReply, pReplyLength);
}
else
{
// Do a regular ISO reset
status = powerUp(pReply, pReplyLength);
}
return status;
break;
case SCARD_POWER_DOWN:
length = 0;
pOutputBuffer[length++] = GEMCORE_CARD_POWER_DOWN;
BufferLength = InputBufferLength;
status = protocol->writeAndWait(pOutputBuffer,length,pInputBuffer,&BufferLength);
if(NT_SUCCESS(status))
{
if(BufferLength) status = translateStatus(pInputBuffer[0],GEMCORE_CARD_POWER);
}
TRACE("GemCore powerDown() response\n");
//TRACE_BUFFER(pInputBuffer,BufferLength);
*pReplyLength = 0;
return status;
break;
}
*pReplyLength = 0;
return STATUS_INVALID_DEVICE_REQUEST;
}
#pragma PAGEDCODE
VOID CGemCore::cancel()
{
}
#pragma PAGEDCODE
NTSTATUS CGemCore::initialize()
{
TRACE("Initializing Gemcore interface...\n");
TRACE("Setting Gemcore reader mode...\n");
Initialized = TRUE;
Mode = READER_MODE_NATIVE;
NTSTATUS status = setReaderMode(READER_MODE_NATIVE);
if(!NT_SUCCESS(status))
{
TRACE("Failed to set Gemcore reader mode %x\n",READER_MODE_NATIVE);
return STATUS_INVALID_DEVICE_STATE;
}
TRACE("Getting Gemcore reader version...\n");
ULONG VersionLength = VERSION_STRING_MAX_LENGTH;
status = getReaderVersion(Version,&VersionLength);
if(!NT_SUCCESS(status))
{
TRACE("Failed to get GemCore reader interface version...\n");
return STATUS_INVALID_DEVICE_STATE;
}
else
{
Version[VersionLength] = 0x00;
TRACE("****** GemCore version - %s ******\n",Version);
}
TRACE("Gemcore interface initialized...\n");
return status;
}
#pragma PAGEDCODE
ULONG CGemCore::getReaderState()
{
ULONG BufferLength;
pOutputBuffer[0] = GEMCORE_GET_CARD_STATUS;
BufferLength = InputBufferLength;
NTSTATUS status = protocol->writeAndWait(pOutputBuffer,1,pInputBuffer,&BufferLength);
TRACE("GemCore getReaderState() response\n");
//TRACE_BUFFER(pInputBuffer,BufferLength);
if(!NT_SUCCESS(status) || !BufferLength || (BufferLength<2))
{
TRACE("FAILED!\n");
return SCARD_ABSENT;
}
if (!(pInputBuffer[1] & 0x04))
{
TRACE("*** Card is absent!\n");
return SCARD_ABSENT;
}
else
if (pInputBuffer[1] & 0x04)
{
TRACE("*** Card is present!\n");
return SCARD_SWALLOWED;
}
else
{
TRACE("Card state is unknown!\n");
return SCARD_ABSENT;
}
return SCARD_ABSENT;
}
#pragma PAGEDCODE
NTSTATUS CGemCore::getReaderVersion(PUCHAR pVersion, PULONG pLength)
{
ULONG BufferLength;
ULONG length;
if(!pVersion || !pLength) return STATUS_INVALID_PARAMETER;
length = sizeof(GEMCORE_GET_FIRMWARE_VERSION);
// Remove last 0x00
if(length) length--;
memory->copy(pOutputBuffer,GEMCORE_GET_FIRMWARE_VERSION,length);
BufferLength = InputBufferLength;
TRACE("getReaderVersion() \n");
//TRACE_BUFFER(pOutputBuffer,length);
NTSTATUS status = protocol->writeAndWait(pOutputBuffer,length,pInputBuffer,&BufferLength);
if(!NT_SUCCESS(status) || !BufferLength)
{
*pLength = 0;
return STATUS_UNSUCCESSFUL;
}
if (pInputBuffer[0])
{
*pLength = 0;
return translateStatus(pInputBuffer[0],0);
}
if(BufferLength-1 > *pLength)
{
BufferLength = *pLength;
}
// Remove status byte...
BufferLength--;
if(BufferLength) memory->copy(pVersion,pInputBuffer+1,BufferLength);
*pLength = BufferLength;
return STATUS_SUCCESS;
}
#pragma PAGEDCODE
NTSTATUS CGemCore::setReaderMode(ULONG mode)
{
BYTE CFG_BYTE;
ULONG BufferLength;
switch(mode)
{
case READER_MODE_NATIVE: CFG_BYTE = 0x00; break;
case READER_MODE_ROS: CFG_BYTE = 0x08; break;
case READER_MODE_TLP: CFG_BYTE = 0x09; break;
default: CFG_BYTE = 0x00; break;
}
pOutputBuffer[0] = GEMCORE_READER_SET_MODE;
pOutputBuffer[1] = 0x00;
pOutputBuffer[2] = CFG_BYTE;
BufferLength = InputBufferLength;
NTSTATUS status = protocol->writeAndWait(pOutputBuffer,3,pInputBuffer,&BufferLength);
if(!NT_SUCCESS(status))
{
TRACE("Failed to set reader mode...\n");
return status;
}
return status;
};
#pragma PAGEDCODE
NTSTATUS CGemCore::translateStatus( const BYTE ReaderStatus, const ULONG IoctlType)
{
switch (ReaderStatus)
{
case 0x00 : return STATUS_SUCCESS;
case 0x01 : return STATUS_NO_SUCH_DEVICE;
case 0x02 : return STATUS_NO_SUCH_DEVICE;
case 0x03 : return STATUS_INVALID_PARAMETER;
case 0x04 : return STATUS_IO_TIMEOUT;
case 0x05 : return STATUS_INVALID_PARAMETER;
case 0x09 : return STATUS_INVALID_PARAMETER;
case 0x10 : return STATUS_UNRECOGNIZED_MEDIA;
case 0x11 : return STATUS_UNRECOGNIZED_MEDIA;
case 0x12 : return STATUS_INVALID_PARAMETER;
case 0x13 : return STATUS_CONNECTION_ABORTED;
case 0x14 : return STATUS_UNRECOGNIZED_MEDIA;
case 0x15 : return STATUS_UNRECOGNIZED_MEDIA;
case 0x16 : return STATUS_INVALID_PARAMETER;
case 0x17 : return STATUS_UNRECOGNIZED_MEDIA;
case 0x18 : return STATUS_UNRECOGNIZED_MEDIA;
case 0x19 : return STATUS_INVALID_PARAMETER;
case 0x1A : return STATUS_INVALID_PARAMETER;
case 0x1B : return STATUS_INVALID_PARAMETER;
case 0x1C : return STATUS_INVALID_PARAMETER;
case 0x1D : return STATUS_UNRECOGNIZED_MEDIA;
case 0x1E : return STATUS_INVALID_PARAMETER;
case 0x1F : return STATUS_INVALID_PARAMETER;
case 0x20 : return STATUS_INVALID_PARAMETER;
case 0x30 : return STATUS_IO_TIMEOUT;
case 0xA0 : return STATUS_SUCCESS;
case 0xA1 : return STATUS_UNRECOGNIZED_MEDIA;
case 0xA2 :
if(IoctlType == GEMCORE_CARD_POWER) return STATUS_UNRECOGNIZED_MEDIA;
else return STATUS_IO_TIMEOUT;
case 0xA3 : return STATUS_PARITY_ERROR;
case 0xA4 : return STATUS_REQUEST_ABORTED;
case 0xA5 : return STATUS_REQUEST_ABORTED;
case 0xA6 : return STATUS_REQUEST_ABORTED;
case 0xA7 : return STATUS_UNRECOGNIZED_MEDIA;
case 0xCF : return STATUS_INVALID_PARAMETER;
case 0xE4 : return STATUS_UNRECOGNIZED_MEDIA;
case 0xE5 : return STATUS_SUCCESS;
case 0xE7 : return STATUS_SUCCESS;
case 0xF7 : return STATUS_NO_MEDIA;
case 0xF8 : return STATUS_UNRECOGNIZED_MEDIA;
case 0xFB : return STATUS_NO_MEDIA;
default : return STATUS_INVALID_PARAMETER;
}
}
#pragma PAGEDCODE
VOID CGemCore::RestoreISOsetting(VOID)
{
configuration.Type = ISO_CARD;//ISO_CARD (02)
configuration.PresenceDetection = DEFAULT_PRESENCE_DETECTION; // (0D)
configuration.Voltage = CARD_DEFAULT_VOLTAGE; //CARD_DEFAULT_VOLTAGE;
configuration.PTSMode = PTS_MODE_DISABLED; //PTS_MODE_DISABLED;
configuration.PTS0 = 0;
configuration.PTS1 = 0;
configuration.PTS2 = 0;
configuration.PTS3 = 0;
configuration.Vpp = 0; //CARD_DEFAULT_VPP;
configuration.ActiveProtocol = 0;// Undefined
}
#pragma PAGEDCODE
NTSTATUS CGemCore::setTransparentConfig(
PSCARD_CARD_CAPABILITIES cardCapabilities,
BYTE NewWtx
)
/*++
Routine Description:
Set the parameters of the transparent mode.
Arguments:
PSCARD_CARD_CAPABILITIES CardCapabilities - structure for card
NewWtx - holds the value (ms) of the new Wtx
--*/
{
LONG etu;
BYTE temp,mask,index;
ULONG Length, BufferLength;
NTSTATUS status;
TRACE("\nGEMCORE T1 setTransparentConfig Enter\n");
// Inverse or direct conversion
if (cardCapabilities->InversConvention)
configuration.transparent.CFG |= 0x20;
else
configuration.transparent.CFG &= 0xDF;
// Transparent T=1 like (with 1 byte for the length).
configuration.transparent.CFG |= 0x08;
// ETU = ((F[Fi]/D[Di]) - 1) / 3
etu = cardCapabilities->ClockRateConversion[
(BYTE) configuration.transparent.Fi].F;
if (cardCapabilities->BitRateAdjustment[
(BYTE) configuration.transparent.Fi].DNumerator) {
etu /= cardCapabilities->BitRateAdjustment[
(BYTE) configuration.transparent.Di].DNumerator;
}
etu -= 1;
etu /= 3;
configuration.transparent.ETU = (BYTE) ( 0x000000FF & etu);
if (cardCapabilities->N == 0xFF) {
configuration.transparent.EGT = (BYTE) 0x00;
} else {
configuration.transparent.EGT = (BYTE) cardCapabilities->N;
}
configuration.transparent.CWT = (BYTE) cardCapabilities->T1.CWI;
if (NewWtx) {
for (mask = 0x80,index = 8; index !=0x00; index--) {
temp = NewWtx & mask;
if (temp == mask)
break;
mask = mask/2;
}
configuration.transparent.BWI = cardCapabilities->T1.BWI + index;
} else {
configuration.transparent.BWI = cardCapabilities->T1.BWI;
}
Length = 6;
BufferLength = InputBufferLength;
pOutputBuffer[0] = GEMCORE_CARD_POWER_UP;
pOutputBuffer[1] = configuration.transparent.CFG;
pOutputBuffer[2] = configuration.transparent.ETU;
pOutputBuffer[3] = configuration.transparent.EGT;
pOutputBuffer[4] = configuration.transparent.CWT;
pOutputBuffer[5] = configuration.transparent.BWI;
status = protocol->writeAndWait(pOutputBuffer,Length,pInputBuffer,&BufferLength);
if(NT_SUCCESS(status))
{
if(BufferLength) status = translateStatus(pInputBuffer[0],GEMCORE_CARD_POWER);
}
TRACE("\nGEMCORE T1 setTransparentConfig Exit\n");
return status;
}
#pragma PAGEDCODE
NTSTATUS CGemCore::setProtocol(ULONG ProtocolRequested)
{
NTSTATUS status;
UCHAR Buffer[256];
ULONG BufferLength = 256;
switch(ProtocolRequested)
{
case SCARD_PROTOCOL_T1:
configuration.PTS0 = PTS_NEGOTIATE_T1 | PTS_NEGOTIATE_PTS1;
configuration.ActiveProtocol = SCARD_PROTOCOL_T1;
break;
case SCARD_PROTOCOL_T0:
configuration.PTS0 = PTS_NEGOTIATE_T0 | PTS_NEGOTIATE_PTS1;
configuration.ActiveProtocol = SCARD_PROTOCOL_T0;
default:
break;
}
// PTS1 has to be set before at power up...
//configuration.PTS1 = CardCapabilities->PtsData.Fl << 4 | CardCapabilities->PtsData.Dl;
if(configuration.PTSMode == PTS_MODE_MANUALLY)
{
status = powerUp(Buffer,&BufferLength);
}
else {
status = power(SCARD_COLD_RESET, Buffer, &BufferLength, FALSE);
}
if(NT_SUCCESS(status))
{
if(BufferLength) status = translateStatus(pInputBuffer[0],GEMCORE_CARD_POWER);
}
return status;
}
// TODO:
// What the purpose of the function?
// It's name does not tell anything...
// Actually it was suggested for the different purposes.
// Function has to be rewritten! It has a lot of mixed stuff like getting
// card status for example.
// ............................
//
// Use to made full T1 exchange in transparent mode
//
#pragma PAGEDCODE
NTSTATUS CGemCore::translate_request(BYTE * pRequest,ULONG RequestLength,BYTE * pReply,ULONG* pReplyLength, PSCARD_CARD_CAPABILITIES cardCapabilities, BYTE NewWtx)
{
NTSTATUS status;
UCHAR Cmd[256];
ULONG CmdLength = 0;
UCHAR Buffer[256];
ULONG BufferLength;
ULONG length;
//
// If the current card type <> TRANSPARENT_MODE_CARD
//
if (configuration.Type != TRANSPARENT_MODE_CARD)
{
// We read the status of the card to known the current voltage and the TA1
BufferLength = 256;
CmdLength = 1;
Cmd[0] = GEMCORE_GET_CARD_STATUS;
status = protocol->writeAndWait(Cmd,CmdLength,Buffer,&BufferLength);
// verify return code of reader
if(NT_SUCCESS(status))
{
if(BufferLength) status = translateStatus(Buffer[0],GEMCORE_CARD_POWER);
}
if (!NT_SUCCESS(status))
{
return status;
}
// Update Config
configuration.transparent.CFG = Buffer[1] & 0x01; //Vcc
configuration.transparent.Fi = Buffer[3] >>4; //Fi
configuration.transparent.Di = 0x0F & Buffer[3]; //Di
//We define the type of the card.
BufferLength = 256;
CmdLength = 2;
// assign TRANSPARENT_MODE_CARD
configuration.Type = TRANSPARENT_MODE_CARD;
Cmd[0] = GEMCORE_DEFINE_CARD_TYPE;
Cmd[1] = (BYTE) configuration.Type;
status = protocol->writeAndWait(Cmd,CmdLength,Buffer,&BufferLength);
if(NT_SUCCESS(status))
{
if(BufferLength) status = translateStatus(Buffer[0],GEMCORE_CARD_POWER);
}
if (!NT_SUCCESS(status))
{
return status;
}
// YN ? Mandatory!!! Else reader will be slow in T=1
// Set the transparent configuration
setTransparentConfig(cardCapabilities, NewWtx);
NewWtx = 0; // to not repeat again this call
}
///////
if(NewWtx)
{
setTransparentConfig(cardCapabilities, NewWtx);
}
TRACE("\nGEMCORE T1 translate_request:\n");
//TRACE_BUFFER(pRequest,RequestLength);
if(!RequestLength || !pRequest ) return STATUS_INVALID_PARAMETER;
length = RequestLength; // protocol
if (RequestLength >= READER_DATA_BUFFER_SIZE )
{
// If the length is upper than the standard available space (254)
// Then Send the last datas
// If the length is lower or equal than the extended available space (255)
// Prepare and send the first part of the extended ISO In command:
// The five command bytes are added in cmd buffer: 0xFF,0xFF,0xFF,0xFF,LN-248
// Read second block of data...
pOutputBuffer[0] = GEMCORE_CARD_WRITE; // specific for transparent exchange write long...
length = length - 254 + 1;
memory->copy(pOutputBuffer+1,pRequest + 254, length - 1);
// Add size of header...
length += 6;
BufferLength = InputBufferLength;
status = protocol->writeAndWait(pOutputBuffer,length,pInputBuffer,&BufferLength);
if(!NT_SUCCESS(status) || !BufferLength)
{
return status;
}
// prepare next paquet
length = 254;
}
pOutputBuffer[0] = GEMCORE_CARD_EXCHANGE;
memory->copy(pOutputBuffer +1 ,pRequest, length);
// Add size of header...
length += 1;
BufferLength = InputBufferLength;
status = protocol->writeAndWait(pOutputBuffer,length,pInputBuffer,&BufferLength);
if(!NT_SUCCESS(status) || !BufferLength)
{
*pReplyLength = 0;
return status;
}
// If the IFD signals more data to read...
// YN: 2 block for response...
if (BufferLength > 0 && pInputBuffer[0] == 0x1B)
{
ULONG BufferLength2 = 256;
UCHAR pInputBuffer2[256];
// Send a command to read the last data.
pOutputBuffer[0] = GEMCORE_CARD_READ; // specific for transparent exchange read long...
length = 1;
status = protocol->writeAndWait(pOutputBuffer,length,pInputBuffer2,&BufferLength2);
if(!NT_SUCCESS(status) || !BufferLength2)
{
*pReplyLength = 0;
return status;
}
if ((BufferLength + BufferLength2 - 2) > *pReplyLength)
{
*pReplyLength = 0;
return STATUS_INVALID_PARAMETER;
}
// Copy the last reader status
pInputBuffer[0] = pInputBuffer2[0];
status = translateStatus(pInputBuffer[0],0);
if(!NT_SUCCESS(status))
{
*pReplyLength = 0;
return status;
}
// Skip 2 status byte.
*pReplyLength = BufferLength + BufferLength2 - 2;
// Skip status byte.
if(*pReplyLength)
{
memory->copy(pReply,pInputBuffer+1, BufferLength -1);
memory->copy(pReply + (BufferLength-1), pInputBuffer2 +1, BufferLength2 -1);
}
TRACE("GemCore translate_request2 () response\n");
//TRACE_BUFFER(pReply,*pReplyLength);
return status;
}
status = translateStatus(pInputBuffer[0],0);
if(!NT_SUCCESS(status))
{
*pReplyLength = 0;
return status;
}
// Skip status byte.
length = BufferLength - 1;
if(*pReplyLength < length)
{
*pReplyLength = 0;
return STATUS_INVALID_BUFFER_SIZE;
}
// Skip status byte.
if(length)
{
memory->copy(pReply,pInputBuffer+1, length);
}
*pReplyLength = length;
TRACE("GemCore translate_request() response\n");
//TRACE_BUFFER(pReply,*pReplyLength);
return status;
};
// TODO:
// ???????????
#pragma PAGEDCODE
NTSTATUS CGemCore::translate_response(BYTE * pRequest,ULONG RequestLength,BYTE * pReply,ULONG* pReplyLength)
{
switch(configuration.ActiveProtocol)
{
case SCARD_PROTOCOL_T1:
break;
case SCARD_PROTOCOL_T0:
default:
break;
}
return STATUS_SUCCESS;
};