📄 ser_card.c
字号:
// @func BOOL | SC_PostInit | This routine does nothing, because
// we do our init/postinit processing from SC_Open
//
BOOL
SC_PostInit(
PVOID pHead // @parm PVOID returned by SC_init.
)
{
#ifdef DEBUG
PSER_CARD_INFO pHWHead = (PSER_CARD_INFO)pHead;
DEBUGMSG (ZONE_FUNCTION, (TEXT("SC_POSTINIT\r\n") ));
#endif
return (TRUE);
}
//
// @doc OEM
// @func ULONG | SC_Close | This routine closes the device identified
// by pHead.
//
// @rdesc The return value is 0 if successful, -1 if failed.
//
ULONG
SC_Close(
PVOID pHead // @parm PVOID returned by SC_Init.
)
{
PSER_CARD_INFO pHWHead = (PSER_CARD_INFO)pHead;
ULONG uTries;
ULONG retval = 0;
DEBUGMSG (ZONE_FUNCTION, (TEXT("+SC_CLOSE\r\n") ));
if ( pHWHead->cOpenCount ) {
pHWHead->cOpenCount--;
if ( ! pHWHead->cOpenCount ) {
// while we are still transmitting, sleep.
uTries = 0;
// If this close is not cause by PowerCycle . We will do follows.
// otherwise the IO port disappeareed after PCMCIA power cycle.
if (pHWHead->fPowerCycle!=TRUE ) {
while ( ((pHWHead->ser16550.IER = READ_PORT_UCHAR(pHWHead->ser16550.pIER))
& SERIAL_IER_THR) && // indicates TX in progress
(uTries++ < 100) && // safety net
!(pHWHead->ser16550.LSR & SERIAL_LSR_TEMT) // indicates FIFO not yet empty
) {
DEBUGMSG (ZONE_CLOSE,
(TEXT("SerClose, TX in progress, IER 0x%X, LSR 0x%X\r\n"),
*pHWHead->ser16550.pIER, pHWHead->ser16550.LSR));
Sleep(10);
}
// Note: We can not call SL_Close when PCMCIA close the driver after power cycle.
// because SL_Close access IO to mask all the interrupt. Of cause this moment
// IO space disappeared.
// It is OK that we do not call SL_Close here. Only thing is wrong is OpenCount..
// But we always call SL_Init & SL_Open or SL_Close & SL_Deinit togather. And
// SL_Deinit does not checking OpenCound So OpenCound will be initial to zero in SL_Init.
SL_Close( pHWHead );
};
// NOTE : To save power, SL_Init was postponed and called
// from SC_Open. To maintain symmetry, I then need to call
// SL_Deinit here, otherwise we leak handles and perhaps
// do other bad things.
SL_Deinit( pHWHead );
// Free up all PCMCIA objects/handles by deregistering
CallCardServices(CardDeregisterClient) (pHWHead->hCardClient);
} else {
// If someone else still has device open, we don't do anything.
DEBUGMSG (ZONE_CLOSE|ZONE_ERROR, (TEXT("SC_CLOSE : Open Count > 1, do nothing\r\n")) );
}
} else {
DEBUGMSG (ZONE_CLOSE|ZONE_ERROR, (TEXT("SC_CLOSE : Open Count == 0, not performing close\r\n")) );
retval = (ULONG)-1;
}
DEBUGMSG (ZONE_FUNCTION, (TEXT("+SC_CLOSE\r\n") ));
return (retval);
}
//
// @doc OEM
// @func VOID | SC_GetCommProperties | Retrieves Comm Properties.
//
// @rdesc None.
//
VOID
SC_GetCommProperties(
PVOID pHead, // @parm PVOID returned by SC_Init.
LPCOMMPROP pCommProp // @parm Pointer to receive COMMPROP structure.
)
{
PSER_CARD_INFO pHWHead = (PSER_CARD_INFO)pHead;
memcpy(pCommProp, &pHWHead->CommProp, sizeof(COMMPROP));
return;
}
//
// @doc OEM
// @func BOOL | SC_SetBaudRate |
// This routine sets the baud rate of the device.
//
// @rdesc None.
//
BOOL
SC_SetBaudRate(
PVOID pHead, // @parm PVOID returned by SC_Init
ULONG BaudRate // @parm ULONG representing decimal baud rate.
)
{
PSER_CARD_INFO pHWHead = (PSER_CARD_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 ( ! SC_SetIRBaudRate( pHWHead, (UINT16)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
SL_SetBaudRate( pHead, BaudRate );
return ( TRUE );
}
//
// @doc OEM
// @func BOOL | SC_PowerOff |
// Called by driver to turn off power to serial port.
//
// @rdesc TRUE if success, FALSE if fail.
//
BOOL
SC_PowerOff(
PVOID pHead // @parm PVOID returned by SC_Init.
)
{
return (TRUE);
}
//
// @doc OEM
// @func BOOL | SC_PowerOn |
// Called by driver to turn on power to serial port.
//
// @rdesc TRUE if success, FALSE if fail.
//
BOOL
SC_PowerOn(
PVOID pHead // @parm PVOID returned by SC_Init.
)
{
PSER_CARD_INFO pHWHead = (PSER_CARD_INFO)pHead;
pHWHead->fPowerCycle=TRUE;
return (TRUE);
}
//
// @doc OEM
// @func BOOL | SC_EnableIR | This routine enables the ir.
//
// @rdesc Returns FALSE since IR not supported on PCMCIA.
//
BOOL
SC_EnableIR(
PVOID pHead, // @parm PVOID returned by SC_init.
ULONG BaudRate // @parm BaudRate
)
{
return (FALSE);
}
//
// @doc OEM
// @func BOOL | SC_DisableIR | This routine disables the ir.
//
// @rdesc Returns TRUE if successful, FALSE if failed.
//
BOOL
SC_DisableIR(
PVOID pHead // @parm PVOID returned by SC_init.
)
{
return (TRUE);
}
//
// @doc OEM
// @func BOOL | SC_Deinit | This routine disables the ir.
//
// @rdesc Returns TRUE if successful, FALSE if failure.
//
BOOL
SC_Deinit(
PVOID pHead // @parm PVOID returned by SC_init.
)
{
PSER_CARD_INFO pHWHead = (PSER_CARD_INFO)pHead;
if ( !pHWHead )
return (FALSE);
// Make sure device is closed before doing DeInit
if ( pHWHead->cOpenCount )
SC_Close( pHead );
// Free the HWObj
LocalFree(pHWHead->pHWObj);
LocalFree(pHWHead);
return (TRUE);
}
//
// @doc OEM
// @func BOOL | SC_DisableIR | This routine disables the ir.
//
// @rdesc Returns TRUE if successful, FALSEotherwise.
//
BOOL
SC_Open(
PVOID pHead // @parm PVOID returned by SC_init.
)
{
PSER_CARD_INFO pHWHead = (PSER_CARD_INFO)pHead;
STATUS status;
DEBUGMSG (ZONE_FUNCTION, (TEXT("+SC_OPEN\r\n") ));
// Lets do the rest of the card initialization
if ( ! InitPCMCIACard( pHWHead, pHWHead->pMddHead ) ) {
DEBUGMSG (ZONE_OPEN|ZONE_ERROR, (TEXT("SC_OPEN - Failed to init card\r\n")));
return (FALSE);
}
// Some PCMCIA cards require an additional delay upon reset. We
// read this value from the registry on card init and sleep here.
DEBUGMSG (ZONE_INIT,(TEXT("SC_OPEN - Sleep %d ms\r\n"),
pHWHead->ResetDelay));
Sleep(pHWHead->ResetDelay);
// Init 16550 info. Note that we do both SL_INIT and SL_OPEN
// This is an unfortunate side effect of PCMCIA. As soon as
// I do a CardRequestConfig, I start drawing power. So we postpone
// that till here (in the open). But, SL_INIT needs our card
// address space in his init routine, and we don't get the address
// till after the request config. So till we come up with a better
// idea for power enable/disable on PCMCIA, we will have to couple
// SL_INIT and SL_OPEN.
SL_Init( pHWHead, pHWHead->pCardIOWin, (UINT8)pHWHead->IO_Granularity,
EvaluateEventFlag, pHWHead->pMddHead, NULL);
DEBUGMSG (ZONE_INIT, (TEXT("SC_OPEN - Init 16550 data\r\n")));
// SL_Init sets up pointers to all the UART registers,
// but some cards don't have a scratch register. So we need to override
// the scratch pointer just in case someone tries to use this register.
if ( pHWHead->NoScratchPad )
pHWHead->ser16550.pScratch = &pHWHead->FakeScratchPad;
// Make sure the card is responding correctly. Some cards have had
// problems where all registers read back as 0. This can cause us to
// infinite loop handling serial interrupts (0 indicates interrupt in
// the ISR). So we will write to the scratch register and make sure
// we can read the value back.
if ( !pHWHead->NoScratchPad ) {
#define SCRATCH_PATTERN 0xC6
WRITE_PORT_UCHAR(pHWHead->ser16550.pScratch, SCRATCH_PATTERN);
// Stick something else on bus, otherwise
// even if no UART is there we may read back the C6
WRITE_PORT_UCHAR(pHWHead->ser16550.pIER, 0x0);
// And now see if the scratch register was really there.
if ( SCRATCH_PATTERN != READ_PORT_UCHAR(pHWHead->ser16550.pScratch) ) {
// Card is not responding. Return error for the open.
DEBUGMSG (ZONE_OPEN|ZONE_ERROR, (TEXT("SC_OPEN - ERROR : UART not responding\r\n")));
// Free up all PCMCIA objects/handles by deregistering
CallCardServices(CardDeregisterClient) (pHWHead->hCardClient);
return (FALSE);
}
}
pHWHead->ser16550.ChipID = CHIP_ID_16550;
// Register to receive PCMCIA interrupts for this card
status = CallCardServices(CardRequestIRQ)( pHWHead->hCardClient,
pHWHead->hCardSock,
(CARD_ISR)SerialEventHandler,
(UINT32)pHWHead->pMddHead );
DEBUGMSG (ZONE_INIT, (TEXT("RequestIRQ returned 0x%X\r\n"),
status ));
// Now that interrupts are hooked, we can actually finish
// initing the UART and open it for use.
SL_PostInit( pHWHead );
SL_Open( pHWHead );
DEBUGMSG (ZONE_INIT, (TEXT("SC_OPEN - Selecting Non IR Mode\r\n")));
pHWHead->fIRMode = FALSE; // Select wired by default
SC_SetIRMode(pHWHead, pHWHead->fIRMode );
if (!(pHWHead->cOpenCount)) { // If it it first open. Clean the flag
pHWHead->fPowerCycle = FALSE;
}
// OK, the device is open, so increment the counter.
pHWHead->cOpenCount++;
DEBUGMSG (ZONE_FUNCTION, (TEXT("-SC_OPEN\r\n") ));
return (TRUE);
}
const
HW_VTBL SerCardIoVTbl = {
SC_Init,
SC_PostInit,
SC_Deinit,
SC_Open,
SC_Close,
SL_GetInterruptType,
SL_RxIntr,
SL_TxIntrEx,
SL_ModemIntr,
SL_LineIntr,
SL_GetRxBufferSize,
SC_PowerOff,
SC_PowerOn,
SL_ClearDTR,
SL_SetDTR,
SL_ClearRTS,
SL_SetRTS,
SC_EnableIR,
SC_DisableIR,
SL_ClearBreak,
SL_SetBreak,
SL_XmitComChar,
SL_GetStatus,
SL_Reset,
SL_GetModemStatus,
SC_GetCommProperties,
SL_PurgeComm,
SL_SetDCB,
SL_SetCommTimeouts,
SL_Ioctl};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -