📄 pcidp.c
字号:
//*****************************************************************************
// THIS CODE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
// OR IMPLIED. THIS CODE IS LABELED "OPEN SOFTWARE" AND MAY BE FREELY USED,
// REPRODUCED, MODIFIED, AND/OR REDISTRIBUTED WITH THE STIPULATION THAT THIS
// NOTICE REMAIN INTACT. REDISTRIBUTION OF ANY KIND IMPLIES THAT ALL
// MODIFICATIONS FALL UNDER THIS "OPEN SOFTWARE" LABEL.
//
// Copyright (C) 2000, Foxen Solutions
// Copyright (C) 2000, FXN
//
// All Rights Reserved.
//*****************************************************************************
//
// ----------------------------------------------------------------------------
// This is PCIDP.c. It is the kernal mode driver for the PCI-DP CY7C09449PV-AC
// board.
//
// NOTE: Best viewed with Tabs set to 2.
// ----------------------------------------------------------------------------
// Issues to resolve are marked with **
// Include the appropriate header files.
#include "PCIDPInc.h"
#include "PCIDP.h"
// ----------------------------------------------------------------------------
// DriverEntry is the entry point for the PCIDP kernel mode driver. Windows NT
// calls this routine to initialize this driver.
// ----------------------------------------------------------------------------
NTSTATUS DriverEntry(
IN OUT PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
){
NTSTATUS NTStatus;
UNICODE_STRING ParamPath;
WCHAR ParamSubKey[] = L"\\Parameters";
WCHAR DeviceWin32Name[] = L"\\DosDevices\\PCIDP00";
UNICODE_STRING DeviceWin32NameUnicode;
WCHAR DeviceNTName[] = L"\\Device\\PCIDP00_CY7C09449PV";
UNICODE_STRING DeviceNTNameUnicode;
PDEVICE_OBJECT DeviceObject = NULL;
pPCIDP_EXTENSION ObjExt;
RTL_QUERY_REGISTRY_TABLE ParametersTable[3];
BOOLEAN FoundPCICard;
ULONG BusNumber;
ULONG PCIVendorIDDefault = 0x12BE;
ULONG PCIDeviceIDDefault = 0x3042;
ULONG PCIVendorID;
ULONG PCIDeviceID;
PCI_SLOT_NUMBER SlotNumber;
ULONG FunctionNumber;
ULONG DeviceNumber;
PCI_COMMON_CONFIG CardInfo;
ULONG InfoSize;
KIRQL PCIIrql;
KAFFINITY PCIAffinity;
PHYSICAL_ADDRESS BusAddress;
PHYSICAL_ADDRESS TranslatedAddress;
ULONG MappedVector;
ULONG AddressSpace;
ULONG IOBaseSize = 8;
USHORT BoardNumber;
BOOLEAN BoolStatus;
PHYSICAL_ADDRESS MaxAddress;
PHYSICAL_ADDRESS PhysicalAddress;
ULONG i;
// --------------------------------------------------------------------------
// Block 1: Start out by obtaining the PCI Vendor and Device IDs.
// --------------------------------------------------------------------------
// Allocate system space for the new registry path buffer.
ParamPath.MaximumLength = RegistryPath->Length + sizeof(ParamSubKey);
ParamPath.Length = ParamPath.MaximumLength;
ParamPath.Buffer = (unsigned short*)ExAllocatePool(
PagedPool,
ParamPath.Length
);
if (ParamPath.Buffer == NULL){
NTStatus = STATUS_NO_MEMORY;
goto Exit;
}
// Copy Registry Path to ParamPath
RtlCopyMemory(
ParamPath.Buffer,
RegistryPath->Buffer,
RegistryPath->Length
);
// Concatenate Sub Key to ParamPath
RtlCopyMemory(
&ParamPath.Buffer[RegistryPath->Length/2],
ParamSubKey,
sizeof(ParamSubKey)
);
//Initialize the parameters table with the vendor and device data.
RtlZeroMemory(&ParametersTable[0], sizeof(ParametersTable));
ParametersTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
ParametersTable[0].Name = L"PCIVendorID";
ParametersTable[0].EntryContext = &PCIVendorID;
ParametersTable[0].DefaultType = REG_DWORD;
ParametersTable[0].DefaultData = &PCIVendorIDDefault;
ParametersTable[0].DefaultLength = sizeof(PCIVendorID);
ParametersTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
ParametersTable[1].Name = L"PCIDeviceID";
ParametersTable[1].EntryContext = &PCIDeviceID;
ParametersTable[1].DefaultType = REG_DWORD;
ParametersTable[1].DefaultData = &PCIDeviceIDDefault;
ParametersTable[1].DefaultLength = sizeof(PCIDeviceID);
// Now get the registry data.
NTStatus = RtlQueryRegistryValues(
IN RTL_REGISTRY_ABSOLUTE,
IN ParamPath.Buffer,
IN OUT &ParametersTable[0],
IN NULL,
IN NULL
);
if(NTStatus != STATUS_SUCCESS)
goto ExitA;
// --------------------------------------------------------------------------
// Block 2: Locate each PCI board using the PCI Vendor and DeviceType IDs.
// Then initialize a driver device object for each board.
// --------------------------------------------------------------------------
BoardNumber = 0;
FoundPCICard = FALSE;
SlotNumber.u.bits.Reserved = 0;
// Loop BusNumber 0 - 3.
for(BusNumber = 0; BusNumber < 4; BusNumber++){
// Loop FunctionNumber 0 - 7.
for(FunctionNumber = 0; FunctionNumber < 8; FunctionNumber++){
SlotNumber.u.bits.FunctionNumber = FunctionNumber;
// Loop DeviceNumber 0 - 31.
for(DeviceNumber = 0; DeviceNumber < 32; DeviceNumber++){
SlotNumber.u.bits.DeviceNumber = DeviceNumber;
// Try to get the PCI Configuration space.
InfoSize = HalGetBusData(
IN PCIConfiguration,
IN BusNumber,
IN SlotNumber.u.AsULONG,
OUT (PVOID)&CardInfo,
IN (ULONG)(sizeof(CardInfo))
); // ID only
// Did we get any data?
if(InfoSize > 2){
// Check for valid device and vendor IDs.
if(CardInfo.VendorID == PCIVendorID &&
CardInfo.DeviceID == PCIDeviceID){
// We found a valid card. Create a device object for it.
DeviceNTName[14] = (USHORT) (0x30 + BoardNumber);
RtlInitUnicodeString(&DeviceNTNameUnicode, DeviceNTName);
NTStatus = IoCreateDevice(
IN DriverObject, // The driver object
IN sizeof(PCIDP_EXTENSION), // Size (bytes) of the device ext.
IN &DeviceNTNameUnicode, // The device name
IN FILE_DEVICE_PCIDP00, // The device type
IN 0, // Ignored by this device
IN FALSE, // Exclusive Device flag
OUT &DeviceObject // New created device object
);
if(NTStatus != STATUS_SUCCESS)
goto ExitA;
// Initialize the driver's extended object.
ObjExt = (pPCIDP_EXTENSION)DeviceObject->DeviceExtension;
RtlZeroMemory(ObjExt, sizeof(PCIDP_EXTENSION));
ObjExt->LLData.IsEmpty = TRUE;
ObjExt->LLData.CurrentLink = NULL;
ObjExt->LLData.InsertedCount = 0;
ObjExt->LLData.FreeMax = 0;
ObjExt->BusNumber = BusNumber;
ObjExt->SlotNumber = SlotNumber;
ObjExt->BoardNumber = BoardNumber;
ObjExt->BaseAddresses[0] = CardInfo.u.type0.BaseAddresses[0];
ObjExt->BaseAddresses[1] = CardInfo.u.type0.BaseAddresses[1];
ObjExt->BaseAddresses[2] = CardInfo.u.type0.BaseAddresses[2];
ObjExt->BaseAddresses[3] = CardInfo.u.type0.BaseAddresses[3];
ObjExt->BaseAddresses[4] = CardInfo.u.type0.BaseAddresses[4];
ObjExt->BaseAddresses[5] = CardInfo.u.type0.BaseAddresses[5];
//ObjExt->MemoryBase - initialized by MmMapIoSpace call
//ObjExt->IOBase - initialized by MmMapIoSpace call
//ObjExt->InterruptObject - initialized by IoConnectInterrupt call
//ObjExt->LListSpin - initialized by KeInitializeSpinLock call
// Translate the bus address for the memory space base address
// to the system logical address. Then map it into nonpaged
// system space. Save the result in device extended space for
// use with other services.
BusAddress.HighPart = 0;
BusAddress.LowPart = CardInfo.u.type0.BaseAddresses[0];
AddressSpace = 0; //address space is memory
BoolStatus = HalTranslateBusAddress(
IN PCIBus, //bus type
IN BusNumber, //bus number
IN BusAddress, //bus address
IN OUT &AddressSpace, //address space is Memory
OUT &TranslatedAddress //translated address
);
if(BoolStatus == FALSE){
NTStatus = STATUS_SOME_NOT_MAPPED;
goto ExitB;
}
if(AddressSpace == 0) //address space of 0 means map it
ObjExt->MemoryBase = (ULONG*)MmMapIoSpace(
IN TranslatedAddress, //address to map
IN MemoryBaseSize, //length in bytes
IN FALSE //memory cache
);
else
ObjExt->MemoryBase = (ULONG*)TranslatedAddress.LowPart;
// Save the I/O space base address for use with other services.
ObjExt->IOBase = (CardInfo.u.type0.BaseAddresses[1] & 0xFFFFFFFE);
// Create a symbolic link, i.e. a name that a Win32 app
// can specify to open the device.
DeviceWin32Name[18] = (USHORT) (0x30 + BoardNumber);
RtlInitUnicodeString(
IN &DeviceWin32NameUnicode,
IN DeviceWin32Name
);
NTStatus = IoCreateSymbolicLink(
IN &DeviceWin32NameUnicode,
IN &DeviceNTNameUnicode
);
if(NTStatus != STATUS_SUCCESS)
goto ExitB;
// Map the PCI board's IRQ to a system vector.
if((ULONG)CardInfo.u.type0.InterruptPin != 0){
MappedVector = HalGetInterruptVector(
IN PCIBus,
IN BusNumber,
IN (ULONG)CardInfo.u.type0.InterruptLine, //interrupt level
IN 0, //interrupt vector
OUT &PCIIrql,
OUT &PCIAffinity
);
// Connect the driver to the IRQ.
NTStatus = IoConnectInterrupt(
OUT &ObjExt->InterruptObject,
IN PCIDPISR, //pointer to ISR
IN DeviceObject, //context to send to ISR
IN NULL, //optional spinlock
IN MappedVector, //mapped interrupt vector
IN PCIIrql, //DIRQL
IN PCIIrql, //DIRQL
//IN Latched, //latched/level interrupt
IN LevelSensitive, //latched/level interrupt
IN TRUE, //shareable interrupt
IN PCIAffinity, //processor enable mask
IN FALSE //floating save (false for X86)
);
if(NTStatus != STATUS_SUCCESS)
goto ExitC;
// Register the PCIDPForDpcIsr routine with this device
// driver.
IoInitializeDpcRequest(
IN DeviceObject,
IN PCIDPForDpcIsr
);
// Set up the spin lock for the linked list holding pending IRPs.
KeInitializeSpinLock(&ObjExt->LListSpin);
}
// Otherwise, interrupts are not enabled on the board.
else
ObjExt->InterruptObject = 0;
// Allocate a contiguous span of memory for DMA usage.
MaxAddress.LowPart = 0xFFFFFFFF;
MaxAddress.HighPart = 0;
ObjExt->VirtualDMAAddress = MmAllocateContiguousMemory(
IN (ULONG)DMASize, //16K
IN MaxAddress //Full 32 bit address range
);
if(ObjExt->VirtualDMAAddress != NULL){
PhysicalAddress = MmGetPhysicalAddress(
ObjExt->VirtualDMAAddress
);
ObjExt->PhysicalDMAAddress = PhysicalAddress.LowPart;
ObjExt->MDL = IoAllocateMdl(
ObjExt->VirtualDMAAddress,
DMASize,
FALSE,
FALSE,
NULL
);
if(ObjExt->MDL){
MmBuildMdlForNonPagedPool(ObjExt->MDL);
MmProbeAndLockPages(
ObjExt->MDL,
KernelMode,
IoModifyAccess
);
}
}
else
ObjExt->PhysicalDMAAddress = 0;
// Reset interrupts and Initialize shared memory.
ObjExt->MemoryBase[HINT] = 0x3FF;
for(i=0x1000; i<0x2000; i++)
ObjExt->MemoryBase[i] = 0xCDCDCDCD;
FoundPCICard = TRUE;
BoardNumber++;
// Debug. Some object extension parameters.
//ObjExt->MemoryBase[0x1C40] = ObjExt->BoardNumber;
//ObjExt->MemoryBase[0x1C41] = ObjExt->BaseAddresses[0];
//ObjExt->MemoryBase[0x1C42] = ObjExt->BaseAddresses[1];
//ObjExt->MemoryBase[0x1C43] = (ULONG)ObjExt->MemoryBase;
//ObjExt->MemoryBase[0x1C44] = ObjExt->IOBase;
//ObjExt->MemoryBase[0x1C45] = (ULONG)ObjExt->VirtualDMAAddress;
//ObjExt->MemoryBase[0x1C46] = ObjExt->PhysicalDMAAddress;
//ObjExt->MemoryBase[0x1C47] = (ULONG)ObjExt->MDL;
//ObjExt->MemoryBase[0x1C48] = (ULONG)ObjExt->InterruptObject;
//ObjExt->MemoryBase[0x1C50] = 0; //IRQ entry count
//ObjExt->MemoryBase[0x1C51] = 0; //IRQ false alarm count
//ObjExt->MemoryBase[0x1C52] = 0; //IRQ DMAComplete int. count
//ObjExt->MemoryBase[0x1C53] = 0; //DPC entry count
//ObjExt->MemoryBase[0x1C54] = 0; //DPC queue not empty count
//ObjExt->MemoryBase[0x1C55] = 0; //DPC next entry count
//ObjExt->MemoryBase[0x1C56] = 0; //DPC type match count
//ObjExt->MemoryBase[0x1C57] = 0; //LL Inserted Count
//ObjExt->MemoryBase[0x1C58] = 0; //LL PutBack
//ObjExt->MemoryBase[0x1C59] = 0; //LL FreeUp
//ObjExt->MemoryBase[0x1C5A] = 0; //LL FreeMax
//ObjExt->MemoryBase[0x1C5B] = 0; //CMDR Entry
//ObjExt->MemoryBase[0x1C5C] = 0; //CMDR GetEntry Cnt
//ObjExt->MemoryBase[0x1C5D] = 0; //CMDR Unmap locked pages
//ObjExt->MemoryBase[0x1C5E] = 0; //CMD Entry
//ObjExt->MemoryBase[0x1C5F] = 0; //CMD LL Insert
//ObjExt->MemoryBase[0x1C60] = 0; //CMD Lin Addr
//ObjExt->MemoryBase[0x1C61] = 0; //DMAUnmap Entry
//ObjExt->MemoryBase[0x1C62] = 0; //DMAUnmap GetEntry Cnt
//ObjExt->MemoryBase[0x1C63] = 0; //DMAUnmap Finish IRP
//ObjExt->MemoryBase[0x1C64] = 0; //GetFreeEntry - Allocate pool
//ObjExt->MemoryBase[0x1C65] = 0; //GetFreeEntry - Existing entry
//ObjExt->MemoryBase[0x1C66] = 0; //Insert - First New
//ObjExt->MemoryBase[0x1C67] = 0; //Insert - Subsequent Nex
//ObjExt->MemoryBase[0x1C68] = 0; //Insert - Existing
}
}
}
}
}
if(FoundPCICard == FALSE){
NTStatus = STATUS_NO_SUCH_DEVICE;
goto ExitA;
}
// Report interrupt, port, and memory usage.
//NTStatus = ReportResources(DriverObject);
//if(NTStatus != STATUS_SUCCESS)
// goto ExitD;
// Initialize the driver object with this driver's entry points.
DriverObject->MajorFunction[IRP_MJ_CREATE] = PCIDPCreateClose;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = PCIDPCreateClose;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = PCIDPDeviceControl;
DriverObject->MajorFunction[IRP_MJ_CLEANUP] = PCIDPCleanup;
DriverObject->DriverUnload = (PDRIVER_UNLOAD)PCIDPUnload;
// All finished with a successful initialization. Set the status and return.
NTStatus = STATUS_SUCCESS;
goto ExitA;
// Exit points for errors found during initializaiton.
// Disconnect the driver from the interrupt and free up DMA memory.
ExitD:
IoFreeMdl(ObjExt->MDL);
MmFreeContiguousMemory(ObjExt->VirtualDMAAddress);
if(ObjExt->InterruptObject)
IoDisconnectInterrupt(ObjExt->InterruptObject);
// Delete the symbolic link.
ExitC:
IoDeleteSymbolicLink(&DeviceWin32NameUnicode);
// Delete the created device object and unmap physical memory.
ExitB:
IoDeleteDevice (DeviceObject);
MmUnmapIoSpace(ObjExt->MemoryBase, MemoryBaseSize);
// Free allocated pooled memory.
ExitA:
ExFreePool(ParamPath.Buffer);
// Final exit
Exit:
return NTStatus;
}
// ----------------------------------------------------------------------------
// PCIDPDeviceControl is called by the I/O system to perform a device I/O
// control function.
// ----------------------------------------------------------------------------
NTSTATUS PCIDPDeviceControl(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
){
PIO_STACK_LOCATION IrpStack;
PVOID IoBuffer;
ULONG InputBufferLength;
ULONG OutputBufferLength;
NTSTATUS NTStatus;
// Initialize the return values with some defaults.
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
// Get a pointer to the current location in the Irp. This is where
// the function codes and parameters are located.
IrpStack = IoGetCurrentIrpStackLocation(IN Irp);
// Get the pointer to the input/output buffer and it's length(s).
IoBuffer = Irp->AssociatedIrp.SystemBuffer;
InputBufferLength = IrpStack->Parameters.DeviceIoControl.InputBufferLength;
OutputBufferLength = IrpStack->Parameters.DeviceIoControl.OutputBufferLength;
// Determine which I/O control code was specified.
switch (IrpStack->Parameters.DeviceIoControl.IoControlCode){
case IOCTL_PCIDP00_MAP_BASE_REGS:
PCIDPMapBaseRegs(
IN DeviceObject,
IN OUT Irp,
IN OUT IoBuffer,
IN InputBufferLength,
IN OutputBufferLength
);
break;
case IOCTL_PCIDP00_UNMAP:
PCIDPUnMap(
IN DeviceObject,
IN OUT Irp,
IN IoBuffer,
IN InputBufferLength
);
break;
case IOCTL_PCIDP00_MAP_DMA_MEM:
PCIDPMapDMAMem(
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -