📄 pdd.c
字号:
//
// 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"
#include <gpio.h> // SmartOne add
#include "ldrarg.h" // SmartOne add
//------------------------------------------------------------------------------
// Grobal variable
BOOL bTxIntEn; // SmartOne add
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
//#define UART_INTEN_TX_OFF (UART_INTEN_LIE|UART_INTEN_RIE|UART_INTEN_MIE) // SmartOne del
////#define UART_INTEN_TX_OFF (UART_INTEN_LIE|UART_INTEN_RIE) // SmartOne add // 我们只使用TX,RX,GPIO9 10设为通用的GPIO,所以MIE改须去掉
////#define UART_INTEN_TX_ON (UART_INTEN_TX_OFF|UART_INTEN_TIE)
#define UART_INTEN_TX_OFF (RX_INT_ENB_BIT)
#define UART_INTEN_TX_ON (TX_INT_ENB_BIT|RX_INT_ENB_BIT)
#define ENABLE_TX_INT(pCpld) {pCpld->uartIntEnable = UART_INTEN_TX_ON; bTxIntEn = TRUE;}
#define DISABLE_TX_INT(pCpld) {pCpld->uartIntEnable = UART_INTEN_TX_OFF; bTxIntEn = FALSE;}
#define DISABLE_ALL_INT(pCpld) {pCpld->uartIntEnable &= ~UART_INTEN_TX_ON; bTxIntEn = FALSE;}
#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
CPLD *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
#ifdef CPLD_PHYSADDR
{ CPLD_PHYSADDR, HWINTR_GPIO7 },
#else
{ 0, 0 },
#endif
};
#define UART_CONFIG_SIZE (sizeof(UartConfig)/sizeof(UART_CONFIG))
static BOOT_ARGS *pBootArgs = (BOOT_ARGS*)(BOOT_ARG_PTR + KSEG1_OFFSET); // SmartOne add
//------------------------------------------------------------------------------
//
// 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 VOID ResetUart(UARTPDD *pPdd)
{
CPLD* pCpld = pPdd->pPortBase;
// 复位 uart,写一个高的脉冲
pCpld->uartCtrl &= ~UART_RESET_BIT;
HalStallExecution(1); // 100ns
pCpld->uartCtrl |= UART_RESET_BIT;
HalStallExecution(8); // 800ns
pCpld->uartCtrl &= ~UART_RESET_BIT;
return ;
}
static VOID EnableUart(UARTPDD *pPdd, BOOL bOn)
{
CPLD* pCpld = pPdd->pPortBase;
if(bOn) {
HalStallExecution(1); // 100ns
pCpld->uartCtrl |= UART_ENABLE_BIT; // don't change fifo status
HalStallExecution(1 * 1000 * 100); // 1ms
}
else {
HalStallExecution(1); // 100ns
pCpld->uartCtrl &= ~UART_ENABLE_BIT; // don't change fifo status
HalStallExecution(1 * 1000 * 100); // 1ms
}
return ;
}
static VOID EnableRxFifo(UARTPDD *pPdd, BOOL bOn)
{
CPLD* pCpld = pPdd->pPortBase;
if(!bOn)
pCpld->uartCtrl |= UART_RX_FIFO_ENB_BIT;
else
pCpld->uartCtrl &= ~UART_RX_FIFO_ENB_BIT;
return ;
}
//------------------------------------------------------------------------------
//
// 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)
{
#if 0
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;
#endif
#if 1
UCHAR lineStat;
CPLD* pCpld = pPdd->pPortBase;
lineStat = pCpld->uartStatus;
return lineStat;
#endif
}
//------------------------------------------------------------------------------
//
// 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;
#if 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);
#endif
return modemStat;
}
//------------------------------------------------------------------------------
//
// Function: SetBaudRate
//
// Description: This function sets baud rate.
//
static BOOL SetBaudRate(UARTPDD *pPdd, ULONG baudRate)
{
////ULONG divider;
BOOL ok = FALSE;
CPLD* pCpld = pPdd->pPortBase;
//RETAILMSG(1, (L"+cplduart::SetBaudRate 01 %d\r\n", baudRate));
// Check baud rate values
if (baudRate != 9600 && baudRate != 38400) goto cleanUp;
// only support two type of baud rate, one is 9600, another is 38400.
EnterCriticalSection(&pPdd->hwCS);
if(baudRate == 38400) {
pCpld->uartCtrl |= UART_SET_BAUDRATE_BIT; // 38400
//RETAILMSG(1, (L"+cplduart::SetBaudRate 02 %d\r\n", baudRate));
}
else {
pCpld->uartCtrl &= ~UART_SET_BAUDRATE_BIT; // 9600
//RETAILMSG(1, (L"+cplduart::SetBaudRate 03 %d\r\n", baudRate));
}
LeaveCriticalSection(&pPdd->hwCS);
#if 0
// 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);
#endif
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;
//RETAILMSG(1, (L"+cplduart::SetWordLength %d\r\n", wordLength));
if (wordLength != 8) goto cleanUp; // cpld里己经固定为8bit数据位
#if 0
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);
#endif
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;
#if 0
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:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -