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.
774 lines
16 KiB
774 lines
16 KiB
/*++
|
|
|
|
Copyright (c) 1997 SCM Microsystems, Inc.
|
|
|
|
Module Name:
|
|
|
|
StcCmd.c
|
|
|
|
Abstract:
|
|
|
|
Basic command functions for STC smartcard reader
|
|
|
|
|
|
Environment:
|
|
|
|
|
|
|
|
Revision History:
|
|
|
|
PP 01.19.1999 1.01 Modification for PC/SC
|
|
YL 1.00 Initial Version
|
|
|
|
--*/
|
|
|
|
#include "common.h"
|
|
#include "StcCmd.h"
|
|
#include "usbcom.h"
|
|
#include "stcusbnt.h"
|
|
|
|
|
|
const STC_REGISTER STCInitialize[] =
|
|
{
|
|
{ ADR_SC_CONTROL, 0x01, 0x00 }, // reset
|
|
{ ADR_CLOCK_CONTROL, 0x01, 0x01 },
|
|
{ ADR_CLOCK_CONTROL, 0x01, 0x03 },
|
|
{ ADR_UART_CONTROL, 0x01, 0x27 },
|
|
{ ADR_UART_CONTROL, 0x01, 0x4F },
|
|
{ ADR_IO_CONFIG, 0x01, 0x02 }, // 0x10 eva board
|
|
{ ADR_FIFO_CONFIG, 0x01, 0x81 },
|
|
{ ADR_INT_CONTROL, 0x01, 0x11 },
|
|
{ 0x0E, 0x01, 0xC0 },
|
|
{ 0x00, 0x00, 0x00 },
|
|
};
|
|
|
|
const STC_REGISTER STCClose[] =
|
|
{
|
|
{ ADR_INT_CONTROL, 0x01, 0x00 },
|
|
{ ADR_SC_CONTROL, 0x01, 0x00 }, // reset
|
|
{ ADR_UART_CONTROL, 0x01, 0x40 },
|
|
{ ADR_CLOCK_CONTROL, 0x01, 0x01 },
|
|
{ ADR_CLOCK_CONTROL, 0x01, 0x00 },
|
|
{ 0x00, 0x00, 0x00 },
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
|
STCResetInterface(
|
|
PREADER_EXTENSION ReaderExtension)
|
|
/*++
|
|
Description:
|
|
|
|
Arguments:
|
|
ReaderExtension context of call
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
DWORD dwETU;
|
|
|
|
dwETU = 0x7401 | 0x0080;
|
|
NtStatus=IFWriteSTCRegister(
|
|
ReaderExtension,
|
|
ADR_ETULENGTH15,
|
|
2,
|
|
(UCHAR *)&dwETU);
|
|
|
|
return(NtStatus);
|
|
}
|
|
|
|
NTSTATUS
|
|
STCReset(
|
|
PREADER_EXTENSION ReaderExtension,
|
|
UCHAR Device,
|
|
BOOLEAN WarmReset,
|
|
PUCHAR pATR,
|
|
PULONG pATRLength)
|
|
/*++
|
|
Description:
|
|
performs a reset of ICC
|
|
|
|
Arguments:
|
|
ReaderExtension context of call
|
|
Device device requested
|
|
WarmReset kind of ICC reset
|
|
pATR ptr to ATR buffer, NULL if no ATR required
|
|
pATRLength size of ATR buffer / length of ATR
|
|
|
|
Return Value:
|
|
STATUS_SUCCESS
|
|
STATUS_NO_MEDIA
|
|
STATUS_UNRECOGNIZED_MEDIA
|
|
error values from IFRead / IFWrite
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS NTStatus = STATUS_SUCCESS;
|
|
|
|
// set UART to autolearn mode
|
|
NTStatus = STCInitUART( ReaderExtension, TRUE );
|
|
|
|
|
|
if( NTStatus == STATUS_SUCCESS)
|
|
{
|
|
//
|
|
// set default frequency for ATR
|
|
//
|
|
NTStatus = STCSetFDIV( ReaderExtension, FREQ_DIV );
|
|
|
|
if( NTStatus == STATUS_SUCCESS && ( !WarmReset ))
|
|
{
|
|
//
|
|
// deactivate contacts
|
|
//
|
|
NTStatus = STCPowerOff( ReaderExtension );
|
|
}
|
|
|
|
//
|
|
// set power to card
|
|
//
|
|
if( NTStatus == STATUS_SUCCESS)
|
|
{
|
|
NTStatus = STCPowerOn( ReaderExtension );
|
|
|
|
if( NTStatus == STATUS_SUCCESS)
|
|
{
|
|
NTStatus = STCReadATR( ReaderExtension, pATR, pATRLength );
|
|
}
|
|
}
|
|
}
|
|
|
|
if( NTStatus != STATUS_SUCCESS )
|
|
{
|
|
STCPowerOff( ReaderExtension );
|
|
}
|
|
return( NTStatus );
|
|
}
|
|
|
|
NTSTATUS
|
|
STCReadATR(
|
|
PREADER_EXTENSION ReaderExtension,
|
|
PUCHAR pATR,
|
|
PULONG pATRLen)
|
|
/*++
|
|
Description:
|
|
Read and analize the ATR
|
|
|
|
Arguments:
|
|
ReaderExtension context of call
|
|
pATR ptr to ATR buffer,
|
|
pATRLen size of ATR buffer / length of ATR
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS NTStatus = STATUS_SUCCESS;
|
|
UCHAR T0_Yx,
|
|
T0_K, // number of historical bytes
|
|
Protocol;
|
|
ULONG ATRLen;
|
|
//
|
|
// set read timeout for ATR
|
|
//
|
|
ReaderExtension->ReadTimeout = 250; // only 250ms for this firs ATR
|
|
//
|
|
// read TS if active low reset
|
|
//
|
|
NTStatus = IFReadSTCData( ReaderExtension, pATR, 1 );
|
|
|
|
if( NTStatus == STATUS_IO_TIMEOUT )
|
|
{
|
|
ReaderExtension->ReadTimeout = 2500;
|
|
NTStatus = STCSetRST( ReaderExtension, TRUE );
|
|
|
|
if( NTStatus == STATUS_SUCCESS )
|
|
{
|
|
NTStatus = IFReadSTCData( ReaderExtension, pATR, 1 );
|
|
}
|
|
}
|
|
|
|
|
|
Protocol = PROTOCOL_TO;
|
|
ATRLen = 1;
|
|
|
|
if( NTStatus == STATUS_SUCCESS )
|
|
{
|
|
// T0
|
|
NTStatus = IFReadSTCData( ReaderExtension, pATR + ATRLen, 1 );
|
|
ATRLen++;
|
|
|
|
/* Convention management */
|
|
if ( pATR[0] == 0x03 ) /* Direct convention */
|
|
{
|
|
pATR[0] = 0x3F;
|
|
}
|
|
|
|
if ( ( pATR[0] != 0x3F ) && ( pATR[0] != 0x3B ) )
|
|
{
|
|
NTStatus = STATUS_DATA_ERROR;
|
|
}
|
|
|
|
if( NTStatus == STATUS_SUCCESS )
|
|
{
|
|
ULONG Request;
|
|
|
|
// number of historical bytes
|
|
T0_K = (UCHAR) ( pATR[ATRLen-1] & 0x0F );
|
|
|
|
// coding of TA, TB, TC, TD
|
|
T0_Yx = (UCHAR) ( pATR[ATRLen-1] & 0xF0 ) >> 4;
|
|
|
|
while(( NTStatus == STATUS_SUCCESS ) && T0_Yx )
|
|
{
|
|
UCHAR Mask;
|
|
|
|
// evaluate presence of TA, TB, TC, TD
|
|
Mask = T0_Yx;
|
|
Request = 0;
|
|
while( Mask )
|
|
{
|
|
if( Mask & 1 )
|
|
{
|
|
Request++;
|
|
}
|
|
Mask >>= 1;
|
|
}
|
|
NTStatus = IFReadSTCData( ReaderExtension, pATR + ATRLen, Request );
|
|
ATRLen += Request;
|
|
if (ATRLen >= ATR_SIZE) {
|
|
NTStatus = STATUS_UNRECOGNIZED_MEDIA;
|
|
break;
|
|
}
|
|
|
|
if( T0_Yx & TDx )
|
|
{
|
|
// high nibble of TD codes the next set of TA, TB, TC, TD
|
|
T0_Yx = ( pATR[ATRLen-1] & 0xF0 ) >> 4;
|
|
// low nibble of TD codes the protocol
|
|
Protocol = pATR[ATRLen-1] & 0x0F;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if( NTStatus == STATUS_SUCCESS )
|
|
{
|
|
// historical bytes
|
|
NTStatus = IFReadSTCData( ReaderExtension, pATR + ATRLen, T0_K );
|
|
|
|
// check sum
|
|
if( NTStatus == STATUS_SUCCESS )
|
|
{
|
|
ATRLen += T0_K;
|
|
|
|
|
|
if( (ATRLen < ATR_SIZE) && (Protocol >= PROTOCOL_T1) )
|
|
{
|
|
NTStatus = IFReadSTCData( ReaderExtension, pATR + ATRLen, 1 );
|
|
if( NTStatus == STATUS_SUCCESS )
|
|
{
|
|
ATRLen++;
|
|
}
|
|
else if( NTStatus == STATUS_IO_TIMEOUT )
|
|
{
|
|
// some cards don't support the TCK
|
|
NTStatus = STATUS_SUCCESS;
|
|
}
|
|
} else {
|
|
if (ATRLen >= ATR_SIZE) {
|
|
NTStatus = STATUS_UNRECOGNIZED_MEDIA;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if( NTStatus == STATUS_IO_TIMEOUT )
|
|
{
|
|
NTStatus = STATUS_UNRECOGNIZED_MEDIA;
|
|
}
|
|
|
|
if(( NTStatus == STATUS_SUCCESS ) && ( pATRLen != NULL ))
|
|
{
|
|
*pATRLen = ATRLen;
|
|
}
|
|
return( NTStatus );
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
STCPowerOff(
|
|
PREADER_EXTENSION ReaderExtension )
|
|
/*++
|
|
Description:
|
|
Deactivates the requested device
|
|
|
|
Arguments:
|
|
ReaderExtension context of call
|
|
|
|
Return Value:
|
|
STATUS_SUCCESS
|
|
error values from IFRead / IFWrite
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS NTStatus = STATUS_SUCCESS;
|
|
UCHAR SCCtrl;
|
|
|
|
// clear SIM
|
|
SCCtrl=0x11;
|
|
NTStatus=IFWriteSTCRegister(
|
|
ReaderExtension,
|
|
ADR_INT_CONTROL,
|
|
1,
|
|
&SCCtrl);
|
|
|
|
SCCtrl = 0x00;
|
|
NTStatus = IFWriteSTCRegister( ReaderExtension, ADR_SC_CONTROL, 1, &SCCtrl );
|
|
|
|
return( NTStatus );
|
|
}
|
|
|
|
NTSTATUS
|
|
STCPowerOn(
|
|
PREADER_EXTENSION ReaderExtension )
|
|
/*++
|
|
Description:
|
|
Deactivates the requested device
|
|
|
|
Arguments:
|
|
ReaderExtension context of call
|
|
|
|
Return Value:
|
|
STATUS_SUCCESS
|
|
error values from IFRead / IFWrite
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS NTStatus = STATUS_SUCCESS;
|
|
UCHAR SCCtrl,Byte;
|
|
|
|
Byte = 0x02;
|
|
NTStatus = IFWriteSTCRegister(
|
|
ReaderExtension,
|
|
ADR_IO_CONFIG,
|
|
1,
|
|
&Byte
|
|
);
|
|
|
|
SCCtrl = 0x40; // vcc
|
|
NTStatus = IFWriteSTCRegister( ReaderExtension, ADR_SC_CONTROL, 1, &SCCtrl );
|
|
|
|
if( NTStatus == STATUS_SUCCESS )
|
|
{
|
|
SCCtrl = 0x41; // vpp
|
|
NTStatus = IFWriteSTCRegister(
|
|
ReaderExtension,
|
|
ADR_SC_CONTROL,
|
|
1,
|
|
&SCCtrl
|
|
);
|
|
|
|
|
|
// set SIM
|
|
SCCtrl = 0x13;
|
|
NTStatus=IFWriteSTCRegister(
|
|
ReaderExtension,
|
|
ADR_INT_CONTROL,
|
|
1,
|
|
&SCCtrl);
|
|
|
|
if( NTStatus == STATUS_SUCCESS )
|
|
{
|
|
SCCtrl = 0xD1; // vcc, clk, io
|
|
NTStatus = IFWriteSTCRegister(
|
|
ReaderExtension,
|
|
ADR_SC_CONTROL,
|
|
1,
|
|
&SCCtrl
|
|
);
|
|
}
|
|
}
|
|
return( NTStatus );
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
STCSetRST(
|
|
PREADER_EXTENSION ReaderExtension,
|
|
BOOLEAN On)
|
|
/*++
|
|
Description:
|
|
|
|
Arguments:
|
|
ReaderExtension context of call
|
|
|
|
Return Value:
|
|
STATUS_SUCCESS
|
|
error values from IFRead / IFWrite
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS NTStatus = STATUS_SUCCESS;
|
|
UCHAR SCCtrl = 0;
|
|
|
|
NTStatus = IFReadSTCRegister( ReaderExtension, ADR_SC_CONTROL, 1,&SCCtrl );
|
|
if( NTStatus == STATUS_SUCCESS )
|
|
{
|
|
if( On )
|
|
{
|
|
SCCtrl |= 0x20;
|
|
}
|
|
else
|
|
{
|
|
SCCtrl &= ~0x20;
|
|
}
|
|
|
|
NTStatus = IFWriteSTCRegister(
|
|
ReaderExtension,
|
|
ADR_SC_CONTROL,
|
|
1,
|
|
&SCCtrl
|
|
);
|
|
}
|
|
return(NTStatus);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
STCConfigureSTC(
|
|
PREADER_EXTENSION ReaderExtension,
|
|
PSTC_REGISTER pConfiguration
|
|
)
|
|
{
|
|
NTSTATUS NTStatus = STATUS_SUCCESS;
|
|
UCHAR Value;
|
|
|
|
do
|
|
{
|
|
if( pConfiguration->Register == ADR_INT_CONTROL )
|
|
{
|
|
// Read interrupt status register to acknoledge wrong states
|
|
NTStatus = IFReadSTCRegister(
|
|
ReaderExtension,
|
|
ADR_INT_STATUS,
|
|
1,
|
|
&Value
|
|
);
|
|
}
|
|
|
|
Value = (UCHAR) pConfiguration->Value;
|
|
NTStatus = IFWriteSTCRegister(
|
|
ReaderExtension,
|
|
pConfiguration->Register,
|
|
pConfiguration->Size,
|
|
(PUCHAR)&pConfiguration->Value
|
|
);
|
|
|
|
if (NTStatus == STATUS_NO_MEDIA)
|
|
{
|
|
// ignore that no card is in the reader
|
|
NTStatus = STATUS_SUCCESS;
|
|
}
|
|
|
|
// delay to stabilize the oscilator clock:
|
|
if( pConfiguration->Register == ADR_CLOCK_CONTROL )
|
|
{
|
|
SysDelay( 100 );
|
|
}
|
|
pConfiguration++;
|
|
|
|
} while(NTStatus == STATUS_SUCCESS && pConfiguration->Size);
|
|
|
|
return NTStatus;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
STCSetETU(
|
|
PREADER_EXTENSION ReaderExtension,
|
|
ULONG NewETU)
|
|
/*++
|
|
Description:
|
|
|
|
Arguments:
|
|
ReaderExtension context of call
|
|
|
|
Return Value:
|
|
STATUS_SUCCESS
|
|
error values from IFRead / IFWrite
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS NTStatus = STATUS_DATA_ERROR;
|
|
UCHAR ETU[2];
|
|
|
|
SmartcardDebug(
|
|
DEBUG_TRACE,
|
|
("%s!STCSetETU %d\n",
|
|
DRIVER_NAME,
|
|
NewETU));
|
|
|
|
if( NewETU < 0x0FFF )
|
|
{
|
|
NTStatus = IFReadSTCRegister(
|
|
ReaderExtension,
|
|
ADR_ETULENGTH15,
|
|
2,
|
|
ETU);
|
|
|
|
if( NTStatus == STATUS_SUCCESS )
|
|
{
|
|
//
|
|
// save all RFU bits
|
|
//
|
|
ETU[1] = (UCHAR) NewETU;
|
|
ETU[0] = (UCHAR)(( ETU[0] & 0xF0 ) | ( NewETU >> 8 ));
|
|
|
|
NTStatus = IFWriteSTCRegister(
|
|
ReaderExtension,
|
|
ADR_ETULENGTH15,
|
|
2,
|
|
ETU);
|
|
}
|
|
}
|
|
return(NTStatus);
|
|
}
|
|
|
|
NTSTATUS
|
|
STCSetCGT(
|
|
PREADER_EXTENSION ReaderExtension,
|
|
ULONG NewCGT)
|
|
/*++
|
|
Description:
|
|
|
|
Arguments:
|
|
ReaderExtension context of call
|
|
|
|
Return Value:
|
|
STATUS_SUCCESS
|
|
error values from IFRead / IFWrite
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS NTStatus = STATUS_DATA_ERROR;
|
|
UCHAR CGT[2];
|
|
|
|
SmartcardDebug(
|
|
DEBUG_TRACE,
|
|
("%s!STCSetCGT %d\n",
|
|
DRIVER_NAME,
|
|
NewCGT));
|
|
|
|
if( NewCGT < 0x01FF )
|
|
{
|
|
NTStatus = IFReadSTCRegister(
|
|
ReaderExtension,
|
|
ADR_CGT8,
|
|
2,
|
|
CGT);
|
|
|
|
if( NTStatus == STATUS_SUCCESS )
|
|
{
|
|
//
|
|
// save all RFU bits
|
|
//
|
|
CGT[1] = ( UCHAR )NewCGT;
|
|
CGT[0] = (UCHAR)(( CGT[0] & 0xFE ) | ( NewCGT >> 8 ));
|
|
|
|
NTStatus = IFWriteSTCRegister(
|
|
ReaderExtension,
|
|
ADR_CGT8,
|
|
2,
|
|
CGT);
|
|
}
|
|
}
|
|
return(NTStatus);
|
|
}
|
|
|
|
NTSTATUS
|
|
STCSetCWT(
|
|
PREADER_EXTENSION ReaderExtension,
|
|
ULONG NewCWT)
|
|
/*++
|
|
Description:
|
|
|
|
Arguments:
|
|
ReaderExtension context of call
|
|
|
|
Return Value:
|
|
STATUS_SUCCESS
|
|
error values from IFRead / IFWrite
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS NTStatus = STATUS_SUCCESS;
|
|
UCHAR CWT[4];
|
|
|
|
|
|
SmartcardDebug(
|
|
DEBUG_TRACE,
|
|
("%s!STCSetCWT %d\n",
|
|
DRIVER_NAME,
|
|
NewCWT));
|
|
// little indians...
|
|
CWT[0] = (( PUCHAR )&NewCWT )[3];
|
|
CWT[1] = (( PUCHAR )&NewCWT )[2];
|
|
CWT[2] = (( PUCHAR )&NewCWT )[1];
|
|
CWT[3] = (( PUCHAR )&NewCWT )[0];
|
|
|
|
NTStatus = IFWriteSTCRegister(
|
|
ReaderExtension,
|
|
ADR_CWT31,
|
|
4,
|
|
CWT );
|
|
return(NTStatus);
|
|
}
|
|
|
|
NTSTATUS
|
|
STCSetBWT(
|
|
PREADER_EXTENSION ReaderExtension,
|
|
ULONG NewBWT)
|
|
/*++
|
|
Description:
|
|
|
|
Arguments:
|
|
ReaderExtension context of call
|
|
|
|
Return Value:
|
|
STATUS_SUCCESS
|
|
error values from IFRead / IFWrite
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS NTStatus = STATUS_SUCCESS;
|
|
UCHAR BWT[4];
|
|
|
|
SmartcardDebug(
|
|
DEBUG_TRACE,
|
|
("%s!STCSetBWT %d\n",
|
|
DRIVER_NAME,
|
|
NewBWT));
|
|
|
|
// little indians...
|
|
BWT[0] = (( PUCHAR )&NewBWT )[3];
|
|
BWT[1] = (( PUCHAR )&NewBWT )[2];
|
|
BWT[2] = (( PUCHAR )&NewBWT )[1];
|
|
BWT[3] = (( PUCHAR )&NewBWT )[0];
|
|
|
|
NTStatus = IFWriteSTCRegister(
|
|
ReaderExtension,
|
|
ADR_BWT31,
|
|
4,
|
|
BWT );
|
|
|
|
return(NTStatus);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
STCSetFDIV(
|
|
PREADER_EXTENSION ReaderExtension,
|
|
ULONG Factor)
|
|
/*++
|
|
Description:
|
|
|
|
Arguments:
|
|
ReaderExtension context of call
|
|
|
|
Return Value:
|
|
STATUS_SUCCESS
|
|
error values from IFRead / IFWrite
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS NTStatus = STATUS_SUCCESS;
|
|
UCHAR DIV = 0;
|
|
|
|
NTStatus = IFReadSTCRegister(
|
|
ReaderExtension,
|
|
ADR_ETULENGTH15,
|
|
1,
|
|
&DIV );
|
|
|
|
if( NTStatus == STATUS_SUCCESS )
|
|
{
|
|
switch( Factor )
|
|
{
|
|
case 1:
|
|
DIV &= ~M_DIV0;
|
|
DIV &= ~M_DIV1;
|
|
break;
|
|
|
|
case 2:
|
|
DIV |= M_DIV0;
|
|
DIV &= ~M_DIV1;
|
|
break;
|
|
|
|
case 4 :
|
|
DIV &= ~M_DIV0;
|
|
DIV |= M_DIV1;
|
|
break;
|
|
|
|
case 8 :
|
|
DIV |= M_DIV0;
|
|
DIV |= M_DIV1;
|
|
break;
|
|
|
|
default :
|
|
NTStatus = STATUS_DATA_ERROR;
|
|
}
|
|
if( NTStatus == STATUS_SUCCESS )
|
|
{
|
|
NTStatus = IFWriteSTCRegister(
|
|
ReaderExtension,
|
|
ADR_ETULENGTH15,
|
|
1,
|
|
&DIV );
|
|
}
|
|
}
|
|
return(NTStatus);
|
|
}
|
|
|
|
NTSTATUS
|
|
STCInitUART(
|
|
PREADER_EXTENSION ReaderExtension,
|
|
BOOLEAN AutoLearn)
|
|
/*++
|
|
Description:
|
|
|
|
Arguments:
|
|
ReaderExtension context of call
|
|
|
|
Return Value:
|
|
STATUS_SUCCESS
|
|
error values from IFRead / IFWrite
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS NTStatus = STATUS_SUCCESS;
|
|
UCHAR Value;
|
|
|
|
Value = AutoLearn ? 0x6F : 0x66;
|
|
|
|
NTStatus = IFWriteSTCRegister(
|
|
ReaderExtension,
|
|
ADR_UART_CONTROL,
|
|
1,
|
|
&Value );
|
|
|
|
return( NTStatus );
|
|
}
|
|
|
|
//---------------------------------------- END OF FILE ----------------------------------------
|