📄 pl011pdd.c
字号:
/*
* The content of this file or document is CONFIDENTIAL and PROPRIETARY
* to Jade Technologies Co., Ltd. It is subjected to the terms of a
* License Agreement between Licensee and Jade Technologies Co., Ltd.
* restricting among other things, the use, reproduction, distribution
* and transfer. Each of the embodiments, including this information
* and any derivative work shall retain this copyright notice.
*
* Copyright (c) 2004 - 2005 Jade Technologies Co., Ltd.
* All rights reserved.
*/
// ----------------------------------------------------------------
// File: PL011pdd.c,v
// Revision: 1.2
// ----------------------------------------------------------------
// $
//
// NOTE:
// This code contains code to support DMA. This is untested
// and is left here as an example only.
//
#include <windows.h> // Main include file for Windows development
#include <ceddk.h> // CE device driver types, constants, and functions
#include <devload.h> // Device loader structures and defines (OpenDeviceKey API)
#include <serhw.h> // Hardware-independent structures, defines and interfaces (HW_VTBL, HWOBJ)
#include <serdbg.h> // Serial device driver debug zone definitions
#include <dma.h>
#include <platform.h>
#include <board.h>
#include <oalintr.h>
#include "PL011api.h" // PL011 UART API
#include "PL011.h" // PL011 UART register and bit definitions
// Watermark info
const PTCHAR part_name = { TEXT("Windows CE UART Device Driver") };
const PTCHAR part_num = { TEXT("OS005-SW-70002-r0p0-00REL0") };
// PL011 serial device driver registry value names (all DWORDs)
//
#define REG_DEVINDEX_VAL_NAME TEXT("DeviceArrayIndex")
#define REG_IOBASE_VAL_NAME TEXT("IoBase")
#define REG_SYSINTR_VAL_NAME TEXT("SysIntr")
#define REG_DMA_VAL_NAME TEXT("DMA")
#define REG_COM_ID TEXT("Order")
// DEBUGMSG helper macros
//
#define DRV_PREFIX TEXT("COM")
#define MSG_PREFIX TEXT(" ") DRV_PREFIX TEXT(": ")
#define MSG_SUFFIX TEXT("\r\n")
#define HEAD_TEXT(msg) (MSG_PREFIX TEXT("+") TEXT(##msg) MSG_SUFFIX)
#define BODY_TEXT(msg) (MSG_PREFIX TEXT(" ") TEXT(##msg) MSG_SUFFIX)
#define TAIL_TEXT(msg) (MSG_PREFIX TEXT("-") TEXT(##msg) MSG_SUFFIX)
#define SUCCEEDED_OR_FAILED(exp) ((exp) ? TEXT("SUCCEEDED") : TEXT("FAILED"))
#ifndef MIN
#define MIN(x,y) ((x) < (y) ? (x) : (y))
#endif
// Types
// Serial event callback type
//
typedef VOID (*EVENT_FUNC)(VOID *pMDDContext, ULONG fEvents);
//UART DMA struct
typedef struct tagUART_DMAInfo {
DWORD OpenCnt; // @field Protects use of this port
//Rx
HANDLE hRxUDmaISTEvent;
DWORD dwRxDMASysIntr;
UCHAR ucRxDMAChannel;
PDWORD pdwRxDestPageList;
PVOID pvRxDestBuffer;
DWORD dwRxDestSize;
//Tx
HANDLE hTxUDmaISTEvent;
DWORD dwTxDMASysIntr;
UCHAR ucTxDMAChannel;
PDWORD pdwTxSourcePageList;
PVOID pvTxSourceBuffer;
DWORD dwTxSourceSize;
}UART_DMA_INFO, *PUART_DMA_INFO;
//End of UART DMA struct
//UART ID to connect to DMA
#define UART0_Rx_ID 5
#define UART0_Tx_ID 6
#define UART1_Rx_ID 3
#define UART1_Tx_ID 4
//UART Rx FIFO Watermark
#define UART_FIFO_Rx_LEVEL 12
// PDD context type
//
typedef struct tagPDD_CONTEXT
{
VOID *pMDDContext; // First argument in MDD callbacks.
HWOBJ *pHWObj; // The MDD doesn't free the HWOBJ, we have to
PL011_CONTEXT *pPL011; // PL011 (UART) context (for PL011 API)
PUCHAR pBaseAddress; // Start of serial registers - mapped
HANDLE hevTxReady; // Event object for signalling transmitter ready / not full
CRITICAL_SECTION cs; // For using this context, thread-safely
ULONG nOpenCount; // Just for debug checks (the MDD manages concurrent opens)
BOOL fIRMode; // IR mode (FALSE or TRUE)
COMMPROP CommProp; // COMMPROP (Comm Properties) structure
DCB dcb; // DCB (Device Control Block) structure
ULONG fCommErrors; // Comm error flags
ULONG fInterrupts; // Shadowed interrupt flags, updated by HWGetIntrType
ULONG fModemStatus; // Modem status flags, updated by HWModemIntrHandler
ULONG nDroppedBytes; // Number of dropped bytes
BOOL fCTSFlowOff; // CTS flow control state (flowed-off | not flowed-off)
BOOL fDSRFlowOff; // DSR flow control state (flowed-off | not flowed-off)
BOOL fAddTxIntr; // Force HWGetIntrType to return an INTR_TX
//DMA related members.
UART_DMA_INFO uart_DMA_Info; // struct to store UART-DMA related information
DWORD DMA_Enable; // DMA_UART ON or OFF
DWORD ComId; // which com port is used, 0 or 1?
BOOL No_DMA_timeout; // If timeout happens to Rx, disable DMA
} PDD_CONTEXT;
// Public function prototypes (external linkage, called by MDD)
// GetSerialObject is the only function that needs external linkage; it's used in the MDD to get
// a device-independent function-table for serial port device driver PDDs.
//
PHWOBJ GetSerialObject(DWORD DeviceArrayIndex);
// Define some internally used functions
BOOL DMA_Close(PUART_DMA_INFO pOpenHead);
// Private DDSI function prototypes (static linkage)
// These functions are private to the PDD and are invoked by the MDD through a function table (in
// the HWOBJ returned from GetSerialObject).
//
static PVOID PDD_Init(ULONG Identifier, PVOID pMDDContext, PHWOBJ pHWObj);
static BOOL PDD_PostInit(PDD_CONTEXT *pPDDContext);
static BOOL PDD_Deinit(PDD_CONTEXT *pPDDContext);
static BOOL PDD_Open(PDD_CONTEXT *pPDDContext);
static ULONG PDD_Close(PDD_CONTEXT *pPDDContext);
static INTERRUPT_TYPE PDD_GetIntrType(PDD_CONTEXT *pPDDContext);
static ULONG PDD_RxIntrHandler(PDD_CONTEXT *pPDDContext, PUCHAR pRxBuffer, ULONG *pBuffLen);
static VOID PDD_TxIntrHandler(PDD_CONTEXT *pPDDContext, PUCHAR pTxBuffer, ULONG *pBuffLen);
static VOID PDD_ModemIntrHandler(PDD_CONTEXT *pPDDContext);
static VOID PDD_LineIntrHandler(PDD_CONTEXT *pPDDContext);
static ULONG PDD_GetRxBufferSize(PDD_CONTEXT *pPDDContext);
static BOOL PDD_PowerOff(PDD_CONTEXT *pPDDContext);
static BOOL PDD_PowerOn(PDD_CONTEXT *pPDDContext);
static VOID PDD_ClearDTR(PDD_CONTEXT *pPDDContext);
static VOID PDD_SetDTR(PDD_CONTEXT *pPDDContext);
static VOID PDD_ClearRTS(PDD_CONTEXT *pPDDContext);
static VOID PDD_SetRTS(PDD_CONTEXT *pPDDContext);
static BOOL PDD_EnableIR(PDD_CONTEXT *pPDDContext, ULONG BaudRate);
static BOOL PDD_DisableIR(PDD_CONTEXT *pPDDContext);
static VOID PDD_ClearBreak(PDD_CONTEXT *pPDDContext);
static VOID PDD_SetBreak(PDD_CONTEXT *pPDDContext);
static BOOL PDD_XmitComChar(PDD_CONTEXT *pPDDContext, UCHAR ComChar);
static ULONG PDD_GetStatus(PDD_CONTEXT *pPDDContext, LPCOMSTAT lpStat);
static VOID PDD_Reset(PDD_CONTEXT *pPDDContext);
static VOID PDD_GetModemStatus(PDD_CONTEXT *pPDDContext, PULONG pModemStatus);
static VOID PDD_GetCommProperties(PDD_CONTEXT *pPDDContext, LPCOMMPROP lpCommProp);
static VOID PDD_PurgeComm(PDD_CONTEXT *pPDDContext, DWORD fdwAction);
static BOOL PDD_SetDCB(PDD_CONTEXT *pPDDContext, LPDCB lpDCB);
static ULONG PDD_SetCommTimeouts(PDD_CONTEXT *pPDDContext, LPCOMMTIMEOUTS lpCommTimeouts);
static BOOL PDD_Ioctl(PDD_CONTEXT *pPDDContext,
DWORD dwCode,
PBYTE pBufIn,
DWORD dwLenIn,
PBYTE pBufOut,
DWORD dwLenOut,
PDWORD pdwActualOut);
// Private, implementation, function prototypes
//
static BOOL ProcessLineStatus(PDD_CONTEXT *pPDDContext, ULONG fLineStatus);
static LONG GetRegistryData(LPCTSTR szKey, DWORD *pdwIOBase, DWORD *pdwSysIntr, DWORD *ComId, DWORD *DMA_Enable);
// Inline helpers
//
__inline static LONG GetRegistryDWORD(HKEY hKey, LPCTSTR szValueName, DWORD *pdwValue)
{
DWORD dwDataSize = sizeof(DWORD);
return RegQueryValueEx(hKey,
szValueName,
NULL,
NULL,
(LPBYTE)pdwValue,
&dwDataSize);
}
// Virtual-function table (DDSI) for serial port PDD (used by serial MDD)
//
static const HW_VTBL VTbl =
{
PDD_Init,
PDD_PostInit,
PDD_Deinit,
PDD_Open,
PDD_Close,
PDD_GetIntrType,
PDD_RxIntrHandler,
PDD_TxIntrHandler,
PDD_ModemIntrHandler,
PDD_LineIntrHandler,
PDD_GetRxBufferSize,
PDD_PowerOff,
PDD_PowerOn,
PDD_ClearDTR,
PDD_SetDTR,
PDD_ClearRTS,
PDD_SetRTS,
PDD_EnableIR,
PDD_DisableIR,
PDD_ClearBreak,
PDD_SetBreak,
PDD_XmitComChar,
PDD_GetStatus,
PDD_Reset,
PDD_GetModemStatus,
PDD_GetCommProperties,
PDD_PurgeComm,
PDD_SetDCB,
PDD_SetCommTimeouts,
PDD_Ioctl
};
// The MDD calls GetSerialObject to get a device-independent function table, filled with device-
// dependent function pointers; this enables a single MDD to be used for different PDDs.
//
PHWOBJ GetSerialObject(DWORD DeviceArrayIndex)
{
HWOBJ *pSerObj;
// Unlike many other serial samples, we do not have a statically allocated array of HWObjs.
// Instead, we allocate a new HWObj for each instance of the driver. The MDD will always call
// GetSerialObject/HWInit/HWDeinit in that order, so we can do the alloc here and do any
// subsequent free in HWDeInit.
// Allocate space for the HWOBJ (no need to use LPTR or LMEM_ZEROINIT to initialise the memory
// to zero because we will be explicitly initialising each member of the open context next).
//
pSerObj = (HWOBJ*)LocalAlloc(LMEM_FIXED , sizeof(HWOBJ));
if (pSerObj == NULL)
return NULL;
// Fill in the HWObj structure that we just allocated.
//
if ( DeviceArrayIndex == 0 )
{
pSerObj->BindFlags = THREAD_AT_OPEN; // Have MDD create thread when device is first opened
pSerObj->dwIntID = SYSINTR_UNDEFINED; // HWInit sets this field with the actual SYSINTR value
pSerObj->pFuncTbl = (HW_VTBL*)&VTbl; // Return pointer to appropriate functions
}
else if ( DeviceArrayIndex == 1 )
{
pSerObj->BindFlags = THREAD_AT_OPEN; // Have MDD create thread when device is first opened
pSerObj->dwIntID = SYSINTR_UNDEFINED; // HWInit sets this field with the actual SYSINTR value
pSerObj->pFuncTbl = (HW_VTBL*)&VTbl; // Return pointer to appropriate functions
}
// Now return this structure to the MDD.
//
return pSerObj;
}
PVOID PDD_Init(ULONG Identifier, PVOID pMDDContext, PHWOBJ pHWObj)
{
PDD_CONTEXT *pPDDContext = NULL;
LONG lRC;
DWORD dwIOBase;
LPVOID pBaseAddr;
DEBUGMSG(ZONE_INIT | ZONE_FUNCTION,
(HEAD_TEXT("PDD_Init(\"%s\", %#08x, %#08x)"), (LPCTSTR)Identifier, pMDDContext, pHWObj));
DEBUGMSG( TRUE, (TEXT("MODULE NAME: %s\r\n"),part_name) );
DEBUGMSG( TRUE, (TEXT("MODULE VERSION: %s\r\n"),part_num) );
RETAILMSG( TRUE, (TEXT("MODULE NAME: %s\r\n"),part_name) );
{
//pin mux
PHYSICAL_ADDRESS PhysicalIoBase;
volatile unsigned long *GPIO_ADD;
PhysicalIoBase.HighPart = 0;
PhysicalIoBase.LowPart = 0x2002B420;
GPIO_ADD = (unsigned long *)MmMapIoSpace( PhysicalIoBase, 0x100 ,FALSE );
RETAILMSG(0,(TEXT("GPIO_ADD = 0x%x\r\n"),GPIO_ADD));
*(volatile long *)GPIO_ADD |= 0xF0;
}
if ((Identifier == 0) || (pMDDContext == NULL) || (pHWObj == NULL))
goto exit_point;
// Allocate space for the PDD context (using LMEM_ZEROINIT will ensure Deinit doesn't mistake
// any uninitialised members for valid objects, should Init fail)
//
pPDDContext = (PDD_CONTEXT*)LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, sizeof(PDD_CONTEXT));
if (pPDDContext == NULL)
goto exit_point;
pPDDContext->pMDDContext = pMDDContext;
pPDDContext->pHWObj = pHWObj;
pPDDContext->pBaseAddress = NULL;
if ((lRC = GetRegistryData((LPCTSTR)Identifier, &dwIOBase, &pHWObj->dwIntID,
&pPDDContext->ComId, &pPDDContext->DMA_Enable)) != ERROR_SUCCESS)
{
DEBUGMSG(ZONE_INIT | ZONE_ERROR,
(BODY_TEXT("PDD_Init: Failed to get registry data [error = %d]"), lRC));
goto fail_point;
}
// New for .NET we need to VirtualAlloc/VirtualCopy the IO addresses as the system
// protection has increased - we can't use just the OEMAddressTable mappings
if (!(pBaseAddr = VirtualAlloc (NULL, 0x1000, MEM_RESERVE, PAGE_NOACCESS)))
{
DEBUGMSG(ZONE_INIT | ZONE_ERROR, (BODY_TEXT("PDD_Init: VirtualAlloc Failed")));
goto fail_point;
}
if (!VirtualCopy (pBaseAddr, (LPVOID)dwIOBase, 0x1000, PAGE_READWRITE | PAGE_NOCACHE))
{
DEBUGMSG(ZONE_INIT | ZONE_ERROR, (BODY_TEXT("PDD_Init: VirtualCopy Failed")));
VirtualFree (pBaseAddr, 0, MEM_RELEASE);
goto fail_point;
}
pPDDContext->pBaseAddress = pBaseAddr;
if ((pPDDContext->pPL011 = PL011Create((ULONG)pBaseAddr)) == NULL)
{
DEBUGMSG(ZONE_INIT | ZONE_ERROR,
(BODY_TEXT("PDD_Init: Failed to create PL011 context")));
goto fail_point;
}
if ((pPDDContext->hevTxReady = CreateEvent(0, FALSE, FALSE, NULL)) == NULL)
{
DEBUGMSG(ZONE_INIT | ZONE_ERROR,
(BODY_TEXT("PDD_Init: Failed to create Win32 event object")));
goto fail_point;
}
// For using this context, thread-safely
//
InitializeCriticalSection(&(pPDDContext->cs));
pPDDContext->nOpenCount = 0; // Just for debug checks (the MDD manages concurrent opens)
pPDDContext->fIRMode = FALSE; // Select wired by default
// Set up our Comm Properties data
//
pPDDContext->CommProp.wPacketLength = 0xFFFF;
pPDDContext->CommProp.wPacketVersion = 0xFFFF;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -