📄 skeleton.c
字号:
/* *---------------------------------------------------------------------- * * Module Name: * skeleton.c * * Abstract: * This module contains the code for a skeleton driver that * can just map a board into user space memory. * * Environment: * Kernel mode * * Author: * Gordon Chaffee * *---------------------------------------------------------------------- */#include <ntddk.h>#include <stdarg.h>/* * Skeleton includes */#include "skeleton_nt.h"#include "skeleton_dev.h"/* *---------------------------------------------------------------------- * Static Variables *---------------------------------------------------------------------- */static int nopens;static int timeout_interval = 100;/* * Internally defined routines */static NTSTATUS CloseDevice(IN PDEVICE_OBJECT devObj, IN PFILE_OBJECT fileObj);static NTSTATUS Dispatch(IN PDEVICE_OBJECT devObj, IN PIRP Irp);static NTSTATUS MapMemory(IN PDEVICE_OBJECT, IN OUT PVOID, IN ULONG, IN ULONG);static NTSTATUS OpenDevice(IN PDEVICE_OBJECT devObj, IN PFILE_OBJECT fileObj);static NTSTATUS ProbePCI(IN PDRIVER_OBJECT drvObj, IN PUNICODE_STRING regPath);static BOOLEAN ServiceInterrupt(IN PKINTERRUPT Interrupt, IN PVOID ServiceContext);static VOID StartIo(IN PDEVICE_OBJECT devObj, IN PIRP Irp);static VOID Unload(IN PDRIVER_OBJECT);static NTSTATUS UnmapMemory(IN PDEVICE_OBJECT, IN OUT PVOID, IN ULONG, IN ULONG);/* *---------------------------------------------------------------------- * Under NT, we can specify the parts of the code that are no longer * needed after initialization with the pragma alloc_text. *---------------------------------------------------------------------- */#if 0#ifdef ALLOC_PRAGMA# pragma alloc_text(INIT,DriverEntry)#endif#endif/* *---------------------------------------------------------------------- * DriverEntry -- * * This routine is called at system initialization time to initialize * this driver. * * Arguments: * DriverObject - Supplies the driver object. * RegistryPath - Supplies the registry path for this driver. * * Return Value: * STATUS_SUCCESS - We could initialize at least one device. * STATUS_NO_SUCH_DEVICE - We could not initialize even one device. * STATUS_UNSUCCESSFUL - For other errors? *---------------------------------------------------------------------- */NTSTATUSDriverEntry(IN PDRIVER_OBJECT drvObj, IN PUNICODE_STRING regPath){ NTSTATUS status; KdPrint(("SKELETON.SYS(DriverEntry): Entering\n")); status = ProbePCI(drvObj, regPath); if (NT_SUCCESS(status)) { /* * Create dispatch points for device control, create, close. */ drvObj->MajorFunction[IRP_MJ_CREATE] = Dispatch; drvObj->MajorFunction[IRP_MJ_CLOSE] = Dispatch; drvObj->MajorFunction[IRP_MJ_DEVICE_CONTROL] = Dispatch; drvObj->MajorFunction[IRP_MJ_READ] = Dispatch; drvObj->MajorFunction[IRP_MJ_WRITE] = Dispatch; drvObj->DriverUnload = Unload; drvObj->DriverStartIo = StartIo; } KdPrint(("SKELETON.SYS(DriverEntry): Exiting\n")); return status;}/* *---------------------------------------------------------------------- * Dispatch -- * * This routine handles all IRPs sent to this device. * * Arguments: * devObj: Pointer to the device object * irp: Pointer to an I/O request packet * * Results: * Standard NT result * * Notes: * We only handle ioctls to map and unmap the skeleton board. *---------------------------------------------------------------------- */static NTSTATUSDispatch(IN PDEVICE_OBJECT devObj, IN PIRP irp){ PIO_STACK_LOCATION irpStack; PVOID ioBuf; ULONG inBufLen; ULONG outBufLen; ULONG ioctlCode; NTSTATUS status; PSKELETON_DEVICE skelDev; ULONG key; skelDev = devObj->DeviceExtension; /* * enter device mutex to ensure one request at a time */ ExAcquireFastMutex(&skelDev->IrpMutex); irp->IoStatus.Status = STATUS_SUCCESS; irp->IoStatus.Information = 0; irpStack = IoGetCurrentIrpStackLocation(irp); ioBuf = irp->AssociatedIrp.SystemBuffer; switch (irpStack->MajorFunction) { case IRP_MJ_CREATE: KdPrint(("SKELETON.SYS: IRP_MJ_CREATE\n")); status = OpenDevice(devObj, irpStack->FileObject); break; case IRP_MJ_CLOSE: KdPrint(("SKELETON.SYS: IRP_MJ_CLOSE\n")); status = CloseDevice(devObj, irpStack->FileObject); break; case IRP_MJ_DEVICE_CONTROL: ioctlCode = irpStack->Parameters.DeviceIoControl.IoControlCode; inBufLen = irpStack->Parameters.DeviceIoControl.InputBufferLength; outBufLen = irpStack->Parameters.DeviceIoControl.OutputBufferLength; switch (ioctlCode) { case IOCTL_SKELETON_MAP_USER_PHYSICAL_MEMORY: /* PV_MMAP */ status = MapMemory(devObj, ioBuf, inBufLen, outBufLen); if (NT_SUCCESS(status)) { /* * Success! Set the following to sizeof(PVOID) to * indicate we're passing valid data back. */ irp->IoStatus.Information = sizeof(PVOID); } else { status = STATUS_INVALID_PARAMETER; KdPrint(("SKELETON.SYS: memory map failed :(\n")); } break; case IOCTL_SKELETON_UNMAP_USER_PHYSICAL_MEMORY: status = UnmapMemory(devObj, ioBuf, inBufLen, outBufLen); break; default: KdPrint(("SKELETON.SYS: unknown IRP_MJ_DEVICE_CONTROL\n")); status = STATUS_INVALID_PARAMETER; break; } break; default: KdPrint(("SKELETON.SYS: unknown Major Function\n")); status = STATUS_INVALID_PARAMETER; } /* * Don't get cute and try to use the status field of * the irp in the return status. That IRP IS GONE as * soon as you call IoCompleteRequest. */ if (status != STATUS_PENDING) { irp->IoStatus.Status = status; IoCompleteRequest(irp, IO_VIDEO_INCREMENT); } else { IoMarkIrpPending(irp); IoStartPacket(devObj, irp, &key, NULL); } ExReleaseFastMutex(&skelDev->IrpMutex); return status;}/* *---------------------------------------------------------------------- * Unload -- * * Just delete the associated device and return * * Arguments: * drvObj: Pointer to the driver object * * Results: * None *---------------------------------------------------------------------- */static VOIDUnload(IN PDRIVER_OBJECT drvObj){ WCHAR devLinkBuf[] = L"\\DosDevices\\SKELETON0"; UNICODE_STRING devLinkUniStr; WCHAR devNum; PDEVICE_OBJECT devObj, nextDev; PSKELETON_DEVICE skelDev; int tmp; CM_RESOURCE_LIST EmptyList; BOOLEAN ResourceConflict; /* * For each device that is on the machine: * * 1. Delete the symbolic links * 2. Turn off the board interrupts and disconnect the interrupt. * 3. Unmap the board memory from system space. * 4. Unreport the resources that were assigned by HalAssignSlotResources * 5. Delete the device object */ for (devNum = 0, devObj = drvObj->DeviceObject; devObj != NULL; devObj = nextDev, devNum++) { devLinkBuf[sizeof(devLinkBuf) - 1] = L'0' + devNum; RtlInitUnicodeString(&devLinkUniStr, devLinkBuf); IoDeleteSymbolicLink(&devLinkUniStr); skelDev = devObj->DeviceExtension; IoDisconnectInterrupt(skelDev->KIntrObj); MmUnmapIoSpace(skelDev->FrameBase, skelDev->MemLength); /* un-report any resources used by the driver and the device */ EmptyList.Count = 0; IoReportResourceUsage(NULL, drvObj, &EmptyList, sizeof(ULONG), drvObj->DeviceObject, &EmptyList, sizeof(ULONG), FALSE, &ResourceConflict); nextDev = devObj->NextDevice; IoDeleteDevice(devObj); } KdPrint(("SKELETON.SYS: unloading\n"));}/* *---------------------------------------------------------------------- * StartTransferTimeout -- * * Starts a timer that can check on the DMA operation. Hopefully, * it never goes off * * Results: * None *---------------------------------------------------------------------- */static voidStartTransferTimeout(IN PDEVICE_OBJECT devObj, int msTimeout, PVOID Ignore){ PSKELETON_DEVICE skelDev = devObj->DeviceExtension; skelDev->TransferDone = FALSE; /* * Timer is in 100 ns units. */ KeSetTimer(&skelDev->DeviceCheckTimer, RtlConvertLongToLargeInteger(-msTimeout * 10000), &skelDev->TimerDpc); skelDev->TimerStarted = TRUE;}/* *---------------------------------------------------------------------- * CancelTransferTimeout -- * * Remove a previously set DMA timeout timer. * * Results: * None *---------------------------------------------------------------------- */static voidCancelTransferTimeout(PVOID Context){ PDEVICE_OBJECT devObj = Context; PSKELETON_DEVICE skelDev = devObj->DeviceExtension; skelDev->TransferDone = TRUE;}/* *---------------------------------------------------------------------- * ProgramDMAUtil * * Utility routine that starts the DMA transfer * * Results: * TRUE *---------------------------------------------------------------------- */static BOOLEANProgramDMAUtil(IN PVOID Context){ PDEVICE_OBJECT devObj = Context; PSKELETON_DEVICE skelDev = devObj->DeviceExtension; ULONG bufLen; BOOLEAN writeOp; ULONG toMapLen, mappedLen; PHYSICAL_ADDRESS physAddr; PVOID virtualAddr; PIRP irp; irp = (PIRP) skelDev->syncParam1; bufLen = skelDev->IrpBufLen; virtualAddr = skelDev->VirtualAddress; writeOp = (skelDev->OperationType == IRP_MJ_READ) ? FALSE : TRUE; toMapLen = bufLen; while (toMapLen > 0) { mappedLen = (toMapLen >= 4096) ? 4096 : toMapLen; physAddr = IoMapTransfer(NULL, irp->MdlAddress, skelDev->MapRegisterBase, virtualAddr, &mappedLen, writeOp); /* * XXX: set addr on the board. This will be different per board. * Maybe you don't even have to do anything. */#if 0 board_write(start_address) = LITTLE_ENDIAN_32(physAddr.u.LowPart);#endif toMapLen -= mappedLen; virtualAddr = (((char *) virtualAddr) + mappedLen); } return TRUE;}/* *---------------------------------------------------------------------- * ProgramDMA * * This routine gets called back by NT when an adapter channel * is free to use. It then uses ProgramDMAUtil to start the * actual transfer * * Results: * *---------------------------------------------------------------------- */static IO_ALLOCATION_ACTIONProgramDMA(IN PDEVICE_OBJECT devObj, IN PIRP irp, IN PVOID MapRegisterBase, IN PVOID Context){ PSKELETON_DEVICE skelDev = devObj->DeviceExtension; skelDev->MapRegisterBase = MapRegisterBase; skelDev->syncParam1 = (ULONG) irp; KeSynchronizeExecution(skelDev->KIntrObj, ProgramDMAUtil, devObj); StartTransferTimeout(devObj, timeout_interval, NULL); /* * return a value that says we want to keep the map registers. */ return DeallocateObjectKeepRegisters;}/* *---------------------------------------------------------------------- * StartIo -- * * This gets called when we are about to start a DMA operation. * This can occur because another DMA operation just completed, * or it can occur because this is the first DMA operation. Either * way, we don't expect anything to interfere with its operation. * * Results: * None *---------------------------------------------------------------------- */static VOIDStartIo(IN PDEVICE_OBJECT devObj, IN PIRP irp){ PIO_STACK_LOCATION irpStack; PVOID ioBuf; ULONG inBufLen; ULONG outBufLen; ULONG ioctlCode; NTSTATUS status; BOOLEAN writeOp; PSKELETON_DEVICE skelDev; skelDev = devObj->DeviceExtension; irpStack = IoGetCurrentIrpStackLocation(irp); KdPrint(("SKELETON.SYS(StartIo): Beginning irp %p\n", irp)); switch (irpStack->MajorFunction) { case IRP_MJ_READ: case IRP_MJ_WRITE: break; case IRP_MJ_DEVICE_CONTROL:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -