📄 mdd.c
字号:
pSerialHead->fAbortRead = 0;
if ( WAIT_TIMEOUT == WaitForSingleObject (pSerialHead->hReadEvent,
Timeout) ) {
// Timeout
break;
}
// Since ticks is a ULONG this handles wrap.
Ticks = GetTickCount() - Ticks;
TimeSpent += Ticks;
// In the absense of WaitForMultipleObjects, we use flags to
// handle errors/aborts. Check for aborts or asynchronous closes.
if ( pSerialHead->fAbortRead ) {
DEBUGMSG(ZONE_USR_READ,(TEXT("COM_Read - Aborting read\r\n")));
break;
}
if ( !pSerialHead->OpenCnt ) {
DEBUGMSG(ZONE_USR_READ|ZONE_ERROR,
(TEXT("COM_Read - device was closed\r\n")));
SetLastError(ERROR_INVALID_HANDLE);
break;
}
}
}
DEBUGMSG (ZONE_USR_READ, (TEXT("ReceiveBytes exiting\r\n")));
if ( pSerialHead->DCB.fInX && pSerialHead->SentXoff &&
(pSerialHead->DCB.XoffLim <
(RxLength(pSerialHead) - RxBytesAvail(pSerialHead))) ) {
PHWOBJ pHWObj = pSerialHead->pHWObj;
DEBUGMSG (ZONE_FLOW, (TEXT("Sending XON\r\n")));
pSerialHead->SentXoff = 0;
if ( !pSerialHead->DCB.fTXContinueOnXoff ) {
pSerialHead->StopXmit = 0;
}
pHWObj->pFuncTbl->HWXmitComChar(pSerialHead->pHWHead,
pSerialHead->DCB.XonChar);
}
// Are we below the flow control limits?
if ( 2*RxBytesAvail(pSerialHead) < RxLength(pSerialHead) ) {
// When buffer is less then 1/2 full we set RTS/DTR
if ( pSerialHead->RtsFlow &&
(pSerialHead->DCB.fRtsControl == RTS_CONTROL_HANDSHAKE) ) {
DEBUGMSG (ZONE_USR_READ|ZONE_FLOW,
(TEXT("DTR_CONTROL_HANDSHAKE Setting RTS\r\n")));
pSerialHead->RtsFlow = 0;
pFuncTbl->HWSetRTS(pHWHead);
}
if ( pSerialHead->DtrFlow &&
(pSerialHead->DCB.fDtrControl == DTR_CONTROL_HANDSHAKE) ) {
DEBUGMSG (ZONE_USR_READ|ZONE_FLOW,
(TEXT("DTR_CONTROL_HANDSHAKE Setting DTR\r\n")));
pSerialHead->DtrFlow = 0;
pFuncTbl->HWSetDTR(pHWHead);
}
}
LeaveCriticalSection(&(pSerialHead->ReceiveCritSec1));
DEBUGMSG (ZONE_USR_READ|ZONE_FUNCTION,
(TEXT("-COM_READ: returning %d (total %d, dropped %d,%d)\r\n"),
BytesRead, pSerialHead->RxBytes, pSerialHead->DroppedBytesMDD,pSerialHead->DroppedBytesPDD));
COM_DEC_USAGE_CNT(pOpenHead);
return (BytesRead);
}
/*
@doc EXTERNAL
@func ULONG | COM_Write | Allows application to transmit bytes to the serial port. Exported to users.
*
@rdesc It returns the number of bytes written or -1 if error.
*
*
*/
ULONG
COM_Write(HANDLE pHead, /*@parm [IN] HANDLE returned by COM_Open.*/
PUCHAR pSourceBytes, /*@parm [IN] Pointer to bytes to be written.*/
ULONG NumberOfBytes /*@parm [IN] Number of bytes to be written. */
)
{
PHW_OPEN_INFO pOpenHead = (PHW_OPEN_INFO)pHead;
PHW_INDEP_INFO pSerialHead = pOpenHead->pSerialHead;
ULONG BytesWritten = 0;
ULONG TotalWritten = 0;
PHWOBJ pHWObj = NULL;
PVOID pHWHead = NULL;
PHW_VTBL pFuncTbl = NULL;
ULONG TotalTimeout; // The Total Timeout
ULONG Timeout; // The Total Timeout
ULONG Ticks; // Time for a loop.
ULONG TimeSpent = 0; // How much time have we been waiting?
ULONG WaitReturn;
ULONG PutRet;
DEBUGMSG (ZONE_WRITE|ZONE_FUNCTION,
(TEXT("+COM_WRITE(0x%X, 0x%X, %d)\r\n"), pHead,
pSourceBytes, NumberOfBytes));
// Check validity of handle
if ( !pSerialHead || !pSerialHead->OpenCnt ) {
DEBUGMSG (ZONE_WRITE|ZONE_ERROR,
(TEXT("COM_WRITE, device not open\r\n") ));
SetLastError (ERROR_INVALID_HANDLE);
return (ULONG)-1;
}
// Make sure the caller has access permissions
if ( !(pOpenHead->AccessCode & GENERIC_WRITE) ) {
DEBUGMSG(ZONE_USR_READ|ZONE_ERROR,
(TEXT("COM_Write: Access permission failure x%X\r\n"),
pOpenHead->AccessCode));
SetLastError (ERROR_INVALID_ACCESS);
return (ULONG)-1;
}
#ifdef DEBUG
if ( IsBadReadPtr(pSourceBytes, NumberOfBytes) ) {
DEBUGMSG (ZONE_WRITE|ZONE_ERROR,
(TEXT("COM_WRITE, bad read pointer\r\n") ));
SetLastError(ERROR_INVALID_PARAMETER);
return (ULONG)-1;
}
#endif
COM_INC_USAGE_CNT(pOpenHead);
pHWObj = pSerialHead->pHWObj;
pHWHead = pSerialHead->pHWHead;
pFuncTbl = pHWObj->pFuncTbl;
pSerialHead->fAbortTransmit = 0;
// Clear any pending event
WaitForSingleObject(pSerialHead->hTransmitEvent,0);
/* Lock out other threads from messing with these pointers.
*/
DEBUGMSG (ZONE_WRITE, (TEXT("COM_Write wait for CritSec %x.\r\n"),
&(pSerialHead->TransmitCritSec1)));
EnterCriticalSection(&(pSerialHead->TransmitCritSec1));
DEBUGMSG (ZONE_WRITE, (TEXT("COM_Write Got CritSec %x.\r\n"),
&(pSerialHead->TransmitCritSec1)));
pSerialHead->TxBytesPending = NumberOfBytes;
TotalTimeout = pSerialHead->CommTimeouts.WriteTotalTimeoutMultiplier*NumberOfBytes +
pSerialHead->CommTimeouts.WriteTotalTimeoutConstant;
Ticks = GetTickCount();
while ( 1 ) {
/* Check used flag to see if there are no users the device.
*/
if ( !pSerialHead->OpenCnt ) {
break;
}
if ( NumberOfBytes ) {
if ( pSerialHead->DCB.fRtsControl == RTS_CONTROL_TOGGLE ) {
pFuncTbl->HWSetRTS(pHWHead);
}
// Don't call PutBytes if we are flowed off.
if ( !pSerialHead->StopXmit ) {
PutRet = pFuncTbl->HWPutBytes(pHWHead, pSourceBytes, NumberOfBytes,
&BytesWritten);
} else {
// If we are flowed off, then no bytes were written. For now, we
// will set PutRet to 10 to cause polling for a flow-on condition.
// We could change this so that XON generates a TX Event and then
// we could wait forever (i.e. PutRet = 0).
BytesWritten = 0;
PutRet = 10;
}
} else {
break;
}
pSerialHead->TxBytes += BytesWritten;
if ( BytesWritten ) {
TotalWritten += BytesWritten;
NumberOfBytes -= BytesWritten;
pSourceBytes += BytesWritten;
DEBUGMSG (ZONE_WRITE,
(TEXT("COM_Write: wrote %d, remaining %d\r\n"),
BytesWritten, NumberOfBytes));
BytesWritten = 0;
}
// If data still left, wait until the Dispatch thread has
// signalled that a transmit event has occurred and try again.
if ( NumberOfBytes ) {
DEBUGMSG (ZONE_WRITE,
(TEXT("COM_Write awaiting xmit event, %d bytes remain\r\n"),
NumberOfBytes));
// Calculate the timeout
if ( !TotalTimeout ) {
Timeout = (ULONG)-1;
} else if ( TimeSpent >= TotalTimeout ) {
DEBUGMSG (ZONE_WARN,
(TEXT("COM_Write - Timeout1 (%d written, %d remain)\r\n"),
TotalWritten, NumberOfBytes));
break;
} else {
Timeout = TotalTimeout - TimeSpent;
}
if ( PutRet ) {
// If HWPutBytes returns true, then we need
// to call back (after a pdd specified interval) to
// see if the flow control condition has
// been removed.
Timeout = (Timeout > PutRet) ? PutRet : Timeout;
}
Ticks = GetTickCount();
DEBUGMSG (ZONE_WRITE,
(TEXT("COM_WRITE: About to wait for %dms\r\n"),
Timeout));
WaitReturn = WaitForSingleObject(pSerialHead->hTransmitEvent, Timeout);
Ticks = GetTickCount() - Ticks;
TimeSpent += Ticks;
// In the absense of WaitForMultipleObjects, we use flags to
// handle errors/aborts. Check for aborts or asynchronous closes.
if ( pSerialHead->fAbortTransmit ) {
DEBUGMSG(ZONE_USR_READ,(TEXT("COM_Write - Aborting write\r\n")));
break;
}
if ( !pSerialHead->OpenCnt ) {
DEBUGMSG(ZONE_WRITE|ZONE_ERROR,
(TEXT("COM_Write - device was closed\r\n")));
SetLastError(ERROR_INVALID_HANDLE);
break;
}
if ( WaitReturn == WAIT_TIMEOUT ) {
// If we were told to wait by the pdd, then loop again
// otherwise it is a write timeout
if ( ! PutRet ) {
DEBUGMSG (ZONE_WARN,
(TEXT("COM_Write - Timeout2 (%d written, %d remain)\r\n"),
TotalWritten, NumberOfBytes));
break;
}
}
}
pSerialHead->TxBytesPending = NumberOfBytes;
}
LeaveCriticalSection(&(pSerialHead->TransmitCritSec1));
DEBUGMSG (ZONE_WRITE|ZONE_FUNCTION,
(TEXT("COM_Write released CritSec: %x. Exiting\r\n"),
&(pSerialHead->TransmitCritSec1)));
/* OK, the Transmitter has gone empty.
*/
EvaluateEventFlag(pSerialHead, EV_TXEMPTY);
if ( pSerialHead->DCB.fRtsControl == RTS_CONTROL_TOGGLE ) {
pFuncTbl->HWClearRTS(pHWHead);
}
COM_DEC_USAGE_CNT(pOpenHead);
DEBUGMSG (ZONE_WRITE|ZONE_FUNCTION,
(TEXT("-COM_WRITE, returning %d\r\n"),TotalWritten));
return (TotalWritten);
}
ULONG
COM_Seek(
HANDLE pHead,
LONG Position,
DWORD Type
)
{
return (ULONG)-1;
}
/*
@doc EXTERNAL
@func BOOL | COM_PowerUp | Turn power on to serial device
* Exported to users.
@rdesc This routine returns a status of 1 if unsuccessful and 0 otherwise.
*/
BOOL
COM_PowerUp(
HANDLE pHead /*@parm Handle to device. */
)
{
PHW_INDEP_INFO pHWIHead = (PHW_INDEP_INFO)pHead;
PHWOBJ pHWObj;
PREFAST_ASSERT (pHWIHead);
pHWObj = (PHWOBJ)pHWIHead->pHWObj;
PREFAST_ASSERT (pHWObj);
return (pHWObj->pFuncTbl->HWPowerOn(pHWIHead->pHWHead));
}
/*
@doc EXTERNAL
@func BOOL | COM_PowerDown | Turns off power to serial device.
* Exported to users.
@rdesc This routine returns a status of 1 if unsuccessful and 0 otherwise.
*/
BOOL
COM_PowerDown(
HANDLE pHead /*@parm Handle to device. */
)
{
PHW_INDEP_INFO pHWIHead = (PHW_INDEP_INFO)pHead;
if ( pHWIHead ) {
PHWOBJ pHWObj = (PHWOBJ)pHWIHead->pHWObj;
return (pHWObj->pFuncTbl->HWPowerOff(pHWIHead->pHWHead));
} else {
return (1);
}
}
/*
@doc INTERNAL
@func ULONG | SerialGetDroppedByteNumber | Returns Number of dropped b
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -