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

📄 pdd.c.bak

📁 基于WinCE 5.0 下的MIPS 32 内核的Au1200(AMD)的UART驱动
💻 BAK
📖 第 1 页 / 共 3 页
字号:
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
// Copyright (c) 2004 BSQUARE 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.
//
#include <windows.h>
#include <bceddk.h>
#include <ddkreg.h>
#define USE_NEW_SERIAL_MODEL
#include <serhw.h>
#include <serdbg.h>
#include "platform.h"
#include "pdd.h"

//------------------------------------------------------------------------------

#define UART_INTEN_TX_OFF  (UART_INTEN_LIE|UART_INTEN_RIE|UART_INTEN_MIE)
#define UART_INTEN_TX_ON   (UART_INTEN_TX_OFF|UART_INTEN_TIE)

#define INP32(a)           ((UCHAR)READ_PORT_ULONG((ULONG*)(a)))
#define OUT32(a, v)        WRITE_PORT_ULONG((ULONG*)(a), (v))

//------------------------------------------------------------------------------

typedef struct {
	AU1X00_UART *pPortBase;             // Mapped virtual address of uart ports
	ULONG irq;                          // IRQ readed from registry
	ULONG sysIntr;                      // Assigned SYSINTR

	PVOID pMdd;                         // MDD context

	BOOL  open;                         // Is device open?
	DCB   dcb;                          // Serial port DCB

	ULONG commErrors;                   // How many errors occured
	ULONG overrunCount;                 // How many chars was missed

	ULONG txFifoLength;                 // TX FIFO length
	ULONG txFifoThresh;                 // TX FIFO threshold
	ULONG rxFifoLength;                 // RX FIFO length (not used...)
	ULONG rxFifoThresh;                 // RX FIFO threshold (not used...)

	BOOL  powerOff;                     // Are we power-off?
	UCHAR fifoCtrl;                     // fifoctrl register on power-off
	UCHAR lineCtrl;                     // linectrl register on power-off
	UCHAR mdmCtrl;                      // mdmctrl register on power-off
	UCHAR clkDiv;                       // clckdiv register on power-off

	BOOL  addTxIntr;                    // Should we add software TX interrupt?
	BOOL  flowOffCTS;                   // Is CTS down?
	BOOL  flowOffDSR;                   // Is DSR down?

	CRITICAL_SECTION hwCS;              // Guard access to HW registers
	CRITICAL_SECTION txCS;              // Guard HWXmitComChar
	HANDLE txEvent;                     // Signal TX interrupt for HWXmitComChar
} UARTPDD;

//------------------------------------------------------------------------------

static HW_VTBL g_pddVTbl = {
	HWInit, 
	HWPostInit,
	HWDeinit, 
	HWOpen, 
	HWClose, 
	HWGetInterruptType,
	HWRxIntr, 
	HWTxIntr, 
	HWModemIntr, 
	HWLineIntr, 
	HWGetRxBufferSize,
	HWPowerOff, 
	HWPowerOn, 
	HWClearDTR, 
	HWSetDTR, 
	HWClearRTS, 
	HWSetRTS,
	HWEnableIR, 
	HWDisableIR, 
	HWClearBreak, 
	HWSetBreak, 
	HWXmitComChar,
	HWGetStatus, 
	HWReset, 
	HWGetModemStatus, 
	HWGetCommProperties,
	HWPurgeComm, 
	HWSetDCB, 
	HWSetCommTimeouts, 
	HWIOCtl
};

//------------------------------------------------------------------------------
// Table used to convert "UnitIndex" from registry into physical addresses
// and IRQs. Au1x00.h only defines those UARTs that the CPU supports so we use
// that to manage available UARTs.
typedef struct {
	ULONG UartPhysAddr;
	ULONG UartIrq;
} UART_CONFIG;

static UART_CONFIG UartConfig[] = {

#ifdef UART0_PHYS_ADDR
	{ UART0_PHYS_ADDR, HWINTR_UART0 },
#else
	{ 0, 0 },
#endif

#ifdef UART1_PHYS_ADDR
	{ UART1_PHYS_ADDR, HWINTR_UART1 },
#else
	{ 0, 0 },
#endif

#ifdef UART2_PHYS_ADDR
	{ UART2_PHYS_ADDR, HWINTR_UART2 },
#else
	{ 0, 0 },
#endif

#ifdef UART3_PHYS_ADDR
	{ UART3_PHYS_ADDR, HWINTR_UART3 },
#else
	{ 0, 0 },
#endif

};

#define UART_CONFIG_SIZE (sizeof(UartConfig)/sizeof(UART_CONFIG))

//------------------------------------------------------------------------------
//
// Function:     ReadLineStat
//
// Description:  This function reads line status register and it calls back
//               MDD if line event occurs. This must be done in this way
//               because register bits are cleared on read.
//

static UCHAR ReadLineStat(UARTPDD *pPdd)
{
	UCHAR lineStat;
	ULONG events;

	// Nothing happen yet...   
	events = 0;

	// Read line status register (it clear most bits)
	lineStat = INP32(&pPdd->pPortBase->linestat);

	// Check for errors
	if ((lineStat&(UART_LINESTAT_OE|UART_LINESTAT_PE|UART_LINESTAT_FE)) != 0) {
		if ((lineStat & UART_LINESTAT_OE) != 0) {
			pPdd->overrunCount++;
			pPdd->commErrors |= CE_OVERRUN;
		}
		if ((lineStat & UART_LINESTAT_PE) != 0) pPdd->commErrors |= CE_RXPARITY;
		if ((lineStat & UART_LINESTAT_FE) != 0) pPdd->commErrors |= CE_FRAME;
		events |= EV_ERR;
	}

	// And for break
	if ((lineStat&UART_LINESTAT_BI) != 0) events |= EV_BREAK;

	// Let MDD know if something happen
	if (events != 0) EvaluateEventFlag(pPdd->pMdd, events);

	return lineStat;
}

//------------------------------------------------------------------------------
//
// Function:     ReadModemStat
//
// Description:  This function reads modem status register and it calls back
//               MDD if modem event occurs. This must be done in this way
//               because register bits are cleared on read.
//

static UCHAR ReadModemStat(UARTPDD *pPdd)
{
	UCHAR modemStat = 0;
	ULONG events;

	// Nothing happen yet...   
	events = 0;

	modemStat = INP32(&pPdd->pPortBase->mdmstat);

	// For changes, we use callback to evaluate the event
	if ((modemStat & UART_MDMSTAT_DC) != 0)  events |= EV_CTS;
	if ((modemStat & UART_MDMSTAT_DR) != 0)  events |= EV_DSR;
	if ((modemStat & UART_MDMSTAT_TRI) != 0) events |= EV_RING;
	if ((modemStat & UART_MDMSTAT_DD) != 0)  events |= EV_RLSD;

	// Let MDD know if something happen
	if (events != 0) EvaluateEventFlag(pPdd->pMdd, events);

	return modemStat;
}


//------------------------------------------------------------------------------
//
// Function:     SetBaudRate
//
// Description:  This function sets baud rate.
//

static BOOL SetBaudRate(UARTPDD *pPdd, ULONG baudRate)
{
	ULONG divider;
	BOOL ok = FALSE;

	// Check baud rate values
	if (baudRate < 110 || baudRate > 1546875) goto cleanUp;

	// Calculate divider
	divider = GetPBUSSpeed() / (16 * baudRate);

	EnterCriticalSection(&pPdd->hwCS);
	OUT32(&pPdd->pPortBase->clkdiv, divider);
	LeaveCriticalSection(&pPdd->hwCS);

	ok = TRUE;

cleanUp:
	return ok;
}

//------------------------------------------------------------------------------
//
// Function:     SetWordLength
//
// Description:  This function sets word length.
//

static BOOL SetWordLength(UARTPDD *pPdd, UCHAR wordLength)
{
	UCHAR lineCtrl;
	BOOL ok = FALSE;

	if (wordLength < 5 || wordLength > 8) goto cleanUp;

	EnterCriticalSection(&pPdd->hwCS);
	lineCtrl = INP32(&pPdd->pPortBase->linectrl);
	lineCtrl = (lineCtrl & 0x03)|(wordLength - 5);
	OUT32(&pPdd->pPortBase->linectrl, lineCtrl);
	LeaveCriticalSection(&pPdd->hwCS);

	ok = TRUE;

cleanUp:
	return ok;
}

//------------------------------------------------------------------------------
//
// Function:     SetParity
//
// Description:  This function sets parity.
//

static BOOL SetParity(UARTPDD *pPdd, UCHAR parity)
{
	UCHAR lineCtrl;
	BOOL ok = FALSE;
	UCHAR mask;

	switch (parity) {
	case NOPARITY:
		mask = 0;
		break;
	case ODDPARITY:
		mask = UART_LINECTRL_PE | (0 << 4);
		break;
	case EVENPARITY:
		mask = UART_LINECTRL_PE | (1 << 4);
		break;
	case MARKPARITY:
		mask = UART_LINECTRL_PE | (2 << 4);
		break;
	case SPACEPARITY:
		mask = UART_LINECTRL_PE | (3 << 4);
		break;
	default:
		goto cleanUp;
   }   

	EnterCriticalSection(&pPdd->hwCS);
	lineCtrl = INP32(&pPdd->pPortBase->linectrl);
	lineCtrl = (lineCtrl & ~UART_LINECTRL_ST)|mask;
	OUT32(&pPdd->pPortBase->linectrl, lineCtrl);
	LeaveCriticalSection(&pPdd->hwCS);

	ok = TRUE;

cleanUp:
	return ok;
}

//------------------------------------------------------------------------------
//
// Function:     SetStopBits
//
// Description:  This function sets word length.
//

static BOOL SetStopBits(UARTPDD *pPdd, UCHAR stopBits)
{
	UCHAR lineCtrl;
	BOOL ok = FALSE;
	UCHAR mask;

	switch (stopBits) {
	case ONESTOPBIT:
		mask = 0;
		break;
	case ONE5STOPBITS:
	case TWOSTOPBITS:
		mask = UART_LINECTRL_ST;
		break;
	default:
		goto cleanUp;
	}   

	EnterCriticalSection(&pPdd->hwCS);
	lineCtrl = INP32(&pPdd->pPortBase->linectrl);
	lineCtrl = (lineCtrl & ~UART_LINECTRL_ST)|mask;
	OUT32(&pPdd->pPortBase->linectrl, lineCtrl);
	LeaveCriticalSection(&pPdd->hwCS);

	ok = TRUE;

cleanUp:
	return ok;
}

//------------------------------------------------------------------------------
//
// Function:     GetSerialObject
//
// Description:  This function returns a pointer to a HWOBJ structure, which
//               contains the correct function pointers and parameters for
//               the relevant PDD layer's hardware interface functions.

PHWOBJ GetSerialObject(DWORD index)
{
	PHWOBJ pHWObj;

	// Allocate space for the HWOBJ.
	pHWObj = malloc(sizeof(HWOBJ));
	if (pHWObj == NULL) goto cleanUp;

	// Fill in the HWObj structure

	pHWObj->BindFlags = THREAD_AT_OPEN; // Have MDD create thread when device is first opened.
	pHWObj->dwIntID = 0;                // SysIntr is filled in at init time
	pHWObj->pFuncTbl = &g_pddVTbl;      // Return pointer to appropriate functions

cleanUp:
	return pHWObj;
}
 

//------------------------------------------------------------------------------
//
// Function:     HWInit
//
// Description:  This function initializes a serial device and it returns
//               information about device
//

static PVOID HWInit(ULONG context, PVOID pMdd, PHWOBJ pHWObj)
{
	BOOL ok = FALSE;
	UARTPDD *pPdd = NULL;
	PHYSICAL_ADDRESS phBase;
	HKEY hKey = NULL;
	ULONG UnitIndex;
	ULONG Size;

  
	DEBUGMSG(ZONE_OPEN, (L"+au1uart::HWInit %s 0x%08x 0x%08x\n", context, pMdd, pHWObj));

	// Allocate SER_INFO structure
	pPdd = malloc(sizeof(UARTPDD));
	if (pPdd == NULL) goto cleanUp;

	// Clear it
	memset(pPdd, 0, sizeof(UARTPDD));

	// Open registry 
	hKey = OpenDeviceKey((LPCTSTR)context);
	if (hKey == NULL) {
		DEBUGMSG(ZONE_ERROR, (L" au1uart::HWInit - Failed open registry key\n"));
		goto cleanUp;
	}

	// Read UnitIndex from the Registry
	Size = sizeof(UnitIndex);
	if (RegQueryValueEx(hKey, L"UnitIndex", NULL, NULL, (PUCHAR)&UnitIndex, &Size)) {
		RETAILMSG(1,(L" au1uart::HWInit - Failed open \"UnitIndex\" registry entry\n"));
		goto cleanUp;
	}

	// Check UnitIndex is valid and supported
	if (UnitIndex > UART_CONFIG_SIZE || UartConfig[UnitIndex].UartPhysAddr == 0) {
		RETAILMSG(1,(L" au1uart::HWInit - UnitIndex %d is invalid\n", UnitIndex));
		goto cleanUp;
	}

	// Map physical memory
	phBase.QuadPart = UartConfig[UnitIndex].UartPhysAddr;
	pPdd->pPortBase = (AU1X00_UART*)MmMapIoSpace(phBase, sizeof(AU1X00_UART), FALSE);
	if (pPdd->pPortBase == NULL) {
		DEBUGMSG(ZONE_ERROR, (L" au1uart::HWInit - Failed map physical memory 0x%x\n", phBase.LowPart));
		goto cleanUp;
	}

	// Save IRQ
	pPdd->irq = UartConfig[UnitIndex].UartIrq;

	pPdd->sysIntr = InterruptConnect(Internal,0,pPdd->irq,0);

	if (SYSINTR_NOP==pPdd->sysIntr) {
		DEBUGMSG(ZONE_ERROR, (L" au1uart::HWInit - Failed map IRQ %d\n", pPdd->irq));
		goto cleanUp;
	}

	
	// Save it to HW object
	pHWObj->dwIntID = pPdd->sysIntr;

	// Create sync objects
	InitializeCriticalSection(&pPdd->hwCS);
	InitializeCriticalSection(&pPdd->txCS);
	pPdd->txEvent = CreateEvent(0, FALSE, FALSE, NULL);
	if (pPdd->txEvent == NULL) {
		DEBUGMSG(ZONE_ERROR, (L" au1uart::HWInit - Failed create event\n"));
		goto cleanUp;
	}
   
	// Allow device
	OUT32(&pPdd->pPortBase->enable, 0);
	OUT32(&pPdd->pPortBase->enable, UART_ENABLE_CE);
	OUT32(&pPdd->pPortBase->enable, UART_ENABLE_CE|UART_ENABLE_E);

	// Disable all interrupts
	OUT32(&pPdd->pPortBase->inten, 0);

	// Save MDD context for callback
	pPdd->pMdd = pMdd;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -