📄 s3c2410_can.cpp
字号:
pOpenHead, pOpenHead->pSpiHead, pSpiHead->OpenCnt));
if( !retval )
goto OpenFail;
return(pOpenHead);
OpenFail :
DEBUGMSG (ZONE_OPEN|ZONE_FUNCTION,
(TEXT("-SPI_Open handle x%X, x%X, Ref x%X\r\n"),
NULL, pOpenHead->pSpiHead, pSpiHead->OpenCnt));
SetLastError(ERROR_OPEN_FAILED);
// If this was the handle with access permission, remove pointer
if ( pOpenHead == pSpiHead->pAccessOwner )
pSpiHead->pAccessOwner = NULL;
// Remove the Open entry from the linked list
RemoveEntryList(&pOpenHead->llist);
// OK, everything is stable so release the critical section
LeaveCriticalSection(&(pSpiHead->OpenCS));
// Free all data allocated in open
if ( pOpenHead->CommEvents.hCommEvent )
CloseHandle(pOpenHead->CommEvents.hCommEvent);
DeleteCriticalSection(&(pOpenHead->CommEvents.EventCS));
LocalFree( pOpenHead );
return(NULL);
}
// ****************************************************************
//
// @doc EXTERNAL
//
// @func BOOL | SPI_Close | close the spi device.
//
// @parm DWORD | pHead | Context pointer returned from SPI_Open
//
// @rdesc TRUE if success; FALSE if failure
//
// @remark This routine is called by the device manager to close the device.
//
//
//
BOOL
SPI_Close(PHW_OPEN_INFO pOpenHead)
{
PHW_INDEP_INFO pSpiHead = pOpenHead->pSpiHead;
int i;
BOOL RetCode = TRUE;
DEBUGMSG (ZONE_CLOSE|ZONE_FUNCTION, (TEXT("+SPI_Close\r\n")));
if ( !pSpiHead )
{
DEBUGMSG (ZONE_ERROR, (TEXT("!!SPI_Close: pSpiHead == NULL!!\r\n")));
SetLastError(ERROR_INVALID_HANDLE);
return(FALSE);
}
// Use the OpenCS to make sure we don't collide with an in-progress open.
EnterCriticalSection(&(pSpiHead->OpenCS));
if ( pSpiHead->OpenCnt )
{
--(pSpiHead->OpenCnt);
DEBUGMSG (1,
(TEXT("SPI_Close: (%d handles) total RX %d, total TX %d, dropped %d\r\n"),
pSpiHead->OpenCnt, pSpiHead->RxBytes, pSpiHead->TxBytes,
pSpiHead->DroppedBytes));
// In multi open case, do we need to restore state later on or something????
if ( pSpiHead->pDispatchThread )
{
SetThreadPriority(pSpiHead->pDispatchThread, THREAD_PRIORITY_NORMAL);
}
// Free up any threads which may be blocked waiting for events.
// Monitor users count to make sure no one is still in one of
// the COM_ functions before proceeding (wait up to 2 s).
for ( i=0; i<20 && pOpenHead->StructUsers; i++ )
{
DEBUGMSG(ZONE_INIT|ZONE_CLOSE,
(TEXT("SPI_Close: %d users in MDD functions\n\r"),
pOpenHead->StructUsers));
// For any open handle, we must free pending waitcommevents
EnterCriticalSection(&(pOpenHead->CommEvents.EventCS));
pOpenHead->CommEvents.fEventMask = 0;
pOpenHead->CommEvents.fAbort = 1;
SetEvent(pOpenHead->CommEvents.hCommEvent);
LeaveCriticalSection(&(pOpenHead->CommEvents.EventCS));
// 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(pSpiHead->hReadEvent);
SetEvent(pSpiHead->hTransmitEvent);
}
/* Sleep, let threads finish */
Sleep(100);
}
if ( i==20 )
{
DEBUGMSG(ZONE_CLOSE|ZONE_INIT|ZONE_ERROR,
(TEXT("SPI_Close: Waited 2s for spi users to exit, %d left\n\r"),
pOpenHead->StructUsers));
}
// If we are closing the last open handle, then close PDD also
if ( !pSpiHead->OpenCnt )
{
// while we are still transmitting, sleep.
//......
EnterCriticalSection(&(pSpiHead->RegCritSec));
try
{
// Disable all interrupts.
DisEnINT(pSpiHead->bEINT);
//中断禁止
w_cmd0(CANINTE, 0x00);
pSpiHead->fSW_EnTxINT = FALSE;
}
except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH)
{
// Just get out of here.
}
LeaveCriticalSection(&(pSpiHead->RegCritSec));
}
// If this was the handle with access permission, remove pointer
if ( pOpenHead == pSpiHead->pAccessOwner )
{
DEBUGMSG(ZONE_INIT|ZONE_CLOSE,
(TEXT("SPI_Close: Closed access owner handle\n\r"),
pOpenHead));
pSpiHead->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 spi port\r\n")));
SetLastError(ERROR_INVALID_HANDLE);
RetCode = FALSE;
}
// OK, other inits/opens can go ahead.
LeaveCriticalSection(&(pSpiHead->OpenCS));
RETAILMSG(1, (TEXT("SPI_Close\r\n")));
DEBUGMSG (ZONE_CLOSE|ZONE_FUNCTION, (TEXT("-SPI_Close\r\n")));
return(RetCode);
}
/*
@doc EXTERNAL
@func BOOL | SPI_Deinit | De-initialize spi port.
@parm DWORD | pSpiHead | Context pointer returned from SPI_Init
*
@rdesc None.
*/
BOOL
SPI_Deinit(PHW_INDEP_INFO pSpiHead)
{
// RETAILMSG(1, (TEXT("+COM_Deinit\r\n")));
DEBUGMSG (ZONE_INIT|ZONE_FUNCTION, (TEXT("+COM_Deinit\r\n")));
if ( !pSpiHead )
{
/* Can't do much without this */
DEBUGMSG (ZONE_INIT|ZONE_ERROR, (TEXT("SPI_Deinit can't find pspiHead\r\n")));
SetLastError(ERROR_INVALID_HANDLE);
return(FALSE);
}
// If we have an interrupt handler thread, kill it
StopDispatchThread( pSpiHead );
/*
** Call close, if we have a user. Note that this call will ensure that
** all users are out of the spi routines before it returns, so we can
** go ahead and free our internal memory.
*/
if ( pSpiHead->OpenCnt )
{
PLIST_ENTRY pEntry;
PHW_OPEN_INFO pOpenHead;
pEntry = pSpiHead->OpenList.Flink;
while ( pEntry != &pSpiHead->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 ));
SPI_Close(pOpenHead);
}
}
/* Free our resources */
if ( pSpiHead->hSpiEvent )
CloseHandle(pSpiHead->hSpiEvent);
if ( pSpiHead->hKillDispatchThread )
CloseHandle(pSpiHead->hKillDispatchThread);
if ( pSpiHead->hTransmitEvent )
CloseHandle(pSpiHead->hTransmitEvent);
if ( pSpiHead->hReadEvent )
CloseHandle(pSpiHead->hReadEvent);
DeleteCriticalSection(&(pSpiHead->ReceiveCritSec1));
DeleteCriticalSection(&(pSpiHead->TransmitCritSec1));
DeleteCriticalSection(&(pSpiHead->RxBufferInfo.CS));
DeleteCriticalSection(&(pSpiHead->TxBufferInfo.CS));
DeleteCriticalSection(&(pSpiHead->OpenCS));
DeleteCriticalSection(&(pSpiHead->TransmitCritSec));
DeleteCriticalSection(&(pSpiHead->RegCritSec));
if ( pSpiHead->RxBufferInfo.RxCharBuffer )
LocalFree(pSpiHead->RxBufferInfo.RxCharBuffer);
SER_VirtualFree();
LocalFree(pSpiHead);
// RETAILMSG(1, (TEXT("-SPI_Deinit\r\n")));
DEBUGMSG (ZONE_INIT|ZONE_FUNCTION, (TEXT("-SPI_Deinit\r\n")));
return(TRUE);
}
/*
@doc EXTERNAL
@func ULONG | SPI_Read | Allows application to receive characters from
* spi 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
SPI_Read(
HANDLE pHead, //@parm [IN] HANDLE returned by SPI_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 pSpiHead = pOpenHead->pSpiHead;
ULONG Ticks;
ULONG Timeout;
ULONG BytesRead = 0;
ULONG IntervalTimeout; // The interval timeout
ULONG AddIntervalTimeout;
ULONG TotalTimeout; // The Total Timeout
ULONG TimeSpent = 0; // How much time have we been waiting?
ULONG Len;
PUCHAR pBuffer = pTargetBuffer;
// RETAILMSG(1, (TEXT("+SPI_READ(0x%X,0x%X,%d)\r\n"), pHead, pTargetBuffer, BufferLength));
DEBUGMSG (ZONE_USR_READ|ZONE_FUNCTION,
(TEXT("+SPI_READ(0x%X,0x%X,%d)\r\n"),
pHead, pTargetBuffer, BufferLength));
// Check to see that the call is valid.
if ( !pSpiHead || !pSpiHead->OpenCnt )
{
DEBUGMSG (ZONE_USR_READ|ZONE_ERROR,
(TEXT("SPI_READ, device not open\r\n") ));
SetLastError (ERROR_INVALID_HANDLE);
return(ULONG)-1;
}
// Make sure the caller has access permissions
if ( !(pOpenHead->AccessCode & GENERIC_READ) )
{
DEBUGMSG(ZONE_USR_READ|ZONE_ERROR,
(TEXT("SPI_Read: Access permission failure x%X\n\r"),
pOpenHead->AccessCode));
SetLastError (ERROR_INVALID_ACCESS);
return(ULONG)-1;
}
#ifdef DEBUG
if ( IsBadWritePtr(pTargetBuffer, BufferLength) )
{
BytesRead = (ULONG)-1;
SetLastError(ERROR_INVALID_PARAMETER);
return(ULONG)-1;
}
#endif
COM_INC_USAGE_CNT(pOpenHead);
/* Practice safe threading.
*/
EnterCriticalSection(&(pSpiHead->ReceiveCritSec1));
/* Compute total time to wait. Take product and add constant.
*/
if ( MAXDWORD != pSpiHead->CommTimeouts.ReadTotalTimeoutMultiplier )
{
TotalTimeout = pSpiHead->CommTimeouts.ReadTotalTimeoutMultiplier*BufferLength +
pSpiHead->CommTimeouts.ReadTotalTimeoutConstant;
// Because we are using FIFO and water level is set to 8, we have to do following
AddIntervalTimeout = pSpiHead->CommTimeouts.ReadTotalTimeoutMultiplier*8;
}
else
{
TotalTimeout = pSpiHead->CommTimeouts.ReadTotalTimeoutConstant;
AddIntervalTimeout=0;
}
IntervalTimeout = pSpiHead->CommTimeouts.ReadIntervalTimeout;
if (IntervalTimeout < MAXDWORD - AddIntervalTimeout)
{
IntervalTimeout +=AddIntervalTimeout;
};
DEBUGMSG (ZONE_USR_READ, (TEXT("TotalTimeout:%d\r\n"), TotalTimeout));
while ( BufferLength )
{
DEBUGMSG (ZONE_USR_READ,
(TEXT("Top of Loop Fifo(R=%d,W=%d,L=%d,BA=%d)\r\n"),
RxRead(pSpiHead), RxWrite(pSpiHead),
RxLength(pSpiHead),
RxBytesAvail(pSpiHead)));
if ( RxBytesAvail(pSpiHead) )
{
RxEnterCS(pSpiHead);
// Copy the data over
// This only copies the continous portion, This will cause a loop
// if the receive data spans the end of the buffer.
Len = MIN(RxBytesAvail(pSpiHead), RxLength(pSpiHead)-RxRead(pSpiHead));
Len = MIN(Len, BufferLength);
// RETAILMSG(1, (TEXT("About to copy %d bytes\r\n"), Len));
DEBUGMSG (ZONE_USR_READ, (TEXT("About to copy %d bytes\r\n"), Len));
memcpy (pTargetBuffer, RxBuffRead(pSpiHead), Len);
// Update Fifo info
RxRead(pSpiHead) += Len;
RxRead(pSpiHead) %= RxLength(pSpiHead);
// Update all the pointers.
BufferLength -= Len;
pTargetBuffer += Len;
BytesRead += Len;
RxLeaveCS(pSpiHead);
}
else
{
// Wait for a SPI 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 )
{
if ( !BytesRead )
{
// On first character we only use total timeout
Timeout = INFINITE;
}
else
{
// No total timeout in use. Just use interval timer
Timeout = IntervalTimeout;
}
}
else
{
// Total timeout is valid
if ( TimeSpent >= TotalTimeout )
{
// Timed out.
break;
}
Timeout = TotalTimeout - TimeSpent;
// On first byte we only use interval timeout
// on subsequent we use minimum of Interval and Timeout
if ( BytesRead && (IntervalTimeout != 0) )
{
Timeout = MIN(Timeout, IntervalTimeout);
}
// Yet another special case.
if ( BytesRead &&
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -