📄 cspiclass.cpp
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on
// your install media.
//
//------------------------------------------------------------------------------
//
// Copyright (C) 2004, Motorola Inc. All Rights Reserved
//
//------------------------------------------------------------------------------
//
// Copyright (C) 2004-2006, Freescale Semiconductor, Inc. All Rights Reserved.
// THIS SOURCE CODE, AND ITS USE AND DISTRIBUTION, IS SUBJECT TO THE TERMS
// AND CONDITIONS OF THE APPLICABLE LICENSE AGREEMENT
//
//------------------------------------------------------------------------------
//
// File: cspiClass.cpp
//
// Provides the implementation of the CSPI bus driver to support CSPI
// transactions from multiple client drivers.
//
//------------------------------------------------------------------------------
#include <windows.h>
#include <nkintr.h>
#include <ceddk.h>
#include <linklist.h>
#include <Devload.h>
#include "csp.h"
#include "cspibus.h"
#include "cspiClass.h"
//------------------------------------------------------------------------------
// External Functions
extern "C" UINT32 BSPCSPICalculateDivRate(UINT32 dwFrequency);
extern "C" BOOL BSPCSPISetIOMux(UINT32 Index);
extern "C" BOOL BSPCSPIReleaseIOMux(UINT32 dwIndex);
extern "C" BOOL BSPCSPIEnableClock(UINT32 dwIndex, BOOL bEnable);
//------------------------------------------------------------------------------
// External Variables
//------------------------------------------------------------------------------
// Defines
//------------------------------------------------------------------------------
// Types
//------------------------------------------------------------------------------
// Global Variables
//------------------------------------------------------------------------------
// Local Variables
//------------------------------------------------------------------------------
// Local Functions
//------------------------------------------------------------------------------
//
// Function: cspiClass
//
// The constructor of the class.
//
// Parameters:
// None.
//
// Returns:
// None.
//
//------------------------------------------------------------------------------
cspiClass::cspiClass()
{
DEBUGMSG(ZONE_INIT, (TEXT("cspiClass +\r\n")));
m_pCSPI = NULL;
m_cspiOpenCount = 0;
m_hIntrEvent = NULL;
m_hEnQEvent = NULL;
m_hThread = NULL;
m_hHeap = NULL;
m_dwSysIntr = SYSINTR_UNDEFINED;
m_bTerminate = FALSE;
m_bUsePolling = FALSE;
DEBUGMSG(ZONE_INIT, (TEXT("cspiClass -\r\n")));
}
//------------------------------------------------------------------------------
//
// Function: ~cspiClass
//
// The destructor of the class.
//
// Parameters:
// None.
//
// Returns:
// None.
//
//------------------------------------------------------------------------------
cspiClass::~cspiClass()
{
DEBUGMSG(ZONE_INIT, (TEXT("~cspiClass\r\n")));
}
//------------------------------------------------------------------------------
//
// Function: CspiInitialize
//
// Initializes the CSPI interface and data structures.
//
// Parameters:
// Index
// [in] CSPI instance (1 = CSPI1, 2 = CSP2) to initialize
//
// Returns:
// None.
//
//------------------------------------------------------------------------------
BOOL cspiClass::CspiInitialize(DWORD Index)
{
PHYSICAL_ADDRESS phyAddr;
DWORD irq;
m_nIndex = Index;
// Create global heap for internal queues/buffers
// flOptions = 0 => no options
// dwInitialSize = 0 => zero bytes initial size
// dwMaximumSize = 0 => heap size limited only by available memory
DEBUGMSG(ZONE_INIT, (TEXT("CspiInitialize: m_hHeap=0x%x\r\n"), m_hHeap));
m_hHeap = HeapCreate(0, 0, 0);
// Check if HeapCreate failed
if (m_hHeap == NULL) {
DEBUGMSG(ZONE_ERROR, (TEXT("CspiInitialize: HeapCreate failed!\r\n")));
goto Error;
}
// Create event for CSPI interrupt signaling
// pEventAttributes = NULL (must be NULL)
// bManualReset = FALSE => resets automatically to nonsignaled
// state after waiting thread released
// bInitialState = FALSE => initial state is non-signaled
// lpName = NULL => object created without a name
m_hIntrEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
// Check if CreateEvent failed
if (m_hIntrEvent == NULL) {
DEBUGMSG(ZONE_ERROR, (TEXT("CspiInitialize: CreateEvent failed!\r\n")));
goto Error;
}
// Create event for process queue thread signaling
// pEventAttributes = NULL (must be NULL)
// bManualReset = FALSE => resets automatically to nonsignaled
// state after waiting thread released
// bInitialState = FALSE => initial state is non-signaled
// lpName = NULL => object created without a name
m_hEnQEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
// Check if CreateEvent failed
if (m_hEnQEvent == NULL) {
DEBUGMSG(ZONE_ERROR, (TEXT("CspiInitialize: CreateEvent failed!\r\n")));
goto Error;
}
if (Index == 1) { // If request is for CSPI1
phyAddr.QuadPart = CSP_BASE_REG_PA_CSPI1;
irq = IRQ_CSPI1;
} else if (Index == 2) { // If request is for CSPI2
phyAddr.QuadPart = CSP_BASE_REG_PA_CSPI2;
irq = IRQ_CSPI2;
} else if (Index == 3) { // If request is for CSPI3
phyAddr.QuadPart = CSP_BASE_REG_PA_CSPI3;
irq = IRQ_CSPI3;
} else { // Else invalid CSPI instance
DEBUGMSG(ZONE_ERROR, (TEXT("CspiInitialize: Invalid CSPI instance!\r\n")));
goto Error;
}
// Configure IOMUX
BSPCSPISetIOMux(Index);
// Map peripheral physical address to virtual address
m_pCSPI = (PCSP_CSPI_REGS)MmMapIoSpace(phyAddr, sizeof(CSP_CSPI_REGS), FALSE);
// Check if virtual mapping failed
if (m_pCSPI == NULL) {
DEBUGMSG(ZONE_ERROR, (TEXT("CspiInitialize: MmMapIoSpace failed!\r\n")));
goto Error;
}
// Call the OAL to translate the IRQ into a SysIntr value.
if (!KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR, &irq, sizeof(DWORD),
&m_dwSysIntr, sizeof(DWORD), NULL)) {
RETAILMSG(1, (TEXT("ERROR: Failed to obtain sysintr value for CSPI interrupt.\r\n")));
goto Error;
}
// Register CSPI interrupt
if (!InterruptInitialize(m_dwSysIntr, m_hIntrEvent, NULL, 0)) {
DEBUGMSG(ZONE_ERROR, (TEXT("CspiInitialize: InterruptInitialize failed!\r\n")));
goto Error;
}
// Create CSPI critical section
InitializeCriticalSection(&m_cspiCs);
// Create CSPI Data Exchange critical section
InitializeCriticalSection(&m_cspiDataXchCs);
// Initialize CSPI linked list of client queue entries
InitializeListHead(&m_ListHead);
DEBUGMSG(ZONE_INIT, (TEXT("CspiInitialize: &m_pCSPI=0x%x\r\n"), &m_pCSPI));
// Disable CSPI to reset internal logic
INSREG32BF(&m_pCSPI->CONTROLREG, CSPI_CONTROLREG_SPIEN, CSPI_CONTROLREG_SPIEN_DISABLE);
// Create CSPI queue processing thread if it does not exist
if (!m_hThread) {
// Set global termination flag
m_bTerminate=FALSE;
// Create processing thread
// pThreadAttributes = NULL (must be NULL)
// dwStackSize = 0 => default stack size determined by linker
// lpStartAddress = CspiProcessQueue => thread entry point
// lpParameter = NULL => point to thread parameter
// dwCreationFlags = 0 => no flags
// lpThreadId = NULL => thread ID is not returned
m_hThread = ::CreateThread(NULL, 0, CspiProcessQueue, this, 0, NULL);
DEBUGMSG(ZONE_INIT, (TEXT("CspiInitialize: this=0x%x\r\n"),this));
// Check if CreateThread failed
if (m_hThread == NULL) {
DEBUGMSG(ZONE_ERROR, (TEXT("CspiInitialize: CreateThread failed!\r\n")));
goto Error;
}
}
m_cspiOpenCount++;
return TRUE;
Error:
CspiRelease();
return FALSE;
}
//------------------------------------------------------------------------------
//
// Function: CspiRelease
//
// Frees allocated memory, closes reference to handles, and resets the state
// of global member variables.
//
// Parameters:
// None.
//
// Returns:
// None.
//
//------------------------------------------------------------------------------
void cspiClass::CspiRelease()
{
DEBUGMSG(ZONE_CLOSE, (TEXT("CspiRelease +\r\n")));
// Kill the exchange packet processing thread
if (m_hThread) {
m_bTerminate = TRUE;
// Try to signal the thread so that it can wake up and terminate
if (m_hEnQEvent)
SetEvent(m_hEnQEvent);
CloseHandle(m_hThread);
m_hThread = NULL;
}
// Release IOMUX pins
BSPCSPIReleaseIOMux(m_nIndex);
// Release SYSINTR
KernelIoControl(IOCTL_HAL_RELEASE_SYSINTR, &m_dwSysIntr, sizeof(DWORD), NULL, 0, NULL);
m_dwSysIntr = SYSINTR_UNDEFINED;
// Destroy the heap
if (m_hHeap != NULL) {
HeapDestroy(m_hHeap);
m_hHeap = NULL;
}
// Close interrupt event handle
if (m_hIntrEvent) {
CloseHandle(m_hIntrEvent);
m_hIntrEvent = NULL;
}
// Close enqueue event handle
if (m_hEnQEvent) {
CloseHandle(m_hEnQEvent);
m_hEnQEvent = NULL;
}
// Free the virtual space allocated for CSPI memory map
if (m_pCSPI != NULL) {
MmUnmapIoSpace(m_pCSPI, sizeof(CSP_CSPI_REGS));
m_pCSPI = NULL;
}
// Deregister the system interrupt
if (m_dwSysIntr != SYSINTR_UNDEFINED) {
InterruptDisable(m_dwSysIntr);
m_dwSysIntr = SYSINTR_UNDEFINED;
}
// Delete the critical section
DeleteCriticalSection(&m_cspiCs);
// Delete the Data Exchange critical section
DeleteCriticalSection(&m_cspiDataXchCs);
DEBUGMSG(ZONE_CLOSE, (TEXT("CspiRelease -\r\n")));
return;
}
//------------------------------------------------------------------------------
//
// Function: CspiEnqueue
//
// This function is invoked as a result of a CSPI client driver calling
// the CSPI DeviceIoControl with CSPI_IOCTL_EXCHANGE. This function
//
// Parameters:
// pData
// [in]
//
// Returns:
// Returns a handle to the newly created msg queue, or NULL if the
// msg queue creation failed.
//
//------------------------------------------------------------------------------
BOOL cspiClass::CspiEnqueue(PCSPI_XCH_PKT_T pXchPkt)
{
PCSPI_XCH_LIST_ENTRY_T pXchListEntry = NULL;
PCSPI_XCH_PKT_T pMappedXchPtr;
DEBUGMSG(ZONE_FUNCTION, (TEXT("CspiEnqueue +\r\n")));
// Allocate space for new list entry
pXchListEntry = (PCSPI_XCH_LIST_ENTRY_T)HeapAlloc(m_hHeap, HEAP_ZERO_MEMORY,
sizeof(CSPI_XCH_LIST_ENTRY_T));
// Check if HeapAlloc failed (fatal error, terminate thread)
if (pXchListEntry == NULL) {
DEBUGMSG(ZONE_ERROR, (TEXT("CspiProcessQueue: HeapAlloc failed!\r\n")));
return FALSE;
}
// Map caller exchange packet pointer to our process space
#if 0 //CE5
pMappedXchPtr = (PCSPI_XCH_PKT_T)MapCallerPtr(pXchPkt,
sizeof(CSPI_XCH_PKT_T));
// Now we can dereference the mapped pointer and map other caller pointers
pXchListEntry->xchPkt.pBusCnfg = (PCSPI_BUSCONFIG_T)MapCallerPtr(
pMappedXchPtr->pBusCnfg, sizeof(CSPI_BUSCONFIG_T));
pXchListEntry->xchPkt.pTxBuf = (LPVOID) MapCallerPtr(
pMappedXchPtr->pTxBuf, pMappedXchPtr->xchCnt);
pXchListEntry->xchPkt.pRxBuf = (LPVOID) MapCallerPtr(
pMappedXchPtr->pRxBuf, pMappedXchPtr->xchCnt);
#else //CE6 directly
pMappedXchPtr = (PCSPI_XCH_PKT_T)pXchPkt;
// Now we can dereference the mapped pointer and map other caller pointers
pXchListEntry->xchPkt.pBusCnfg = (PCSPI_BUSCONFIG_T)pMappedXchPtr->pBusCnfg;
pXchListEntry->xchPkt.pTxBuf = (LPVOID) pMappedXchPtr->pTxBuf;
pXchListEntry->xchPkt.pRxBuf = (LPVOID) pMappedXchPtr->pRxBuf;
#endif
pXchListEntry->xchPkt.xchCnt = pMappedXchPtr->xchCnt;
pXchListEntry->xchPkt.xchEvent = pMappedXchPtr->xchEvent;
// Check whether the completion event is NULL
// If it's NULL, then send the package immediately
if (pXchListEntry->xchPkt.xchEvent == NULL) {
DEBUGMSG(ZONE_FUNCTION, (TEXT("CspiEnqueue: Sending the package immediately\r\n")));
// Wrap the exchange in critical section to
// serialize accesses with CspiProcessQueue thread
EnterCriticalSection(&m_cspiDataXchCs);
pXchListEntry->xchPkt.xchCnt = CspiDataExchange(&pXchListEntry->xchPkt);
LeaveCriticalSection(&m_cspiDataXchCs);
return TRUE;
}
// Wrap linked list insert operation in critical section to
// serialize accesses with CspiProcessQueue thread
EnterCriticalSection(&m_cspiCs);
// Insert exchange packet into our list
InsertTailList(&m_ListHead, &(pXchListEntry->link));
LeaveCriticalSection(&m_cspiCs);
DEBUGMSG(ZONE_FUNCTION, (TEXT("CspiEnqueue -\r\n")));
// Signal queue processing thread that a new packet is ready
return SetEvent(m_hEnQEvent);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -