⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pcidppublic.c

📁 一个amccs5933芯片的驱动程序开发源程序和部分文档
💻 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 + -