Sorry, I forgot the attachment previously.
Darmawan Salihun wrote:
Hi all, I attach the device driver code for my experimental flashrom port to windows back then. It's buggy, too much direct access, etc. But, it works at some points during my brief testing phase. It's based on the old flashrom version 1.23. I know, it's not a good example of software engineering practice. Nonetheless, I want to discuss, on which API that I should be removing from user mode application accesses and which one to retain.
Regards, Darmawan
#ifndef __BIOS_PROBE_H__ #define __BIOS_PROBE_H__
#include <ntddk.h> #include "../interfaces.h"
// Debugging macros
#if DBG #define BIOS_PROBE_KDPRINT(_x_) \ DbgPrint("BIOS_PROBE.SYS: ");\ DbgPrint _x_; #else
#define BIOS_PROBE_KDPRINT(_x_)
#endif
#define BIOS_PROBE_DEVICE_NAME_U L"\Device\bios_probe" #define BIOS_PROBE_DOS_DEVICE_NAME_U L"\DosDevices\bios_probe"
typedef struct _MMIO_RING_0_MAP{ PVOID sysAddrBase; // the starting system virtual address of the mapped physical address range ULONG size; // size of the mapped physical address range PVOID usermodeAddrBase; // pointer to the usermode virtual address where this range is mapped PMDL pMdl; // Memory Descriptor List for the memory mapped I/O range to be mapped }MMIO_RING_0_MAP, *PMMIO_RING_0_MAP;
typedef struct _DEVICE_EXTENSION{ MMIO_RING_0_MAP mapZone[MAX_MAPPED_MMIO]; ULONG rtl8139IoBase; // quick hack! }DEVICE_EXTENSION, *PDEVICE_EXTENSION;
NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING registryPath );
NTSTATUS DispatchCreate( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp );
NTSTATUS DispatchClose( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp );
VOID DispatchUnload( IN PDRIVER_OBJECT DriverObject );
NTSTATUS DispatchRead( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp );
NTSTATUS DispatchWrite( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp );
NTSTATUS DispatchIoControl( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp );
#endif //__BIOS_PROBE_H__
/*++
Module Name: bios_probe.c
Abstract: The main file of the BIOS probing utility device driver
Author: Darmawan Salihun (Aug 27, 2006)
Environment: Kernel mode
Revision History:
- Originated from the CancelSafeIrq Win_XP DDK sample by Eliyas Yakub
- (August 27, 2006) BIOS Probing device driver constructed by Darmawan Salihun
- (Sept. 9th, 2006) Device driver architecture reworked to accomodate up to 256 memory mapped I/O (MMIO) range to be mapped by the driver. Systematic comments added.
TODO: - Add routines to check if a requested physical address range __overlaps__ with the currently allocated mapZone in the device extension. Do this in MapMmio function!
--*/
#include "bios_probe.h" #include <devioctl.h> #include "../interfaces.h" #include "rtl8139_hack.h"
NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath ) /*++
Routine Description:
Installable driver initialization entry point. This entry point is called directly by the I/O system.
Arguments:
DriverObject - pointer to the driver object
registryPath - pointer to a unicode string representing the path, to driver-specific key in the registry.
Return Value:
STATUS_SUCCESS if successful, STATUS_UNSUCCESSFUL otherwise
--*/ { NTSTATUS status = STATUS_SUCCESS; UNICODE_STRING unicodeDeviceName; UNICODE_STRING unicodeDosDeviceName; PDEVICE_OBJECT deviceObject; PDEVICE_EXTENSION pDevExt; ULONG i;
UNREFERENCED_PARAMETER (RegistryPath);
BIOS_PROBE_KDPRINT(("DriverEntry Enter \n"));
DriverObject->DriverUnload = DispatchUnload;
DriverObject->MajorFunction[IRP_MJ_CREATE]= DispatchCreate; DriverObject->MajorFunction[IRP_MJ_CLOSE] = DispatchClose; DriverObject->MajorFunction[IRP_MJ_READ] = DispatchRead; DriverObject->MajorFunction[IRP_MJ_WRITE] = DispatchWrite; DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DispatchIoControl;
(void) RtlInitUnicodeString(&unicodeDeviceName, BIOS_PROBE_DEVICE_NAME_U);
status = IoCreateDevice( DriverObject, sizeof(DEVICE_EXTENSION), &unicodeDeviceName, FILE_DEVICE_UNKNOWN, 0, (BOOLEAN) FALSE, &deviceObject );
if (!NT_SUCCESS(status)) { return status; }
DbgPrint("DeviceObject %p\n", deviceObject);
// // Set the flag signifying that we will do direct I/O. This causes NT // to lock the user buffer into memory when it's accessed // deviceObject->Flags |= DO_DIRECT_IO;
// // Allocate and initialize a Unicode String containing the Win32 name // for our device. // (void)RtlInitUnicodeString( &unicodeDosDeviceName, BIOS_PROBE_DOS_DEVICE_NAME_U );
status = IoCreateSymbolicLink( (PUNICODE_STRING) &unicodeDosDeviceName, (PUNICODE_STRING) &unicodeDeviceName );
if (!NT_SUCCESS(status)) { IoDeleteDevice(deviceObject); return status; }
// // Initialize device extension // pDevExt = (PDEVICE_EXTENSION)deviceObject->DeviceExtension; for(i = 0; i < MAX_MAPPED_MMIO; i++) { pDevExt->mapZone[i].sysAddrBase = NULL; pDevExt->mapZone[i].size = 0; pDevExt->mapZone[i].usermodeAddrBase = NULL; pDevExt->mapZone[i].pMdl = NULL; } pDevExt->rtl8139IoBase = 0; // quick hack !
BIOS_PROBE_KDPRINT(("DriverEntry Exit = %x\n", status));
return status; }
NTSTATUS DispatchCreate( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) /*++ Routine Description: Process the create IRPs sent to this device. This routine does nothing but signalling successful IRP handling.
Arguments: DeviceObject - pointer to a device object. Irp - pointer to an I/O Request Packet.
Return Value: NT Status code --*/ { NTSTATUS status = STATUS_SUCCESS;
BIOS_PROBE_KDPRINT(("DispatchCreate Enter\n"));
// // The dispatch routine for IRP_MJ_CREATE is called when a // file object associated with the device is created. // This is typically because of a call to CreateFile() in // a user-mode program or because a another driver is // layering itself over a this driver. A driver is // required to supply a dispatch routine for IRP_MJ_CREATE. // BIOS_PROBE_KDPRINT(("IRP_MJ_CREATE\n")); Irp->IoStatus.Information = 0;
// // Save Status for return and complete Irp // Irp->IoStatus.Status = status; IoCompleteRequest(Irp, IO_NO_INCREMENT);
BIOS_PROBE_KDPRINT((" DispatchCreate Exit = %x\n", status));
return status; }
NTSTATUS ReadPortByte(PIRP pIrp) /*++ Routine Description: Process the IRPs with IOCTL_READ_PORT_BYTE code. This routine reads a byte from the designated port, and returns the value to usermode application through pointer to the locked-down usermode buffer in the IRP.
Arguments: pIrp - pointer to an I/O Request Packet.
Return Value: NT Status code --*/ { NTSTATUS status = STATUS_SUCCESS; IO_BYTE* pUsermodeMem = (IO_BYTE*) MmGetSystemAddressForMdlSafe( pIrp->MdlAddress, NormalPagePriority );
if( NULL != pUsermodeMem) { __asm { pushad ;// save all register contents
mov ebx, pUsermodeMem ;// build user-mode memory pointer register mov dx,[ebx].port8 ;// fetch input port addr in al,dx ;// read the byte from the device mov [ebx].value8, al ;// write probing result directly to user-mode memory
popad ;// restore all saved register value } } else { status = STATUS_INVALID_USER_BUFFER; }
return status; }
NTSTATUS ReadPortWord(PIRP pIrp) /*++ Routine Description: Process the IRPs with IOCTL_READ_PORT_WORD code. This routine reads a word from the designated port, and returns the value to usermode application through pointer to the locked-down usermode buffer in the IRP.
Arguments: pIrp - pointer to an I/O Request Packet.
Return Value: NT Status code --*/ { NTSTATUS status = STATUS_SUCCESS; IO_WORD* pUsermodeMem = (IO_WORD*) MmGetSystemAddressForMdlSafe( pIrp->MdlAddress, NormalPagePriority );
if( NULL != pUsermodeMem) { __asm { pushad ;// save all register contents
mov ebx, pUsermodeMem ;// build user-mode memory pointer register mov dx, [ebx].port16 ;// fetch input port addr in ax, dx ;// read the bytes from the device mov [ebx].value16, ax ;// write probing result directly to user-mode memory
popad ;// restore all saved register value } } else { status = STATUS_INVALID_USER_BUFFER; }
return status; }
NTSTATUS ReadPortLong(PIRP pIrp) /*++ Routine Description: Process the IRPs with IOCTL_READ_PORT_LONG code. This routine reads a DWORD from the designated port, and returns the value to usermode application through pointer to the locked-down usermode buffer in the IRP.
Arguments: pIrp - pointer to an I/O Request Packet.
Return Value: NT Status code --*/ { NTSTATUS status = STATUS_SUCCESS; IO_LONG* pUsermodeMem = (IO_LONG*) MmGetSystemAddressForMdlSafe( pIrp->MdlAddress, NormalPagePriority );
if( NULL != pUsermodeMem) { __asm { pushad ;// save all register contents
mov ebx, pUsermodeMem ;// build user-mode memory pointer register mov dx, [ebx].port32 ;// fetch input port addr in eax, dx ;// read the bytes from the device mov [ebx].value32, eax ;// write probing result directly to user-mode memory
popad ;// restore all saved register value } } else { status = STATUS_INVALID_USER_BUFFER; }
return status; }
NTSTATUS WritePortByte(PIRP pIrp) /*++ Routine Description: Process the IRPs with IOCTL_WRITE_PORT_BYTE code. This routine writes a byte to the designated port. The value of the byte and the port address are obtained through pointer to the locked-down buffer in the IRP.
Arguments: pIrp - pointer to an I/O Request Packet.
Return Value: NT Status code --*/ { NTSTATUS status = STATUS_SUCCESS; IO_BYTE* pUsermodeMem = (IO_BYTE*) MmGetSystemAddressForMdlSafe( pIrp->MdlAddress, NormalPagePriority );
if( NULL != pUsermodeMem) { __asm { pushad ;// save all register contents
mov ebx, pUsermodeMem ;// build user-mode memory pointer register mov dx, [ebx].port8 ;// fetch input port addr mov al, [ebx].value8 ;// read the value to be written directly from user-mode memory out dx, al ;// write the byte to the device
popad ;// restore all saved register value } } else { status = STATUS_INVALID_USER_BUFFER; }
return status; }
NTSTATUS WritePortWord(PIRP pIrp) /*++ Routine Description: Process the IRPs with IOCTL_WRITE_PORT_WORD code. This routine writes a word to the designated port. The value of the word and the port address are obtained through pointer to the locked-down buffer in the IRP.
Arguments: pIrp - pointer to an I/O Request Packet.
Return Value: NT Status code --*/ { NTSTATUS status = STATUS_SUCCESS; IO_WORD* pUsermodeMem = (IO_WORD*) MmGetSystemAddressForMdlSafe( pIrp->MdlAddress, NormalPagePriority );
if( NULL != pUsermodeMem) { __asm { pushad ;// save all register contents
mov ebx, pUsermodeMem ;// build user-mode memory pointer register mov dx, [ebx].port16 ;// fetch input port addr mov ax, [ebx].value16 ;// read the value to be written directly from user-mode memory out dx, ax ;// write the bytes to the device
popad ;// restore all saved register value } } else { status = STATUS_INVALID_USER_BUFFER; }
return status; }
NTSTATUS WritePortLong(PIRP pIrp) /*++ Routine Description: Process the IRPs with IOCTL_WRITE_PORT_LONG code. This routine writes a dword to the designated port. The value of the dword and the port address are obtained through pointer to the locked-down buffer in the IRP.
Arguments: pIrp - pointer to an I/O Request Packet.
Return Value: NT Status code --*/ { NTSTATUS status = STATUS_SUCCESS; IO_LONG* pUsermodeMem = (IO_LONG*) MmGetSystemAddressForMdlSafe( pIrp->MdlAddress, NormalPagePriority );
if( NULL != pUsermodeMem) { __asm { pushad ;// save all register contents
mov ebx, pUsermodeMem ;// build user-mode memory pointer register mov dx, [ebx].port32 ;// fetch input port addr mov eax, [ebx].value32 ;// read the value to be written directly from user-mode memory out dx, eax ;// write the bytes to the device
popad ;// restore all saved register value } } else { status = STATUS_INVALID_USER_BUFFER; }
return status; }
NTSTATUS MapMmio(PDEVICE_OBJECT pDO, PIRP pIrp) /*++ Routine Description: Process the IRPs with IOCTL_MAP_MMIO code. This routine maps a physical address range to the usermode application address space.
Arguments: pDO - pointer to the device object of this driver. pIrp - pointer to an I/O Request Packet.
Return Value: NT Status code
Notes: This function can only map the area below the 4-GB limit. --*/ { PDEVICE_EXTENSION pDevExt; PHYSICAL_ADDRESS phyAddr; PMMIO_MAP pUsermodeMem; ULONG i, free_idx; pDevExt = (PDEVICE_EXTENSION) pDO->DeviceExtension;
// // Check for free mapZone in the device extension. // If none is free, return an error code. // for(i = 0; i < MAX_MAPPED_MMIO; i++) { if( pDevExt->mapZone[i].sysAddrBase == NULL ) { free_idx = i; break; } }
if( i == MAX_MAPPED_MMIO ) { return STATUS_INVALID_DEVICE_REQUEST; }
// // We have obtained a free mapZone, map the physical address range. // pUsermodeMem = (MMIO_MAP*) MmGetSystemAddressForMdlSafe( pIrp->MdlAddress, NormalPagePriority ); if( NULL == pUsermodeMem) { return STATUS_INVALID_USER_BUFFER; }
phyAddr.HighPart = 0; phyAddr.LowPart = pUsermodeMem->phyAddrStart;
pDevExt->mapZone[free_idx].sysAddrBase = MmMapIoSpace( phyAddr, pUsermodeMem->size, MmNonCached); if(NULL == pDevExt->mapZone[free_idx].sysAddrBase) { return STATUS_BUFFER_TOO_SMALL; }
pDevExt->mapZone[free_idx].pMdl = IoAllocateMdl(pDevExt->mapZone[free_idx].sysAddrBase, pUsermodeMem->size, FALSE, FALSE, NULL); if(NULL == pDevExt->mapZone[free_idx].pMdl) { MmUnmapIoSpace(pDevExt->mapZone[free_idx].sysAddrBase, pUsermodeMem->size); pDevExt->mapZone[free_idx].sysAddrBase = NULL; return STATUS_BUFFER_TOO_SMALL; }
pDevExt->mapZone[free_idx].size = pUsermodeMem->size;
// // Map the system virtual address to usermode virtual address // MmBuildMdlForNonPagedPool(pDevExt->mapZone[free_idx].pMdl); pDevExt->mapZone[free_idx].usermodeAddrBase = MmMapLockedPagesSpecifyCache( pDevExt->mapZone[free_idx].pMdl, UserMode, MmNonCached, NULL, FALSE, NormalPagePriority); if(NULL == pDevExt->mapZone[free_idx].usermodeAddrBase) { IoFreeMdl(pDevExt->mapZone[free_idx].pMdl); MmUnmapIoSpace(pDevExt->mapZone[free_idx].sysAddrBase, pDevExt->mapZone[free_idx].size); pDevExt->mapZone[free_idx].sysAddrBase = NULL; pDevExt->mapZone[free_idx].size = 0; return STATUS_BUFFER_TOO_SMALL; }
// copy the resulting usermode virtual address to IRP "buffer" pUsermodeMem->usermodeVirtAddr = pDevExt->mapZone[free_idx].usermodeAddrBase;
return STATUS_SUCCESS; }
NTSTATUS CleanupMmioMapping(PDEVICE_EXTENSION pDevExt, ULONG i) /*++ Routine Description: This routine cleanup the mapping of a MMIO range and resources it consumes.
Arguments: pDevExt - pointer to the device extension of the driver i - index of the mapZone to cleanup
Return Value: NT Status code --*/ { if( NULL != pDevExt->mapZone[i].usermodeAddrBase ) { MmUnmapLockedPages( pDevExt->mapZone[i].usermodeAddrBase, pDevExt->mapZone[i].pMdl); pDevExt->mapZone[i].usermodeAddrBase = NULL; } if( NULL != pDevExt->mapZone[i].pMdl ) { IoFreeMdl(pDevExt->mapZone[i].pMdl); pDevExt->mapZone[i].pMdl = NULL; } if( NULL != pDevExt->mapZone[i].sysAddrBase ) { MmUnmapIoSpace( pDevExt->mapZone[i].sysAddrBase, pDevExt->mapZone[i].size); pDevExt->mapZone[i].sysAddrBase = NULL; pDevExt->mapZone[i].size = 0; }
return STATUS_SUCCESS; }
NTSTATUS UnmapMmio(PDEVICE_OBJECT pDO, PIRP pIrp) /*++ Routine Description: Process the IRPs with IOCTL_UNMAP_MMIO code. This routine unmaps a previously mapped physical address range.
Arguments: pDO - pointer to the device object of this driver. pIrp - pointer to an I/O Request Packet.
Return Value: NT Status code
Notes: This function can only unmap the area below the 4-GB limit. --*/ { PDEVICE_EXTENSION pDevExt; PMMIO_MAP pMmioMap; ULONG i;
// // Unmap the requested zone from the system address space // and update the device extension data // pDevExt = (PDEVICE_EXTENSION) pDO->DeviceExtension; pMmioMap = (PMMIO_MAP) MmGetSystemAddressForMdlSafe( pIrp->MdlAddress, NormalPagePriority );
for(i = 0 ; i < MAX_MAPPED_MMIO; i++) { if(pDevExt->mapZone[i].usermodeAddrBase == pMmioMap->usermodeVirtAddr) { CleanupMmioMapping(pDevExt, i); break; } }
return STATUS_SUCCESS; }
NTSTATUS DispatchIoControl( IN PDEVICE_OBJECT pDO, IN PIRP pIrp ) /*++ Routine Description: Io control code dispatch routine
Arguments: DeviceObject - pointer to a device object. Irp - pointer to current Irp
Return Value: NT status code. --*/ { NTSTATUS status = STATUS_SUCCESS; PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(pIrp); ULONG * pIoBase = NULL; ULONG bufLength, i; UCHAR * buf; PDEVICE_EXTENSION pDevExt; switch(irpStack->Parameters.DeviceIoControl.IoControlCode) { case IOCTL_READ_PORT_BYTE: { if(irpStack->Parameters.DeviceIoControl.InputBufferLength >= sizeof(IO_BYTE)) { status = ReadPortByte(pIrp); } else { status = STATUS_BUFFER_TOO_SMALL; } }break;
case IOCTL_READ_PORT_WORD: { if(irpStack->Parameters.DeviceIoControl.InputBufferLength >= sizeof(IO_WORD)) { status = ReadPortWord(pIrp); } else { status = STATUS_BUFFER_TOO_SMALL; } }break;
case IOCTL_READ_PORT_LONG: { if(irpStack->Parameters.DeviceIoControl.InputBufferLength >= sizeof(IO_LONG)) { status = ReadPortLong(pIrp); } else { status = STATUS_BUFFER_TOO_SMALL; } }break;
case IOCTL_WRITE_PORT_BYTE: { if(irpStack->Parameters.DeviceIoControl.InputBufferLength >= sizeof(IO_BYTE)) { status = WritePortByte(pIrp); } else { status = STATUS_BUFFER_TOO_SMALL; } }break;
case IOCTL_WRITE_PORT_WORD: { if(irpStack->Parameters.DeviceIoControl.InputBufferLength >= sizeof(IO_WORD)) { status = WritePortWord(pIrp); } else { status = STATUS_BUFFER_TOO_SMALL; } }break;
case IOCTL_WRITE_PORT_LONG: { if(irpStack->Parameters.DeviceIoControl.InputBufferLength >= sizeof(IO_LONG)) { status = WritePortLong(pIrp); } else { status = STATUS_BUFFER_TOO_SMALL; } }break;
case IOCTL_MAP_MMIO: { if(irpStack->Parameters.DeviceIoControl.InputBufferLength >= sizeof(MMIO_MAP)) { status = MapMmio(pDO, pIrp); } else { status = STATUS_BUFFER_TOO_SMALL; } }break; case IOCTL_UNMAP_MMIO: { if(irpStack->Parameters.DeviceIoControl.InputBufferLength >= sizeof(MMIO_MAP)) { status = UnmapMmio(pDO, pIrp); } else { status = STATUS_BUFFER_TOO_SMALL; } }break; case IOCTL_RTL8139_IOBASE_HACK: // must be called prior to IOCTL_RTL8139_ROM_WRITE_HACK // (writing into RTL8139 ROM) { if(irpStack->Parameters.DeviceIoControl.OutputBufferLength >= sizeof(ULONG)) { pIoBase = (ULONG*) MmGetSystemAddressForMdlSafe(pIrp->MdlAddress, NormalPagePriority); pDevExt = (PDEVICE_EXTENSION) pDO->DeviceExtension; pDevExt->rtl8139IoBase = *pIoBase; } else { status = STATUS_BUFFER_TOO_SMALL; } }break;
case IOCTL_RTL8139_ROM_WRITE_HACK: // must be called __after__ IOCTL_RTL8139_IOBASE_HACK { bufLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
DbgPrint("IOCTL_RTL8139_ROM_WRITE_HACK: buffer length = %d\n", bufLength); buf = (UCHAR*) MmGetSystemAddressForMdlSafe(pIrp->MdlAddress, NormalPagePriority);
/* for( i = 0; i < bufLength; i+=4) { DbgPrint("IOCTL_RTL8139_ROM_WRITE_HACK: buf[%04X] = %08X\n", i,*((ULONG*)&buf[i])); } */
pDevExt = (PDEVICE_EXTENSION) pDO->DeviceExtension;
DbgPrint("IOCTL_RTL8139_ROM_WRITE_HACK: pDevExt->rtl8139IoBase = %X\n", pDevExt->rtl8139IoBase); WriteRtl8139RomHack(pDevExt->rtl8139IoBase, bufLength, buf); }break; default: { status = STATUS_INVALID_DEVICE_REQUEST; }break; }
// // complete the I/O request and return appropriate values // pIrp->IoStatus.Status = status;
// Set number of bytes to copy back to user-mode if(status == STATUS_SUCCESS) { pIrp->IoStatus.Information = irpStack->Parameters.DeviceIoControl.OutputBufferLength; } else { pIrp->IoStatus.Information = 0; } IoCompleteRequest( pIrp, IO_NO_INCREMENT );
return status; }
NTSTATUS DispatchRead( IN PDEVICE_OBJECT pDO, IN PIRP pIrp ) /*++ Routine Description: Read dispatch routine
Arguments: DeviceObject - pointer to a device object. Irp - pointer to current Irp
Return Value: NT status code.
Note: This function does nothing. It's merely a place holder to satisfy the need of the user mode code to open the driver with a GENERIC_READ parameter. --*/ { // Just complete the I/O request right away pIrp->IoStatus.Status = STATUS_SUCCESS; pIrp->IoStatus.Information = 0; IoCompleteRequest( pIrp, IO_NO_INCREMENT );
return STATUS_SUCCESS; }
NTSTATUS DispatchWrite( IN PDEVICE_OBJECT pDO, IN PIRP pIrp ) /*++ Routine Description: Write dispatch routine
Arguments: DeviceObject - pointer to a device object. Irp - pointer to current Irp
Return Value: NT status code.
Note: This function does nothing. It's merely a place holder to satisfy the need of the user mode code to open the driver with a GENERIC_WRITE parameter. --*/ { // Just complete the I/O request right away pIrp->IoStatus.Status = STATUS_SUCCESS; pIrp->IoStatus.Information = 0; IoCompleteRequest( pIrp, IO_NO_INCREMENT );
return STATUS_SUCCESS; }
NTSTATUS DispatchClose( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) /*++ Routine Description: Process the close IRPs sent to this device.
Arguments: DeviceObject - pointer to a device object. Irp - pointer to an I/O Request Packet.
Return Value: NT Status code
Note: This function clean-up the mapped MMIO ranges that haven't been cleaned-up by a "buggy" usermode application. --*/ { PDEVICE_EXTENSION pDevExt; ULONG i; NTSTATUS status = STATUS_SUCCESS;
BIOS_PROBE_KDPRINT(("DispatchClose Enter\n"));
pDevExt = DeviceObject->DeviceExtension ;
// // Clean-up the mapped MMIO space in case the usermode // application forget to call UnmapMmio for some MMIO zone. // This is to guard against some buggy usermode application. // for(i = 0; i < MAX_MAPPED_MMIO; i++) { if(pDevExt->mapZone[i].sysAddrBase != NULL) { CleanupMmioMapping(pDevExt, i); } }
// // The IRP_MJ_CLOSE dispatch routine is called when a file object // opened on the driver is being removed from the system; that is, // all file object handles have been closed and the reference count // of the file object is down to 0. // BIOS_PROBE_KDPRINT(("IRP_MJ_CLOSE\n")); Irp->IoStatus.Information = 0;
// // Save Status for return and complete Irp // Irp->IoStatus.Status = status; IoCompleteRequest(Irp, IO_NO_INCREMENT);
BIOS_PROBE_KDPRINT((" DispatchClose Exit = %x\n", status));
return status; }
VOID DispatchUnload( IN PDRIVER_OBJECT DriverObject ) /*++ Routine Description: Free all the allocated resources, etc.
Arguments: DriverObject - pointer to a driver object.
Return Value: VOID --*/ { PDEVICE_OBJECT deviceObject = DriverObject->DeviceObject; UNICODE_STRING uniWin32NameString;
BIOS_PROBE_KDPRINT(("DispatchUnload Enter\n"));
// // Create counted string version of our Win32 device name. //
RtlInitUnicodeString( &uniWin32NameString, BIOS_PROBE_DOS_DEVICE_NAME_U );
IoDeleteSymbolicLink( &uniWin32NameString );
ASSERT(!deviceObject->AttachedDevice);
IoDeleteDevice( deviceObject );
BIOS_PROBE_KDPRINT(("DispatchUnload Exit\n")); return; }