📄 pcidppublic.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 PCIDPPublic.c. It contains those PCIDP kernel routines published
// for use by an application using the IoDeviceControl system service.
#pragma code_seg("_LTEXT") //match PCIDP assembly module code segment
#pragma data_seg("_LDATA") //match PCIDP assembly module data segment
#include "PCIDPInc.h"
#include "Pci.h"
#include "PCIDP.h"
// ----------------------------------------------------------------------------
// PCIDPHello validates the board exists.
// ----------------------------------------------------------------------------
unsigned long PCIDPHello(PDIOCPARAMETERS Params){
pPCIDP00_HELLO_SEND IoInput;
// Initialize variables.
IoInput = (pPCIDP00_HELLO_SEND)Params->lpvInBuffer;
// Check for adequate buffer length.
if(Params->cbInBuffer < sizeof(PCIDP00_HELLO_SEND))
return ERROR_INSUFFICIENT_BUFFER;
// Check for the existence of the board in question.
if(ObjExt[IoInput->Devnode] == 0)
return ERROR_BAD_DEVICE;
else
return ERROR_SUCCESS;
}
// ----------------------------------------------------------------------------
// PCIDPGetDriverVersion returns the latest version number.
// ----------------------------------------------------------------------------
unsigned long PCIDPGetDriverVersion(PDIOCPARAMETERS Params){
pPCIDP00_GET_VERSION_SEND IoInput;
pPCIDP00_GET_VERSION_RECV IoOutput;
// Initialize variables.
IoInput = (pPCIDP00_GET_VERSION_SEND)Params->lpvInBuffer;
IoOutput = (pPCIDP00_GET_VERSION_RECV)Params->lpvOutBuffer;
// Check for adequate buffer length.
if(Params->cbInBuffer < sizeof(PCIDP00_HELLO_SEND))
return ERROR_INSUFFICIENT_BUFFER;
// Check for the existence of the board in question.
if(ObjExt[IoInput->Devnode] == 0)
return ERROR_BAD_DEVICE;
// Now return the version number.
IoOutput->Version = 0x20001101;
Params->lpcbBytesReturned = sizeof(PCIDP00_GET_VERSION_RECV);
return ERROR_SUCCESS;
}
// ----------------------------------------------------------------------------
// PDIDPMapBaseRegs
// ----------------------------------------------------------------------------
unsigned long PCIDPMapBaseRegs(PDIOCPARAMETERS Params){
unsigned long NTStatus;
pPCIDP00_MAP_BASE_REGS_SEND IoInput;
pPCIDP00_MAP_BASE_REGS_RECV IoOutput;
unsigned long LinearAddress;
unsigned long NumberOfPages;
int Node;
// Initialize variables.
IoInput = (pPCIDP00_MAP_BASE_REGS_SEND)Params->lpvInBuffer;
IoOutput = (pPCIDP00_MAP_BASE_REGS_RECV)Params->lpvOutBuffer;
// Make sure the buffer lengths are of sufficient size to handle
// the transactions.
if((Params->cbInBuffer < sizeof(PCIDP00_MAP_BASE_REGS_SEND)) ||
(Params->cbOutBuffer < sizeof(PCIDP00_MAP_BASE_REGS_RECV))){
return ERROR_INSUFFICIENT_BUFFER;
}
Node = IoInput->Devnode;
if(ObjExt[Node] == 0)
return ERROR_BAD_DEVICE;
// Check for a valid Base Address Register index.
if(IoInput->RegNumber > 5){
return ERROR_INVALID_DATA;
}
// Check that the base address register's value is non-zero.
if((ObjExt[Node]->BaseAddresses[IoInput->RegNumber] & 0xFFFFFFFE) == 0){
return ERROR_INVALID_ADDRESS;
}
// First check to see if the address is for I/O space. If it is, we
// can't map it. Just return the I/O Address so the application can
// use an I/O access driver to read and write from this space.
if((ObjExt[Node]->BaseAddresses[IoInput->RegNumber] & 1) == 1){
IoOutput->IOSpace = 1;
IoOutput->Length = IoInput->Length;
IoOutput->Address = ObjExt[Node]->BaseAddresses[IoInput->RegNumber] & 0xFFFFFFFE;
Params->lpcbBytesReturned = sizeof(PCIDP00_MAP_BASE_REGS_RECV);
return ERROR_SUCCESS;
}
// At this point, base address register contains an address to memory.
NumberOfPages = (IoInput->Length+4095) >> 12;
LinearAddress = _PageReserve(
PR_PRIVATE, //ring 3 access private areana
NumberOfPages, //size in 4K pages
0 //no flags
);
if(LinearAddress == -1)
return ERROR_NOACCESS;
NTStatus = _PageCommitPhys(
LinearAddress >> 12, //linear page number
NumberOfPages, //size in 4K pages
ObjExt[Node]->BaseAddresses[IoInput->RegNumber] >> 12, //physical page
PC_INCR | PC_USER | PC_WRITEABLE //flags
);
if(NTStatus == 0)
return ERROR_NOACCESS;
NTStatus = _LinPageLock(
LinearAddress >> 12, //linear page number
NumberOfPages, //size in 4K pages
0 //flags
);
if(NTStatus == 0)
return ERROR_NOACCESS;
IoOutput->Address = LinearAddress;
IoOutput->Length = IoInput->Length;
IoOutput->IOSpace = 0;
Params->lpcbBytesReturned = sizeof(PCIDP00_MAP_BASE_REGS_RECV);
return ERROR_SUCCESS;
}
// ----------------------------------------------------------------------------
// PCIDPUnMap unmaps a region of virtual memory from physical memory
// that was mapped earlier using the PCIDPMapBaseRegs routines.
// ----------------------------------------------------------------------------
unsigned long PCIDPUnMap(PDIOCPARAMETERS Params){
pPCIDP00_UNMAP_SEND IoInput;
int Node;
// Initialize variables.
IoInput = (pPCIDP00_UNMAP_SEND)Params->lpvInBuffer;
// Check for adequate buffer length.
if(Params->cbInBuffer < sizeof(PCIDP00_UNMAP_SEND))
return ERROR_INSUFFICIENT_BUFFER;
Node = IoInput->Devnode;
if(ObjExt[Node] == 0)
return ERROR_BAD_DEVICE;
_PageFree(
(PVOID)IoInput->Address,
0
);
return ERROR_SUCCESS;
}
// ----------------------------------------------------------------------------
// PDIDPMapDMAMem
// ----------------------------------------------------------------------------
unsigned long PCIDPMapDMAMem(PDIOCPARAMETERS Params){
unsigned long NTStatus;
pPCIDP00_MAP_DMA_MEM_SEND IoInput;
pPCIDP00_MAP_DMA_MEM_RECV IoOutput;
unsigned long LinearAddress;
int Node;
// Initialize variables.
IoInput = (pPCIDP00_MAP_DMA_MEM_SEND)Params->lpvInBuffer;
IoOutput = (pPCIDP00_MAP_DMA_MEM_RECV)Params->lpvOutBuffer;
// Make sure the buffer lengths are of sufficient size to handle
// the transactions.
if((Params->cbInBuffer < sizeof(PCIDP00_MAP_DMA_MEM_SEND)) ||
(Params->cbOutBuffer < sizeof(PCIDP00_MAP_DMA_MEM_RECV))){
return ERROR_INSUFFICIENT_BUFFER;
}
Node = IoInput->Devnode;
if(ObjExt[Node] == 0)
return ERROR_BAD_DEVICE;
// Map to the DMA address space if the driver was successful in allocating
// space at startup.
if(ObjExt[Node]->PhysicalDMAAddress == 0)
return ERROR_NOT_ENOUGH_MEMORY;
LinearAddress = _PageReserve(
PR_SHARED, //ring 3 access
4, //size in 4K pages
PR_FIXED //pages never move
);
if(LinearAddress == -1)
return ERROR_NOACCESS;
NTStatus = _PageCommitPhys(
LinearAddress >> 12, //linear page number
4, //size in 4K pages
ObjExt[Node]->PhysicalDMAAddress >> 12, //physical address
PC_INCR | PC_USER | PC_WRITEABLE //ring 3 access
);
if(NTStatus == 0)
return ERROR_NOACCESS;
IoOutput->LinearAddress = LinearAddress;
IoOutput->PhysicalAddress = ObjExt[Node]->PhysicalDMAAddress;
Params->lpcbBytesReturned = sizeof(PCIDP00_MAP_DMA_MEM_RECV);
return ERROR_SUCCESS;
}
// ----------------------------------------------------------------------------
// PDIDPUnMapDMA
// ----------------------------------------------------------------------------
unsigned long PCIDPUnMapDMA(PDIOCPARAMETERS Params){
pPCIDP00_UNMAP_DMA_SEND IoInput;
int Node;
// Initialize variables.
IoInput = (pPCIDP00_UNMAP_DMA_SEND)Params->lpvInBuffer;
// Check for adequate buffer length.
if(Params->cbInBuffer < sizeof(PCIDP00_UNMAP_DMA_SEND))
return ERROR_INSUFFICIENT_BUFFER;
Node = IoInput->Devnode;
if(ObjExt[Node] == 0)
return ERROR_BAD_DEVICE;
_PageFree(
(PVOID)IoInput->LinearAddress,
0
);
return ERROR_SUCCESS;
}
// ----------------------------------------------------------------------------
// PCIDPGetPCIRegs
// ----------------------------------------------------------------------------
unsigned long PCIDPGetPCIRegs(PDIOCPARAMETERS Params){
// Define variables.
pPCIDP00_GET_PCI_CONFIG_REGS_SEND IoInput;
pPCIDP00_GET_PCI_CONFIG_REGS_RECV IoOutput;
int Node;
unsigned long ReturnStatus;
// Initialize variables.
IoInput = (pPCIDP00_GET_PCI_CONFIG_REGS_SEND)Params->lpvInBuffer;
IoOutput = (pPCIDP00_GET_PCI_CONFIG_REGS_RECV)Params->lpvOutBuffer;
// Make sure the buffer lengths are of sufficient size to handle
// the transactions.
if((Params->cbInBuffer < sizeof(PCIDP00_GET_PCI_CONFIG_REGS_SEND)) ||
(Params->cbOutBuffer < sizeof(PCIDP00_GET_PCI_CONFIG_REGS_RECV))){
return ERROR_INSUFFICIENT_BUFFER;
}
Node = IoInput->Devnode;
if(ObjExt[Node] == 0)
return ERROR_BAD_DEVICE;
// Now get the PCI register space.
ReturnStatus = CM_Call_Enumerator_Function(
ObjExt[Node]->Devnode,
PCI_ENUM_FUNC_GET_DEVICE_INFO,
0,
(PVOID)IoOutput,
sizeof(PCIDP00_GET_PCI_CONFIG_REGS_RECV),
0
);
if(ReturnStatus != CR_SUCCESS)
return ERROR_ACCESS_DENIED;
Params->lpcbBytesReturned = sizeof(PCIDP00_GET_PCI_CONFIG_REGS_RECV);
return ERROR_SUCCESS;
}
// ----------------------------------------------------------------------------
// PCIDPSetPCIRegs
// ----------------------------------------------------------------------------
unsigned long PCIDPSetPCIRegs(PDIOCPARAMETERS Params){
// Define variables.
pPCIDP00_SET_PCI_CONFIG_REGS_SEND IoInput;
int Node;
unsigned long ReturnStatus;
// Initialize variables.
IoInput = (pPCIDP00_SET_PCI_CONFIG_REGS_SEND)Params->lpvInBuffer;
// Make sure the buffer length is of sufficient size to handle
// the transactions.
if(Params->cbInBuffer < sizeof(PCIDP00_SET_PCI_CONFIG_REGS_SEND))
return ERROR_INSUFFICIENT_BUFFER;
Node = IoInput->Devnode;
if(ObjExt[Node] == 0)
return ERROR_BAD_DEVICE;
// Now set the PCI register space.
ReturnStatus = CM_Call_Enumerator_Function(
ObjExt[Node]->Devnode,
PCI_ENUM_FUNC_SET_DEVICE_INFO,
0,
(PVOID)IoInput->PCIConfigRegs,
sizeof(PCIDP00_SET_PCI_CONFIG_REGS_SEND),
0
);
if(ReturnStatus != CR_SUCCESS)
return ERROR_ACCESS_DENIED;
return ERROR_SUCCESS;
}
// ----------------------------------------------------------------------------
// PCIDPRegisterInterrupt
// ----------------------------------------------------------------------------
unsigned long PCIDPRegisterInterrupt(PDIOCPARAMETERS Params){
// Define variables.
NTSTATUS NTStatus;
pPCIDP00_REGISTER_INTERRUPT_SEND IoInput;
PULONG MemoryBase;
int Node;
pLINKED_LIST LLEntry;
ULONG Type;
ULONG HINTPattern;
// Initialize variables.
IoInput = (pPCIDP00_REGISTER_INTERRUPT_SEND)Params->lpvInBuffer;
// Make sure the buffer length is of sufficient size to handle
// the transactions.
if(Params->cbInBuffer < sizeof(PCIDP00_REGISTER_INTERRUPT_SEND))
return ERROR_INSUFFICIENT_BUFFER;
Node = IoInput->Devnode;
if(ObjExt[Node] == 0)
return ERROR_BAD_DEVICE;
// Initialize variables.
MemoryBase = ObjExt[Node]->MemoryBase;
// Check that call was made via the PCIDP API.
if((IoInput->InterruptType & 0xF0C00000) != 0xF0C00000){
NTStatus = ERROR_ACCESS_DENIED;
goto ExitA;
}
Type = IoInput->InterruptType & 0x000003FF;
// Check to make sure the board has the interrupt pin enabled.
if(ObjExt[Node]->InterruptObject == 0){
NTStatus = ERROR_SERVICE_DISABLED;
goto ExitA;
}
// Check for a valid interrupt type.
switch(Type){
case PCIMasterAbort:
case PCITargetAbort:
case I2OOutboundPostFIFONotEmpty:
case DMAComplete:
case LocalToHostExternalSignal:
case LocalToHostMailbox:
case I2OPCIFIFOOverflow:
break;
default:
NTStatus = ERROR_INVALID_DATA;
goto ExitA;
}
// Get an empty linked list entry.
LLEntry = GetFreeEntry(ObjExt[Node]);
if(LLEntry != NULL){
// Add this event package to the linked list
LLEntry->RegisteredInterrupt.Event = IoInput->Event0;
LLEntry->RegisteredInterrupt.Type = Type;
InsertEntry(ObjExt[Node], LLEntry);
// Enable the interrupt on the board and clear the status bit.
HINTPattern = MemoryBase[HINT] & 0xFFFF0000; //get enabled ints
HINTPattern |= Type; //bit to clear status
HINTPattern |= (Type << 16); //bit to enable the interrupt
MemoryBase[HINT] = HINTPattern;
NTStatus = ERROR_SUCCESS;
}
else
NTStatus = ERROR_NOT_ENOUGH_MEMORY;
ExitA:
return NTStatus;
}
// ----------------------------------------------------------------------------
// PCIDPUnRegisterInterrupt
// ----------------------------------------------------------------------------
unsigned long PCIDPUnregisterInterrupt(PDIOCPARAMETERS Params){
pPCIDP00_UNREGISTER_INTERRUPT_SEND IoInput;
pREGISTERED_INTERRUPT RegisteredInt;
pLINKED_LIST CurrentLink;
pLINKED_LIST FirstLink;
PULONG MemoryBase;
ULONG Type;
unsigned long ReturnStatus;
int Count;
int Node;
// Initialize variables.
IoInput = (pPCIDP00_UNREGISTER_INTERRUPT_SEND)Params->lpvInBuffer;
// Make sure the buffer length is of sufficient size to handle
// the transactions.
if(Params->cbInBuffer < sizeof(PCIDP00_UNREGISTER_INTERRUPT_SEND))
return ERROR_INSUFFICIENT_BUFFER;
Node = IoInput->Devnode;
if(ObjExt[Node] == 0)
return ERROR_BAD_DEVICE;
MemoryBase = ObjExt[Node]->MemoryBase;
// Find the event, close it, and remove the linked list entry.
ReturnStatus = ERROR_INVALID_EVENTNAME;
CurrentLink = NULL;
FirstLink = NULL;
while(
GetNextEntry(
ObjExt[Node],
&FirstLink,
&CurrentLink,
&RegisteredInt
) == TRUE
){
if(RegisteredInt->Event == IoInput->Event0){
VWIN32_CloseVxDHandleW(RegisteredInt->Event);
FreeEntry(ObjExt[Node], CurrentLink);
ReturnStatus = ERROR_SUCCESS;
Type = RegisteredInt->Type;
break;
}
}
// Disable the interrupt type on the board if this is last instance
// of it.
if(ReturnStatus == ERROR_SUCCESS){
Count = 1;
CurrentLink = NULL;
FirstLink = NULL;
while(
GetNextEntry(
ObjExt[Node],
&FirstLink,
&CurrentLink,
&RegisteredInt
) == TRUE
){
if(RegisteredInt->Type == Type){
Count++;
}
}
if(Count == 1)
MemoryBase[HINT] &= (~Type) << 16;
}
return ReturnStatus;
}
#pragma code_seg()
#pragma data_seg()
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -