729 lines
19 KiB
C++
729 lines
19 KiB
C++
//-------------------------------------------------------------------
|
|
// This is abstract class for generic device
|
|
// Specific devices should use it as a parent device
|
|
// Author: Sergey Ivanov
|
|
// Log:
|
|
// 01.11.99 - implemented
|
|
//-------------------------------------------------------------------
|
|
#ifdef USBREADER_PROJECT
|
|
#pragma message("COMPILING USB READER...")
|
|
|
|
#ifndef __USB_READER__
|
|
#define __USB_READER__
|
|
|
|
#include "generic.h"
|
|
#include "usbreader.h"
|
|
|
|
#include "smartcard.h"
|
|
#include "usbdev.h"
|
|
#include "reader.h"
|
|
|
|
#include "gemcore.h"
|
|
|
|
#pragma PAGEDCODE
|
|
CUSBReader::CUSBReader()
|
|
{
|
|
ULONG DevID;
|
|
|
|
m_Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
m_Type = USBREADER_DEVICE;
|
|
interface = NULL;
|
|
DevID = incrementDeviceNumber();
|
|
TRACE("########### Creating USBReader with index %d\n",DevID);
|
|
// Each reader creates own smartcard object...
|
|
scard_Initialized = FALSE;
|
|
smartCard = new (NonPagedPool) CSmartCard;
|
|
|
|
TRACE("**** Creating pooling thread... ****\n");
|
|
// We can not use default device function because it was already used by
|
|
// our Io thread (unless we extend it?)
|
|
// Lets define new thread function and xfer control to it...
|
|
PoolingThread = new (NonPagedPool) CThread((PCLIENT_THREAD_ROUTINE)PoolingThreadFunction,this,
|
|
getDevicePoolingInterval());
|
|
if(!ALLOCATED_OK(PoolingThread))
|
|
{
|
|
DISPOSE_OBJECT(PoolingThread);
|
|
TRACE("****** FAILED TO CREATE POOLING THREAD!\n");
|
|
}
|
|
else
|
|
{
|
|
// Thread which controls asynchronous driver communications
|
|
IoThread = new (NonPagedPool) CThread((PCLIENT_THREAD_ROUTINE)ThreadFunction,this,0);
|
|
if(!ALLOCATED_OK(IoThread))
|
|
{
|
|
DISPOSE_OBJECT(IoThread);
|
|
TRACE("****** FAILED TO CREATE IO THREAD!\n");
|
|
}
|
|
else
|
|
{
|
|
IoThread->start();
|
|
setDeviceState(WORKING);
|
|
m_Status = STATUS_SUCCESS;
|
|
}
|
|
}
|
|
TRACE("********* USB Reader %8.8lX was created with status %8.8lX...\n",this,m_Status);
|
|
}
|
|
|
|
#pragma PAGEDCODE
|
|
CUSBReader::~CUSBReader()
|
|
{
|
|
TRACE("Destroing USB reader pooling thread...\n");
|
|
|
|
if(PoolingThread) PoolingThread->dispose();
|
|
|
|
|
|
if(smartCard)
|
|
{
|
|
TRACE("Disconnecting from smartcard system...\n");
|
|
smartCard->smartCardDisconnect();
|
|
smartCard->dispose();
|
|
}
|
|
if(interface) interface->dispose();
|
|
|
|
if(IoThread) IoThread->stop();
|
|
cancelAllPendingRequests();
|
|
if(IoThread) IoThread->dispose();
|
|
|
|
remove();
|
|
TRACE("********* USB Reader %8.8lX was destroied...\n",this);
|
|
}
|
|
|
|
//Handle IRP_MJ_DEVICE_READ request
|
|
#pragma PAGEDCODE
|
|
NTSTATUS CUSBReader::open(IN PIRP Irp)
|
|
{
|
|
NTSTATUS status;
|
|
TRACE("\n------- USB READER OPEN DEVICE --------\n");
|
|
if(getDeviceState()!=WORKING)
|
|
{
|
|
TRACE(" READER IS NOT AT WORKING STATE... State %x\n",getDeviceState());
|
|
status = STATUS_DEVICE_NOT_CONNECTED;
|
|
return completeDeviceRequest(Irp,status,0);
|
|
}
|
|
if(IoThread)
|
|
{
|
|
status = makeRequestPending(Irp,m_DeviceObject,OPEN_REQUEST);
|
|
// Tell thread to start processing
|
|
if(NT_SUCCESS(status))
|
|
{
|
|
TRACE("CALL THREAD FUNCTION...\n");
|
|
IoThread->callThreadFunction();
|
|
}
|
|
else return completeDeviceRequest(Irp,status,0);
|
|
}
|
|
else
|
|
{
|
|
// IoThread is not ready... Process synchronously!
|
|
status = thread_open(Irp);
|
|
}
|
|
return status;
|
|
}
|
|
|
|
|
|
#pragma PAGEDCODE
|
|
NTSTATUS CUSBReader::thread_open(PIRP Irp)
|
|
{
|
|
TRACE("\n------- PROCESSING USB READER OPEN DEVICE --------\n");
|
|
TRACE("DEVICE NUMBER %x\n", this);
|
|
if (!NT_SUCCESS(acquireRemoveLock()))
|
|
{
|
|
TRACE("------- FAILED TO LOCK USB READER --------\n");
|
|
return completeDeviceRequest(Irp, STATUS_DELETE_PENDING, 0);
|
|
}
|
|
|
|
// Check if device is already active and reports
|
|
// device busy...
|
|
if(isOpenned())
|
|
{
|
|
TRACE("------- USB READER ALREADY OPENNED --------\n");
|
|
releaseRemoveLock();
|
|
return completeDeviceRequest(Irp, STATUS_DEVICE_BUSY, 0);
|
|
}
|
|
|
|
if(!NT_SUCCESS(synchronizeDevicePowerState()))
|
|
{
|
|
DEBUG_START();//Force to debug even if thread disable it...
|
|
TRACE("******* FAILED TO SYNCHRONIZE DEVICE POWER...\n");
|
|
releaseRemoveLock();
|
|
return completeDeviceRequest(Irp, STATUS_INVALID_DEVICE_STATE, 0);
|
|
}
|
|
|
|
if(PoolingThread) PoolingThread->start();
|
|
|
|
markAsOpenned();
|
|
|
|
TRACE("\n------- USB READER OPENNED! --------\n");
|
|
releaseRemoveLock();
|
|
return completeDeviceRequest(Irp, STATUS_SUCCESS, 0);
|
|
};//Create
|
|
|
|
#pragma PAGEDCODE
|
|
VOID CUSBReader::onDeviceStart()
|
|
{
|
|
TRACE("============= PNP START INITIALIZATION ===============\n");
|
|
if(interface)
|
|
{
|
|
if(!interface->isInitialized())
|
|
{
|
|
interface->initialize();
|
|
}
|
|
}
|
|
|
|
reader_UpdateCardState();
|
|
setNotificationState(SCARD_SWALLOWED);
|
|
TRACE("============= PNP START INITIALIZATION FINISHED ===============\n");
|
|
};
|
|
|
|
#pragma PAGEDCODE
|
|
NTSTATUS CUSBReader::close(PIRP Irp)
|
|
{
|
|
DEBUG_START();//Force to debug even if thread disable it...
|
|
TRACE("\n------- USB READER CLOSE DEVICE -------\n");
|
|
if(!isOpenned())
|
|
{
|
|
return completeDeviceRequest(Irp, STATUS_SUCCESS, 0);
|
|
}
|
|
// Check lock count to know if some pending calls exist...
|
|
// Finish all pending calls...
|
|
// Stop Card pooling...
|
|
if(PoolingThread) PoolingThread->stop();
|
|
|
|
// Power down card if inserted...
|
|
if(getCardState()== SCARD_SWALLOWED)
|
|
{
|
|
ULONG ResponseBufferLength = 0;
|
|
reader_WaitForIdleAndBlock();
|
|
reader_Power(SCARD_POWER_DOWN,NULL,&ResponseBufferLength, FALSE);
|
|
reader_set_Idle();
|
|
}
|
|
|
|
setNotificationState(getCardState());
|
|
completeCardTracking();
|
|
|
|
markAsClosed();
|
|
return completeDeviceRequest(Irp, STATUS_SUCCESS, 0);
|
|
};
|
|
|
|
|
|
#pragma PAGEDCODE
|
|
NTSTATUS CUSBReader::deviceControl(IN PIRP Irp)
|
|
{
|
|
NTSTATUS status;
|
|
TRACE("\n----- IRP_MJ_DEVICE_CONTROL ------\n");
|
|
if(getDeviceState()!=WORKING)
|
|
{
|
|
TRACE(" READER IS NOT AT WORKING STATE... State %x\n",getDeviceState());
|
|
status = STATUS_DEVICE_NOT_CONNECTED;
|
|
return completeDeviceRequest(Irp,status,0);
|
|
}
|
|
|
|
status = thread_deviceControl(Irp);
|
|
return status;
|
|
}
|
|
|
|
// Redefine base class system interface function...
|
|
//Handle IRP_MJ_DEVICE_CONTROL request
|
|
#pragma PAGEDCODE
|
|
NTSTATUS CUSBReader::thread_deviceControl(IN PIRP Irp)
|
|
{ // RequestControl
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
ULONG info = 0;
|
|
|
|
if (!NT_SUCCESS(acquireRemoveLock()))
|
|
{
|
|
DEBUG_START();//Force to debug even if thread disable it...
|
|
TRACE("******* DIOC: FAILED TO AQUIRE REMOVE LOCK...\n");
|
|
return completeDeviceRequest(Irp, STATUS_DELETE_PENDING, 0);
|
|
}
|
|
|
|
TRACE("----- thread_deviceControl() ------\n");
|
|
|
|
if(isSurprizeRemoved())
|
|
{
|
|
DEBUG_START();//Force to debug even if thread disable it...
|
|
TRACE("******* DIOC: FAILED! DEVICE WAS SURPRIZE REMOVED...\n");
|
|
releaseRemoveLock();
|
|
return completeDeviceRequest(Irp, STATUS_DELETE_PENDING, 0);
|
|
}
|
|
|
|
// This was fix for "device SET_POWER without system SET_POWER"
|
|
// It was seen first on ia64 machine
|
|
// If device was powered off tell system to restore power on this device,
|
|
// wait till device will be at proper state...
|
|
/*if(!NT_SUCCESS(synchronizeDevicePowerState()))
|
|
{
|
|
DEBUG_START();//Force to debug even if thread disable it...
|
|
TRACE("******* FAILED TO SYNCHRONIZE DEVICE POWER...\n");
|
|
releaseRemoveLock();
|
|
return completeDeviceRequest(Irp, STATUS_INVALID_DEVICE_STATE, 0);
|
|
}
|
|
*/
|
|
|
|
// If we've got request but device was not enable yet -> wait for the device!
|
|
// (One of the reasons to disable device - power state change)
|
|
if(!synchronizeDeviceExecution())
|
|
{
|
|
DEBUG_START();//Force to debug even if thread disable it...
|
|
TRACE("******* DIOC: FAILED TO SYNCHRONIZE EXECUTION ...\n");
|
|
releaseRemoveLock();
|
|
return completeDeviceRequest(Irp, STATUS_DELETE_PENDING, 0);
|
|
}
|
|
|
|
// SmartCard system will complete the request,
|
|
// So... We do not need to do it here.
|
|
status = SmartcardDeviceControl(getCardExtention(),Irp);
|
|
TRACE("===== USB reader: SmartcardDeviceControl() returns %8.8lX\n", status);
|
|
releaseRemoveLock();
|
|
|
|
if(!NT_SUCCESS(status))
|
|
{// In case of errors force to update card status...
|
|
if(PoolingThread) PoolingThread->callThreadFunction();
|
|
}
|
|
return status;
|
|
}
|
|
|
|
#pragma PAGEDCODE
|
|
NTSTATUS CUSBReader::cleanup(PIRP Irp)
|
|
{
|
|
DEBUG_START();//Force to debug even if thread disable it...
|
|
TRACE("\n----- IRP_MJ_CLEANUP ------\n");
|
|
|
|
if(PoolingThread) PoolingThread->stop();
|
|
cancelAllPendingRequests();
|
|
|
|
|
|
setNotificationState(getCardState());
|
|
completeCardTracking();
|
|
|
|
reader_set_Idle();
|
|
TRACE("----- IRP_MJ_CLEANUP FINISHED... ------\n");
|
|
return completeDeviceRequest(Irp, STATUS_SUCCESS, 0);
|
|
}
|
|
|
|
|
|
#pragma LOCKEDCODE
|
|
// This is callback function for the attached threads
|
|
VOID CUSBReader::PoolingThreadFunction(CUSBReader* device)
|
|
{
|
|
if(device) device->PoolingThreadRoutine();
|
|
};
|
|
|
|
#pragma PAGEDCODE
|
|
NTSTATUS CUSBReader::PoolingThreadRoutine()
|
|
{
|
|
NTSTATUS status;
|
|
ULONG State;
|
|
LONG TimeOut;
|
|
if(!NT_SUCCESS(status = reader_WaitForIdle())) return status;
|
|
reader_set_busy();
|
|
|
|
TimeOut = getCommandTimeout();
|
|
setCommandTimeout(10000);//Change get status command timeout!
|
|
|
|
DEBUG_STOP();
|
|
State = reader_UpdateCardState();
|
|
TRACE("======>> Card state %x\n",CardState);
|
|
DEBUG_START();
|
|
|
|
setCommandTimeout(TimeOut);
|
|
|
|
reader_set_Idle();
|
|
return STATUS_SUCCESS;
|
|
};
|
|
|
|
#pragma LOCKEDCODE
|
|
VOID CUSBReader::reader_set_busy()
|
|
{
|
|
setBusy();
|
|
};
|
|
|
|
#pragma LOCKEDCODE
|
|
VOID CUSBReader::reader_set_Idle()
|
|
{
|
|
setIdle();
|
|
};
|
|
|
|
#pragma LOCKEDCODE
|
|
NTSTATUS CUSBReader::reader_WaitForIdle()
|
|
{
|
|
return waitForIdle();
|
|
};
|
|
|
|
#pragma LOCKEDCODE
|
|
NTSTATUS CUSBReader::reader_WaitForIdleAndBlock()
|
|
{
|
|
return waitForIdleAndBlock();
|
|
};
|
|
|
|
|
|
#ifdef DEBUG
|
|
/*
|
|
// Overwrite device functions...
|
|
NTSTATUS CUSBReader::read(IN PIRP Irp)
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
ULONG info = 0;
|
|
TRACE("USB reader: IRP_MJ_DEVICE_READ\n");
|
|
if (!NT_SUCCESS(acquireRemoveLock())) return completeDeviceRequest(Irp, STATUS_DELETE_PENDING, 0);
|
|
|
|
status = reader_Read(Irp);
|
|
releaseRemoveLock();
|
|
status = completeDeviceRequest(Irp, status, info);
|
|
return status;
|
|
}
|
|
NTSTATUS CUSBReader::write(IN PIRP Irp)
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
ULONG info = 0;
|
|
TRACE("USB reader: IRP_MJ_DEVICE_WRITE\n");
|
|
if (!NT_SUCCESS(acquireRemoveLock())) return completeDeviceRequest(Irp, STATUS_DELETE_PENDING, 0);
|
|
status = reader_Write(Irp);
|
|
releaseRemoveLock();
|
|
status = completeDeviceRequest(Irp, status, info);
|
|
return status;
|
|
}
|
|
*/
|
|
#endif
|
|
|
|
|
|
#pragma PAGEDCODE
|
|
BOOL CUSBReader::createInterface(LONG interfaceType, LONG protocolType,CUSBReader* device)
|
|
{
|
|
interface = kernel->createReaderInterface(interfaceType,protocolType,device);
|
|
if(interface) return TRUE;
|
|
else return FALSE;
|
|
};
|
|
|
|
#pragma PAGEDCODE
|
|
VOID CUSBReader::initializeSmartCardSystem()
|
|
{
|
|
if(smartCard)
|
|
{
|
|
CardState = SCARD_UNKNOWN;
|
|
StateToNotify = SCARD_UNKNOWN;
|
|
smartCard->smartCardConnect(this);
|
|
}
|
|
};
|
|
|
|
|
|
#pragma PAGEDCODE
|
|
VOID CUSBReader::onSystemPowerDown()
|
|
{
|
|
// Stop pooling thread
|
|
TRACE("Stop polling thread going to PowerDeviceD3 (OFF)\n");
|
|
disableDevice();
|
|
|
|
if(PoolingThread) {if(PoolingThread->isThreadActive()) setThreadRestart();};
|
|
if(PoolingThread) PoolingThread->stop();
|
|
return;
|
|
}
|
|
|
|
#pragma PAGEDCODE
|
|
VOID CUSBReader::onSystemPowerUp()
|
|
{
|
|
// Stop pooling thread
|
|
TRACE("Restore reader state going to PowerDeviceD0 (ON)\n");
|
|
if(interface)
|
|
{
|
|
if(interface->isInitialized())
|
|
{
|
|
// Restore reader mode after power down
|
|
NTSTATUS status = interface->setReaderMode(READER_MODE_NATIVE);
|
|
if(!NT_SUCCESS(status))
|
|
{
|
|
TRACE("Failed to set Gemcore reader mode %x\n",READER_MODE_NATIVE);
|
|
}
|
|
}
|
|
}
|
|
if(getCardState() >= SCARD_SWALLOWED) setCardState(SCARD_ABSENT);
|
|
completeCardTracking();
|
|
|
|
if(isRequiredThreadRestart())
|
|
{
|
|
TRACE("Starting pooling thread going to PowerDeviceD0 (ON)\n");
|
|
if(PoolingThread) PoolingThread->start();
|
|
}
|
|
|
|
enableDevice();
|
|
return;
|
|
}
|
|
|
|
#pragma PAGEDCODE
|
|
BOOLEAN CUSBReader::setDevicePowerState(IN DEVICE_POWER_STATE DeviceState)
|
|
{
|
|
NTSTATUS ntStatus = STATUS_SUCCESS;
|
|
BOOLEAN fRes = FALSE;
|
|
|
|
DEBUG_START();
|
|
switch (DeviceState)
|
|
{
|
|
case PowerDeviceD3:
|
|
// Device will be going OFF,
|
|
// TODO: add any needed device-dependent code to save state here.
|
|
// ( We have nothing to do in this sample )
|
|
TRACE("Set Device Power State to PowerDeviceD3 (OFF)\n");
|
|
setCurrentDevicePowerState(DeviceState);
|
|
break;
|
|
case PowerDeviceD1:
|
|
case PowerDeviceD2:
|
|
// power states D1,D2 translate to USB suspend
|
|
#ifdef DEBUG
|
|
TRACE("Set Device Power State to %s\n",Powerdevstate[DeviceState]);
|
|
#endif
|
|
setCurrentDevicePowerState(DeviceState);
|
|
break;
|
|
case PowerDeviceD0:
|
|
TRACE("Set Device Power State to PowerDeviceD0(ON)\n");
|
|
// We'll need to finish the rest in the completion routine;
|
|
// signal caller we're going to D0 and will need to set a completion routine
|
|
fRes = TRUE;
|
|
// Caller will pass on to PDO ( Physical Device object )
|
|
break;
|
|
default:
|
|
TRACE(" Bogus DeviceState = %x\n", DeviceState);
|
|
}
|
|
return fRes;
|
|
}
|
|
|
|
#pragma PAGEDCODE
|
|
ULONG CUSBReader::reader_UpdateCardState()
|
|
{
|
|
if(interface)
|
|
{
|
|
CardState = interface->getReaderState();
|
|
completeCardTracking();
|
|
}
|
|
else CardState = 0;
|
|
return CardState;
|
|
};
|
|
|
|
#pragma LOCKEDCODE
|
|
VOID CUSBReader::completeCardTracking()
|
|
{
|
|
if(smartCard)
|
|
{
|
|
smartCard->completeCardTracking();
|
|
}
|
|
};
|
|
|
|
|
|
#pragma PAGEDCODE
|
|
NTSTATUS CUSBReader::reader_getVersion(PUCHAR pVersion, PULONG pLength)
|
|
{
|
|
if(interface) return interface->getReaderVersion(pVersion,pLength);
|
|
else return STATUS_INVALID_DEVICE_STATE;
|
|
};
|
|
|
|
#pragma PAGEDCODE
|
|
NTSTATUS CUSBReader::reader_setMode(ULONG mode)
|
|
{
|
|
if(interface) return interface->setReaderMode(mode);
|
|
else return STATUS_INVALID_DEVICE_STATE;
|
|
};
|
|
|
|
#ifdef DEBUG
|
|
#pragma PAGEDCODE
|
|
NTSTATUS CUSBReader::reader_Read(IN PIRP Irp)
|
|
{
|
|
CIoPacket* request = new (NonPagedPool) CIoPacket(Irp);
|
|
if(!ALLOCATED_OK(request) || !ALLOCATED_OK(interface))
|
|
{
|
|
DISPOSE_OBJECT(request);
|
|
return completeDeviceRequest(Irp,STATUS_INSUFFICIENT_RESOURCES,0);
|
|
}
|
|
|
|
NTSTATUS status = interface->read(request);
|
|
DISPOSE_OBJECT(request);
|
|
return status;
|
|
};
|
|
|
|
#pragma PAGEDCODE
|
|
NTSTATUS CUSBReader::reader_Write(IN PIRP Irp)
|
|
{
|
|
CIoPacket* request = new (NonPagedPool) CIoPacket(Irp);
|
|
if(!ALLOCATED_OK(request) || !ALLOCATED_OK(interface))
|
|
{
|
|
DISPOSE_OBJECT(request);
|
|
return completeDeviceRequest(Irp,STATUS_INSUFFICIENT_RESOURCES,0);
|
|
}
|
|
|
|
NTSTATUS status = interface->write(request);
|
|
DISPOSE_OBJECT(request);
|
|
return status;
|
|
};
|
|
#endif
|
|
|
|
#pragma PAGEDCODE
|
|
NTSTATUS CUSBReader::reader_Read(BYTE * pRequest,ULONG RequestLength,BYTE * pReply,ULONG* pReplyLength)
|
|
{
|
|
if(interface) return interface->readAndWait(pRequest,RequestLength,pReply,pReplyLength);
|
|
else return STATUS_INVALID_DEVICE_STATE;
|
|
};
|
|
|
|
#pragma PAGEDCODE
|
|
NTSTATUS CUSBReader::reader_Write(BYTE* pRequest,ULONG RequestLength,BYTE * pReply,ULONG* pReplyLength)
|
|
{
|
|
if(interface) return interface->writeAndWait(pRequest,RequestLength,pReply,pReplyLength);
|
|
else return STATUS_INVALID_DEVICE_STATE;
|
|
};
|
|
|
|
#pragma PAGEDCODE
|
|
NTSTATUS CUSBReader::reader_Ioctl(ULONG ControlCode,BYTE* pRequest,ULONG RequestLength,BYTE* pReply,ULONG* pReplyLength)
|
|
{
|
|
if(interface) return interface->ioctl(ControlCode,pRequest,RequestLength,pReply,pReplyLength);
|
|
else return STATUS_INVALID_DEVICE_STATE;
|
|
};
|
|
|
|
#pragma PAGEDCODE
|
|
NTSTATUS CUSBReader::reader_SwitchSpeed(ULONG ControlCode,BYTE* pRequest,ULONG RequestLength,BYTE* pReply,ULONG* pReplyLength)
|
|
{
|
|
if(interface) return interface->SwitchSpeed(ControlCode,pRequest,RequestLength,pReply,pReplyLength);
|
|
else return STATUS_INVALID_DEVICE_STATE;
|
|
};
|
|
|
|
#pragma PAGEDCODE
|
|
NTSTATUS CUSBReader::reader_VendorAttribute(ULONG ControlCode,BYTE* pRequest,ULONG RequestLength,BYTE* pReply,ULONG* pReplyLength)
|
|
{
|
|
if(interface) return interface->VendorAttribute(ControlCode,pRequest,RequestLength,pReply,pReplyLength);
|
|
else return STATUS_INVALID_DEVICE_STATE;
|
|
};
|
|
|
|
|
|
#pragma PAGEDCODE
|
|
NTSTATUS CUSBReader::reader_Power(ULONG ControlCode,BYTE* pReply,ULONG* pReplyLength, BOOLEAN Specific)
|
|
{
|
|
if(interface) return interface->power(ControlCode,pReply,pReplyLength, Specific);
|
|
else return STATUS_INVALID_DEVICE_STATE;
|
|
};
|
|
|
|
#pragma PAGEDCODE
|
|
NTSTATUS CUSBReader::reader_SetProtocol(ULONG ProtocolRequested, UCHAR ProtocolNegociation)
|
|
{
|
|
NTSTATUS status;
|
|
|
|
if(interface)
|
|
{
|
|
ReaderConfig config = interface->getConfiguration();
|
|
// Update all required configuration fields to set specific protocol
|
|
|
|
switch(ProtocolNegociation)
|
|
{
|
|
case PROTOCOL_MODE_DEFAULT:
|
|
config.PTSMode = PTS_MODE_DISABLED;
|
|
break;
|
|
case PROTOCOL_MODE_MANUALLY:
|
|
default:
|
|
config.PTSMode = PTS_MODE_MANUALLY;
|
|
break;
|
|
}
|
|
|
|
config.PTS1 = smartCardExtention.CardCapabilities.PtsData.Fl << 4 |
|
|
smartCardExtention.CardCapabilities.PtsData.Dl;
|
|
|
|
interface->setConfiguration(config);
|
|
|
|
status = interface->setProtocol(ProtocolRequested);
|
|
return status;
|
|
}
|
|
else return STATUS_INVALID_DEVICE_STATE;
|
|
};
|
|
|
|
|
|
#pragma PAGEDCODE
|
|
NTSTATUS CUSBReader::setTransparentConfig(PSCARD_CARD_CAPABILITIES cardCapabilities, BYTE NewWtx)
|
|
{
|
|
if(interface) return interface->setTransparentConfig(cardCapabilities,NewWtx);
|
|
else return STATUS_INVALID_DEVICE_STATE;
|
|
};
|
|
|
|
|
|
#pragma PAGEDCODE
|
|
NTSTATUS CUSBReader::reader_translate_request(BYTE * pRequest,ULONG RequestLength,BYTE * pReply,ULONG* pReplyLength, PSCARD_CARD_CAPABILITIES cardCapabilities, BYTE NewWtx)
|
|
{
|
|
if(interface) return interface->translate_request(pRequest,RequestLength,pReply,pReplyLength, cardCapabilities, NewWtx);
|
|
else return STATUS_INVALID_DEVICE_STATE;
|
|
};
|
|
|
|
#pragma PAGEDCODE
|
|
NTSTATUS CUSBReader::reader_translate_response(BYTE * pRequest,ULONG RequestLength,BYTE * pReply,ULONG* pReplyLength)
|
|
{
|
|
if(interface) return interface->translate_response(pRequest,RequestLength,pReply,pReplyLength);
|
|
else return STATUS_INVALID_DEVICE_STATE;
|
|
};
|
|
|
|
#pragma PAGEDCODE
|
|
NTSTATUS CUSBReader::PnP_HandleSurprizeRemoval(IN PIRP Irp)
|
|
{ // It is PnP internal function.
|
|
// So, device will be locked at PnP entry and
|
|
// we do not need to do it here.
|
|
TRACE("******** USB READER SURPRIZE REMOVAL ********\n");
|
|
|
|
// Just stop thread and remove all pending IOs
|
|
if(PoolingThread) PoolingThread->stop();
|
|
|
|
setSurprizeRemoved();
|
|
cancelAllPendingRequests();
|
|
|
|
return PnP_Default(Irp);
|
|
};
|
|
|
|
|
|
VOID CUSBReader::onDeviceStop()
|
|
{
|
|
TRACE("******** ON USB READER STOP ********\n");
|
|
// Just stop thread and remove all pending IOs
|
|
if(PoolingThread) PoolingThread->stop();
|
|
//if(IoThread) IoThread->stop();
|
|
return;
|
|
};
|
|
|
|
// Reader startIoRequest function
|
|
// It will dispatch all pending Io requests
|
|
NTSTATUS CUSBReader::startIoRequest(CPendingIRP* IrpReq)
|
|
{
|
|
NTSTATUS status;
|
|
TRACE(" CUSBReader::::startIoRequest() was called...\n");
|
|
// Our child's functions run under protection of child BUSY/IDLE breaks.
|
|
// So, we do not need to check idle state here...
|
|
if(getDeviceState()!=WORKING)
|
|
{
|
|
TRACE(" READER IS NOT AT WORKING STATE... State %x\n",getDeviceState());
|
|
TRACE(" <<<<<< READER IO REQUEST FINISHED WITH STATUS %8.8lX>>>>>>\n",STATUS_DEVICE_NOT_CONNECTED);
|
|
NTSTATUS status = completeDeviceRequest(IrpReq->Irp, STATUS_DEVICE_NOT_CONNECTED, 0);
|
|
IrpReq->dispose();
|
|
return status;
|
|
}
|
|
|
|
// Our reader will support asynchronous communications only for these functions...
|
|
switch(IrpReq->Type)
|
|
{
|
|
case OPEN_REQUEST:
|
|
TRACE("OPEN_REQUEST RECIEVED FROM THREAD...\n");
|
|
status = thread_open(IrpReq->Irp);
|
|
break;
|
|
case IOCTL_REQUEST:
|
|
TRACE("IOCTL_REQUEST RECIEVED FROM THREAD...\n");
|
|
status = thread_deviceControl(IrpReq->Irp);
|
|
break;
|
|
default:
|
|
status = STATUS_INVALID_DEVICE_REQUEST;
|
|
}
|
|
IrpReq->dispose();
|
|
TRACE(" <<<<<< READER IO REQUEST FINISHED WITH STATUS %8.8lX>>>>>>\n",status);
|
|
return status;
|
|
};
|
|
|
|
NTSTATUS CUSBReader::ThreadRoutine()
|
|
{
|
|
// If somebody inserted pending request - dispatch it...
|
|
// It will call specific child device startIoRequest().
|
|
// It is up to that device how to handle it.
|
|
// If child device is busy - it can insert this request into
|
|
// child device request queue again and process it later...
|
|
startNextPendingRequest();
|
|
return STATUS_SUCCESS;
|
|
};
|
|
|
|
#endif
|
|
#endif //USBREADER_PROJECT
|