//------------------------------------------------------------------- // 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; }