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.
874 lines
20 KiB
874 lines
20 KiB
/*++
|
|
Copyright (c) 1998 Gemplus Development
|
|
|
|
Name:
|
|
gprelcmd.c
|
|
|
|
Description:
|
|
This module holds the functions used for the PC Card I/O.
|
|
Environment:
|
|
Kernel Mode
|
|
|
|
Revision History:
|
|
06/04/99: (Y. Nadeau + M. Veillette)
|
|
- Code Review
|
|
24/03/99: V1.00.004 (Y. Nadeau)
|
|
- Fix to GprllWait to work in DPC
|
|
06/05/98: V1.00.003 (P. Plouidy)
|
|
- Power management for NT5
|
|
10/02/98: V1.00.002 (P. Plouidy)
|
|
- Plug and Play for NT5
|
|
03/07/97: V1.00.001 (P. Plouidy)
|
|
- Start of development.
|
|
|
|
|
|
--*/
|
|
|
|
|
|
//
|
|
// Include section:
|
|
// - stdio.h: standards definitons.
|
|
// - ntddk.h: DDK Windows NT general definitons.
|
|
// - ntdef.h: Windows NT general definitons.
|
|
//
|
|
#include <stdio.h>
|
|
#include <ntddk.h>
|
|
#include <ntdef.h>
|
|
|
|
#include "gprelcmd.h"
|
|
|
|
//
|
|
// Function definition section:
|
|
//
|
|
|
|
#if DBG
|
|
void GPR_Debug_Buffer(
|
|
PUCHAR pBuffer,
|
|
DWORD Lenght)
|
|
{
|
|
USHORT index;
|
|
|
|
SmartcardDebug(
|
|
DEBUG_TRACE,
|
|
(" LEN=%d CMD=",
|
|
Lenght)
|
|
);
|
|
for(index=0;index<Lenght;index++)
|
|
{
|
|
SmartcardDebug(
|
|
DEBUG_TRACE,
|
|
("%02X,",
|
|
pBuffer[index])
|
|
);
|
|
}
|
|
SmartcardDebug(
|
|
DEBUG_TRACE,
|
|
("\n")
|
|
);
|
|
}
|
|
#endif
|
|
|
|
|
|
|
|
NTSTATUS GDDK_Translate(
|
|
const BYTE IFDStatus,
|
|
const UCHAR Tag
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Translate IFD status in NT status codes.
|
|
|
|
Arguments:
|
|
|
|
IFDStatus - is the value to translate.
|
|
IoctlType - is the current smart card ioctl.
|
|
|
|
Return Value:
|
|
|
|
the translated code status.
|
|
|
|
--*/
|
|
{
|
|
switch (IFDStatus)
|
|
{
|
|
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 0x0C : return STATUS_DEVICE_PROTOCOL_ERROR;
|
|
case 0x0D : return STATUS_SUCCESS;
|
|
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 (Tag == OPEN_SESSION_CMD)
|
|
{ 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;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description :
|
|
Read a byte at IO address
|
|
|
|
--*/
|
|
BOOLEAN G_ReadByte(const USHORT BIOAddr,UCHAR *Value)
|
|
{
|
|
*Value = READ_PORT_UCHAR((PUCHAR) BIOAddr);
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description :
|
|
Write a byte at IO address
|
|
|
|
--*/
|
|
BOOLEAN G_WriteByte(const USHORT BIOAddr,UCHAR *Value)
|
|
{
|
|
WRITE_PORT_UCHAR((PUCHAR) BIOAddr,*Value);
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description :
|
|
Read a buffer of "Len" bytes at IO address
|
|
--*/
|
|
BOOLEAN G_ReadBuf(const USHORT BIOAddr,const USHORT Len,UCHAR *Buffer)
|
|
{
|
|
USHORT i;
|
|
|
|
for(i=0;i<Len;i++)
|
|
{
|
|
*(Buffer+i) = READ_PORT_UCHAR((UCHAR *) UlongToPtr(BIOAddr+i));
|
|
}
|
|
#if DBG
|
|
// Excluse reader status reply
|
|
if(! ((Buffer[0] == 0xA2) && (Buffer[1]==4)) )
|
|
{
|
|
SmartcardDebug(
|
|
DEBUG_TRACE,
|
|
("%s!G_ReadBuf:",
|
|
SC_DRIVER_NAME)
|
|
);
|
|
GPR_Debug_Buffer(Buffer, Len );
|
|
}
|
|
#endif
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description :
|
|
Write a buffer of "Len" bytes at IO address
|
|
--*/
|
|
BOOLEAN G_WriteBuf(const USHORT BIOAddr,const USHORT Len,UCHAR *Buffer)
|
|
{
|
|
|
|
USHORT i;
|
|
|
|
for(i=0;i<Len;i++)
|
|
{
|
|
WRITE_PORT_UCHAR((UCHAR *) UlongToPtr(BIOAddr + i),*(Buffer+i));
|
|
}
|
|
#if DBG
|
|
// Excluse reader status cmd
|
|
if(! ((Buffer[0] == 0xA0) && (Buffer[2] == 0x02)) )
|
|
{
|
|
SmartcardDebug(
|
|
DEBUG_TRACE,
|
|
("%s!G_WriteBuf:",
|
|
SC_DRIVER_NAME)
|
|
);
|
|
GPR_Debug_Buffer(Buffer,Len);
|
|
}
|
|
#endif
|
|
|
|
return(TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description :
|
|
Mask a register located at a specified address with a specified
|
|
byte
|
|
--*/
|
|
BOOLEAN G_MaskRegister(
|
|
const USHORT BIOAddr,
|
|
const UCHAR Mask,
|
|
const UCHAR BitState)
|
|
{
|
|
if(BitState == 0)
|
|
{
|
|
WRITE_PORT_UCHAR((PUCHAR)BIOAddr,(UCHAR) (READ_PORT_UCHAR((PUCHAR)BIOAddr) & ~Mask));
|
|
}
|
|
else
|
|
{
|
|
WRITE_PORT_UCHAR((PUCHAR)BIOAddr,(UCHAR) (READ_PORT_UCHAR((PUCHAR)BIOAddr) | Mask));
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description :
|
|
Read a byte to an input address port
|
|
--*/
|
|
UCHAR GprllReadRegister(
|
|
const PREADER_EXTENSION pReaderExt,
|
|
const SHORT GPRRegister
|
|
)
|
|
{
|
|
//
|
|
// Locals variables:
|
|
// value holds the result of the read operation.
|
|
//
|
|
UCHAR value;
|
|
|
|
value = 0x0;
|
|
G_ReadByte((const USHORT)
|
|
(((const USHORT) (pReaderExt->BaseIoAddress)) + (const USHORT) GPRRegister),
|
|
&value
|
|
);
|
|
|
|
return(value);
|
|
}
|
|
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description :
|
|
Call the G_MaskRegister function in the lower level
|
|
--*/
|
|
void GprllMaskHandshakeRegister(
|
|
const PREADER_EXTENSION pReaderExt,
|
|
const UCHAR Mask,
|
|
const UCHAR BitState
|
|
)
|
|
{
|
|
G_MaskRegister((const USHORT)
|
|
(((const USHORT) (pReaderExt->BaseIoAddress))
|
|
+ (const USHORT) REGISTER_HANDSHAKE),
|
|
(const UCHAR) Mask,
|
|
(const UCHAR) BitState);
|
|
// YN
|
|
// get hardware time to update register
|
|
GprllWait(1);
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS GprllKeWaitAckEvent(
|
|
const PREADER_EXTENSION pReaderExt,
|
|
const UCHAR Tx
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
This function Wait the acknowledge of the GPR after
|
|
a send command to IOPort. We made a smart verification
|
|
of the timer depending of the Tag command.
|
|
|
|
Arguments In:
|
|
pReaderExt holds the pointer to the READER_EXTENSION structure.
|
|
Tx holds the command type
|
|
Return Value:
|
|
NTStatus
|
|
--*/
|
|
{
|
|
UCHAR T; // Tag return
|
|
LARGE_INTEGER lTimeout;
|
|
NTSTATUS NTStatus = STATUS_SUCCESS;
|
|
ULONG NbLoop = 0;
|
|
ULONG NbSecondTotal;
|
|
ULONG ElapsedSecond = 0;
|
|
ULONG TimeInLoop =1;
|
|
BOOLEAN Continue = TRUE;
|
|
ULONG i = 0;
|
|
|
|
ASSERT( KeGetCurrentIrql() == PASSIVE_LEVEL );
|
|
|
|
// Make a smart timer depending on type of command
|
|
if( (Tx & 0xf0) == APDU_EXCHANGE_CMD)
|
|
{
|
|
NbSecondTotal = pReaderExt->CmdTimeOut;
|
|
}
|
|
else
|
|
{
|
|
NbSecondTotal = GPR_CMD_TIME;
|
|
}
|
|
|
|
NbLoop = (NbSecondTotal / TimeInLoop);
|
|
|
|
while( (Continue) && (ElapsedSecond < NbSecondTotal) )
|
|
{
|
|
ElapsedSecond += TimeInLoop;
|
|
|
|
lTimeout.QuadPart = -((LONGLONG)TimeInLoop * 10000000);
|
|
|
|
//Wait the acknowledge of the GPR
|
|
NTStatus = KeWaitForSingleObject(
|
|
&(pReaderExt->GPRAckEvent),
|
|
Executive,
|
|
KernelMode,
|
|
TRUE,
|
|
&lTimeout
|
|
);
|
|
|
|
if(NTStatus == STATUS_TIMEOUT)
|
|
{
|
|
// Verify if the reader was been
|
|
// remove during exchange
|
|
|
|
lTimeout.QuadPart = 0;
|
|
|
|
NTStatus = KeWaitForSingleObject(
|
|
&(pReaderExt->ReaderRemoved),
|
|
Executive,
|
|
KernelMode,
|
|
FALSE,
|
|
&lTimeout
|
|
);
|
|
SmartcardDebug(
|
|
DEBUG_PROTOCOL,
|
|
( "%s!GprllKeWaitAckEvent: TIMEOUT KeWaitForSingleObject=%X(hex)\n",
|
|
SC_DRIVER_NAME,
|
|
NTStatus)
|
|
);
|
|
|
|
if (NTStatus == STATUS_SUCCESS)
|
|
{
|
|
NTStatus = STATUS_DEVICE_REMOVED;
|
|
Continue = FALSE;
|
|
}
|
|
// Read the T register
|
|
// <== Test if GPR hasn't been removed STATUS_DEVICE_NOT_CONNECTED
|
|
|
|
|
|
// Reading T out
|
|
T = GprllReadRegister(pReaderExt,REGISTER_T);
|
|
if ( T == 0xFF )
|
|
{
|
|
NTStatus = STATUS_DEVICE_REMOVED;
|
|
Continue = FALSE;
|
|
}
|
|
// Else is a Timeout
|
|
}
|
|
else
|
|
{
|
|
Continue = FALSE;
|
|
NTStatus = STATUS_SUCCESS;
|
|
}
|
|
}
|
|
return NTStatus;
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS GprllTLVExchange(
|
|
const PREADER_EXTENSION pReaderExt,
|
|
const UCHAR Ti,
|
|
const USHORT Li,
|
|
const UCHAR *Vi,
|
|
UCHAR *To,
|
|
USHORT *Lo,
|
|
UCHAR *Vo
|
|
)
|
|
/*++
|
|
|
|
Routine Description :
|
|
Exchange data with GPR with a TLV command.
|
|
|
|
Arguments
|
|
In:
|
|
pReaderExt holds the pointer to the READER_EXTENSION structure.
|
|
Ti holds the command type
|
|
Li holds the command length
|
|
Vi holds the command data
|
|
|
|
Out:
|
|
To holds the command response type
|
|
Lo holds the command response length
|
|
Vo holds the command response data
|
|
|
|
Return Value
|
|
NTStatus
|
|
|
|
STATUS_SUCCESS is Ok
|
|
else if an error condition is raised:
|
|
STATUS_DEVICE_PROTOCOL_ERROR
|
|
STATUS_INVALID_DEVICE_STATE
|
|
STATUS_DEVICE_NOT_CONNECTED
|
|
STATUS_UNRECOGNIZED_MEDIA
|
|
|
|
and others received IFDstatus corresponding to NTSTATUS
|
|
|
|
--*/
|
|
{
|
|
// Local variables
|
|
// - T is type of TLV protocol
|
|
// - new_Ti is the Ti modified
|
|
// - L is length in TLV protocol
|
|
// - V is data filed in TLV protocol
|
|
|
|
NTSTATUS NTStatus = STATUS_SUCCESS;
|
|
UCHAR T;
|
|
UCHAR new_Ti;
|
|
USHORT L;
|
|
UCHAR V[GPR_BUFFER_SIZE];
|
|
|
|
//Verification of Li
|
|
if ( (USHORT) Li >= GPR_BUFFER_SIZE )
|
|
{
|
|
return (STATUS_DEVICE_PROTOCOL_ERROR);
|
|
}
|
|
|
|
new_Ti = Ti;
|
|
|
|
//
|
|
// Write the TLV
|
|
// by Write TLV if Li <= 28 or By ChainIn if Li > 28
|
|
//
|
|
if (Li<=MAX_V_LEN)
|
|
{
|
|
GprllSendCmd(pReaderExt,new_Ti,Li,Vi);
|
|
|
|
NTStatus = GprllKeWaitAckEvent(
|
|
pReaderExt,
|
|
Ti
|
|
);
|
|
|
|
if (STATUS_SUCCESS != NTStatus)
|
|
{
|
|
// YN
|
|
GprllMaskHandshakeRegister(pReaderExt,HANDSHAKE_IREQ,0);
|
|
|
|
return NTStatus;
|
|
}
|
|
|
|
// GPR Command to read I/O Window:
|
|
// In the handshake register, set to 0 bit 2(IREQ) , and set to 1 bit 1 (INTR)
|
|
|
|
}
|
|
else
|
|
{
|
|
NTStatus = GprllSendChainUp(
|
|
pReaderExt,
|
|
new_Ti,
|
|
Li,
|
|
Vi
|
|
);
|
|
|
|
if (STATUS_SUCCESS != NTStatus)
|
|
{
|
|
// YN
|
|
GprllMaskHandshakeRegister(pReaderExt,HANDSHAKE_IREQ,0);
|
|
|
|
return(NTStatus);
|
|
}
|
|
}
|
|
|
|
// Read the T register, need to know if new data to exchange
|
|
T = pReaderExt->To;
|
|
|
|
// Read Answer by Read TLV or Chain Out method if To = Ti + 6
|
|
if ( T == (new_Ti + 6) )
|
|
{
|
|
NTStatus = GprllReadChainUp(pReaderExt,&T,&L,V);
|
|
|
|
if (STATUS_SUCCESS != NTStatus )
|
|
{
|
|
// YN
|
|
GprllMaskHandshakeRegister(pReaderExt,HANDSHAKE_IREQ,0);
|
|
|
|
return(NTStatus);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
L = pReaderExt->Lo;
|
|
ASSERT(pReaderExt->Vo !=0);
|
|
memcpy(V,pReaderExt->Vo,L);
|
|
GprllMaskHandshakeRegister(pReaderExt,HANDSHAKE_IREQ,0);
|
|
}
|
|
|
|
// Verify if Response buffer len is large enough
|
|
// to contain data received from the reader
|
|
//
|
|
|
|
if( L > *Lo )
|
|
{
|
|
*To=T;
|
|
*Lo=1;
|
|
Vo[0]=14;
|
|
return(STATUS_UNRECOGNIZED_MEDIA);
|
|
}
|
|
|
|
// Translate answer
|
|
*To=T;
|
|
*Lo=L;
|
|
memcpy(Vo,V,(SHORT)L);
|
|
|
|
return (GDDK_Translate(Vo[0], Ti));
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void GprllSendCmd(
|
|
const PREADER_EXTENSION pReaderExt,
|
|
const UCHAR Ti,
|
|
const USHORT Li,
|
|
const UCHAR *Vi
|
|
)
|
|
/*++
|
|
|
|
Routine Description :
|
|
Write TLV into I/O Window and
|
|
Send Command to GPR to read I/O Window
|
|
|
|
Arguments:
|
|
pReaderExt holds the pointer to the READER_EXTENSION structure.
|
|
Ti holds the command type
|
|
Li holds the command length
|
|
Vi holds the command data
|
|
--*/
|
|
{
|
|
// Local variables
|
|
// - TLV is an intermediate buffer.
|
|
UCHAR TLV[2 + MAX_V_LEN];
|
|
USHORT Li_max;
|
|
|
|
//Write Ti, Li and Vi[]
|
|
TLV[0] = Ti;
|
|
TLV[1] = (UCHAR) Li;
|
|
ASSERT(Vi != 0);
|
|
|
|
Li_max = Li;
|
|
|
|
if (Li_max > MAX_V_LEN)
|
|
{
|
|
Li_max = MAX_V_LEN;
|
|
}
|
|
memcpy(TLV+2,Vi,Li_max);
|
|
G_WriteBuf((const USHORT)
|
|
(((const USHORT) (pReaderExt->BaseIoAddress)) + (const USHORT) REGISTER_T),
|
|
(const USHORT) (Li_max + 2),
|
|
(UCHAR *) TLV
|
|
);
|
|
|
|
// GPR Command to read I/O Window:
|
|
// In the handshake register, set to 0 bit 2(IREQ) , and set to 1 bit 1 (INTR)
|
|
GprllMaskHandshakeRegister(pReaderExt,HANDSHAKE_IREQ,0);
|
|
GprllMaskHandshakeRegister(pReaderExt,HANDSHAKE_INTR,1);
|
|
}
|
|
|
|
|
|
|
|
void GprllReadResp(
|
|
const PREADER_EXTENSION pReaderExt
|
|
)
|
|
/*++
|
|
|
|
Routine Description :
|
|
Read no chainning TLV into I/O Window and
|
|
Send Command to GPR to read I/O Window
|
|
|
|
Arguments
|
|
In:
|
|
pReaderExt holds the pointer to the READER_EXTENSION structure.
|
|
|
|
Out:
|
|
To holds the command response type
|
|
Lo holds the command response length
|
|
Vo holds the command response data
|
|
--*/
|
|
{
|
|
//Local variables
|
|
// - TLV is an intermediate buffer.
|
|
|
|
UCHAR TLV[2 + MAX_V_LEN];
|
|
|
|
TLV[0] = 0x0;
|
|
// Read To, Lo and Vo[]
|
|
G_ReadBuf((const USHORT)
|
|
(((const USHORT) (pReaderExt->BaseIoAddress)) + (const USHORT) REGISTER_T),
|
|
MAX_V_LEN + 2,
|
|
TLV);
|
|
|
|
pReaderExt->To = TLV[0];
|
|
// maximum number of character is set by the TLV buffer
|
|
pReaderExt->Lo = TLV[1];
|
|
|
|
if (pReaderExt->Lo > MAX_V_LEN)
|
|
{
|
|
pReaderExt->Lo = MAX_V_LEN;
|
|
}
|
|
|
|
|
|
memcpy(pReaderExt->Vo,TLV+2,pReaderExt->Lo);
|
|
|
|
// Acquit the Hand shake:
|
|
// In the handshake register, set to 0 bit 2 (BUSY/IREQ)
|
|
GprllMaskHandshakeRegister(pReaderExt,HANDSHAKE_IREQ,0);
|
|
}
|
|
|
|
|
|
NTSTATUS GprllSendChainUp(
|
|
const PREADER_EXTENSION pReaderExt,
|
|
const UCHAR Ti,
|
|
const USHORT Li,
|
|
const UCHAR *Vi
|
|
)
|
|
/*++
|
|
|
|
Routine Description : Send chainning TLV to GPR
|
|
|
|
Arguments:
|
|
In:
|
|
pReaderExt holds the pointer to the READER_EXTENSION structure.
|
|
Ti holds the command type
|
|
Li holds the command length
|
|
Vi holds the command data
|
|
|
|
Out: Nothing
|
|
--*/
|
|
{
|
|
// Local variables
|
|
// - Tc is type of TLV protocol ( TLV chaining method )
|
|
// - Lc is Length of TLV protocol ( chaining method )
|
|
// - Vc is 28 bytes max of data to send
|
|
// - Length is an temporary var to store Li
|
|
UCHAR Tc;
|
|
UCHAR Response;
|
|
UCHAR Lo;
|
|
USHORT Lc;
|
|
USHORT Length;
|
|
UCHAR Vc[MAX_V_LEN];
|
|
NTSTATUS NTStatus = STATUS_SUCCESS;
|
|
|
|
Length=Li;
|
|
|
|
//Prepare Tc (Add 4 to Ti for chaining method)
|
|
Tc=Ti+4;
|
|
Vc[0] = 0x0;
|
|
while ( Length > 0 )
|
|
{
|
|
//Prepare Lc
|
|
//If length TLV > 28 Length = 28 else it's last command L = Length
|
|
if ( Length > MAX_V_LEN )
|
|
{
|
|
Lc=MAX_V_LEN;
|
|
}
|
|
else
|
|
{
|
|
Lc=Length;
|
|
Tc=Ti;
|
|
}
|
|
//Prepare Vc
|
|
memcpy(Vc,Vi+Li-Length,Lc);
|
|
|
|
//Write to I/O window
|
|
// Dont need the answer - handled by the interrupt function.
|
|
GprllSendCmd(pReaderExt,Tc,Lc,Vc);
|
|
|
|
NTStatus = GprllKeWaitAckEvent(
|
|
pReaderExt,
|
|
Ti
|
|
);
|
|
if(STATUS_SUCCESS != NTStatus)
|
|
{
|
|
return NTStatus;
|
|
}
|
|
|
|
//If an error test Response
|
|
Response = GprllReadRegister(pReaderExt,REGISTER_V);
|
|
|
|
if(0x00 != Response)
|
|
{
|
|
Lo = GprllReadRegister(pReaderExt,REGISTER_L);
|
|
if (Lo == 0x01)
|
|
{
|
|
return (GDDK_Translate(Response, Ti));
|
|
}
|
|
else
|
|
{
|
|
// This is not a exchange is a cmd to reader
|
|
// we don't care about the reader status.
|
|
return (NTStatus);
|
|
}
|
|
}
|
|
Length=Length-Lc;
|
|
}
|
|
return(NTStatus);
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS GprllReadChainUp(
|
|
const PREADER_EXTENSION pReaderExt,
|
|
UCHAR *To,
|
|
USHORT *Lo,
|
|
UCHAR *Vo
|
|
)
|
|
/*++
|
|
|
|
Routine Description : Receive chainning TLV response from GPR
|
|
|
|
Arguments
|
|
In:
|
|
pReaderExt holds the pointer to the READER_EXTENSION structure.
|
|
|
|
Out:
|
|
To holds the command response type
|
|
Lo holds the command response length
|
|
Vo holds the command response data
|
|
--*/
|
|
{
|
|
// Local variables
|
|
// - Tc is type of TLV protocol ( TLV chaining method )
|
|
// - Lc is Length of TLV protocol ( chaining method )
|
|
// - Length is an temporary var to store Lo
|
|
UCHAR Tc;
|
|
USHORT Lc;
|
|
SHORT Lenght;
|
|
NTSTATUS NTStatus = STATUS_SUCCESS;
|
|
|
|
// Reading T out
|
|
Tc = GprllReadRegister(pReaderExt,REGISTER_T);
|
|
*To=Tc-4;
|
|
|
|
Lenght = 0;
|
|
do
|
|
{
|
|
// Read TLV
|
|
Tc = pReaderExt->To;
|
|
Lc = pReaderExt->Lo;
|
|
ASSERT(pReaderExt->Vo != 0);
|
|
|
|
// The Vo buffer is limited by the caller local variable.
|
|
if ( Lenght + (SHORT) pReaderExt->Lo > GPR_BUFFER_SIZE)
|
|
{
|
|
return (STATUS_BUFFER_TOO_SMALL);
|
|
}
|
|
|
|
memcpy(Vo+Lenght,pReaderExt->Vo,pReaderExt->Lo);
|
|
|
|
GprllMaskHandshakeRegister(pReaderExt,HANDSHAKE_IREQ,0);
|
|
|
|
// Prepare Lo
|
|
*Lo=(USHORT)Lenght+Lc;
|
|
Lenght=Lenght+Lc;
|
|
|
|
// GPR send the next Chainning TLV
|
|
// In the handshake register, set to 0 bit 2(IREQ) and set to 1 bit 1 (INTR)
|
|
if ((*To) != Tc )
|
|
{
|
|
GprllMaskHandshakeRegister(pReaderExt,HANDSHAKE_IREQ,0);
|
|
GprllMaskHandshakeRegister(pReaderExt,HANDSHAKE_INTR,1);
|
|
|
|
NTStatus = GprllKeWaitAckEvent(
|
|
pReaderExt,
|
|
*To
|
|
);
|
|
|
|
if(STATUS_SUCCESS != NTStatus)
|
|
{
|
|
return NTStatus;
|
|
}
|
|
}
|
|
|
|
// (End do) if To=Tc -> Last Chainning TLV
|
|
} while( (*To) != Tc );
|
|
|
|
return(NTStatus);
|
|
}
|
|
|
|
|
|
void GprllWait(
|
|
const LONG lWaitingTime
|
|
)
|
|
/*++
|
|
|
|
Routine Description : This function puts the driver in a waiting state
|
|
for a timeout. If IRQL < DISPATCH_LEVEL, use normal fonction to process
|
|
this delay. use KeStallExecutionProcessor, just when GprllWait is called
|
|
in the context of DPC routine.
|
|
|
|
Arguments
|
|
pReaderExt: Pointer to the current ReaderExtension structure.
|
|
lWaitingTime: Timeout value in ms
|
|
--*/
|
|
{
|
|
LARGE_INTEGER Delay;
|
|
|
|
if( KeGetCurrentIrql() >= DISPATCH_LEVEL )
|
|
{
|
|
ULONG Cnt = 20 * lWaitingTime;
|
|
|
|
while( Cnt-- )
|
|
{
|
|
// KeStallExecutionProcessor: counted in us
|
|
KeStallExecutionProcessor( 50 );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Delay.QuadPart = (LONGLONG)-10 * 1000 * lWaitingTime;
|
|
|
|
// KeDelayExecutionThread: counted in 100 ns
|
|
KeDelayExecutionThread( KernelMode, FALSE, &Delay );
|
|
}
|
|
return;
|
|
}
|