📄 mdd.c
字号:
// Make sure the caller has access permissions
if ( !(pOpenHead->AccessCode & GENERIC_WRITE) ) {
DEBUGMSG(ZONE_USR_READ|ZONE_ERROR,
(TEXT("SERDMA_Write: Access permission failure x%X\n\r"),
pOpenHead->AccessCode));
SetLastError (ERROR_INVALID_ACCESS);
return (ULONG)-1;
}
if ( pSourceBytes == NULL ) {
DEBUGMSG (ZONE_WRITE|ZONE_ERROR,
(TEXT("SERDMA_Write, bad read pointer\r\n") ));
SetLastError(ERROR_INVALID_PARAMETER);
return (ULONG)-1;
}
// Construct the DMA packet
if (NumberOfBytes > sizeof(pTransmitPacketBuffer->u.PacketContents)) {
DEBUGMSG (ZONE_WRITE|ZONE_ERROR,
(TEXT("SERDMA_Write, bad read pointer\r\n") ));
SetLastError(ERROR_INVALID_PARAMETER);
return (ULONG)-1;
}
pTransmitPacketBuffer = (DMA_PACKET_BUFFER*)
InterlockedExchangePointer(g_pPacketBufferCache, NULL);
if ( pTransmitPacketBuffer == NULL ) {
// Another thread is using the global PacketBuffer. Allocate a new one here.
pTransmitPacketBuffer = LocalAlloc(LMEM_FIXED, sizeof(DMA_PACKET_BUFFER));
if ( pTransmitPacketBuffer == NULL ) {
SetLastError(ERROR_OUTOFMEMORY);
return (ULONG)-1;
}
}
pTransmitPacketBuffer->u.PacketLength = (USHORT)NumberOfBytes;
if (!CeSafeCopyMemory(pTransmitPacketBuffer->u.PacketContents, pSourceBytes, NumberOfBytes)) {
DEBUGMSG (ZONE_WRITE|ZONE_ERROR,
(TEXT("SERDMA_Write, bad read pointer\r\n") ));
SetLastError(ERROR_INVALID_PARAMETER);
goto EXIT;
}
COM_INC_USAGE_CNT(pOpenHead);
pHWObj = pSerialHead->pHWObj;
pHWHead = pSerialHead->pHWHead;
pFuncTbl = pHWObj->pFuncTbl;
// Transmit the packet
Len = sizeof(*pTransmitPacketBuffer);
pFuncTbl->HWTxIntrHandler(pHWHead,
(PUCHAR)pTransmitPacketBuffer,
&Len);
// Report the event to WaitCommEvent()
EvaluateEventFlag(pSerialHead, EV_TXEMPTY);
COM_DEC_USAGE_CNT(pOpenHead);
ulRet = NumberOfBytes;
EXIT:
if (pTransmitPacketBuffer == &g_PacketBuffer) {
// We're using the global buffer. Release it now.
g_pPacketBufferCache = &g_PacketBuffer;
}
else {
LocalFree(pTransmitPacketBuffer);
}
DEBUGMSG (ZONE_WRITE|ZONE_FUNCTION,
(TEXT("-SERDMA_Write, returning %d\n\r"),ulRet));
return ulRet;
}
ULONG
SERDMA_Seek(
HANDLE pHead,
LONG Position,
DWORD Type
)
{
return(ULONG)-1;
}
/*
@doc EXTERNAL
@func BOOL | SERDMA_PowerUp | Turn power on to serial device
* Exported to users.
@rdesc This routine returns a status of 1 if unsuccessful and 0 otherwise.
*/
BOOL
SERDMA_PowerUp(
HANDLE pHead /*@parm Handle to device. */
)
{
return 0;
}
/*
@doc EXTERNAL
@func BOOL | SERDMA_PowerDown | Turns off power to serial device.
* Exported to users.
@rdesc This routine returns a status of 1 if unsuccessful and 0 otherwise.
*/
BOOL
SERDMA_PowerDown(
HANDLE pHead /*@parm Handle to device. */
)
{
PHW_INDEP_INFO pSerialHead = (PHW_INDEP_INFO)pHead;
PVOID pHWHead = pSerialHead->pHWHead;
SL_PowerOff(pHWHead);
return 0;
}
// Routine to handle the PROCESS_EXITING flag. Should let free any threads blocked on pOpenHead,
// so they can be killed and the process closed.
BOOL
ProcessExiting(PHW_OPEN_INFO pOpenHead)
{
PHW_INDEP_INFO pSerialHead = pOpenHead->pSerialHead;
PHWOBJ pHWObj;
int i;
BOOL RetCode = TRUE;
DEBUGMSG (ZONE_CLOSE|ZONE_FUNCTION, (TEXT("+ProcessExiting\r\n")));
if ( !pSerialHead ) {
DEBUGMSG (ZONE_ERROR, (TEXT("!!ProcessExiting: 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 ) {
DEBUGMSG (1,
(TEXT("ProcessClose: (%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("ProcessExiting: %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(pSerialHead->hReadEvent);
}
/* Sleep, let threads finish */
Sleep(100);
}
if ( i==20 )
DEBUGMSG(ZONE_CLOSE|ZONE_INIT|ZONE_ERROR,
(TEXT("ProcessExiting: Waited 2s for serial users to exit, %d left\n\r"),
pOpenHead->StructUsers));
} 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("-ProcessExiting\r\n")));
return RetCode;
}
/*
* @doc INTERNAL
* @func BOOL | ApplyDCB | Apply the current DCB.
*
* This function will apply the current DCB settings to the device.
* It will also call to the PDD to set the PDD values.
*/
BOOL
ApplyDCB (PHW_INDEP_INFO pSerialHead, DCB *pDCB, BOOL fOpen)
{
PHWOBJ pHWObj = pSerialHead->pHWObj;
if ( !pHWObj->pFuncTbl->HWSetDCB(pSerialHead->pHWHead,
pDCB) ) {
return FALSE;
}
if ( !fOpen ) {
return TRUE;
}
// If PDD SetDCB was successful, save the supplied DCB and
// configure port to match these settings.
memcpy(&(pSerialHead->DCB), pDCB, sizeof(DCB));
return TRUE;
}
// ****************************************************************
//
// @func VOID | EvaluateEventFlag | Evaluate an event mask.
//
// @parm PHW_INDEP_INFO | pHWIHead | MDD context pointer
// @parm ULONG | fdwEventMask | Bitmask of events
//
// @rdesc No return
//
// @remark This function is called by the PDD (and internally in the MDD
// to evaluate a COMM event. If the user is waiting for a
// COMM event (see WaitCommEvent()) then it will signal the
// users thread.
//
VOID
EvaluateEventFlag(PVOID pHead, ULONG fdwEventMask)
{
PHW_INDEP_INFO pHWIHead = (PHW_INDEP_INFO)pHead;
PLIST_ENTRY pEntry;
PHW_OPEN_INFO pOpenHead;
DWORD dwTmpEvent, dwOrigEvent;
BOOL fRetCode;
if ( !pHWIHead->OpenCnt ) {
DEBUGMSG (ZONE_EVENTS|ZONE_ERROR,
(TEXT(" EvaluateEventFlag - device was closed\r\n")));
SetLastError (ERROR_INVALID_HANDLE);
return;
}
DEBUGMSG (ZONE_EVENTS, (TEXT(" CommEvent - Event 0x%X, Global Mask 0x%X\r\n"),
fdwEventMask,
pHWIHead->fEventMask));
// Now that we support multiple opens, we must check mask for each open handle
// To keep this relatively painless, we keep a per-device mask which is the
// bitwise or of each current open mask. We can check this first before doing
// all the linked list work to figure out who to notify
if ( pHWIHead->fEventMask & fdwEventMask ) {
pEntry = pHWIHead->OpenList.Flink;
while ( pEntry != &pHWIHead->OpenList ) {
pOpenHead = CONTAINING_RECORD( pEntry, HW_OPEN_INFO, llist);
pEntry = pEntry->Flink; // advance to next
EnterCriticalSection(&(pOpenHead->CommEvents.EventCS));
// Don't do anything unless this event is of interest to the MDD.
if ( pOpenHead->CommEvents.fEventMask & fdwEventMask ) {
// Store the event data
dwOrigEvent = pOpenHead->CommEvents.fEventData;
do {
dwTmpEvent = dwOrigEvent;
dwOrigEvent = InterlockedExchange(&(pOpenHead->CommEvents.fEventData),
dwTmpEvent | fdwEventMask) ;
} while ( dwTmpEvent != dwOrigEvent );
// Signal the MDD that new event data is available.
fRetCode = SetEvent(pOpenHead->CommEvents.hCommEvent);
DEBUGMSG (ZONE_EVENTS, (TEXT(" CommEvent - Event 0x%X, Handle 0x%X Mask 0x%X (%X)\r\n"),
dwTmpEvent | fdwEventMask,
pOpenHead,
pOpenHead->CommEvents.fEventMask,
fRetCode));
}
LeaveCriticalSection(&(pOpenHead->CommEvents.EventCS));
}
}
}
/*
@doc INTERNAL
@func BOOL | WaitCommEvent | See Win32 documentation.
* Exported to users.
*/
BOOL
WINAPI
WaitCommEvent(
PHW_OPEN_INFO pOpenHead, // @parm Handle to device.
PULONG pfdwEventMask, // @parm Pointer to ULONG to receive CommEvents.fEventMask.
LPOVERLAPPED Unused // @parm Pointer to OVERLAPPED not used.
)
{
PHW_INDEP_INFO pHWIHead = pOpenHead->pSerialHead;
DWORD dwEventData;
DEBUGMSG(ZONE_FUNCTION|ZONE_EVENTS,(TEXT("+WaitCommEvent x%X x%X, pMask x%X\n\r"),
pOpenHead, pHWIHead , pfdwEventMask));
if ( !pHWIHead || !pHWIHead->OpenCnt ) {
DEBUGMSG (ZONE_ERROR|ZONE_EVENTS, (TEXT("-WaitCommEvent - device not open (x%X, %d) \r\n"),
pHWIHead, (pHWIHead == NULL) ? 0 : pHWIHead->OpenCnt));
*pfdwEventMask = 0;
SetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
// We should return immediately if mask is 0
if ( !pOpenHead->CommEvents.fEventMask ) {
DEBUGMSG (ZONE_ERROR|ZONE_EVENTS, (TEXT("-WaitCommEvent - Mask already clear\r\n")));
*pfdwEventMask = 0;
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
COM_INC_USAGE_CNT(pOpenHead);
// Abort should only affect us once we start waiting. Ignore any old aborts
pOpenHead->CommEvents.fAbort = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -