ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 디바이스 드라이버 2
    Device Driver 2010. 8. 8. 15:27
    #include <ntddk.h>        /* required for WDM driver development */
    #include <stdarg.h>     /* standard io include files */
    #include <stdio.h>

    #include "devioctl.h"
    #include <initguid.h>

    DEFINE_GUID(GUID_SAMPLE,
    0x5665dec0, 0xa40a, 0x11d1, 0xb9, 0x84, 0x0, 0x20, 0xaf, 0xd7, 0x97, 0x78);
    // 현재 우리가 사용될 DeviceStack에 대한 Interface GUID를 정의합니다

    #include "SAMPLE1.h"   

    void IrpStringOut( PIRP Irp ) // IRP를 디버그프린트합니다
    {
        KIRQL Irql;
        PIO_STACK_LOCATION pStack;
       
        pStack = IoGetCurrentIrpStackLocation( Irp );

        switch( pStack->MajorFunction )
        {
        case IRP_MJ_CREATE:
            DbgPrint("[IRP_MJ_CREATE]");
            break;
        case IRP_MJ_READ:
            DbgPrint("[IRP_MJ_READ]");
            break;
        case IRP_MJ_WRITE:
            DbgPrint("[IRP_MJ_WRITE]");
            break;
        case IRP_MJ_CLEANUP:
            DbgPrint("[IRP_MJ_CLEANUP]");
            break;
        case IRP_MJ_CLOSE:
            DbgPrint("[IRP_MJ_CLOSE]");
            break;
        case IRP_MJ_DEVICE_CONTROL:
            DbgPrint("[IRP_MJ_DEVICE_CONTROL]");
            DbgPrint("ControlCode = %8X", pStack->Parameters.DeviceIoControl.IoControlCode);
            break;
        case IRP_MJ_PNP:
            DbgPrint("[IRP_MJ_PNP]");
            switch( pStack->MinorFunction )
            {
                case IRP_MN_START_DEVICE:
                    DbgPrint("IRP_MN_START_DEVICE");
                    break;
                case IRP_MN_REMOVE_DEVICE:
                    DbgPrint("IRP_MN_REMOVE_DEVICE");
                    break;
                case IRP_MN_SURPRISE_REMOVAL:
                    DbgPrint("IRP_MN_SURPRISE_REMOVAL");
                    break;
                default:
                    DbgPrint("ANY MN FUNCTION");
                    break;
            }
            break;
        case IRP_MJ_POWER:
            DbgPrint("[IRP_MJ_POWER]");
            switch( pStack->MinorFunction )
            {
                case IRP_MN_SET_POWER:
                    DbgPrint("IRP_MN_SET_POWER");
                    break;
                case IRP_MN_QUERY_POWER:
                    DbgPrint("IRP_MN_QUERY_POWER");
                    break;
                default:
                    DbgPrint("ANY MN FUNCTION");
                    break;
            }
            break;
        default:
            DbgPrint("[ANY IRP] = 0x%8X\n", Irp );
            return;
        }
        DbgPrint("\n");
    }

    NTSTATUS                                                           
    DriverEntry                                                        
        (                                                              
        IN PDRIVER_OBJECT DriverObject,             /* pointer to the device object */
        IN PUNICODE_STRING RegistryPath             /* pointer to a unicode string representing the path */
                                                    /*    to the drivers specific key in the registry    */
        )// 드라이버가 메모리에 처음상주하는 경우에만 한번 호출됩니다
    {
        NTSTATUS returnStatus = STATUS_SUCCESS;     /* stores status to be returned */

        DbgPrint("DriverEntry ++ \n" );

        DriverObject->DriverUnload = SAMPLE1_Unload;
        DriverObject->DriverExtension->AddDevice = SAMPLE1_AddDevice;
        DriverObject->MajorFunction[IRP_MJ_PNP] = SAMPLE1_PnpDispatch;
        DriverObject->MajorFunction[IRP_MJ_POWER] = SAMPLE1_PowerDispatch;
        DriverObject->MajorFunction[IRP_MJ_CREATE] = SAMPLE1_Create; // Win32 API CreateFile()과 연결됩니다
        DriverObject->MajorFunction[IRP_MJ_CLOSE] = SAMPLE1_Close; // Win32 API CloseHandle()과 연결됩니다
        DriverObject->MajorFunction[IRP_MJ_CLEANUP] = SAMPLE1_Cleanup; // Win32 API CloseHandle()과 연결됩니다

        DbgPrint("DriverEntry -- \n" );
        return returnStatus;
    }

    NTSTATUS
    SAMPLE1_AddDevice
        (
        IN PDRIVER_OBJECT DriverObject,        
        IN PDEVICE_OBJECT PhysicalDeviceObject 
        )// PNPManager는 이곳을 통해서 IRP DeviceStack을 구성하라는 요청을 합니다
    {
        /* IRP DeviceStack을 구성하기 위해서는 몇가지 단계를 거치게 됩니다
        1. DeviceObject생성작업
        2. 현존하는 DeviceStack위로 DeviceObject를 올리기
        3. DeviceObject의 Flag값 변경하기
        */
        PDEVICE_EXTENSION deviceExtension;             
        NTSTATUS returnStatus = STATUS_SUCCESS;        
        PDEVICE_OBJECT DeviceObject = NULL;            
        ULONG dwRet;

        DbgPrint("SAMPLE1_AddDevice ++ \n" );

        returnStatus = IoCreateDevice                                      
                        (                                              
                            DriverObject,                              
                            sizeof ( DEVICE_EXTENSION ),               
                            NULL,                  
                            FILE_DEVICE_UNKNOWN,
                            FILE_AUTOGENERATED_DEVICE_NAME,                                         
                            FALSE,                                     
                            &DeviceObject      
                        );// DeviceObject를 생성합니다

        if( !NT_SUCCESS( returnStatus ) )
        {
            DbgPrint("IoCreateDevice() Error, Status = %8X\n", returnStatus );
            goto SAMPLE1_AddDevice_Exit;
        }

        deviceExtension = DeviceObject->DeviceExtension;

        RtlZeroMemory( deviceExtension, sizeof(DEVICE_EXTENSION));

        deviceExtension->PhysicalDeviceObject = PhysicalDeviceObject;
       
        deviceExtension->DeviceObject = DeviceObject;

        deviceExtension->NextLayerDeviceObject =
        IoAttachDeviceToDeviceStack (
                                DeviceObject,
                                PhysicalDeviceObject   
        );// 현존하는 DeviceStack위로 DeviceObject를 올립니다

        DeviceObject->Flags |= deviceExtension->NextLayerDeviceObject->Flags &
                                ( DO_POWER_PAGABLE  | DO_POWER_INRUSH); // DeviceObject의 Flag를 변경합니다

        DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; // DeviceObject의 Flag를 변경합니다

        IoRegisterDeviceInterface( PhysicalDeviceObject, &GUID_SAMPLE, NULL, &deviceExtension->UnicodeString );
        // 현재 우리가 속한 DeviceStack에 대해 InterfaceGuid를 등록합니다
        // 리턴되는 de->UnicodeString는 사용자가 접근하는 이름입니다


    SAMPLE1_AddDevice_Exit:
        DbgPrint("SAMPLE1_AddDevice -- \n" );
        return returnStatus;
    }

    VOID                                                               
    SAMPLE1_Unload                                                      
        (                                                              
        IN PDRIVER_OBJECT DriverObject  /* pointer to device object */
        )
    {// 더이상 드라이버가 관여할 DeviceObject가 없으면 이곳이 호출된후, 드라이버는 메모리에서 제거됩니다

        DbgPrint("SAMPLE1_Unload ++ \n" );

        // Do job..

        DbgPrint("SAMPLE1_Unload -- \n" );
    }

    NTSTATUS
    SAMPLE1_DeferIrpCompletion
        (
        IN PDEVICE_OBJECT DeviceObject,     /* pointer to a device object */
        IN PIRP Irp,                        /* pointer to a I/O request packet */
        IN PVOID Context                    /* driver defined context */
        )// 명령어 IRP가 NextLayer 드라이버에서 IoCompleteRequest()함수에 의해서 종결요청되는 경우에 호출됩니다
    {
        PKEVENT event = Context;    /* kernel event passed in Context */

        DbgPrint("SAMPLE1_DeferIrpCompletion ++ \n" );

        KeSetEvent(event,
                   1,
                   FALSE);

       
        DbgPrint("SAMPLE1_DeferIrpCompletion -- \n" );

        return STATUS_MORE_PROCESSING_REQUIRED; // IoCompleteRequest()함수로 하여금, 현재 IRP의 종결과정을 중단하라는 요청을 합니다
    }

    NTSTATUS
    SAMPLE1_PnpDispatch
        (
        IN PDEVICE_OBJECT DeviceObject,     /* pointer to device object */
        IN PIRP Irp                         /* pointer to an I/O request packet */
        )
    {// PNPManager가 보내는 IRP를 처리하는 처리기
        PIO_STACK_LOCATION pStack;                /* pointer to IRP stack */
        PDEVICE_EXTENSION deviceExtension;          /* pointer to device extention */
        NTSTATUS returnStatus = STATUS_SUCCESS;     /* stores status to be returned */
        PDEVICE_OBJECT NextLayerDeviceObject;           /* pointer to the stack device object */
       
        DbgPrint("SAMPLE1_PnpDispatch ++ \n" );

        IrpStringOut( Irp );

        pStack = IoGetCurrentIrpStackLocation ( Irp );
        deviceExtension = DeviceObject->DeviceExtension;
        NextLayerDeviceObject = deviceExtension->NextLayerDeviceObject;
               
        switch ( pStack->MinorFunction )
        {
            case IRP_MN_START_DEVICE :
            {// DeviceStack을 구동하라는 허가를 의미합니다
                KEVENT event;   /* event used to wait for an operation to complete */
                KeInitializeEvent(&event, NotificationEvent, FALSE);
                IoCopyCurrentIrpStackLocationToNext(Irp); 
                IoSetCompletionRoutine(Irp,
                                       SAMPLE1_DeferIrpCompletion,
                                       &event,
                                       TRUE,
                                       TRUE,
                                       TRUE); // SAMPLE1_DeferIrpCompletion()함수가 현재 IRP에 대해 Next Layer Driver가 호출하는
                                              // IoCompleteRequest()함수에 의해서 호출되도록 유도합니다
               
                returnStatus = IoCallDriver(NextLayerDeviceObject,Irp); // NextLayer Driver에게 이 명령을 전달한뒤, 결과를 확인합니다
                if (returnStatus == STATUS_PENDING)
                {
                    KeWaitForSingleObject(
                        &event,
                        Executive,
                        KernelMode,
                        FALSE,
                        NULL);
                    returnStatus = Irp->IoStatus.Status;
                }
                if( !NT_SUCCESS( returnStatus ) )
                {
                    DbgPrint("Start Device Fail\n" );
                    IoCompleteRequest( Irp, IO_NO_INCREMENT );
                    goto SAMPLE1_PnpDispatch_Exit;
                }
                // NextLayer Driver가 이 명령을 성공적으로 다루었으면, 우리도 무엇인가를 해도 좋다는 의미입니다

                // Do Job...
                IoSetDeviceInterfaceState( &deviceExtension->UnicodeString, TRUE );
                // 사용자가 우리의 DeviceStack에 접근하는 것을 허용

                IoCompleteRequest( Irp, IO_NO_INCREMENT ); // 현재 IRP를 종결요청합니다
                // SAMPLE1_DeferIrpCompletion()함수에서 우리는 IRP에 대한 Next Layer Driver가 호출한 IoCompleteRequest()에 대해
            }    // 무시하도록 "STATUS_MORE_PROCESSING_REQUIRED"리턴을 시켰기때문에, 우리가 종결요청을 해야합니다
            break;

            case IRP_MN_SURPRISE_REMOVAL :
            { // 갑자기 장치가 PC에서 제거되었다는 의미에서 전달됩니다

                IoSetDeviceInterfaceState( &deviceExtension->UnicodeString, FALSE );
                // 사용자가 우리의 DeviceStack에 접근하는 것을 금지

                Irp->IoStatus.Status = STATUS_SUCCESS;
                IoSkipCurrentIrpStackLocation( Irp ); // 현재 IRP는 이후 종결될때까지 더이상 간섭을 하지 않겠다는 의미입니다
                returnStatus = IoCallDriver(NextLayerDeviceObject, Irp);
            }
            break;

            case IRP_MN_REMOVE_DEVICE :
            { // IRP DeviceStack을 해체하라는 요청의 의미로 전달됩니다
                IoSetDeviceInterfaceState( &deviceExtension->UnicodeString, FALSE );
                // 사용자가 우리의 DeviceStack에 접근하는 것을 금지

                RtlFreeUnicodeString( &deviceExtension->UnicodeString );
                // 사용자가 접근하는 이름을 메모리에서 해제한다

                IoDetachDevice ( NextLayerDeviceObject );// Next Layer Driver와의 연결고리를 우선 끊습니다
                                                         // SAMPLE1_AddDevice()에서 IoAttachDeviceToDeviceStack()함수의 반대의미
                IoDeleteDevice ( DeviceObject );         // 우리의 DeviceObject를 제거합니다
                                                         // SAMPLE1_AddDevice()에서 IoCreateDevice()함수의 반대의미
                Irp->IoStatus.Status = STATUS_SUCCESS;
                IoSkipCurrentIrpStackLocation( Irp ); // 현재 IRP는 이후 종결될때까지 더이상 간섭을 하지 않겠다는 의미입니다
                returnStatus = IoCallDriver(NextLayerDeviceObject, Irp);
            }
            break;

            default:
            {
                IoSkipCurrentIrpStackLocation( Irp ); // 현재 IRP는 이후 종결될때까지 더이상 간섭을 하지 않겠다는 의미입니다
                returnStatus = IoCallDriver(NextLayerDeviceObject, Irp);
            }
            break;
        }

    SAMPLE1_PnpDispatch_Exit:
        DbgPrint("SAMPLE1_PnpDispatch -- \n" );

        return returnStatus;
    }

    NTSTATUS                                                           
    SAMPLE1_PowerDispatch
        (                                                              
            IN PDEVICE_OBJECT DeviceObject,                            
            IN PIRP Irp                                                
        )
    {// POWERManager가 보내는 IRP를 처리하는 처리기
        PDEVICE_EXTENSION        deviceExtension;
        NTSTATUS returnStatus;
        PDEVICE_OBJECT NextLayerDeviceObject;           /* pointer to the stack device object */
       
        DbgPrint("SAMPLE1_PowerDispatch ++ \n" );

        IrpStringOut( Irp );

        deviceExtension = DeviceObject->DeviceExtension;
        NextLayerDeviceObject = deviceExtension->NextLayerDeviceObject;

        PoStartNextPowerIrp( Irp ); // 또 다른 Power IRP를 받을 수 있다고 PowerManager에게 알립니다
        IoSkipCurrentIrpStackLocation( Irp ); // 현재 IRP는 이후 종결될때까지 더이상 간섭을 하지 않겠다는 의미입니다
        returnStatus = PoCallDriver(NextLayerDeviceObject, Irp); // Power IRP는 다른 IRP와 달리, 반드시 PoCallDriver()함수를 사용해야 합니다
       
        DbgPrint("SAMPLE1_PowerDispatch -- \n" );
        return returnStatus;
    }

    NTSTATUS                                                           
    SAMPLE1_Create
        (                                                              
            IN PDEVICE_OBJECT DeviceObject,                            
            IN PIRP Irp                                                
        )
    {// Application가 보내는 CreateFile()함수에 대응되는 처리기
        NTSTATUS returnStatus = STATUS_SUCCESS;

        DbgPrint("SAMPLE1_Create ++ \n" );

        IrpStringOut( Irp );
       
        DbgPrint("SAMPLE1_Create -- \n" );

        Irp->IoStatus.Status = returnStatus;
        IoCompleteRequest( Irp, IO_NO_INCREMENT );

        return returnStatus;
    }

    NTSTATUS                                                           
    SAMPLE1_Cleanup
        (                                                              
            IN PDEVICE_OBJECT DeviceObject,                            
            IN PIRP Irp                                                
        )
    {// Application가 보내는 CloseHandle()함수에 대응되는 처리기
        NTSTATUS returnStatus = STATUS_SUCCESS;

        DbgPrint("SAMPLE1_Cleanup ++ \n" );

        IrpStringOut( Irp );
       
        DbgPrint("SAMPLE1_Cleanup -- \n" );

        Irp->IoStatus.Status = returnStatus;
        IoCompleteRequest( Irp, IO_NO_INCREMENT );

        return returnStatus;
    }

    NTSTATUS                                                           
    SAMPLE1_Close
        (                                                              
            IN PDEVICE_OBJECT DeviceObject,                            
            IN PIRP Irp                                                
        )
    {// Application가 보내는 CloseHandle()함수에 대응되는 처리기
        NTSTATUS returnStatus = STATUS_SUCCESS;

        DbgPrint("SAMPLE1_Close ++ \n" );

        IrpStringOut( Irp );
       
        DbgPrint("SAMPLE1_Close -- \n" );

        Irp->IoStatus.Status = returnStatus;
        IoCompleteRequest( Irp, IO_NO_INCREMENT );

        return returnStatus;
    }

Designed by Tistory.