Windows2003-3790/drivers/smartcrd/sccmusbm/scusbcb.c
2020-09-30 16:53:55 +02:00

3490 lines
117 KiB
C

/*****************************************************************************
@doc INT EXT
******************************************************************************
* $ProjectName: $
* $ProjectRevision: $
*-----------------------------------------------------------------------------
* $Source: z:/pr/cmeu0/sw/sccmusbm.ms/rcs/scusbcb.c $
* $Revision: 1.9 $
*-----------------------------------------------------------------------------
* $Author: WFrischauf $
*-----------------------------------------------------------------------------
* History: see EOF
*-----------------------------------------------------------------------------
*
* Copyright © 2000 OMNIKEY AG
******************************************************************************/
#include "wdm.h"
#include "stdarg.h"
#include "stdio.h"
#include "usbdi.h"
#include "usbdlib.h"
#include "sccmusbm.h"
ULONG dataRatesSupported[] = { 9600, 19200, 38400, 76800, 115200};
ULONG CLKFrequenciesSupported[] = {3571};
/*****************************************************************************
Routine Description:
Arguments:
Return Value:
*****************************************************************************/
NTSTATUS CMUSB_StartCardTracking(
IN PDEVICE_OBJECT DeviceObject
)
{
NTSTATUS NTStatus;
HANDLE hThread;
PDEVICE_EXTENSION DeviceExtension;
PSMARTCARD_EXTENSION SmartcardExtension;
DeviceExtension = DeviceObject->DeviceExtension;
SmartcardExtension = &DeviceExtension->SmartcardExtension;
// settings for thread synchronization
SmartcardExtension->ReaderExtension->TimeToTerminateThread = FALSE;
SmartcardExtension->ReaderExtension->fThreadTerminated = FALSE;
SmartcardDebug(DEBUG_TRACE,
("%s!StartCardTracking: Enter\n",DRIVER_NAME));
KeWaitForSingleObject(&SmartcardExtension->ReaderExtension->CardManIOMutex,
Executive,
KernelMode,
FALSE,
NULL);
// create thread for updating current state
NTStatus = PsCreateSystemThread(&hThread,
THREAD_ALL_ACCESS,
NULL,
NULL,
NULL,
CMUSB_UpdateCurrentStateThread,
DeviceObject);
if (!NT_ERROR(NTStatus))
{
//
// We've got the thread. Now get a pointer to it.
//
NTStatus = ObReferenceObjectByHandle(hThread,
THREAD_ALL_ACCESS,
NULL,
KernelMode,
&SmartcardExtension->ReaderExtension->ThreadObjectPointer,
NULL);
if (NT_ERROR(NTStatus))
{
SmartcardExtension->ReaderExtension->TimeToTerminateThread = TRUE;
}
else
{
//
// Now that we have a reference to the thread
// we can simply close the handle.
//
ZwClose(hThread);
}
}
SmartcardDebug(DEBUG_DRIVER,
("%s!StartCardTracking: -----------------------------------------------------------\n",DRIVER_NAME));
SmartcardDebug(DEBUG_DRIVER,
("%s!StartCardTracking: STARTING THREAD\n",DRIVER_NAME));
SmartcardDebug(DEBUG_DRIVER,
("%s!StartCardTracking: -----------------------------------------------------------\n",DRIVER_NAME));
KeReleaseMutex(&SmartcardExtension->ReaderExtension->CardManIOMutex,
FALSE);
SmartcardDebug(DEBUG_TRACE,
("%s!StartCardTracking: Exit %lx\n",DRIVER_NAME,NTStatus));
return NTStatus;
}
/*****************************************************************************
Routine Description:
Arguments:
Return Value:
*****************************************************************************/
VOID CMUSB_StopCardTracking(
IN PDEVICE_OBJECT DeviceObject
)
{
PDEVICE_EXTENSION DeviceExtension;
PSMARTCARD_EXTENSION SmartcardExtension;
SmartcardDebug(DEBUG_TRACE,
("%s!StopCardTracking: Enter\n",DRIVER_NAME));
DeviceExtension = DeviceObject->DeviceExtension;
SmartcardExtension = &DeviceExtension->SmartcardExtension;
if (SmartcardExtension->ReaderExtension->fThreadTerminated == FALSE) {
SmartcardDebug(DEBUG_DRIVER,
("%s!StopCardTracking: waiting for mutex\n",DRIVER_NAME));
// kill thread
KeWaitForSingleObject(&SmartcardExtension->ReaderExtension->CardManIOMutex,
Executive,
KernelMode,
FALSE,
NULL);
SmartcardExtension->ReaderExtension->TimeToTerminateThread = TRUE;
KeReleaseMutex(&SmartcardExtension->ReaderExtension->CardManIOMutex,FALSE);
KeWaitForSingleObject(SmartcardExtension->ReaderExtension->ThreadObjectPointer,
Executive,
KernelMode,
FALSE,
NULL);
ObDereferenceObject(SmartcardExtension->ReaderExtension->ThreadObjectPointer);
}
SmartcardDebug(DEBUG_TRACE,
("%s!StopCardTracking: Exit\n",DRIVER_NAME));
}
/*****************************************************************************
Routine Description:
Arguments:
Return Value:
*****************************************************************************/
VOID CMUSB_UpdateCurrentStateThread(
IN PVOID Context
)
{
PDEVICE_OBJECT DeviceObject = Context;
PDEVICE_EXTENSION DeviceExtension;
PSMARTCARD_EXTENSION SmartcardExtension;
NTSTATUS NTStatus,DebugStatus;
ULONG ulInterval;
DeviceExtension = DeviceObject->DeviceExtension;
SmartcardExtension = &DeviceExtension->SmartcardExtension;
KeWaitForSingleObject(&DeviceExtension->CanRunUpdateThread,
Executive,
KernelMode,
FALSE,
NULL);
SmartcardDebug(DEBUG_DRIVER,
("%s!UpdateCurrentStateThread started\n",DRIVER_NAME));
do {
// every 500 ms the s NTStatus request is sent
ulInterval = 500;
KeWaitForSingleObject(&SmartcardExtension->ReaderExtension->CardManIOMutex,
Executive,
KernelMode,
FALSE,
NULL);
if ( SmartcardExtension->ReaderExtension->TimeToTerminateThread ) {
SmartcardDebug(DEBUG_DRIVER,
("%s!UpdateCurrentStateThread: -----------------------------------------\n",DRIVER_NAME));
SmartcardDebug(DEBUG_DRIVER,
("%s!UpdateCurrentStateThread: STOPPING THREAD\n",DRIVER_NAME));
SmartcardDebug(DEBUG_DRIVER,
("%s!UpdateCurrentStateThread: -----------------------------------------\n",DRIVER_NAME));
KeReleaseMutex(&SmartcardExtension->ReaderExtension->CardManIOMutex,FALSE);
SmartcardExtension->ReaderExtension->fThreadTerminated = TRUE;
PsTerminateSystemThread( STATUS_SUCCESS );
}
NTStatus = CMUSB_UpdateCurrentState (DeviceObject);
if (NTStatus == STATUS_DEVICE_DATA_ERROR) {
SmartcardDebug(DEBUG_DRIVER,
("%s!setting update interval to 1ms\n",DRIVER_NAME));
ulInterval = 1;
} else if (NTStatus != STATUS_SUCCESS) {
SmartcardDebug(DEBUG_DRIVER,
("%s!NO STATUS RECEIVED\n",DRIVER_NAME));
}
KeReleaseMutex(&SmartcardExtension->ReaderExtension->CardManIOMutex,FALSE);
CMUSB_Wait (ulInterval);
}
while (TRUE);
}
NTSTATUS CMUSB_UpdateCurrentState(
IN PDEVICE_OBJECT DeviceObject
)
{
NTSTATUS NTStatus;
PDEVICE_EXTENSION DeviceExtension;
PSMARTCARD_EXTENSION SmartcardExtension;
BOOLEAN fCardStateChanged = FALSE;
ULONG ulBytesRead;
KIRQL irql;
DeviceExtension = DeviceObject->DeviceExtension;
SmartcardExtension = &DeviceExtension->SmartcardExtension;
SmartcardExtension->SmartcardRequest.BufferLength = 0;
NTStatus = CMUSB_WriteP0(DeviceObject,
0x20, //bRequest,
0x00, //bValueLo,
0x00, //bValueHi,
0x00, //bIndexLo,
0x00 //bIndexHi,
);
if (NTStatus == STATUS_SUCCESS) {
SmartcardExtension->ReaderExtension->ulTimeoutP1 = DEFAULT_TIMEOUT_P1;
SmartcardExtension->SmartcardReply.BufferLength = 1;
NTStatus = CMUSB_ReadP1(DeviceObject);
ulBytesRead = SmartcardExtension->SmartcardReply.BufferLength;
if (NTStatus == STATUS_SUCCESS && ulBytesRead == 1) { /* we got the NTStatus information */
if ((SmartcardExtension->SmartcardReply.Buffer[0] & 0x40) == 0x40) {
if ((SmartcardExtension->SmartcardReply.Buffer[0] & 0x80) == 0x80) {
SmartcardExtension->ReaderExtension->ulNewCardState = POWERED;
} else {
SmartcardExtension->ReaderExtension->ulNewCardState = INSERTED;
}
} else {
SmartcardExtension->ReaderExtension->ulNewCardState = REMOVED;
}
KeAcquireSpinLock(&SmartcardExtension->OsData->SpinLock,
&irql);
if (SmartcardExtension->ReaderExtension->ulNewCardState == INSERTED &&
SmartcardExtension->ReaderExtension->ulOldCardState == POWERED ) {
// card has been removed and reinserted
SmartcardExtension->ReaderExtension->ulNewCardState = REMOVED;
}
if (SmartcardExtension->ReaderExtension->ulNewCardState == INSERTED &&
(SmartcardExtension->ReaderExtension->ulOldCardState == UNKNOWN ||
SmartcardExtension->ReaderExtension->ulOldCardState == REMOVED )) {
// card has been inserted
SmartcardDebug(DEBUG_DRIVER,( "%s!UpdateCurrentStateThread Smartcard inserted\n",DRIVER_NAME));
fCardStateChanged = TRUE;
SmartcardExtension->ReaderCapabilities.CurrentState = SCARD_SWALLOWED;
SmartcardExtension->CardCapabilities.Protocol.Selected = SCARD_PROTOCOL_UNDEFINED;
}
// state after reset of the PC
if (SmartcardExtension->ReaderExtension->ulNewCardState == POWERED &&
SmartcardExtension->ReaderExtension->ulOldCardState == UNKNOWN ) {
// card has been inserted
SmartcardDebug(DEBUG_DRIVER,( "%s!UpdateCurrentStateThread Smartcard inserted (and powered)\n",DRIVER_NAME));
fCardStateChanged = TRUE;
SmartcardExtension->ReaderCapabilities.CurrentState = SCARD_SWALLOWED;
SmartcardExtension->CardCapabilities.Protocol.Selected = SCARD_PROTOCOL_UNDEFINED;
}
if (SmartcardExtension->ReaderExtension->ulNewCardState == REMOVED &&
(SmartcardExtension->ReaderExtension->ulOldCardState == UNKNOWN ||
SmartcardExtension->ReaderExtension->ulOldCardState == INSERTED ||
SmartcardExtension->ReaderExtension->ulOldCardState == POWERED ) ) {
// card has been removed
fCardStateChanged = TRUE;
SmartcardDebug(DEBUG_DRIVER,( "%s!UpdateCurrentStateThread Smartcard removed\n",DRIVER_NAME));
SmartcardExtension->ReaderCapabilities.CurrentState = SCARD_ABSENT;
SmartcardExtension->CardCapabilities.Protocol.Selected = SCARD_PROTOCOL_UNDEFINED;
SmartcardExtension->CardCapabilities.ATR.Length = 0;
RtlFillMemory((PVOID)&SmartcardExtension->ReaderExtension->CardParameters,
sizeof(CARD_PARAMETERS),
0x00);
}
KeReleaseSpinLock(&SmartcardExtension->OsData->SpinLock,
irql);
// complete IOCTL_SMARTCARD_IS_ABSENT or IOCTL_SMARTCARD_IS_PRESENT
if (fCardStateChanged == TRUE &&
SmartcardExtension->OsData->NotificationIrp != NULL) {
SmartcardDebug(DEBUG_DRIVER,("%s!UpdateCurrentStateThread: completing IRP\n",DRIVER_NAME));
CMUSB_CompleteCardTracking(SmartcardExtension);
}
// save old state
SmartcardExtension->ReaderExtension->ulOldCardState = SmartcardExtension->ReaderExtension->ulNewCardState;
}
}
return NTStatus;
}
/*****************************************************************************
Routine Description:
Arguments:
Return Value:
*****************************************************************************/
VOID CMUSB_CompleteCardTracking(
IN PSMARTCARD_EXTENSION SmartcardExtension
)
{
KIRQL ioIrql, keIrql;
PIRP notificationIrp;
IoAcquireCancelSpinLock(&ioIrql);
KeAcquireSpinLock(&SmartcardExtension->OsData->SpinLock, &keIrql);
notificationIrp = SmartcardExtension->OsData->NotificationIrp;
SmartcardExtension->OsData->NotificationIrp = NULL;
KeReleaseSpinLock(&SmartcardExtension->OsData->SpinLock, keIrql);
if (notificationIrp) {
IoSetCancelRoutine(notificationIrp,NULL);
}
IoReleaseCancelSpinLock(ioIrql);
if (notificationIrp) {
SmartcardDebug(DEBUG_DRIVER,
("%s!CompleteCardTracking: Completing NotificationIrp %lxh\n",DRIVER_NAME,notificationIrp));
// finish the request
if (notificationIrp->Cancel) {
notificationIrp->IoStatus.Status = STATUS_CANCELLED;
} else {
notificationIrp->IoStatus.Status = STATUS_SUCCESS;
}
notificationIrp->IoStatus.Information = 0;
IoCompleteRequest(notificationIrp, IO_NO_INCREMENT);
}
}
/*****************************************************************************
Routine Description:
Arguments:
Return Value:
*****************************************************************************/
NTSTATUS CMUSB_Wait (ULONG ulMilliseconds)
{
NTSTATUS NTStatus = STATUS_SUCCESS;
LARGE_INTEGER WaitTime;
// -10000 indicates 1ms relativ
WaitTime = RtlConvertLongToLargeInteger(ulMilliseconds * -10000);
KeDelayExecutionThread(KernelMode,FALSE,&WaitTime);
return NTStatus;
}
/*****************************************************************************
Routine Description:
Arguments:
Return Value:
*****************************************************************************/
NTSTATUS CMUSB_CreateClose(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
NTSTATUS NTStatus = STATUS_SUCCESS;
PDEVICE_EXTENSION DeviceExtension;
PSMARTCARD_EXTENSION SmartcardExtension;
PIO_STACK_LOCATION IrpStack = IoGetCurrentIrpStackLocation(Irp);
SmartcardDebug(DEBUG_TRACE,
("%s!CreateClose: Enter\n",DRIVER_NAME));
DeviceExtension = DeviceObject->DeviceExtension;
SmartcardExtension = &DeviceExtension->SmartcardExtension;
//
// dispatch major function
//
switch (IrpStack->MajorFunction) {
case IRP_MJ_CREATE:
SmartcardDebug(DEBUG_DRIVER,
("%s!CreateClose: IRP_MJ_CREATE\n",DRIVER_NAME));
if (DeviceExtension->RemoveDeviceRequested) {
NTStatus = STATUS_DEVICE_BUSY;
} else {
if (InterlockedIncrement(&DeviceExtension->lOpenCount) > 1) {
InterlockedDecrement(&DeviceExtension->lOpenCount);
NTStatus = STATUS_ACCESS_DENIED;
}
}
break;
case IRP_MJ_CLOSE:
SmartcardDebug(DEBUG_DRIVER,
("%s!CreateClose: IRP_MJ_CLOSE\n",DRIVER_NAME));
if (InterlockedDecrement(&DeviceExtension->lOpenCount) < 0) {
InterlockedIncrement(&DeviceExtension->lOpenCount);
}
// check if the device has been removed
// if so free the resources
if (DeviceExtension->DeviceRemoved == TRUE) {
SmartcardDebug(DEBUG_DRIVER,
("%s!CreateClose: freeing resources\n",DRIVER_NAME));
if (DeviceExtension->fPnPResourceManager == FALSE) {
//
// Free all allocated buffer
//
ExFreePool(DeviceExtension->DosDeviceName.Buffer);
}
ExFreePool(SmartcardExtension->ReaderExtension);
SmartcardExtension->ReaderExtension = NULL;
//
// Let the lib free the send/receive buffers
//
SmartcardExit(SmartcardExtension);
}
break;
default:
//
// unrecognized command
//
NTStatus = STATUS_INVALID_DEVICE_REQUEST;
break;
}
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = NTStatus;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
SmartcardDebug(DEBUG_TRACE,
("%s!CreateClose: Exit %lx\n",DRIVER_NAME,NTStatus));
return NTStatus;
}
/*****************************************************************************
Routine Description:
Arguments:
Return Value:
*****************************************************************************/
NTSTATUS CMUSB_Transmit(
IN PSMARTCARD_EXTENSION SmartcardExtension
)
{
NTSTATUS NTStatus;
//this seems to make problems in Windows 98
//KeSetPriorityThread(KeGetCurrentThread(),HIGH_PRIORITY);
switch (SmartcardExtension->CardCapabilities.Protocol.Selected) {
case SCARD_PROTOCOL_RAW:
NTStatus = STATUS_INVALID_DEVICE_REQUEST;
break;
case SCARD_PROTOCOL_T0:
NTStatus = CMUSB_TransmitT0(SmartcardExtension);
break;
case SCARD_PROTOCOL_T1:
NTStatus = CMUSB_TransmitT1(SmartcardExtension);
break;
default:
NTStatus = STATUS_INVALID_DEVICE_REQUEST;
break;
}
//KeSetPriorityThread(KeGetCurrentThread(),LOW_REALTIME_PRIORITY);
return NTStatus;
}
/*****************************************************************************
Routine Description:
Arguments:
Return Value:
*****************************************************************************/
NTSTATUS CMUSB_ResetT0ReadBuffer(
PSMARTCARD_EXTENSION SmartcardExtension
)
{
SmartcardExtension->ReaderExtension->T0ReadBuffer_OffsetLastByte = -1;
SmartcardExtension->ReaderExtension->T0ReadBuffer_OffsetLastByteRead = -1;
return STATUS_SUCCESS;
}
/*****************************************************************************
Routine Description:
Arguments:
Return Value:
*****************************************************************************/
NTSTATUS CMUSB_ReadT0(
PSMARTCARD_EXTENSION SmartcardExtension
)
{
NTSTATUS NTStatus = STATUS_SUCCESS;
NTSTATUS DebugStatus;
LONG lBytesToRead;
LONG lBytesRead;
LONG lLastByte;
LONG lLastByteRead;
PDEVICE_EXTENSION DeviceExtension;
PUSBD_PIPE_INFORMATION pipeHandle = NULL;
PUSBD_INTERFACE_INFORMATION interface;
SmartcardDebug(DEBUG_TRACE,
("%s!ReadT0: Enter\n",DRIVER_NAME));
DeviceExtension = SmartcardExtension->OsData->DeviceObject->DeviceExtension;
interface = DeviceExtension->UsbInterface;
pipeHandle = &interface->Pipes[0];
lBytesToRead = (LONG)SmartcardExtension->SmartcardReply.BufferLength;
lLastByte = SmartcardExtension->ReaderExtension->T0ReadBuffer_OffsetLastByte;
lLastByteRead = SmartcardExtension->ReaderExtension->T0ReadBuffer_OffsetLastByteRead;
// check if further bytes must be read from pipe 1
while (lLastByteRead + lBytesToRead > lLastByte) {
SmartcardExtension->SmartcardReply.BufferLength = 1;
SmartcardExtension->ReaderExtension->ulTimeoutP1 = 1000 +
(ULONG)((SmartcardExtension->CardCapabilities.T0.WT/1000) * lBytesToRead);
NTStatus = CMUSB_ReadP1(SmartcardExtension->OsData->DeviceObject);
if (NTStatus == STATUS_DEVICE_DATA_ERROR) {
DebugStatus = CMUSB_ReadStateAfterP1Stalled(SmartcardExtension->OsData->DeviceObject);
goto ExitReadT0;
} else if (NTStatus != STATUS_SUCCESS) {
goto ExitReadT0;
}
lBytesRead = (LONG)SmartcardExtension->SmartcardReply.BufferLength;
RtlCopyBytes((PVOID)(SmartcardExtension->ReaderExtension->T0ReadBuffer + (lLastByte +1)),
(PVOID)SmartcardExtension->SmartcardReply.Buffer,
lBytesRead);
lLastByte += lBytesRead;
} // end of while
// copy bytes
SmartcardExtension->SmartcardReply.BufferLength = lBytesToRead;
RtlCopyBytes ((PVOID)SmartcardExtension->SmartcardReply.Buffer,
(PVOID)(SmartcardExtension->ReaderExtension->T0ReadBuffer + (lLastByteRead +1)),
lBytesToRead);
lLastByteRead += lBytesToRead;
/*
SmartcardDebug(DEBUG_TRACE,
("%s!lBytesToRead=%ld lLastByte=%ld lLastByteRead=%ld\n",
DRIVER_NAME,
lBytesToRead,
lLastByte,
lLastByteRead)
);
*/
SmartcardExtension->ReaderExtension->T0ReadBuffer_OffsetLastByte = lLastByte;
SmartcardExtension->ReaderExtension->T0ReadBuffer_OffsetLastByteRead = lLastByteRead;
SmartcardDebug(DEBUG_TRACE,
("%s!ReadT0: Exit %lx\n",DRIVER_NAME,NTStatus));
ExitReadT0:
return NTStatus;
}
/*****************************************************************************
Routine Description:
Arguments:
Return Value:
*****************************************************************************/
#define T0_HEADER_LEN 0x05
#define T0_STATE_LEN 0x02
#define TIMEOUT_CANCEL_READ_P1 30000
NTSTATUS CMUSB_TransmitT0(
PSMARTCARD_EXTENSION SmartcardExtension
)
{
NTSTATUS NTStatus;
NTSTATUS DebugStatus;
UCHAR bWriteBuffer[CMUSB_BUFFER_SIZE];
UCHAR bReadBuffer [CMUSB_BUFFER_SIZE];
ULONG ulWriteBufferOffset;
ULONG ulReadBufferOffset;
ULONG ulBytesToWrite;
ULONG ulBytesToRead;
ULONG ulBytesToWriteThisStep;
ULONG ulBytesToReadThisStep;
ULONG ulBytesStillToWrite;
ULONG ulBytesRead;
ULONG ulBytesStillToRead;
BOOLEAN fDataDirectionFromCard;
BYTE bProcedureByte;
BYTE bINS;
BOOLEAN fT0TransferToCard;
BOOLEAN fT0TransferFromCard;
BOOLEAN fSW1SW2Sent;
ULONG ulUsedCWT;
UCHAR bUsedCWTHi;
LARGE_INTEGER liTimeout;
PDEVICE_EXTENSION DeviceExtension;
UCHAR bTmp;
ULONG i;
PUSBD_PIPE_INFORMATION pipeHandle = NULL;
PUSBD_INTERFACE_INFORMATION interface;
SmartcardDebug(DEBUG_TRACE,
("%s!TransmitT0 : Enter\n",DRIVER_NAME));
fT0TransferToCard = FALSE;
fT0TransferFromCard = FALSE;
fSW1SW2Sent = FALSE;
// resync CardManUSB by reading the NTStatus byte
SmartcardExtension->SmartcardRequest.BufferLength = 0;
NTStatus = CMUSB_WriteP0(SmartcardExtension->OsData->DeviceObject,
0x20, //bRequest,
0x00, //bValueLo,
0x00, //bValueHi,
0x00, //bIndexLo,
0x00 //bIndexHi,
);
if (NTStatus != STATUS_SUCCESS) {
// if we can't read the NTStatus there must be a serious error
goto ExitTransmitT0;
}
SmartcardExtension->ReaderExtension->ulTimeoutP1 = DEFAULT_TIMEOUT_P1;
SmartcardExtension->SmartcardReply.BufferLength = 1;
NTStatus = CMUSB_ReadP1(SmartcardExtension->OsData->DeviceObject);
if (NTStatus == STATUS_DEVICE_DATA_ERROR) {
DebugStatus = CMUSB_ReadStateAfterP1Stalled(SmartcardExtension->OsData->DeviceObject);
goto ExitTransmitT0;
} else if (NTStatus != STATUS_SUCCESS) {
// if we can't read the NTStatus there must be a serious error
goto ExitTransmitT0;
}
DeviceExtension = SmartcardExtension->OsData->DeviceObject->DeviceExtension;
interface = DeviceExtension->UsbInterface;
pipeHandle = &interface->Pipes[0];
SmartcardExtension->ReaderExtension->ulTimeoutP1 = (ULONG)(SmartcardExtension->CardCapabilities.T0.WT/1000);
//
// Let the lib build a T=0 packet
//
SmartcardExtension->SmartcardRequest.BufferLength = 0; // no bytes additionally needed
NTStatus = SmartcardT0Request(SmartcardExtension);
if (NTStatus != STATUS_SUCCESS) {
//
// This lib detected an error in the data to send.
//
goto ExitTransmitT0;
}
ulBytesStillToWrite = ulBytesToWrite = T0_HEADER_LEN + SmartcardExtension->T0.Lc;
ulBytesStillToRead = ulBytesToRead = SmartcardExtension->T0.Le;
if (SmartcardExtension->T0.Lc)
fT0TransferToCard = TRUE;
if (SmartcardExtension->T0.Le)
fT0TransferFromCard = TRUE;
// ----------------------------
// smart card ==> CardMan USB
// ----------------------------
if (fT0TransferFromCard) {
SmartcardDebug(DEBUG_PROTOCOL,
("%s!TransmitT0: MODE 3\n",DRIVER_NAME));
// granularity 256 ms
ulUsedCWT = (ULONG)(SmartcardExtension->CardCapabilities.T0.WT/1000);
SmartcardDebug(DEBUG_PROTOCOL,
("%s!TransmitT0: ulUsedCWT= %ld\n",DRIVER_NAME,ulUsedCWT));
bUsedCWTHi = (UCHAR)(((ulUsedCWT & 0x0000FF00)>>8) + 1 + 5) ;
// copy data to the write buffer
SmartcardDebug(DEBUG_PROTOCOL,
("%s!TransmitT0: CLA = %x INS = %x P1 = %x P2 = %x L = %x\n", DRIVER_NAME,
SmartcardExtension->SmartcardRequest.Buffer[0],
SmartcardExtension->SmartcardRequest.Buffer[1],
SmartcardExtension->SmartcardRequest.Buffer[2],
SmartcardExtension->SmartcardRequest.Buffer[3],
SmartcardExtension->SmartcardRequest.Buffer[4]));
RtlCopyBytes((PVOID)bWriteBuffer,
(PVOID)SmartcardExtension->SmartcardRequest.Buffer,
ulBytesToWrite);
bINS = bWriteBuffer[1];
ulWriteBufferOffset = 0;
ulReadBufferOffset = 0;
// STEP 1 : write CLA INS P1 P2 Lc
ulBytesToWriteThisStep = 5;
RtlCopyBytes((PVOID)(SmartcardExtension->SmartcardRequest.Buffer),
(PVOID)(bWriteBuffer+ulWriteBufferOffset),
ulBytesToWriteThisStep);
if (SmartcardExtension->ReaderExtension->fInverseAtr == TRUE) {
CMUSB_InverseBuffer(SmartcardExtension->SmartcardRequest.Buffer,
SmartcardExtension->SmartcardRequest.BufferLength);
}
SmartcardExtension->SmartcardReply.BufferLength = 512;
NTStatus = CMUSB_ReadP1_T0(SmartcardExtension->OsData->DeviceObject);
if (NTStatus != STATUS_SUCCESS) {
SmartcardDebug(DEBUG_PROTOCOL,
("%s!TransmitT0: CMUSB_ReadP1_T0 returned = %x\n",DRIVER_NAME,NTStatus));
goto ExitTransmitT0;
}
SmartcardExtension->SmartcardRequest.BufferLength = ulBytesToWriteThisStep;
NTStatus = CMUSB_WriteP0(SmartcardExtension->OsData->DeviceObject,
0x03, // mode 3
bUsedCWTHi, //bValueLo,
0x00, //bValueHi,
(UCHAR)(ulBytesToRead%256), //bIndexLo,
(UCHAR)(SmartcardExtension->SmartcardRequest.Buffer[1]) //bIndexHi,
);
if (NTStatus != STATUS_SUCCESS) {
SmartcardDebug(DEBUG_PROTOCOL,
("%s!TransmitT0: CMUSB_WriteP0 returned %x\n",DRIVER_NAME,NTStatus));
goto ExitTransmitT0;
}
liTimeout = RtlConvertLongToLargeInteger(TIMEOUT_CANCEL_READ_P1 * -10000);
SmartcardDebug(DEBUG_PROTOCOL,
("%s!TransmitT0: waiting for P1 event\n",DRIVER_NAME,NTStatus));
NTStatus = KeWaitForSingleObject(&DeviceExtension->ReadP1Completed,
Executive,
KernelMode,
FALSE,
&liTimeout);
// -----------------------------
// check if P1 has been stalled
// -----------------------------
if (SmartcardExtension->ReaderExtension->fP1Stalled == TRUE) {
SmartcardDebug(DEBUG_PROTOCOL,
("%s!STransmitT0: TATUS_DEVICE_DATA_ERROR\n",DRIVER_NAME));
NTStatus = STATUS_DEVICE_DATA_ERROR;
// P1 has been stalled ==> we must reset the pipe and send a NTStatus to enable it again
DebugStatus = CMUSB_ResetPipe(SmartcardExtension->OsData->DeviceObject,
pipeHandle);
DebugStatus = CMUSB_ReadStateAfterP1Stalled(SmartcardExtension->OsData->DeviceObject);
SmartcardExtension->SmartcardReply.BufferLength = 0;
goto ExitTransmitT0;
}
// -------------------------------
// check if a timeout has occured
// -------------------------------
else if (NTStatus == STATUS_TIMEOUT) {
// probably the smart card does not work
// cancel T0 read operation by sending any P0 command
SmartcardDebug(DEBUG_PROTOCOL,
("%s!TransmitT0: cancelling read operation\n",DRIVER_NAME));
SmartcardExtension->SmartcardRequest.BufferLength = 0;
NTStatus = CMUSB_WriteP0(SmartcardExtension->OsData->DeviceObject,
0x20, //bRequest,
0x00, //bValueLo,
0x00, //bValueHi,
0x00, //bIndexLo,
0x00 //bIndexHi,
);
NTStatus = STATUS_IO_TIMEOUT;
goto ExitTransmitT0;
}
// -------------------------------------------
// check if at least 9 bytes have been sent
// -------------------------------------------
else if (SmartcardExtension->SmartcardReply.BufferLength < 9) {
NTStatus = STATUS_UNSUCCESSFUL;
goto ExitTransmitT0;
} else {
#if DBG
SmartcardDebug(DEBUG_PROTOCOL,
("%s!<==[P1] ",DRIVER_NAME));
for (i=0;i< SmartcardExtension->SmartcardReply.BufferLength;i++) {
bTmp = SmartcardExtension->SmartcardReply.Buffer[i];
if (SmartcardExtension->ReaderExtension->fInverseAtr &&
SmartcardExtension->ReaderExtension->ulTimeoutP1 != DEFAULT_TIMEOUT_P1) {
//CMUSB_InverseBuffer(&bTmp,1);
SmartcardDebug(DEBUG_PROTOCOL,("%x ",bTmp));
} else {
SmartcardDebug(DEBUG_PROTOCOL,("%x ",bTmp));
}
}
SmartcardDebug(DEBUG_PROTOCOL,
("(%ld)\n",SmartcardExtension->SmartcardReply.BufferLength));
#endif
// ignore the first 8 dummy bytes
SmartcardExtension->SmartcardReply.BufferLength -= 8;
RtlCopyBytes((PVOID)(bReadBuffer),
(PVOID)(SmartcardExtension->SmartcardReply.Buffer+8),
SmartcardExtension->SmartcardReply.BufferLength);
RtlCopyBytes((PVOID)(SmartcardExtension->SmartcardReply.Buffer),
(PVOID)(bReadBuffer),
SmartcardExtension->SmartcardReply.BufferLength);
if (SmartcardExtension->ReaderExtension->fInverseAtr) {
CMUSB_InverseBuffer(SmartcardExtension->SmartcardReply.Buffer,
SmartcardExtension->SmartcardReply.BufferLength);
}
}
}
// -----------------------------
// CardMan USB ==> smart card or
// no transfer
// -----------------------------
else {
SmartcardDebug(DEBUG_PROTOCOL,
("%s!TransmitT0: MODE 2\n",DRIVER_NAME));
// copy data to the write buffer
SmartcardDebug(DEBUG_PROTOCOL,
("%s!TransmitT0: CLA = %x INS = %x P1 = %x P2 = %X L = %x\n",DRIVER_NAME,
SmartcardExtension->SmartcardRequest.Buffer[0],
SmartcardExtension->SmartcardRequest.Buffer[1],
SmartcardExtension->SmartcardRequest.Buffer[2],
SmartcardExtension->SmartcardRequest.Buffer[3],
SmartcardExtension->SmartcardRequest.Buffer[4]));
RtlCopyBytes((PVOID)bWriteBuffer,
(PVOID)SmartcardExtension->SmartcardRequest.Buffer,
ulBytesToWrite);
// SendingToCard:
ulWriteBufferOffset = 0;
ulReadBufferOffset = 0;
bINS = bWriteBuffer[1];
// STEP 1 : write CLA INS P1 P2 Lc
ulBytesToWriteThisStep = 5;
RtlCopyBytes((PVOID)(SmartcardExtension->SmartcardRequest.Buffer),
(PVOID)(bWriteBuffer+ulWriteBufferOffset),
ulBytesToWriteThisStep);
SmartcardExtension->SmartcardRequest.BufferLength = ulBytesToWriteThisStep;
if (SmartcardExtension->ReaderExtension->fInverseAtr == TRUE) {
CMUSB_InverseBuffer(SmartcardExtension->SmartcardRequest.Buffer,
SmartcardExtension->SmartcardRequest.BufferLength);
}
NTStatus = CMUSB_WriteP0(SmartcardExtension->OsData->DeviceObject,
0x02, //T=0
0x00, //bValueLo,
0x00, //bValueHi,
0x00, //bIndexLo,
0x00 //bIndexHi,
);
if (NTStatus != STATUS_SUCCESS) {
goto ExitTransmitT0;
}
ulWriteBufferOffset += ulBytesToWriteThisStep;
ulBytesStillToWrite -= ulBytesToWriteThisStep;
NTStatus = CMUSB_ResetT0ReadBuffer(SmartcardExtension);
// STEP 2 : read procedure byte
do {
do {
SmartcardExtension->SmartcardReply.BufferLength = 1;
NTStatus = CMUSB_ReadT0(SmartcardExtension);
if (NTStatus != STATUS_SUCCESS) {
goto ExitTransmitT0;
}
ulBytesRead = SmartcardExtension->SmartcardReply.BufferLength;
bProcedureByte = SmartcardExtension->SmartcardReply.Buffer[0];
if (SmartcardExtension->ReaderExtension->fInverseAtr) {
CMUSB_InverseBuffer(&bProcedureByte,1);
}
SmartcardDebug(DEBUG_PROTOCOL,
("%s!TransmitT0: procedure byte = %x\n",
DRIVER_NAME,
bProcedureByte));
if (bProcedureByte == 0x60) {
// wait work waitung time;
// we just try to read again
}
} while (bProcedureByte == 0x60);
// check for ACK
if ((bProcedureByte & 0xFE) == (bINS & 0xFE) ) {
ulBytesToWriteThisStep = ulBytesStillToWrite;
if (ulBytesToWriteThisStep > 0) { // at least one byte must be sent to the card
RtlCopyBytes((PVOID)(SmartcardExtension->SmartcardRequest.Buffer),
(PVOID)(bWriteBuffer+ulWriteBufferOffset),
ulBytesToWriteThisStep);
SmartcardExtension->SmartcardRequest.BufferLength = ulBytesToWriteThisStep;
if (SmartcardExtension->ReaderExtension->fInverseAtr == TRUE) {
CMUSB_InverseBuffer(SmartcardExtension->SmartcardRequest.Buffer,
SmartcardExtension->SmartcardRequest.BufferLength);
}
NTStatus = CMUSB_WriteP0(SmartcardExtension->OsData->DeviceObject,
0x02, //bRequest,
0x00, //bValueLo,
0x00, //bValueHi,
0x00, //bIndexLo,
0x00 //bIndexHi,
);
if (NTStatus != STATUS_SUCCESS) {
goto ExitTransmitT0;
}
ulWriteBufferOffset += ulBytesToWriteThisStep;
ulBytesStillToWrite -= ulBytesToWriteThisStep;
}
}
// check for NAK
else if ( (~bProcedureByte & 0xFE) == (bINS & 0xFE)) {
ulBytesToWriteThisStep = 1;
RtlCopyBytes((PVOID)SmartcardExtension->SmartcardRequest.Buffer,
(PVOID)(bWriteBuffer+ulWriteBufferOffset),
ulBytesToWriteThisStep);
SmartcardExtension->SmartcardRequest.BufferLength = ulBytesToWriteThisStep;
if (SmartcardExtension->ReaderExtension->fInverseAtr == TRUE) {
CMUSB_InverseBuffer(SmartcardExtension->SmartcardRequest.Buffer,
SmartcardExtension->SmartcardRequest.BufferLength);
}
NTStatus = CMUSB_WriteP0(SmartcardExtension->OsData->DeviceObject,
0x02, //bRequest,
0x00, //bValueLo,
0x00, //bValueHi,
0x00, //bIndexLo,
0x00 //bIndexHi,
);
if (NTStatus != STATUS_SUCCESS) {
goto ExitTransmitT0;
}
ulWriteBufferOffset += ulBytesToWriteThisStep;
ulBytesStillToWrite -= ulBytesToWriteThisStep;
}
// check for SW1
else if ( (bProcedureByte > 0x60 && bProcedureByte <= 0x6F) ||
(bProcedureByte >= 0x90 && bProcedureByte <= 0x9F) ) {
bReadBuffer[ulReadBufferOffset] = SmartcardExtension->SmartcardReply.Buffer[0];
ulReadBufferOffset++;
SmartcardExtension->SmartcardReply.BufferLength = 1;
NTStatus = CMUSB_ReadT0(SmartcardExtension);
if (NTStatus != STATUS_SUCCESS) {
goto ExitTransmitT0;
}
ulBytesRead = SmartcardExtension->SmartcardReply.BufferLength;
RtlCopyBytes((PVOID)(bReadBuffer + ulReadBufferOffset),
(PVOID)(SmartcardExtension->SmartcardReply.Buffer),
SmartcardExtension->SmartcardReply.BufferLength);
ulReadBufferOffset += ulBytesRead;
fSW1SW2Sent = TRUE;
} else {
NTStatus = STATUS_UNSUCCESSFUL;
goto ExitTransmitT0;
}
}while (!fSW1SW2Sent);
if (SmartcardExtension->ReaderExtension->fInverseAtr) {
CMUSB_InverseBuffer(bReadBuffer,
ulReadBufferOffset);
}
// copy received bytes
RtlCopyBytes((PVOID)SmartcardExtension->SmartcardReply.Buffer,
(PVOID)bReadBuffer,
ulReadBufferOffset);
SmartcardExtension->SmartcardReply.BufferLength = ulReadBufferOffset;
}
// let the lib copy the received bytes to the user buffer
NTStatus = SmartcardT0Reply(SmartcardExtension);
ExitTransmitT0:
// ------------------------------------------
// ITSEC E2 requirements: clear write buffers
// ------------------------------------------
RtlFillMemory((PVOID)bWriteBuffer,sizeof(bWriteBuffer),0x00);
RtlFillMemory((PVOID)SmartcardExtension->SmartcardRequest.Buffer,
SmartcardExtension->SmartcardRequest.BufferSize,0x00);
SmartcardDebug(DEBUG_TRACE,
("%s!TransmitT0 : Exit %lx\n",DRIVER_NAME,NTStatus));
return NTStatus;
}
#undef T0_HEADER_LEN
#undef T0_STATE_LEN
#undef TIMEOUT_CANCEL_READ_P1
/*****************************************************************************
Routine Description:
Arguments:
Return Value:
*****************************************************************************/
NTSTATUS CMUSB_TransmitT1(
PSMARTCARD_EXTENSION SmartcardExtension
)
{
NTSTATUS NTStatus;
NTSTATUS DebugStatus;
ULONG ulBytesToRead;
ULONG ulCurrentWaitTime;
ULONG ulWTXWaitTime;
LARGE_INTEGER waitTime;
BOOLEAN fStateTimer;
ULONG ulTemp;
PDEVICE_EXTENSION DeviceExtension;
PUSBD_INTERFACE_INFORMATION interface;
PUSBD_PIPE_INFORMATION pipeHandle = NULL;
BOOLEAN fCancelTimer = FALSE;
BYTE bTemp;
BYTE bMultiplier;
SmartcardDebug(DEBUG_PROTOCOL,
("%s!TransmitT1: CWT = %ld(ms)\n",DRIVER_NAME,
SmartcardExtension->CardCapabilities.T1.CWT/1000));
SmartcardDebug(DEBUG_PROTOCOL,
("%s!TransmitT1: BWT = %ld(ms)\n",DRIVER_NAME,
SmartcardExtension->CardCapabilities.T1.BWT/1000));
DeviceExtension = SmartcardExtension->OsData->DeviceObject->DeviceExtension;
interface = DeviceExtension->UsbInterface;
pipeHandle = &interface->Pipes[0];
ulCurrentWaitTime = (ULONG)(1000 + SmartcardExtension->CardCapabilities.T1.BWT/1000);
ulWTXWaitTime = 0;
do {
SmartcardExtension->SmartcardRequest.BufferLength = 0;
NTStatus = SmartcardT1Request(SmartcardExtension);
if (NTStatus != STATUS_SUCCESS) {
// this should never happen, so we return immediately
goto ExitTransmitT1;
}
NTStatus = CMUSB_WriteP0(SmartcardExtension->OsData->DeviceObject,
0x01, //T=1
0x00, //bValueLo,
0x00, //bValueHi,
0x00, //bIndexLo,
0x00 //bIndexHi,
);
if (NTStatus != STATUS_SUCCESS)
break; // there must be severe error
if (ulWTXWaitTime == 0 ) { // use BWT
waitTime = RtlConvertLongToLargeInteger(ulCurrentWaitTime * -10000);
} else { // use WTX time
waitTime = RtlConvertLongToLargeInteger(ulWTXWaitTime * -10000);
}
KeSetTimer(&SmartcardExtension->ReaderExtension->WaitTimer,
waitTime,
NULL);
// timer is now in the queue
fCancelTimer = TRUE;
ulTemp = 0;
do {
NTStatus = CMUSB_ReadP1(SmartcardExtension->OsData->DeviceObject);
if (NTStatus == STATUS_DEVICE_DATA_ERROR) {
DebugStatus = CMUSB_ReadStateAfterP1Stalled(SmartcardExtension->OsData->DeviceObject);
goto ExitTransmitT1;
}
fStateTimer = KeReadStateTimer(&SmartcardExtension->ReaderExtension->WaitTimer);
if (fStateTimer == TRUE) {
// timer has been removed from the queue
fCancelTimer = FALSE;
SmartcardDebug(DEBUG_PROTOCOL,
("%s!TransmitT1: T1 card does not respond in time\n",DRIVER_NAME));
NTStatus = STATUS_IO_TIMEOUT;
break;
}
if (SmartcardExtension->SmartcardReply.Buffer[0] >= 3) {
if (SmartcardExtension->SmartcardReply.Buffer[1] > ulTemp) {
// restart CWT for 32 bytes
ulCurrentWaitTime = (ULONG)(100 + 32*(SmartcardExtension->CardCapabilities.T1.CWT/1000));
waitTime = RtlConvertLongToLargeInteger(ulCurrentWaitTime * -10000);
KeSetTimer(&SmartcardExtension->ReaderExtension->WaitTimer,
waitTime,
NULL);
// timer is in the queue
fCancelTimer = TRUE;
ulTemp = SmartcardExtension->SmartcardReply.Buffer[1];
} else {
// CardMan USB has not received further bytes
// do nothing
}
}
} while (SmartcardExtension->SmartcardReply.Buffer[0] < 3 ||
(SmartcardExtension->SmartcardReply.Buffer[0] !=
SmartcardExtension->SmartcardReply.Buffer[1] + 4 ) );
// cancel timer now
if (fCancelTimer == TRUE) {
fCancelTimer = FALSE;
KeCancelTimer(&SmartcardExtension->ReaderExtension->WaitTimer);
// timer is removed from the queue
}
if (NTStatus != STATUS_SUCCESS) {
SmartcardExtension->SmartcardReply.BufferLength = 0L;
} else {
ulBytesToRead = SmartcardExtension->SmartcardReply.Buffer[0];
SmartcardExtension->SmartcardReply.BufferLength = SmartcardExtension->SmartcardReply.Buffer[0];
NTStatus = CMUSB_ReadP0(SmartcardExtension->OsData->DeviceObject);
}
bTemp = SmartcardExtension->SmartcardReply.Buffer[1];
bMultiplier = SmartcardExtension->SmartcardReply.Buffer[3];
if (SmartcardExtension->ReaderExtension->fInverseAtr == TRUE) {
CMUSB_InverseBuffer(&bTemp,1);
CMUSB_InverseBuffer(&bMultiplier,1);
}
if (bTemp == T1_WTX_REQUEST) {
SmartcardDebug(DEBUG_PROTOCOL,
("%s!TransmitT1: T1_WTX_REQUEST received\n",DRIVER_NAME));
ulWTXWaitTime = (ULONG)(1000 +
bMultiplier * (SmartcardExtension->CardCapabilities.T1.BWT/1000));
} else {
ulWTXWaitTime = 0;
}
// bug fix for smclib
if (SmartcardExtension->T1.State == T1_IFS_RESPONSE &&
SmartcardExtension->T1.OriginalState == T1_I_BLOCK) {
SmartcardExtension->T1.State = T1_I_BLOCK;
}
NTStatus = SmartcardT1Reply(SmartcardExtension);
}
while (NTStatus == STATUS_MORE_PROCESSING_REQUIRED);
ExitTransmitT1:
// ------------------------------------------
// ITSEC E2 requirements: clear write buffers
// ------------------------------------------
RtlFillMemory((PVOID)SmartcardExtension->SmartcardRequest.Buffer,
SmartcardExtension->SmartcardRequest.BufferSize,0x00);
// timer will be cancelled here if there was an error
if (fCancelTimer == TRUE) {
KeCancelTimer(&SmartcardExtension->ReaderExtension->WaitTimer);
// timer is removed from the queue
}
return NTStatus;
}
/*****************************************************************************
Routine Description:
This function sets the desired protocol . If necessary a PTS is performed
Arguments: pointer to SMARTCARD_EXTENSION
Return Value: NT NTStatus
*****************************************************************************/
NTSTATUS CMUSB_SetProtocol(
PSMARTCARD_EXTENSION SmartcardExtension
)
{
NTSTATUS NTStatus = STATUS_SUCCESS;
NTSTATUS DebugStatus;
ULONG ulNewProtocol;
UCHAR abPTSRequest[4];
UCHAR abReadBuffer[6];
UCHAR abPTSReply [4];
ULONG ulBytesRead;
LARGE_INTEGER liWaitTime;
BOOLEAN fStateTimer;
ULONG ulWaitTime;
PDEVICE_EXTENSION DeviceExtension;
PUSBD_PIPE_INFORMATION pipeHandle = NULL;
PUSBD_INTERFACE_INFORMATION interface;
UCHAR bTemp;
BOOLEAN fCancelTimer = FALSE;
KIRQL irql;
SmartcardDebug(DEBUG_TRACE,
("%s!SetProtocol : Enter\n",DRIVER_NAME));
DeviceExtension = SmartcardExtension->OsData->DeviceObject->DeviceExtension;
interface = DeviceExtension->UsbInterface;
pipeHandle = &interface->Pipes[0];
//
// Check if the card is already in specific state
// and if the caller wants to have the already selected protocol.
// We return success if this is the case.
//
if ((SmartcardExtension->CardCapabilities.Protocol.Selected & SmartcardExtension->MinorIoControlCode)) {
NTStatus = STATUS_SUCCESS;
goto ExitSetProtocol;
}
ulNewProtocol = SmartcardExtension->MinorIoControlCode;
while (TRUE) {
// set initial character of PTS
abPTSRequest[0] = 0xFF;
// set the format character
if (SmartcardExtension->CardCapabilities.Protocol.Supported &
ulNewProtocol &
SCARD_PROTOCOL_T1) {
// select T=1 and indicate that PTS1 follows
abPTSRequest[1] = 0x11;
SmartcardExtension->CardCapabilities.Protocol.Selected =
SCARD_PROTOCOL_T1;
} else if (SmartcardExtension->CardCapabilities.Protocol.Supported &
ulNewProtocol &
SCARD_PROTOCOL_T0) {
// select T=1 and indicate that PTS1 follows
abPTSRequest[1] = 0x10;
SmartcardExtension->CardCapabilities.Protocol.Selected =
SCARD_PROTOCOL_T0;
} else {
NTStatus = STATUS_INVALID_DEVICE_REQUEST;
goto ExitSetProtocol;
}
// CardMan USB support higher baudrates only for T=1
// ==> Dl=1
if (abPTSRequest[1] == 0x10) {
SmartcardDebug(DEBUG_PROTOCOL,
("%s! overwriting PTS1 for T=0\n",DRIVER_NAME));
SmartcardExtension->CardCapabilities.PtsData.Dl = 0x01;
}
// set pts1 which codes Fl and Dl
bTemp = (BYTE) (SmartcardExtension->CardCapabilities.PtsData.Fl << 4 |
SmartcardExtension->CardCapabilities.PtsData.Dl);
switch (bTemp) {
case 0x11:
case 0x12:
case 0x13:
case 0x14:
case 0x18:
case 0x91:
case 0x92:
case 0x93:
case 0x94:
case 0x98:
// do nothing
// we support these Fl/Dl parameters
break ;
default:
SmartcardDebug(DEBUG_PROTOCOL,
("%s! overwriting PTS1(0x%x)\n",DRIVER_NAME,bTemp));
// we must correct Fl/Dl
SmartcardExtension->CardCapabilities.PtsData.Dl = 0x01;
SmartcardExtension->CardCapabilities.PtsData.Fl = 0x01;
bTemp = (BYTE) (SmartcardExtension->CardCapabilities.PtsData.Fl << 4 |
SmartcardExtension->CardCapabilities.PtsData.Dl);
break;
}
abPTSRequest[2] = bTemp;
// set pck (check character)
abPTSRequest[3] = (BYTE)(abPTSRequest[0] ^ abPTSRequest[1] ^ abPTSRequest[2]);
SmartcardDebug(DEBUG_PROTOCOL,
("%s! writing PTS request\n",DRIVER_NAME));
RtlCopyBytes((PVOID)SmartcardExtension->SmartcardRequest.Buffer,
(PVOID)abPTSRequest,
4);
SmartcardExtension->SmartcardRequest.BufferLength = 4;
NTStatus = CMUSB_WriteP0(SmartcardExtension->OsData->DeviceObject,
0x01, //we can use T=1 setting for direct communication
0x00, //bValueLo,
0x00, //bValueHi,
0x00, //bIndexLo,
0x00); //bIndexHi,
if (NTStatus != STATUS_SUCCESS) {
SmartcardDebug(DEBUG_ERROR,
("%s! writing PTS request failed\n",DRIVER_NAME));
goto ExitSetProtocol;
}
// read back pts data
SmartcardDebug(DEBUG_PROTOCOL,
("%s! reading PTS reply\n",DRIVER_NAME));
// maximim initial waiting time is 9600 * etu
// => 1 sec is sufficient
ulWaitTime = 1000;
liWaitTime = RtlConvertLongToLargeInteger(ulWaitTime * -10000);
KeSetTimer(&SmartcardExtension->ReaderExtension->WaitTimer,
liWaitTime,
NULL);
// timer is now in the queue
fCancelTimer = TRUE;
do {
SmartcardExtension->ReaderExtension->ulTimeoutP1 = ulWaitTime;
DebugStatus = CMUSB_ReadP1(SmartcardExtension->OsData->DeviceObject);
// -----------------------------
// check if P1 has been stalled
// -----------------------------
if (SmartcardExtension->ReaderExtension->fP1Stalled == TRUE) {
DebugStatus = CMUSB_ReadStateAfterP1Stalled(SmartcardExtension->OsData->DeviceObject);
SmartcardExtension->SmartcardReply.BufferLength = 0;
goto ExitSetProtocol;
}
fStateTimer = KeReadStateTimer(&SmartcardExtension->ReaderExtension->WaitTimer);
if (fStateTimer == TRUE) {
// timer has timed out and has been removed from the queue
fCancelTimer = FALSE;
SmartcardDebug(DEBUG_PROTOCOL,
("%s! Timeout while PTS reply\n",DRIVER_NAME));
NTStatus = STATUS_IO_TIMEOUT;
break;
}
} while (SmartcardExtension->SmartcardReply.Buffer[0] < 4 );
if (fCancelTimer == TRUE) {
fCancelTimer = FALSE;
// timer is still in the queue, remove it
KeCancelTimer(&SmartcardExtension->ReaderExtension->WaitTimer);
}
if (NTStatus == STATUS_IO_TIMEOUT) {
if (SmartcardExtension->SmartcardReply.Buffer[0] == 3) {
SmartcardExtension->SmartcardReply.BufferLength = 3;
} else {
if (SmartcardExtension->CardCapabilities.PtsData.Type !=
PTS_TYPE_DEFAULT) {
SmartcardDebug(DEBUG_PROTOCOL,
("%s! PTS failed : Trying default parameters\n",DRIVER_NAME));
// the card did either not reply or it replied incorrectly
// so try default values
SmartcardExtension->CardCapabilities.PtsData.Type = PTS_TYPE_DEFAULT;
SmartcardExtension->MinorIoControlCode = SCARD_COLD_RESET;
NTStatus = CMUSB_CardPower(SmartcardExtension);
continue;
}
goto ExitSetProtocol;
}
} else {
SmartcardExtension->SmartcardReply.BufferLength = 4;
}
NTStatus = CMUSB_ReadP0(SmartcardExtension->OsData->DeviceObject);
ulBytesRead = SmartcardExtension->SmartcardReply.BufferLength;
if (NTStatus != STATUS_SUCCESS ||
!(ulBytesRead == 4 || ulBytesRead == 3)) {
SmartcardDebug(DEBUG_ERROR,
("%s! reading PTS reply failed\n",DRIVER_NAME));
goto ExitSetProtocol;
}
RtlCopyBytes((PVOID)abPTSReply,
(PVOID)SmartcardExtension->SmartcardReply.Buffer,
ulBytesRead);
if (ulBytesRead == 4 &&
abPTSReply[0] == abPTSRequest[0] &&
abPTSReply[1] == abPTSRequest[1] &&
abPTSReply[2] == abPTSRequest[2] &&
abPTSReply[3] == abPTSRequest[3] ) {
SmartcardDebug(DEBUG_PROTOCOL,
("%s! PTS request and reply match\n",DRIVER_NAME));
NTStatus = STATUS_SUCCESS;
switch (abPTSRequest[2]) {
// Fl/Dl
case 0x11:
SmartcardExtension->ReaderExtension->CardParameters.bBaudRate =
CMUSB_FREQUENCY_3_72MHZ + CMUSB_BAUDRATE_9600;
break ;
case 0x12:
SmartcardExtension->ReaderExtension->CardParameters.bBaudRate =
CMUSB_FREQUENCY_3_72MHZ + CMUSB_BAUDRATE_19200;
break ;
case 0x13:
SmartcardExtension->ReaderExtension->CardParameters.bBaudRate =
CMUSB_FREQUENCY_3_72MHZ + CMUSB_BAUDRATE_38400;
break ;
case 0x14:
SmartcardExtension->ReaderExtension->CardParameters.bBaudRate =
CMUSB_FREQUENCY_3_72MHZ + CMUSB_BAUDRATE_76800;
break ;
case 0x18:
SmartcardExtension->ReaderExtension->CardParameters.bBaudRate =
CMUSB_FREQUENCY_3_72MHZ + CMUSB_BAUDRATE_115200;
break ;
case 0x91:
SmartcardExtension->ReaderExtension->CardParameters.bBaudRate =
CMUSB_FREQUENCY_5_12MHZ + CMUSB_BAUDRATE_9600;
break ;
case 0x92:
SmartcardExtension->ReaderExtension->CardParameters.bBaudRate =
CMUSB_FREQUENCY_5_12MHZ + CMUSB_BAUDRATE_19200;
break ;
case 0x93:
SmartcardExtension->ReaderExtension->CardParameters.bBaudRate =
CMUSB_FREQUENCY_5_12MHZ + CMUSB_BAUDRATE_38400;
break ;
case 0x94:
SmartcardExtension->ReaderExtension->CardParameters.bBaudRate =
CMUSB_FREQUENCY_5_12MHZ + CMUSB_BAUDRATE_76800;
break ;
case 0x98:
SmartcardExtension->ReaderExtension->CardParameters.bBaudRate =
CMUSB_FREQUENCY_5_12MHZ + CMUSB_BAUDRATE_115200;
break ;
}
break;
}
if (ulBytesRead == 3 &&
abPTSReply[0] == abPTSRequest[0] &&
(abPTSReply[1] & 0x7F) == (abPTSRequest[1] & 0x0F) &&
abPTSReply[2] == (BYTE)(abPTSReply[0] ^ abPTSReply[1] )) {
SmartcardDebug(DEBUG_PROTOCOL,
("%s! short PTS reply received\n",DRIVER_NAME));
NTStatus = STATUS_SUCCESS;
if ((abPTSRequest[2] & 0x90) == 0x90) {
SmartcardExtension->ReaderExtension->CardParameters.bBaudRate =
CMUSB_FREQUENCY_5_12MHZ + CMUSB_BAUDRATE_9600;
} else {
SmartcardExtension->ReaderExtension->CardParameters.bBaudRate =
CMUSB_FREQUENCY_3_72MHZ + CMUSB_BAUDRATE_9600;
}
break ;
}
if (SmartcardExtension->CardCapabilities.PtsData.Type !=
PTS_TYPE_DEFAULT) {
SmartcardDebug(DEBUG_PROTOCOL,
("%s! PTS failed : Trying default parameters\n",DRIVER_NAME));
// the card did either not reply or it replied incorrectly
// so try default values
SmartcardExtension->CardCapabilities.PtsData.Type = PTS_TYPE_DEFAULT;
SmartcardExtension->MinorIoControlCode = SCARD_COLD_RESET;
NTStatus = CMUSB_CardPower(SmartcardExtension);
continue;
}
// the card failed the pts request
NTStatus = STATUS_DEVICE_PROTOCOL_ERROR;
goto ExitSetProtocol;
}
ExitSetProtocol:
switch (NTStatus) {
case STATUS_IO_TIMEOUT:
SmartcardExtension->CardCapabilities.Protocol.Selected = SCARD_PROTOCOL_UNDEFINED;
*SmartcardExtension->IoRequest.Information = 0;
break;
case STATUS_SUCCESS:
// now indicate that we're in specific mode
KeAcquireSpinLock(&SmartcardExtension->OsData->SpinLock,
&irql);
SmartcardExtension->ReaderCapabilities.CurrentState = SCARD_SPECIFIC;
KeReleaseSpinLock(&SmartcardExtension->OsData->SpinLock,
irql);
// return the selected protocol to the caller
*(PULONG) SmartcardExtension->IoRequest.ReplyBuffer =
SmartcardExtension->CardCapabilities.Protocol.Selected;
*SmartcardExtension->IoRequest.Information =
sizeof(SmartcardExtension->CardCapabilities.Protocol.Selected);
SmartcardDebug(DEBUG_PROTOCOL,
("%s! Selected protocol: T=%ld\n",DRIVER_NAME,
SmartcardExtension->CardCapabilities.Protocol.Selected-1));
// -----------------------
// set parameters
// -----------------------
if (SmartcardExtension->CardCapabilities.N != 0xff) {
SmartcardExtension->ReaderExtension->CardParameters.bStopBits = 2 + SmartcardExtension->CardCapabilities.N;
} else {
// N = 255
if (SmartcardExtension->CardCapabilities.Protocol.Selected & SCARD_PROTOCOL_T0) {
// 12 etu for T=0;
SmartcardExtension->ReaderExtension->CardParameters.bStopBits = 2;
} else {
// 11 etu for T=1
SmartcardExtension->ReaderExtension->CardParameters.bStopBits = 1;
}
}
NTStatus = CMUSB_SetCardParameters (SmartcardExtension->OsData->DeviceObject,
SmartcardExtension->ReaderExtension->CardParameters.bCardType,
SmartcardExtension->ReaderExtension->CardParameters.bBaudRate,
SmartcardExtension->ReaderExtension->CardParameters.bStopBits);
break;
default :
SmartcardExtension->CardCapabilities.Protocol.Selected = SCARD_PROTOCOL_UNDEFINED;
*SmartcardExtension->IoRequest.Information = 0;
break;
}
SmartcardDebug(DEBUG_TRACE,
("%s!SetProtocol : Exit %lx\n",DRIVER_NAME,NTStatus));
return NTStatus;
}
/*****************************************************************************
Routine Description:
Arguments:
Return Value:
*****************************************************************************/
NTSTATUS
CMUSB_CardPower(IN PSMARTCARD_EXTENSION SmartcardExtension)
{
NTSTATUS NTStatus = STATUS_SUCCESS;
NTSTATUS DebugStatus = STATUS_SUCCESS;
UCHAR pbAtrBuffer[MAXIMUM_ATR_LENGTH];
ULONG ulAtrLength;
KIRQL irql;
#if DBG
ULONG i;
#endif;
SmartcardDebug(DEBUG_TRACE,
("%s!CardPower: Enter\n",DRIVER_NAME));
#if DBG
switch (SmartcardExtension->MinorIoControlCode) {
case SCARD_WARM_RESET:
SmartcardDebug(DEBUG_ATR,
("%s!CardPower: SCARD_WARM_RESTART\n",DRIVER_NAME));
break;
case SCARD_COLD_RESET:
SmartcardDebug(DEBUG_ATR,
("%s!CardPower: SCARD_COLD_RESTART\n",DRIVER_NAME));
break;
case SCARD_POWER_DOWN:
SmartcardDebug(DEBUG_ATR,
("%s!CardPower: SCARD_POWER_DOWN\n",DRIVER_NAME));
break;
}
#endif
//DbgBreakPoint();
switch (SmartcardExtension->MinorIoControlCode) {
case SCARD_WARM_RESET:
case SCARD_COLD_RESET:
// try asynchronous cards first
// because some asynchronous cards
// do not return 0xFF in the first byte
NTStatus = CMUSB_PowerOnCard(SmartcardExtension,
pbAtrBuffer,
&ulAtrLength);
if (NTStatus != STATUS_SUCCESS && NTStatus!= STATUS_NO_MEDIA) {
NTStatus = CMUSB_PowerOnSynchronousCard(SmartcardExtension,
pbAtrBuffer,
&ulAtrLength);
}
if (NTStatus != STATUS_SUCCESS) {
goto ExitCardPower;
}
if (SmartcardExtension->ReaderExtension->fRawModeNecessary == FALSE) {
// copy ATR to smart card structure
// the lib needs the ATR for evaluation of the card parameters
RtlCopyBytes((PVOID)SmartcardExtension->CardCapabilities.ATR.Buffer,
(PVOID)pbAtrBuffer,
ulAtrLength);
SmartcardExtension->CardCapabilities.ATR.Length = (UCHAR)ulAtrLength;
KeAcquireSpinLock(&SmartcardExtension->OsData->SpinLock,
&irql);
SmartcardExtension->ReaderCapabilities.CurrentState = SCARD_NEGOTIABLE;
KeReleaseSpinLock(&SmartcardExtension->OsData->SpinLock,
irql);
SmartcardExtension->CardCapabilities.Protocol.Selected = SCARD_PROTOCOL_UNDEFINED;
NTStatus = SmartcardUpdateCardCapabilities(SmartcardExtension);
if (NTStatus != STATUS_SUCCESS) {
goto ExitCardPower;
}
// -----------------------
// set parameters
// -----------------------
if (SmartcardExtension->CardCapabilities.N != 0xff) {
// 0 <= N <= 254
SmartcardExtension->ReaderExtension->CardParameters.bStopBits = 2 + SmartcardExtension->CardCapabilities.N;
} else {
// N = 255
if (SmartcardExtension->CardCapabilities.Protocol.Selected & SCARD_PROTOCOL_T0) {
// 12 etu for T=0;
SmartcardExtension->ReaderExtension->CardParameters.bStopBits = 2;
} else {
// 11 etu for T=1
SmartcardExtension->ReaderExtension->CardParameters.bStopBits = 1;
}
}
NTStatus = CMUSB_SetCardParameters (SmartcardExtension->OsData->DeviceObject,
SmartcardExtension->ReaderExtension->CardParameters.bCardType,
SmartcardExtension->ReaderExtension->CardParameters.bBaudRate,
SmartcardExtension->ReaderExtension->CardParameters.bStopBits);
#if DBG
SmartcardDebug(DEBUG_ATR,("%s!CardPower: ATR : ",DRIVER_NAME));
for (i = 0;i < ulAtrLength;i++)
SmartcardDebug(DEBUG_ATR,("%2.2x ",SmartcardExtension->CardCapabilities.ATR.Buffer[i]));
SmartcardDebug(DEBUG_ATR,("\n"));
#endif
} else {
SmartcardExtension->CardCapabilities.ATR.Buffer[0] = 0x3B;
SmartcardExtension->CardCapabilities.ATR.Buffer[1] = 0x04;
if (ulAtrLength > 62) {
NTStatus = STATUS_DEVICE_PROTOCOL_ERROR;
goto ExitCardPower;
}
RtlCopyBytes((PVOID)&SmartcardExtension->CardCapabilities.ATR.Buffer[2],
(PVOID)pbAtrBuffer,
ulAtrLength);
ulAtrLength += 2;
SmartcardExtension->CardCapabilities.ATR.Length = (UCHAR)ulAtrLength;
KeAcquireSpinLock(&SmartcardExtension->OsData->SpinLock,
&irql);
SmartcardExtension->ReaderCapabilities.CurrentState = SCARD_SPECIFIC;
KeReleaseSpinLock(&SmartcardExtension->OsData->SpinLock,
irql);
SmartcardExtension->CardCapabilities.Protocol.Selected = SCARD_PROTOCOL_T0;
NTStatus = SmartcardUpdateCardCapabilities(SmartcardExtension);
if (NTStatus != STATUS_SUCCESS) {
goto ExitCardPower;
}
SmartcardDebug(DEBUG_ATR,("CardPower: ATR of synchronous smart card : %2.2x %2.2x %2.2x %2.2x\n",
pbAtrBuffer[0],pbAtrBuffer[1],pbAtrBuffer[2],pbAtrBuffer[3]));
// copied from serial CardMan
//SmartcardExtension->ReaderExtension->SyncParameters.fCardResetRequested = TRUE;
}
// copy ATR to user space
if (SmartcardExtension->IoRequest.ReplyBufferLength >= SmartcardExtension->CardCapabilities.ATR.Length) {
RtlCopyBytes((PVOID)SmartcardExtension->IoRequest.ReplyBuffer,
(PVOID)SmartcardExtension->CardCapabilities.ATR.Buffer,
SmartcardExtension->CardCapabilities.ATR.Length);
*SmartcardExtension->IoRequest.Information = ulAtrLength;
} else {
// Called from SET_PROTOCOL, so we don't want to copy the ATR.
}
break;
case SCARD_POWER_DOWN:
NTStatus = CMUSB_PowerOffCard(SmartcardExtension);
if (NTStatus != STATUS_SUCCESS) {
goto ExitCardPower;
}
KeAcquireSpinLock(&SmartcardExtension->OsData->SpinLock,
&irql);
SmartcardExtension->ReaderCapabilities.CurrentState = SCARD_SWALLOWED;
SmartcardExtension->CardCapabilities.Protocol.Selected = SCARD_PROTOCOL_UNDEFINED;
KeReleaseSpinLock(&SmartcardExtension->OsData->SpinLock,
irql);
break;
}
ExitCardPower:
SmartcardDebug(DEBUG_TRACE,
("%s!CardPower: Exit %lx\n",DRIVER_NAME,NTStatus));
return NTStatus;
}
/*****************************************************************************
Routine Description:
Arguments:
Return Value:
*****************************************************************************/
NTSTATUS CMUSB_PowerOffCard (
IN PSMARTCARD_EXTENSION SmartcardExtension
)
{
NTSTATUS NTStatus;
NTSTATUS DebugStatus;
PDEVICE_OBJECT DeviceObject;
ULONG ulBytesRead;
SmartcardDebug(DEBUG_TRACE,
("%s!PowerOffCard: Enter\n",DRIVER_NAME));
DeviceObject = SmartcardExtension->OsData->DeviceObject;
SmartcardExtension->SmartcardRequest.BufferLength = 0;
NTStatus = CMUSB_WriteP0(DeviceObject,
0x11, //bRequest,
0x00, //bValueLo,
0x00, //bValueHi,
0x00, //bIndexLo,
0x00 //bIndexHi,
);
// now read the NTStatus
SmartcardExtension->ReaderExtension->ulTimeoutP1 = DEFAULT_TIMEOUT_P1;
NTStatus = CMUSB_ReadP1(DeviceObject);
if (NTStatus == STATUS_DEVICE_DATA_ERROR) {
DebugStatus = CMUSB_ReadStateAfterP1Stalled(SmartcardExtension->OsData->DeviceObject);
goto ExitPowerOff;
}
ExitPowerOff:
// set card state for update thread
// otherwise a card removal/insertion would be recognized
if (SmartcardExtension->ReaderExtension->ulOldCardState == POWERED)
SmartcardExtension->ReaderExtension->ulOldCardState = INSERTED;
SmartcardDebug(DEBUG_TRACE,
("%s!PowerOffCard: Exit %lx\n",DRIVER_NAME,NTStatus));
return NTStatus;
}
/*****************************************************************************
Routine Description:
Arguments:
Return Value:
*****************************************************************************/
NTSTATUS CMUSB_ReadStateAfterP1Stalled(
IN PDEVICE_OBJECT DeviceObject
)
{
NTSTATUS NTStatus;
PSMARTCARD_EXTENSION SmartcardExtension;
PDEVICE_EXTENSION DeviceExtension;
SmartcardDebug(DEBUG_TRACE,
("%s!ReadStateAfterP1Stalled: Enter\n",DRIVER_NAME));
DeviceExtension = DeviceObject->DeviceExtension;
SmartcardExtension = &DeviceExtension->SmartcardExtension;
SmartcardExtension->SmartcardRequest.BufferLength = 0;
NTStatus = CMUSB_WriteP0(DeviceObject,
0x20, //bRequest,
0x00, //bValueLo,
0x00, //bValueHi,
0x00, //bIndexLo,
0x00 //bIndexHi,
);
if (NTStatus != STATUS_SUCCESS) {
// if we can't read the NTStatus there must be a serious error
goto ExitReadState;
}
SmartcardExtension->ReaderExtension->ulTimeoutP1 = DEFAULT_TIMEOUT_P1;
SmartcardExtension->SmartcardReply.BufferLength = 1;
NTStatus = CMUSB_ReadP1(DeviceObject);
if (NTStatus != STATUS_SUCCESS) {
// if we can't read the NTStatus there must be a serious error
goto ExitReadState;
}
SmartcardDebug(DEBUG_TRACE,
("%s!ReadStateAfterP1Stalled: Exit %lx\n",DRIVER_NAME,NTStatus));
ExitReadState:
return NTStatus;
}
/*****************************************************************************
Routine Description:
Arguments:
Return Value:
*****************************************************************************/
NTSTATUS CMUSB_PowerOnCard (
IN PSMARTCARD_EXTENSION SmartcardExtension,
IN PUCHAR pbATR,
OUT PULONG pulATRLength
)
{
UCHAR abMaxAtrBuffer[SCARD_ATR_LENGTH];
ULONG ulCurrentLengthOfAtr;
ULONG ulPtrToCurrentAtrByte;
ULONG ulExpectedLengthOfAtr;
BOOLEAN fTryNextCard;
BOOLEAN fValidAtrReceived = FALSE;
ULONG ulBytesRead;
NTSTATUS NTStatus;
PDEVICE_OBJECT DeviceObject;
NTSTATUS DebugStatus;
BOOLEAN fInverseAtr = FALSE;
ULONG ulHistoricalBytes;
ULONG i;
BOOLEAN fTDxSent;
BOOLEAN fOnlyT0;
UCHAR bResetMode;
UCHAR abFrequency[2] = {CMUSB_FREQUENCY_3_72MHZ,
CMUSB_FREQUENCY_5_12MHZ};
ULONG ulCardType;
UCHAR bCardType;
UCHAR bStopBits;
UCHAR bBaudRate;
SmartcardDebug(DEBUG_TRACE,
("%s!PowerOnCard: Enter\n",DRIVER_NAME));
DeviceObject = SmartcardExtension->OsData->DeviceObject;
if (SmartcardExtension->MinorIoControlCode == SCARD_COLD_RESET)
bResetMode = SMARTCARD_COLD_RESET;
else
bResetMode = SMARTCARD_WARM_RESET;
// clear card parameters
SmartcardExtension->ReaderExtension->CardParameters.bBaudRate = 0;
SmartcardExtension->ReaderExtension->CardParameters.bCardType = 0;
SmartcardExtension->ReaderExtension->CardParameters.bStopBits = 0;
// set default card parameters
// asnyc, 9600 baud, even parity
bStopBits = 2;
bBaudRate = CMUSB_BAUDRATE_9600;
bCardType = CMUSB_SMARTCARD_ASYNCHRONOUS;
for (ulCardType = 0;ulCardType < 2;ulCardType++) {
#if DBG
switch (ulCardType) {
case 0:
SmartcardDebug(DEBUG_ATR,
("%s!PowerOnCard: trying 3.72 Mhz smart card\n",DRIVER_NAME));
break;
case 1:
SmartcardDebug(DEBUG_ATR,
("%s!PowerOnCard: trying 5.12 Mhz smart card\n",DRIVER_NAME));
break;
}
#endif
bBaudRate |= abFrequency[ulCardType];
NTStatus = CMUSB_SetCardParameters (SmartcardExtension->OsData->DeviceObject,
bCardType,
bBaudRate,
bStopBits);
if (NTStatus != STATUS_SUCCESS) {
// if we can't set the card parameters there must be a serious error
goto ExitPowerOnCard;
}
ulCurrentLengthOfAtr = 0L;
ulPtrToCurrentAtrByte = 0L;
fOnlyT0 = TRUE;
fTryNextCard = FALSE;
fValidAtrReceived = FALSE;
RtlFillMemory((PVOID)abMaxAtrBuffer,
sizeof(abMaxAtrBuffer),
0x00);
// resync CardManUSB by reading the NTStatus byte
SmartcardExtension->SmartcardRequest.BufferLength = 0;
NTStatus = CMUSB_WriteP0(DeviceObject,
0x20, //bRequest,
0x00, //bValueLo,
0x00, //bValueHi,
0x00, //bIndexLo,
0x00 //bIndexHi,
);
if (NTStatus != STATUS_SUCCESS) {
// if we can't read the NTStatus there must be a serious error
goto ExitPowerOnCard;
}
SmartcardExtension->ReaderExtension->ulTimeoutP1 = DEFAULT_TIMEOUT_P1;
SmartcardExtension->SmartcardReply.BufferLength = 1;
NTStatus = CMUSB_ReadP1(DeviceObject);
if (NTStatus == STATUS_DEVICE_DATA_ERROR) {
DebugStatus = CMUSB_ReadStateAfterP1Stalled(SmartcardExtension->OsData->DeviceObject);
goto ExitPowerOnCard;
} else if (NTStatus != STATUS_SUCCESS) {
// if we can't read the NTStatus there must be a serious error
goto ExitPowerOnCard;
}
// check if card is really inserted
if (SmartcardExtension->SmartcardReply.Buffer[0] == 0x00) {
NTStatus = STATUS_NO_MEDIA;
goto ExitPowerOnCard;
}
// issue power on command
NTStatus = CMUSB_WriteP0(DeviceObject,
0x10, //bRequest,
bResetMode, //bValueLo,
0x00, //bValueHi,
0x00, //bIndexLo,
0x00 //bIndexHi,
);
if (NTStatus != STATUS_SUCCESS) {
// if we can't issue the power on command there must be a serious error
goto ExitPowerOnCard;
}
SmartcardExtension->ReaderExtension->ulTimeoutP1 = DEFAULT_TIMEOUT_P1;
NTStatus = CMUSB_ReadP1(DeviceObject);
if (NTStatus == STATUS_DEVICE_DATA_ERROR) {
DebugStatus = CMUSB_ReadStateAfterP1Stalled(SmartcardExtension->OsData->DeviceObject);
goto ExitPowerOnCard;
} else if (NTStatus != STATUS_SUCCESS) {
continue;
}
ulBytesRead = SmartcardExtension->SmartcardReply.BufferLength;
RtlCopyBytes((PVOID)(abMaxAtrBuffer+ulCurrentLengthOfAtr),
(PVOID)SmartcardExtension->SmartcardReply.Buffer,
ulBytesRead);
// check if inverse convention used
if (abMaxAtrBuffer[0] == 0x03) {
fInverseAtr = TRUE;
}
if (fInverseAtr) {
CMUSB_InverseBuffer(abMaxAtrBuffer+ulCurrentLengthOfAtr,
ulBytesRead);
}
if (abMaxAtrBuffer[0] != 0x3B &&
abMaxAtrBuffer[0] != 0x3F ) {
continue; // try next card
}
ulCurrentLengthOfAtr += ulBytesRead;
// ---------------------
// TS character
// ---------------------
SmartcardDebug(DEBUG_ATR,("PowerOnCard: TS = %2.2x\n",abMaxAtrBuffer[0]));
if (abMaxAtrBuffer[ulPtrToCurrentAtrByte] != 0x3B &&
abMaxAtrBuffer[ulPtrToCurrentAtrByte] != 0x3F ) {
continue;
}
// ---------------------
// T0 character
// ---------------------
ulExpectedLengthOfAtr = 2;
if (ulCurrentLengthOfAtr < ulExpectedLengthOfAtr) {
NTStatus = CMUSB_ReadP1(DeviceObject);
if (NTStatus == STATUS_DEVICE_DATA_ERROR) {
DebugStatus = CMUSB_ReadStateAfterP1Stalled(SmartcardExtension->OsData->DeviceObject);
goto ExitPowerOnCard;
} else if (NTStatus != STATUS_SUCCESS) {
continue;
}
ulBytesRead = SmartcardExtension->SmartcardReply.BufferLength;
RtlCopyBytes((PVOID)(abMaxAtrBuffer+ulCurrentLengthOfAtr),
(PVOID)SmartcardExtension->SmartcardReply.Buffer,
ulBytesRead);
if (fInverseAtr) {
CMUSB_InverseBuffer(abMaxAtrBuffer+ulCurrentLengthOfAtr,
ulBytesRead);
}
ulCurrentLengthOfAtr += ulBytesRead;
}
SmartcardDebug(DEBUG_ATR,("PowerOnCard: T0 = %2.2x\n",abMaxAtrBuffer[1]));
ulHistoricalBytes = abMaxAtrBuffer[1] & 0x0F;
do {
ulPtrToCurrentAtrByte = ulExpectedLengthOfAtr - 1;
fTDxSent = FALSE;
if (abMaxAtrBuffer[ulPtrToCurrentAtrByte] & 0x10)
ulExpectedLengthOfAtr++;
if (abMaxAtrBuffer[ulPtrToCurrentAtrByte] & 0x20)
ulExpectedLengthOfAtr++;
if (abMaxAtrBuffer[ulPtrToCurrentAtrByte] & 0x40)
ulExpectedLengthOfAtr++;
if (abMaxAtrBuffer[ulPtrToCurrentAtrByte] & 0x80) {
ulExpectedLengthOfAtr++;
fTDxSent = TRUE;
}
if (fOnlyT0 == TRUE &&
ulPtrToCurrentAtrByte != 1 && // check if not T0
(abMaxAtrBuffer[ulPtrToCurrentAtrByte ] & 0x0f) ) {
fOnlyT0 = FALSE;
}
// TA1, TB1, TC1 , TD1
while (ulCurrentLengthOfAtr < ulExpectedLengthOfAtr) {
NTStatus = CMUSB_ReadP1(DeviceObject);
if (NTStatus == STATUS_DEVICE_DATA_ERROR) {
DebugStatus = CMUSB_ReadStateAfterP1Stalled(SmartcardExtension->OsData->DeviceObject);
goto ExitPowerOnCard;
} else if (NTStatus != STATUS_SUCCESS) {
fTryNextCard = TRUE;
break;
}
ulBytesRead = SmartcardExtension->SmartcardReply.BufferLength;
RtlCopyBytes((PVOID)(abMaxAtrBuffer+ulCurrentLengthOfAtr),
(PVOID)SmartcardExtension->SmartcardReply.Buffer,
ulBytesRead);
if (fInverseAtr) {
CMUSB_InverseBuffer(abMaxAtrBuffer+ulCurrentLengthOfAtr,
ulBytesRead);
}
ulCurrentLengthOfAtr += ulBytesRead;
} // end of while
if (fTryNextCard == TRUE) {
break;
}
#ifdef DBG
SmartcardDebug(DEBUG_ATR,("PowerOnCard: ATR read bytes: "));
for (i = 0;i < ulExpectedLengthOfAtr;i++)
SmartcardDebug(DEBUG_ATR,("%2.2x ",abMaxAtrBuffer[i]));
SmartcardDebug(DEBUG_ATR,("\n"));
#endif
} while (fTDxSent == TRUE);
if (fTryNextCard == TRUE) {
continue;
}
// read historical bytes
// bug fix : old SAMOS cards have a damaged ATR
if (abMaxAtrBuffer[0] == 0x3b &&
abMaxAtrBuffer[1] == 0xbf &&
abMaxAtrBuffer[2] == 0x11 &&
abMaxAtrBuffer[3] == 0x00 &&
abMaxAtrBuffer[4] == 0x81 &&
abMaxAtrBuffer[5] == 0x31 &&
abMaxAtrBuffer[6] == 0x90 &&
abMaxAtrBuffer[7] == 0x73 ) {
ulHistoricalBytes = 4;
}
ulExpectedLengthOfAtr += ulHistoricalBytes;
if (fOnlyT0 == FALSE) {
ulExpectedLengthOfAtr ++;
}
while (ulCurrentLengthOfAtr < ulExpectedLengthOfAtr) {
NTStatus = CMUSB_ReadP1(DeviceObject);
if (NTStatus == STATUS_DEVICE_DATA_ERROR) {
DebugStatus = CMUSB_ReadStateAfterP1Stalled(SmartcardExtension->OsData->DeviceObject);
goto ExitPowerOnCard;
} else if (NTStatus != STATUS_SUCCESS) {
fTryNextCard = TRUE;
break;
}
ulBytesRead = SmartcardExtension->SmartcardReply.BufferLength;
RtlCopyBytes((PVOID)(abMaxAtrBuffer+ulCurrentLengthOfAtr),
(PVOID)SmartcardExtension->SmartcardReply.Buffer,
ulBytesRead);
if (fInverseAtr) {
CMUSB_InverseBuffer(abMaxAtrBuffer+ulCurrentLengthOfAtr,
ulBytesRead);
}
ulCurrentLengthOfAtr += ulBytesRead;
}
if (fTryNextCard == TRUE) {
continue;
}
// check ATR
if (ulCurrentLengthOfAtr < 3 ||
ulCurrentLengthOfAtr > SCARD_ATR_LENGTH ) {
goto ExitPowerOnCard;
}
// check if the ATR of a SAMOS card with damaged ATR msut be corrected
CMUSB_CheckAtrModified(abMaxAtrBuffer,ulCurrentLengthOfAtr);
NTStatus = STATUS_SUCCESS;
fValidAtrReceived = TRUE;
RtlCopyBytes((PVOID)pbATR,
(PVOID)abMaxAtrBuffer,
ulCurrentLengthOfAtr);
*pulATRLength = ulCurrentLengthOfAtr;
if (fInverseAtr) {
SmartcardExtension->ReaderExtension->fInverseAtr = TRUE;
} else {
SmartcardExtension->ReaderExtension->fInverseAtr = FALSE;
}
SmartcardExtension->ReaderExtension->fRawModeNecessary = FALSE;
// -------------------
// set card parameters
// -------------------
if (SmartcardExtension->ReaderExtension->fInverseAtr) {
SmartcardExtension->ReaderExtension->CardParameters.bBaudRate |= CMUSB_ODD_PARITY;
}
SmartcardExtension->ReaderExtension->CardParameters.bBaudRate |= abFrequency[ulCardType];
SmartcardExtension->ReaderExtension->CardParameters.bBaudRate |= CMUSB_BAUDRATE_9600;
SmartcardExtension->ReaderExtension->CardParameters.bCardType = CMUSB_SMARTCARD_ASYNCHRONOUS;
break;
}
ExitPowerOnCard:
// return correct error code
if (NTStatus != STATUS_NO_MEDIA && fValidAtrReceived == FALSE) {
SmartcardDebug(DEBUG_ATR,
("%s!PowerOnCard: no valid ATR received\n",DRIVER_NAME));
NTStatus = STATUS_UNRECOGNIZED_MEDIA;
}
if (NTStatus!=STATUS_SUCCESS) {
// turn off VCC again
CMUSB_PowerOffCard (SmartcardExtension );
// ignor NTStatus
}
SmartcardDebug(DEBUG_TRACE,
("%s!PowerOnCard: Exit %lx\n",DRIVER_NAME,NTStatus));
return NTStatus;
}
/*****************************************************************************
Routine Description:
Arguments:
Return Value:
*****************************************************************************/
NTSTATUS CMUSB_CardTracking(
PSMARTCARD_EXTENSION pSmartcardExtension
)
{
KIRQL oldIrql;
SmartcardDebug(DEBUG_TRACE,
("%s!CardTracking: Enter\n",DRIVER_NAME ));
//
// Set cancel routine for the notification irp
//
IoAcquireCancelSpinLock(&oldIrql);
IoSetCancelRoutine(pSmartcardExtension->OsData->NotificationIrp,
CMUSB_CancelCardTracking);
IoReleaseCancelSpinLock(oldIrql);
//
// Mark notification irp pending
//
IoMarkIrpPending(pSmartcardExtension->OsData->NotificationIrp);
SmartcardDebug(DEBUG_TRACE,
("%s!CardTracking: Exit\n",DRIVER_NAME ));
return STATUS_PENDING;
}
/*****************************************************************************
Routine Description:
Arguments:
Return Value:
*****************************************************************************/
NTSTATUS CMUSB_Cleanup(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
PSMARTCARD_EXTENSION SmartcardExtension = &DeviceExtension->SmartcardExtension;
SmartcardDebug(DEBUG_TRACE,
("%s!Cleanup: Enter\n",DRIVER_NAME));
if (SmartcardExtension->OsData->NotificationIrp != NULL &&
// test if there is a pending IRP at all
SmartcardExtension->ReaderExtension != NULL &&
// if the device has been removed ReaderExtension == NULL
DeviceExtension->lOpenCount == 1 )
// complete card tracking only if this is the the last close call
// otherwise the card tracking of the resource manager is canceled
{
//
// We need to complete the notification irp
//
CMUSB_CompleteCardTracking(SmartcardExtension);
}
SmartcardDebug(DEBUG_DRIVER,
("%s!Cleanup: Completing IRP %lx\n",DRIVER_NAME,Irp));
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_SUCCESS;
IoCompleteRequest(Irp,IO_NO_INCREMENT);
SmartcardDebug(DEBUG_TRACE,
("%s!Cleanup: Exit\n",DRIVER_NAME));
return STATUS_SUCCESS;
}
/*****************************************************************************
Routine Description:
Arguments:
Return Value:
*****************************************************************************/
NTSTATUS CMUSB_CancelCardTracking(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
PDEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
PSMARTCARD_EXTENSION SmartcardExtension = &DeviceExtension->SmartcardExtension;
SmartcardDebug(DEBUG_TRACE,
("%s!CancelCardTracking: Enter\n",DRIVER_NAME));
ASSERT(Irp == SmartcardExtension->OsData->NotificationIrp);
IoReleaseCancelSpinLock(Irp->CancelIrql);
CMUSB_CompleteCardTracking(SmartcardExtension);
SmartcardDebug(DEBUG_TRACE,
("%s!CancelCardTracking: Exit\n",DRIVER_NAME));
return STATUS_CANCELLED;
}
/*****************************************************************************
Routine Description:
Arguments:
Return Value:
*****************************************************************************/
NTSTATUS CMUSB_IoCtlVendor(
PSMARTCARD_EXTENSION SmartcardExtension
)
{
NTSTATUS NTStatus = STATUS_SUCCESS;
NTSTATUS DebugStatus;
UCHAR pbAtrBuffer[MAXIMUM_ATR_LENGTH];
ULONG ulAtrLength;
SmartcardDebug(DEBUG_TRACE,
("%s!IoCtlVendor : Enter\n",DRIVER_NAME));
switch (SmartcardExtension->MajorIoControlCode) {
case CM_IOCTL_CR80S_SAMOS_SET_HIGH_SPEED:
NTStatus = CMUSB_SetHighSpeed_CR80S_SAMOS(SmartcardExtension);
break;
case CM_IOCTL_GET_FW_VERSION:
NTStatus = CMUSB_GetFWVersion(SmartcardExtension);
break;
case CM_IOCTL_READ_DEVICE_DESCRIPTION:
NTStatus = CMUSB_ReadDeviceDescription(SmartcardExtension);
break;
case CM_IOCTL_SET_READER_9600_BAUD:
NTStatus = CMUSB_SetReader_9600Baud(SmartcardExtension);
break;
case CM_IOCTL_SET_READER_38400_BAUD:
NTStatus = CMUSB_SetReader_38400Baud(SmartcardExtension);
break;
case CM_IOCTL_SET_SYNC_PARAMETERS:
// in case of CardManUSB do nothing
NTStatus = STATUS_SUCCESS;
break;
case CM_IOCTL_SYNC_CARD_POWERON:
NTStatus = CMUSB_PowerOnSynchronousCard(SmartcardExtension,
pbAtrBuffer,
&ulAtrLength);
break;
case CM_IOCTL_2WBP_RESET_CARD:
SmartcardExtension->MinorIoControlCode = SMARTCARD_WARM_RESET;
NTStatus = CMUSB_PowerOnSynchronousCard(SmartcardExtension,
pbAtrBuffer,
&ulAtrLength);
break;
case CM_IOCTL_2WBP_TRANSFER:
NTStatus = CMUSB_Transmit2WBP(SmartcardExtension);
break;
case CM_IOCTL_3WBP_TRANSFER:
NTStatus = CMUSB_Transmit3WBP(SmartcardExtension);
break;
default:
NTStatus = STATUS_INVALID_DEVICE_REQUEST;
break;
}
SmartcardDebug(DEBUG_TRACE,
("%s!IoCtlVendor : Exit %lx\n",DRIVER_NAME,NTStatus));
return NTStatus;
}
/*****************************************************************************
Routine Description:
Arguments:
Return Value: STATUS_UNSUCCESSFUL
STATUS_SUCCESS
*****************************************************************************/
NTSTATUS CMUSB_SetHighSpeed_CR80S_SAMOS (
IN PSMARTCARD_EXTENSION SmartcardExtension
)
{
NTSTATUS NTStatus;
NTSTATUS DebugStatus;
UCHAR abReadBuffer[16];
ULONG ulBytesRead;
BYTE abCR80S_SAMOS_SET_HIGH_SPEED[4] = {0xFF,0x11,0x94,0x7A};
ULONG ulAtrLength;
BYTE abAtr[MAXIMUM_ATR_LENGTH];
LARGE_INTEGER liWaitTime;
BOOLEAN fStateTimer;
ULONG ulWaitTime;
BOOLEAN fCancelTimer = FALSE;
SmartcardDebug(DEBUG_TRACE,
("%s!SetHighSpeed_CR80S_SAMOS: Enter\n",DRIVER_NAME));
SmartcardDebug(DEBUG_PROTOCOL,
("%s!SetHighSpeed_CR80S_SAMOS: writing high speed command\n",DRIVER_NAME));
RtlCopyBytes((PVOID)SmartcardExtension->SmartcardRequest.Buffer,
(PVOID)abCR80S_SAMOS_SET_HIGH_SPEED,
sizeof(abCR80S_SAMOS_SET_HIGH_SPEED));
SmartcardExtension->SmartcardRequest.BufferLength = 4;
NTStatus = CMUSB_WriteP0(SmartcardExtension->OsData->DeviceObject,
0x01, //we can use T=1 setting for direct communication
0x00, //bValueLo,
0x00, //bValueHi,
0x00, //bIndexLo,
0x00); //bIndexHi,
if (NTStatus != STATUS_SUCCESS) {
SmartcardDebug(DEBUG_ERROR,
("%s!SetHighSpeed_CR80S_SAMOS: writing high speed command failed\n",DRIVER_NAME));
goto ExitSetHighSpeed;
}
// read back pts data
SmartcardDebug(DEBUG_PROTOCOL,
("%s!SetHighSpeed_CR80S_SAMOS: reading echo\n",DRIVER_NAME));
// maximim initial waiting time is 9600 * etu
// => 1 sec is sufficient
ulWaitTime = 1000;
liWaitTime = RtlConvertLongToLargeInteger(ulWaitTime * -10000);
KeSetTimer(&SmartcardExtension->ReaderExtension->WaitTimer,
liWaitTime,
NULL);
fCancelTimer = TRUE;
do {
SmartcardExtension->ReaderExtension->ulTimeoutP1 = ulWaitTime;
NTStatus = CMUSB_ReadP1(SmartcardExtension->OsData->DeviceObject);
if (NTStatus == STATUS_DEVICE_DATA_ERROR) {
DebugStatus = CMUSB_ReadStateAfterP1Stalled(SmartcardExtension->OsData->DeviceObject);
break;
}
fStateTimer = KeReadStateTimer(&SmartcardExtension->ReaderExtension->WaitTimer);
if (fStateTimer == TRUE) {
fCancelTimer =FALSE;
SmartcardDebug(DEBUG_PROTOCOL,
("%s!SetHighSpeed_CR80S_SAMOS: timeout while reading echo\n",DRIVER_NAME));
break;
}
} while (SmartcardExtension->SmartcardReply.Buffer[0] < 4 );
if (NTStatus != STATUS_SUCCESS) {
goto ExitSetHighSpeed;
}
SmartcardExtension->SmartcardReply.BufferLength = 4;
NTStatus = CMUSB_ReadP0(SmartcardExtension->OsData->DeviceObject);
if (NTStatus != STATUS_SUCCESS) {
SmartcardDebug(DEBUG_ERROR,
("%s!SetHighSpeed_CR80S_SAMOS: reading echo failed\n",DRIVER_NAME));
goto ExitSetHighSpeed;
}
ulBytesRead = SmartcardExtension->SmartcardReply.BufferLength;
RtlCopyBytes((PVOID)abReadBuffer,
(PVOID)SmartcardExtension->SmartcardReply.Buffer,
ulBytesRead);
// if the card has accepted this string , the string is echoed
if (abReadBuffer[0] == abCR80S_SAMOS_SET_HIGH_SPEED[0] &&
abReadBuffer[1] == abCR80S_SAMOS_SET_HIGH_SPEED[1] &&
abReadBuffer[2] == abCR80S_SAMOS_SET_HIGH_SPEED[2] &&
abReadBuffer[3] == abCR80S_SAMOS_SET_HIGH_SPEED[3] ) {
SmartcardExtension->ReaderExtension->CardParameters.bBaudRate = 0;
SmartcardExtension->ReaderExtension->CardParameters.bBaudRate |= CMUSB_FREQUENCY_5_12MHZ;
SmartcardExtension->ReaderExtension->CardParameters.bBaudRate |= CMUSB_BAUDRATE_76800;
SmartcardExtension->ReaderExtension->CardParameters.bCardType = CMUSB_SMARTCARD_ASYNCHRONOUS;
NTStatus = CMUSB_SetCardParameters (SmartcardExtension->OsData->DeviceObject,
SmartcardExtension->ReaderExtension->CardParameters.bCardType,
SmartcardExtension->ReaderExtension->CardParameters.bBaudRate,
SmartcardExtension->ReaderExtension->CardParameters.bStopBits);
} else {
DebugStatus = CMUSB_PowerOffCard(SmartcardExtension);
// a cold reset is necessary now
SmartcardExtension->MinorIoControlCode = SCARD_COLD_RESET;
DebugStatus = CMUSB_PowerOnCard(SmartcardExtension,abAtr,&ulAtrLength);
NTStatus = STATUS_UNSUCCESSFUL;
}
ExitSetHighSpeed:
if (fCancelTimer == TRUE) {
KeCancelTimer(&SmartcardExtension->ReaderExtension->WaitTimer);
}
*SmartcardExtension->IoRequest.Information = 0L;
if (NTStatus != STATUS_SUCCESS)
NTStatus = STATUS_UNSUCCESSFUL;
SmartcardDebug(DEBUG_TRACE,
("%s!SetHighSpeed_CR80S_SAMOS: Exit %lx\n",DRIVER_NAME,NTStatus));
return NTStatus;
}
/*****************************************************************************
Routine Description:
Arguments:
Return Value:
*****************************************************************************/
NTSTATUS CMUSB_GetFWVersion (
IN PSMARTCARD_EXTENSION SmartcardExtension
)
{
NTSTATUS NTStatus = STATUS_SUCCESS;
SmartcardDebug(DEBUG_TRACE,
("%s!GetFWVersion : Enter\n",DRIVER_NAME));
if (SmartcardExtension->IoRequest.ReplyBufferLength < sizeof (ULONG)) {
NTStatus = STATUS_BUFFER_OVERFLOW;
goto ExitGetFWVersion;
} else {
*(PULONG)(SmartcardExtension->IoRequest.ReplyBuffer) =
SmartcardExtension->ReaderExtension->ulFWVersion;
}
ExitGetFWVersion:
*SmartcardExtension->IoRequest.Information = sizeof(ULONG);
SmartcardDebug(DEBUG_TRACE,
("%s!GetFWVersion : Exit %lx\n",DRIVER_NAME,NTStatus));
return NTStatus;
}
/*****************************************************************************
Routine Description:
Arguments:
Return Value: STATUS_UNSUCCESSFUL
STATUS_SUCCESS
*****************************************************************************/
NTSTATUS CMUSB_SetReader_9600Baud (
IN PSMARTCARD_EXTENSION SmartcardExtension
)
{
NTSTATUS NTStatus = STATUS_SUCCESS;
KIRQL irql;
SmartcardDebug(DEBUG_TRACE,
("%s!SetReader_9600Baud: Enter\n",DRIVER_NAME));
// check if card is already in specific mode
KeAcquireSpinLock(&SmartcardExtension->OsData->SpinLock,
&irql);
if (SmartcardExtension->ReaderCapabilities.CurrentState != SCARD_SPECIFIC) {
KeReleaseSpinLock(&SmartcardExtension->OsData->SpinLock,
irql);
NTStatus = STATUS_INVALID_DEVICE_REQUEST;
goto ExitSetReader9600;
} else {
KeReleaseSpinLock(&SmartcardExtension->OsData->SpinLock,
irql);
}
// set 9600 Baud for 3.58 MHz
SmartcardExtension->ReaderExtension->CardParameters.bBaudRate = CMUSB_FREQUENCY_3_72MHZ + CMUSB_BAUDRATE_9600;
SmartcardExtension->ReaderExtension->CardParameters.bCardType = CMUSB_SMARTCARD_ASYNCHRONOUS;
NTStatus = CMUSB_SetCardParameters (SmartcardExtension->OsData->DeviceObject,
SmartcardExtension->ReaderExtension->CardParameters.bCardType,
SmartcardExtension->ReaderExtension->CardParameters.bBaudRate,
SmartcardExtension->ReaderExtension->CardParameters.bStopBits);
ExitSetReader9600:
*SmartcardExtension->IoRequest.Information = 0L;
SmartcardDebug(DEBUG_TRACE,
("%s!SetReader_9600Baud: Exit %lx\n",DRIVER_NAME,NTStatus));
return(NTStatus);
}
/*****************************************************************************
Routine Description:
Arguments:
Return Value: STATUS_UNSUCCESSFUL
STATUS_SUCCESS
*****************************************************************************/
NTSTATUS CMUSB_SetReader_38400Baud (
IN PSMARTCARD_EXTENSION SmartcardExtension
)
{
NTSTATUS NTStatus = STATUS_SUCCESS;
KIRQL irql;
SmartcardDebug(DEBUG_TRACE,
("%s!SetReader_38400Baud: Enter\n",DRIVER_NAME));
// check if card is already in specific mode
KeAcquireSpinLock(&SmartcardExtension->OsData->SpinLock,
&irql);
if (SmartcardExtension->ReaderCapabilities.CurrentState != SCARD_SPECIFIC) {
KeReleaseSpinLock(&SmartcardExtension->OsData->SpinLock,
irql);
NTStatus = STATUS_INVALID_DEVICE_REQUEST;
goto ExitSetReader38400;
} else {
KeReleaseSpinLock(&SmartcardExtension->OsData->SpinLock,
irql);
}
// set 384000 Baud for 3.58 MHz card
SmartcardExtension->ReaderExtension->CardParameters.bBaudRate = CMUSB_FREQUENCY_3_72MHZ + CMUSB_BAUDRATE_38400;
SmartcardExtension->ReaderExtension->CardParameters.bCardType = CMUSB_SMARTCARD_ASYNCHRONOUS;
NTStatus = CMUSB_SetCardParameters (SmartcardExtension->OsData->DeviceObject,
SmartcardExtension->ReaderExtension->CardParameters.bCardType,
SmartcardExtension->ReaderExtension->CardParameters.bBaudRate,
SmartcardExtension->ReaderExtension->CardParameters.bStopBits);
ExitSetReader38400:
*SmartcardExtension->IoRequest.Information = 0L;
SmartcardDebug(DEBUG_TRACE,
("%s!SetReader_38400Baud: Exit %lx\n",DRIVER_NAME,NTStatus));
return(NTStatus);
}
/*****************************************************************************
Routine Description:
Arguments:
Return Value:
*****************************************************************************/
VOID
CMUSB_InitializeSmartcardExtension(
IN PSMARTCARD_EXTENSION SmartcardExtension
)
{
// ==================================
// Fill the Vendor_Attr structure
// ==================================
RtlCopyBytes((PVOID)SmartcardExtension->VendorAttr.VendorName.Buffer,
(PVOID)CM2020_VENDOR_NAME,
sizeof(CM2020_VENDOR_NAME)
);
//
// Length of vendor name
//
SmartcardExtension->VendorAttr.VendorName.Length = sizeof(CM2020_VENDOR_NAME);
//
// Reader name
//
RtlCopyBytes((PVOID)SmartcardExtension->VendorAttr.IfdType.Buffer,
(PVOID)CM2020_PRODUCT_NAME,
sizeof(CM2020_PRODUCT_NAME));
//
// Length of reader name
//
SmartcardExtension->VendorAttr.IfdType.Length = sizeof(CM2020_PRODUCT_NAME);
//
// Version number
//
SmartcardExtension->VendorAttr.IfdVersion.BuildNumber = BUILDNUMBER_CARDMAN_USB;
SmartcardExtension->VendorAttr.IfdVersion.VersionMinor = VERSIONMINOR_CARDMAN_USB;
SmartcardExtension->VendorAttr.IfdVersion.VersionMajor = VERSIONMAJOR_CARDMAN_USB;
//
// Unit number which is zero based
//
SmartcardExtension->VendorAttr.UnitNo = SmartcardExtension->ReaderExtension->ulDeviceInstance;
// ================================================
// Fill the SCARD_READER_CAPABILITIES structure
// ===============================================
//
// Supported protoclols by the reader
//
SmartcardExtension->ReaderCapabilities.SupportedProtocols = SCARD_PROTOCOL_T1 | SCARD_PROTOCOL_T0;
//
// Reader type serial, keyboard, ....
//
SmartcardExtension->ReaderCapabilities.ReaderType = SCARD_READER_TYPE_USB;
//
// Mechanical characteristics like swallows etc.
//
SmartcardExtension->ReaderCapabilities.MechProperties = 0;
//
// Current state of the reader
//
SmartcardExtension->ReaderExtension->ulOldCardState = UNKNOWN;
SmartcardExtension->ReaderExtension->ulNewCardState = UNKNOWN;
SmartcardExtension->ReaderCapabilities.CurrentState = SCARD_UNKNOWN;
//
// Data Rate
//
SmartcardExtension->ReaderCapabilities.DataRate.Default =
SmartcardExtension->ReaderCapabilities.DataRate.Max =
dataRatesSupported[0];
// reader could support higher data rates
SmartcardExtension->ReaderCapabilities.DataRatesSupported.List =
dataRatesSupported;
SmartcardExtension->ReaderCapabilities.DataRatesSupported.Entries =
sizeof(dataRatesSupported) / sizeof(dataRatesSupported[0]);
//
// CLK Frequency
//
SmartcardExtension->ReaderCapabilities.CLKFrequency.Default =
SmartcardExtension->ReaderCapabilities.CLKFrequency.Max =
CLKFrequenciesSupported[0];
// reader could support higher frequencies
SmartcardExtension->ReaderCapabilities.CLKFrequenciesSupported.List =
CLKFrequenciesSupported;
SmartcardExtension->ReaderCapabilities.CLKFrequenciesSupported.Entries =
sizeof(CLKFrequenciesSupported) / sizeof(CLKFrequenciesSupported[0]);
//
// MaxIFSD
//
SmartcardExtension->ReaderCapabilities.MaxIFSD = ATTR_MAX_IFSD_CARDMAN_USB;
}
/*****************************************************************************
Routine Description:
This function always returns 'CardManUSB'.
Arguments: pointer to SMARTCARD_EXTENSION
Return Value: NT NTStatus
*****************************************************************************/
NTSTATUS
CMUSB_ReadDeviceDescription(IN PSMARTCARD_EXTENSION SmartcardExtension )
{
NTSTATUS NTStatus = STATUS_SUCCESS;
BYTE abDeviceDescription[] = "CardManUSB";
SmartcardDebug(DEBUG_TRACE,
("%s!ReadDeviceDescription : Enter\n",DRIVER_NAME));
if (SmartcardExtension->IoRequest.ReplyBufferLength < sizeof(abDeviceDescription)) {
NTStatus = STATUS_BUFFER_OVERFLOW;
*SmartcardExtension->IoRequest.Information = 0L;
goto ExitReadDeviceDescription;
} else {
RtlCopyBytes((PVOID)SmartcardExtension->IoRequest.ReplyBuffer,
(PVOID)abDeviceDescription,
sizeof(abDeviceDescription));
*SmartcardExtension->IoRequest.Information = sizeof(abDeviceDescription);
}
ExitReadDeviceDescription:
SmartcardDebug(DEBUG_TRACE,
("%s!ReadDeviceDescription : Exit %lx\n",DRIVER_NAME,NTStatus));
return NTStatus;
}
/*****************************************************************************
Routine Description:
This routine always returns FALSE.
Arguments: pointer to SMARDCARD_EXTENSION
Return Value: NT NTStatus
*****************************************************************************/
NTSTATUS
CMUSB_IsSPESupported (IN PSMARTCARD_EXTENSION SmartcardExtension )
{
NTSTATUS NTStatus = STATUS_SUCCESS;
SmartcardDebug(DEBUG_TRACE,
("%s!IsSPESupported: Enter\n",DRIVER_NAME));
if (SmartcardExtension->IoRequest.ReplyBufferLength < sizeof (ULONG)) {
NTStatus = STATUS_BUFFER_OVERFLOW;
*SmartcardExtension->IoRequest.Information = 0;
goto ExitIsSPESupported;
} else {
*(PULONG)(SmartcardExtension->IoRequest.ReplyBuffer) = FALSE;
*SmartcardExtension->IoRequest.Information = sizeof(ULONG);
}
ExitIsSPESupported:
SmartcardDebug(DEBUG_TRACE,
("%s!IsSPESupported: Exit %lx\n",DRIVER_NAME,NTStatus));
return NTStatus;
}
/*****************************************************************************
Routine Description:
Arguments:
Return Value:
*****************************************************************************/
NTSTATUS CMUSB_SetCardParameters (
IN PDEVICE_OBJECT DeviceObject,
IN UCHAR bCardType,
IN UCHAR bBaudRate,
IN UCHAR bStopBits
)
{
NTSTATUS NTStatus;
PDEVICE_EXTENSION DeviceExtension;
PSMARTCARD_EXTENSION SmartcardExtension;
SmartcardDebug(DEBUG_TRACE,
("%s!SetCardParameters: Enter\n",DRIVER_NAME));
SmartcardDebug(DEBUG_PROTOCOL,
("%s!SetCardParameters: ##################################################\n",DRIVER_NAME));
SmartcardDebug(DEBUG_PROTOCOL,
("%s!SetCardParameters: bCardType = %x bBaudRate = %x bStopBits = %x\n",DRIVER_NAME,
bCardType,bBaudRate,bStopBits));
SmartcardDebug(DEBUG_PROTOCOL,
("%s!SetCardParameters: ##################################################\n",DRIVER_NAME));
DeviceExtension = DeviceObject->DeviceExtension;
SmartcardExtension = &DeviceExtension->SmartcardExtension;
SmartcardExtension->SmartcardRequest.BufferLength = 0;
NTStatus = CMUSB_WriteP0(DeviceObject,
0x30, //bRequest,
bCardType, //bValueLo,
bBaudRate, //bValueHi,
bStopBits, //bIndexLo,
0x00 //bIndexHi,
);
SmartcardDebug(DEBUG_TRACE,
("%s!SetCardParameters: Exit %lx\n",DRIVER_NAME,NTStatus));
return NTStatus;
}
/*****************************************************************************
Routine Description:
Bit0 -> Bit 7
Bit1 -> Bit 6
Bit2 -> Bit 5
Bit3 -> Bit 4
Bit4 -> Bit 3
Bit5 -> Bit 2
Bit6 -> Bit 1
Bit7 -> Bit 0
Arguments:
Return Value:
*****************************************************************************/
VOID CMUSB_InverseBuffer (
PUCHAR pbBuffer,
ULONG ulBufferSize
)
{
ULONG i;
ULONG j;
ULONG m;
ULONG n;
for (i=0; i<ulBufferSize; i++) {
n = 0;
for (j=1; j<=8; j++) {
m = (pbBuffer[i] << j);
m &= 0x00000100;
n |= (m >> (9-j));
}
pbBuffer[i] = (UCHAR)~n;
}
return;
}
/*****************************************************************************
Routine Description:
This function checks if an incorrect ATR has been received.
It corrects the number of historical bytes and the checksum byte
Arguments: pointer to current ATR
length of ATR
Return Value: none
*****************************************************************************/
VOID CMUSB_CheckAtrModified (
PUCHAR pbBuffer,
ULONG ulBufferSize
)
{
UCHAR bNumberHistoricalBytes;
UCHAR bXorChecksum;
ULONG i;
if (ulBufferSize < 0x09) // mininmum length of a modified ATR
return ; // ATR is ok
// variant 2
if (pbBuffer[0] == 0x3b &&
pbBuffer[1] == 0xbf &&
pbBuffer[2] == 0x11 &&
pbBuffer[3] == 0x00 &&
pbBuffer[4] == 0x81 &&
pbBuffer[5] == 0x31 &&
pbBuffer[6] == 0x90 &&
pbBuffer[7] == 0x73 &&
ulBufferSize == 13 ) {
// correct number of historical bytes
bNumberHistoricalBytes = 4;
pbBuffer[1] &= 0xf0;
pbBuffer[1] |= bNumberHistoricalBytes;
// correct checksum byte
bXorChecksum = pbBuffer[1];
for (i=2;i<ulBufferSize-1;i++)
bXorChecksum ^= pbBuffer[i];
pbBuffer[ulBufferSize -1 ] = bXorChecksum;
SmartcardDebug(DEBUG_ATR,
("%s!CheckAtrModified: correcting SAMOS ATR (variant 2)\n",
DRIVER_NAME));
}
// variant 1
if (pbBuffer[0] == 0x3b &&
pbBuffer[1] == 0xb4 &&
pbBuffer[2] == 0x11 &&
pbBuffer[3] == 0x00 &&
pbBuffer[4] == 0x81 &&
pbBuffer[5] == 0x31 &&
pbBuffer[6] == 0x90 &&
pbBuffer[7] == 0x73 &&
ulBufferSize == 13 ) {
// correct checksum byte
bXorChecksum = pbBuffer[1];
for (i=2;i<ulBufferSize-1;i++)
bXorChecksum ^= pbBuffer[i];
if (pbBuffer[ulBufferSize -1 ] != bXorChecksum ) {
pbBuffer[ulBufferSize -1 ] = bXorChecksum;
SmartcardDebug(DEBUG_ATR,
("%s!CheckAtrModified: correcting SAMOS ATR (variant 1)\n",
DRIVER_NAME));
}
}
// variant 3
if (pbBuffer[0] == 0x3b &&
pbBuffer[1] == 0xbf &&
pbBuffer[2] == 0x11 &&
pbBuffer[3] == 0x00 &&
pbBuffer[4] == 0x81 &&
pbBuffer[5] == 0x31 &&
pbBuffer[6] == 0x90 &&
pbBuffer[7] == 0x73 &&
ulBufferSize == 9 ) {
// correct number of historical bytes
bNumberHistoricalBytes = 0;
pbBuffer[1] &= 0xf0;
pbBuffer[1] |= bNumberHistoricalBytes;
// correct checksum byte
bXorChecksum = pbBuffer[1];
for (i=2;i<ulBufferSize-1;i++)
bXorChecksum ^= pbBuffer[i];
pbBuffer[ulBufferSize -1 ] = bXorChecksum;
SmartcardDebug(DEBUG_ATR,
("%s!CheckAtrModified: correcting SAMOS ATR (variant 3)\n",
DRIVER_NAME));
}
}
/*****************************************************************************
* History:
* $Log: scusbcb.c $
* Revision 1.9 2001/01/17 12:36:04 WFrischauf
* No comment given
*
* Revision 1.8 2000/09/25 13:38:21 WFrischauf
* No comment given
*
* Revision 1.7 2000/08/24 09:04:38 TBruendl
* No comment given
*
* Revision 1.6 2000/08/16 14:35:03 WFrischauf
* No comment given
*
* Revision 1.5 2000/08/16 08:25:06 TBruendl
* warning :uninitialized memory removed
*
* Revision 1.4 2000/07/24 11:34:59 WFrischauf
* No comment given
*
* Revision 1.1 2000/07/20 11:50:14 WFrischauf
* No comment given
*
*
*****************************************************************************/