?? ser2410_ser.c
字號:
//
// 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.
//
/*++
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.
Module Name:
Abstract:
Notes:
--*/
#define EXAMINE_BOOTARGS
#define DEBUGMODE 0
#include <windows.h>
#include <types.h>
#include <ceddk.h>
#include <memory.h>
#include <serhw.h>
#include <ser16550.h>
#include <hw16550.h>
#include <nkintr.h>
#include <devload.h>
#include <windev.h>
#include <notify.h>
#include "S2410.h"
#define USERDBG 1
#ifdef EXAMINE_BOOTARGS
#include <bootarg.h>
#include <oalintr.h>
#include <pc.h>
#endif
#include <ser2410.h>
#undef ZONE_INIT
#include <serdbg.h>
#define BAUD_TABLE_SIZE 23
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};
// Miscellaneous internal routines.
PUCHAR
static
Ser_InternalMapRegisterAddresses(
ULONG HWAddress,
ULONG Size
)
{
PUCHAR ioPortBase;
ULONG inIoSpace = 1;
PHYSICAL_ADDRESS ioPhysicalBase = { HWAddress, 0};
RETAILMSG(DEBUGMODE, (TEXT("+ Ser_InternalMapRegisterAddresses : HalTranslateBusAddress\r\n")));
if ( HalTranslateBusAddress(Isa, 0, ioPhysicalBase, &inIoSpace, &ioPhysicalBase) ) {
DEBUGMSG(1, (TEXT("Ser_InternalMapRegisterAddresses : HalTranslateBusAddress - OK\r\n")));
if ( !inIoSpace ) {
DEBUGMSG(1, (TEXT("Ser_InternalMapRegisterAddresses : ! IO Space\r\n")));
if ( (ioPortBase = (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);
}
} else {
DEBUGMSG(1, (TEXT("Ser_InternalMapRegisterAddresses : IO Space\r\n")));
ioPortBase = (PUCHAR)ioPhysicalBase.LowPart;
}
} else {
DEBUGMSG(ZONE_INIT | ZONE_ERROR, (TEXT("Error translating I/O Ports.\r\n")));
return (NULL);
}
RETAILMSG(DEBUGMODE, (TEXT("- Ser_InternalMapRegisterAddresses : %d\r\n"),ioPortBase ));
return (ioPortBase);
}
/*
* 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.
PS2410_UART_INFO pHWHead2 = (PS2410_UART_INFO)pHWHead;
RETAILMSG (DEBUGMODE, (TEXT("SerSetOutputMode : ")));
if(UseIR)
{
RETAILMSG (DEBUGMODE, (TEXT("IRDA \r\n")));
SETREG(pHWHead2,rULCON,SER2410_IRMODE_MASK); // Infra-red mode enable.
}
else
{
RETAILMSG (DEBUGMODE, (TEXT("SERIAL \r\n")));
CLEARREG(pHWHead2,rULCON,SER2410_IRMODE_MASK); // Infra-red mode enable.
}
}
/*++
*******************************************************************************
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
LONG regError;
HKEY hKey;
DWORD dwDataSize = GCI_BUFFER_SIZE;
RETAILMSG(DEBUGMODE, (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 );
}
// 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)(&pHWHead->dwDevIndex),
&dwDataSize);
if ( regError == ERROR_SUCCESS ) {
dwDataSize = PC_REG_IRQ_VAL_LEN;
regError = RegQueryValueEx(
hKey,
PC_REG_IRQ_VAL_NAME,
NULL,
NULL,
(LPBYTE)(&pHWHead->dwIRQ),
&dwDataSize);
}
if ( regError == ERROR_SUCCESS ) {
dwDataSize = PC_REG_IOBASE_VAL_LEN;
regError = RegQueryValueEx(
hKey,
PC_REG_IOBASE_VAL_NAME,
NULL,
NULL,
(LPBYTE)(&pHWHead->dwIOBase),
&dwDataSize);
}
if ( regError == ERROR_SUCCESS ) {
dwDataSize = PC_REG_IOLEN_VAL_LEN;
regError = RegQueryValueEx(
hKey,
PC_REG_IOLEN_VAL_NAME,
NULL,
NULL,
(LPBYTE)(&pHWHead->dwIOLen),
&dwDataSize);
}
RegCloseKey (hKey);
if ( regError != ERROR_SUCCESS ) {
RETAILMSG(DEBUGMODE, (TEXT("Failed to get serial registry values, Error 0x%X\r\n"),regError));
return ( FALSE );
}
RETAILMSG (DEBUGMODE,(TEXT("SerInit - Devindex %d, IRQ %d, IOB %X, IOLen %X \r\n"),
pHWHead->dwDevIndex, pHWHead->dwIRQ, pHWHead->dwIOBase, pHWHead->dwIOLen));
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(
BOOL bIR,
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;
#ifdef EXAMINE_BOOTARGS
PVOID *ppBootArgs = NULL; // Pointer to pointer to bootargs.
PHYSICAL_ADDRESS PhysicalAddress = {0,0};
#endif
// 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.
RETAILMSG(DEBUGMODE, (TEXT("SerInit - !!! \r\n")));
// 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->dwIOBase, pHWHead->dwIOLen);
#ifdef EXAMINE_BOOTARGS
// Allocate a pointer to our bootargs since they may indicate that we don't have
// access to the hardware resource.
// First, map the bootargs pointer itself. Note that I'm reading/writing
// directly on the physical address. I can do this since I know this is CEPC and
// know the adress is not in IO space. For OEM platforms you would want to do
// HalTranslateBusAddress first.
PhysicalAddress.LowPart = BOOT_ARG_PTR_LOCATION & ~0x80000000;
if ( ppBootArgs = MmMapIoSpace(PhysicalAddress, sizeof( PVOID ), TRUE ) ) {
DEBUGMSG (ZONE_INIT,
(TEXT("SerInit - ppBootArgs (%X) at %X\r\n"),
PhysicalAddress.LowPart, ppBootArgs ));
} else {
DEBUGMSG (ZONE_INIT | ZONE_ERROR,
(TEXT("SerInit - ppBootArgs failure at %X\r\n"), PhysicalAddress.LowPart ));
goto ALLOCFAILED;
}
// Now map the bootargs structure itself
PhysicalAddress.LowPart = (DWORD) *ppBootArgs;
if ( pHWHead->pBootArgs = MmMapIoSpace(PhysicalAddress, sizeof(BOOT_ARGS), TRUE ) ) {
DEBUGMSG (ZONE_INIT,
(TEXT("SerInit - pBootArgs (%X) at %X\r\n"),
PhysicalAddress.LowPart, pHWHead->pBootArgs ));
} else {
DEBUGMSG (ZONE_INIT | ZONE_ERROR,
(TEXT("SerInit - pBootArgs failure at %X\r\n"),
(DWORD)PhysicalAddress.LowPart));
goto ALLOCFAILED;
}
// We no longer need ppBootArgs
MmUnmapIoSpace( ppBootArgs, sizeof(PVOID) );
#endif // EXAMINE_BOOTARGS
pHWHead->pMddHead = pMddHead;
pHWHead->pHWObj = pHWObj;
pHWHead->cOpenCount = 0;
RETAILMSG(DEBUGMODE,(TEXT("SerInit - IRQ %d = SYSINTR %d\r\n"),
pHWHead->dwIRQ, 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 = bIR;
pHWHead->s2410COM.UseIrDA = bIR;
#ifdef EXAMINE_BOOTARGS
// Don't actually init the hardware if it is being used for debugging
if ( ((pHWHead->pBootArgs->ucComPort == 1) && (pHWHead->dwIOBase == COM1_BASE)) ||
((pHWHead->pBootArgs->ucComPort == 2) && (pHWHead->dwIOBase == COM2_BASE)) ||
((pHWHead->pBootArgs->ucComPort == 3) && (pHWHead->dwIOBase == COM3_BASE)) ||
((pHWHead->pBootArgs->ucComPort == 4) && (pHWHead->dwIOBase == COM4_BASE)) ) {
DEBUGMSG (ZONE_INIT|ZONE_ERROR, (TEXT("\r\nSerInit - Skipping hardware init of debug port\r\n\r\n")));
} else
#endif
{
DEBUGMSG (ZONE_INIT|USERDBG, (TEXT("SerInit - Init 16550 data\r\n")));
SL_Init( pHWHead, pHWHead->pBaseAddress, 1,
EvaluateEventFlag, pMddHead, (PLOOKUP_TBL)&BaudTable);
DEBUGMSG (ZONE_INIT,
(TEXT("SerInit - Disabling UART Power\r\n")));
SerSetOutputMode(pHWHead, FALSE, FALSE );
// SerSetOutputMode(pHWHead, bIR, ~bIR);
}
return (pHWHead);
ALLOCFAILED:
if ( pHWHead->pBaseAddress )
VirtualFree(pHWHead->pBaseAddress, 0, MEM_RELEASE);
if ( ppBootArgs )
MmUnmapIoSpace( ppBootArgs, sizeof( PVOID ) );
if ( pHWHead->pBootArgs )
MmUnmapIoSpace( pHWHead->pBootArgs, sizeof(BOOT_ARGS) );
LocalFree(pHWHead);
return (NULL);
}
PVOID
SerInitSerial(
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
)
{
RETAILMSG(DEBUGMODE, (TEXT("SerInitSerial\r\n")));
return (SerInit(FALSE, Identifier, pMddHead, pHWObj));
}
PVOID
SerInitIR(
ULONG Identifier, // @parm Device identifier.
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -