390 lines
14 KiB
C++
390 lines
14 KiB
C++
//-------------------------------------------------------------------
|
|
// This is driver object
|
|
// It defines interface with specific system
|
|
// Author: Sergey Ivanov
|
|
// Log:
|
|
// 06/08/99 - implemented
|
|
//-------------------------------------------------------------------
|
|
#include "driver.h"
|
|
|
|
#ifdef WDM_KERNEL
|
|
#pragma message("******** WDM build... ********")
|
|
#endif
|
|
|
|
#include "usbreader.h"
|
|
|
|
// Walter Oney
|
|
// @func Determine if we're running under Windows 98 or Windows 2000
|
|
// @rdesc TRUE if running under Windows 98, FALSE if under Windows 2000
|
|
// @comm This function calls IoIsWdmVersionAvailable to see if the OS
|
|
// supports WDM version 1.10. Win98 and Win98 2d ed support 1.00, whereas
|
|
// Win2K supports 1.10.
|
|
|
|
#pragma PAGEDCODE
|
|
|
|
BOOLEAN GENERIC_EXPORT isWin98()
|
|
{ // IsWin98
|
|
#ifdef _X86_
|
|
return !IoIsWdmVersionAvailable(1, 0x10);
|
|
#else
|
|
return FALSE;
|
|
#endif // _X86_
|
|
}// IsWin98
|
|
|
|
#pragma LOCKEDCODE
|
|
|
|
#if DEBUG && defined(_X86_)
|
|
|
|
extern "C" VOID __declspec(naked) __cdecl _chkesp()
|
|
{
|
|
_asm je okay
|
|
ASSERT(!DRIVERNAME " - Stack pointer mismatch!");
|
|
okay:
|
|
_asm ret
|
|
}
|
|
|
|
#endif // DBG
|
|
|
|
// This will fix some linker problem
|
|
int __cdecl _purecall(VOID) {return 0;};
|
|
|
|
#pragma LOCKEDDATA
|
|
BOOLEAN SystemWin98 = TRUE;
|
|
ULONG ObjectCounter = 0;
|
|
|
|
#pragma INITCODE
|
|
// Driver main entry...(Actually, it could have any name...)
|
|
NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject,PUNICODE_STRING RegistryPath)
|
|
{
|
|
DBG_PRINT ("\n");
|
|
DBG_PRINT ("*** DriverEntry: DriverObject %8.8lX ***\n", DriverObject);
|
|
|
|
if(SystemWin98 = isWin98())
|
|
{
|
|
DBG_PRINT("======== WINDOWS 98 DETECTED ========\n");
|
|
}
|
|
else
|
|
DBG_PRINT("======== WINDOWS 2000 DETECTED ========\n");
|
|
// Create driver kernel...
|
|
#pragma message("********** Compiling WDM driver version *********")
|
|
DBG_PRINT (" Loading WDM kernel\n");
|
|
kernel = CKernel::loadWDMKernel();
|
|
if(!kernel)
|
|
{
|
|
// LOG ERROR!
|
|
DBG_PRINT ("ERROR: At loading WDM kernel! ***\n");
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
DBG_PRINT (" Creating unicode string for registry path...\n");
|
|
|
|
kernel->RegistryPath = new (NonPagedPool)CUString(RegistryPath);
|
|
if (!ALLOCATED_OK(kernel->RegistryPath))
|
|
{
|
|
// LOG ERROR!
|
|
DISPOSE_OBJECT(kernel->RegistryPath);
|
|
DISPOSE_OBJECT(kernel);
|
|
DBG_PRINT ("ERROR: At allocating WDM registry path! ***\n");
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
DBG_PRINT (" Registering WDM system callbacks\n");
|
|
|
|
DriverObject->DriverExtension->AddDevice = WDM_AddDevice;
|
|
DriverObject->DriverUnload = WDM_Unload;
|
|
|
|
DriverObject->MajorFunction[IRP_MJ_CREATE] = open;
|
|
DriverObject->MajorFunction[IRP_MJ_CLOSE] = close;
|
|
|
|
DriverObject->MajorFunction[IRP_MJ_WRITE] = write;
|
|
DriverObject->MajorFunction[IRP_MJ_READ] = read;
|
|
// The mechanism for handling read and write requests for a device that uses
|
|
// interrupts includes a Start I/O routine, an interrupt service routine, and
|
|
// a deferred procedure call routine that finishes handling interrupts. We
|
|
// need to supply the StartIo routine address here.
|
|
//DriverObject->DriverStartIo = startIo;
|
|
|
|
DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = WDM_SystemControl;
|
|
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = deviceControl;
|
|
DriverObject->MajorFunction[IRP_MJ_PNP] = pnpRequest;
|
|
DriverObject->MajorFunction[IRP_MJ_POWER] = powerRequest;
|
|
|
|
DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = flush;
|
|
DriverObject->MajorFunction[IRP_MJ_CLEANUP] = cleanup;
|
|
|
|
DBG_PRINT ("**** Driver was initialized successfully! ****\n");
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
WDM_SystemControl(
|
|
PDEVICE_OBJECT DeviceObject,
|
|
PIRP Irp
|
|
)
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
CDevice *device;
|
|
|
|
device = kernel->getRegisteredDevice(DeviceObject);
|
|
|
|
IoSkipCurrentIrpStackLocation(Irp);
|
|
status = IoCallDriver(device->getLowerDriver(), Irp);
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
#pragma PAGEDCODE
|
|
VOID WDM_Unload(IN PDRIVER_OBJECT DriverObject)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
DBG_PRINT ("\n*** Unload: Driver %8.8lX ***\n", DriverObject);
|
|
kernel->dispose();
|
|
DBG_PRINT("*** Object counter before unload %d\n",ObjectCounter);
|
|
|
|
DBG_PRINT (">>>>>>> All active devices were removed! Driver was unloaded! <<<<<<\n");
|
|
}
|
|
|
|
|
|
#pragma PAGEDCODE
|
|
|
|
// C wrapper functions for driver object
|
|
LONG WDM_AddDevice(IN PDRIVER_OBJECT DriverObject,IN PDEVICE_OBJECT DeviceObject)
|
|
{
|
|
NTSTATUS status = STATUS_UNSUCCESSFUL;
|
|
// Get registry about device type installation
|
|
// switch depends of device.
|
|
// Create device object
|
|
// Check device type and create device specific objects
|
|
// like serial, usb, PCMCIA and so on...
|
|
// Specific objects can overwrite base class functions.
|
|
// For now we will create USB device object
|
|
//TODO recognize device type dinamically...
|
|
|
|
|
|
#pragma message("********** Compiling USB READER driver version *********")
|
|
//status = WDM_Add_USBDevice(DriverObject,DeviceObject);
|
|
DBG_PRINT ("Adding USB reader...\n");
|
|
status = WDM_Add_USBReader(DriverObject,DeviceObject);
|
|
return status;
|
|
}
|
|
|
|
|
|
// We decided to support different devices at system...
|
|
// It requires to have different callback functions for different devices.
|
|
// So let's create wrappers and redirect requests to specific devices.
|
|
|
|
// CALLBACK WRAPPER FUNCTIONS
|
|
// This callbacks should be defined at any device object
|
|
#pragma LOCKEDCODE
|
|
IMPLEMENT_CALLBACK_LONG1(open,IN PIRP);
|
|
IMPLEMENT_CALLBACK_LONG1(close,IN PIRP);
|
|
|
|
IMPLEMENT_CALLBACK_LONG1(read,IN PIRP);
|
|
IMPLEMENT_CALLBACK_LONG1(write,IN PIRP);
|
|
IMPLEMENT_CALLBACK_VOID1(startIo,IN PIRP);
|
|
IMPLEMENT_CALLBACK_LONG1(deviceControl,IN PIRP);
|
|
IMPLEMENT_CALLBACK_LONG1(flush,IN PIRP);
|
|
IMPLEMENT_CALLBACK_LONG1(cleanup,IN PIRP);
|
|
IMPLEMENT_CALLBACK_LONG1(powerRequest,IN PIRP);
|
|
|
|
// Support callbacks
|
|
IMPLEMENT_CALLBACK_VOID1(cancelPendingIrp,IN PIRP);
|
|
|
|
#pragma LOCKEDCODE
|
|
NTSTATUS pnpRequest(IN PDEVICE_OBJECT fdo,IN PIRP Irp)
|
|
{
|
|
CDevice* device;
|
|
//CUSBReader* device;// TO CHANGE LATER....
|
|
NTSTATUS status;
|
|
PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(Irp);
|
|
ULONG MinorFunction = stack->MinorFunction;
|
|
|
|
//device = (CUSBReader*) kernel->getRegisteredDevice(fdo);// TO CHANGE LATER....
|
|
device = kernel->getRegisteredDevice(fdo);// TO CHANGE LATER....
|
|
if(!device)
|
|
{
|
|
DBG_PRINT ("*** PnP: Device was already removed...***\n");
|
|
Irp->IoStatus.Status = STATUS_INVALID_DEVICE_STATE;
|
|
Irp->IoStatus.Information = 0;
|
|
::IoCompleteRequest(Irp,IO_NO_INCREMENT);
|
|
return STATUS_INVALID_DEVICE_STATE;
|
|
}
|
|
|
|
status = device->pnpRequest(Irp);
|
|
|
|
if(MinorFunction == IRP_MN_REMOVE_DEVICE)
|
|
{
|
|
//Child devices will be removed by BUS...
|
|
if(device->getObjectType()!= CHILD_DEVICE)
|
|
{
|
|
PDEVICE_OBJECT DeviceObject = device->getSystemObject();
|
|
// Sometimes Unload can interrupt standard PnP sequence
|
|
// and remove device before we finish...
|
|
DBG_PRINT ("*** PnP: Disposing device -> %8.8lX ***\n", device);
|
|
device->dispose();
|
|
if(DeviceObject)
|
|
{
|
|
DBG_PRINT("Deleting device object %8.8lX from system...\n",DeviceObject);
|
|
DBG_PRINT("<<<<< OBJECT REFERENCE COUNT ON REMOVE %d\n",DeviceObject->ReferenceCount);
|
|
IoDeleteDevice(DeviceObject);
|
|
}
|
|
}
|
|
}
|
|
return status;
|
|
}
|
|
|
|
#pragma PAGEDCODE
|
|
LONG WDM_Add_USBReader(IN PDRIVER_OBJECT DriverObject,IN PDEVICE_OBJECT DeviceObject)
|
|
{
|
|
NTSTATUS status;
|
|
WCHAR wcTemp[256];
|
|
ULONG junk;
|
|
|
|
CLogger* logger = kernel->getLogger();
|
|
|
|
DBG_PRINT("*** AddDevice: DriverObject %8.8lX, DeviceObject %8.8lX ***\n", DriverObject, DeviceObject);
|
|
DBG_PRINT(" Creating WDM USB reader...\n");
|
|
CUSBReader* reader = kernel->createUSBReader();
|
|
if(ALLOCATED_OK(reader))
|
|
{
|
|
reader->acquireRemoveLock();
|
|
DBG_PRINT ("Call USB reader object to add the reader...\n");
|
|
status = reader->add(DriverObject,DeviceObject);
|
|
if(!NT_SUCCESS(status))
|
|
{
|
|
DBG_PRINT ("###### Add() reports error! Disposing reader...\n");
|
|
reader->dispose();
|
|
return status;
|
|
}
|
|
else//Register our device object and device class
|
|
{
|
|
DBG_PRINT (" Registering new reader %8.8lX at kernel...\n",reader);
|
|
//kernel->registerObject(reader->getSystemObject(),(CDevice*)reader);
|
|
kernel->registerObject(reader->getSystemObject(),(CUSBReader*)reader);
|
|
}
|
|
|
|
{
|
|
CUString* ustrTmp;
|
|
ANSI_STRING astrTmp;
|
|
UNICODE_STRING valname;
|
|
ULONG size = 0;
|
|
HANDLE hkey;
|
|
|
|
DBG_PRINT ("=====================================================\n");
|
|
// Set default values..
|
|
reader->setVendorName("Gemplus",sizeof("Gemplus"));
|
|
reader->setDeviceType("GemPC430",sizeof("GemPC430"));
|
|
|
|
// Get Hardware ID
|
|
status = IoGetDeviceProperty(DeviceObject, DevicePropertyHardwareID, sizeof(wcTemp), wcTemp, &junk);
|
|
if(NT_SUCCESS(status))
|
|
{
|
|
DBG_PRINT(" Device Hardware ID - %ws\n", wcTemp);
|
|
}
|
|
|
|
status = IoGetDeviceProperty(DeviceObject, DevicePropertyDeviceDescription, sizeof(wcTemp), wcTemp, &junk);
|
|
if(NT_SUCCESS(status))
|
|
{
|
|
DBG_PRINT(" Device description - %ws\n", wcTemp);
|
|
}
|
|
|
|
status = IoGetDeviceProperty(DeviceObject, DevicePropertyManufacturer, sizeof(wcTemp), wcTemp, &junk);
|
|
if(NT_SUCCESS(status))
|
|
{
|
|
DBG_PRINT(" Device Manufacturer - %ws\n", wcTemp);
|
|
}
|
|
|
|
// Get OEM IfdType if present
|
|
status = IoOpenDeviceRegistryKey(DeviceObject, PLUGPLAY_REGKEY_DEVICE, KEY_READ, &hkey);
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
// Get Vendor name...
|
|
RtlInitUnicodeString(&valname, L"VendorName");
|
|
size = 0;
|
|
status = ZwQueryValueKey(hkey, &valname, KeyValuePartialInformation, NULL, 0, &size);
|
|
if (status != STATUS_OBJECT_NAME_NOT_FOUND && size)
|
|
{
|
|
PKEY_VALUE_PARTIAL_INFORMATION vpip = (PKEY_VALUE_PARTIAL_INFORMATION) ExAllocatePool(NonPagedPool, size);
|
|
if(vpip)
|
|
{
|
|
status = ZwQueryValueKey(hkey, &valname, KeyValuePartialInformation, vpip, size, &size);
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
DBG_PRINT(" OEM Vendor name found - '%ws' \n", vpip->Data);
|
|
// Copy string into the driver...
|
|
ustrTmp = new(NonPagedPool) CUString((PWCHAR)vpip->Data);
|
|
if(ALLOCATED_OK(ustrTmp))
|
|
{
|
|
RtlUnicodeStringToAnsiString(&astrTmp,&ustrTmp->m_String,TRUE);
|
|
reader->setVendorName(astrTmp.Buffer,astrTmp.Length);
|
|
RtlFreeAnsiString(&astrTmp);
|
|
}
|
|
DISPOSE_OBJECT(ustrTmp);
|
|
}
|
|
ExFreePool(vpip);
|
|
}
|
|
}
|
|
|
|
// Get IfdType...
|
|
RtlInitUnicodeString(&valname, L"IfdType");
|
|
size = 0;
|
|
status = ZwQueryValueKey(hkey, &valname, KeyValuePartialInformation, NULL, 0, &size);
|
|
if (status != STATUS_OBJECT_NAME_NOT_FOUND && size)
|
|
{
|
|
PKEY_VALUE_PARTIAL_INFORMATION vpip = (PKEY_VALUE_PARTIAL_INFORMATION) ExAllocatePool(NonPagedPool, size);
|
|
if(vpip)
|
|
{
|
|
status = ZwQueryValueKey(hkey, &valname, KeyValuePartialInformation, vpip, size, &size);
|
|
if (NT_SUCCESS(status))
|
|
{
|
|
DBG_PRINT(" OEM IfdType found - '%ws' \n", vpip->Data);
|
|
// Copy string into the driver...
|
|
ustrTmp = new(NonPagedPool) CUString((PWCHAR)vpip->Data);
|
|
if(ALLOCATED_OK(ustrTmp))
|
|
{
|
|
RtlUnicodeStringToAnsiString(&astrTmp,&ustrTmp->m_String,TRUE);
|
|
reader->setDeviceType(astrTmp.Buffer,astrTmp.Length);
|
|
RtlFreeAnsiString(&astrTmp);
|
|
}
|
|
DISPOSE_OBJECT(ustrTmp);
|
|
}
|
|
ExFreePool(vpip);
|
|
}
|
|
}
|
|
|
|
ZwClose(hkey);
|
|
}
|
|
DBG_PRINT ("=====================================================\n");
|
|
|
|
}
|
|
status = STATUS_SUCCESS;
|
|
DBG_PRINT("**** Initializing SmartCardSystem... ****\n");
|
|
reader->initializeSmartCardSystem();
|
|
|
|
DBG_PRINT("**** Creating reader interface type %d, protocol %d ****\n",READER_INTERFACE_GEMCORE,READER_PROTOCOL_LV);
|
|
if(!reader->createInterface(READER_INTERFACE_GEMCORE,READER_PROTOCOL_LV,reader))
|
|
{
|
|
DBG_PRINT("**** Failed to create reader interface... ****\n");
|
|
if(ALLOCATED_OK(logger)) logger->logEvent(GRCLASS_FAILED_TO_CREATE_INTERFACE,DeviceObject);
|
|
//Close and unregister reader...
|
|
reader->dispose();
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
DBG_PRINT("**** USB reader successfuly loaded! ****\n");
|
|
reader->releaseRemoveLock();
|
|
//if(ALLOCATED_OK(logger)) logger->logEvent(GRCLASS_START_OK, reader->getSystemObject());
|
|
return status;
|
|
}
|
|
else
|
|
{
|
|
DISPOSE_OBJECT(reader);
|
|
DBG_PRINT("#### Failed to create USB reader...\n");
|
|
if(ALLOCATED_OK(logger)) logger->logEvent(GRCLASS_FAILED_TO_CREATE_READER,DeviceObject);
|
|
}
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|