📄 spi.c
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this sample source code is subject to the terms of the Microsoft
// license agreement under which you licensed this sample source code. If
// you did not accept the terms of the license agreement, you are not
// authorized to use this sample source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the LICENSE.RTF on your install media or the root of your tools installation.
// THE SAMPLE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES.
//
//------------------------------------------------------------------------------
//
// File: spi.c
//
#include <windows.h>
#include <winuser.h>
#include <winuserm.h>
#include <pm.h>
#include <ceddk.h>
#include <ceddkex.h>
#include <spi.h>
#include <buses.h>
#include <omap2420.h>
//------------------------------------------------------------------------------
// Local Definitions
#define SPI_DEVICE_COOKIE 'spiD'
#define SPI_INSTANCE_COOKIE 'spiI'
//#undef DEBUGMSG
//#define DEBUGMSG(x, y) RETAILMSG(1,y)
extern DBGPARAM dpCurSettings;
//------------------------------------------------------------------------------
// Local Structures
typedef struct {
DWORD cookie;
DWORD memBase;
DWORD irq;
LONG instances;
HANDLE hParentBus;
OMAP3_MCSPI_REGS *pSPIRegs;
CRITICAL_SECTION cs;
DWORD sysIntr;
HANDLE hIntrEvent;
DWORD timeout;
CEDEVICE_POWER_STATE powerState;
} SPI_DEVICE;
typedef struct {
DWORD cookie;
SPI_DEVICE *pDevice;
DWORD address;
} SPI_INSTANCE;
//------------------------------------------------------------------------------
// Local Functions
BOOL SPI_Deinit(DWORD context);
BOOL SPI_SetSlaveAddress(DWORD context, DWORD address);
BOOL SPI_SetupMCSPI_Channel(OMAP3_MCSPI_REGS *pSPIRegs, DWORD address);
VOID SPI_ClockOn(SPI_DEVICE *pDevice);
VOID SPI_ClockOff(SPI_DEVICE *pDevice);
//------------------------------------------------------------------------------
// Global variables
const GUID DEVICE_IFC_SPI_GUID;
//------------------------------------------------------------------------------
// Device registry parameters
static const DEVICE_REGISTRY_PARAM g_deviceRegParams[] = {
{
L"MemBase", PARAM_DWORD, TRUE, offset(SPI_DEVICE, memBase),
fieldsize(SPI_DEVICE, memBase), NULL
}, {
L"Irq", PARAM_DWORD, TRUE, offset(SPI_DEVICE, irq),
fieldsize(SPI_DEVICE, irq), NULL
}, {
L"Timeout", PARAM_DWORD, FALSE, offset(SPI_DEVICE, timeout),
fieldsize(SPI_DEVICE, timeout), (VOID*)500
}
};
//------------------------------------------------------------------------------
//
// Function: SPI_Init
//
// Called by device manager to initialize device.
//
DWORD SPI_Init(LPCTSTR szContext, LPCVOID pBusContext)
{
DWORD rc = (DWORD)NULL;
SPI_DEVICE *pDevice = NULL;
PHYSICAL_ADDRESS pa;
DWORD dwCount=0;
DEBUGMSG(ZONE_INIT, (
L"+SPI_Init(%s, 0x%08x)\r\n", szContext, pBusContext
));
// Create device structure
pDevice = (SPI_DEVICE *)LocalAlloc(LPTR, sizeof(SPI_DEVICE));
if (pDevice == NULL) {
DEBUGMSG(ZONE_ERROR, (L"ERROR: SPI_Init: "
L"Failed allocate SPI controller structure\r\n"
));
goto cleanUp;
}
// Set cookie
pDevice->cookie = SPI_DEVICE_COOKIE;
// Initalize critical section
InitializeCriticalSection(&pDevice->cs);
// Read device parameters
if (GetDeviceRegistryParams(
szContext, pDevice, dimof(g_deviceRegParams), g_deviceRegParams
) != ERROR_SUCCESS) {
DEBUGMSG(ZONE_ERROR, (L"ERROR: SPI_Init: "
L"Failed read SPI driver registry parameters\r\n"
));
goto cleanUp;
}
// Open parent bus
pDevice->hParentBus = CreateBusAccessHandle(szContext);
if (pDevice->hParentBus == NULL) {
DEBUGMSG(ZONE_ERROR, (L"ERROR: SPI_Init: "
L"Failed open parent bus driver\r\n"
));
goto cleanUp;
}
// Set hardware to full power
pDevice->powerState = D0;
SPI_ClockOn(pDevice);
SetDevicePowerState(pDevice->hParentBus, D0, NULL);
// Map SPI controller
pa.QuadPart = pDevice->memBase;
pDevice->pSPIRegs = MmMapIoSpace(pa, sizeof(OMAP3_MCSPI_REGS), FALSE);
if (pDevice->pSPIRegs == NULL) {
DEBUGMSG(ZONE_ERROR, (L"ERROR: SPI_Init: "
L"Failed map SPI controller registers\r\n"
));
goto cleanUp;
}
// Map SPI interrupt
if (!KernelIoControl(
IOCTL_HAL_REQUEST_SYSINTR, &pDevice->irq, sizeof(pDevice->irq),
&pDevice->sysIntr, sizeof(pDevice->sysIntr), NULL
)) {
DEBUGMSG(ZONE_ERROR, (L"ERROR: SPI_Init: "
L"Failed map SPI controller interrupt\r\n"
));
goto cleanUp;
}
// Create interrupt event
pDevice->hIntrEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if (pDevice->hIntrEvent == NULL) {
DEBUGMSG(ZONE_ERROR, (L"ERROR: SPI_Init: "
L"Failed create interrupt event\r\n"
));
goto cleanUp;
}
// Initialize interrupt
if (!InterruptInitialize(pDevice->sysIntr, pDevice->hIntrEvent, NULL, 0)) {
DEBUGMSG (ZONE_ERROR, (L"ERROR: SPI_Init: "
L"InterruptInitialize failed\r\n"
));
goto cleanUp;
}
// Reset the SPI controller
SETREG32(&pDevice->pSPIRegs->ulMCSPI_SYSCONFIG, MCSPI_SYSCONFIG_SRST);
// TODO: Get base clock from kernel & read L/H periods from registry
// Wait until resetting is done
while ( !(INREG32(&pDevice->pSPIRegs->ulMCSPI_SYSSTATUS) & BIT0)) {
Sleep (1);
if (dwCount++>0x100)
{
// Break out dead lock, something is wrong.
ERRORMSG (TRUE, (TEXT("SPI: ERROR holding in reset.\n")));
goto cleanUp;
}
}
// Disable all interrupts.
OUTREG32(&pDevice->pSPIRegs->ulMCSPI_IRQENABLE, 0);
// Clear interrupts.
OUTREG32(&pDevice->pSPIRegs->ulMCSPI_IRQSTATUS, 0xFFFF);
// Setup Module Control as master
OUTREG32(&pDevice->pSPIRegs->ulMCSPI_MODULCTRL, 0);
// Turn on the clock on default 1M rate.
// Reset the SPI controller
SETREG32(&pDevice->pSPIRegs->ulMCSPI_SYSCONFIG, 0x308);
// g_pSpiRegs->ulSET1 &= ~0x001E;
// g_pSpiRegs->ulSET1 |= (GetClockParams(INIT_CLOCK_RATE) << 1);
// g_pSpiRegs->ulSET1 |= BIT0;
// Enable the SPI
// SETREG16(&pDevice->pSPIRegs->CON, SPI_CON_EN);
// Return non-null value
rc = (DWORD)pDevice;
// Set this driver to internal suspend mode
SetDevicePowerState(pDevice->hParentBus, pDevice->powerState = D4, NULL);
SPI_ClockOff(pDevice);
cleanUp:
if (rc == 0) SPI_Deinit((DWORD)pDevice);
DEBUGMSG(ZONE_INIT, (L"-SPI_Init(rc = %d)\r\n", rc));
return rc;
}
//------------------------------------------------------------------------------
//
// Function: SPI_Deinit
//
// Called by device manager to uninitialize device.
//
BOOL SPI_Deinit(DWORD context)
{
BOOL rc = FALSE;
SPI_DEVICE *pDevice = (SPI_DEVICE*)context;
DEBUGMSG(ZONE_INIT, (L"+SPI_Deinit(0x%08x)\r\n", context));
// Check if we get correct context
if (pDevice == NULL || pDevice->cookie != SPI_DEVICE_COOKIE) {
DEBUGMSG (ZONE_ERROR, (L"ERROR: SPI_Deinit: "
L"Incorrect context paramer\r\n"
));
goto cleanUp;
}
// Check for open instances
if (pDevice->instances > 0) {
DEBUGMSG (ZONE_ERROR, (L"ERROR: SPI_Deinit: "
L"Deinit with active instance (%d instances active)\r\n",
pDevice->instances
));
goto cleanUp;
}
// Set hardware to D4 and close parent bus driver
if (pDevice->hParentBus!= NULL)
{
SetDevicePowerState(pDevice->hParentBus, D4,NULL);
CloseBusAccessHandle(pDevice->hParentBus);
}
// Delete critical section
DeleteCriticalSection(&pDevice->cs);
// Unmap SPI controller registers
if (pDevice->pSPIRegs != NULL)
{
MmUnmapIoSpace((VOID*)pDevice->pSPIRegs, sizeof(OMAP3_MCSPI_REGS));
}
//Turn clocks off
SPI_ClockOff(pDevice);
// Release SPI controller interrupt
if (pDevice->sysIntr != 0)
{
InterruptDisable(pDevice->sysIntr);
KernelIoControl(
IOCTL_HAL_RELEASE_SYSINTR, &pDevice->sysIntr,
sizeof(pDevice->sysIntr), NULL, 0, NULL
);
}
// Close interrupt handler
if (pDevice->hIntrEvent != NULL) CloseHandle(pDevice->hIntrEvent);
// Free device structure
LocalFree(pDevice);
// Done
rc = TRUE;
cleanUp:
DEBUGMSG(ZONE_INIT, (L"-SPI_Deinit(rc = %d)\r\n", rc));
return rc;
}
//------------------------------------------------------------------------------
//
// Function: SPI_Open
//
// Called by device manager to open a device for reading and/or writing.
//
DWORD SPI_Open(DWORD context, DWORD accessCode, DWORD shareMode)
{
DWORD rc = (DWORD)NULL;
SPI_DEVICE *pDevice = (SPI_DEVICE*)context;
SPI_INSTANCE *pInstance = NULL;
DEBUGMSG(ZONE_FUNCTION, (
L"+SPI_Open(0x%08x, 0x%08x, 0x%08x\r\n", context, accessCode, shareMode
));
// Check if we get correct context
if (pDevice == NULL || pDevice->cookie != SPI_DEVICE_COOKIE) {
DEBUGMSG (ZONE_ERROR, (L"ERROR: SPI_Open: "
L"Incorrect context parameter\r\n"
));
goto cleanUp;
}
// Create device structure
pInstance = (SPI_INSTANCE*)LocalAlloc(LPTR, sizeof(SPI_INSTANCE));
if (pInstance == NULL) {
DEBUGMSG(ZONE_ERROR, (L"ERROR: SPI_Open: "
L"Failed allocate SPI instance structure\r\n"
));
goto cleanUp;
}
// Set cookie
pInstance->cookie = SPI_INSTANCE_COOKIE;
// Save device reference
pInstance->pDevice = pDevice;
// Increment number of open instances
InterlockedIncrement(&pDevice->instances);
// sanity check number of instances
ASSERT(pDevice->instances > 0);
// Done...
rc = (DWORD)pInstance;
cleanUp:
DEBUGMSG(ZONE_FUNCTION, (L"-SPI_Open(rc = 0x%08x)\r\n", rc));
return rc;
}
//------------------------------------------------------------------------------
//
// Function: SPI_Close
//
// This function closes the device context.
//
BOOL SPI_Close(DWORD context)
{
BOOL rc = FALSE;
SPI_DEVICE *pDevice;
SPI_INSTANCE *pInstance = (SPI_INSTANCE*)context;
DEBUGMSG(ZONE_FUNCTION, (L"+SPI_Close(0x%08x)\r\n", context));
// Check if we get correct context
if (pInstance == NULL || pInstance->cookie != SPI_INSTANCE_COOKIE) {
DEBUGMSG (ZONE_ERROR, (L"ERROR: SPI_Transfer: "
L"Incorrect context paramer\r\n"
));
goto cleanUp;
}
// Get device context
pDevice = pInstance->pDevice;
// sanity check number of instances
ASSERT(pDevice->instances > 0);
// Decrement number of open instances
InterlockedDecrement(&pDevice->instances);
// Free instance structure
LocalFree(pInstance);
// Done...
rc = TRUE;
cleanUp:
DEBUGMSG(ZONE_FUNCTION, (L"-SPI_Close(rc = %d)\r\n", rc));
return rc;
}
//------------------------------------------------------------------------------
//
// Function: SPI_Transfer
//
// This function reads data from the device identified by the open context.
//
DWORD SPI_Transfer(DWORD context, PVOID pBuffer)
{
DWORD rc = 0;
SPI_DEVICE *pDevice;
SPI_INSTANCE *pInstance = (SPI_INSTANCE*)context;
OMAP3_MCSPI_REGS *pSPIRegs;
UINT32* pData = (UINT32*)pBuffer;
DWORD dwCount;
// DEBUGMSG(ZONE_FUNCTION, ( L"+SPI_Transfer(0x%08x, 0x%08x\r\n", context, *pData));
// Check if we get correct context
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -