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