📄 mdd.c
字号:
// Initially, open list is empty.
InitializeListHead( &pSerialHead->OpenList );
InitializeCriticalSection(&(pSerialHead->OpenCS));
pSerialHead->pAccessOwner = NULL;
pSerialHead->fEventMask = 0;
/* Initialize the critical sections that will guard the parts of
* the receive and transmit buffers.
*/
InitializeCriticalSection(&(pSerialHead->ReceiveCritSec1));
/* Want to use the Identifier to do RegOpenKey and RegQueryValue (?)
* to get the index to be passed to GetHWObj.
* The HWObj will also have a flag denoting whether to start the
* listening thread or provide the callback.
*/
DEBUGMSG (ZONE_INIT,(TEXT("Try to open %s\r\n"), (LPCTSTR)Identifier));
hKey = OpenDeviceKey((LPCTSTR)Identifier);
if ( !hKey ) {
DEBUGMSG (ZONE_INIT | ZONE_ERROR,
(TEXT("Failed to open devkeypath, SERDMA_Init failed\r\n")));
LocalFree(pSerialHead);
return(NULL);
}
datasize = sizeof(DWORD);
if ( RegQueryValueEx(hKey, L"DeviceArrayIndex", NULL, NULL,
(LPBYTE)&DevIndex, &datasize) ) {
DEBUGMSG (ZONE_INIT | ZONE_ERROR,
(TEXT("Failed to get DeviceArrayIndex value, SERDMA_Init failed\r\n")));
RegCloseKey (hKey);
LocalFree(pSerialHead);
return(NULL);
}
datasize = sizeof(DWORD);
if ( RegQueryValueEx(hKey, L"Priority256", NULL, NULL,
(LPBYTE)&pSerialHead->Priority256, &datasize) ) {
pSerialHead->Priority256 = DEFAULT_CE_THREAD_PRIORITY;
DEBUGMSG (ZONE_INIT | ZONE_WARN,
(TEXT("Failed to get Priority256 value, defaulting to %d\r\n"), pSerialHead->Priority256));
}
datasize = sizeof(DWORD);
if ( RegQueryValueEx(hKey, L"DMAChannel", NULL, NULL,
(LPBYTE)&DMAChannelNumber, &datasize) || DMAChannelNumber > 9) {
DEBUGMSG (ZONE_INIT | ZONE_ERROR,
(TEXT("Failed to get DMAChannel value, SERDMA_Init failed\r\n")));
RegCloseKey (hKey);
LocalFree(pSerialHead);
return(NULL);
}
RegCloseKey (hKey);
DEBUGMSG (ZONE_INIT,
(TEXT("DevIndex %X\r\n"), DevIndex));
pSerialHead->hKillDispatchThread = CreateEvent(0, FALSE, FALSE, NULL); // auto reset, initially clear
pSerialHead->hReadEvent = CreateEvent(0, TRUE, FALSE, NULL); // manual reset, initially clear
pSerialHead->hReceiveBufferEmpty = CreateEvent(0, TRUE, TRUE, NULL); // manual reset, initially set
wcscpy(ChannelEventName, L"channel0");
ChannelEventName[7] = '0'+(WCHAR)DMAChannelNumber; // DMAChannelNumber has been validated to be 0...9 already.
pSerialHead->hReceiveDataReady = CreateEvent(0, FALSE, FALSE, ChannelEventName); // set/reset by the DMA device itself. The second and third args are ignored.
if ( !pSerialHead->hKillDispatchThread ||
!pSerialHead->hReadEvent ||
!pSerialHead->hReceiveBufferEmpty ||
!pSerialHead->hReceiveDataReady) {
DEBUGMSG(ZONE_ERROR | ZONE_INIT,
(TEXT("Error creating event, SERDMA_Init failed\n\r")));
LocalFree(pSerialHead);
return NULL;
}
// Initialize hardware dependent data.
pSerialHead->pHWObj = GetSerialObject( DevIndex );
if ( !pSerialHead->pHWObj ) {
DEBUGMSG(ZONE_ERROR | ZONE_INIT,
(TEXT("Error in GetSerialObject, SERDMA_Init failed\n\r")));
LocalFree(pSerialHead);
return NULL;
}
DEBUGMSG (ZONE_INIT, (TEXT("About to call HWInit(%s,0x%X)\r\n"),
Identifier, pSerialHead));
pHWHead = pSerialHead->pHWObj->pFuncTbl->HWInit(Identifier, pSerialHead, pSerialHead->pHWObj);
pSerialHead->pHWHead = pHWHead;
/* Check that HWInit did stuff ok. From here on out, call Deinit function
* when things fail.
*/
if ( !pHWHead ) {
DEBUGMSG (ZONE_INIT | ZONE_ERROR,
(TEXT("Hardware doesn't init correctly, SERDMA_Init failed\r\n")));
SERDMA_Deinit(pSerialHead);
return NULL;
}
DEBUGMSG (ZONE_INIT,
(TEXT("Back from hardware init\r\n")));
if ( pSerialHead->pHWObj->BindFlags & THREAD_AT_INIT ) {
// Hook the interrupt and start the associated thread.
if ( ! StartDispatchThread( pSerialHead ) ) {
// Failed on InterruptInitialize or CreateThread. Bail.
SERDMA_Deinit(pSerialHead);
return NULL;
}
}
// OK, now that everything is ready on our end, give the PDD
// one last chance to init interrupts, etc.
// For SERDMA, this opens the file HANDLE to the DMA device
// instance.
if (!pSerialHead->pHWObj->pFuncTbl->HWPostInit( pHWHead )) {
SERDMA_Deinit(pSerialHead);
return NULL;
}
DEBUGMSG (ZONE_INIT | ZONE_FUNCTION, (TEXT("-SERDMA_Init\r\n")));
return pSerialHead;
}
/*
@doc EXTERNAL
@func HANDLE | SERDMA_Open | Serial port driver initialization.
* Description: This routine must be called by the user to open the
* serial device. The HANDLE returned must be used by the application in
* all subsequent calls to the serial driver. This routine starts the thread
* which handles the serial events.
* Exported to users.
*
@rdesc This routine returns a HANDLE representing the device.
*/
HANDLE
SERDMA_Open(
HANDLE pHead, // @parm Handle returned by SERDMA_Init.
DWORD AccessCode, // @parm access code.
DWORD ShareMode // @parm share mode - Not used in this driver.
)
{
PHW_INDEP_INFO pSerialHead = (PHW_INDEP_INFO)pHead;
PHW_OPEN_INFO pOpenHead;
PHWOBJ pHWObj = pSerialHead->pHWObj;
DEBUGMSG (ZONE_OPEN|ZONE_FUNCTION, (TEXT("+SERDMA_Open handle x%X, access x%X, share x%X\r\n"),
pHead, AccessCode, ShareMode));
// Return NULL if SerialInit failed.
if ( !pSerialHead ) {
DEBUGMSG (ZONE_OPEN|ZONE_ERROR,
(TEXT("Open attempted on uninited device!\r\n")));
SetLastError(ERROR_INVALID_HANDLE);
return(NULL);
}
// Return NULL if opening with access & someone else already has
if ( (AccessCode & (GENERIC_READ | GENERIC_WRITE)) &&
pSerialHead->pAccessOwner ) {
DEBUGMSG (ZONE_OPEN|ZONE_ERROR,
(TEXT("Open requested access %x, handle x%X already has x%X!\r\n"),
AccessCode, pSerialHead->pAccessOwner,
pSerialHead->pAccessOwner->AccessCode));
SetLastError(ERROR_INVALID_ACCESS);
return(NULL);
}
// OK, lets allocate an open structure
pOpenHead = (PHW_OPEN_INFO)LocalAlloc(LPTR, sizeof(HW_OPEN_INFO));
if ( !pOpenHead ) {
DEBUGMSG(ZONE_INIT | ZONE_ERROR,
(TEXT("Error allocating memory for pOpenHead, SERDMA_Open failed\n\r")));
return(NULL);
}
// Init the structure
pOpenHead->pSerialHead = pSerialHead; // pointer back to our parent
pOpenHead->StructUsers = 0;
pOpenHead->AccessCode = AccessCode;
pOpenHead->ShareMode = ShareMode;
pOpenHead->CommEvents.hCommEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
pOpenHead->CommEvents.fEventMask = 0;
pOpenHead->CommEvents.fEventData = 0;
pOpenHead->CommEvents.fAbort = 0;
InitializeCriticalSection(&(pOpenHead->CommEvents.EventCS));
// if we have access permissions, note it in pSerialhead
if ( AccessCode & (GENERIC_READ | GENERIC_WRITE) ) {
DEBUGMSG(ZONE_INIT|ZONE_CLOSE,
(TEXT("SERDMA_Open: Access permission handle granted x%X\n\r"),
pOpenHead));
pSerialHead->pAccessOwner = pOpenHead;
}
// add this open entry to list of open entries.
// Note that we hold the open CS for the duration of the routine since
// all of our state info is in flux during this time. In particular,
// without the CS is would be possible for an open & close to be going on
// simultaneously and have bad things happen like spinning a new event
// thread before the old one was gone, etc.
EnterCriticalSection(&(pSerialHead->OpenCS));
InsertHeadList(&pSerialHead->OpenList,
&pOpenHead->llist);
// If port not yet opened, we need to do some init
if ( ! pSerialHead->OpenCnt ) {
DEBUGMSG(ZONE_INIT|ZONE_OPEN,
(TEXT("SERDMA_Open: First open : Do Init x%X\n\r"),
pOpenHead));
if ( pSerialHead->pHWObj->BindFlags & THREAD_AT_OPEN ) {
DEBUGMSG(ZONE_INIT|ZONE_OPEN,
(TEXT("SERDMA_Open: Starting DispatchThread x%X\n\r"),
pOpenHead));
// Hook the interrupt and start the associated thread.
if ( ! StartDispatchThread( pSerialHead ) ) {
// Failed on InterruptInitialize or CreateThread. Bail.
DEBUGMSG(ZONE_INIT|ZONE_OPEN,
(TEXT("SERDMA_Open: Failed StartDispatchThread x%X\n\r"),
pOpenHead));
goto OpenFail;
}
}
pHWObj->pFuncTbl->HWSetCommTimeouts(pSerialHead->pHWHead,
&(pSerialHead->CommTimeouts));
if ( !pHWObj->pFuncTbl->HWOpen(pSerialHead->pHWHead) ) {
DEBUGMSG (ZONE_OPEN|ZONE_ERROR, (TEXT("HW Open failed.\r\n")));
goto OpenFail;
}
pHWObj->pFuncTbl->HWPurgeComm(pSerialHead->pHWHead, PURGE_RXCLEAR);
if ( pHWObj->BindFlags & THREAD_IN_MDD ) {
CeSetThreadPriority(pSerialHead->pDispatchThread,
pSerialHead->Priority256);
}
}
++(pSerialHead->OpenCnt);
// OK, we are finally back in a stable state. Release the CS.
LeaveCriticalSection(&(pSerialHead->OpenCS));
DEBUGMSG (ZONE_OPEN|ZONE_FUNCTION, (TEXT("-SERDMA_Open handle x%X, x%X, Ref x%X\r\n"),
pOpenHead, pOpenHead->pSerialHead, pSerialHead->OpenCnt));
return pOpenHead;
OpenFail :
DEBUGMSG (ZONE_OPEN|ZONE_FUNCTION, (TEXT("-SERDMA_Open handle x%X, x%X, Ref x%X\r\n"),
NULL, pOpenHead->pSerialHead, pSerialHead->OpenCnt));
SetLastError(ERROR_OPEN_FAILED);
// If this was the handle with access permission, remove pointer
if ( pOpenHead == pSerialHead->pAccessOwner )
pSerialHead->pAccessOwner = NULL;
// Remove the Open entry from the linked list
RemoveEntryList(&pOpenHead->llist);
// OK, everything is stable so release the critical section
LeaveCriticalSection(&(pSerialHead->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 | SERDMA_Close | close the serial device.
//
// @parm DWORD | pHead | Context pointer returned from SERDMA_Open
//
// @rdesc TRUE if success; FALSE if failure
//
// @remark This routine is called by the device manager to close the device.
//
//
//
BOOL
SERDMA_Close(PHW_OPEN_INFO pOpenHead)
{
PHW_INDEP_INFO pSerialHead = pOpenHead->pSerialHead;
PHWOBJ pHWObj;
int i;
BOOL RetCode = TRUE;
DEBUGMSG (ZONE_CLOSE|ZONE_FUNCTION, (TEXT("+SERDMA_Close\r\n")));
if ( !pSerialHead ) {
DEBUGMSG (ZONE_ERROR, (TEXT("!!SERDMA_Close: pSerialHead == NULL!!\r\n")));
SetLastError(ERROR_INVALID_HANDLE);
return(FALSE);
}
pHWObj = (PHWOBJ)pSerialHead->pHWObj;
// Use the OpenCS to make sure we don't collide with an in-progress open.
EnterCriticalSection(&(pSerialHead->OpenCS));
if ( pSerialHead->OpenCnt ) {
--(pSerialHead->OpenCnt);
DEBUGMSG (1, (TEXT("SERDMA_Close: (%d handles)\r\n"), pSerialHead->OpenCnt));
// In multi open case, do we need to restore state later on or something????
if ( pHWObj && (pHWObj->BindFlags & THREAD_IN_MDD) &&
pSerialHead->pDispatchThread ) {
SetThreadPriority(pSerialHead->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 SERDMA_ functions before proceeding (wait up to 2 s).
for ( i=0; i<20 && pOpenHead->StructUsers; i++ ) {
DEBUGMSG(ZONE_INIT|ZONE_CLOSE,
(TEXT("SERDMA_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));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -