📄 ser_pdd.c
字号:
/*
Copyright(c) 1998,1999 SIC/Hitachi,Ltd.
Module Name:
Ser_pdd.c
Revision History:
26th April 1999 Released
*/
#include <windows.h>
#include <types.h>
#include <memory.h>
#include <serhw.h>
#include <hw16550.h>
#include <serdbg.h>
#include <nkintr.h>
#include "ccir.h"
#include "ser_pdd.h"
//#include "mobytel.h"
#include "cc.h"
#include "macros.h"
//#include "shx.h"
extern DWORD dwHD64465Base;
// #define DBGMSG
#define DBGMSG NKDbgPrintfW
#define BAUD_TABLE_SIZE 19
static const
PAIRS BaudPairs[BAUD_TABLE_SIZE] = {
{50, 2307},
{75, 1538},
{110, 1049},
{135, 858},
{150, 769},
{300, 384},
{600, 192},
{1200, 96},
{1800, 64},
{2000, 58},
{2400, 48},
{3600, 32},
{4800, 24},
{7200, 16},
{9600, 12},
{19200, 6},
{38400, 3},
{57600, 2},
{115200, 1}
};
static const LOOKUP_TBL BaudTable = {BAUD_TABLE_SIZE, (PAIRS *) BaudPairs};
// Miscellaneous internal routines.
PUCHAR
static
Ser_InternalMapRegisterAddresses(
ULONG HWAddress,
ULONG Size
)
{
PUCHAR ioPortBase;
// DEBUGMSG(ZONE_FUNCTION,
DEBUGMSG(1,
(TEXT("+Ser_InternalMapRegisterAddresses: adr=0x%x len=0x%x\r\n"),
HWAddress, Size));
ioPortBase = VirtualAlloc(0, Size, MEM_RESERVE, PAGE_NOACCESS);
if ( ioPortBase == NULL )
{
ERRORMSG(1, (TEXT("Ser_InternalMapRegisterAddresses: VirtualAlloc failed!\r\n")));
}
else if ( !VirtualCopy((PVOID)ioPortBase, (PVOID)HWAddress, Size, PAGE_READWRITE|PAGE_NOCACHE) )
{
ERRORMSG(1, (TEXT("Ser_InternalMapRegisterAddresses: VirtualCopy failed!\r\n")));
VirtualFree( (PVOID)ioPortBase, 0, MEM_RELEASE );
ioPortBase = 0;
}
// DEBUGMSG(ZONE_FUNCTION,
DEBUGMSG(1,
(TEXT("-Ser_InternalMapRegisterAddresses: mapped at 0x%x\r\n"),
ioPortBase ));
return ioPortBase;
}
static
BOOL
SerSetIRBaudRate(
PSER_INFO pHWHead,
ULONG baud // @parm UINT16 what is the baud rate
)
{
DEBUGMSG (ZONE_INIT, (TEXT("Serial set IR Baud %d\r\n"),
baud));
return TRUE;
}
/*
* NOTE : The caller should have set pHWHead->fIRMode. It is not
* set here, since power on/off may need to temporarily disable
* the intefaces without actually overwriting the current recorded
* mode.
*/
static
void
SerSetOutputMode(
PSER_INFO pHWHead,
BOOL UseIR, // @parm BOOL Should we use IR interface
BOOL Use9Pin // @parm BOOL Should we use Wire interface
)
{
// TODO - here you need to set the interface to either IR mode
// or normal serial. Note that it is possible for both BOOls to
// be false (i.e. power down), but never for both to be TRUE.
}
/*
@doc OEM
@func PVOID | SerInit | Initializes device identified by argument.
* This routine sets information controlled by the user
* such as Line control and baud rate. It can also initialize events and
* interrupts, thereby indirectly managing initializing hardware buffers.
* Exported only to driver, called only once per process.
*
@rdesc The return value is a PVOID to be passed back into the HW
dependent layer when HW functions are called.
*/
static
PVOID
SerInit(
ULONG Identifier, // @parm Device identifier.
PVOID pMddHead // @parm First argument to mdd callbacks.
)
{
PSER_INFO pHWHead;
// Note on defaults. While the PC typcially considers COM1 to be at
// 3F8, irq4 and COM2 to be 2F8, irq3, NKPC uses COM1 internally for the
// debugger. So, when NK tells me to start "COM1" it really means the
// first one that's available, which is what the PC calls COM2. Confused?
// The end result is that COM1 on NK is what the PC considers to be COM2.
// But wait, there's more. On a Puzzle, the debugger is on COM2 and the
// COM1 for NK is ACTUALLY COM1. So PCs need 2F8 for their port base
// and Puzzles need 3F8.
const UINT cDefaultCom1PortBase = 0x2F8;
const UINT cDefaultComPortRange = 8;
// Allocate for our main data structure and one of it's fields.
pHWHead = (PSER_INFO)LocalAlloc( LMEM_ZEROINIT|LMEM_FIXED ,
sizeof(SER_INFO) );
if (!pHWHead)
goto ALLOCFAILED;
// This call will map the address space for the 16550 UART.
pHWHead->pBaseAddress = Ser_InternalMapRegisterAddresses(
(dwHD64465Base + HD64465_FIR_OFFSET), 0x400);
pHWHead->pMddHead = pMddHead;
pHWHead->cOpenCount = 0;
// Set up our Comm Properties data
pHWHead->CommProp.wPacketLength = 0xffff;
pHWHead->CommProp.wPacketVersion = 0xffff;
pHWHead->CommProp.dwServiceMask = SP_SERIALCOMM;
pHWHead->CommProp.dwReserved1 = 0;
pHWHead->CommProp.dwMaxTxQueue = 16;
pHWHead->CommProp.dwMaxRxQueue = 16;
pHWHead->CommProp.dwMaxBaud = BAUD_115200;
pHWHead->CommProp.dwProvSubType = PST_RS232;
pHWHead->CommProp.dwProvCapabilities =
PCF_DTRDSR | PCF_RLSD | PCF_RTSCTS |
PCF_SETXCHAR |
PCF_INTTIMEOUTS |
PCF_PARITY_CHECK |
PCF_SPECIALCHARS |
PCF_TOTALTIMEOUTS |
PCF_XONXOFF;
pHWHead->CommProp.dwSettableBaud =
BAUD_075 | BAUD_110 | BAUD_150 | BAUD_300 | BAUD_600 |
BAUD_1200 | BAUD_1800 | BAUD_2400 | BAUD_4800 |
BAUD_7200 | BAUD_9600 | BAUD_14400 |
BAUD_19200 | BAUD_38400 | BAUD_56K | BAUD_128K |
BAUD_115200 | BAUD_57600 | BAUD_USER;
pHWHead->CommProp.dwSettableParams =
SP_BAUD | SP_DATABITS | SP_HANDSHAKING | SP_PARITY |
SP_PARITY_CHECK | SP_RLSD | SP_STOPBITS;
pHWHead->CommProp.wSettableData =
DATABITS_5 | DATABITS_6 | DATABITS_7 | DATABITS_8;
pHWHead->CommProp.wSettableStopParity =
STOPBITS_10 | STOPBITS_20 |
PARITY_NONE | PARITY_ODD | PARITY_EVEN | PARITY_SPACE |
PARITY_MARK;
// Init 16550 info, register stride is 1
DEBUGMSG (ZONE_INIT, (TEXT("SerInit - Init 16550 data\r\n")));
CCIR_Init( pHWHead, pHWHead->pBaseAddress, CC_16550_REG_STRIDE,
EvaluateEventFlag, pMddHead, (PLOOKUP_TBL)&BaudTable);
DEBUGMSG (ZONE_INIT,
(TEXT("SerInit - Disabling UART Power\r\n")));
pHWHead->fIRMode = FALSE; // Select wired by default
SerSetOutputMode(pHWHead, FALSE, FALSE );
return pHWHead;
ALLOCFAILED:
if ( pHWHead->pBaseAddress )
VirtualFree(pHWHead->pBaseAddress, 0, MEM_RELEASE);
LocalFree(pHWHead);
return NULL;
}
/*
@doc OEM
@func ULONG | SerClose | This routine closes the device identified by the PVOID returned by SerInit.
* Not exported to users, only to driver.
*
@rdesc The return value is 0.
*/
static
ULONG
SerClose(
PVOID pHead // @parm PVOID returned by SerInit.
)
{
PSER_INFO pHWHead = (PSER_INFO)pHead;
ULONG uTries;
// DEBUGMSG (ZONE_CLOSE,(TEXT("+SerClose\r\n")));
DEBUGMSG (1,(TEXT("+SerClose\r\n")));
if( pHWHead->cOpenCount )
{
DEBUGMSG (ZONE_CLOSE,
(TEXT("SerClose, closing device\r\n")));
pHWHead->cOpenCount--;
// while we are still transmitting, sleep.
uTries = 0;
while ( (uTries++ < 100) &&
!(pHWHead->ser16550.LSR & SERIAL_LSR_TEMT) )
{
DEBUGMSG (ZONE_CLOSE,
(TEXT("SerClose, TX in progress, LSR 0x%X\r\n"),
pHWHead->ser16550.LSR));
Sleep(10);
}
// When the device is closed, we power it down.
DEBUGMSG (ZONE_CLOSE,
(TEXT("SerClose - Powering down UART\r\n")));
pHWHead->fIRMode = FALSE;
SerSetOutputMode(pHWHead, FALSE, FALSE );
CCIR_Close( pHWHead );
}
// DEBUGMSG (ZONE_CLOSE,(TEXT("-SerClose\r\n")));
DEBUGMSG (1,(TEXT("-SerClose\r\n")));
return 0;
}
/*
@doc OEM
@func PVOID | SerDeinit | Deinitializes device identified by argument.
* This routine frees any memory allocated by SerInit.
*
*/
static
BOOL
SerDeinit(
PVOID pHead // @parm PVOID returned by SerInit.
)
{
PSER_INFO pHWHead = (PSER_INFO)pHead;
if ( !pHWHead )
return FALSE;
// Make sure device is closed before doing DeInit
if( pHWHead->cOpenCount )
SerClose( pHead );
if ( pHWHead->pBaseAddress )
VirtualFree(pHWHead->pBaseAddress, 0, MEM_RELEASE);
LocalFree(pHWHead);
return TRUE;
}
/*
@doc OEM
@func VOID | SerGetCommProperties | Retrieves Comm Properties.
*
@rdesc None.
*/
static
VOID
SerGetCommProperties(
PVOID pHead, // @parm PVOID returned by SerInit.
LPCOMMPROP pCommProp // @parm Pointer to receive COMMPROP structure.
)
{
PSER_INFO pHWHead = (PSER_INFO)pHead;
*pCommProp = pHWHead->CommProp;
return;
}
/*
@doc OEM
@func VOID | SerSetBaudRate |
* This routine sets the baud rate of the device.
* Not exported to users, only to driver.
*
@rdesc None.
*/
static
BOOL
SerSetBaudRate(
PVOID pHead, // @parm PVOID returned by SerInit
ULONG BaudRate // @parm ULONG representing decimal baud rate.
)
{
PSER_INFO pHWHead = (PSER_INFO)pHead;
// If we are running in IR mode, try to set the IR baud
// first, since it supports a subset of the rates supported
// by the UART. If we fail setting the IR rate, then
// return an error and leave the UART alone.
if( pHWHead->fIRMode )
{
if( ! SerSetIRBaudRate( pHWHead, BaudRate ) )
{
DEBUGMSG (ZONE_ERROR,
(TEXT("Unsupported IR BaudRate\r\n")));
// We should return an error, but vtbl doesn't expect one
return FALSE;
}
}
// Now set buadrate on the UART
return( CCIR_SetBaudRate( pHead, BaudRate ) );
}
/*
@doc OEM
@func BOOL | SerPowerOff |
* Called by driver to turn off power to serial port.
* Not exported to users, only to driver.
*
@rdesc This routine returns a status.
*/
static
BOOL
SerPowerOff(
PVOID pHead // @parm PVOID returned by SerInit.
)
{
PSER_INFO pHWHead = (PSER_INFO)pHead;
// First, power down the UART
CCIR_PowerOff( pHWHead );
// And then disable our IR and 9 Pin interface
SerSetOutputMode( pHWHead, FALSE, FALSE );
return TRUE;
}
/*
@doc OEM
@func BOOL | SerPowerOn |
* Called by driver to turn on power to serial port.
* Not exported to users, only to driver.
*
@rdesc This routine returns a status.
*/
static
BOOL
SerPowerOn(
PVOID pHead // @parm PVOID returned by SerInit.
)
{
PSER_INFO pHWHead = (PSER_INFO)pHead;
// First, power up the UART
CCIR_PowerOn( pHWHead );
// And then enable our IR interface (if needed)
SerSetOutputMode( pHWHead, pHWHead->fIRMode, !pHWHead->fIRMode );
return TRUE;
}
/*
@doc OEM
@func BOOL | SerEnableIR | This routine enables ir.
* Not exported to users, only to driver.
*
@rdesc Returns TRUE if successful, FALSEotherwise.
*/
static
BOOL
SerEnableIR(
PVOID pHead, // @parm PVOID returned by Serinit.
ULONG BaudRate // @parm PVOID returned by HWinit.
)
{
PSER_INFO pHWHead = (PSER_INFO)pHead;
// Not sure why he passes baudRate when its already in our
// pHWHead. So I'll ignore it and use the one in our struct.
pHWHead->fIRMode = TRUE;
SerSetOutputMode( pHWHead, pHWHead->fIRMode, !pHWHead->fIRMode );
return TRUE;
}
/*
@doc OEM
@func BOOL | SerDisableIR | This routine disable the ir.
* Not exported to users, only to driver.
*
@rdesc Returns TRUE if successful, FALSEotherwise.
*/
static
BOOL
SerDisableIR(
PVOID pHead /*@parm PVOID returned by Serinit. */
)
{
PSER_INFO pHWHead = (PSER_INFO)pHead;
pHWHead->fIRMode = FALSE;
SerSetOutputMode( pHWHead, pHWHead->fIRMode, !pHWHead->fIRMode );
return TRUE;
}
/*
@doc OEM
@func BOOL | SerOpen | This routine is called when the port is opened.
* Not exported to users, only to driver.
*
@rdesc Returns TRUE if successful, FALSEotherwise.
*/
static
BOOL
SerOpen(
PVOID pHead /*@parm PVOID returned by Serinit. */
)
{
PSER_INFO pHWHead = (PSER_INFO)pHead;
// Disallow multiple simultaneous opens
if( pHWHead->cOpenCount )
return FALSE;
pHWHead->cOpenCount++;
// DEBUGMSG (ZONE_OPEN,
DEBUGMSG (1,
(TEXT("SerOpen - Selecting Non IR Mode\r\n")));
pHWHead->fIRMode = FALSE; // Select wired by default
SerSetOutputMode(pHWHead, pHWHead->fIRMode, !pHWHead->fIRMode );
// BUGBUG - If we want to support 16450s, we'll need to dynamically
// identify them here.
pHWHead->ser16550.ChipID = CHIP_ID_16550;
// Init 16550 info
// DEBUGMSG (ZONE_OPEN, (TEXT("SerOpen - Calling CCIR_Open\r\n")));
DEBUGMSG (1, (TEXT("SerOpen - Calling CCIR_Open\r\n")));
CCIR_Open( pHWHead );
return TRUE;
}
const
HW_VTBL CCIRIoVTbl = {
SerInit,
SerDeinit,
SerOpen,
SerClose,
CCIR_RxIntr,
CCIR_GetRxStart,
CCIR_GetInterruptType,
CCIR_OtherIntr,
CCIR_LineIntr,
CCIR_GetRxBufferSize,
CCIR_TxIntr,
CCIR_PutBytes,
SerPowerOff,
SerPowerOn,
CCIR_ClearDTR,
CCIR_SetDTR,
CCIR_ClearRTS,
CCIR_SetRTS,
SerEnableIR,
SerDisableIR,
CCIR_ClearBreak,
CCIR_SetBreak,
CCIR_XmitComChar,
CCIR_GetStatus,
CCIR_Reset,
CCIR_GetModemStatus,
SerGetCommProperties,
CCIR_PurgeComm,
CCIR_SetDCB,
CCIR_SetCommTimeouts
};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -