serial.c

来自「i.mx27 soc for wince 6.0」· C语言 代码 · 共 981 行 · 第 1/3 页

C
981
字号
//------------------------------------------------------------------------------
//
//  Copyright (c) Microsoft 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.
//
//------------------------------------------------------------------------------
//
//  Copyright (C) 2004, Motorola Inc. All Rights Reserved
//
//------------------------------------------------------------------------------
//
//  Copyright (C) 2004-2006, Freescale Semiconductor, Inc. All Rights Reserved.
//  THIS SOURCE CODE, AND ITS USE AND DISTRIBUTION, IS SUBJECT TO THE TERMS
//  AND CONDITIONS OF THE APPLICABLE LICENSE AGREEMENT 
//
//------------------------------------------------------------------------------
//
//  File:  serial.c
//
//   This file implements the device specific functions for zeus serial device.
//
//------------------------------------------------------------------------------



//------------------------------------------------------------------------------
// INCLUDE FILES  
//------------------------------------------------------------------------------

#include <windows.h>
#include <types.h>
#include <memory.h>
#include <nkintr.h>
#include <serhw.h>
#include <memory.h>
#include <notify.h>
#include <devload.h>
#include <ceddk.h>
#include <windev.h>
#include <serdbg.h>
#include <uart.h>
#include <csp.h>
#include <serial.h>

//------------------------------------------------------------------------------
// External Functions
//-----------------------------------------------------------------------------
extern BOOL BSPUartGetType( ULONG HWAddr, uartType_c * pType );

//------------------------------------------------------------------------------
// MACRO DEFINITIONS 
//------------------------------------------------------------------------------
#define BAUD_TABLE_SIZE 23

//------------------------------------------------------------------------------
// Local Variables
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},
    {12800,     9},
    {14400,     8},
    {19200,     6},
    {23040,     5},
    {28800,     4},
    {38400,     3},
    {57600,     2},
    {115200,    1}
};

static const LOOKUP_TBL BaudTable = {BAUD_TABLE_SIZE, (PAIRS *) BaudPairs};

//------------------------------------------------------------------------------
// Local Functions
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
//
// Function: Ser_InternalMapRegisterAddresses
//
//  This function retrieves the current
//  properties of the communications device.
//
// Parameters:
//      HWAddress
//          [in] physical address of the hardware.
//      Size
//          [in] how much larger the address window is.
//
// Returns:
//      This function returns the base virtual address
//      that maps the base physical address for the range.
//
//-----------------------------------------------------------------------------
PUCHAR static Ser_InternalMapRegisterAddresses( ULONG HWAddress, ULONG Size )
{
    PUCHAR ioPortBase;
    ULONG inIoSpace = 1;
    PHYSICAL_ADDRESS ioPhysicalBase = {HWAddress, 0};

    DEBUGMSG(ZONE_FUNCTION, (TEXT("Ser_InternalMapRegisterAddresses : HalTranslateBusAddress 0x%x\r\n"), HWAddress));
    if (HalTranslateBusAddress(Isa, 0, ioPhysicalBase, &inIoSpace, &ioPhysicalBase)) {
        if (!inIoSpace) {
            if ((ioPortBase = (PUCHAR)MmMapIoSpace(ioPhysicalBase, Size, FALSE)) == NULL) {
                DEBUGMSG(ZONE_ERROR, (TEXT("Error mapping I/O Ports\r\n")));
                return (NULL);
            }
        } else {
            ioPortBase = (PUCHAR)ioPhysicalBase.LowPart;
        }
    } else {
        DEBUGMSG(ZONE_ERROR, (TEXT("Error translating I/O Ports.\r\n")));
        return (NULL);
    }

    DEBUGMSG(ZONE_FUNCTION, (TEXT("Ser_InternalMapRegisterAddresses : %d\r\n"), ioPortBase));

    return (ioPortBase);
}


//-----------------------------------------------------------------------------
//
// Function: Ser_GetRegistryData
//
//  This function takes the registry path provided
//  to COM_Init and uses it to find this requested comm
//  port's DeviceArrayIndex, the IOPort Base Address,
//  and the interrupt number.
//
// Parameters:
//      pSerHead
//          [in] pointer to PSER_INFO structure.
//      regKeyPath
//          [in] the registry path passed in to COM_Init.
//
// Returns:
//      TRUE if success. FALSE if failure.
//
//-----------------------------------------------------------------------------
static BOOL Ser_GetRegistryData( PSER_INFO pSerHead, LPCTSTR regKeyPath )
{
    LONG regError;
    HKEY hKey;
    DWORD dwDataSize;

    DEBUGMSG(ZONE_FUNCTION, (TEXT("Ser_GetRegistryData+: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_ERROR, (TEXT("Failed to open device key\r\n")));
        return (FALSE);
    }

    // Okay, we're finally ready to try and load our registry data.
    dwDataSize = PC_REG_DEVINDEX_VAL_LEN;
    regError = RegQueryValueEx(
                              hKey,
                              PC_REG_DEVINDEX_VAL_NAME,
                              NULL,
                              NULL,
                              (LPBYTE)(&pSerHead->dwDevIndex),
                              &dwDataSize);

    if (regError == ERROR_SUCCESS) {
        dwDataSize = PC_REG_IOBASE_VAL_LEN;
        regError = RegQueryValueEx(
                                  hKey,
                                  PC_REG_IOBASE_VAL_NAME,
                                  NULL,
                                  NULL,
                                  (LPBYTE)(&pSerHead->dwIOBase),
                                  &dwDataSize);
    }

    if (regError == ERROR_SUCCESS) {
        dwDataSize = PC_REG_IOLEN_VAL_LEN;
        regError = RegQueryValueEx(
                                  hKey, 
                                  PC_REG_IOLEN_VAL_NAME, 
                                  NULL, 
                                  NULL,
                                  (LPBYTE)(&pSerHead->dwIOLen), 
                                  &dwDataSize);
    }

    RegCloseKey (hKey);

    if (regError != ERROR_SUCCESS) {
        DEBUGMSG(ZONE_ERROR, (TEXT("Failed to get serial registry values, Error 0x%X\r\n"), regError));
        return (FALSE);
    }

    DEBUGMSG(ZONE_FUNCTION, (TEXT("Ser_GetRegistryData-\r\n")));

    return (TRUE); 
}


//-----------------------------------------------------------------------------
//
// Function: SerInit
//
//  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.
//
// Parameters:
//      bIR 
//          [in] Is IR mode used.
//      Identifier 
//          [in] Device identifier.
//      pMDDContext 
//          [in] First argument to mdd callbacks.
//      pHWObj 
//          [in] Pointer to our own HW OBJ for this device.
//
// Returns:  
//      The return value is a PVOID to be passed back 
//      into the HW dependent layer when HW functions are 
//      called.
//
//-----------------------------------------------------------------------------
static PVOID SerInit( BOOL bIR, ULONG Identifier, PVOID pMDDContext, PHWOBJ pHWObj )
{
    PSER_INFO pSerHead;
    BOOL InitError = FALSE;
    ULONG irq;
    DEVICE_LOCATION devLoc;
    uartType_c type;
    DWORD dwSources;
    DWORD dwTransferred;

    DEBUGMSG(ZONE_FUNCTION, (TEXT("SerInit+\r\n")));

    // Allocate for our main data structure and one of it's fields.
    pSerHead = (PSER_INFO)LocalAlloc(LMEM_ZEROINIT|LMEM_FIXED, sizeof(SER_INFO));

    if (!pSerHead)
        return(NULL);

    if (!Ser_GetRegistryData(pSerHead, (LPCTSTR)Identifier)) {
        DEBUGMSG(ZONE_ERROR, (TEXT("SerInit - Unable to read registry data!!\r\n")));
        InitError = TRUE;
    }

    if (!InitError){
        pSerHead->pBaseAddress = Ser_InternalMapRegisterAddresses(pSerHead->dwIOBase, pSerHead->dwIOLen);

        pSerHead->pHWObj = pHWObj;
        pSerHead->cOpenCount = 0;

        DEBUGMSG(ZONE_FUNCTION, (TEXT("SerInit \r\n")));

        if (!BSPUartGetType(pSerHead->dwIOBase, &type)) {
            DEBUGMSG(ZONE_ERROR, (TEXT("ERROR: Failed to obtain uart info.\r\n")));
            return (NULL);
        }
	
        // Use kernel IOCTL to translate the UART base address into an IRQ since
        // the IRQ value differs based on the SoC. Note that DEVICE_LOCATION
        // fields except IfcType and LogicalLoc are ignored for internal SoC 
        // components.
        devLoc.IfcType = Internal;
        devLoc.LogicalLoc = pSerHead->dwIOBase;

        if (!KernelIoControl(IOCTL_HAL_REQUEST_IRQ, &devLoc, sizeof(devLoc),
            &irq, sizeof(irq), NULL))
        {
            ERRORMSG(1, (_T("Cannot obtain UART IRQ!\r\n")));
            LocalFree(pSerHead);
            DEBUGMSG(ZONE_ERROR, (TEXT("SerInit - Initialization failed!!\r\n")));
            return (NULL);
        }

        // Use kernel IOCTL to translate the UART base address into an IRQ since
        // the IRQ value differs based on the SoC. Note that DEVICE_LOCATION
        // fields except IfcType and LogicalLoc are ignored for internal SoC 
        // components.
        if (!KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR, &irq, sizeof(DWORD), 
        &pSerHead->pHWObj->dwIntID, sizeof(DWORD), NULL)) {
            DEBUGMSG(ZONE_ERROR, (TEXT("ERROR: Failed to obtain sysintr value for UART interrupt.\r\n")));
            LocalFree(pSerHead);
            DEBUGMSG(ZONE_ERROR, (TEXT("SerInit - Initialization failed!!\r\n")));
            return (NULL);
        }

        if (!bIR) {
            dwSources = pSerHead->pHWObj->dwIntID;
            if(KernelIoControl(IOCTL_HAL_ENABLE_WAKE, &dwSources, sizeof(DWORD),
                NULL, 0, &dwTransferred) == FALSE)
            {
                DEBUGMSG(ZONE_ERROR, (TEXT("ERROR: IOCTL_HAL_ENABLE_WAKE failed\r\n")));
                LocalFree(pSerHead);
                DEBUGMSG(ZONE_ERROR, (TEXT("SerInit - Initialization failed!!\r\n")));
                return (NULL);
            }
        }
        DEBUGMSG(ZONE_FUNCTION, (TEXT("SerInit - bIR=%d, dwIntID=%d, irq=%d\r\n"), bIR, pSerHead->pHWObj->dwIntID, irq));

        // Set up our Comm Properties data    
        pSerHead->CommProp.wPacketLength = 0xffff;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?