📄 pcidpplugnplay.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 PCIDPPlugNPlay.c. It contains the dynamic loading functionality
// of the VxD as well as the Win32 interface to the services.
#pragma code_seg("_LTEXT") //match PCIDP assembly module code segment
#pragma data_seg("_LDATA") //match PCIDP assembly module data segment
#define _DECLARE_GLOBALS_
#include "PCIDPInc.h"
#undef _DECLARE_GLOBALS_
#include "Pci.h"
#include "pcidp.h"
unsigned long DeviceIocontrol(PDIOCPARAMETERS Params){
unsigned long ReturnStatus;
Params->lpcbBytesReturned = 0; //start out with no return data.
switch (Params->dwIoControlCode){
case DIOC_OPEN: //invoked when ring 3 calls CreateFile
ReturnStatus = 0; //success
break;
case DIOC_CLOSEHANDLE: //invoked with ring 3 calls CloseHandle
ReturnStatus = 0; //success
break;
case IOCTL_PCIDP00_MAP_BASE_REGS:
ReturnStatus = PCIDPMapBaseRegs(Params);
break;
case IOCTL_PCIDP00_UNMAP:
ReturnStatus = PCIDPUnMap(Params);
break;
case IOCTL_PCIDP00_MAP_DMA_MEM:
ReturnStatus = PCIDPMapDMAMem(Params);
break;
case IOCTL_PCIDP00_UNMAP_DMA:
ReturnStatus = PCIDPUnMapDMA(Params);
break;
case IOCTL_PCIDP00_GET_PCI_CONFIG_REGS:
ReturnStatus = PCIDPGetPCIRegs(Params);
break;
case IOCTL_PCIDP00_SET_PCI_CONFIG_REGS:
ReturnStatus = PCIDPSetPCIRegs(Params);
break;
case IOCTL_PCIDP00_REGISTER_INTERRUPT:
ReturnStatus = PCIDPRegisterInterrupt(Params);
break;
case IOCTL_PCIDP00_UNREGISTER_INTERRUPT:
ReturnStatus = PCIDPUnregisterInterrupt(Params);
break;
case IOCTL_PCIDP00_HELLO:
ReturnStatus = PCIDPHello(Params);
break;
case IOCTL_PCIDP00_GET_VERSION:
ReturnStatus = PCIDPGetDriverVersion(Params);
break;
default:
ReturnStatus = ERROR_INVALID_FUNCTION;
break;
}
return ReturnStatus;
}
unsigned long PnPNewDevice(
unsigned long Devnode,
unsigned long LoadType
){
unsigned long ReturnStatus = CR_OUT_OF_MEMORY;
int i;
PCI_COMMON_CONFIG CardInfo;
switch (LoadType){
// The VxD loader has a PCIDP board for the driver to bind with.
case DLVXD_LOAD_DRIVER:
// Loop until we a find an empty driver object extension.
for(i=0; i<BoardLimit; i++){
// Found one. Allocate some memory for the extension.
if(ObjExt[i] == 0){
ObjExt[i] = (PVOID)_HeapAllocate(sizeof(PCIDP_EXTENSION), HEAPZEROINIT);
if(ObjExt[i] == 0) break; //skip out if it fails
ObjExt[i]->Devnode = Devnode;
ObjExt[i]->LLData.IsEmpty = TRUE;
ObjExt[i]->LLData.CurrentLink = NULL;
ObjExt[i]->LLData.InsertedCount = 0;
ObjExt[i]->LLData.FreeMax = 0;
//ObjExt->InterruptObject - initialized in PnPStart
ReturnStatus = CM_Call_Enumerator_Function(
Devnode,
PCI_ENUM_FUNC_GET_DEVICE_INFO,
0,
&CardInfo,
sizeof(CardInfo),
0
);
if(ReturnStatus != CR_SUCCESS) break;
// Save some PCI configuration data in the device object extension
ObjExt[i]->BaseAddresses[0] = CardInfo.u.type0.BaseAddresses[0];
ObjExt[i]->BaseAddresses[1] = CardInfo.u.type0.BaseAddresses[1];
ObjExt[i]->BaseAddresses[2] = CardInfo.u.type0.BaseAddresses[2];
ObjExt[i]->BaseAddresses[3] = CardInfo.u.type0.BaseAddresses[3];
ObjExt[i]->BaseAddresses[4] = CardInfo.u.type0.BaseAddresses[4];
ObjExt[i]->BaseAddresses[5] = CardInfo.u.type0.BaseAddresses[5];
ObjExt[i]->IOBase = (CardInfo.u.type0.BaseAddresses[1] & 0xFFFFFFFE);
// Set up the IRQ resource.
if(CardInfo.u.type0.InterruptPin != 0){
ObjExt[i]->InterruptObject = 1; //interrupt is available to register
}
else
ObjExt[i]->InterruptObject = 0; //no interrupt available to register
// Now register this driver as the PnP handler for the PCIDP board.
ReturnStatus = CM_Register_Device_Driver(
Devnode,
PnPHandler,
(ULONG) ObjExt[i],
CM_REGISTER_DEVICE_DRIVER_DISABLEABLE |
CM_REGISTER_DEVICE_DRIVER_REMOVABLE
);
if(ReturnStatus != CR_SUCCESS) break;
// To get here means we were successful in the set up so break out.
break;
}
}
// The registration failed, deallocate the object extension and return
// empty handed.
if(ReturnStatus != CR_SUCCESS && ObjExt[i] != 0){
_HeapFree((PVOID)ObjExt[i], 0);
ObjExt[i] = 0;
}
break;
default:
ReturnStatus = CR_DEFAULT;
break;
}
return ReturnStatus;
}
CONFIGRET CM_HANDLER PnPHandler(
CONFIGFUNC Function,
SUBCONFIGFUNC SubFunction,
DEVNODE Devnode,
DWORD RefData,
ULONG Flags
){
CONFIGRET ReturnStatus;
switch (Function){
// Do not grant permission to invalidate or remove device node.
case CONFIG_TEST:
ReturnStatus = CR_FAILURE;
break;
// Accept whatever resources are provided.
case CONFIG_FILTER:
ReturnStatus = CR_SUCCESS;
break;
// There are no children to enumerate.
case CONFIG_ENUMERATE:
ReturnStatus = CR_SUCCESS;
break;
// Can't argue with this one, system shutting down.
case CONFIG_REMOVE:
ReturnStatus = PnPStop(Devnode);
break;
case CONFIG_START:
ReturnStatus = PnPStart(Devnode);
break;
// Shouldn't get this one, but if so same as a shutdown.
case CONFIG_STOP:
ReturnStatus = PnPStop(Devnode);
break;
// Any others (there shouldn't be).
default:
ReturnStatus = CR_DEFAULT;
}
return ReturnStatus;
}
CONFIGRET PnPStart(DEVNODE Devnode){
CONFIGRET ReturnStatus;
CMCONFIG Config;
unsigned long LinearAddress;
unsigned long PhysicalAddress;
VID IRQDesc;
int Node = FindIndex(Devnode);
if(Node == -1){
ReturnStatus = CR_INVALID_DEVNODE;
goto ExitPnpStart;
}
// Now get the allocated resources.
ReturnStatus = CM_Get_Alloc_Log_Conf(
&Config,
Devnode,
CM_GET_ALLOC_LOG_CONF_ALLOC
);
if(ReturnStatus != CR_SUCCESS)
goto ExitPnpStart;
// Map to the board's shared memory and register space for use
// within other services. No sense loading the driver if we
// can't map.
if(Config.wNumMemWindows == 0){
ReturnStatus = CR_OUT_OF_MEMORY;
goto ExitPnpStart;
}
LinearAddress = (unsigned long)_MapPhysToLinear(
Config.dMemBase[0],
Config.dMemLength[0],
0
);
if(LinearAddress == -1){
ObjExt[Node]->MemoryBase = 0;
ReturnStatus = CR_FAILURE;
goto ExitPnpStart;
}
else
ObjExt[Node]->MemoryBase = (unsigned long*)LinearAddress;
// Allocate 16K (4 pages) of contiguous memory for DMA operations.
// Failure to do so means the driver cannot support DMA transfers
// (which is reported to the user at the API level).
PhysicalAddress = _PageCommitContig(
0, //ignored since no linear address need be associated
4, //number of pages
PCC_NOLIN, //no linear address space associated with this memory
0, //4K alignment
0, //no address restrictions
-1 //no address restrictions
);
if(PhysicalAddress == -1)
PhysicalAddress = 0;
// Save the physical address for use with the Map DMA service.
ObjExt[Node]->PhysicalDMAAddress = PhysicalAddress;
// Register the interrupt.
if(ObjExt[Node]->InterruptObject == 1 && Config.wNumIRQs){
// Set up the structure to pass to VPICD_Virtualize_IRQ
IRQDesc.VID_IRQ_Number = Config.bIRQRegisters[0];
IRQDesc.VID_Options = VPICD_OPT_CAN_SHARE | VPICD_OPT_REF_DATA;
IRQDesc.VID_Hw_Int_Proc = (DWORD)PCIDPISR;
IRQDesc.VID_EOI_Proc = 0;
IRQDesc.VID_Virt_Int_Proc = 0;
IRQDesc.VID_Mask_Change_Proc = 0;
IRQDesc.VID_IRET_Proc = 0;
IRQDesc.VID_IRET_Time_Out = 500;
IRQDesc.VID_Hw_Int_Ref = (ULONG)ObjExt[Node];
// Now pass the structure to VPICD and get back the IRQ handle.
ObjExt[Node]->InterruptObject = VPICD_Virtualize_IRQ(&IRQDesc);
// Make sure the IRQ is unmasked on the PIC. Otherwise, the interrupt
// will never occur.
if(ObjExt[Node]->InterruptObject)
VPICD_Physically_Unmask(ObjExt[Node]->InterruptObject);
}
else
ObjExt[Node]->InterruptObject = 0;
ExitPnpStart:
return ReturnStatus;
}
CONFIGRET PnPStop(DEVNODE Devnode){
int i;
pREGISTERED_INTERRUPT RegisteredInt;
pLINKED_LIST CurrentLink;
pLINKED_LIST FirstLink;
unsigned long LinearAddress;
int Node = FindIndex(Devnode);
if(Node != -1){
// Close all ring 0 events.
CurrentLink = NULL;
FirstLink = NULL;
while(GetNextEntry(ObjExt[Node], &FirstLink, &CurrentLink, &RegisteredInt) == TRUE){
VWIN32_CloseVxDHandleW(RegisteredInt->Event);
PutBackEntry(ObjExt[Node], CurrentLink);
}
// Delete all allocated entries in the linked list.
DeleteAllEntries(ObjExt[Node]);
// Unvirtualize the IRQ.
if(ObjExt[Node]->InterruptObject)
VPICD_Force_Default_Behavior(ObjExt[Node]->InterruptObject);
// Deallocate the DMA space.
// Nothing to do. The space is allocated for the life of the system.
// Unmap from the board's shared memory and register space.
// Nothing to do. The linear address space is allocated for the life
// of the system.
// Lastly, deallocate the device object extension.
_HeapFree((PVOID)ObjExt[Node], 0);
ObjExt[Node] = 0;
}
return CR_SUCCESS;
}
unsigned long PCIDPISR_C(
unsigned long IRQHandle,
unsigned long HWRefData
){
unsigned long Status;
pPCIDP_EXTENSION ObjExt = (pPCIDP_EXTENSION)HWRefData;
pINTERRUPT_DATA IntData;
PULONG MemoryBase;
ULONG HINTStatusReg;
// Check the masked HINT for an active interrupt. If it's not set,
// the PCIDP card did not cause the interrupt, so exit quick.
MemoryBase = ObjExt->MemoryBase;
// Debug
//MemoryBase[0x1010]++;
HINTStatusReg = MemoryBase[HINT] & 0x03FF;
if(HINTStatusReg == 0){
// Debug
//MemoryBase[0x1011]++;
Status = 0;
goto ExitA;
}
// Initialize variables.
IntData = &ObjExt->InterruptData;
// This board caused the interrupt. Now determine what type of interrupt
// was triggered.
if(HINTStatusReg & PCIMasterAbort){
IntData->Type[IntData->QueNext] = PCIMasterAbort;
IntData->QueNext++;
if(IntData->QueNext == InterruptQueSize) IntData->QueNext = 0;
}
if(HINTStatusReg & PCITargetAbort){
IntData->Type[IntData->QueNext] = PCITargetAbort;
IntData->QueNext++;
if(IntData->QueNext == InterruptQueSize) IntData->QueNext = 0;
}
if(HINTStatusReg & I2OOutboundPostFIFONotEmpty){
IntData->Type[IntData->QueNext] = I2OOutboundPostFIFONotEmpty;
IntData->QueNext++;
if(IntData->QueNext == InterruptQueSize) IntData->QueNext = 0;
}
if(HINTStatusReg & DMAComplete){
IntData->Type[IntData->QueNext] = DMAComplete;
IntData->QueNext++;
if(IntData->QueNext == InterruptQueSize) IntData->QueNext = 0;
// Debug
//MemoryBase[0x1012]++;
}
if(HINTStatusReg & LocalToHostExternalSignal){
IntData->Type[IntData->QueNext] = LocalToHostExternalSignal;
IntData->QueNext++;
if(IntData->QueNext == InterruptQueSize) IntData->QueNext = 0;
}
if(HINTStatusReg & LocalToHostMailbox){
IntData->Type[IntData->QueNext] = LocalToHostMailbox;
IntData->QueNext++;
if(IntData->QueNext == InterruptQueSize) IntData->QueNext = 0;
}
if(HINTStatusReg & I2OPCIFIFOOverflow){
IntData->Type[IntData->QueNext] = I2OPCIFIFOOverflow;
IntData->QueNext++;
if(IntData->QueNext == InterruptQueSize) IntData->QueNext = 0;
}
// Clear all set interrupts as indicated in the status part of the
// HINT register while preserving the enabled part of the HINT. This
// is done by writing a 1 to each active bit which just happens to
// be value in HINTStatusReg.
MemoryBase[HINT] |= HINTStatusReg;
// Lastly, request the defered interrupt handler be queued for processing.
// This is done by setting Status to HWRefData (success) which tells PCIDPISR
// (the caller to this routine) to finish up the interrupt handling.
Status = HWRefData;
ExitA:
return Status;
}
void PCIDPForDpcIsr_C(unsigned long HWRefData){
pPCIDP_EXTENSION ObjExt = (pPCIDP_EXTENSION)HWRefData;
pINTERRUPT_DATA IntData;
pREGISTERED_INTERRUPT RegisteredInt;
pLINKED_LIST CurrentLink;
pLINKED_LIST FirstLink;
// Debug
//PULONG MemoryBase;
// Initialize variables.
IntData = &ObjExt->InterruptData;
CurrentLink = NULL;
FirstLink = NULL;
// Debug
//MemoryBase = ObjExt->MemoryBase;
//MemoryBase[0x1013]++;
//Service all of the recorded interrupts by checking to see if the interrupt
//type has been registered by the user.
while(IntData->QueNew != IntData->QueNext){
// Debug
//MemoryBase[0x1014]++;
while(GetNextEntry(ObjExt, &FirstLink, &CurrentLink, &RegisteredInt) == TRUE){
// Debug
//MemoryBase[0x1015]++;
if(IntData->Type[IntData->QueNew] == RegisteredInt->Type){
// Debug
//MemoryBase[0x1016]++;
// Found an entry. Have the event flag signaled.
VWIN32_SetWin32EventW(RegisteredInt->Event);
}
PutBackEntry(ObjExt, CurrentLink);
}
IntData->QueNew++;
if(IntData->QueNew == InterruptQueSize) IntData->QueNew = 0;
}
}
int FindIndex(DEVNODE Devnode){
int i;
for(i=0; i<BoardLimit; i++){
if(ObjExt[i] != 0){
if(ObjExt[i]->Devnode == Devnode)
break;
}
}
if(i<BoardLimit) return i;
else return -1;
}
#pragma code_seg()
#pragma data_seg()
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -