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

📄 xrcom16550.c

📁 wince 5.0下 实现PCI8串口卡驱动
💻 C
📖 第 1 页 / 共 2 页
字号:
////////////////////////////////////////
//(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 + -