📄 mdd.c
字号:
// And only for the handle with access permissions do we
// have to worry about read, write, etc being blocked.
if ( pOpenHead->AccessCode & (GENERIC_READ | GENERIC_WRITE) ) {
SetEvent(pSerialHead->hReadEvent);
}
/* Sleep, let threads finish */
Sleep(100);
}
if ( i==20 )
DEBUGMSG(ZONE_CLOSE|ZONE_INIT|ZONE_ERROR,
(TEXT("SERDMA_Close: Waited 2s for serial users to exit, %d left\n\r"),
pOpenHead->StructUsers));
// If we are closing the last open handle, then close PDD also
if ( !pSerialHead->OpenCnt ) {
DEBUGMSG (ZONE_CLOSE, (TEXT("About to call HWClose\r\n")));
if ( pHWObj )
pHWObj->pFuncTbl->HWClose(pSerialHead->pHWHead);
DEBUGMSG (ZONE_CLOSE, (TEXT("Returned from HWClose\r\n")));
// And if thread was spun in open, kill it now.
if ( pSerialHead->pHWObj->BindFlags & THREAD_AT_OPEN ) {
DEBUGMSG (ZONE_CLOSE, (TEXT("SERDMA_Close : Stopping Dispatch Thread\r\n")));
StopDispatchThread( pSerialHead );
}
}
// If this was the handle with access permission, remove pointer
if ( pOpenHead == pSerialHead->pAccessOwner ) {
DEBUGMSG(ZONE_INIT|ZONE_CLOSE,
(TEXT("SERDMA_Close: Closed access owner handle\n\r"),
pOpenHead));
pSerialHead->pAccessOwner = NULL;
}
// Remove the entry from the linked list
RemoveEntryList(&pOpenHead->llist);
// Free all data allocated in open
DeleteCriticalSection(&(pOpenHead->CommEvents.EventCS));
if ( pOpenHead->CommEvents.hCommEvent )
CloseHandle(pOpenHead->CommEvents.hCommEvent);
LocalFree( pOpenHead );
} else {
DEBUGMSG (ZONE_ERROR, (TEXT("!!Close of non-open serial port\r\n")));
SetLastError(ERROR_INVALID_HANDLE);
RetCode = FALSE;
}
// OK, other inits/opens can go ahead.
LeaveCriticalSection(&(pSerialHead->OpenCS));
DEBUGMSG (ZONE_CLOSE|ZONE_FUNCTION, (TEXT("-SERDMA_Close\r\n")));
return RetCode;
}
/*
@doc EXTERNAL
@func BOOL | SERDMA_Deinit | De-initialize serial port.
@parm DWORD | pSerialHead | Context pointer returned from SERDMA_Init
*
@rdesc None.
*/
BOOL
SERDMA_Deinit(PHW_INDEP_INFO pSerialHead)
{
DEBUGMSG (ZONE_INIT|ZONE_FUNCTION, (TEXT("+SERDMA_Deinit\r\n")));
if ( !pSerialHead ) {
/* Can't do much without this */
DEBUGMSG (ZONE_INIT|ZONE_ERROR,
(TEXT("SERDMA_Deinit can't find pSerialHead\r\n")));
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
// If we have an interrupt handler thread, kill it
if ( pSerialHead->pHWObj->BindFlags & THREAD_IN_MDD ) {
StopDispatchThread( pSerialHead );
}
/*
** Call close, if we have a user. Note that this call will ensure that
** all users are out of the serial routines before it returns, so we can
** go ahead and free our internal memory.
*/
if ( pSerialHead->OpenCnt ) {
PLIST_ENTRY pEntry;
PHW_OPEN_INFO pOpenHead;
pEntry = pSerialHead->OpenList.Flink;
while ( pEntry != &pSerialHead->OpenList ) {
pOpenHead = CONTAINING_RECORD( pEntry, HW_OPEN_INFO, llist);
pEntry = pEntry->Flink; // advance to next
DEBUGMSG (ZONE_INIT | ZONE_CLOSE, (TEXT(" Deinit - Closing Handle 0x%X\r\n"),
pOpenHead ));
SERDMA_Close(pOpenHead);
}
}
/* Free our resources */
if ( pSerialHead->hKillDispatchThread )
CloseHandle(pSerialHead->hKillDispatchThread);
if ( pSerialHead->hReadEvent )
CloseHandle(pSerialHead->hReadEvent);
if ( pSerialHead->hReceiveBufferEmpty )
CloseHandle(pSerialHead->hReceiveBufferEmpty);
if ( pSerialHead->hReceiveDataReady )
CloseHandle(pSerialHead->hReceiveDataReady);
DeleteCriticalSection(&(pSerialHead->ReceiveCritSec1));
DeleteCriticalSection(&(pSerialHead->OpenCS));
/* Now, call HW specific deinit function */
if ( pSerialHead->pHWObj && pSerialHead->pHWObj->pFuncTbl ) {
DEBUGMSG (ZONE_INIT, (TEXT("About to call HWDeinit\r\n")));
pSerialHead->pHWObj->pFuncTbl->HWDeinit(pSerialHead->pHWHead);
DEBUGMSG (ZONE_INIT, (TEXT("Returned from HWDeinit\r\n")));
}
LocalFree(pSerialHead);
DEBUGMSG (ZONE_INIT|ZONE_FUNCTION, (TEXT("-SERDMA_Deinit\r\n")));
return TRUE;
}
/*
@doc EXTERNAL
@func ULONG | SERDMA_Read | Allows application to receive characters from
* serial port. This routine sets the buffer and bufferlength to be used
* by the reading thread. It also enables reception and controlling when
* to return to the user. It writes to the referent of the fourth argument
* the number of bytes transacted. It returns the status of the call.
*
* Exported to users.
@rdesc This routine returns: -1 if error, or number of bytes read.
*/
ULONG
SERDMA_Read(
HANDLE pHead, //@parm [IN] HANDLE returned by SERDMA_Open
PUCHAR pTargetBuffer, //@parm [IN,OUT] Pointer to valid memory.
ULONG BufferLength //@parm [IN] Size in bytes of pTargetBuffer.
)
{
PHW_OPEN_INFO pOpenHead = (PHW_OPEN_INFO)pHead;
PHW_INDEP_INFO pSerialHead = pOpenHead->pSerialHead;
PHW_VTBL pFuncTbl;
PVOID pHWHead;
ULONG BytesRead = 0; // this initial value is returned if there is a timeout
int ReadTries;
ULONG Ticks;
ULONG Timeout;
ULONG IntervalTimeout; // The interval timeout
ULONG AddIntervalTimeout;
ULONG TotalTimeout; // The Total Timeout
ULONG TimeSpent = 0; // How much time have we been waiting?
DEBUGMSG (ZONE_USR_READ|ZONE_FUNCTION,
(TEXT("+SERDMA_Read(0x%X,0x%X,%d)\r\n"),
pHead, pTargetBuffer, BufferLength));
// Check to see that the call is valid.
if ( !pSerialHead || !pSerialHead->OpenCnt ) {
DEBUGMSG (ZONE_USR_READ|ZONE_ERROR,
(TEXT("SERDMA_Read, device not open\r\n") ));
SetLastError (ERROR_INVALID_HANDLE);
return (ULONG)-1;
}
pFuncTbl = pSerialHead->pHWObj->pFuncTbl;
pHWHead = pSerialHead->pHWHead;
// Make sure the caller has access permissions
if ( !(pOpenHead->AccessCode & GENERIC_READ) ) {
DEBUGMSG(ZONE_USR_READ|ZONE_ERROR,
(TEXT("SERDMA_Read: Access permission failure x%X\n\r"),
pOpenHead->AccessCode));
SetLastError (ERROR_INVALID_ACCESS);
return (ULONG)-1;
}
if ( BufferLength > DMA_PACKET_SIZE) {
SetLastError(ERROR_INVALID_PARAMETER);
return (ULONG)-1;
}
if (pTargetBuffer == NULL) {
BytesRead = (ULONG)-1;
SetLastError(ERROR_INVALID_PARAMETER);
return (ULONG)-1;
}
COM_INC_USAGE_CNT(pOpenHead);
/* Practice safe threading.
*/
EnterCriticalSection(&(pSerialHead->ReceiveCritSec1));
/* Compute total time to wait. Take product and add constant.
*/
if ( MAXDWORD != pSerialHead->CommTimeouts.ReadTotalTimeoutMultiplier ) {
TotalTimeout = pSerialHead->CommTimeouts.ReadTotalTimeoutMultiplier*BufferLength +
pSerialHead->CommTimeouts.ReadTotalTimeoutConstant;
// Because we are using FIFO and water level is set to 8, we have to do following
AddIntervalTimeout=pSerialHead->CommTimeouts.ReadTotalTimeoutMultiplier*8;
} else {
TotalTimeout = pSerialHead->CommTimeouts.ReadTotalTimeoutConstant;
AddIntervalTimeout=0;
}
IntervalTimeout = pSerialHead->CommTimeouts.ReadIntervalTimeout;
if (IntervalTimeout < MAXDWORD - AddIntervalTimeout) {
IntervalTimeout +=AddIntervalTimeout;
}
DEBUGMSG (ZONE_USR_READ, (TEXT("TotalTimeout:%d\r\n"), TotalTimeout));
for (ReadTries=0;ReadTries<2;ReadTries++) {
if (pSerialHead->RxDataReady) {
// A packet is already ready. Copy it to the caller's buffer
BytesRead = min(BufferLength, pSerialHead->ReceivePacketBuffer.u.PacketLength);
if (!CeSafeCopyMemory(pTargetBuffer,
pSerialHead->ReceivePacketBuffer.u.PacketContents, BytesRead)) {
DEBUGMSG(ZONE_USR_READ|ZONE_ERROR,
(TEXT("SERDMA_Read: Buffer error\n\r")));
SetLastError(ERROR_INVALID_PARAMETER);
BytesRead = -1;
break;
}
// Indicate that the ReceivePacketBuffer is available again
pSerialHead->RxDataReady = 0;
SetEvent(pSerialHead->hReceiveBufferEmpty);
break;
}
// Else no packet is ready - wait until one arrives or we time out
// Wait for a serial event?
if ( (IntervalTimeout == MAXDWORD) && (TotalTimeout == 0) ) {
// For some reason this means don't wait.
break;
}
if ( (IntervalTimeout == 0) && (TotalTimeout == 0) ) {
// Not completely clear but this could mean wait
// for ever
Timeout = INFINITE;
} else if ( TotalTimeout == 0 ) {
// On first character we only use total timeout
Timeout = INFINITE;
} else {
// Total timeout is valid
if ( TimeSpent >= TotalTimeout ) {
// Timed out.
break;
}
Timeout = TotalTimeout - TimeSpent;
// On first byte we only use interval timeout
}
Ticks = GetTickCount();
DEBUGMSG (ZONE_USR_READ, (TEXT("About to wait %dms\r\n"), Timeout));
pSerialHead->fAbortRead = 0;
if ( WAIT_TIMEOUT == WaitForSingleObject (pSerialHead->hReadEvent,
Timeout) ) {
// Timeout
break;
}
// 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("SERDMA_Read - Aborting read\r\n")));
break;
}
if ( !pSerialHead->OpenCnt ) {
DEBUGMSG(ZONE_USR_READ|ZONE_ERROR,
(TEXT("SERDMA_Read - device was closed\n\r")));
SetLastError(ERROR_INVALID_HANDLE);
break;
}
}
LeaveCriticalSection(&(pSerialHead->ReceiveCritSec1));
COM_DEC_USAGE_CNT(pOpenHead);
DEBUGMSG (ZONE_USR_READ|ZONE_FUNCTION,
(TEXT("-SERDMA_Read: returning %d\r\n"),
BytesRead));
return BytesRead;
}
/*
@doc EXTERNAL
@func ULONG | SERDMA_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
SERDMA_Write(HANDLE pHead, /*@parm [IN] HANDLE returned by SERDMA_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;
PHW_VTBL pFuncTbl;
PHWOBJ pHWObj;
PVOID pHWHead;
ULONG Len;
ULONG ulRet = -1;
DMA_PACKET_BUFFER *pTransmitPacketBuffer = NULL;
// bugbug: COM_Write in the SMDK2410 version begins with a Sleep(10). Remove it!
DEBUGMSG (ZONE_WRITE|ZONE_FUNCTION,
(TEXT("+SERDMA_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("SERDMA_Write, device not open\r\n") ));
SetLastError (ERROR_INVALID_HANDLE);
return (ULONG)-1;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -