📄 xrcom16550.c
字号:
////////////////////////////////////////
//(c) 2005 EXAR Corporation
//All Rights Reserved.
//
//Exar Corporation ("Exar") hereby grants the User of this Exar
//product-specific XR17C15x Windows CE.Net Device Driver (hereinafter
//referred to as "Driver") a non-exclusive, nontransferable license
//to use the Driver in accordance with the term set forth below.
//Before using the Driver, the User should read the following use
//restrictions. If the User does not accept these terms, the Driver
//should not be used or downloaded.
//The User is granted this limited license to use this Driver for
//User's end product that includes the Exar XR17C158/XR17D158 Octal UART PCI
//device, XR17C154/XR17D154 Quad UART PCI Device, and XR17C152/XR17D152 Dual UART
//PCI Device and is not granted rights to sell, loan, rent, lease or
//license the Driver, in whole or in part, or in modified form to anyone
//other than User. User may modify the Driver to suit its specific
//applications but rights to derivative works and such modifications
//shall belong to Exar.
//
//The Driver is provided on an "AS IS" basis and Exar makes absolutely
//no warranty with respect to performance or the information contained
//therein. EXAR DISCLAIMS AND USER WAIVES ALL WARRANTIES, EXPRESS OR
//IMPLIED, INCLUDING WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A
//PARTICULAR PURPOSE. The entire risk as to Driver quality and
//performance is with the User. ACCORDINGLY, IN NO EVENT SHALL EXAR
//BE LIABLE FOR ANY DAMAGES, WHETHER IN CONTRACT OR TORT, INCLUDING
//ANY LOST PROFITS OR OTHER INCIDENTAL, CONSEQUENTIAL, EXEMPLARY, OR
//PUNITIVE DAMAGES ARISING OUT OF THE USE OR APPLICATION OF THE DRIVER.
//Further, Exar reserves the right to make changes tot eh Driver without
//notice to improve reliability, function or design. Exar does not
//convey any license under patent rights or any other intellectual
//property rights, including those of third parties.
//
//Exar is not obligated to provide maintenance or support for the Driver.
//
//////////////////////////////////////////////////////////
/*++
Module Name: xrcom16550.c
Abstract:
Notes:
--*/
#include <windows.h>
#include <types.h>
#include <ceddk.h>
#include <memory.h>
#include <nkintr.h>
#include <devload.h>
#include <ddkreg.h>
#include <serhw.h>
#include <ser16550.h>
#include <hw16550.h>
#include <nkintr.h>
#include <devload.h>
#include <ddkreg.h>
#include <pm.h>
#include "xrcom16550.h"
#include "xrser16550.h"
#undef ZONE_INIT
#include <serdbg.h>
// #define DBGMSG
#define DBGMSG NKDbgPrintfW
#define BAUD_TABLE_SIZE 22
static const
PAIRS BaudPairs[BAUD_TABLE_SIZE] = {
{50, 18432},
{75, 12288},
{150, 6144},
{300, 3072},
{600, 1536},
{1200, 768},
{1800, 512},
{2400, 384},
{3600, 256},
{4800, 192},
{7200, 128},
{9600, 96},
{12800, 72},
{14400, 64},
{19200, 48},
{28800, 32},
{38400, 24},
{57600, 16},
{115200, 8},
{230400, 4},
{460800, 2},
{921600, 1}
};
static const LOOKUP_TBL BaudTable = {BAUD_TABLE_SIZE, (PAIRS *) BaudPairs};
// UART register stride (default = 1 byte).
static DWORD g_dwRegStride = 1;
// Miscellaneous internal routines.
PUCHAR
static
Ser_InternalMapRegisterAddresses(
ULONG InterfaceType,
ULONG BusNumber,
ULONG HWAddress,
ULONG Size,
PVOID * ppStaticAddress
)
{
PUCHAR ioMemBase;
ULONG inMemSpace = 0;
PHYSICAL_ADDRESS ioPhysicalBase = { HWAddress, 0};
DEBUGMSG(ZONE_FUNCTION,
(TEXT("Ser_InternalMapRegisterAddresses : HalTranslateBusAddress\r\n")));
if ( HalTranslateBusAddress(InterfaceType, BusNumber, ioPhysicalBase, &inMemSpace,
&ioPhysicalBase) ) {
DEBUGMSG(1,
(TEXT("Ser_InternalMapRegisterAddresses : HalTranslateBusAddress - OK\r\n")));
if ( !inMemSpace ) {
DEBUGMSG(1,
(TEXT("Ser_InternalMapRegisterAddresses : ! IO Space\r\n")));
if ( (ioMemBase = (PUCHAR)MmMapIoSpace(ioPhysicalBase,
Size, FALSE)) == NULL ) {
// We may as well not continue
DEBUGMSG(ZONE_INIT | ZONE_ERROR,
(TEXT("Error mapping I/O Ports\r\n")));
return (NULL);
}
if (ppStaticAddress) { // Need create static address for ISR.
ioPhysicalBase.LowPart=HWAddress;
ioPhysicalBase.HighPart=0;
inMemSpace=0;
TransBusAddrToStatic(InterfaceType, BusNumber, ioPhysicalBase,Size,
&inMemSpace, ppStaticAddress);
};
} else {
DEBUGMSG(1,
(TEXT("Ser_InternalMapRegisterAddresses : IO Space\r\n")));
ioMemBase = (PUCHAR)ioPhysicalBase.LowPart;
if (ppStaticAddress) { // Need create static address for ISR.
*ppStaticAddress=ioMemBase; //IO no need for mapping.
};
}
} else {
DEBUGMSG(ZONE_INIT | ZONE_ERROR,
(TEXT("Error translating I/O Ports.\r\n")));
return (NULL);
}
DEBUGMSG(ZONE_FUNCTION,
(TEXT("Ser_InternalMapRegisterAddresses : %d\r\n"),
ioMemBase ));
return (ioMemBase);
}
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
)
{
// If you support IR, 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.
}
/*++
*******************************************************************************
Routine:
Ser_GetRegistryData
Description:
Take the registry path provided to COM_Init and use it to find this
requested comm port's DeviceArrayIndex, teh IOPort Base Address, and the
Interrupt number.
Arguments:
LPCTSTR regKeyPath the registry path passed in to COM_Init.
Return Value:
-1 if there is an error.
*******************************************************************************
--*/
BOOL
Ser_GetRegistryData(PSER_INFO pHWHead, LPCTSTR regKeyPath)
{
#define GCI_BUFFER_SIZE 256
HKEY hKey;
DWORD dwDataSize = GCI_BUFFER_SIZE;
ULONG kvaluetype;
ULONG datasize = sizeof(ULONG);
DEBUGMSG(ZONE_INIT, (TEXT("Try to open %s\r\n"), regKeyPath));
// We've been handed the name of a key in the registry that was generated
// on the fly by device.exe. We're going to open that key and pull from it
// a value that is the name of this serial port's real key. That key
// will have the DeviceArrayIndex that we're trying to find.
hKey = OpenDeviceKey(regKeyPath);
if ( hKey == NULL )
{
DEBUGMSG(ZONE_INIT | ZONE_ERROR,
(TEXT("Failed to open device key\r\n")));
return ( FALSE );
}
//
// values needed here -
//
datasize = sizeof(DWORD);
//pHWHead->dwSysIntr = dii.dwSysintr;
if ( RegQueryValueEx(hKey, L"SysInterrupt", NULL, &kvaluetype,
(LPBYTE)&pHWHead->dwSysIntr, &datasize) )
{
DEBUGMSG (ZONE_INIT | ZONE_ERROR,
(TEXT("Failed to get SysInterrupt value, Ser_GetRegistryData failed\r\n")));
RegCloseKey (hKey);
return(FALSE);
}
pHWHead->ser16550.dwSysIntr = pHWHead->dwSysIntr;
//pHWHead->ser16550.dwIrq = dii.dwIrq;
if ( RegQueryValueEx(hKey, L"IRQ", NULL, &kvaluetype,
(LPBYTE)&pHWHead->ser16550.dwIrq, &datasize) )
{
DEBUGMSG (ZONE_INIT | ZONE_ERROR,
(TEXT("Failed to get IRQ value, Ser_GetRegistryData failed\r\n")));
RegCloseKey (hKey);
return(FALSE);
}
//
// ISR handler - hardcoded here
//
//_tcscpy(pHWHead->ser16550.RegIsrDll, TEXT("isr16550.dll"));
_tcscpy(pHWHead->ser16550.RegIsrDll, TEXT("xrisr.dll"));
_tcscpy(pHWHead->ser16550.RegIsrHandler, TEXT("ISRHandler"));
//pHWHead->dwDevIndex;
if ( RegQueryValueEx(hKey, L"DevIndex", NULL, &kvaluetype,
(LPBYTE)&pHWHead->dwDevIndex, &datasize) )
{
DEBUGMSG (ZONE_INIT | ZONE_ERROR,
(TEXT("Failed to get DevIndex value, Ser_GetRegistryData failed\r\n")));
RegCloseKey (hKey);
return(FALSE);
}
//pHWHead->dwInterfaceType = dwi.dwInterfaceType;
if ( RegQueryValueEx(hKey, L"InterfaceType", NULL, &kvaluetype,
(LPBYTE)&pHWHead->dwInterfaceType, &datasize) )
{
DEBUGMSG (ZONE_INIT | ZONE_ERROR,
(TEXT("Failed to get InterfaceType value, Ser_GetRegistryData failed\r\n")));
RegCloseKey (hKey);
return(FALSE);
}
// pHWHead->dwBusNumber = dwi.dwBusNumber;
if ( RegQueryValueEx(hKey, L"BusNumber", NULL, &kvaluetype,
(LPBYTE)&pHWHead->dwBusNumber, &datasize) )
{
DEBUGMSG (ZONE_INIT | ZONE_ERROR,
(TEXT("Failed to get BusNumber value, Ser_GetRegistryData failed\r\n")));
RegCloseKey (hKey);
return(FALSE);
}
//pHWHead->dwIOBase = dwi.memWindows[0].dwBase;
if ( RegQueryValueEx(hKey, L"MemBase", NULL, &kvaluetype,
(LPBYTE)&pHWHead->dwMemBase, &datasize) )
{
DEBUGMSG (ZONE_INIT | ZONE_ERROR,
(TEXT("Failed to get MemBase value, Ser_GetRegistryData failed\r\n")));
RegCloseKey (hKey);
return(FALSE);
}
//pHWHead->dwIOLen = dwi.memWindows[0].dwLen;
if ( RegQueryValueEx(hKey, L"MemLength", NULL, &kvaluetype,
(LPBYTE)&pHWHead->dwMemLen, &datasize) )
{
DEBUGMSG (ZONE_INIT | ZONE_ERROR,
(TEXT("Failed to get MemLength value, Ser_GetRegistryData failed\r\n")));
RegCloseKey (hKey);
return(FALSE);
}
//g_dwRegStride;
if ( RegQueryValueEx(hKey, L"RegStride", NULL, &kvaluetype,
(LPBYTE)&g_dwRegStride, &datasize) )
{
DEBUGMSG (ZONE_INIT | ZONE_ERROR,
(TEXT("Failed to get RegStride value, Ser_GetRegistryData failed\r\n")));
RegCloseKey (hKey);
return(FALSE);
}
//pHWHead->dwPortInstanceOnChip; // for limiting the access to Config Reg to 1st port only
if ( RegQueryValueEx(hKey, L"PortInstanceOnChip", NULL, &kvaluetype,
(LPBYTE)&pHWHead->dwPortInstanceOnChip, &datasize) )
{
DEBUGMSG (ZONE_INIT | ZONE_ERROR,
(TEXT("Failed to get dwPortInstanceOnChip value, Ser_GetRegistryData failed\r\n")));
RegCloseKey (hKey);
return(FALSE);
}
RegCloseKey (hKey);
DEBUGMSG (1|ZONE_INIT,
(TEXT("SerInit - Devindex %d, SysIntr %d, IOB %X, IOLen %X \r\n"),
pHWHead->dwDevIndex, pHWHead->dwSysIntr, pHWHead->dwMemBase, pHWHead->dwMemLen));
return ( 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.
PHWOBJ pHWObj // @parm Pointer to our own HW OBJ for this device
)
{
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.
// 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 )
return( NULL );
if ( ! Ser_GetRegistryData(pHWHead, (LPCTSTR)Identifier) ) {
DEBUGMSG (ZONE_INIT|ZONE_ERROR,
(TEXT("SerInit - Unable to read registry data. Failing Init !!! \r\n")));
goto ALLOCFAILED;
}
pHWHead->pBaseAddress = Ser_InternalMapRegisterAddresses(pHWHead->dwInterfaceType,
pHWHead->dwBusNumber,
pHWHead->dwMemBase,
pHWHead->dwMemLen,
&pHWHead->ser16550.pVirtualStaticAddr);
pHWHead->pMddHead = pMddHead;
pHWHead->pHWObj = pHWObj;
pHWHead->cOpenCount = 0;
// Legacy - We have 2 identical fields becausw registry used to contain IRQ
pHWHead->pHWObj->dwIntID = pHWHead->dwSysIntr;
DEBUGMSG (1|ZONE_INIT,
(TEXT("SerInit - SYSINTR %d\r\n"), pHWHead->pHWObj->dwIntID));
// 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;
pHWHead->fIRMode = FALSE; // Select wired by default
{
// Init 16550 info, register stride is 1
DEBUGMSG (ZONE_INIT, (TEXT("SerInit - Init 16550 data\r\n")));
XRSL_Init( pHWHead, pHWHead->pBaseAddress, (UCHAR)g_dwRegStride,
EvaluateEventFlag, pMddHead, (PLOOKUP_TBL)&BaudTable);
DEBUGMSG (ZONE_INIT,
(TEXT("SerInit - Disabling UART Power\r\n")));
SerSetOutputMode(pHWHead, FALSE, FALSE );
}
#ifdef WAKEUPONTHISDEVICE
pHWHead->LastDx=D0;
#endif
return (pHWHead);
ALLOCFAILED:
if ( pHWHead->pBaseAddress )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -