📄 pdd.c.bak
字号:
//
// 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 + -