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

-- 
linuxbios mailing list
[email protected]
http://www.linuxbios.org/mailman/listinfo/linuxbios

Reply via email to