📄 skeleton.c
字号:
ioBuf = irp->AssociatedIrp.SystemBuffer; inBufLen = irpStack->Parameters.DeviceIoControl.InputBufferLength; outBufLen = irpStack->Parameters.DeviceIoControl.OutputBufferLength; ioctlCode = irpStack->Parameters.DeviceIoControl.IoControlCode; switch (ioctlCode) { default: KdPrint(("SKELETON.SYS(StartIo): unexpected IRP_MJ_DEVICE_CONTROL\n")); status = STATUS_INVALID_PARAMETER; break; } if (status != STATUS_PENDING) { irp->IoStatus.Status = status; IoCompleteRequest(irp, IO_VIDEO_INCREMENT); IoStartNextPacket(devObj, TRUE); } return; default: KdPrint(("SKELETON.SYS(StartIo): unexpected major function\n")); irp->IoStatus.Status = STATUS_INVALID_PARAMETER; IoCompleteRequest(irp, IO_NO_INCREMENT); IoStartNextPacket(devObj, TRUE); return; } skelDev->OperationType = irpStack->MajorFunction; skelDev->IrpSystemBuffer = irp->AssociatedIrp.SystemBuffer; if (skelDev->OperationType == IRP_MJ_READ) { skelDev->IrpBufLen = irpStack->Parameters.Read.Length; } else { skelDev->IrpBufLen = irpStack->Parameters.Write.Length; } if (skelDev->IrpBufLen == 0 || irp->MdlAddress == NULL) { irp->IoStatus.Status = STATUS_INVALID_PARAMETER; IoCompleteRequest(irp, IO_NO_INCREMENT); IoStartNextPacket(devObj, TRUE); } skelDev->VirtualAddress = MmGetMdlVirtualAddress(irp->MdlAddress); if (skelDev->TimerStarted) { KeCancelTimer(&skelDev->DeviceCheckTimer); skelDev->TimerStarted = FALSE; } writeOp = (skelDev->OperationType == IRP_MJ_READ) ? FALSE : TRUE; KeFlushIoBuffers(irp->mdlAddress, !writeOp, TRUE); status = IoAllocateAdapterChannel(skelDev->AdaptorObj, devObj, skelDev->DmaMapRegisters, ProgramDMA, devObj); KdPrint(("SKELETON.SYS(StartIo): Exiting irp %p\n", irp)); if (!NT_SUCCESS(status)) { KdPrint(("SKELETON.SYS: Unable to allocate adaptor channel for DMA\n")); irp->IoStatus.Status = status; IoCompleteRequest(irp, IO_NO_INCREMENT); return; }}/* *---------------------------------------------------------------------- * TransferDPC -- * * This routine is called at DISPATCH_LEVEL by the system at the * ServiceInterrupt(). * * This routine is protected against interrupts since it was queued * by an interrupt, and the next DMA related interrupt won't occur * until something else happens. * * This routine is called when a DMA transfer has not been completed. * It sets everything up to continue the tranfer. *---------------------------------------------------------------------- */static VOIDTransferDPC(IN PKDPC Dpc, IN PVOID Context, IN PVOID Arg1, IN PVOID Arg2){ PDEVICE_OBJECT devObj = Context; PSKELETON_DEVICE skelDev = devObj->DeviceExtension; PIRP irp; BOOLEAN writeOp; KdPrint(("SKELETON.SYS(TransferDPC): Finished irp %p\n", devObj->CurrentIrp)); CancelTransferTimeout(devObj); irp = devObj->CurrentIrp; writeOp = (skelDev->OperationType == IRP_MJ_WRITE) ? TRUE : FALSE; IoFlushAdapterBuffers(NULL, irp->MdlAddress, skelDev->MapRegisterBase, skelDev->VirtualAddress, skelDev->IrpBufLen, writeOp); IoFreeMapRegisters(skelDev->AdaptorObj, skelDev->MapRegisterBase, skelDev->DmaMapRegisters); if (skelDev->OperationType == IRP_MJ_READ) { KeFlushIoBuffers(irp->MdlAddress, TRUE, TRUE); } irp->IoStatus.Status = skelDev->IrpStatus; if (skelDev->IrpStatus == STATUS_SUCCESS) { irp->IoStatus.Information = skelDev->IrpBytesTransferred; } IoCompleteRequest(irp, IO_VIDEO_INCREMENT); IoStartNextPacket(devObj, TRUE); skelDev->DpcRequested = FALSE; return;}/* *---------------------------------------------------------------------- * ServiceTimeoutUtil -- * * Utility routine for ServiceTimeout. Runs code that is * sensitive to interrupts. *---------------------------------------------------------------------- */static BOOLEANServiceTimeoutUtil(IN PCONTEXT Context){ PSKELETON_DEVICE skelDev = (PSKELETON_DEVICE) Context; return TRUE;}/* *---------------------------------------------------------------------- * ServiceTimeout -- * * Service a timeout. Is this a routine to check on the board * if nothing happens after a little while? If so, * ddk/src/multimedia/soundlib/wave.c does something similar. * * Results: * None *---------------------------------------------------------------------- */voidServiceTimeout(PDEVICE_OBJECT devObj){ PSKELETON_DEVICE skelDev = devObj->DeviceExtension; KeSynchronizeExecution(skelDev->KIntrObj, ServiceTimeoutUtil, skelDev); skelDev->IrpStatus = STATUS_UNSUCCESSFUL; skelDev->IrpBytesTransferred = 0L; skelDev->RequestDpc = TRUE; KdPrint(("SKELETON.SYS: ServiceTimeout calling TransferDPC\n")); TransferDPC(NULL, devObj, NULL, NULL);}/* *---------------------------------------------------------------------- * TimeoutDPC -- * * This routine gets called when a timeout occurs. We then * need to check plxDev->TransferDone to see if the transfer * finished before this timer went off. If is did, then we * can just ignore this DPC call. If not, we need to clear * everything up, fail the request, and move on. * * Results: * None *---------------------------------------------------------------------- */static VOIDTimeoutDPC(IN PKDPC Dpc, IN PVOID Context, IN PVOID Param1, IN PVOID Param2){ PDEVICE_OBJECT devObj = Context; PSKELETON_DEVICE skelDev = devObj->DeviceExtension; skelDev->TimerStarted = FALSE; if (! skelDev->TransferDone) { /* * XXX: Clean up the hardware here if necessary. */ ServiceTimeout(devObj); }}/* *---------------------------------------------------------------------- * OpenDevice -- * * Open the device. We will allow multiple opens to the device. * * Results: * A standard NT result *---------------------------------------------------------------------- */static NTSTATUSOpenDevice(IN PDEVICE_OBJECT devObj, IN PFILE_OBJECT fileObj){ PSKELETON_DEVICE skelDev; KdPrint(("SKELETON.SYS: OpenDevice called\n")); skelDev = devObj->DeviceExtension; ++nopens; /* inc global open */ return STATUS_SUCCESS;}/* *---------------------------------------------------------------------- * CloseDevice -- * * Close up device and free resources allocated by OpenDevice * * Results: * A standard NT result *---------------------------------------------------------------------- */static NTSTATUSCloseDevice(IN PDEVICE_OBJECT devObj, IN PFILE_OBJECT fileObj){ PSKELETON_DEVICE skelDev; skelDev = devObj->DeviceExtension; nopens--; /* decrement global open */ return STATUS_SUCCESS;}/* *---------------------------------------------------------------------- * MapMemory -- * * Given a physical address, maps this address into a user mode * process's address space * * Arguments: * devObj pointer to a device object * ioBuf pointer to the I/O buffer * inBufLen input buffer length * outBufLen output buffer length * * Results: * STATUS_SUCCESS * STATUS_UNSUCCESSFUL * STATUS_BUFFER_TOO_SMALL, * (other STATUS_* as returned by kernel APIs) *---------------------------------------------------------------------- */static NTSTATUSMapMemory(IN PDEVICE_OBJECT devObj, IN OUT PVOID ioBuf, IN ULONG inBufLen, IN ULONG outBufLen){ INTERFACE_TYPE interfaceType; ULONG busNumber; PHYSICAL_ADDRESS physicalAddr; ULONG len; UNICODE_STRING physicalMemUniStr; OBJECT_ATTRIBUTES objAttrs; HANDLE physicalMemHandle = NULL; PVOID physicalMemSection = NULL; ULONG inIoSpace, inIoSpace2; NTSTATUS status; PHYSICAL_ADDRESS physicalAddrBase; PHYSICAL_ADDRESS physicalAddrEnd; PHYSICAL_ADDRESS viewBase; PHYSICAL_ADDRESS mappedLen; BOOLEAN xlateBaseAddr; BOOLEAN xlateEndAddr; PVOID virtualAddr; PSKELETON_DEVICE skelDev; skelDev = devObj->DeviceExtension; if (outBufLen < sizeof(PVOID)) { KdPrint(("SKELETON.SYS(MapMemory): Insufficient output buffer\n")); status = STATUS_BUFFER_TOO_SMALL; goto done; } /* * Get a pointer to physical memory... * * - Create the name * - Initialize the data to find the object * - Open a handle to the oject and check the status * - Get a pointer to the object * - Free the handle */ RtlInitUnicodeString(&physicalMemUniStr, L"\\Device\\PhysicalMemory"); InitializeObjectAttributes(&objAttrs, &physicalMemUniStr, OBJ_CASE_INSENSITIVE, (HANDLE) NULL, (PSECURITY_DESCRIPTOR) NULL); status = ZwOpenSection(&physicalMemHandle, SECTION_ALL_ACCESS, &objAttrs); if (!NT_SUCCESS(status)) { KdPrint(("SKELETON.SYS: ZwOpenSection failed\n")); goto done; } status = ObReferenceObjectByHandle(physicalMemHandle, SECTION_ALL_ACCESS, (POBJECT_TYPE) NULL, KernelMode, &physicalMemSection, (POBJECT_HANDLE_INFORMATION) NULL); if (!NT_SUCCESS(status)) { KdPrint(("SKELETON.SYS: ObReferenceObjectByHandle failed\n")); goto close_handle; } interfaceType = PCIBus; busNumber = skelDev->BusId; physicalAddr = skelDev->MemStart; len = skelDev->MemLength; inIoSpace = skelDev->FrameMemType; inIoSpace2 = skelDev->FrameMemType; /* * Initialize the physical addresses that will be translated */ physicalAddrEnd = RtlLargeIntegerAdd(physicalAddr, RtlConvertUlongToLargeInteger(len)); /* * Translate the physical addresses. */ xlateBaseAddr = HalTranslateBusAddress(interfaceType, busNumber, physicalAddr, &inIoSpace, &physicalAddrBase); xlateEndAddr = HalTranslateBusAddress(interfaceType, busNumber, physicalAddrEnd, &inIoSpace2, &physicalAddrEnd); if (!(xlateBaseAddr && xlateEndAddr)) { KdPrint(("SKELETON.SYS: HalTranslatephysicalAddress failed\n")); status = STATUS_UNSUCCESSFUL; goto close_handle; } /* * Calculate the length of the memory to be mapped */ mappedLen = RtlLargeIntegerSubtract(physicalAddrEnd, physicalAddrBase); /* * If the mappedlen is zero, somthing very weird happened in the HAL * since the Length was checked against zero. */ if (mappedLen.LowPart == 0) { KdPrint(("SKELETON.SYS: mappedLen.LowPart == 0\n")); status = STATUS_UNSUCCESSFUL; goto close_handle; } len = mappedLen.LowPart; /* * If the address is in io space, just return the address, otherwise * go through the mapping mechanism */ if (inIoSpace) { *((PVOID *) ioBuf) = (PVOID) physicalAddrBase.LowPart; } else { /* * initialize view base that will receive the physical mapped * address after the MapViewOfSection call. */ viewBase = physicalAddrBase; /* * Let ZwMapViewOfSection pick an address */ virtualAddr = NULL; /* * Map the section */ status = ZwMapViewOfSection(physicalMemHandle, (HANDLE) -1, &virtualAddr, 0L, len, &viewBase, &len, ViewShare, 0, PAGE_READWRITE | PAGE_NOCACHE); if (!NT_SUCCESS(status)) { KdPrint(("SKELETON.SYS: ZwMapViewOfSection failed\n")); goto close_handle; } /* * Mapping the section above rounded the physical address down to the * nearest 64 K boundary. Now return a virtual address that sits where * we want by adding in the offset from the beginning of the section. */ (ULONG) virtualAddr += (ULONG)physicalAddrBase.LowPart - (ULONG)viewBase.LowPart; *((PVOID *) ioBuf) = virtualAddr; } status = STATUS_SUCCESS;close_handle: ZwClose(physicalMemHandle);done: return status;}/* *---------------------------------------------------------------------- * UnmapMemory -- * * Unmaps board's memory from the process's address space. * * Results: * STATUS_SUCCESS * STATUS_BUFFER_TOO_SMALL, *---------------------------------------------------------------------- */static NTSTATUS
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -