997 lines
34 KiB
C
997 lines
34 KiB
C
|
/*****************************************************************************
|
|||
|
@doc INT EXT
|
|||
|
******************************************************************************
|
|||
|
* $ProjectName: $
|
|||
|
* $ProjectRevision: $
|
|||
|
*-----------------------------------------------------------------------------
|
|||
|
* $Source: z:/pr/cmeu0/sw/sccmusbm.ms/rcs/scusbsyn.c $
|
|||
|
* $Revision: 1.3 $
|
|||
|
*-----------------------------------------------------------------------------
|
|||
|
* $Author: TBruendl $
|
|||
|
*-----------------------------------------------------------------------------
|
|||
|
* History: see EOF
|
|||
|
*-----------------------------------------------------------------------------
|
|||
|
*
|
|||
|
* Copyright <EFBFBD> 2000 OMNIKEY AG
|
|||
|
******************************************************************************/
|
|||
|
|
|||
|
|
|||
|
|
|||
|
#include "wdm.h"
|
|||
|
#include "stdarg.h"
|
|||
|
#include "stdio.h"
|
|||
|
|
|||
|
#include "usbdi.h"
|
|||
|
#include "usbdlib.h"
|
|||
|
#include "sccmusbm.h"
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
/*****************************************************************************
|
|||
|
Routine Description: Powers a synchronous card and reads the ATR
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
*****************************************************************************/
|
|||
|
NTSTATUS
|
|||
|
CMUSB_PowerOnSynchronousCard (
|
|||
|
IN PSMARTCARD_EXTENSION smartcardExtension,
|
|||
|
IN PUCHAR pbATR,
|
|||
|
OUT PULONG pulATRLength
|
|||
|
)
|
|||
|
{
|
|||
|
PDEVICE_OBJECT deviceObject;
|
|||
|
NTSTATUS status = STATUS_SUCCESS;
|
|||
|
NTSTATUS DebugStatus;
|
|||
|
UCHAR abMaxAtrBuffer[SCARD_ATR_LENGTH];
|
|||
|
UCHAR abSendBuffer[CMUSB_SYNCH_BUFFER_SIZE];
|
|||
|
UCHAR bResetMode;
|
|||
|
|
|||
|
SmartcardDebug(DEBUG_TRACE,
|
|||
|
("%s!PowerOnSynchronousCard: Enter\n",DRIVER_NAME));
|
|||
|
|
|||
|
deviceObject = smartcardExtension->OsData->DeviceObject;
|
|||
|
|
|||
|
// in case of warm reset we have to power off the card first
|
|||
|
if (smartcardExtension->MinorIoControlCode != SCARD_COLD_RESET)
|
|||
|
{
|
|||
|
status = CMUSB_PowerOffCard (smartcardExtension );
|
|||
|
if (status != STATUS_SUCCESS)
|
|||
|
{
|
|||
|
// if we can't turn off power there must be a serious error
|
|||
|
goto ExitPowerOnSynchronousCard;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// set card parameters
|
|||
|
smartcardExtension->ReaderExtension->CardParameters.bBaudRate = 0;
|
|||
|
smartcardExtension->ReaderExtension->CardParameters.bCardType = CMUSB_SMARTCARD_SYNCHRONOUS;
|
|||
|
smartcardExtension->ReaderExtension->CardParameters.bStopBits = 0;
|
|||
|
|
|||
|
status = CMUSB_SetCardParameters (deviceObject,
|
|||
|
smartcardExtension->ReaderExtension->CardParameters.bCardType,
|
|||
|
smartcardExtension->ReaderExtension->CardParameters.bBaudRate,
|
|||
|
smartcardExtension->ReaderExtension->CardParameters.bStopBits);
|
|||
|
if (status != STATUS_SUCCESS)
|
|||
|
{
|
|||
|
// if we can't set the card parameters there must be a serious error
|
|||
|
goto ExitPowerOnSynchronousCard;
|
|||
|
}
|
|||
|
|
|||
|
RtlFillMemory((PVOID)abMaxAtrBuffer,
|
|||
|
sizeof(abMaxAtrBuffer),
|
|||
|
0x00);
|
|||
|
|
|||
|
// resync CardManUSB by reading the status byte
|
|||
|
// still necessary with synchronous cards ???
|
|||
|
smartcardExtension->SmartcardRequest.BufferLength = 0;
|
|||
|
status = CMUSB_WriteP0(deviceObject,
|
|||
|
0x20, //bRequest,
|
|||
|
0x00, //bValueLo,
|
|||
|
0x00, //bValueHi,
|
|||
|
0x00, //bIndexLo,
|
|||
|
0x00 //bIndexHi,
|
|||
|
);
|
|||
|
|
|||
|
if (status != STATUS_SUCCESS)
|
|||
|
{
|
|||
|
// if we can't read the status there must be a serious error
|
|||
|
goto ExitPowerOnSynchronousCard;
|
|||
|
}
|
|||
|
|
|||
|
smartcardExtension->ReaderExtension->ulTimeoutP1 = DEFAULT_TIMEOUT_P1;
|
|||
|
status = CMUSB_ReadP1(deviceObject);
|
|||
|
if (status == STATUS_DEVICE_DATA_ERROR)
|
|||
|
{
|
|||
|
DebugStatus = CMUSB_ReadStateAfterP1Stalled(deviceObject);
|
|||
|
goto ExitPowerOnSynchronousCard;
|
|||
|
}
|
|||
|
else if (status != STATUS_SUCCESS)
|
|||
|
{
|
|||
|
// if we can't read the status there must be a serious error
|
|||
|
goto ExitPowerOnSynchronousCard;
|
|||
|
}
|
|||
|
|
|||
|
// check if card is really inserted
|
|||
|
if (smartcardExtension->SmartcardReply.Buffer[0] == 0x00)
|
|||
|
{
|
|||
|
status = STATUS_NO_MEDIA;
|
|||
|
goto ExitPowerOnSynchronousCard;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
// issue power on command
|
|||
|
// according to WZ nothing is sent back
|
|||
|
smartcardExtension->SmartcardRequest.BufferLength = 0;
|
|||
|
status = CMUSB_WriteP0(deviceObject,
|
|||
|
0x10, //bRequest,
|
|||
|
SMARTCARD_COLD_RESET, //bValueLo,
|
|||
|
0x00, //bValueHi,
|
|||
|
0x00, //bIndexLo,
|
|||
|
0x00 //bIndexHi,
|
|||
|
);
|
|||
|
if (status != STATUS_SUCCESS)
|
|||
|
{
|
|||
|
// if we can't issue the power on command there must be a serious error
|
|||
|
goto ExitPowerOnSynchronousCard;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
// build control code for ATR
|
|||
|
abSendBuffer[0]=CMUSB_CalcSynchControl(0,0,0,0, 1,0,0,0);
|
|||
|
abSendBuffer[1]=CMUSB_CalcSynchControl(1,1,0,0, 1,0,0,0);
|
|||
|
abSendBuffer[2]=CMUSB_CalcSynchControl(0,0,0,0, 0,0,0,0);
|
|||
|
// fill memory so that we can discard first byte
|
|||
|
RtlFillMemory((PVOID)&abSendBuffer[3],5,abSendBuffer[2]);
|
|||
|
|
|||
|
// now get 4 bytes ATR -> 32 bytes to send
|
|||
|
abSendBuffer[8]=CMUSB_CalcSynchControl(0,0,0,0, 0,1,0,0);
|
|||
|
RtlFillMemory((PVOID)&abSendBuffer[9],31,abSendBuffer[8]);
|
|||
|
|
|||
|
//now set clock to low to finish operation
|
|||
|
//and of course additional fill bytes
|
|||
|
abSendBuffer[40]=CMUSB_CalcSynchControl(0,0,0,0, 0,0,0,0);
|
|||
|
RtlFillMemory((PVOID)&abSendBuffer[41],7,abSendBuffer[40]);
|
|||
|
|
|||
|
// now send command type 08 to CardManUSB
|
|||
|
smartcardExtension->SmartcardRequest.BufferLength = 48;
|
|||
|
RtlCopyBytes((PVOID) smartcardExtension->SmartcardRequest.Buffer,
|
|||
|
(PVOID) abSendBuffer,
|
|||
|
smartcardExtension->SmartcardRequest.BufferLength);
|
|||
|
status = CMUSB_WriteP0(deviceObject,
|
|||
|
0x08, //bRequest,
|
|||
|
0x00, //bValueLo,
|
|||
|
0x00, //bValueHi,
|
|||
|
0x00, //bIndexLo,
|
|||
|
0x00 //bIndexHi,
|
|||
|
);
|
|||
|
if (status != STATUS_SUCCESS)
|
|||
|
{
|
|||
|
// if we can't write ATR command there must be a serious error
|
|||
|
if (status == STATUS_DEVICE_DATA_ERROR)
|
|||
|
{
|
|||
|
//error mapping necessary because there are CardManUSB
|
|||
|
//which have no support for synchronous cards
|
|||
|
status = STATUS_UNRECOGNIZED_MEDIA;
|
|||
|
}
|
|||
|
goto ExitPowerOnSynchronousCard;
|
|||
|
}
|
|||
|
|
|||
|
status = CMUSB_ReadP1(deviceObject);
|
|||
|
if (status == STATUS_DEVICE_DATA_ERROR)
|
|||
|
{
|
|||
|
DebugStatus = CMUSB_ReadStateAfterP1Stalled(deviceObject);
|
|||
|
goto ExitPowerOnSynchronousCard;
|
|||
|
}
|
|||
|
else if (status != STATUS_SUCCESS)
|
|||
|
{
|
|||
|
// if we can't read the ATR -> there must be a serious error
|
|||
|
goto ExitPowerOnSynchronousCard;
|
|||
|
}
|
|||
|
|
|||
|
if (smartcardExtension->SmartcardReply.BufferLength!=6)
|
|||
|
{
|
|||
|
// 48 bytes sent but not 6 bytes received
|
|||
|
// -> something went wrong
|
|||
|
status=STATUS_DEVICE_DATA_ERROR;
|
|||
|
goto ExitPowerOnSynchronousCard;
|
|||
|
}
|
|||
|
|
|||
|
// now bytes 1-4 in SmartcardReply.Buffer should be ATR
|
|||
|
SmartcardDebug(DEBUG_ATR,
|
|||
|
("%s!ATR = %02x %02x %02x %02x\n",DRIVER_NAME,
|
|||
|
smartcardExtension->SmartcardReply.Buffer[1],
|
|||
|
smartcardExtension->SmartcardReply.Buffer[2],
|
|||
|
smartcardExtension->SmartcardReply.Buffer[3],
|
|||
|
smartcardExtension->SmartcardReply.Buffer[4]));
|
|||
|
|
|||
|
// check if ATR != 0xFF -> synchronous card
|
|||
|
if (smartcardExtension->SmartcardReply.Buffer[1]==0xFF &&
|
|||
|
smartcardExtension->SmartcardReply.Buffer[2]==0xFF &&
|
|||
|
smartcardExtension->SmartcardReply.Buffer[3]==0xFF &&
|
|||
|
smartcardExtension->SmartcardReply.Buffer[4]==0xFF )
|
|||
|
{
|
|||
|
status = STATUS_UNRECOGNIZED_MEDIA;
|
|||
|
*pulATRLength = 0;
|
|||
|
goto ExitPowerOnSynchronousCard;
|
|||
|
}
|
|||
|
|
|||
|
//it seems we have a synchronous smart card and a valid ATR
|
|||
|
//let<65>s set the variables
|
|||
|
smartcardExtension->ReaderExtension->fRawModeNecessary = TRUE;
|
|||
|
*pulATRLength = 4;
|
|||
|
RtlCopyBytes((PVOID) pbATR,
|
|||
|
(PVOID) &(smartcardExtension->SmartcardReply.Buffer[1]),
|
|||
|
*pulATRLength );
|
|||
|
|
|||
|
|
|||
|
|
|||
|
ExitPowerOnSynchronousCard:
|
|||
|
|
|||
|
if (status!=STATUS_SUCCESS)
|
|||
|
{
|
|||
|
// turn off VCC again
|
|||
|
CMUSB_PowerOffCard (smartcardExtension );
|
|||
|
// ignor status
|
|||
|
}
|
|||
|
|
|||
|
SmartcardDebug(DEBUG_TRACE,
|
|||
|
("%s!PowerOnSynchronousCard: Exit %lx\n",DRIVER_NAME,status));
|
|||
|
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/*****************************************************************************
|
|||
|
Routine Description: Data transfer to synchronous cards SLE 4442/4432
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
*****************************************************************************/
|
|||
|
NTSTATUS
|
|||
|
CMUSB_Transmit2WBP (
|
|||
|
IN PSMARTCARD_EXTENSION smartcardExtension
|
|||
|
)
|
|||
|
{
|
|||
|
PDEVICE_OBJECT deviceObject;
|
|||
|
NTSTATUS status = STATUS_SUCCESS;
|
|||
|
NTSTATUS DebugStatus;
|
|||
|
PCHAR pbInData;
|
|||
|
ULONG ulBytesToRead;
|
|||
|
ULONG ulBitsToRead;
|
|||
|
ULONG ulBytesToReadThisStep;
|
|||
|
ULONG ulBytesRead;
|
|||
|
UCHAR abSendBuffer[CMUSB_SYNCH_BUFFER_SIZE];
|
|||
|
int i;
|
|||
|
|
|||
|
|
|||
|
SmartcardDebug(DEBUG_TRACE,
|
|||
|
("%s!Transmit2WBP: Enter\n",DRIVER_NAME));
|
|||
|
|
|||
|
|
|||
|
deviceObject = smartcardExtension->OsData->DeviceObject;
|
|||
|
|
|||
|
// resync CardManUSB by reading the status byte
|
|||
|
// still necessary with synchronous cards ???
|
|||
|
smartcardExtension->SmartcardRequest.BufferLength = 0;
|
|||
|
status = CMUSB_WriteP0(deviceObject,
|
|||
|
0x20, //bRequest,
|
|||
|
0x00, //bValueLo,
|
|||
|
0x00, //bValueHi,
|
|||
|
0x00, //bIndexLo,
|
|||
|
0x00 //bIndexHi,
|
|||
|
);
|
|||
|
|
|||
|
if (status != STATUS_SUCCESS)
|
|||
|
{
|
|||
|
// if we can't read the status there must be a serious error
|
|||
|
goto ExitTransmit2WBP;
|
|||
|
}
|
|||
|
|
|||
|
smartcardExtension->ReaderExtension->ulTimeoutP1 = DEFAULT_TIMEOUT_P1;
|
|||
|
status = CMUSB_ReadP1(deviceObject);
|
|||
|
if (status == STATUS_DEVICE_DATA_ERROR)
|
|||
|
{
|
|||
|
DebugStatus = CMUSB_ReadStateAfterP1Stalled(deviceObject);
|
|||
|
goto ExitTransmit2WBP;
|
|||
|
}
|
|||
|
else if (status != STATUS_SUCCESS)
|
|||
|
{
|
|||
|
// if we can't read the status there must be a serious error
|
|||
|
goto ExitTransmit2WBP;
|
|||
|
}
|
|||
|
|
|||
|
// check if card is really inserted
|
|||
|
if (smartcardExtension->SmartcardReply.Buffer[0] == 0x00)
|
|||
|
{
|
|||
|
// it is not sure, which error messages are accepted
|
|||
|
// status = STATUS_NO_MEDIA_IN_DEVICE;
|
|||
|
status = STATUS_UNRECOGNIZED_MEDIA;
|
|||
|
goto ExitTransmit2WBP;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
pbInData = smartcardExtension->IoRequest.RequestBuffer + sizeof(SYNC_TRANSFER);
|
|||
|
ulBitsToRead = ((PSYNC_TRANSFER)(smartcardExtension->IoRequest.RequestBuffer))->ulSyncBitsToRead;
|
|||
|
ulBytesToRead = ulBitsToRead/8 + (ulBitsToRead % 8 ? 1 : 0);
|
|||
|
// ulBitsToWrite = ((PSYNC_TRANSFER)(smartcardExtension->IoRequest.RequestBuffer))->ulSyncBitsToWrite;
|
|||
|
// ulBytesToWrite = ulBitsToWrite/8;
|
|||
|
|
|||
|
if (smartcardExtension->IoRequest.ReplyBufferLength < ulBytesToRead)
|
|||
|
{
|
|||
|
status = STATUS_BUFFER_OVERFLOW;
|
|||
|
goto ExitTransmit2WBP;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
// send command
|
|||
|
status=CMUSB_SendCommand2WBP(smartcardExtension, pbInData);
|
|||
|
if (status != STATUS_SUCCESS)
|
|||
|
{
|
|||
|
// if we can't send the command -> proceeding is sensless
|
|||
|
goto ExitTransmit2WBP;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
// now we have to differenciate, wheter card is in
|
|||
|
// outgoing data mode (after read command) or
|
|||
|
// in processing mode (after write/erase command)
|
|||
|
switch (*pbInData)
|
|||
|
{
|
|||
|
case SLE4442_READ:
|
|||
|
case SLE4442_READ_PROT_MEM:
|
|||
|
case SLE4442_READ_SEC_MEM:
|
|||
|
// outgoing data mode
|
|||
|
|
|||
|
//now read data
|
|||
|
abSendBuffer[0]=CMUSB_CalcSynchControl(0,0,0,0, 0,1,0,0);
|
|||
|
RtlFillMemory((PVOID)&abSendBuffer[1],ATTR_MAX_IFSD_SYNCHRON_USB-1,abSendBuffer[0]);
|
|||
|
|
|||
|
//read data in 6 byte packages
|
|||
|
ulBytesRead=0;
|
|||
|
do
|
|||
|
{
|
|||
|
if ((ulBytesToRead - ulBytesRead) > ATTR_MAX_IFSD_SYNCHRON_USB/8)
|
|||
|
ulBytesToReadThisStep = ATTR_MAX_IFSD_SYNCHRON_USB/8;
|
|||
|
else
|
|||
|
ulBytesToReadThisStep = ulBytesToRead - ulBytesRead;
|
|||
|
|
|||
|
// now send command type 08 to CardManUSB
|
|||
|
smartcardExtension->SmartcardRequest.BufferLength = ulBytesToReadThisStep*8;
|
|||
|
RtlCopyBytes((PVOID) smartcardExtension->SmartcardRequest.Buffer,
|
|||
|
(PVOID) abSendBuffer,
|
|||
|
smartcardExtension->SmartcardRequest.BufferLength);
|
|||
|
status = CMUSB_WriteP0(deviceObject,
|
|||
|
0x08, //bRequest,
|
|||
|
0x00, //bValueLo,
|
|||
|
0x00, //bValueHi,
|
|||
|
0x00, //bIndexLo,
|
|||
|
0x00 //bIndexHi,
|
|||
|
);
|
|||
|
if (status != STATUS_SUCCESS)
|
|||
|
{
|
|||
|
// if we can't write command there must be a serious error
|
|||
|
goto ExitTransmit2WBP;
|
|||
|
}
|
|||
|
|
|||
|
status = CMUSB_ReadP1(deviceObject);
|
|||
|
if (status == STATUS_DEVICE_DATA_ERROR)
|
|||
|
{
|
|||
|
DebugStatus = CMUSB_ReadStateAfterP1Stalled(deviceObject);
|
|||
|
goto ExitTransmit2WBP;
|
|||
|
}
|
|||
|
else if (status != STATUS_SUCCESS)
|
|||
|
{
|
|||
|
// if we can't read there must be a serious error
|
|||
|
goto ExitTransmit2WBP;
|
|||
|
}
|
|||
|
|
|||
|
if (smartcardExtension->SmartcardReply.BufferLength!=ulBytesToReadThisStep)
|
|||
|
{
|
|||
|
// wrong number of bytes read
|
|||
|
// -> something went wrong
|
|||
|
status=STATUS_DEVICE_DATA_ERROR;
|
|||
|
goto ExitTransmit2WBP;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RtlCopyBytes((PVOID) &(smartcardExtension->IoRequest.ReplyBuffer[ulBytesRead]),
|
|||
|
(PVOID) smartcardExtension->SmartcardReply.Buffer,
|
|||
|
smartcardExtension->SmartcardReply.BufferLength);
|
|||
|
|
|||
|
ulBytesRead+=smartcardExtension->SmartcardReply.BufferLength;
|
|||
|
}
|
|||
|
while ((status == STATUS_SUCCESS) && (ulBytesToRead > ulBytesRead));
|
|||
|
*(smartcardExtension->IoRequest.Information)=ulBytesRead;
|
|||
|
|
|||
|
if (status!=STATUS_SUCCESS)
|
|||
|
{
|
|||
|
goto ExitTransmit2WBP;
|
|||
|
}
|
|||
|
|
|||
|
// according to datasheet, clock should be set to low now
|
|||
|
// this is not necessary, because this is done before next command
|
|||
|
// or card is reseted respectivly
|
|||
|
|
|||
|
break;
|
|||
|
case SLE4442_WRITE:
|
|||
|
case SLE4442_WRITE_PROT_MEM:
|
|||
|
case SLE4442_COMPARE_PIN:
|
|||
|
case SLE4442_UPDATE_SEC_MEM:
|
|||
|
// processing mode
|
|||
|
|
|||
|
abSendBuffer[0]=CMUSB_CalcSynchControl(0,0,0,0, 0,1,0,0);
|
|||
|
RtlFillMemory((PVOID)&abSendBuffer[1],ATTR_MAX_IFSD_SYNCHRON_USB-1,abSendBuffer[0]);
|
|||
|
|
|||
|
do
|
|||
|
{
|
|||
|
|
|||
|
// now send command type 08 to CardManUSB
|
|||
|
smartcardExtension->SmartcardRequest.BufferLength = ATTR_MAX_IFSD_SYNCHRON_USB;
|
|||
|
RtlCopyBytes((PVOID) smartcardExtension->SmartcardRequest.Buffer,
|
|||
|
(PVOID) abSendBuffer,
|
|||
|
smartcardExtension->SmartcardRequest.BufferLength);
|
|||
|
status = CMUSB_WriteP0(deviceObject,
|
|||
|
0x08, //bRequest,
|
|||
|
0x00, //bValueLo,
|
|||
|
0x00, //bValueHi,
|
|||
|
0x00, //bIndexLo,
|
|||
|
0x00 //bIndexHi,
|
|||
|
);
|
|||
|
if (status != STATUS_SUCCESS)
|
|||
|
{
|
|||
|
// if we can't write command there must be a serious error
|
|||
|
goto ExitTransmit2WBP;
|
|||
|
}
|
|||
|
|
|||
|
status = CMUSB_ReadP1(deviceObject);
|
|||
|
if (status == STATUS_DEVICE_DATA_ERROR)
|
|||
|
{
|
|||
|
DebugStatus = CMUSB_ReadStateAfterP1Stalled(deviceObject);
|
|||
|
goto ExitTransmit2WBP;
|
|||
|
}
|
|||
|
else if (status != STATUS_SUCCESS)
|
|||
|
{
|
|||
|
// if we can't read there must be a serious error
|
|||
|
goto ExitTransmit2WBP;
|
|||
|
}
|
|||
|
|
|||
|
if (smartcardExtension->SmartcardReply.BufferLength!=ATTR_MAX_IFSD_SYNCHRON_USB/8)
|
|||
|
{
|
|||
|
// wrong number of bytes read
|
|||
|
// -> something went wrong
|
|||
|
status=STATUS_DEVICE_DATA_ERROR;
|
|||
|
goto ExitTransmit2WBP;
|
|||
|
}
|
|||
|
|
|||
|
/* not necessary this way, check last byte only
|
|||
|
ulReplySum=0;
|
|||
|
for (i=0;i<(int)smartcardExtension->SmartcardReply.BufferLength;i++)
|
|||
|
{
|
|||
|
ulReplySum+=smartcardExtension->SmartcardReply.Buffer[i];
|
|||
|
}
|
|||
|
*/
|
|||
|
}
|
|||
|
while ((status == STATUS_SUCCESS) &&
|
|||
|
(smartcardExtension->SmartcardReply.Buffer[smartcardExtension->SmartcardReply.BufferLength-1]==0));
|
|||
|
*(smartcardExtension->IoRequest.Information)=0;
|
|||
|
|
|||
|
if (status!=STATUS_SUCCESS)
|
|||
|
{
|
|||
|
goto ExitTransmit2WBP;
|
|||
|
}
|
|||
|
|
|||
|
// according to datasheet, clock should be set to low now
|
|||
|
// this is not necessary, because this is done before next command
|
|||
|
// or card is reseted respectivly
|
|||
|
|
|||
|
|
|||
|
break;
|
|||
|
default:
|
|||
|
// should not happen
|
|||
|
status=STATUS_ILLEGAL_INSTRUCTION;
|
|||
|
goto ExitTransmit2WBP;
|
|||
|
}
|
|||
|
|
|||
|
ExitTransmit2WBP:
|
|||
|
|
|||
|
|
|||
|
SmartcardDebug(DEBUG_TRACE,
|
|||
|
("%s!Transmit2WBP: Exit %lx\n",DRIVER_NAME,status));
|
|||
|
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/*****************************************************************************
|
|||
|
Routine Description: Transmits a command (3 Bytes) to a SLE 4442/4432
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
*****************************************************************************/
|
|||
|
NTSTATUS
|
|||
|
CMUSB_SendCommand2WBP (
|
|||
|
IN PSMARTCARD_EXTENSION smartcardExtension,
|
|||
|
IN PUCHAR pbCommandData
|
|||
|
)
|
|||
|
{
|
|||
|
PDEVICE_OBJECT deviceObject;
|
|||
|
NTSTATUS status = STATUS_SUCCESS;
|
|||
|
NTSTATUS DebugStatus;
|
|||
|
UCHAR abSendBuffer[CMUSB_SYNCH_BUFFER_SIZE];
|
|||
|
UCHAR* pByte;
|
|||
|
UCHAR bValue;
|
|||
|
int i,j;
|
|||
|
|
|||
|
|
|||
|
SmartcardDebug(DEBUG_TRACE,
|
|||
|
("%s!SendCommand2WBP: Enter\n",DRIVER_NAME));
|
|||
|
|
|||
|
SmartcardDebug(DEBUG_PROTOCOL,
|
|||
|
("%s!SendCommand2WBP: 4442 Command = %02x %02x %02x\n",DRIVER_NAME,
|
|||
|
pbCommandData[0],
|
|||
|
pbCommandData[1],
|
|||
|
pbCommandData[2]));
|
|||
|
|
|||
|
deviceObject = smartcardExtension->OsData->DeviceObject;
|
|||
|
|
|||
|
// build control code for command to send
|
|||
|
// command is in first 3 Bytes of pbInData
|
|||
|
abSendBuffer[0]=CMUSB_CalcSynchControl(0,0,0,0, 0,0,0,0);
|
|||
|
abSendBuffer[1]=CMUSB_CalcSynchControl(0,0,1,1, 0,1,1,1);
|
|||
|
abSendBuffer[2]=CMUSB_CalcSynchControl(0,1,1,0, 0,1,1,0);
|
|||
|
|
|||
|
pByte=&abSendBuffer[3];
|
|||
|
for (j=0;j<3;j++)
|
|||
|
{
|
|||
|
for (i=0;i<8;i++)
|
|||
|
{
|
|||
|
bValue=(pbCommandData[j]&(1<<i));
|
|||
|
*pByte=CMUSB_CalcSynchControl(0,0,1,bValue, 0,1,1,bValue);
|
|||
|
pByte++;
|
|||
|
}
|
|||
|
}
|
|||
|
abSendBuffer[27]=CMUSB_CalcSynchControl(0,0,1,0, 0,1,1,0);
|
|||
|
abSendBuffer[28]=CMUSB_CalcSynchControl(0,1,1,0, 0,1,1,0);
|
|||
|
RtlFillMemory((PVOID)&abSendBuffer[29],2,abSendBuffer[28]);
|
|||
|
abSendBuffer[31]=CMUSB_CalcSynchControl(0,1,1,0, 0,1,1,1);
|
|||
|
|
|||
|
// now send command type 08 to CardManUSB
|
|||
|
smartcardExtension->SmartcardRequest.BufferLength = 32;
|
|||
|
RtlCopyBytes((PVOID) smartcardExtension->SmartcardRequest.Buffer,
|
|||
|
(PVOID) abSendBuffer,
|
|||
|
smartcardExtension->SmartcardRequest.BufferLength);
|
|||
|
status = CMUSB_WriteP0(deviceObject,
|
|||
|
0x08, //bRequest,
|
|||
|
0x00, //bValueLo,
|
|||
|
0x00, //bValueHi,
|
|||
|
0x00, //bIndexLo,
|
|||
|
0x00 //bIndexHi,
|
|||
|
);
|
|||
|
if (status != STATUS_SUCCESS)
|
|||
|
{
|
|||
|
// if we can't write command there must be a serious error
|
|||
|
goto ExitSendCommand2WBP;
|
|||
|
}
|
|||
|
|
|||
|
status = CMUSB_ReadP1(deviceObject);
|
|||
|
if (status == STATUS_DEVICE_DATA_ERROR)
|
|||
|
{
|
|||
|
DebugStatus = CMUSB_ReadStateAfterP1Stalled(deviceObject);
|
|||
|
goto ExitSendCommand2WBP;
|
|||
|
}
|
|||
|
else if (status != STATUS_SUCCESS)
|
|||
|
{
|
|||
|
// if we can't read there must be a serious error
|
|||
|
goto ExitSendCommand2WBP;
|
|||
|
}
|
|||
|
|
|||
|
if (smartcardExtension->SmartcardReply.BufferLength!=4)
|
|||
|
{
|
|||
|
// 32 bytes sent but not 4 bytes received
|
|||
|
// -> something went wrong
|
|||
|
status=STATUS_DEVICE_DATA_ERROR;
|
|||
|
goto ExitSendCommand2WBP;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
ExitSendCommand2WBP:
|
|||
|
|
|||
|
SmartcardDebug(DEBUG_TRACE,
|
|||
|
("%s!SendCommand2WBP: Exit %lx\n",DRIVER_NAME,status));
|
|||
|
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/*****************************************************************************
|
|||
|
Routine Description: Data transfer to synchronous cards SLE 4428/4418
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
*****************************************************************************/
|
|||
|
NTSTATUS
|
|||
|
CMUSB_Transmit3WBP (
|
|||
|
IN PSMARTCARD_EXTENSION smartcardExtension
|
|||
|
)
|
|||
|
{
|
|||
|
PDEVICE_OBJECT deviceObject;
|
|||
|
NTSTATUS status = STATUS_SUCCESS;
|
|||
|
NTSTATUS DebugStatus;
|
|||
|
PCHAR pbInData;
|
|||
|
ULONG ulBytesToRead;
|
|||
|
ULONG ulBitsToRead;
|
|||
|
ULONG ulBytesToReadThisStep;
|
|||
|
ULONG ulBytesRead;
|
|||
|
UCHAR abSendBuffer[CMUSB_SYNCH_BUFFER_SIZE];
|
|||
|
int i;
|
|||
|
|
|||
|
|
|||
|
SmartcardDebug(DEBUG_TRACE,
|
|||
|
("%s!Transmit3WBP: Enter\n",DRIVER_NAME));
|
|||
|
|
|||
|
|
|||
|
deviceObject = smartcardExtension->OsData->DeviceObject;
|
|||
|
|
|||
|
// resync CardManUSB by reading the status byte
|
|||
|
// still necessary with synchronous cards ???
|
|||
|
smartcardExtension->SmartcardRequest.BufferLength = 0;
|
|||
|
status = CMUSB_WriteP0(deviceObject,
|
|||
|
0x20, //bRequest,
|
|||
|
0x00, //bValueLo,
|
|||
|
0x00, //bValueHi,
|
|||
|
0x00, //bIndexLo,
|
|||
|
0x00 //bIndexHi,
|
|||
|
);
|
|||
|
|
|||
|
if (status != STATUS_SUCCESS)
|
|||
|
{
|
|||
|
// if we can't read the status there must be a serious error
|
|||
|
goto ExitTransmit3WBP;
|
|||
|
}
|
|||
|
|
|||
|
smartcardExtension->ReaderExtension->ulTimeoutP1 = DEFAULT_TIMEOUT_P1;
|
|||
|
status = CMUSB_ReadP1(deviceObject);
|
|||
|
if (status == STATUS_DEVICE_DATA_ERROR)
|
|||
|
{
|
|||
|
DebugStatus = CMUSB_ReadStateAfterP1Stalled(deviceObject);
|
|||
|
goto ExitTransmit3WBP;
|
|||
|
}
|
|||
|
else if (status != STATUS_SUCCESS)
|
|||
|
{
|
|||
|
// if we can't read the status there must be a serious error
|
|||
|
goto ExitTransmit3WBP;
|
|||
|
}
|
|||
|
|
|||
|
// check if card is really inserted
|
|||
|
if (smartcardExtension->SmartcardReply.Buffer[0] == 0x00)
|
|||
|
{
|
|||
|
// it is not sure, which error messages are accepted
|
|||
|
// status = STATUS_NO_MEDIA_IN_DEVICE;
|
|||
|
status = STATUS_UNRECOGNIZED_MEDIA;
|
|||
|
goto ExitTransmit3WBP;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
pbInData = smartcardExtension->IoRequest.RequestBuffer + sizeof(SYNC_TRANSFER);
|
|||
|
ulBitsToRead = ((PSYNC_TRANSFER)(smartcardExtension->IoRequest.RequestBuffer))->ulSyncBitsToRead;
|
|||
|
ulBytesToRead = ulBitsToRead/8 + (ulBitsToRead % 8 ? 1 : 0);
|
|||
|
// ulBitsToWrite = ((PSYNC_TRANSFER)(smartcardExtension->IoRequest.RequestBuffer))->ulSyncBitsToWrite;
|
|||
|
// ulBytesToWrite = ulBitsToWrite/8;
|
|||
|
|
|||
|
if (smartcardExtension->IoRequest.ReplyBufferLength < ulBytesToRead)
|
|||
|
{
|
|||
|
status = STATUS_BUFFER_OVERFLOW;
|
|||
|
goto ExitTransmit3WBP;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
// send command
|
|||
|
status=CMUSB_SendCommand3WBP(smartcardExtension, pbInData);
|
|||
|
if (status != STATUS_SUCCESS)
|
|||
|
{
|
|||
|
// if we can't send the command -> proceeding is useless
|
|||
|
goto ExitTransmit3WBP;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
// now we have to differenciate, wheter card is in
|
|||
|
// outgoing data mode (after read command) or
|
|||
|
// in processing mode (after write/erase command)
|
|||
|
switch (*pbInData & 0x3F)
|
|||
|
{
|
|||
|
case SLE4428_READ:
|
|||
|
case SLE4428_READ_PROT:
|
|||
|
// outgoing data mode
|
|||
|
|
|||
|
//now read data
|
|||
|
abSendBuffer[0]=CMUSB_CalcSynchControl(0,0,0,0, 0,1,0,0);
|
|||
|
RtlFillMemory((PVOID)&abSendBuffer[1],ATTR_MAX_IFSD_SYNCHRON_USB-1,abSendBuffer[0]);
|
|||
|
|
|||
|
//read data in 6 byte packages
|
|||
|
ulBytesRead=0;
|
|||
|
do
|
|||
|
{
|
|||
|
if ((ulBytesToRead - ulBytesRead) > ATTR_MAX_IFSD_SYNCHRON_USB/8)
|
|||
|
ulBytesToReadThisStep = ATTR_MAX_IFSD_SYNCHRON_USB/8;
|
|||
|
else
|
|||
|
ulBytesToReadThisStep = ulBytesToRead - ulBytesRead;
|
|||
|
|
|||
|
// now send command type 08 to CardManUSB
|
|||
|
smartcardExtension->SmartcardRequest.BufferLength = ulBytesToReadThisStep*8;
|
|||
|
RtlCopyBytes((PVOID) smartcardExtension->SmartcardRequest.Buffer,
|
|||
|
(PVOID) abSendBuffer,
|
|||
|
smartcardExtension->SmartcardRequest.BufferLength);
|
|||
|
status = CMUSB_WriteP0(deviceObject,
|
|||
|
0x08, //bRequest,
|
|||
|
0x00, //bValueLo,
|
|||
|
0x00, //bValueHi,
|
|||
|
0x00, //bIndexLo,
|
|||
|
0x00 //bIndexHi,
|
|||
|
);
|
|||
|
if (status != STATUS_SUCCESS)
|
|||
|
{
|
|||
|
// if we can't write command there must be a serious error
|
|||
|
goto ExitTransmit3WBP;
|
|||
|
}
|
|||
|
|
|||
|
status = CMUSB_ReadP1(deviceObject);
|
|||
|
if (status == STATUS_DEVICE_DATA_ERROR)
|
|||
|
{
|
|||
|
DebugStatus = CMUSB_ReadStateAfterP1Stalled(deviceObject);
|
|||
|
goto ExitTransmit3WBP;
|
|||
|
}
|
|||
|
else if (status != STATUS_SUCCESS)
|
|||
|
{
|
|||
|
// if we can't read there must be a serious error
|
|||
|
goto ExitTransmit3WBP;
|
|||
|
}
|
|||
|
|
|||
|
if (smartcardExtension->SmartcardReply.BufferLength!=ulBytesToReadThisStep)
|
|||
|
{
|
|||
|
// wrong number of bytes read
|
|||
|
// -> something went wrong
|
|||
|
status=STATUS_DEVICE_DATA_ERROR;
|
|||
|
goto ExitTransmit3WBP;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
RtlCopyBytes((PVOID) &(smartcardExtension->IoRequest.ReplyBuffer[ulBytesRead]),
|
|||
|
(PVOID) smartcardExtension->SmartcardReply.Buffer,
|
|||
|
smartcardExtension->SmartcardReply.BufferLength);
|
|||
|
|
|||
|
ulBytesRead+=smartcardExtension->SmartcardReply.BufferLength;
|
|||
|
}
|
|||
|
while ((status == STATUS_SUCCESS) && (ulBytesToRead > ulBytesRead));
|
|||
|
*(smartcardExtension->IoRequest.Information)=ulBytesRead;
|
|||
|
|
|||
|
if (status!=STATUS_SUCCESS)
|
|||
|
{
|
|||
|
goto ExitTransmit3WBP;
|
|||
|
}
|
|||
|
|
|||
|
// according to datasheet, clock should be set to low now
|
|||
|
// this is not necessary, because this is done before next command
|
|||
|
// or card is reseted respectivly
|
|||
|
|
|||
|
break;
|
|||
|
case SLE4428_WRITE:
|
|||
|
case SLE4428_WRITE_PROT:
|
|||
|
case SLE4428_COMPARE:
|
|||
|
case SLE4428_SET_COUNTER&0x3F:
|
|||
|
case SLE4428_COMPARE_PIN&0x3F:
|
|||
|
// processing mode
|
|||
|
|
|||
|
abSendBuffer[0]=CMUSB_CalcSynchControl(0,0,0,0, 0,1,0,0);
|
|||
|
RtlFillMemory((PVOID)&abSendBuffer[1],ATTR_MAX_IFSD_SYNCHRON_USB-1,abSendBuffer[0]);
|
|||
|
|
|||
|
do
|
|||
|
{
|
|||
|
|
|||
|
// now send command type 08 to CardManUSB
|
|||
|
smartcardExtension->SmartcardRequest.BufferLength = ATTR_MAX_IFSD_SYNCHRON_USB;
|
|||
|
RtlCopyBytes((PVOID) smartcardExtension->SmartcardRequest.Buffer,
|
|||
|
(PVOID) abSendBuffer,
|
|||
|
smartcardExtension->SmartcardRequest.BufferLength);
|
|||
|
status = CMUSB_WriteP0(deviceObject,
|
|||
|
0x08, //bRequest,
|
|||
|
0x00, //bValueLo,
|
|||
|
0x00, //bValueHi,
|
|||
|
0x00, //bIndexLo,
|
|||
|
0x00 //bIndexHi,
|
|||
|
);
|
|||
|
if (status != STATUS_SUCCESS)
|
|||
|
{
|
|||
|
// if we can't write command there must be a serious error
|
|||
|
goto ExitTransmit3WBP;
|
|||
|
}
|
|||
|
|
|||
|
status = CMUSB_ReadP1(deviceObject);
|
|||
|
if (status == STATUS_DEVICE_DATA_ERROR)
|
|||
|
{
|
|||
|
DebugStatus = CMUSB_ReadStateAfterP1Stalled(deviceObject);
|
|||
|
goto ExitTransmit3WBP;
|
|||
|
}
|
|||
|
else if (status != STATUS_SUCCESS)
|
|||
|
{
|
|||
|
// if we can't read there must be a serious error
|
|||
|
goto ExitTransmit3WBP;
|
|||
|
}
|
|||
|
|
|||
|
if (smartcardExtension->SmartcardReply.BufferLength!=ATTR_MAX_IFSD_SYNCHRON_USB/8)
|
|||
|
{
|
|||
|
// wrong number of bytes read
|
|||
|
// -> something went wrong
|
|||
|
status=STATUS_DEVICE_DATA_ERROR;
|
|||
|
goto ExitTransmit3WBP;
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
while ((status == STATUS_SUCCESS) &&
|
|||
|
(smartcardExtension->SmartcardReply.Buffer[smartcardExtension->SmartcardReply.BufferLength-1]==0xFF));
|
|||
|
*(smartcardExtension->IoRequest.Information)=0;
|
|||
|
|
|||
|
if (status!=STATUS_SUCCESS)
|
|||
|
{
|
|||
|
goto ExitTransmit3WBP;
|
|||
|
}
|
|||
|
|
|||
|
// according to datasheet, clock should be set to low now
|
|||
|
// this is not necessary, because this is done before next command
|
|||
|
// or card is reseted respectivly
|
|||
|
|
|||
|
|
|||
|
break;
|
|||
|
default:
|
|||
|
// should not happen
|
|||
|
status=STATUS_ILLEGAL_INSTRUCTION;
|
|||
|
goto ExitTransmit3WBP;
|
|||
|
}
|
|||
|
|
|||
|
ExitTransmit3WBP:
|
|||
|
|
|||
|
|
|||
|
SmartcardDebug(DEBUG_TRACE,
|
|||
|
("%s!Transmit3WBP: Exit %lx\n",DRIVER_NAME,status));
|
|||
|
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/*****************************************************************************
|
|||
|
Routine Description: Transmits a command (3 Bytes) to a SLE 4428/4418
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
*****************************************************************************/
|
|||
|
NTSTATUS
|
|||
|
CMUSB_SendCommand3WBP (
|
|||
|
IN PSMARTCARD_EXTENSION smartcardExtension,
|
|||
|
IN PUCHAR pbCommandData
|
|||
|
)
|
|||
|
{
|
|||
|
PDEVICE_OBJECT deviceObject;
|
|||
|
NTSTATUS status = STATUS_SUCCESS;
|
|||
|
NTSTATUS DebugStatus;
|
|||
|
UCHAR abSendBuffer[CMUSB_SYNCH_BUFFER_SIZE];
|
|||
|
UCHAR* pByte;
|
|||
|
UCHAR bValue;
|
|||
|
int i,j;
|
|||
|
|
|||
|
|
|||
|
SmartcardDebug(DEBUG_TRACE,
|
|||
|
("%s!SendCommand3WBP: Enter\n",DRIVER_NAME));
|
|||
|
|
|||
|
SmartcardDebug(DEBUG_PROTOCOL,
|
|||
|
("%s!SendCommand3WBP: 4442 Command = %02x %02x %02x\n",DRIVER_NAME,
|
|||
|
pbCommandData[0],
|
|||
|
pbCommandData[1],
|
|||
|
pbCommandData[2]));
|
|||
|
|
|||
|
deviceObject = smartcardExtension->OsData->DeviceObject;
|
|||
|
|
|||
|
// build control code for command to send
|
|||
|
// command is in first 3 Bytes of pbInData
|
|||
|
abSendBuffer[0]=CMUSB_CalcSynchControl(0,0,0,0, 0,0,0,0);
|
|||
|
|
|||
|
pByte=&abSendBuffer[1];
|
|||
|
for (j=0;j<3;j++)
|
|||
|
{
|
|||
|
for (i=0;i<8;i++)
|
|||
|
{
|
|||
|
bValue=(pbCommandData[j]&(1<<i));
|
|||
|
*pByte=CMUSB_CalcSynchControl(1,0,1,bValue, 1,1,1,bValue);
|
|||
|
pByte++;
|
|||
|
}
|
|||
|
}
|
|||
|
abSendBuffer[25]=CMUSB_CalcSynchControl(1,0,1,0, 0,0,0,0);
|
|||
|
// one additional clock cycle, because
|
|||
|
// first bit is only read back after second clock
|
|||
|
// for write it has no influence
|
|||
|
abSendBuffer[26]=CMUSB_CalcSynchControl(0,0,0,0, 0,1,0,0);
|
|||
|
// fill rest with zeros
|
|||
|
abSendBuffer[27]=CMUSB_CalcSynchControl(0,0,0,0, 0,0,0,0);
|
|||
|
RtlFillMemory((PVOID)&abSendBuffer[28],4,abSendBuffer[27]);
|
|||
|
|
|||
|
// now send command type 08 to CardManUSB
|
|||
|
smartcardExtension->SmartcardRequest.BufferLength = 32;
|
|||
|
RtlCopyBytes((PVOID) smartcardExtension->SmartcardRequest.Buffer,
|
|||
|
(PVOID) abSendBuffer,
|
|||
|
smartcardExtension->SmartcardRequest.BufferLength);
|
|||
|
status = CMUSB_WriteP0(deviceObject,
|
|||
|
0x08, //bRequest,
|
|||
|
0x00, //bValueLo,
|
|||
|
0x00, //bValueHi,
|
|||
|
0x00, //bIndexLo,
|
|||
|
0x00 //bIndexHi,
|
|||
|
);
|
|||
|
if (status != STATUS_SUCCESS)
|
|||
|
{
|
|||
|
// if we can't write command there must be a serious error
|
|||
|
goto ExitSendCommand3WBP;
|
|||
|
}
|
|||
|
|
|||
|
status = CMUSB_ReadP1(deviceObject);
|
|||
|
if (status == STATUS_DEVICE_DATA_ERROR)
|
|||
|
{
|
|||
|
DebugStatus = CMUSB_ReadStateAfterP1Stalled(deviceObject);
|
|||
|
goto ExitSendCommand3WBP;
|
|||
|
}
|
|||
|
else if (status != STATUS_SUCCESS)
|
|||
|
{
|
|||
|
// if we can't read there must be a serious error
|
|||
|
goto ExitSendCommand3WBP;
|
|||
|
}
|
|||
|
|
|||
|
if (smartcardExtension->SmartcardReply.BufferLength!=4)
|
|||
|
{
|
|||
|
// 32 bytes sent but not 4 bytes received
|
|||
|
// -> something went wrong
|
|||
|
status=STATUS_DEVICE_DATA_ERROR;
|
|||
|
goto ExitSendCommand3WBP;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
ExitSendCommand3WBP:
|
|||
|
|
|||
|
SmartcardDebug(DEBUG_TRACE,
|
|||
|
("%s!SendCommand3WBP: Exit %lx\n",DRIVER_NAME,status));
|
|||
|
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
/*****************************************************************************
|
|||
|
* History:
|
|||
|
* $Log: scusbsyn.c $
|
|||
|
* Revision 1.3 2000/08/24 09:04:39 TBruendl
|
|||
|
* No comment given
|
|||
|
*
|
|||
|
* Revision 1.2 2000/07/24 11:35:00 WFrischauf
|
|||
|
* No comment given
|
|||
|
*
|
|||
|
* Revision 1.1 2000/07/20 11:50:16 WFrischauf
|
|||
|
* No comment given
|
|||
|
*
|
|||
|
*
|
|||
|
******************************************************************************/
|
|||
|
|